pcc-20181216004075500017500000000000000000001340533064100114075ustar raggewheelpcc-20181216/CVS004075500017500000000000000000001340533064200120435ustar raggewheelpcc-20181216/CVS/Root010064400017500000000000000000111340533064000127530ustar raggewheel/cvsroot pcc-20181216/CVS/Repository010064400017500000000000000000041340533064000142110ustar raggewheelpcc pcc-20181216/CVS/Entries010064400017500000000000000006701340533064200134560ustar raggewheel/Makefile.in/1.9/Tue Jun 7 13:56:05 2011// /config.guess/1.5/Sun Mar 13 11:07:00 2016// /config.h.in/1.35/Wed Nov 14 20:26:59 2018// /config.sub/1.13/Tue Jan 17 20:53:52 2017// /configure/1.137/Wed Nov 21 18:23:51 2018// /configure.ac/1.157/Wed Nov 21 18:23:51 2018// /install-sh/1.1/Sat Oct 16 07:57:40 2004// D/arch//// D/cc//// D/common//// D/doc//// D/f77//// D/lib//// D/mip//// D/os//// /DATESTAMP/1.628/Sun Dec 16 02:00:02 2018// D pcc-20181216/DATESTAMP010064400017500000000000000000111340533064200127210ustar raggewheel20181216 pcc-20181216/Makefile.in010064400017500000000000000014541157342676500135550ustar raggewheel# $Id: Makefile.in,v 1.9 2011/06/07 13:56:05 plunky Exp $ # # Makefile.in for top-level of pcc. # @SET_MAKE@ ALL_SUBDIRS= cc DIST_SUBDIRS= $(ALL_SUBDIRS) f77 all install clean: @for subdir in $(ALL_SUBDIRS); do \ _nextdir_=$${_thisdir_+$$_thisdir_/}$$subdir; \ echo "===> $$_nextdir_"; \ (_thisdir_=$$_nextdir_; export _thisdir_; cd $$subdir && \ exec $(MAKE) $(MFLAGS) $@) || exit $$?; \ echo "<=== $$_nextdir_"; \ done distclean: @for subdir in $(DIST_SUBDIRS); do \ _nextdir_=$${_thisdir_+$$_thisdir_/}$$subdir; \ echo "===> $$_nextdir_"; \ (_thisdir_=$$_nextdir_; export _thisdir_; cd $$subdir && \ exec $(MAKE) $(MFLAGS) $@) || exit $$?; \ echo "<=== $$_nextdir_"; \ done rm -rf Makefile config.log stamp-h1 config.status \ configure.lineno config.h autom4te.cache pcc-20181216/config.guess010064400017500000000000001237121267124472400140200ustar raggewheel#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2014 Free Software Foundation, Inc. timestamp='2014-11-04' # 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 3 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, see . # # 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. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD # # Please send patches to . me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2014 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case "${UNAME_SYSTEM}" in Linux|GNU|GNU/*) # If the system lacks a compiler, then just pick glibc. # We could probably try harder. LIBC=gnu eval $set_cc_for_build cat <<-EOF > $dummy.c #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #else LIBC=gnu #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` ;; esac # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/lslpp ] ; then IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW64*:*) echo ${UNAME_MACHINE}-pc-mingw64 exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; *:MSYS*:*) echo ${UNAME_MACHINE}-pc-msys exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix${UNAME_RELEASE} exit ;; aarch64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="gnulibc1" ; fi echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arc:Linux:*:* | arceb:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-${LIBC} else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi else echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf fi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; cris:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; hexagon:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:Linux:*:*) echo ${UNAME_MACHINE}-pc-linux-${LIBC} exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } ;; openrisc*:Linux:*:*) echo or1k-unknown-linux-${LIBC} exit ;; or32:Linux:*:* | or1k*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; padre:Linux:*:*) echo sparc-unknown-linux-${LIBC} exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-${LIBC} exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; *) echo hppa-unknown-linux-${LIBC} ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-${LIBC} exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-${LIBC} exit ;; ppc64le:Linux:*:*) echo powerpc64le-unknown-linux-${LIBC} exit ;; ppcle:Linux:*:*) echo powerpcle-unknown-linux-${LIBC} exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux-${LIBC} exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; tile*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-${LIBC} exit ;; x86_64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; x86_64:Haiku:*:*) echo x86_64-unknown-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown eval $set_cc_for_build if test "$UNAME_PROCESSOR" = unknown ; then UNAME_PROCESSOR=powerpc fi if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi fi elif test "$UNAME_PROCESSOR" = i386 ; then # Avoid executing cc on OS X 10.9, as it ships with a stub # that puts up a graphical alert prompting to install # developer tools. Any system running Mac OS X 10.7 or # later (Darwin 11 and later) is required to have a 64-bit # processor. This is not true of the ARM version of Darwin # that Apple uses in portable devices. UNAME_PROCESSOR=x86_64 fi echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-?:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk${UNAME_RELEASE} exit ;; NSE-*:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; x86_64:VMkernel:*:*) echo ${UNAME_MACHINE}-unknown-esx exit ;; esac cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: pcc-20181216/config.h.in010064400017500000000000000106201337310242300135040ustar raggewheel/* config.h.in. Generated from configure.ac by autoheader. */ /* Define if building universal (internal helper macro) */ #undef AC_APPLE_UNIVERSAL_BUILD /* Using a.out ABI */ #undef AOUTABI /* Define path to alternate assembler */ #undef ASSEMBLER /* Using Classic 68k ABI */ #undef CLASSIC68K /* Using COFF ABI */ #undef COFFABI /* Define path to alternate compiler */ #undef COMPILER /* Using ECOFF ABI */ #undef ECOFFABI /* Using ELF ABI */ #undef ELFABI /* Define to 1 if printf supports C99 size specifiers */ #undef HAVE_C99_FORMAT /* Define to 1 if you have the `ffs' function. */ #undef HAVE_FFS /* Define to 1 if you have the `getopt' function. */ #undef HAVE_GETOPT /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_LIBGEN_H /* Define to 1 if you have the header file. */ #undef HAVE_MALLOC_H /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the `mkstemp' function. */ #undef HAVE_MKSTEMP /* Define to 1 if you have the `snprintf' function. */ #undef HAVE_SNPRINTF /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the `strlcat' function. */ #undef HAVE_STRLCAT /* Define to 1 if you have the `strlcpy' function. */ #undef HAVE_STRLCPY /* Define to 1 if you have the `strtold' function. */ #undef HAVE_STRTOLD /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have that is POSIX.1 compatible. */ #undef HAVE_SYS_WAIT_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if you have the `vfork' function. */ #undef HAVE_VFORK /* Define to 1 if you have the `vsnprintf' function. */ #undef HAVE_VSNPRINTF /* Define if host is BIG endian */ #undef HOST_BIG_ENDIAN /* Define if host is LITTLE endian */ #undef HOST_LITTLE_ENDIAN /* Define alternate standard lib directory */ #undef LIBDIR /* Define path to alternate linker */ #undef LINKER /* Using Mach-O ABI */ #undef MACHOABI /* Define target Multi-Arch path */ #undef MULTIARCH_PATH /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Major version no */ #undef PCC_MAJOR /* Minor version no */ #undef PCC_MINOR /* Minor minor version no */ #undef PCC_MINORMINOR /* Using PE/COFF ABI */ #undef PECOFFABI /* Define path to alternate preprocessor */ #undef PREPROCESSOR /* Enable STABS debugging output */ #undef STABS /* Enable DWARF debugging output */ #undef DWARF /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define alternate standard include directory */ #undef STDINC /* Define if target defaults to BIG endian */ #undef TARGET_BIG_ENDIAN /* Define if target defaults to LITTLE endian */ #undef TARGET_LITTLE_ENDIAN /* Enable thread-local storage (TLS). */ #undef TLS /* Version string */ #undef VERSSTR /* Target string */ #undef TARGSTR /* Size of wide-character type in chars */ #undef WCHAR_SIZE /* Type to use for wide characters */ #undef WCHAR_TYPE /* determine whether 16, 32 or 64 bit host */ #undef SIZEOF_INT_P /* Compile for use of libvmf */ #undef LIBVMF /* are we cross-compiling? */ #undef CROSS_COMPILING /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel). */ #if defined AC_APPLE_UNIVERSAL_BUILD # if defined __BIG_ENDIAN__ # define WORDS_BIGENDIAN 1 # endif #else # ifndef WORDS_BIGENDIAN # undef WORDS_BIGENDIAN # endif #endif /* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a `char[]'. */ #undef YYTEXT_POINTER pcc-20181216/config.sub010064400017500000000000001065541303750214000134520ustar raggewheel#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2015 Free Software Foundation, Inc. timestamp='2015-08-20' # 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 3 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, see . # # 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. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches to . # # 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. # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD # 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. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2015 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # 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 nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; android-linux) os=-linux-android basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown ;; *) 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 | -axis | -knuth | -cray | -microblaze*) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -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/'` ;; -sco5v6*) # 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*178) os=-lynxos178 ;; -lynx*5) os=-lynxos5 ;; -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 ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; 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. 1750a | 580 \ | a29k \ | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arceb \ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | avr | avr32 \ | ba \ | be32 | be64 \ | bfin \ | c4x | c8051 | clipper \ | d10v | d30v | dlx | dsp16xx \ | e2k | epiphany \ | fido | fr30 | frv | ft32 \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | k1om \ | le32 | le64 \ | lm32 \ | m16c | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa32r6 | mipsisa32r6el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64r6 | mipsisa64r6el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipsr5900 | mipsr5900el \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 | nios2eb | nios2el \ | nova | ns16k | ns32k \ | open8 | or1k | or1knd | or32 \ | pdp7 | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ | riscv32 | riscv64 \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | visium \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown ;; c55x) basic_machine=tic55x-unknown ;; c6x) basic_machine=tic6x-unknown ;; leon|leon[3-9]) basic_machine=sparc-$basic_machine ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown os=-none ;; xscaleeb) basic_machine=armeb-unknown ;; xscaleel) basic_machine=armel-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*86 | x86_64) 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. 580-* \ | a29k-* \ | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | ba-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | c8051-* | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | e2k-* | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | k1om-* \ | le32-* | le64-* \ | lm32-* \ | m16c-* | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ | microblaze-* | microblazeel-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa32r6-* | mipsisa32r6el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64r6-* | mipsisa64r6el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipsr5900-* | mipsr5900el-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* | nios2eb-* | nios2el-* \ | none-* | nova-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | or1k*-* \ | orion-* \ | pdp7-* | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ | riscv32-* | riscv64-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | visium-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) 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) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) 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 ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; asmjs) basic_machine=asmjs-unknown ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c54x-*) basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c55x-*) basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c6x-*) basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; 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 | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; 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) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) 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 ;; 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) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; leon-*|leon[3-9]-*) basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze*) basic_machine=microblaze-xilinx ;; mingw64) basic_machine=x86_64-pc os=-mingw64 ;; mingw32) basic_machine=i686-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; moxiebox) basic_machine=moxie-unknown os=-moxiebox ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; msys) basic_machine=i686-pc os=-msys ;; mvs) basic_machine=i370-ibm os=-mvs ;; nacl) basic_machine=le32-unknown os=-nacl ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; 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) 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) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; neo-tandem) basic_machine=neo-tandem ;; nse-tandem) basic_machine=nse-tandem ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) 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/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos | rdos64) basic_machine=x86_64-pc os=-rdos ;; rdos32) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; strongarm-* | thumb-*) basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` ;; 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 ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tile*) basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) 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*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-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) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) 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. -auroraux) os=-auroraux ;; -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* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* | -cloudabi* | -sortix* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -bitrig* | -openbsd* | -solidbsd* | -litebsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -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|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -nacl*) ;; -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 score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; c8051-*) os=-elf ;; hexagon-*) os=-elf ;; tic54x-*) os=-coff ;; tic55x-*) os=-coff ;; tic6x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) 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 ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) 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 ;; -cnk*|-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* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: pcc-20181216/configure010075500017500000000000005572741337532126700134300ustar raggewheel#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for Portable C Compiler 1.2.0.DEVEL. # # Report bugs to . # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org and $0: pcc@lists.ludd.ltu.se about your system, including any $0: error possibly output before this message. Then install $0: a modern shell, or manually run the script under such a $0: shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='Portable C Compiler' PACKAGE_TARNAME='pcc' PACKAGE_VERSION='1.2.0.DEVEL' PACKAGE_STRING='Portable C Compiler 1.2.0.DEVEL' PACKAGE_BUGREPORT='pcc@lists.ludd.ltu.se' PACKAGE_URL='http://pcc.ludd.ltu.se/' # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='LTLIBOBJS LIBOBJS CF1 CF0 CCNAMES ADD_CPPFLAGS ADD_CFLAGS hostos targmachdir targmach targosver targos ALLOCA LEXLIB LEX_OUTPUT_ROOT LEX YFLAGS YACC INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM SET_MAKE EGREP GREP CPP CC_FOR_BUILD OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC BINPREFIX target_os target_vendor target_cpu target host_os host_vendor host_cpu host build_os build_vendor build_cpu build target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_multiarch with_incdir with_libdir with_assembler with_linker with_libvmf enable_tls enable_Werror enable_gcc_compat enable_pcc_debug enable_twopass enable_stripping with_yasm enable_native ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP YACC YFLAGS' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= 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=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -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_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$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 ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$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 | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$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 ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) 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 | -n) 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 ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$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_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=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 ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # 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 the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` 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 test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # 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 <<_ACEOF \`configure' configures Portable C Compiler 1.2.0.DEVEL to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/pcc] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] --target=TARGET configure for building compilers for TARGET [HOST] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of Portable C Compiler 1.2.0.DEVEL:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-multiarch=yes/no/auto/ Enable use of Linux Multi-Arch paths (default: auto) --enable-tls Enable Thread-local storage (TLS). --enable-Werror Enable use of compiler -Werror flag --disable-gcc-compat Disable GCC compatibility --disable-pcc-debug Disable PCC debugging --enable-twopass Link PCC as a two-pass compiler --disable-stripping Disable stripping of symbols in installed binaries --enable-native Build the compiler as a native rather than cross-build compiler Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-incdir= Specify the default include path. --with-libdir= Specify the default library path. --with-assembler= Specify alternate assember. --with-linker= Specify alternate linker. --with-libvmf= Use libvmf. --with-yasm Use yasm assembler Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor YACC The `Yet Another Compiler Compiler' implementation to use. Defaults to the first program found out of: `bison -y', `byacc', `yacc'. YFLAGS The list of arguments that will be passed by default to $YACC. This script will default YFLAGS to the empty string to avoid a default value of `-d' given by some make applications. Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . Portable C Compiler home page: . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF Portable C Compiler configure 1.2.0.DEVEL generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_compute_int LINENO EXPR VAR INCLUDES # -------------------------------------------- # Tries to find the compile-time value of EXPR in a program that includes # INCLUDES, setting VAR accordingly. Returns whether the value could be # computed ac_fn_c_compute_int () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if test "$cross_compiling" = yes; then # Depending upon the size, compute the lo and hi bounds. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) >= 0)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_lo=0 ac_mid=0 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=$ac_mid; break else as_fn_arith $ac_mid + 1 && ac_lo=$as_val if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= break fi as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) < 0)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=-1 ac_mid=-1 while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) >= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_lo=$ac_mid; break else as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= break fi as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done else ac_lo= ac_hi= fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext # Binary search between lo and hi bounds. while test "x$ac_lo" != "x$ac_hi"; do as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { static int test_array [1 - 2 * !(($2) <= $ac_mid)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_hi=$ac_mid else as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done case $ac_lo in #(( ?*) eval "$3=\$ac_lo"; ac_retval=0 ;; '') ac_retval=1 ;; esac else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 static long int longval () { return $2; } static unsigned long int ulongval () { return $2; } #include #include int main () { FILE *f = fopen ("conftest.val", "w"); if (! f) return 1; if (($2) < 0) { long int i = longval (); if (i != ($2)) return 1; fprintf (f, "%ld", i); } else { unsigned long int i = ulongval (); if (i != ($2)) return 1; fprintf (f, "%lu", i); } /* Do not output a trailing newline, as this causes \r\n confusion on some platforms. */ return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : echo >>conftest.val; read $3 &5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ( $as_echo "## ------------------------------------ ## ## Report this to pcc@lists.ludd.ltu.se ## ## ------------------------------------ ##" ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* 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_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by Portable C Compiler $as_me 1.2.0.DEVEL, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers config.h" 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 elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 $as_echo_n "checking target system type... " >&6; } if ${ac_cv_target+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$target_alias" = x; then ac_cv_target=$ac_cv_host else ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 $as_echo "$ac_cv_target" >&6; } case $ac_cv_target in *-*-*) ;; *) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;; esac target=$ac_cv_target ac_save_IFS=$IFS; IFS='-' set x $ac_cv_target shift target_cpu=$1 target_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: target_os=$* IFS=$ac_save_IFS case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac # The aliases save the names the user supplied, while $host etc. # will get canonicalized. test -n "$target_alias" && test "$program_prefix$program_suffix$program_transform_name" = \ NONENONEs,x,x, && program_prefix=${target_alias}- abi=unknown endian=little targosver=0 tls=no gcccompat=yes pccdebug=yes stripping=yes native=no useyasm=no stabs=no dwarf=no # allowed: UNSIGNED (4-char u_int), INT (4-char int), SHORT (2-char u_short) wchar_type=INT case "$target_os" in apple) targos=apple abi=classic68k stabs=yes case "$target_cpu" in m68k) targmach=m68k endian=big ;; esac ;; bsd) targos=bsd abi=aout case "$target_cpu" in pdp11) targmach=pdp11 ;; nova) targmach=nova ;; esac wchar_type=USHORT ;; darwin*) targos=darwin abi=macho stabs=yes case "$target_os" in *10.*) targosver=10 ;; *9.*) targosver=9 ;; *8.*) targosver=8 ;; *7.*) targosver=7 ;; esac case "$target_cpu" in i?86) targmach=i386 ;; powerpc) targmach=powerpc endian=big ;; x86_64) targmach=amd64 ;; esac ;; dragonfly*) targos=dragonfly abi=elf stabs=yes tls=yes case "$target_cpu" in i?86) targmach=i386 ;; x86_64) targmach=amd64 ;; esac ;; freebsd*) targos=freebsd abi=elf stabs=yes case "$target_os" in *10.*) targosver=10 ;; *9.*) targosver=9 ;; *8.*) targosver=8 ;; *7.*) targosver=7 ;; *6.*) targosver=6 ;; *5.*) targosver=5 ;; *4.*) targosver=4 ;; esac case "$target_cpu" in i386) targmach=i386 ;; sparc64) targmach=sparc64 endian=big ;; x86_64) targmach=amd64 ;; esac ;; linux-android*) targos=android abi=elf stabs=yes case "$target_cpu" in arm*) targmach=arm ;; i?86) targmach=i386 ;; x86_64) targmach=amd64 ;; mips64el) targmach=mips64 ;; mips64) targmach=mips64 endian=big ;; mipseb) targmach=mips endian=big ;; mips*) targmach=mips ;; esac ;; linux*) targos=linux abi=elf stabs=yes case "$target_cpu" in arm*) targmach=arm ;; i?86) targmach=i386 ;; powerpc*) targmach=powerpc endian=big ;; x86_64) targmach=amd64 ;; mips64el) targmach=mips64 ;; mips64) targmach=mips64 endian=big ;; mipseb) targmach=mips endian=big ;; mips*) targmach=mips ;; esac case "$target_os" in *-musl*) ADD_CPPFLAGS="$ADD_CPPFLAGS -DUSE_MUSL" ;; esac ;; litebsd*) targos=litebsd abi=elf case "$target_cpu" in mips*) targmach=mips ;; esac ;; midnightbsd*) targos=midnightbsd abi=elf stabs=yes case "$target_cpu" in i?86) targmach=i386 ;; sparc64) targmach=sparc64 endian=big ;; esac ;; mingw*) targos=win32 abi=pecoff wchar_type=USHORT targmach=i386 altincdir="c:/mingw/include" altlibdir="c:/mingw/lib" ;; minix*) targos=minix targosver=`uname -v` stabs=yes case "$targosver" in # explicit setting 1.*) # pcc works for 3.1.6 # not tested for 3.1.7 and 3.1.8 targosver=3.1.x abi=aout ;; *3*) # Minix switched to ELF with 3.2 targosver=3.2+ abi=elf ;; *) # default to elf targosver=unknown abi=elf ;; esac case "$target_cpu" in i86) targmach=i86 ;; i?86) targmach=i386 ;; arm*) targmach=arm ;; x86_64) targmach=amd64 ;; esac ;; mirbsd*) targos=mirbsd abi=elf stabs=yes wchar_type=USHORT case "$target_cpu" in i?86) targmach=i386 ;; esac ;; netbsd*) targos=netbsd abi=elf stabs=yes case "$target_os" in *7.*) targosver=7 ;; *6.*) targosver=6 ;; *5.*) targosver=5 ;; *4.*) targosver=4 ;; *3.*) targosver=3 ;; *2.*) targosver=2 ;; *1.*) targosver=1 ;; esac case "$target_cpu" in armeb) targmach=arm endian=big ;; arm*) targmach=arm ;; i?86) targmach=i386 ;; m68k*) targmach=m68k endian=big ;; mips64el) targmach=mips64 ;; mips64) targmach=mips64 endian=big ;; mipseb) targmach=mips endian=big ;; mips*) targmach=mips ;; pdp10) targmach=pdp10 ;; powerpc) targmach=powerpc endian=big ;; riscv32) targmach=riscv32 targmachdir=riscv ;; riscv64) targmach=riscv64 targmachdir=riscv ;; sparc64) targmach=sparc64 endian=big ;; vax) targmach=vax ;; x86_64) targmach=amd64 ;; esac ;; nextstep*) targos=nextstep abi=macho stabs=yes case "$target_cpu" in i?86) targmach=i386 ;; sparc) targmach=sparc endian=big ;; hppa) targmach=hppa endian=big ;; esac ;; openbsd*) targos=openbsd abi=elf stabs=yes case "$target_cpu" in i?86) targmach=i386 ;; vax) targmach=vax ;; mips64el) targmach=mips64 ;; mips64) targmach=mips64 endian=big ;; powerpc) targmach=powerpc endian=big ;; sparc64) targmach=sparc64 endian=big ;; m68k) targmach=m68k endian=big ;; x86_64) targmach=amd64 ;; esac ;; sysv4*) targos=sysv4 abi=elf case "$target_cpu" in i?86) targmach=i386 ;; esac ;; sunos*|solaris*) targos=sunos abi=elf stabs=yes case "$target_cpu" in i?86) targmach=i386 ;; sparc*) targmach=sparc64 endian=big ;; esac ;; windows*|pe*) target_alias=i386-pe targos=win32 abi=pecoff wchar_type=USHORT targmach=i386 ;; *) targos="$target_os" case "$target_cpu" in m16c) targmach=m16c ;; nova) targmach=nova ;; i86) targmach=i86 ;; pdp7) targmach=pdp7 ;; esac ;; esac if test "X$targos" = X -o "X$targmach" = X ; then as_fn_error $? "'$target' is not (yet) supported by pcc." "$LINENO" 5 fi if test "X$targmachdir" = X ; then targmachdir=$targmach fi case "$host_os" in apple) hostos=apple ;; bsd) hostos=bsd ;; darwin*) hostos=darwin ;; dragonfly*) hostos=dragonfly ;; freebsd*) hostos=freebsd ;; linux*) ADD_CPPFLAGS="$ADD_CPPFLAGS -D_BSD_SOURCE" hostos=linux ;; litebsd*) hostos=litebsd ;; midnightbsd*) hostos=midnightbsd ;; mingw*) hostos=win32 ;; minix*) hostos=minix ;; mirbsd*) hostos=mirbsd ;; netbsd*) hostos=netbsd ;; nextstep*) hostos=nextstep ;; openbsd*) hostos=openbsd ;; sunos*|solaris*) ADD_CPPFLAGS="$ADD_CPPFLAGS -D_XOPEN_SOURCE=600" hostos=sunos ;; pe*|windows*) # quick hack for cross-build to win32 host hostos=win32 if "$prefix" = NONE; then prefix="c:/pcc" assembler="yasm.exe -p gnu -f win32" linker="link.exe /nologo" ADD_CPPFLAGS="$ADD_CPPFLAGS -DMSLINKER" fi ;; esac if test "X$endian" = "Xbig" ; then $as_echo "#define TARGET_BIG_ENDIAN 1" >>confdefs.h else $as_echo "#define TARGET_LITTLE_ENDIAN 1" >>confdefs.h fi case "$abi" in elf*) $as_echo "#define ELFABI 1" >>confdefs.h ;; aout) $as_echo "#define AOUTABI 1" >>confdefs.h ;; macho) $as_echo "#define MACHOABI 1" >>confdefs.h ;; coff) $as_echo "#define COFFABI 1" >>confdefs.h ;; ecoff) $as_echo "#define ECOFFABI 1" >>confdefs.h ;; pecoff) $as_echo "#define PECOFFABI 1" >>confdefs.h ;; classic68k) $as_echo "#define CLASSIC68K 1" >>confdefs.h ;; esac if test "$stabs" = "yes"; then $as_echo "#define STABS 1" >>confdefs.h fi if test "$dwarf" = "yes"; then $as_echo "#define DWARF 1" >>confdefs.h fi # Specify alternate assembler, linker, include and lib paths # Check whether --enable-multiarch was given. if test "${enable_multiarch+set}" = set; then : enableval=$enable_multiarch; multiarch=$enableval else multiarch=auto fi # Check whether --with-incdir was given. if test "${with_incdir+set}" = set; then : withval=$with_incdir; altincdir=$withval fi # Check whether --with-libdir was given. if test "${with_libdir+set}" = set; then : withval=$with_libdir; altlibdir=$withval fi # Check whether --with-assembler was given. if test "${with_assembler+set}" = set; then : withval=$with_assembler; assembler=$withval fi # Check whether --with-linker was given. if test "${with_linker+set}" = set; then : withval=$with_linker; linker=$withval fi # Check whether --with-libvmf was given. if test "${with_libvmf+set}" = set; then : withval=$with_libvmf; libvmf=$withval else libvmf=no fi # Check whether --enable-tls was given. if test "${enable_tls+set}" = set; then : enableval=$enable_tls; tls=$enableval fi if test "$tls" = "yes"; then $as_echo "#define TLS 1" >>confdefs.h fi # Check whether --enable-Werror was given. if test "${enable_Werror+set}" = set; then : enableval=$enable_Werror; werror=$enableval fi if test "$werror" = "yes"; then ADD_CFLAGS="$ADD_CFLAGS -Werror" fi # Check whether --enable-gcc-compat was given. if test "${enable_gcc_compat+set}" = set; then : enableval=$enable_gcc_compat; gcccompat=$enableval fi if test "$gcccompat" = "yes"; then ADD_CPPFLAGS="$ADD_CPPFLAGS -DGCC_COMPAT"; fi # Check whether --enable-pcc-debug was given. if test "${enable_pcc_debug+set}" = set; then : enableval=$enable_pcc_debug; pccdebug=$enableval fi if test "$pccdebug" = "yes"; then ADD_CPPFLAGS="$ADD_CPPFLAGS -DPCC_DEBUG"; fi # Check whether --enable-twopass was given. if test "${enable_twopass+set}" = set; then : enableval=$enable_twopass; twopass=$enableval fi if test "$twopass" = "yes"; then ADD_CPPFLAGS="$ADD_CPPFLAGS -DTWOPASS"; CCNAMES='$(BINPREFIX)cc0$(EXEEXT) $(BINPREFIX)cc1$(EXEEXT)' CF0='-DPASS1' CF1='-DPASS2' else CCNAMES='$(BINPREFIX)ccom$(EXEEXT)' fi # Check whether --enable-stripping was given. if test "${enable_stripping+set}" = set; then : enableval=$enable_stripping; stripping=$enableval fi if test "$stripping" = "yes"; then if test -z "$INSTALL_PROGRAM"; then INSTALL_PROGRAM='${INSTALL} -s' else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Installed binaries may be unstripped" >&5 $as_echo "$as_me: WARNING: Installed binaries may be unstripped" >&2;} fi fi # Check whether --with-yasm was given. if test "${with_yasm+set}" = set; then : withval=$with_yasm; useyasm=$withval fi if test "$useyasm" = "yes"; then assembler="yasm" ADD_CPPFLAGS="$ADD_CPPFLAGS -DUSE_YASM" fi # Check whether --enable-native was given. if test "${enable_native+set}" = set; then : enableval=$enable_native; native=$enableval fi # Setup for ubuntu multiarch multiarch_path= case x$multiarch in xno) ;; xyes) multiarch_path=`dpkg-architecture -qDEB_HOST_MULTIARCH 2>/dev/null` || multiarch_path= case $multiarch_path in *-*-*) ;; *) as_fn_error $? "Cannot determine Multi-Arch path '$multiarch_path'!" "$LINENO" 5 ;; esac ;; xauto|x) multiarch_path=`dpkg-architecture -qDEB_HOST_MULTIARCH 2>/dev/null` || multiarch_path= case x$multiarch_path in x*-*-*) ;; x) ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Ignoring unrecognised Multi-Arch path '$multiarch_path'!" >&5 $as_echo "$as_me: WARNING: Ignoring unrecognised Multi-Arch path '$multiarch_path'!" >&2;} multiarch_path= ;; esac ;; x*-*-*) multiarch_path=$multiarch ;; *) as_fn_error $? "Ignoring unrecognised Multi-Arch path '$multiarch_path'!" "$LINENO" 5 ;; esac if test -n "$multiarch_path"; then cat >>confdefs.h <<_ACEOF #define MULTIARCH_PATH "$multiarch_path" _ACEOF multiarch="\"$multiarch_path\"" else multiarch="(no)" fi # setup for building a cross-compiler if test "X$native" = "Xyes" -o "X$target_alias" = "X$host_alias" -o "X$target_alias" = "X"; then BINPREFIX="" else BINPREFIX="${target_alias}-" test "X$prefix" = XNONE && prefix="$ac_default_prefix" test "X$exec_prefix" = XNONE && exec_prefix="${prefix}" if test -z "$altincdir"; then altincdir=${exec_prefix}/${target_alias}/include fi if test -z "$altlibdir"; then altlibdir=${exec_prefix}/${target_alias}/lib fi if test -z "$assembler"; then assembler=${BINPREFIX}as fi if test -z "$linker"; then linker=${BINPREFIX}ld fi preprocessor="${BINPREFIX}cpp" compiler="${BINPREFIX}ccom" $as_echo "#define CROSS_COMPILING 1" >>confdefs.h fi if test -n "$altincdir"; then cat >>confdefs.h <<_ACEOF #define STDINC "$altincdir" _ACEOF fi if test -n "$altlibdir"; then cat >>confdefs.h <<_ACEOF #define LIBDIR "${altlibdir}/" _ACEOF fi if test -n "$assembler"; then cat >>confdefs.h <<_ACEOF #define ASSEMBLER "$assembler" _ACEOF fi if test -n "$linker"; then cat >>confdefs.h <<_ACEOF #define LINKER "$linker" _ACEOF fi if test -n "$preprocessor"; then cat >>confdefs.h <<_ACEOF #define PREPROCESSOR "$preprocessor" _ACEOF fi if test -n "$compiler"; then cat >>confdefs.h <<_ACEOF #define COMPILER "$compiler" _ACEOF fi case $wchar_type in USHORT) wchar_size=2 ;; UNSIGNED|INT) wchar_size=4 ;; *) as_fn_error $? "Unknown wchar_t '$wchar_type'." "$LINENO" 5 ;; esac cat >>confdefs.h <<_ACEOF #define WCHAR_TYPE $wchar_type _ACEOF cat >>confdefs.h <<_ACEOF #define WCHAR_SIZE $wchar_size _ACEOF # check for additional compiler flags ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi 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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_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 $# != 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 ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu DESIRED_FLAGS="-Wall -Wmissing-prototypes -Wstrict-prototypes -Wshadow -Wsign-compare -Wtruncate" for flag in $DESIRED_FLAGS do { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts $flag" >&5 $as_echo_n "checking whether $CC accepts $flag... " >&6; } cflags="$CFLAGS" CFLAGS="$CFLAGS $flag -Werror" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : use_flag=yes else use_flag=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="$cflags" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $use_flag" >&5 $as_echo "$use_flag" >&6; } if test $use_flag = yes; then ADD_CFLAGS="$ADD_CFLAGS $flag" fi done # setup for cross-compiling mkext { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a C compiler for mkext" >&5 $as_echo_n "checking for a C compiler for mkext... " >&6; } if test $cross_compiling = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: cross compiling" >&5 $as_echo "cross compiling" >&6; } for ac_prog in pcc gcc cc do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC_FOR_BUILD+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC_FOR_BUILD"; then ac_cv_prog_CC_FOR_BUILD="$CC_FOR_BUILD" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC_FOR_BUILD="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC_FOR_BUILD=$ac_cv_prog_CC_FOR_BUILD if test -n "$CC_FOR_BUILD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC_FOR_BUILD" >&5 $as_echo "$CC_FOR_BUILD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC_FOR_BUILD" && break done else { $as_echo "$as_me:${as_lineno-$LINENO}: result: not cross compiling" >&5 $as_echo "not cross compiling" >&6; } CC_FOR_BUILD=${CC-cc} fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C99 printf size specifiers" >&5 $as_echo_n "checking for C99 printf size specifiers... " >&6; } if ${ac_cv_have_c99_format+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_have_c99_format=yes else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { char buf[64]; if (sprintf(buf, "%lld%hhd%jd%zd%td", (long long int)1, (char)2, (intmax_t)3, (size_t)4, (ptrdiff_t)5) != 5) exit(1); else if (strcmp(buf, "12345")) exit(2); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_have_c99_format=yes else ac_cv_have_c99_format=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_c99_format" >&5 $as_echo "$ac_cv_have_c99_format" >&6; } if test $ac_cv_have_c99_format = yes; then $as_echo "#define HAVE_C99_FORMAT 1" >>confdefs.h fi # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. # This bug is HP SR number 8606223364. { $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int *" >&5 $as_echo_n "checking size of int *... " >&6; } if ${ac_cv_sizeof_int_p+:} false; then : $as_echo_n "(cached) " >&6 else if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int *))" "ac_cv_sizeof_int_p" "$ac_includes_default"; then : else if test "$ac_cv_type_int_p" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot compute sizeof (int *) See \`config.log' for more details" "$LINENO" 5; } else ac_cv_sizeof_int_p=0 fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int_p" >&5 $as_echo "$ac_cv_sizeof_int_p" >&6; } cat >>confdefs.h <<_ACEOF #define SIZEOF_INT_P $ac_cv_sizeof_int_p _ACEOF # Byteorder of host { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 $as_echo_n "checking whether byte ordering is bigendian... " >&6; } if ${ac_cv_c_bigendian+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_bigendian=unknown # See if we're dealing with a universal compiler. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __APPLE_CC__ not a universal capable compiler #endif typedef int dummy; _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # Check for potential -arch flags. It is not universal unless # there are at least two -arch flags with different values. ac_arch= ac_prev= for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do if test -n "$ac_prev"; then case $ac_word in i?86 | x86_64 | ppc | ppc64) if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then ac_arch=$ac_word else ac_cv_c_bigendian=universal break fi ;; esac ac_prev= elif test "x$ac_word" = "x-arch"; then ac_prev=arch fi done fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_c_bigendian = unknown; then # See if sys/param.h defines the BYTE_ORDER macro. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { #if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ && LITTLE_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # It does; now see whether it defined to BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { #if BYTE_ORDER != BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_bigendian=yes else ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { #if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) bogus endian macros #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : # It does; now see whether it defined to _BIG_ENDIAN or not. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { #ifndef _BIG_ENDIAN not big endian #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_bigendian=yes else ac_cv_c_bigendian=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi if test $ac_cv_c_bigendian = unknown; then # Compile a test program. if test "$cross_compiling" = yes; then : # Try to guess by grepping values from an object file. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; int use_ascii (int i) { return ascii_mm[i] + ascii_ii[i]; } short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; int use_ebcdic (int i) { return ebcdic_mm[i] + ebcdic_ii[i]; } extern int foo; int main () { return use_ascii (foo) == use_ebcdic (foo); ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then ac_cv_c_bigendian=yes fi if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then if test "$ac_cv_c_bigendian" = unknown; then ac_cv_c_bigendian=no else # finding both strings is unlikely to happen, but who knows? ac_cv_c_bigendian=unknown fi fi fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { /* Are we little or big endian? From Harbison&Steele. */ union { long int l; char c[sizeof (long int)]; } u; u.l = 1; return u.c[sizeof (long int) - 1] == 1; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_c_bigendian=no else ac_cv_c_bigendian=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 $as_echo "$ac_cv_c_bigendian" >&6; } case $ac_cv_c_bigendian in #( yes) $as_echo "#define HOST_BIG_ENDIAN 1" >>confdefs.h ;; #( no) $as_echo "#define HOST_LITTLE_ENDIAN 1" >>confdefs.h ;; #( universal) $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h ;; #( *) as_fn_error $? "unknown endianness presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; esac # Checks for programs. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi # 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 # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir 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. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&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_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' 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 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_YACC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$YACC"; then ac_cv_prog_YACC="$YACC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_YACC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi YACC=$ac_cv_prog_YACC if test -n "$YACC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $YACC" >&5 $as_echo "$YACC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$YACC" && break done test -n "$YACC" || YACC="yacc" for ac_prog in flex lex do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_LEX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$LEX"; then ac_cv_prog_LEX="$LEX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_LEX="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi LEX=$ac_cv_prog_LEX if test -n "$LEX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LEX" >&5 $as_echo "$LEX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$LEX" && break done test -n "$LEX" || LEX=":" if test "x$LEX" != "x:"; then cat >conftest.l <<_ACEOF %% a { ECHO; } b { REJECT; } c { yymore (); } d { yyless (1); } e { /* IRIX 6.5 flex 2.5.4 underquotes its yyless argument. */ yyless ((input () != 0)); } f { unput (yytext[0]); } . { BEGIN INITIAL; } %% #ifdef YYTEXT_POINTER extern char *yytext; #endif int main (void) { return ! yylex () + ! yywrap (); } _ACEOF { { ac_try="$LEX conftest.l" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$LEX conftest.l") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking lex output file root" >&5 $as_echo_n "checking lex output file root... " >&6; } if ${ac_cv_prog_lex_root+:} false; then : $as_echo_n "(cached) " >&6 else if test -f lex.yy.c; then ac_cv_prog_lex_root=lex.yy elif test -f lexyy.c; then ac_cv_prog_lex_root=lexyy else as_fn_error $? "cannot find output from $LEX; giving up" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_root" >&5 $as_echo "$ac_cv_prog_lex_root" >&6; } LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root if test -z "${LEXLIB+set}"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking lex library" >&5 $as_echo_n "checking lex library... " >&6; } if ${ac_cv_lib_lex+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_LIBS=$LIBS ac_cv_lib_lex='none needed' for ac_lib in '' -lfl -ll; do LIBS="$ac_lib $ac_save_LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ `cat $LEX_OUTPUT_ROOT.c` _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_lex=$ac_lib fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext test "$ac_cv_lib_lex" != 'none needed' && break done LIBS=$ac_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lex" >&5 $as_echo "$ac_cv_lib_lex" >&6; } test "$ac_cv_lib_lex" != 'none needed' && LEXLIB=$ac_cv_lib_lex fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether yytext is a pointer" >&5 $as_echo_n "checking whether yytext is a pointer... " >&6; } if ${ac_cv_prog_lex_yytext_pointer+:} false; then : $as_echo_n "(cached) " >&6 else # POSIX says lex can declare yytext either as a pointer or an array; the # default is implementation-dependent. Figure out which it is, since # not all implementations provide the %pointer and %array declarations. ac_cv_prog_lex_yytext_pointer=no ac_save_LIBS=$LIBS LIBS="$LEXLIB $ac_save_LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define YYTEXT_POINTER 1 `cat $LEX_OUTPUT_ROOT.c` _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_prog_lex_yytext_pointer=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_yytext_pointer" >&5 $as_echo "$ac_cv_prog_lex_yytext_pointer" >&6; } if test $ac_cv_prog_lex_yytext_pointer = yes; then $as_echo "#define YYTEXT_POINTER 1" >>confdefs.h fi rm -f conftest.l $LEX_OUTPUT_ROOT.c fi # Checks for libraries. if test $libvmf != no ; then LIBS=-lvmf $as_echo "#define LIBVMF 1" >>confdefs.h if test $libvmf != yes ; then LDFLAGS=-L$libvmf fi fi # Checks for header files. # AC_CHECK_HEADERS([fcntl.h stdlib.h string.h unistd.h]) for ac_header in string.h malloc.h libgen.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sys/wait.h that is POSIX.1 compatible" >&5 $as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; } if ${ac_cv_header_sys_wait_h+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #ifndef WEXITSTATUS # define WEXITSTATUS(stat_val) ((unsigned int) (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; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_sys_wait_h=yes else ac_cv_header_sys_wait_h=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_wait_h" >&5 $as_echo "$ac_cv_header_sys_wait_h" >&6; } if test $ac_cv_header_sys_wait_h = yes; then $as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h fi # Checks for library functions. ## AC_FUNC_STRTOD # AC_FUNC_VPRINTF # AC_CHECK_FUNCS([memset strchr strdup strrchr strtol]) for ac_func in strtold vsnprintf snprintf mkstemp strlcat strlcpy getopt ffs vfork do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" if test "x$ac_cv_type_size_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define size_t unsigned int _ACEOF fi # The Ultrix 4.2 mips builtin alloca declared by alloca.h only works # for constant arguments. Useless! { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working alloca.h" >&5 $as_echo_n "checking for working alloca.h... " >&6; } if ${ac_cv_working_alloca_h+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { char *p = (char *) alloca (2 * sizeof (int)); if (p) return 0; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_working_alloca_h=yes else ac_cv_working_alloca_h=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_alloca_h" >&5 $as_echo "$ac_cv_working_alloca_h" >&6; } if test $ac_cv_working_alloca_h = yes; then $as_echo "#define HAVE_ALLOCA_H 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for alloca" >&5 $as_echo_n "checking for alloca... " >&6; } if ${ac_cv_func_alloca_works+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __GNUC__ # define alloca __builtin_alloca #else # ifdef _MSC_VER # include # define alloca _alloca # elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) # include # else # ifdef HAVE_ALLOCA_H # include # else # ifdef _AIX #pragma alloca # else # ifndef alloca /* predefined by HP cc +Olibcalls */ void *alloca (size_t); # endif # endif # endif # endif #endif int main () { char *p = (char *) alloca (1); if (p) return 0; ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_func_alloca_works=yes else ac_cv_func_alloca_works=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_alloca_works" >&5 $as_echo "$ac_cv_func_alloca_works" >&6; } if test $ac_cv_func_alloca_works = yes; then $as_echo "#define HAVE_ALLOCA 1" >>confdefs.h else # The SVR3 libPW and SVR4 libucb both contain incompatible functions # that cause trouble. Some versions do not even contain alloca or # contain a buggy version. If you still want to use their alloca, # use ar to extract alloca.o from them instead of compiling alloca.c. ALLOCA=\${LIBOBJDIR}alloca.$ac_objext $as_echo "#define C_ALLOCA 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether \`alloca.c' needs Cray hooks" >&5 $as_echo_n "checking whether \`alloca.c' needs Cray hooks... " >&6; } if ${ac_cv_os_cray+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined CRAY && ! defined CRAY2 webecray #else wenotbecray #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "webecray" >/dev/null 2>&1; then : ac_cv_os_cray=yes else ac_cv_os_cray=no fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_os_cray" >&5 $as_echo "$ac_cv_os_cray" >&6; } if test $ac_cv_os_cray = yes; then for ac_func in _getb67 GETB67 getb67; do as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define CRAY_STACKSEG_END $ac_func _ACEOF break fi done fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking stack direction for C alloca" >&5 $as_echo_n "checking stack direction for C alloca... " >&6; } if ${ac_cv_c_stack_direction+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_c_stack_direction=0 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int find_stack_direction (int *addr, int depth) { int dir, dummy = 0; if (! addr) addr = &dummy; *addr = addr < &dummy ? 1 : addr == &dummy ? 0 : -1; dir = depth ? find_stack_direction (addr, depth - 1) : 0; return dir + dummy; } int main (int argc, char **argv) { return find_stack_direction (0, argc + !argv + 20) < 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_c_stack_direction=1 else ac_cv_c_stack_direction=-1 fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_stack_direction" >&5 $as_echo "$ac_cv_c_stack_direction" >&6; } cat >>confdefs.h <<_ACEOF #define STACK_DIRECTION $ac_cv_c_stack_direction _ACEOF fi pcc_major=`echo $PACKAGE_VERSION | awk -F. '{print $1}'` pcc_minor=`echo $PACKAGE_VERSION | awk -F. '{print $2}'` pcc_minorminor=`echo $PACKAGE_VERSION | awk -F. '{print $3}'` test -n "$MPVERSION" && MPVERSION=", $MPVERSION" versstr="\"$PACKAGE_STRING `cat $srcdir/DATESTAMP` for $target$MPVERSION\"" targstr="\"$target$MPVERSION\"" cat >>confdefs.h <<_ACEOF #define PCC_MAJOR $pcc_major _ACEOF cat >>confdefs.h <<_ACEOF #define PCC_MINOR $pcc_minor _ACEOF cat >>confdefs.h <<_ACEOF #define PCC_MINORMINOR $pcc_minorminor _ACEOF cat >>confdefs.h <<_ACEOF #define VERSSTR $versstr _ACEOF cat >>confdefs.h <<_ACEOF #define TARGSTR $targstr _ACEOF ac_config_files="$ac_config_files Makefile cc/Makefile cc/cc/Makefile cc/cpp/Makefile cc/ccom/Makefile cc/cxxcom/Makefile cc/driver/Makefile f77/Makefile f77/f77/Makefile f77/fcom/Makefile" cat >confcache <<\_ACEOF # 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, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # 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. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by Portable C Compiler $as_me 1.2.0.DEVEL, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Report bugs to . Portable C Compiler home page: ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ Portable C Compiler config.status 1.2.0.DEVEL configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "cc/Makefile") CONFIG_FILES="$CONFIG_FILES cc/Makefile" ;; "cc/cc/Makefile") CONFIG_FILES="$CONFIG_FILES cc/cc/Makefile" ;; "cc/cpp/Makefile") CONFIG_FILES="$CONFIG_FILES cc/cpp/Makefile" ;; "cc/ccom/Makefile") CONFIG_FILES="$CONFIG_FILES cc/ccom/Makefile" ;; "cc/cxxcom/Makefile") CONFIG_FILES="$CONFIG_FILES cc/cxxcom/Makefile" ;; "cc/driver/Makefile") CONFIG_FILES="$CONFIG_FILES cc/driver/Makefile" ;; "f77/Makefile") CONFIG_FILES="$CONFIG_FILES f77/Makefile" ;; "f77/f77/Makefile") CONFIG_FILES="$CONFIG_FILES f77/f77/Makefile" ;; "f77/fcom/Makefile") CONFIG_FILES="$CONFIG_FILES f77/fcom/Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #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. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi eval "exec_prefix=$exec_prefix" eval "bindir=$bindir" eval "libexecdir=$libexecdir" echo echo "Target CPU is .................... ${targmach}" echo "Target ABI is .................... ${abi}" echo "Target OS is ..................... ${targos}" echo "Compiler is called ............... ${BINPREFIX}pcc${EXEEXT}" echo "Installing compiler into ......... ${bindir}" echo "Installing pre-processor into .... ${libexecdir}" echo "Using assembler .................. ${assembler-}" echo "Using linker ..................... ${linker-}" echo "Using Multi-Arch path ............ ${multiarch}" echo "Using include path ............... ${altincdir-}" echo "Using library path ............... ${altlibdir-}" echo "Use libvmf ....................... $libvmf" echo "Has TLS support .................. $tls" echo "Has GCC compatibility ............ $gcccompat" echo "Has PCC debugging ................ $pccdebug" echo "Type of wchar_t is ............... ${wchar_type} (${wchar_size} chars)" echo echo "Configure finished. Do 'make && make install' to compile and install. " pcc-20181216/configure.ac010064400017500000000000000420671337532126700137740ustar raggewheel -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ(2.59) AC_INIT([Portable C Compiler], [1.2.0.DEVEL], [pcc@lists.ludd.ltu.se], [pcc], [http://pcc.ludd.ltu.se/]) AC_CONFIG_HEADER([config.h]) AC_CANONICAL_TARGET abi=unknown endian=little targosver=0 tls=no gcccompat=yes pccdebug=yes stripping=yes native=no useyasm=no stabs=no dwarf=no # allowed: UNSIGNED (4-char u_int), INT (4-char int), SHORT (2-char u_short) wchar_type=INT case "$target_os" in apple) targos=apple abi=classic68k stabs=yes case "$target_cpu" in m68k) targmach=m68k endian=big ;; esac ;; bsd) targos=bsd abi=aout case "$target_cpu" in pdp11) targmach=pdp11 ;; nova) targmach=nova ;; esac wchar_type=USHORT ;; darwin*) targos=darwin abi=macho stabs=yes case "$target_os" in *10.*) targosver=10 ;; *9.*) targosver=9 ;; *8.*) targosver=8 ;; *7.*) targosver=7 ;; esac case "$target_cpu" in i?86) targmach=i386 ;; powerpc) targmach=powerpc endian=big ;; x86_64) targmach=amd64 ;; esac ;; dragonfly*) targos=dragonfly abi=elf stabs=yes tls=yes case "$target_cpu" in i?86) targmach=i386 ;; x86_64) targmach=amd64 ;; esac ;; freebsd*) targos=freebsd abi=elf stabs=yes case "$target_os" in *10.*) targosver=10 ;; *9.*) targosver=9 ;; *8.*) targosver=8 ;; *7.*) targosver=7 ;; *6.*) targosver=6 ;; *5.*) targosver=5 ;; *4.*) targosver=4 ;; esac case "$target_cpu" in i386) targmach=i386 ;; sparc64) targmach=sparc64 endian=big ;; x86_64) targmach=amd64 ;; esac ;; linux-android*) targos=android abi=elf stabs=yes case "$target_cpu" in arm*) targmach=arm ;; i?86) targmach=i386 ;; x86_64) targmach=amd64 ;; mips64el) targmach=mips64 ;; mips64) targmach=mips64 endian=big ;; mipseb) targmach=mips endian=big ;; mips*) targmach=mips ;; esac ;; linux*) targos=linux abi=elf stabs=yes case "$target_cpu" in arm*) targmach=arm ;; i?86) targmach=i386 ;; powerpc*) targmach=powerpc endian=big ;; x86_64) targmach=amd64 ;; mips64el) targmach=mips64 ;; mips64) targmach=mips64 endian=big ;; mipseb) targmach=mips endian=big ;; mips*) targmach=mips ;; esac case "$target_os" in *-musl*) ADD_CPPFLAGS="$ADD_CPPFLAGS -DUSE_MUSL" ;; esac ;; litebsd*) targos=litebsd abi=elf case "$target_cpu" in mips*) targmach=mips ;; esac ;; midnightbsd*) targos=midnightbsd abi=elf stabs=yes case "$target_cpu" in i?86) targmach=i386 ;; sparc64) targmach=sparc64 endian=big ;; esac ;; mingw*) targos=win32 abi=pecoff wchar_type=USHORT targmach=i386 altincdir="c:/mingw/include" altlibdir="c:/mingw/lib" ;; minix*) targos=minix targosver=`uname -v` stabs=yes case "$targosver" in # explicit setting 1.*) # pcc works for 3.1.6 # not tested for 3.1.7 and 3.1.8 targosver=3.1.x abi=aout ;; *3*) # Minix switched to ELF with 3.2 targosver=3.2+ abi=elf ;; *) # default to elf targosver=unknown abi=elf ;; esac case "$target_cpu" in i86) targmach=i86 ;; i?86) targmach=i386 ;; arm*) targmach=arm ;; x86_64) targmach=amd64 ;; esac ;; mirbsd*) targos=mirbsd abi=elf stabs=yes wchar_type=USHORT case "$target_cpu" in i?86) targmach=i386 ;; esac ;; netbsd*) targos=netbsd abi=elf stabs=yes case "$target_os" in *7.*) targosver=7 ;; *6.*) targosver=6 ;; *5.*) targosver=5 ;; *4.*) targosver=4 ;; *3.*) targosver=3 ;; *2.*) targosver=2 ;; *1.*) targosver=1 ;; esac case "$target_cpu" in armeb) targmach=arm endian=big ;; arm*) targmach=arm ;; i?86) targmach=i386 ;; m68k*) targmach=m68k endian=big ;; mips64el) targmach=mips64 ;; mips64) targmach=mips64 endian=big ;; mipseb) targmach=mips endian=big ;; mips*) targmach=mips ;; pdp10) targmach=pdp10 ;; powerpc) targmach=powerpc endian=big ;; riscv32) targmach=riscv32 targmachdir=riscv ;; riscv64) targmach=riscv64 targmachdir=riscv ;; sparc64) targmach=sparc64 endian=big ;; vax) targmach=vax ;; x86_64) targmach=amd64 ;; esac ;; nextstep*) targos=nextstep abi=macho stabs=yes case "$target_cpu" in i?86) targmach=i386 ;; sparc) targmach=sparc endian=big ;; hppa) targmach=hppa endian=big ;; esac ;; openbsd*) targos=openbsd abi=elf stabs=yes case "$target_cpu" in i?86) targmach=i386 ;; vax) targmach=vax ;; mips64el) targmach=mips64 ;; mips64) targmach=mips64 endian=big ;; powerpc) targmach=powerpc endian=big ;; sparc64) targmach=sparc64 endian=big ;; m68k) targmach=m68k endian=big ;; x86_64) targmach=amd64 ;; esac ;; sysv4*) targos=sysv4 abi=elf case "$target_cpu" in i?86) targmach=i386 ;; esac ;; sunos*|solaris*) targos=sunos abi=elf stabs=yes case "$target_cpu" in i?86) targmach=i386 ;; sparc*) targmach=sparc64 endian=big ;; esac ;; windows*|pe*) target_alias=i386-pe targos=win32 abi=pecoff wchar_type=USHORT targmach=i386 ;; *) targos="$target_os" case "$target_cpu" in m16c) targmach=m16c ;; nova) targmach=nova ;; i86) targmach=i86 ;; pdp7) targmach=pdp7 ;; esac ;; esac if test "X$targos" = X -o "X$targmach" = X ; then AC_MSG_ERROR(['$target' is not (yet) supported by pcc.]) fi if test "X$targmachdir" = X ; then targmachdir=$targmach fi case "$host_os" in apple) hostos=apple ;; bsd) hostos=bsd ;; darwin*) hostos=darwin ;; dragonfly*) hostos=dragonfly ;; freebsd*) hostos=freebsd ;; linux*) ADD_CPPFLAGS="$ADD_CPPFLAGS -D_BSD_SOURCE" hostos=linux ;; litebsd*) hostos=litebsd ;; midnightbsd*) hostos=midnightbsd ;; mingw*) hostos=win32 ;; minix*) hostos=minix ;; mirbsd*) hostos=mirbsd ;; netbsd*) hostos=netbsd ;; nextstep*) hostos=nextstep ;; openbsd*) hostos=openbsd ;; sunos*|solaris*) ADD_CPPFLAGS="$ADD_CPPFLAGS -D_XOPEN_SOURCE=600" hostos=sunos ;; pe*|windows*) # quick hack for cross-build to win32 host hostos=win32 if "$prefix" = NONE; then prefix="c:/pcc" assembler="yasm.exe -p gnu -f win32" linker="link.exe /nologo" ADD_CPPFLAGS="$ADD_CPPFLAGS -DMSLINKER" fi ;; esac if test "X$endian" = "Xbig" ; then AC_DEFINE(TARGET_BIG_ENDIAN, 1, [Define if target defaults to BIG endian]) else AC_DEFINE(TARGET_LITTLE_ENDIAN, 1, [Define if target defaults to LITTLE endian]) fi case "$abi" in elf*) AC_DEFINE(ELFABI, 1, [Using ELF ABI]) ;; aout) AC_DEFINE(AOUTABI, 1, [Using a.out ABI]) ;; macho) AC_DEFINE(MACHOABI, 1, [Using Mach-O ABI]) ;; coff) AC_DEFINE(COFFABI, 1, [Using COFF ABI]) ;; ecoff) AC_DEFINE(ECOFFABI, 1, [Using ECOFF ABI]) ;; pecoff) AC_DEFINE(PECOFFABI, 1, [Using PE/COFF ABI]) ;; classic68k) AC_DEFINE(CLASSIC68K, 1, [Using Classic 68k ABI]) ;; esac if test "$stabs" = "yes"; then AC_DEFINE(STABS, 1, [Enable STABS debugging output]) fi if test "$dwarf" = "yes"; then AC_DEFINE(DWARF, 1, [Enable DWARF debugging output]) fi # Specify alternate assembler, linker, include and lib paths AC_ARG_ENABLE(multiarch, AS_HELP_STRING([--enable-multiarch=yes/no/auto/], [Enable use of Linux Multi-Arch paths (default: auto)]), [multiarch=$enableval], [multiarch=auto]) AC_ARG_WITH(incdir, AS_HELP_STRING([--with-incdir=], [Specify the default include path.]), altincdir=$withval, []) AC_ARG_WITH(libdir, AS_HELP_STRING([--with-libdir=], [Specify the default library path.]), altlibdir=$withval, []) AC_ARG_WITH(assembler, AS_HELP_STRING([--with-assembler=], [Specify alternate assember.]), assembler=$withval, []) AC_ARG_WITH(linker, AS_HELP_STRING([--with-linker=], [Specify alternate linker.]), linker=$withval, []) AC_ARG_WITH(libvmf, AS_HELP_STRING([--with-libvmf=], [Use libvmf.]), libvmf=$withval, libvmf=no) AC_ARG_ENABLE(tls, AS_HELP_STRING([--enable-tls], [Enable Thread-local storage (TLS).]), [tls=$enableval], []) if test "$tls" = "yes"; then AC_DEFINE(TLS, 1, [Enable thread-local storage (TLS).]) fi AC_ARG_ENABLE(Werror, AS_HELP_STRING([--enable-Werror], [Enable use of compiler -Werror flag]), [werror=$enableval], []) if test "$werror" = "yes"; then ADD_CFLAGS="$ADD_CFLAGS -Werror" fi AC_ARG_ENABLE(gcc-compat, AS_HELP_STRING([--disable-gcc-compat], [Disable GCC compatibility]), [gcccompat=$enableval], []) if test "$gcccompat" = "yes"; then ADD_CPPFLAGS="$ADD_CPPFLAGS -DGCC_COMPAT"; fi AC_ARG_ENABLE(pcc-debug, AS_HELP_STRING([--disable-pcc-debug], [Disable PCC debugging]), [pccdebug=$enableval], []) if test "$pccdebug" = "yes"; then ADD_CPPFLAGS="$ADD_CPPFLAGS -DPCC_DEBUG"; fi AC_ARG_ENABLE(twopass, AS_HELP_STRING([--enable-twopass], [Link PCC as a two-pass compiler]), [twopass=$enableval], []) if test "$twopass" = "yes"; then ADD_CPPFLAGS="$ADD_CPPFLAGS -DTWOPASS"; CCNAMES='$(BINPREFIX)cc0$(EXEEXT) $(BINPREFIX)cc1$(EXEEXT)' CF0='-DPASS1' CF1='-DPASS2' else CCNAMES='$(BINPREFIX)ccom$(EXEEXT)' fi AC_ARG_ENABLE(stripping, AS_HELP_STRING([--disable-stripping], [Disable stripping of symbols in installed binaries]), [stripping=$enableval], []) if test "$stripping" = "yes"; then if test -z "$INSTALL_PROGRAM"; then INSTALL_PROGRAM='${INSTALL} -s' else AC_MSG_WARN([Installed binaries may be unstripped]) fi fi AC_ARG_WITH(yasm, AS_HELP_STRING([--with-yasm], [Use yasm assembler]), useyasm=$withval, []) if test "$useyasm" = "yes"; then assembler="yasm" ADD_CPPFLAGS="$ADD_CPPFLAGS -DUSE_YASM" fi AC_ARG_ENABLE(native, AS_HELP_STRING([--enable-native], [Build the compiler as a native rather than cross-build compiler]), [native=$enableval], []) # Setup for ubuntu multiarch multiarch_path= case x$multiarch in xno) ;; xyes) multiarch_path=`dpkg-architecture -qDEB_HOST_MULTIARCH 2>/dev/null` || multiarch_path= case $multiarch_path in *-*-*) ;; *) AC_MSG_ERROR([Cannot determine Multi-Arch path '$multiarch_path'!]) ;; esac ;; xauto|x) multiarch_path=`dpkg-architecture -qDEB_HOST_MULTIARCH 2>/dev/null` || multiarch_path= case x$multiarch_path in x*-*-*) ;; x) ;; *) AC_MSG_WARN([Ignoring unrecognised Multi-Arch path '$multiarch_path'!]) multiarch_path= ;; esac ;; x*-*-*) multiarch_path=$multiarch ;; *) AC_MSG_ERROR([Ignoring unrecognised Multi-Arch path '$multiarch_path'!]) ;; esac if test -n "$multiarch_path"; then AC_DEFINE_UNQUOTED([MULTIARCH_PATH], ["$multiarch_path"], [Define target Multi-Arch path]) multiarch="\"$multiarch_path\"" else multiarch="(no)" fi # setup for building a cross-compiler if test "X$native" = "Xyes" -o "X$target_alias" = "X$host_alias" -o "X$target_alias" = "X"; then BINPREFIX="" else BINPREFIX="${target_alias}-" test "X$prefix" = XNONE && prefix="$ac_default_prefix" test "X$exec_prefix" = XNONE && exec_prefix="${prefix}" if test -z "$altincdir"; then altincdir=${exec_prefix}/${target_alias}/include fi if test -z "$altlibdir"; then altlibdir=${exec_prefix}/${target_alias}/lib fi if test -z "$assembler"; then assembler=${BINPREFIX}as fi if test -z "$linker"; then linker=${BINPREFIX}ld fi preprocessor="${BINPREFIX}cpp" compiler="${BINPREFIX}ccom" AC_DEFINE(CROSS_COMPILING, 1, [Cross-compiling.]) fi AC_SUBST(BINPREFIX) if test -n "$altincdir"; then AC_DEFINE_UNQUOTED(STDINC, "$altincdir", [Define alternate standard include directory]) fi if test -n "$altlibdir"; then AC_DEFINE_UNQUOTED(LIBDIR, "${altlibdir}/", [Define alternate standard lib directory]) fi if test -n "$assembler"; then AC_DEFINE_UNQUOTED(ASSEMBLER, "$assembler", [Define path to alternate assembler]) fi if test -n "$linker"; then AC_DEFINE_UNQUOTED(LINKER, "$linker", [Define path to alternate linker]) fi if test -n "$preprocessor"; then AC_DEFINE_UNQUOTED(PREPROCESSOR, "$preprocessor", [Define path to alternate preprocessor]) fi if test -n "$compiler"; then AC_DEFINE_UNQUOTED(COMPILER, "$compiler", [Define path to alternate compiler]) fi case $wchar_type in USHORT) wchar_size=2 ;; UNSIGNED|INT) wchar_size=4 ;; *) AC_MSG_ERROR([Unknown wchar_t '$wchar_type'.]) ;; esac AC_DEFINE_UNQUOTED(WCHAR_TYPE, $wchar_type, [Type to use for wide characters]) AC_DEFINE_UNQUOTED(WCHAR_SIZE, $wchar_size, [Size of wide-character type in chars]) # check for additional compiler flags AC_PROG_CC DESIRED_FLAGS="-Wall -Wmissing-prototypes -Wstrict-prototypes -Wshadow -Wsign-compare -Wtruncate" for flag in $DESIRED_FLAGS do AC_MSG_CHECKING([whether $CC accepts $flag]) cflags="$CFLAGS" CFLAGS="$CFLAGS $flag -Werror" AC_COMPILE_IFELSE([ AC_LANG_PROGRAM([[]], [[]]) ], [ use_flag=yes ], [ use_flag=no ]) CFLAGS="$cflags" AC_MSG_RESULT([$use_flag]) if test $use_flag = yes; then ADD_CFLAGS="$ADD_CFLAGS $flag" fi done # setup for cross-compiling mkext AC_MSG_CHECKING([for a C compiler for mkext]) if test $cross_compiling = yes; then AC_MSG_RESULT([cross compiling]) AC_CHECK_PROGS(CC_FOR_BUILD, [pcc gcc cc]) else AC_MSG_RESULT([not cross compiling]) CC_FOR_BUILD=${CC-cc} AC_SUBST(CC_FOR_BUILD) fi AC_CACHE_CHECK([for C99 printf size specifiers], ac_cv_have_c99_format, [ AC_RUN_IFELSE([ AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT], [[ char buf[64]; if (sprintf(buf, "%lld%hhd%jd%zd%td", (long long int)1, (char)2, (intmax_t)3, (size_t)4, (ptrdiff_t)5) != 5) exit(1); else if (strcmp(buf, "12345")) exit(2); ]])], [ ac_cv_have_c99_format=yes ], [ ac_cv_have_c99_format=no ], [ ac_cv_have_c99_format=yes ]) ]) if test $ac_cv_have_c99_format = yes; then AC_DEFINE([HAVE_C99_FORMAT], 1, [Define to 1 if printf supports C99 size specifiers]) fi AC_CHECK_SIZEOF([int *]) # Byteorder of host AC_C_BIGENDIAN([AC_DEFINE(HOST_BIG_ENDIAN, 1, [Define if host is BIG endian])], [AC_DEFINE(HOST_LITTLE_ENDIAN, 1, [Define if host is LITTLE endian])], []) # Checks for programs. AC_PROG_MAKE_SET AC_PROG_INSTALL AC_PROG_YACC AC_PROG_LEX # Checks for libraries. if test $libvmf != no ; then LIBS=-lvmf AC_DEFINE(LIBVMF, 1, [Use libvmf.]) if test $libvmf != yes ; then LDFLAGS=-L$libvmf fi fi # Checks for header files. # AC_CHECK_HEADERS([fcntl.h stdlib.h string.h unistd.h]) AC_CHECK_HEADERS([string.h malloc.h libgen.h]) AC_HEADER_SYS_WAIT # Checks for library functions. ## AC_FUNC_STRTOD # AC_FUNC_VPRINTF # AC_CHECK_FUNCS([memset strchr strdup strrchr strtol]) AC_CHECK_FUNCS([strtold vsnprintf snprintf mkstemp strlcat strlcpy getopt ffs vfork]) AC_FUNC_ALLOCA AC_EXEEXT AC_SUBST(targos) AC_SUBST(targosver) AC_SUBST(targmach) AC_SUBST(targmachdir) AC_SUBST(hostos) AC_SUBST(prefix) AC_SUBST(exec_prefix) AC_SUBST(libexecdir) AC_SUBST(includedir) AC_SUBST(PACKAGE_VERSION) AC_SUBST(ADD_CFLAGS) AC_SUBST(ADD_CPPFLAGS) AC_SUBST(CCNAMES) AC_SUBST(CF0) AC_SUBST(CF1) AC_SUBST(LIBS) AC_SUBST(LDFLAGS) pcc_major=`echo $PACKAGE_VERSION | awk -F. '{print $1}'` pcc_minor=`echo $PACKAGE_VERSION | awk -F. '{print $2}'` pcc_minorminor=`echo $PACKAGE_VERSION | awk -F. '{print $3}'` test -n "$MPVERSION" && MPVERSION=", $MPVERSION" versstr="\"$PACKAGE_STRING `cat $srcdir/DATESTAMP` for $target$MPVERSION\"" targstr="\"$target$MPVERSION\"" AC_DEFINE_UNQUOTED(PCC_MAJOR, $pcc_major, [Major version no]) AC_DEFINE_UNQUOTED(PCC_MINOR, $pcc_minor, [Minor version no]) AC_DEFINE_UNQUOTED(PCC_MINORMINOR, $pcc_minorminor, [Minor minor version no]) AC_DEFINE_UNQUOTED(VERSSTR, $versstr, [Version string]) AC_DEFINE_UNQUOTED(TARGSTR, $targstr, [Target string]) AC_CONFIG_FILES([Makefile cc/Makefile cc/cc/Makefile cc/cpp/Makefile cc/ccom/Makefile cc/cxxcom/Makefile cc/driver/Makefile f77/Makefile f77/f77/Makefile f77/fcom/Makefile ]) AC_OUTPUT eval "exec_prefix=$exec_prefix" eval "bindir=$bindir" eval "libexecdir=$libexecdir" echo echo "Target CPU is .................... ${targmach}" echo "Target ABI is .................... ${abi}" echo "Target OS is ..................... ${targos}" echo "Compiler is called ............... ${BINPREFIX}pcc${EXEEXT}" echo "Installing compiler into ......... ${bindir}" echo "Installing pre-processor into .... ${libexecdir}" echo "Using assembler .................. ${assembler-}" echo "Using linker ..................... ${linker-}" echo "Using Multi-Arch path ............ ${multiarch}" echo "Using include path ............... ${altincdir-}" echo "Using library path ............... ${altlibdir-}" echo "Use libvmf ....................... $libvmf" echo "Has TLS support .................. $tls" echo "Has GCC compatibility ............ $gcccompat" echo "Has PCC debugging ................ $pccdebug" echo "Type of wchar_t is ............... ${wchar_type} (${wchar_size} chars)" echo echo "Configure finished. Do 'make && make install' to compile and install. " pcc-20181216/install-sh010075500017500000000000000157221013415216400134740ustar raggewheel#!/bin/sh # # install - install a program, script, or datafile # # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd=$cpprog shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd=$stripprog shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "$0: no input file specified" >&2 exit 1 else : fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d "$dst" ]; then instcmd=: chmodcmd="" else instcmd=$mkdirprog fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f "$src" ] || [ -d "$src" ] then : else echo "$0: $src does not exist" >&2 exit 1 fi if [ x"$dst" = x ] then echo "$0: no destination specified" >&2 exit 1 else : fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d "$dst" ] then dst=$dst/`basename "$src"` else : fi fi ## this sed command emulates the dirname command dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-$defaultIFS}" oIFS=$IFS # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` IFS=$oIFS pathcomp='' while [ $# -ne 0 ] ; do pathcomp=$pathcomp$1 shift if [ ! -d "$pathcomp" ] ; then $mkdirprog "$pathcomp" else : fi pathcomp=$pathcomp/ done fi if [ x"$dir_arg" != x ] then $doit $instcmd "$dst" && if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dst"; else : ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dst"; else : ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dst"; else : ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dst"; else : ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename "$dst"` else dstfile=`basename "$dst" $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename "$dst"` else : fi # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/#inst.$$# rmtmp=$dstdir/#rm.$$# # Trap to clean up temp files at exit. trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0 trap '(exit $?); exit' 1 2 13 15 # Move or copy the file name to the temp name $doit $instcmd "$src" "$dsttmp" && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dsttmp"; else :;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dsttmp"; else :;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dsttmp"; else :;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dsttmp"; else :;fi && # Now remove or move aside any old file at destination location. We try this # two ways since rm can't unlink itself on some systems and the destination # file might be busy for other reasons. In this case, the final cleanup # might fail but the new file should still install successfully. { if [ -f "$dstdir/$dstfile" ] then $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null || { echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 (exit 1); exit } else : fi } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" fi && # The final little trick to "correctly" pass the exit status to the exit trap. { (exit 0); exit } pcc-20181216/arch004075500017500000000000000000001340533064000123235ustar raggewheelpcc-20181216/arch/CVS004075500017500000000000000000001340533064000127565ustar raggewheelpcc-20181216/arch/CVS/Root010064400017500000000000000000111340533064000136700ustar raggewheel/cvsroot pcc-20181216/arch/CVS/Repository010064400017500000000000000000111340533064000151240ustar raggewheelpcc/arch pcc-20181216/arch/CVS/Entries010064400017500000000000000003071340533064000143660ustar raggewheelD/amd64//// D/arm//// D/hppa//// D/i386//// D/i86//// D/m16c//// D/m68k//// D/mips//// D/mips64//// D/nova//// D/pdp10//// D/pdp11//// D/pdp7//// D/powerpc//// D/sparc64//// D/superh//// D/vax//// D pcc-20181216/arch/amd64004075500017500000000000000000001340533064000132365ustar raggewheelpcc-20181216/arch/amd64/CVS004075500017500000000000000000001340533064000136715ustar raggewheelpcc-20181216/arch/amd64/CVS/Root010064400017500000000000000000111340533064000146030ustar raggewheel/cvsroot pcc-20181216/arch/amd64/CVS/Repository010064400017500000000000000000171340533064000160450ustar raggewheelpcc/arch/amd64 pcc-20181216/arch/amd64/CVS/Entries010064400017500000000000000003731340533064000153040ustar raggewheel/code.c/1.91/Sat Dec 1 17:18:55 2018// /local.c/1.102/Sun Dec 2 18:40:45 2018// /local2.c/1.70/Sat Nov 24 21:03:55 2018// /macdefs.h/1.40/Sat Jul 28 09:39:11 2018// /order.c/1.19/Sun Dec 3 17:34:15 2017// /table.c/1.57/Sat Nov 24 21:03:55 2018// D pcc-20181216/arch/amd64/code.c010064400017500000000000000744451340054117700144120ustar raggewheel/* $Id: code.c,v 1.91 2018/12/01 17:18:55 ragge Exp $ */ /* * Copyright (c) 2008 Michael Shalayeff * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass1.h" #ifndef LANG_CXX #undef NIL #define NIL NULL #define NODE P1ND #define nfree p1nfree #define ccopy p1tcopy #define tfree p1tfree #endif static int nsse, ngpr, nrsp, rsaoff; static int thissse, thisgpr, thisrsp; enum { NO_CLASS, INTEGER, INTMEM, SSE, SSEMEM, X87, STRREG, STRMEM, STRSSE, STRIF, STRFI, STRX87 }; static const int argregsi[] = { RDI, RSI, RDX, RCX, R08, R09 }; /* * The Register Save Area looks something like this. * It is put first on stack with fixed offsets. * struct { * long regs[6]; * double xmm[8][2]; // 16 byte in width * }; */ #define RSASZ (6*SZLONG+8*2*SZDOUBLE) #define RSALONGOFF(x) (RSASZ-(x)*SZLONG) #define RSADBLOFF(x) ((8*2*SZDOUBLE)-(x)*SZDOUBLE*2) /* va_list */ #define VAARGSZ (SZINT*2+SZPOINT(CHAR)*2) #define VAGPOFF(x) (x) #define VAFPOFF(x) (x-SZINT) #define VAOFA(x) (x-SZINT-SZINT) #define VARSA(x) (x-SZINT-SZINT-SZPOINT(0)) static int stroffset; static int varneeds; #define NEED_1FPREF 001 #define NEED_2FPREF 002 #define NEED_1REGREF 004 #define NEED_2REGREF 010 #define NEED_MEMREF 020 #define NEED_STRFI 040 #define NEED_STRIF 0100 static int argtyp(TWORD t, union dimfun *df, struct attr *ap); static NODE *movtomem(NODE *p, int off, int reg); static NODE *movtoreg(NODE *p, int rno); void varattrib(char *name, struct attr *sap); /* * Print out assembler segment name. */ #ifdef MACHOABI void setseg(int seg, char *name) { switch (seg) { case PROG: name = ".text"; break; case DATA: case LDATA: name = ".data"; break; case RDATA: name = ".const"; break; case STRNG: name = ".cstring"; break; case UDATA: break; case CTORS: name = ".mod_init_func"; break; case DTORS: name = ".mod_term_func"; break; default: cerror("unknown seg %d", seg); } printf("\t%s\n", name); } #else void setseg(int seg, char *name) { switch (seg) { case PROG: name = ".text"; break; case DATA: case LDATA: name = ".data"; break; case STRNG: case RDATA: name = ".section .rodata"; break; case UDATA: break; case PICLDATA: case PICDATA: name = ".section .data.rel.rw,\"aw\",@progbits"; break; case PICRDATA: name = ".section .data.rel.ro,\"aw\",@progbits"; break; case TLSDATA: name = ".section .tdata,\"awT\",@progbits"; break; case TLSUDATA: name = ".section .tbss,\"awT\",@nobits"; break; case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break; case DTORS: name = ".section\t.dtors,\"aw\",@progbits"; break; case NMSEG: printf("\t.section %s,\"a%c\",@progbits\n", name, cftnsp ? 'x' : 'w'); return; } printf("\t%s\n", name); } #endif /* * Define everything needed to print out some data (or text). * This means segment, alignment, visibility, etc. */ void defloc(struct symtab *sp) { char *name; name = getexname(sp); if (sp->sclass == EXTDEF) { printf("\t.globl %s\n", name); #ifndef MACHOABI if (ISFTN(sp->stype)) { printf("\t.type %s,@function\n", name); } else { printf("\t.type %s,@object\n", name); printf("\t.size %s,%d\n", name, (int)tsize(sp->stype, sp->sdf, sp->sap)/SZCHAR); } #endif } if (sp->slevel == 0) printf("%s:\n", name); else printf(LABFMT ":\n", sp->soffset); } /* * code for the end of a function * deals with struct return here * The return value is in (or pointed to by) RETREG. */ void efcode(void) { struct symtab *sp; extern int gotnr; TWORD t; NODE *p, *r, *l; int typ; gotnr = 0; /* new number for next fun */ sp = cftnsp; t = DECREF(sp->stype); if (t != STRTY && t != UNIONTY) return; /* XXX should have one routine for this */ ngpr = nsse = 0; typ = argtyp(t, sp->sdf, sp->sap); if (typ == STRMEM) { r = block(REG, NIL, NIL, INCREF(t), sp->sdf, sp->sap); regno(r) = RAX; r = buildtree(UMUL, r, NIL); l = tempnode(stroffset, INCREF(t), sp->sdf, sp->sap); l = buildtree(UMUL, l, NIL); ecomp(buildtree(ASSIGN, l, r)); l = block(REG, NIL, NIL, LONG, 0, 0); regno(l) = RAX; r = tempnode(stroffset, LONG, 0, 0); ecomp(buildtree(ASSIGN, l, r)); } else if (typ == STRX87) { p = block(REG, NIL, NIL, INCREF(LDOUBLE), 0, 0); regno(p) = RAX; p = buildtree(UMUL, buildtree(PLUS, p, bcon(1)), NIL); ecomp(movtoreg(p, 041)); p = block(REG, NIL, NIL, INCREF(LDOUBLE), 0, 0); regno(p) = RAX; p = buildtree(UMUL, p, NIL); ecomp(movtoreg(p, 040)); } else { TWORD t1, t2; int r1, r2; if (typ == STRSSE || typ == STRFI) r1 = XMM0, t1 = DOUBLE; else r1 = RAX, t1 = LONG; if (typ == STRSSE) r2 = XMM1, t2 = DOUBLE; else if (typ == STRFI) r2 = RAX, t2 = LONG; else if (typ == STRIF) r2 = XMM0, t2 = DOUBLE; else /* if (typ == STRREG) */ r2 = RDX, t2 = LONG; if (tsize(t, sp->sdf, sp->sap) > SZLONG) { p = block(REG, NIL, NIL, INCREF(t2), 0, 0); regno(p) = RAX; p = buildtree(UMUL, buildtree(PLUS, p, bcon(1)), NIL); ecomp(movtoreg(p, r2)); } p = block(REG, NIL, NIL, INCREF(t1), 0, 0); regno(p) = RAX; p = buildtree(UMUL, p, NIL); ecomp(movtoreg(p, r1)); } } /* * code for the beginning of a function; a is an array of * indices in symtab for the arguments; n is the number */ void bfcode(struct symtab **s, int cnt) { union arglist *al; struct symtab *sp; NODE *p, *r; TWORD t; int i, rno, typ, ssz; /* recalculate the arg offset and create TEMP moves */ /* Always do this for reg, even if not optimizing, to free arg regs */ nsse = ngpr = 0; nrsp = ARGINIT; if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { sp = cftnsp; if (argtyp(DECREF(sp->stype), sp->sdf, sp->sap) == STRMEM) { r = block(REG, NIL, NIL, LONG, 0, 0); regno(r) = argregsi[ngpr++]; p = tempnode(0, r->n_type, r->n_df, r->n_ap); stroffset = regno(p); ecomp(buildtree(ASSIGN, p, r)); } } for (i = 0; i < cnt; i++) { sp = s[i]; if (sp == NULL) continue; /* XXX when happens this? */ ssz = (int)tsize(sp->stype, sp->sdf, sp->sap); switch (typ = argtyp(sp->stype, sp->sdf, sp->sap)) { case INTEGER: case SSE: if (typ == SSE) rno = XMM0 + nsse++; else rno = argregsi[ngpr++]; r = block(REG, NIL, NIL, sp->stype, sp->sdf, sp->sap); regno(r) = rno; p = tempnode(0, sp->stype, sp->sdf, sp->sap); sp->soffset = regno(p); sp->sflags |= STNODE; ecomp(buildtree(ASSIGN, p, r)); break; case SSEMEM: sp->soffset = nrsp; nrsp += SZDOUBLE; if (xtemps) { p = tempnode(0, sp->stype, sp->sdf, sp->sap); p = buildtree(ASSIGN, p, nametree(sp)); sp->soffset = regno(p->n_left); sp->sflags |= STNODE; ecomp(p); } break; case INTMEM: sp->soffset = nrsp; nrsp += SZLONG; if (xtemps) { p = tempnode(0, sp->stype, sp->sdf, sp->sap); p = buildtree(ASSIGN, p, nametree(sp)); sp->soffset = regno(p->n_left); sp->sflags |= STNODE; ecomp(p); } break; case STRX87: case STRMEM: /* Struct in memory */ sp->soffset = nrsp; nrsp += ssz; break; case X87: /* long double args */ sp->soffset = nrsp; nrsp += SZLDOUBLE; break; case STRFI: case STRIF: case STRSSE: case STRREG: /* Struct in register */ autooff += (2*SZLONG); if (typ == STRSSE || typ == STRFI) { rno = XMM0 + nsse++; t = DOUBLE; } else { rno = argregsi[ngpr++]; t = LONG; } r = block(REG, NIL, NIL, t, 0, 0); regno(r) = rno; ecomp(movtomem(r, -autooff, FPREG)); if (ssz > SZLONG) { if (typ == STRSSE || typ == STRIF) { rno = XMM0 + nsse++; t = DOUBLE; } else { rno = argregsi[ngpr++]; t = LONG; } r = block(REG, NIL, NIL, t, 0, 0); regno(r) = rno; ecomp(movtomem(r, -autooff+SZLONG, FPREG)); } sp->soffset = -autooff; break; default: cerror("bfcode: %d", typ); } } /* Check if there are varargs */ if (cftnsp->sdf == NULL || cftnsp->sdf->dfun == NULL) return; /* no prototype */ al = cftnsp->sdf->dfun; for (; al->type != TELLIPSIS; al++) { t = al->type; if (t == TNULL) return; if (ISSOU(BTYPE(t))) al++; for (i = 0; t > BTMASK; t = DECREF(t)) if (ISARY(t) || ISFTN(t)) i++; if (i) al++; } /* fix stack offset */ SETOFF(autooff, ALMAX); /* Save reg arguments in the reg save area */ p = NIL; for (i = ngpr; i < 6; i++) { r = block(REG, NIL, NIL, LONG, 0, 0); regno(r) = argregsi[i]; r = movtomem(r, -RSALONGOFF(i)-autooff, FPREG); p = (p == NIL ? r : block(COMOP, p, r, INT, 0, 0)); } for (i = nsse; i < 8; i++) { r = block(REG, NIL, NIL, DOUBLE, 0, 0); regno(r) = i + XMM0; r = movtomem(r, -RSADBLOFF(i)-autooff, FPREG); p = (p == NIL ? r : block(COMOP, p, r, INT, 0, 0)); } autooff += RSASZ; rsaoff = autooff; thissse = nsse; thisgpr = ngpr; thisrsp = nrsp; ecomp(p); } /* called just before final exit */ /* flag is 1 if errors, 0 if none */ void ejobcode(int flag) { if (flag) return; #ifdef MACHOABI #define PT(x) #else #define PT(x) printf(".type __pcc_" x ",@function\n") #endif #define P(x) printf(x "\n") /* printout varargs routines if used */ if (varneeds & NEED_STRFI) { /* struct with one float and then int */ P(".text\n.align 4"); PT("strif"); P("__pcc_strif:"); P("cmpl $176,4(%%rdi)\njae .Ladd16"); P("cmpl $48,(%%rdi)\njae .Ladd16\n"); P("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax"); P("movq (%%rax),%%rdx\nmovq %%rdx,24(%%rdi)"); P("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax"); P("movq 16(%%rax),%%rdx\nmovq %%rdx,32(%%rdi)"); P("leaq 24(%%rdi),%%rax\nret"); } if (varneeds & NEED_STRIF) { /* struct with one int and one float */ P(".text\n.align 4"); PT("strif"); P("__pcc_strif:"); P("cmpl $176,4(%%rdi)\njae .Ladd16"); P("cmpl $48,(%%rdi)\njae .Ladd16\n"); P("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax"); P("movq (%%rax),%%rdx\nmovq %%rdx,24(%%rdi)"); P("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax"); P("movq 16(%%rax),%%rdx\nmovq %%rdx,32(%%rdi)"); P("leaq 24(%%rdi),%%rax\nret"); } if (varneeds & NEED_2FPREF) { /* struct with two float regs */ P(".text\n.align 4"); PT("2fpref"); P("__pcc_2fpref:"); P("cmpl $160,4(%%rdi)\njae .Ladd16"); P("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax"); P("addl $32,4(%%rdi)"); P("movq (%%rax),%%rdx\nmovq %%rdx,24(%%rdi)"); P("movq 16(%%rax),%%rdx\nmovq %%rdx,32(%%rdi)"); P("leaq 24(%%rdi),%%rax\nret"); } if (varneeds & NEED_1FPREF) { printf(".text\n.align 4\n"); PT("1fpref"); printf("__pcc_1fpref:\n"); printf("cmpl $176,4(%%rdi)\njae .Ladd8\n"); printf("movl 4(%%rdi),%%eax\naddq 16(%%rdi),%%rax\n"); printf("addl $16,4(%%rdi)\nret\n"); } if (varneeds & NEED_1REGREF) { printf(".text\n.align 4\n"); PT("1regref"); printf("__pcc_1regref:\n"); printf("cmpl $48,(%%rdi)\njae .Ladd8\n"); printf("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax\n"); printf("addl $8,(%%rdi)\nret\n"); } if (varneeds & NEED_2REGREF) { printf(".text\n.align 4\n"); PT("2regref"); printf("__pcc_2regref:\n"); printf("cmpl $40,(%%rdi)\njae .Ladd16\n"); printf("movl (%%rdi),%%eax\naddq 16(%%rdi),%%rax\n"); printf("addl $16,(%%rdi)\nret\n"); } if (varneeds & NEED_MEMREF) { printf(".text\n.align 4\n"); PT("memref"); printf("__pcc_memref:\n"); printf("movq 8(%%rdi),%%rax\n"); printf("addq %%rsi,8(%%rdi)\nret\n"); } if (varneeds & (NEED_1FPREF|NEED_1REGREF)) { P(".Ladd8:"); P("movq 8(%%rdi),%%rax"); P("addq $8,8(%%rdi)"); P("ret"); } if (varneeds & (NEED_2FPREF|NEED_2REGREF|NEED_STRFI|NEED_STRIF)) { P(".Ladd16:"); P("movq 8(%%rdi),%%rax"); P("addq $16,8(%%rdi)"); P("ret"); } #ifdef MACHOABI printf("\t.ident \"PCC: %s\"\n", VERSSTR); #else printf("\t.ident \"PCC: %s\"\n\t.end\n", VERSSTR); #endif } /* * Varargs stuff: * The ABI says that va_list should be declared as this typedef. * We handcraft it here and then just reference it. * * typedef struct { * unsigned int gp_offset; * unsigned int fp_offset; * void *overflow_arg_area; * void *reg_save_area; * } __builtin_va_list[1]; * * ...actually, we allocate two of them and use the second one as * bounce buffers for floating point structs... * * There are a number of asm routines printed out if varargs are used: * long __pcc_gpnext(va) - get a gpreg value * long __pcc_fpnext(va) - get a fpreg value * void *__pcc_1regref(va) - get reference to a onereg struct * void *__pcc_2regref(va) - get reference to a tworeg struct * void *__pcc_memref(va,sz) - get reference to a large struct */ static char *gp_offset, *fp_offset, *overflow_arg_area, *reg_save_area; static char *_1fpref, *_2fpref, *_1regref, *_2regref, *memref; static char *strif, *strfi; void bjobcode(void) { struct symtab *sp; struct rstack *rp; NODE *p, *q; char *c; #if defined(__GNUC__) || defined(__PCC__) /* Be sure that the compiler uses full x87 */ /* XXX cross-compiling will fail here */ volatile int fcw = 0; __asm("fstcw (%0)" : : "r"(&fcw)); fcw |= 0x33f; __asm("fldcw (%0)" : : "r"(&fcw)); #endif /* amd64 names for some asm constant printouts */ astypnames[INT] = astypnames[UNSIGNED] = "\t.long"; astypnames[LONG] = astypnames[ULONG] = "\t.quad"; gp_offset = addname("gp_offset"); fp_offset = addname("fp_offset"); overflow_arg_area = addname("overflow_arg_area"); reg_save_area = addname("reg_save_area"); rp = bstruct(NULL, STNAME, NULL); p = block(NAME, NIL, NIL, UNSIGNED, 0, 0); soumemb(p, gp_offset, 0); soumemb(p, fp_offset, 0); p->n_type = VOID+PTR; p->n_ap = NULL; soumemb(p, overflow_arg_area, 0); soumemb(p, reg_save_area, 0); nfree(p); q = dclstruct(rp); c = addname("__builtin_va_list"); p = block(LB, bdty(NAME, c), bcon(2), INT, 0, 0); p = tymerge(q, p); p->n_sp = lookup(c, 0); defid(p, TYPEDEF); nfree(q); nfree(p); /* for the static varargs functions */ #define MKN(vn, rn) \ { vn = addname(rn); sp = lookup(vn, SNORMAL); \ sp->sclass = USTATIC; sp->stype = FTN|VOID|(PTR<n_left; r = buildtree(ASSIGN, structref(ccopy(p), STREF, reg_save_area), mkstkref(-rsaoff, VOID)); r = buildtree(COMOP, r, buildtree(ASSIGN, structref(ccopy(p), STREF, overflow_arg_area), mkstkref(thisrsp, VOID))); r = buildtree(COMOP, r, buildtree(ASSIGN, structref(ccopy(p), STREF, gp_offset), bcon(thisgpr*(SZLONG/SZCHAR)))); r = buildtree(COMOP, r, buildtree(ASSIGN, structref(ccopy(p), STREF, fp_offset), bcon(thissse*(SZDOUBLE*2/SZCHAR)+48))); tfree(a); return r; } static NODE * mkvacall(char *fun, NODE *a, int typ) { NODE *r, *f = block(NAME, NIL, NIL, INT, 0, 0); NODE *ap = a->n_left; NODE *dp = a->n_right; OFFSZ sz = tsize(dp->n_type, dp->n_df, dp->n_ap); f->n_sp = lookup(fun, SNORMAL); varneeds |= typ; f->n_type = f->n_sp->stype; f = clocal(f); SETOFF(sz, ALLONG); r = buildtree(CALL, f, buildtree(CM, ccopy(ap), bcon(sz/SZCHAR))); r = ccast(r, INCREF(dp->n_type), 0, dp->n_df, dp->n_ap); r = buildtree(UMUL, r, NIL); return r; } NODE * amd64_builtin_va_arg(const struct bitable *bt, NODE *a) { NODE *r, *dp; int typ; OFFSZ sz; dp = a->n_right; nsse = ngpr = 0; sz = tsize(dp->n_type, dp->n_df, dp->n_ap); switch (typ = argtyp(dp->n_type, dp->n_df, dp->n_ap)) { case INTEGER: r = mkvacall(_1regref, a, NEED_1REGREF); break; case SSE: r = mkvacall(_1fpref, a, NEED_1FPREF); break; default: cerror("va_arg: bad type %d", typ); case X87: case STRX87: case STRMEM: /* stored in memory */ r = mkvacall(memref, a, NEED_MEMREF); break; case STRREG: /* struct in general regs */ if (sz <= SZLONG) r = mkvacall(_1regref, a, NEED_1REGREF); else r = mkvacall(_2regref, a, NEED_2REGREF); break; case STRSSE: if (sz <= SZLONG) r = mkvacall(_1fpref, a, NEED_1FPREF); else r = mkvacall(_2fpref, a, NEED_2FPREF); break; case STRIF: r = mkvacall(strif, a, NEED_STRIF); break; case STRFI: r = mkvacall(strfi, a, NEED_STRFI); break; } tfree(a); return r; } NODE * amd64_builtin_va_end(const struct bitable *bt, NODE *a) { tfree(a); return bcon(0); /* nothing */ } NODE * amd64_builtin_va_copy(const struct bitable *bt, NODE *a) { NODE *f; f = buildtree(ASSIGN, buildtree(UMUL, a->n_left, NIL), buildtree(UMUL, a->n_right, NIL)); nfree(a); return f; } static NODE * movtoreg(NODE *p, int rno) { NODE *r; r = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap); regno(r) = rno; return clocal(buildtree(ASSIGN, r, p)); } static NODE * movtomem(NODE *p, int off, int reg) { struct symtab s; NODE *r, *l; s.stype = p->n_type; s.squal = 0; s.sdf = p->n_df; s.sap = p->n_ap; s.soffset = off; s.sclass = AUTO; l = block(REG, NIL, NIL, PTR+STRTY, 0, 0); slval(l, 0); regno(l) = reg; r = block(NAME, NIL, NIL, p->n_type, p->n_df, p->n_ap); r->n_sp = &s; r = stref(block(STREF, l, r, 0, 0, 0)); return clocal(buildtree(ASSIGN, r, p)); } /* * Check what to do with a struct/union. We traverse down in the struct to * find which types it is and where the struct really should be. * The return vals we may end up with are: * STRREG - The whole struct is saved in general registers. * STRMEM - the struct is saved in memory. * STRSSE - the whole struct is saved in SSE registers. * STRIF - First word of struct is saved in general reg, other SSE. * STRFI - First word of struct is saved in SSE, next in general reg. * * INTEGER, MEMORY, X87, X87UP, X87COMPLEX, SSE, NO_CLASS. * * - If size > 16 bytes or there are packed fields, use memory. * - If any part of an eight-byte should be in a general register, * the eight-byte is stored in a general register * - If the eight-byte only contains float or double, use a SSE register * - Otherwise use memory. * * Arrays must be broken up as separate elements, since the elements * are classified separately. For example; * struct s { short s; float f[3]; } S; * will have the first 64 bits passed in general reg and the second in SSE. * * sp below is a pointer to a member list. * off tells how many bits in that the classification should start. */ /* * fill in an array of what elements are classified as. * May return: * - NO_CLASS (if more checks needed) * - STRMEM (if known to end up in memory) */ #define MAXCLELEM 128 static struct { int off; int cl; } cla[MAXCLELEM]; static int clp; static int fillstr(struct symtab *sp); static int fillun(struct symtab *sp); static int flatten(TWORD t, struct symtab *sp) { int cl; clp = 0; cl = (t == STRTY ? fillstr(sp) : fillun(sp)); return cl; } static int fillstr(struct symtab *sp) { int cl = NO_CLASS; TWORD t; int sz; for (; sp; sp = sp->snext) { t = sp->stype; sz = (int)tsize(t, sp->sdf, sp->sap); while (ISARY(t)) t = DECREF(t); if (t <= ULONGLONG || ISPTR(t)) { cla[clp].cl = STRREG; cla[clp++].off = (int)sp->soffset; } else if (t <= DOUBLE) { cla[clp].cl = STRSSE; cla[clp++].off = (int)sp->soffset; } else if (t == LDOUBLE) { cl = STRMEM; break; } else { /* struct or union */ #ifdef GCC_COMPAT if (attr_find(sp->sap, GCC_ATYP_PACKED)) { cl = STRMEM; break; } #endif if (t == STRTY) cl = fillstr(strmemb(sp->sap)); else if (t == UNIONTY) cl = fillun(strmemb(sp->sap)); else cerror("fillstr: %d", t); if (cl == STRMEM) break; } } return cl; } /* NO_CLASS, STRMEM, STRREG, STRSSE, X87 */ static int unmerge(int old, int new) { int cl = old; if (new == STRMEM) cl = new; else switch (old) { case NO_CLASS: cl = new; break; case STRREG: case STRMEM: break; case X87: if (new == STRREG) cl = new; else if (new == STRSSE) cl = STRMEM; else cl = X87; break; case STRSSE: if (new == X87) cl = STRMEM; else cl = new; break; } return cl; } static int fillun(struct symtab *sp) { int cl = NO_CLASS; TWORD t; cla[clp].off = (int)sp->soffset; for (; sp; sp = sp->snext) { t = sp->stype; while (ISARY(t)) t = DECREF(t); if (t <= ULONGLONG || ISPTR(t)) { cl = unmerge(cl, STRREG); } else if (t <= DOUBLE) { cl = unmerge(cl, STRSSE); } else if (t == LDOUBLE) { cl = unmerge(cl, X87); } else { /* struct or union */ #ifdef GCC_COMPAT if (attr_find(sp->sap, GCC_ATYP_PACKED)) { cl = STRMEM; } else #endif { int cl2 = NO_CLASS; if (t == STRTY) cl2 = fillstr(strmemb(sp->sap)); else if (t == UNIONTY) cl2 = fillun(strmemb(sp->sap)); else cerror("fillstr: %d", t); cl = unmerge(cl, cl2); } } if (cl == STRMEM) break; } if (cl == X87) cl = STRMEM; cla[clp].cl = cl; clp++; return cl; } /* * Check for long double complex structs. */ static int iscplx87(struct symtab *sp) { if (sp->stype == LDOUBLE && sp->snext->stype == LDOUBLE && sp->snext->snext == NULL) return STRX87; return 0; } /* * AMD64 parameter classification. */ static int argtyp(TWORD t, union dimfun *df, struct attr *ap) { int i, cl2, cl = 0; if (t <= ULONG || ISPTR(t) || t == BOOL) { cl = ngpr < 6 ? INTEGER : INTMEM; } else if (t == FLOAT || t == DOUBLE || t == FIMAG || t == IMAG) { cl = nsse < 8 ? SSE : SSEMEM; } else if (t == LDOUBLE || t == LIMAG) { cl = X87; /* XXX */ } else if (t == STRTY || t == UNIONTY) { int sz = (int)tsize(t, df, ap); #ifdef GCC_COMPAT if (attr_find(ap, GCC_ATYP_PACKED)) { cl = STRMEM; } else #endif if (iscplx87(strmemb(ap)) == STRX87) { cl = STRX87; } else if (sz > 2*SZLONG) { cl = STRMEM; } else { if ((cl = flatten(t, strmemb(ap))) == STRMEM) return STRMEM; cl = cl2 = NO_CLASS; for (i = 0; i < clp; i++) { if (cla[i].off < SZLONG) { if (cl == NO_CLASS || cl == STRSSE) cl = cla[i].cl; } else { if (cl2 == NO_CLASS || cl2 == STRSSE) cl2 = cla[i].cl; } } if (cl == STRMEM || cl2 == STRMEM) cl = STRMEM; else if (cl == STRREG && cl2 == STRSSE) cl = STRIF; else if (cl2 == STRREG && cl == STRSSE) cl = STRFI; if (cl == STRREG && ngpr > 4) cl = STRMEM; else if (cl == STRSSE && nsse > 6) cl = STRMEM; else if ((cl == STRIF || cl == STRFI) && (ngpr > 5 || nsse > 7)) cl = STRMEM; } } else cerror("FIXME: classify"); return cl; } /* * Do the "hard work" in assigning correct destination for arguments. * Also convert arguments < INT to inte (default argument promotions). * XXX - should be dome elsewhere. */ static NODE * argput(NODE *p) { NODE *q, *ql; TWORD ty; int typ, r, ssz, rn; if (p->n_op == CM) { p->n_left = argput(p->n_left); p->n_right = argput(p->n_right); return p; } /* first arg may be struct return pointer */ /* XXX - check if varargs; setup al */ switch (typ = argtyp(p->n_type, p->n_df, p->n_ap)) { case INTEGER: case SSE: if (typ == SSE) r = XMM0 + nsse++; else r = argregsi[ngpr++]; if (p->n_type < INT || p->n_type == BOOL) p = cast(p, INT, 0); p = movtoreg(p, r); break; case X87: r = nrsp; nrsp += SZLDOUBLE; p = movtomem(p, r, STKREG); break; case SSEMEM: r = nrsp; nrsp += SZDOUBLE; p = movtomem(p, r, STKREG); break; case INTMEM: r = nrsp; nrsp += SZLONG; if (p->n_type < INT || p->n_type == BOOL) p = cast(p, INT, 0); p = movtomem(p, r, STKREG); break; case STRFI: case STRIF: case STRSSE: case STRREG: /* Struct in registers */ /* Cast to long/sse pointer and move to the registers */ /* XXX can overrun struct size */ ssz = (int)tsize(p->n_type, p->n_df, p->n_ap); if (typ == STRSSE || typ == STRFI) { r = XMM0 + nsse++; ty = DOUBLE; } else { r = argregsi[ngpr++]; ty = LONG; } p = nfree(p); /* remove STARG */ p = makety(p, PTR|ty, 0, 0, 0); ql = tempnode(0, PTR|ty, 0, 0); rn = regno(ql); p = buildtree(ASSIGN, ql, p); ql = tempnode(rn, PTR|ty, 0, 0); ql = movtoreg(buildtree(UMUL, ql, NIL), r); p = buildtree(COMOP, p, ql); if (ssz > SZLONG) { if (typ == STRSSE || typ == STRIF) { r = XMM0 + nsse++; ty = DOUBLE; } else { r = argregsi[ngpr++]; ty = LONG; } ql = tempnode(rn, PTR|ty, 0, 0); ql = buildtree(UMUL, buildtree(PLUS, ql, bcon(1)), NIL); ql = movtoreg(ql, r); p = buildtree(CM, p, ql); } break; case STRX87: case STRMEM: { struct symtab s; NODE *l, *t; q = buildtree(UMUL, p->n_left, NIL); s.stype = p->n_type; s.squal = 0; s.sdf = p->n_df; s.sap = p->n_ap; s.soffset = nrsp; s.sclass = AUTO; nrsp += (int)tsize(p->n_type, p->n_df, p->n_ap); l = block(REG, NIL, NIL, PTR+STRTY, 0, 0); slval(l, 0); regno(l) = STKREG; t = block(NAME, NIL, NIL, p->n_type, p->n_df, p->n_ap); t->n_sp = &s; t = stref(block(STREF, l, t, 0, 0, 0)); t = (buildtree(ASSIGN, t, q)); nfree(p); p = t->n_left; nfree(t); break; } default: cerror("argument %d", typ); } return p; } /* * Sort arglist so that register assignments ends up last. */ static int argsort(NODE *p) { NODE *q, *r; int rv = 0; if (p->n_op != CM) { if (p->n_op == ASSIGN && p->n_left->n_op == REG && coptype(p->n_right->n_op) != LTYPE) { q = tempnode(0, p->n_type, p->n_df, p->n_ap); r = ccopy(q); p->n_right = buildtree(COMOP, buildtree(ASSIGN, q, p->n_right), r); } return rv; } if (p->n_right->n_op == CM) { /* fixup for small structs in regs */ q = p->n_right->n_left; p->n_right->n_left = p->n_left; p->n_left = p->n_right; p->n_right = p->n_left->n_right; p->n_left->n_right = q; } if (p->n_right->n_op == ASSIGN && p->n_right->n_left->n_op == REG && coptype(p->n_right->n_right->n_op) != LTYPE) { /* move before everything to avoid reg trashing */ q = tempnode(0, p->n_right->n_type, p->n_right->n_df, p->n_right->n_ap); r = ccopy(q); p->n_right->n_right = buildtree(COMOP, buildtree(ASSIGN, q, p->n_right->n_right), r); } if (p->n_right->n_op == ASSIGN && p->n_right->n_left->n_op == REG) { if (p->n_left->n_op == CM && p->n_left->n_right->n_op == STASG) { q = p->n_left->n_right; p->n_left->n_right = p->n_right; p->n_right = q; rv = 1; } else if (p->n_left->n_op == STASG) { q = p->n_left; p->n_left = p->n_right; p->n_right = q; rv = 1; } } return rv | argsort(p->n_left); } /* * Called with a function call with arguments as argument. * This is done early in buildtree() and only done once. * Returns p. */ NODE * funcode(NODE *p) { NODE *l, *r; TWORD t; int i; nsse = ngpr = nrsp = 0; /* Check if hidden arg needed */ /* If so, add it in pass2 */ if ((l = p->n_left)->n_type == INCREF(FTN)+STRTY || l->n_type == INCREF(FTN)+UNIONTY) { OFFSZ ssz = tsize(BTYPE(l->n_type), l->n_df, l->n_ap); struct symtab *sp = strmemb(l->n_ap); if (ssz == 2*SZLDOUBLE && sp->stype == LDOUBLE && sp->snext->stype == LDOUBLE) ; /* long complex struct */ else if (ssz > 2*SZLONG) ngpr++; } /* Convert just regs to assign insn's */ p->n_right = argput(p->n_right); /* Must sort arglist so that STASG ends up first */ /* This avoids registers being clobbered */ while (argsort(p->n_right)) ; /* Check if there are varargs */ if (nsse || l->n_df == NULL || l->n_df->dfun == NULL) { ; /* Need RAX */ } else { union arglist *al = l->n_df->dfun; for (; al->type != TELLIPSIS; al++) { if ((t = al->type) == TNULL) return p; /* No need */ if (ISSOU(BTYPE(t))) al++; for (i = 0; t > BTMASK; t = DECREF(t)) if (ISARY(t) || ISFTN(t)) i++; if (i) al++; } } /* Always emit number of SSE regs used */ l = movtoreg(bcon(nsse), RAX); if (p->n_right->n_op != CM) { p->n_right = block(CM, l, p->n_right, INT, 0, 0); } else { for (r = p->n_right; r->n_left->n_op == CM; r = r->n_left) ; r->n_left = block(CM, l, r->n_left, INT, 0, 0); } return p; } /* fix up type of field p */ void fldty(struct symtab *p) { } /* * XXX - fix genswitch. */ int mygenswitch(int num, TWORD type, struct swents **p, int n) { return 0; } /* * Return return as given by a. */ NODE * builtin_return_address(const struct bitable *bt, NODE *a) { int nframes; NODE *f; nframes = (int)glval(a); tfree(a); f = block(REG, NIL, NIL, PTR+VOID, 0, 0); regno(f) = FPREG; while (nframes--) f = block(UMUL, f, NIL, PTR+VOID, 0, 0); f = block(PLUS, f, bcon(8), INCREF(PTR+VOID), 0, 0); f = buildtree(UMUL, f, NIL); return f; } /* * Return frame as given by a. */ NODE * builtin_frame_address(const struct bitable *bt, NODE *a) { int nframes; NODE *f; nframes = (int)glval(a); tfree(a); f = block(REG, NIL, NIL, PTR+VOID, 0, 0); regno(f) = FPREG; while (nframes--) f = block(UMUL, f, NIL, PTR+VOID, 0, 0); return f; } /* * Return "canonical frame address". */ NODE * builtin_cfa(const struct bitable *bt, NODE *a) { NODE *f; f = block(REG, NIL, NIL, PTR+VOID, 0, 0); regno(f) = FPREG; return block(PLUS, f, bcon(16), INCREF(PTR+VOID), 0, 0); } int codeatyp(NODE *); int codeatyp(NODE *p) { TWORD t; int typ; ngpr = nsse = 0; t = DECREF(p->n_type); if (ISSOU(t) == 0) { p = p->n_left; t = DECREF(DECREF(p->n_type)); } if (ISSOU(t) == 0) cerror("codeatyp"); typ = argtyp(t, p->n_df, p->n_ap); return typ; } pcc-20181216/arch/amd64/local.c010064400017500000000000000445111340102345500145540ustar raggewheel/* $Id: local.c,v 1.102 2018/12/02 18:40:45 ragge Exp $ */ /* * Copyright (c) 2008 Michael Shalayeff * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "pass1.h" #ifndef LANG_CXX #define NODE P1ND #define ccopy p1tcopy #define tfree p1tfree #define nfree p1nfree #define fwalk p1fwalk #define talloc p1alloc #endif /* this file contains code which is dependent on the target machine */ /* * Check if a constant is too large for a type. */ #ifdef notyet static int toolarge(TWORD t, CONSZ con) { U_CONSZ ucon = con; switch (t) { case ULONG: case LONG: case ULONGLONG: case LONGLONG: break; /* cannot be too large */ #define SCHK(i) case i: if (con > MAX_##i || con < MIN_##i) return 1; break #define UCHK(i) case i: if (ucon > MAX_##i) return 1; break SCHK(INT); SCHK(SHORT); case BOOL: SCHK(CHAR); UCHK(UNSIGNED); UCHK(USHORT); UCHK(UCHAR); default: cerror("toolarge"); } return 0; } #endif static char * getsoname(struct symtab *sp) { struct attr *ap; return (ap = attr_find(sp->sap, ATTR_SONAME)) ? ap->sarg(0) : sp->sname; } #define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz)) /* * Make a symtab entry for PIC use. */ static struct symtab * picsymtab(char *p, char *s, char *s2) { struct symtab *sp = IALLOC(sizeof(struct symtab)); size_t len = strlen(p) + strlen(s) + strlen(s2) + 1; sp->sname = IALLOC(len); strlcpy(sp->sname, p, len); strlcat(sp->sname, s, len); strlcat(sp->sname, s2, len); sp->sap = attr_new(ATTR_SONAME, 1); sp->sap->sarg(0) = sp->sname; sp->sclass = EXTERN; sp->sflags = sp->slevel = 0; return sp; } int gotnr; /* tempnum for GOT register */ int argstacksize; /* * Create a reference for an extern variable or function. */ static NODE * picext(NODE *p) { #if defined(ELFABI) NODE *q; struct symtab *sp; char *c; if (attr_find(p->n_sp->sap, ATTR_AMD64_BEENHERE)) return p; #ifdef GCC_COMPAT struct attr *ga; if ((ga = attr_find(p->n_sp->sap, GCC_ATYP_VISIBILITY)) && strcmp(ga->sarg(0), "hidden") == 0) return p; /* no GOT reference */ #endif c = getexname(p->n_sp); sp = picsymtab("", c, mcmodel & MCLARGE ? "@GOTOFF" : "@GOTPCREL"); sp->sap = attr_add(sp->sap, attr_new(ATTR_AMD64_BEENHERE, 1)); q = block(NAME, NIL, NIL, INCREF(p->n_type), p->n_df, p->n_ap); q->n_sp = sp; q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); q->n_sp = sp; nfree(p); return q; #elif defined(MACHOABI) return p; #endif } static NODE * cmop(NODE *l, NODE *r) { return block(CM, l, r, INT, 0, 0); } static NODE * mkx(char *s, NODE *p) { p = block(XARG, p, NIL, INT, 0, 0); p->n_name = s; return p; } static char * mk3str(char *s1, char *s2, char *s3) { size_t len = strlen(s1) + strlen(s2) + strlen(s3) + 1; char *sd; sd = tmpalloc(len); strlcpy(sd, s1, len); strlcat(sd, s2, len); strlcat(sd, s3, len); return sd; } /* * Create a reference for a TLS variable. * This is the "General dynamic" version. */ static NODE * tlspic(NODE *p) { NODE *q, *r, *s; char *s1, *s2; /* * .byte 0x66 * leaq x@TLSGD(%rip),%rdi * .word 0x6666 * rex64 * call __tls_get_addr@PLT */ /* Need the .byte stuff around. Why? */ /* Use inline assembler */ q = mkx("%rdx", bcon(0)); q = cmop(q, mkx("%rcx", bcon(0))); q = cmop(q, mkx("%rsi", bcon(0))); q = cmop(q, mkx("%rdi", bcon(0))); q = cmop(q, mkx("%r8", bcon(0))); q = cmop(q, mkx("%r9", bcon(0))); q = cmop(q, mkx("%r10", bcon(0))); q = cmop(q, mkx("%r11", bcon(0))); s = ccopy(r = tempnode(0, INCREF(p->n_type), p->n_df, p->n_ap)); r = mkx("=a", r); r = block(XASM, r, q, INT, 0, 0); /* Create the magic string */ s1 = ".byte 0x66\n\tleaq "; s2 = "@TLSGD(%%rip),%%rdi\n" "\t.word 0x6666\n\trex64\n\tcall __tls_get_addr@PLT"; if (attr_find(p->n_sp->sap, ATTR_SONAME) == NULL) { p->n_sp->sap = attr_add(p->n_sp->sap, attr_new(ATTR_SONAME, 1)); p->n_sp->sap->sarg(0) = p->n_sp->sname; } r->n_name = addstring(mk3str(s1, attr_find(p->n_sp->sap, ATTR_SONAME)->sarg(0), s2)); r = block(COMOP, r, s, INCREF(p->n_type), p->n_df, p->n_ap); r = buildtree(UMUL, r, NIL); tfree(p); return r; } #ifdef GCC_COMPAT /* * The "initial exec" tls model. */ static NODE * tlsinitialexec(NODE *p) { NODE *q, *r, *s; char *s1, *s2; /* * movq %fs:0,%rax * addq x@GOTTPOFF(%rip),%rax */ q = bcon(0); q->n_type = STRTY; s = ccopy(r = tempnode(0, INCREF(p->n_type), p->n_df, p->n_ap)); r = mkx("=r", r); r = block(XASM, r, q, INT, 0, 0); s1 = "movq %%fs:0,%0\n\taddq "; s2 = "@GOTTPOFF(%%rip),%0"; if (attr_find(p->n_sp->sap, ATTR_SONAME) == NULL) { p->n_sp->sap = attr_add(p->n_sp->sap, attr_new(ATTR_SONAME, 1)); p->n_sp->sap->sarg(0) = p->n_sp->sname; } r->n_name = mk3str(s1, attr_find(p->n_sp->sap, ATTR_SONAME)->sarg(0), s2); r = block(COMOP, r, s, INCREF(p->n_type), p->n_df, p->n_ap); r = buildtree(UMUL, r, NIL); tfree(p); return r; } #endif static NODE * tlsref(NODE *p) { #ifdef GCC_COMPAT struct symtab *sp = p->n_sp; struct attr *ga; char *c; if ((ga = attr_find(sp->sap, GCC_ATYP_TLSMODEL)) != NULL) { c = ga->sarg(0); if (strcmp(c, "initial-exec") == 0) return tlsinitialexec(p); else if (strcmp(c, "global-dynamic") == 0) ; else werror("unsupported tls model '%s'", c); } #endif return tlspic(p); } /* clocal() is called to do local transformations on * an expression tree preparitory to its being * written out in intermediate code. * * the major essential job is rewriting the * automatic variables and arguments in terms of * REG and OREG nodes * conversion ops which are not necessary are also clobbered here * in addition, any special features (such as rewriting * exclusive or) are easily handled here as well */ NODE * clocal(NODE *p) { register struct symtab *q; register NODE *r, *l; register int o; register int m; TWORD t; #ifdef PCC_DEBUG if (xdebug) { printf("clocal: %p\n", p); fwalk(p, eprint, 0); } #endif switch( o = p->n_op ){ case NAME: if ((q = p->n_sp) == NULL) return p; /* Nothing to care about */ switch (q->sclass) { case PARAM: case AUTO: /* fake up a structure reference */ r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); slval(r, 0); r->n_rval = FPREG; p = stref(block(STREF, r, p, 0, 0, 0)); break; case USTATIC: if (kflag == 0) break; /* FALLTHROUGH */ case STATIC: #ifdef TLS if (q->sflags & STLS) { p = tlsref(p); break; } #endif break; case REGISTER: p->n_op = REG; slval(p, 0); p->n_rval = q->soffset; break; case EXTERN: case EXTDEF: if (q->sflags & STLS) { p = tlsref(p); break; } if (kflag == 0 || statinit) break; if (blevel > 0) p = picext(p); break; } break; case UCALL: case USTCALL: /* For now, always clear eax */ l = block(REG, NIL, NIL, INT, 0, 0); regno(l) = RAX; p->n_right = clocal(buildtree(ASSIGN, l, bcon(0))); p->n_op -= (UCALL-CALL); break; case SCONV: /* Special-case shifts */ if (p->n_type == LONG && (l = p->n_left)->n_op == LS && l->n_type == INT && l->n_right->n_op == ICON) { p->n_left = l->n_left; p = buildtree(LS, p, l->n_right); nfree(l); break; } l = p->n_left; /* Float conversions may need extra casts */ if (p->n_type == FLOAT || p->n_type == DOUBLE || p->n_type == LDOUBLE) { if (l->n_type < INT || l->n_type == BOOL) { p->n_left = block(SCONV, l, NIL, ISUNSIGNED(l->n_type) ? UNSIGNED : INT, l->n_df, l->n_ap); break; } } if (p->n_type == l->n_type) { nfree(p); return l; } if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 && tsize(p->n_type, p->n_df, p->n_ap) == tsize(l->n_type, l->n_df, l->n_ap)) { if (p->n_type != FLOAT && p->n_type != DOUBLE && l->n_type != FLOAT && l->n_type != DOUBLE && l->n_type != LDOUBLE && p->n_type != LDOUBLE) { if (l->n_op == NAME || l->n_op == UMUL || l->n_op == TEMP) { l->n_type = p->n_type; nfree(p); return l; } } } if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT && coptype(l->n_op) == BITYPE && l->n_op != COMOP && l->n_op != QUEST && l->n_op != ASSIGN) { l->n_type = p->n_type; nfree(p); return l; } o = l->n_op; m = p->n_type; if (o == ICON) { /* if named constant and pointer, allow cast to long/ulong */ if (!nncon(l) && (l->n_type & TMASK) && (m == LONG || m == ULONG)) { l->n_type = m; l->n_ap = 0; return nfree(p); } if (ISPTR(l->n_type) && !nncon(l)) break; /* cannot convert named pointers */ if (l->n_sp == 0) { p->n_type = ULONG; concast(l, m); } else if (m != LONG && m != ULONG) break; l->n_type = m; l->n_ap = 0; nfree(p); return l; } else if (l->n_op == FCON) cerror("SCONV FCON"); if ((p->n_type == CHAR || p->n_type == UCHAR || p->n_type == SHORT || p->n_type == USHORT) && (l->n_type == FLOAT || l->n_type == DOUBLE || l->n_type == LDOUBLE)) { p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap); p->n_left->n_type = INT; return p; } break; case MOD: case DIV: if (o == DIV && p->n_type != CHAR && p->n_type != SHORT) break; if (o == MOD && p->n_type != CHAR && p->n_type != SHORT) break; /* make it an int division by inserting conversions */ p->n_left = makety(p->n_left, INT, 0, 0, 0); p->n_right = makety(p->n_right, INT, 0, 0, 0); p = makety(p, p->n_type, 0, 0, 0); p->n_left->n_type = INT; break; case FORCE: /* put return value in return reg */ p->n_op = ASSIGN; p->n_right = p->n_left; p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0); t = p->n_type; if (ISITY(t)) t = t - (FIMAG-FLOAT); p->n_left->n_rval = p->n_left->n_type == BOOL ? RETREG(CHAR) : RETREG(t); break; case LS: case RS: /* shift count must be in a char */ if (p->n_right->n_type == CHAR || p->n_right->n_type == UCHAR) break; p->n_right = makety(p->n_right, CHAR, 0, 0, 0); break; } #ifdef PCC_DEBUG if (xdebug) { printf("clocal end: %p\n", p); fwalk(p, eprint, 0); } #endif return(p); } void myp2tree(NODE *p) { struct attr *ap; struct symtab *sp, sps; static int dblxor, fltxor; int codeatyp(NODE *); if (p->n_op == STCALL || p->n_op == USTCALL) { /* save struct encoding */ p->n_ap = attr_add(p->n_ap, ap = attr_new(ATTR_AMD64_CMPLRET, 1)); ap->iarg(0) = codeatyp(p); } if (p->n_op == UMINUS && (p->n_type == FLOAT || p->n_type == DOUBLE)) { /* Store xor code for sign change */ if (dblxor == 0) { dblxor = getlab(); fltxor = getlab(); sps.stype = LDOUBLE; sps.squal = CON >> TSHIFT; sps.sflags = sps.sclass = 0; sps.sname = ""; sps.slevel = 1; sps.sap = NULL; sps.soffset = dblxor; locctr(DATA, &sps); defloc(&sps); printf("\t.long 0,0x80000000,0,0\n"); printf(LABFMT ":\n", fltxor); printf("\t.long 0x80000000,0,0,0\n"); } p->n_ap = attr_add(p->n_ap, ap = attr_new(ATTR_AMD64_XORLBL, 1)); ap->iarg(0) = p->n_type == FLOAT ? fltxor : dblxor; return; } if (kflag && (cdope(p->n_op) & CALLFLG) && p->n_left->n_op == NAME) { /* Convert @GOTPCREL to @PLT */ char *s; sp = p->n_left->n_sp; if ((s = strstr(sp->sname, "@GOTPCREL")) != NULL) { if (mcmodel & MCLARGE) memcpy(s, "@PLTOFF", sizeof("@PLTOFF")); else memcpy(s, "@PLT", sizeof("@PLT")); p->n_left->n_op = ICON; } return; } if (p->n_op != FCON) return; #ifdef mach_amd64 { /* Do not lose negative zeros */ long long ll[2]; short ss; #ifdef LANG_CXX memcpy(ll, &p->n_dcon, sizeof(ll)); #else memcpy(ll, p->n_scon, sizeof(ll)); #endif memcpy(&ss, &ll[1], sizeof(ss)); if (ll[0] == 0 && ss == 0) return; } #else #error fixme #endif /* XXX should let float constants follow */ sp = IALLOC(sizeof(struct symtab)); sp->sclass = STATIC; sp->sap = NULL; sp->slevel = 1; /* fake numeric label */ sp->soffset = getlab(); sp->sflags = 0; sp->stype = p->n_type; sp->squal = (CON >> TSHIFT); sp->sname = NULL; locctr(DATA, sp); defloc(sp); inval(0, tsize(sp->stype, sp->sdf, sp->sap), p); p->n_op = NAME; slval(p, 0); p->n_sp = sp; } /* * Convert ADDROF NAME to ICON? */ int andable(NODE *p) { #ifdef notdef /* shared libraries cannot have direct referenced static syms */ if (p->n_sp->sclass == STATIC || p->n_sp->sclass == USTATIC) return 1; #endif return !kflag; } /* * Return 1 if a variable of type type is OK to put in register. */ int cisreg(TWORD t) { if (t == LDOUBLE) return 0; return 1; } /* * Allocate off bits on the stack. p is a tree that when evaluated * is the multiply count for off, t is a storeable node where to write * the allocated address. */ void spalloc(NODE *t, NODE *p, OFFSZ off) { NODE *sp; p = buildtree(MUL, p, bcon(off/SZCHAR)); p = buildtree(PLUS, p, bcon(30)); p = buildtree(AND, p, xbcon(-16, NULL, LONG)); /* sub the size from sp */ sp = block(REG, NIL, NIL, p->n_type, 0, 0); slval(sp, 0); sp->n_rval = STKREG; ecomp(buildtree(MINUSEQ, sp, p)); /* save the address of sp */ sp = block(REG, NIL, NIL, PTR+LONG, t->n_df, t->n_ap); slval(sp, 0); sp->n_rval = STKREG; t->n_type = sp->n_type; ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */ } /* * print out a constant node, may be associated with a label. * Do not free the node after use. * off is bit offset from the beginning of the aggregate * fsz is the number of bits this is referring to */ int ninval(CONSZ off, int fsz, NODE *p) { return 0; } /* make a name look like an external name in the local machine */ char * exname(char *p) { #ifdef MACHOABI #define NCHNAM 256 static char text[NCHNAM+1]; int i; if (p == NULL) return ""; text[0] = '_'; for (i=1; *p && istype, sp->sdf, sp->sap); SETOFF(off,SZCHAR); off /= SZCHAR; al = talign(sp->stype, sp->sap)/SZCHAR; #ifdef MACHOABI if (sp->sclass == STATIC) { al = ispow2(al); printf("\t.zerofill __DATA,__bss,"); if (sp->slevel == 0) { printf("%s", name); } else printf(LABFMT, sp->soffset); printf(",%lld,%d\n", off, al); } else { printf("\t.comm %s,0%llo,%d\n", name, off, al); } #else if (sp->sclass == STATIC) { if (sp->slevel == 0) { printf("\t.local %s\n", name); } else printf("\t.local " LABFMT "\n", sp->soffset); } if (sp->slevel == 0) { printf("\t.comm %s,0%llo,%d\n", name, off, al); } else printf("\t.comm " LABFMT ",0%llo,%d\n", sp->soffset, off, al); #endif } static char * section2string(char *name) { size_t len = strlen(name); if (strncmp(name, "link_set", 8) == 0) { const char postfix[] = ",\"aw\",@progbits"; char *s; s = IALLOC(len + sizeof(postfix)); memcpy(s, name, len); memcpy(s + len, postfix, sizeof(postfix)); return s; } return newstring(name, len); } char *nextsect; static int gottls; static char *alias; static int constructor; static int destructor; /* * Give target the opportunity of handling pragmas. */ int mypragma(char *str) { char *a2 = pragtok(NULL); if (strcmp(str, "tls") == 0 && a2 == NULL) { gottls = 1; return 1; } if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) { constructor = 1; return 1; } if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) { destructor = 1; return 1; } if (strcmp(str, "section") == 0 && a2 != NULL) { nextsect = section2string(a2); return 1; } if (strcmp(str, "alias") == 0 && a2 != NULL) { alias = tmpstrdup(a2); return 1; } return 0; } /* * Called when a identifier has been declared. */ void fixdef(struct symtab *sp) { /* may have sanity checks here */ if (gottls) sp->sflags |= STLS; gottls = 0; #ifdef GCC_COMPAT struct attr *ga; #ifdef HAVE_WEAKREF /* not many as'es have this directive */ if ((ga = attr_find(sp->sap, GCC_ATYP_WEAKREF)) != NULL) { char *wr = ga->sarg(0); char *sn = getsoname(sp); if (wr == NULL) { if ((ga = attr_find(sp->sap, GCC_ATYP_ALIAS))) { wr = ga->sarg(0); } } if (wr == NULL) printf("\t.weak %s\n", sn); else printf("\t.weakref %s,%s\n", sn, wr); } else #endif if ((ga = attr_find(sp->sap, GCC_ATYP_ALIAS)) != NULL) { char *an = ga->sarg(0); char *sn = getsoname(sp); char *v; v = attr_find(sp->sap, GCC_ATYP_WEAK) ? "weak" : "globl"; printf("\t.%s %s\n", v, sn); printf("\t.set %s,%s\n", sn, an); } #endif if (alias != NULL && (sp->sclass != PARAM)) { printf("\t.globl %s\n", getexname(sp)); printf("%s = ", getexname(sp)); printf("%s\n", exname(alias)); alias = NULL; } if ((constructor || destructor) && (sp->sclass != PARAM)) { NODE *p = talloc(); p->n_op = NAME; p->n_sp = (struct symtab *)(constructor ? "constructor" : "destructor"); #ifdef GCC_COMPAT sp->sap = attr_add(sp->sap, gcc_attr_parse(p)); #endif constructor = destructor = 0; } } void pass1_lastchance(struct interpass *ip) { } pcc-20181216/arch/amd64/local2.c010064400017500000000000000604561337633627300146640ustar raggewheel/* $Id: local2.c,v 1.70 2018/11/24 21:03:55 ragge Exp $ */ /* * Copyright (c) 2008 Michael Shalayeff * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass2.h" # include # include static int stkpos; void deflab(int label) { printf(LABFMT ":\n", label); } static int regoff[MAXREGS]; static TWORD ftype; char *rbyte[], *rshort[], *rlong[]; static int needframe; int mcmodel = MCSMALL; /* * Print out the prolog assembler. * addto and regoff are already calculated. */ static void prtprolog(struct interpass_prolog *ipp, int addto) { int i; printf("\tpushq %%rbp\n"); printf("\tmovq %%rsp,%%rbp\n"); addto = (addto+15) & ~15; /* 16-byte aligned */ if (addto) printf("\tsubq $%d,%%rsp\n", addto); /* save permanent registers */ for (i = 0; i < MAXREGS; i++) if (TESTBIT(p2env.p_regs, i)) printf("\tmovq %s,-%d(%s)\n", rnames[i], regoff[i], rnames[FPREG]); } /* * calculate stack size and offsets */ static int offcalc(struct interpass_prolog *ipp) { int i, addto; addto = p2maxautooff; if (addto >= AUTOINIT/SZCHAR) addto -= AUTOINIT/SZCHAR; for (i = 0; i < MAXREGS; i++) if (TESTBIT(p2env.p_regs, i)) { addto += SZLONG/SZCHAR; regoff[i] = addto; } return addto; } /* * Traverse a tree to check if we need to emit a frame at all. * We emit it if: * - any function call * - rsp or rbp referenced * Return 1 if frame is needed, 0 otherwise. */ static int chkf(NODE *p) { int o = p->n_op; if ((o == REG || o == OREG) && (regno(p) == RBP || regno(p) == RSP)) return 1; if (callop(o)) return 1; if (optype(o) == UTYPE) return chkf(p->n_left); else if (optype(o) == BITYPE) return chkf(p->n_left) || chkf(p->n_right); return 0; } static int chkframe(struct interpass_prolog *ipp) { struct interpass *ip; DLIST_FOREACH(ip, &ipp->ipp_ip, qelem) { if (ip->type == IP_EPILOG) break; if (ip->type == IP_NODE) { if (chkf(ip->ip_node)) return 1; } } return 0; } void prologue(struct interpass_prolog *ipp) { int addto; ftype = ipp->ipp_type; if (xdeljumps) needframe = chkframe(ipp); else needframe = 1; #ifdef LANG_F77 if (ipp->ipp_vis) printf(" .globl %s\n", ipp->ipp_name); printf(" .align 16\n"); printf("%s:\n", ipp->ipp_name); #endif /* * We here know what register to save and how much to * add to the stack. */ addto = offcalc(ipp); if (addto) needframe = 1; if (needframe) prtprolog(ipp, addto); } void eoftn(struct interpass_prolog *ipp) { int i; if (ipp->ipp_ip.ip_lbl == 0) return; /* no code needs to be generated */ if (needframe) { /* return from function code */ for (i = 0; i < MAXREGS; i++) if (TESTBIT(p2env.p_regs, i)) printf(" movq -%d(%s),%s\n", regoff[i], rnames[FPREG], rnames[i]); /* struct return needs special treatment */ if (ftype == STRTY || ftype == UNIONTY) { printf(" movl 8(%%ebp),%%eax\n"); printf(" leave\n"); printf(" ret $%d\n", 4); } else { printf(" leave\n"); printf(" ret\n"); } } else printf("\tret\n"); #ifndef MACHOABI printf("\t.size %s,.-%s\n", ipp->ipp_name, ipp->ipp_name); #endif } /* * add/sub/... * * Param given: */ void hopcode(int f, int o) { char *str; switch (o) { case PLUS: str = "add"; break; case MINUS: str = "sub"; break; case AND: str = "and"; break; case OR: str = "or"; break; case ER: str = "xor"; break; default: comperr("hopcode2: %d", o); str = 0; /* XXX gcc */ } printf("%s%c", str, f); } /* * Return type size in bytes. Used by R2REGS, arg 2 to offset(). */ int tlen(NODE *p) { switch(p->n_type) { case CHAR: case UCHAR: return(1); case SHORT: case USHORT: return(SZSHORT/SZCHAR); case DOUBLE: return(SZDOUBLE/SZCHAR); case INT: case UNSIGNED: return(SZINT/SZCHAR); case LONG: case ULONG: case LONGLONG: case ULONGLONG: return SZLONGLONG/SZCHAR; default: if (!ISPTR(p->n_type)) comperr("tlen type %d not pointer"); return SZPOINT(p->n_type)/SZCHAR; } } /* * Compare two floating point numbers. */ static void fcomp(NODE *p) { int swap = ((p->n_su & DORIGHT) != 0); int failjump = attr_find(p->n_ap, ATTR_FP_SWAPPED) != 0; //printf("fcomp: DOR %d op %s\n", swap, opst[p->n_op]); if (p->n_op == GT || p->n_op == GE) { swap ^= 1; p->n_op = (p->n_op == GT ? LT : LE); } //printf("fcomp2: DOR %d op %s\n", swap, opst[p->n_op]); if (swap) expand(p, 0, "\tfxch\n"); expand(p, 0, "\tfucomip %st(1),%st\n"); /* emit compare insn */ expand(p, 0, "\tfstp %st(0)\n"); /* pop fromstack */ switch (p->n_op) { case EQ: /* jump if: Z is set and P is clear */ expand(p, 0, "\tjne 1f\n"); expand(p, 0, "\tjnp LC\n"); expand(p, 0, "\t1:\n"); break; case NE: /* jump if: Z is clear or P is set */ expand(p, 0, "\tjne LC\n"); expand(p, 0, "\tjp LC\n"); break; case LT: expand(p, 0, "\tja LC\n"); if (failjump) expand(p, 0, "\tjp LC\n"); break; case LE: expand(p, 0, "\tjae LC\n"); if (failjump) expand(p, 0, "\tjp LC\n"); break; } } int fldexpand(NODE *p, int cookie, char **cp) { comperr("fldexpand"); return 0; } static void stasg(NODE *p) { struct attr *ap = attr_find(p->n_ap, ATTR_P2STRUCT); expand(p, INAREG, " leaq AL,%rdi\n"); if (ap->iarg(0) >= 8) printf("\tmovl $%d,%%ecx\n\trep movsq\n", ap->iarg(0) >> 3); if (ap->iarg(0) & 4) printf("\tmovsl\n"); if (ap->iarg(0) & 2) printf("\tmovsw\n"); if (ap->iarg(0) & 1) printf("\tmovsb\n"); } #define E(x) expand(p, 0, x) /* * Generate code to convert an unsigned long to xmm float/double. */ static void ultofd(NODE *p) { E(" movq AL,A1\n"); E(" testq A1,A1\n"); E(" js 2f\n"); E(" cvtsi2sZfq A1,A3\n"); E(" jmp 3f\n"); E("2:\n"); E(" movq A1,A2\n"); E(" shrq A2\n"); E(" andq $1,A1\n"); E(" orq A1,A2\n"); E(" cvtsi2sZfq A2,A3\n"); E(" addsZf A3,A3\n"); E("3:\n"); } /* * Generate code to convert an SSE float/double to an unsigned long. */ static void fdtoul(NODE *p) { if (p->n_left->n_type == FLOAT) E(" movabsq $0x5f000000,A1\n"); else E(" movabsq $0x43e0000000000000,A1\n"); E(" movd A1,A3\n"); E(" ucomisZg A3,AL\n"); E(" jae 2f\n"); E(" cvttsZg2siq AL,A1\n"); E(" jmp 3f\n"); E("2:\n"); E(" subsZg A3,AL\n"); E(" cvttsZg2siq AL,A1\n"); E(" movabsq $0x8000000000000000,A2\n"); E(" xorq A2,A1\n"); E("3:\n"); } #undef E void zzzcode(NODE *p, int c) { struct attr *ap, *ap2; NODE *l; int pr, lr, s; char **rt; switch (c) { case 'A': /* swap st0 and st1 if right is evaluated second */ if ((p->n_su & DORIGHT) == 0) { if (logop(p->n_op)) printf(" fxch\n"); else printf("r"); } break; case 'b': /* float/double to unsigned long cast */ fdtoul(p); break; case 'C': /* remove from stack after subroutine call */ pr = p->n_qual; if (p->n_op == UCALL) return; /* XXX remove ZC from UCALL */ if (pr) printf(" addq $%d, %s\n", pr, rnames[RSP]); #define STRREG 6 #define STRSSE 8 #define STRIF 9 #define STRFI 10 #define STRX87 11 ap = attr_find(p->n_ap, ATTR_P2STRUCT); ap2 = attr_find(p->n_ap, ATTR_AMD64_CMPLRET); if ((p->n_op == STCALL || p->n_op == USTCALL) && ap->iarg(0) == 32 && ap2->iarg(0) == STRX87) { printf("\tfstpt -%d(%%rbp)\n", stkpos); printf("\tfstpt -%d(%%rbp)\n", stkpos-16); printf("\tleaq -%d(%%rbp),%%rax\n", stkpos); } if ((p->n_op == STCALL || p->n_op == USTCALL) && ap->iarg(0) <= 16) { /* store reg-passed structs on stack */ if (ap2->iarg(0) == STRREG || ap2->iarg(0) == STRIF) printf("\tmovq %%rax,-%d(%%rbp)\n", stkpos); else printf("\tmovsd %%xmm0,-%d(%%rbp)\n", stkpos); if (ap->iarg(0) > 8) { if (ap2->iarg(0) == STRREG) printf("\tmovq %%rdx"); else if (ap2->iarg(0) == STRFI) printf("\tmovq %%rax"); else if (ap2->iarg(0) == STRIF) printf("\tmovsd %%xmm0"); else printf("\tmovsd %%xmm1"); printf(",-%d(%%rbp)\n", stkpos-8); } printf("\tleaq -%d(%%rbp),%%rax\n", stkpos); } break; case 'c': /* xor label */ if ((ap = attr_find(p->n_ap, ATTR_AMD64_XORLBL)) == NULL) comperr("missing xor label"); printf(LABFMT, ap->iarg(0)); break; case 'F': /* Structure argument */ ap = attr_find(p->n_ap, ATTR_P2STRUCT); printf(" subq $%d,%%rsp\n", ap->iarg(0)); printf(" movq %%rsp,%%rsi\n"); stasg(p); break; case 'G': /* Floating point compare */ fcomp(p); break; case 'j': /* convert unsigned long to f/d */ ultofd(p); break; case 'M': /* Output sconv move, if needed */ l = getlr(p, 'L'); /* XXX fixneed: regnum */ pr = DECRA(p->n_reg, 0); lr = DECRA(l->n_reg, 0); if (pr == lr) break; printf(" movb %s,%s\n", rbyte[lr], rbyte[pr]); l->n_rval = l->n_reg = p->n_reg; /* XXX - not pretty */ break; case 'N': /* output long reg name */ printf("%s", rlong[getlr(p, '1')->n_rval]); break; case 'P': /* Put hidden argument in rdi */ ap = attr_find(p->n_ap, ATTR_P2STRUCT); ap2 = attr_find(p->n_ap, ATTR_AMD64_CMPLRET); if (ap->iarg(0) > 16 && ap2->iarg(0) != STRX87) printf("\tleaq -%d(%%rbp),%%rdi\n", stkpos); break; case 'Q': /* emit struct assign */ stasg(p); break; case 'R': /* print opname based on right type */ case 'L': /* print opname based on left type */ switch (getlr(p, c)->n_type) { case CHAR: case UCHAR: s = 'b'; break; case SHORT: case USHORT: s = 'w'; break; case INT: case UNSIGNED: s = 'l'; break; default: s = 'q'; break; } printf("%c", s); break; case 'U': { /* output branch insn for ucomi */ static char *fpcb[] = { "jz", "jnz", "jbe", "jc", "jnc", "ja" }; if (p->n_op < EQ || p->n_op > GT) comperr("bad fp branch"); if (p->n_op == NE || p->n_op == GT || p->n_op == GE) expand(p, 0, " jp LC\n"); else if (p->n_op == EQ) printf("\tjp 1f\n"); printf(" %s ", fpcb[p->n_op - EQ]); expand(p, 0, "LC\n"); if (p->n_op == EQ) printf("1:\n"); break; } case '8': /* special reg name printout (64-bit) */ case '1': /* special reg name printout (32-bit) */ l = getlr(p, '1'); rt = c == '8' ? rnames : rlong; printf("%s", rt[l->n_rval]); break; case 'g': p = p->n_left; /* FALLTHROUGH */ case 'f': /* float or double */ printf("%c", p->n_type == FLOAT ? 's' : 'd'); break; case 'q': /* int or long */ printf("%c", p->n_left->n_type == LONG ? 'q' : ' '); break; default: comperr("zzzcode %c", c); } } int canaddr(NODE *); int canaddr(NODE *p) { int o = p->n_op; if (o==NAME || o==REG || o==ICON || o==OREG || (o==UMUL && shumul(p->n_left, SOREG))) return(1); return(0); } /* * Does the bitfield shape match? */ int flshape(NODE *p) { comperr("flshape"); return(0); } /* INTEMP shapes must not contain any temporary registers */ /* XXX should this go away now? */ int shtemp(NODE *p) { return 0; #if 0 int r; if (p->n_op == STARG ) p = p->n_left; switch (p->n_op) { case REG: return (!istreg(p->n_rval)); case OREG: r = p->n_rval; if (R2TEST(r)) { if (istreg(R2UPK1(r))) return(0); r = R2UPK2(r); } return (!istreg(r)); case UMUL: p = p->n_left; return (p->n_op != UMUL && shtemp(p)); } if (optype(p->n_op) != LTYPE) return(0); return(1); #endif } void adrcon(CONSZ val) { printf("$" CONFMT, val); } void conput(FILE *fp, NODE *p) { long val = getlval(p); switch (p->n_op) { case ICON: if (p->n_name[0] != '\0') { fprintf(fp, "%s", p->n_name); if (val) fprintf(fp, "+%ld", val); } else fprintf(fp, "%ld", val); return; default: comperr("illegal conput, p %p", p); } } /*ARGSUSED*/ void insput(NODE *p) { comperr("insput"); } /* * Write out the upper address, like the upper register of a 2-register * reference, or the next memory location. * XXX - not needed on amd64 */ void upput(NODE *p, int size) { size /= SZCHAR; switch (p->n_op) { case REG: printf("%%%s", &rnames[p->n_rval][3]); break; case NAME: case OREG: setlval(p, getlval(p) + size); adrput(stdout, p); setlval(p, getlval(p) - size); break; case ICON: printf("$" CONFMT, getlval(p) >> 32); break; default: comperr("upput bad op %d size %d", p->n_op, size); } } void adrput(FILE *io, NODE *p) { int r; char **rc; /* output an address, with offsets, from p */ switch (p->n_op) { case NAME: if (p->n_name[0] != '\0') { if (getlval(p) != 0) fprintf(io, CONFMT "+", getlval(p)); fprintf(io, "%s(%%rip)", p->n_name); } else fprintf(io, CONFMT, getlval(p)); return; case OREG: r = p->n_rval; if (p->n_name[0]) printf("%s%s", p->n_name, getlval(p) ? "+" : ""); if (getlval(p)) fprintf(io, "%lld", getlval(p)); if (R2TEST(r)) { int r1 = R2UPK1(r); int r2 = R2UPK2(r); int sh = R2UPK3(r); fprintf(io, "(%s,%s,%d)", r1 == MAXREGS ? "" : rnames[r1], r2 == MAXREGS ? "" : rnames[r2], sh); } else fprintf(io, "(%s)", rnames[p->n_rval]); return; case ICON: /* addressable value of the constant */ fputc('$', io); conput(io, p); return; case REG: switch (p->n_type) { case CHAR: case UCHAR: rc = rbyte; break; case SHORT: case USHORT: rc = rshort; break; case INT: case UNSIGNED: rc = rlong; break; default: rc = rnames; break; } fprintf(io, "%s", rc[p->n_rval]); return; default: comperr("illegal address, op %d, node %p", p->n_op, p); return; } } static char * ccbranches[] = { "je", /* jumpe */ "jne", /* jumpn */ "jle", /* jumple */ "jl", /* jumpl */ "jge", /* jumpge */ "jg", /* jumpg */ "jbe", /* jumple (jlequ) */ "jb", /* jumpl (jlssu) */ "jae", /* jumpge (jgequ) */ "ja", /* jumpg (jgtru) */ }; /* printf conditional and unconditional branches */ void cbgen(int o, int lab) { if (o < EQ || o > UGT) comperr("bad conditional branch: %s", opst[o]); printf(" %s " LABFMT "\n", ccbranches[o-EQ], lab); } /* * gcc xasm has the ability to generate different asm types * via some magic. * * Only support AT&T asm for now. */ static char * adjustname(char *s) { size_t len = strlen(s); char *d = tmpalloc(len+1); int i, j, flvl, tlvl; flvl = tlvl = 0; for (i = j = 0; i < (int)len; i++) { switch (s[i]) { case '{': tlvl++; break; case '}': if (tlvl)tlvl--; else flvl--; break; case '|': tlvl--; flvl++; break; default: if (flvl == 0) d[j++] = s[i]; break; } } d[j] = 0; return d; } static void fixcalls(NODE *p, void *arg) { int ps; /* Prepare for struct return by allocating bounce space on stack */ switch (p->n_op) { case STCALL: case USTCALL: ps = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0); if (ps < 16) ps = 16; if (ps+p2autooff > stkpos) stkpos = ps+p2autooff; break; case XASM: p->n_name = adjustname(p->n_name); break; } } void myreader(struct interpass *ipole) { struct interpass *ip; stkpos = p2autooff; DLIST_FOREACH(ip, ipole, qelem) { if (ip->type != IP_NODE) continue; walkf(ip->ip_node, fixcalls, 0); } if (stkpos > p2autooff) p2autooff = stkpos; if (stkpos > p2maxautooff) p2maxautooff = stkpos; if (x2debug) printip(ipole); } /* * Remove some PCONVs after OREGs are created. */ static void pconv2(NODE *p, void *arg) { NODE *q; if (p->n_op == PLUS) { if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) { if (p->n_right->n_op != ICON) return; if (p->n_left->n_op != PCONV) return; if (p->n_left->n_left->n_op != OREG) return; q = p->n_left->n_left; nfree(p->n_left); p->n_left = q; /* * This will be converted to another OREG later. */ } } if (mcmodel & (MCMEDIUM|MCLARGE)) { if (p->n_op == NAME) { q = tcopy(p); p->n_left = q; p->n_op = UMUL; q->n_op = ICON; q->n_type = INCREF(q->n_type); } else if (p->n_op == ADDROF && p->n_left->n_op == UMUL) { q = p->n_left; *p = *p->n_left->n_left; q = nfree(q); nfree(q); } } } void mycanon(NODE *p) { walkf(p, pconv2, 0); } void myoptim(struct interpass *ip) { } void rmove(int s, int d, TWORD t) { switch (t) { case INT: case UNSIGNED: printf(" movl %s,%s\n", rlong[s], rlong[d]); break; case CHAR: case UCHAR: printf(" movb %s,%s\n", rbyte[s], rbyte[d]); break; case SHORT: case USHORT: printf(" movw %s,%s\n", rshort[s], rshort[d]); break; case FLOAT: printf(" movss %s,%s\n", rnames[s], rnames[d]); break; case DOUBLE: printf(" movsd %s,%s\n", rnames[s], rnames[d]); break; case LDOUBLE: #ifdef notdef /* a=b()*c(); will generate this */ /* XXX can it fail anyway? */ comperr("bad float rmove: %d %d", s, d); #endif break; default: printf(" movq %s,%s\n", rnames[s], rnames[d]); break; } } /* * For class c, find worst-case displacement of the number of * registers in the array r[] indexed by class. */ int COLORMAP(int c, int *r) { switch (c) { case CLASSA: return r[CLASSA] < 14; case CLASSB: return r[CLASSB] < 16; case CLASSC: return r[CLASSC] < CREGCNT; } return 0; /* XXX gcc */ } char *rnames[MAXREGS] = { "%rax", "%rdx", "%rcx", "%rbx", "%rsi", "%rdi", "%rbp", "%rsp", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7", "%xmm8", "%xmm9", "%xmm10", "%xmm11", "%xmm12", "%xmm13", "%xmm14", "%xmm15", }; /* register names for shorter sizes */ char *rbyte[] = { "%al", "%dl", "%cl", "%bl", "%sil", "%dil", "%bpl", "%spl", "%r8b", "%r9b", "%r10b", "%r11b", "%r12b", "%r13b", "%r14b", "%r15b", }; char *rshort[] = { "%ax", "%dx", "%cx", "%bx", "%si", "%di", "%bp", "%sp", "%r8w", "%r9w", "%r10w", "%r11w", "%r12w", "%r13w", "%r14w", "%r15w", }; char *rlong[] = { "%eax", "%edx", "%ecx", "%ebx", "%esi", "%edi", "%ebp", "%esp", "%r8d", "%r9d", "%r10d", "%r11d", "%r12d", "%r13d", "%r14d", "%r15d", }; /* * Return a class suitable for a specific type. */ int gclass(TWORD t) { if (t == LDOUBLE) return CLASSC; if (t == FLOAT || t == DOUBLE) return CLASSB; return CLASSA; } static int argsiz(NODE *p) { TWORD t = p->n_type; if (p->n_left->n_op == REG) return 0; /* not on stack */ if (t == LDOUBLE) return 16; if (p->n_op == STASG) return attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0); return 8; } /* * Calculate argument sizes. */ void lastcall(NODE *p) { NODE *op = p; int size = 0; p->n_qual = 0; if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) return; for (p = p->n_right; p->n_op == CM; p = p->n_left) size += argsiz(p->n_right); size += argsiz(p); size = (size+15) & ~15; if (size) printf(" subq $%d,%s\n", size, rnames[RSP]); op->n_qual = size; /* XXX */ } /* * Special shapes. */ int special(NODE *p, int shape) { int o = p->n_op; switch (shape) { case SFUNCALL: if (o == STCALL || o == USTCALL) return SRREG; break; case SPCON: if (o != ICON || p->n_name[0] || getlval(p) < 0 || getlval(p) > 0x7fffffff) break; return SRDIR; case SMIXOR: return tshape(p, SZERO); case SMILWXOR: if (o != ICON || p->n_name[0] || getlval(p) == 0 || getlval(p) & 0xffffffff) break; return SRDIR; case SMIHWXOR: if (o != ICON || p->n_name[0] || getlval(p) == 0 || (getlval(p) >> 32) != 0) break; return SRDIR; case SCON32: if (o != ICON || p->n_name[0]) break; if (getlval(p) < MIN_INT || getlval(p) > MAX_INT) break; return SRDIR; default: cerror("special: %x\n", shape); } return SRNOPE; } /* * Target-dependent command-line options. */ void mflags(char *str) { #define S(x) (strcmp(x, str) == 0) if (S("cmodel=small")) mcmodel = MCSMALL; else if (S("cmodel=medium")) mcmodel = MCMEDIUM; else if (S("cmodel=large")) mcmodel = MCLARGE; else comperr("bad -m arg"); } /* * Do something target-dependent for xasm arguments. */ int myxasm(struct interpass *ip, NODE *p) { struct interpass *ip2; int Cmax[] = { 31, 63, 127, 0xffff, 3, 255 }; NODE *in = 0, *ut = 0; TWORD t; char *w; int reg; int c, cw, v; cw = xasmcode(p->n_name); if (cw & (XASMASG|XASMINOUT)) ut = p->n_left; if ((cw & XASMASG) == 0) in = p->n_left; c = XASMVAL(cw); retry: switch (c) { case 'D': reg = RDI; break; case 'S': reg = RSI; break; case 'A': case 'a': reg = RAX; break; case 'b': reg = RBX; break; case 'c': reg = RCX; break; case 'd': reg = RDX; break; case 'Q': reg = RDX; break; /* Always dx for now */ case 'x': case 'q': case 't': case 'u': p->n_name = tmpstrdup(p->n_name); w = strchr(p->n_name, c); *w = 'r'; /* now reg */ return c == 'q' || c == 'x' || c == 't' ? 0 : 1; case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': if (p->n_left->n_op != ICON) { if ((c = XASMVAL1(cw))) { if (c == 'r') { p->n_name++; return 0; } goto retry; } uerror("xasm arg not constant"); } v = (int)getlval(p->n_left); if ((c == 'K' && v < -128) || (c == 'L' && v != 0xff && v != 0xffff) || (c != 'K' && v < 0) || (v > Cmax[c-'I'])) uerror("xasm val out of range"); p->n_name = "i"; return 1; default: return 0; } /* If there are requested either memory or register, delete memory */ w = p->n_name = tmpstrdup(p->n_name); if (*w == '=') w++; *w++ = 'r'; *w = 0; t = p->n_left->n_type; if (t == FLOAT || t == DOUBLE) { reg += 16; } else if (t == LDOUBLE) { reg += 32; } if (in && ut) in = tcopy(in); p->n_left = mklnode(REG, 0, reg, t); if (ut) { ip2 = ipnode(mkbinode(ASSIGN, ut, tcopy(p->n_left), t)); DLIST_INSERT_AFTER(ip, ip2, qelem); } if (in) { ip2 = ipnode(mkbinode(ASSIGN, tcopy(p->n_left), in, t)); DLIST_INSERT_BEFORE(ip, ip2, qelem); } return 1; } void targarg(char *w, void *arg, int n) { NODE **ary = arg; NODE *p, *q; if (w[1] < '0' || w[1] > (n + '0')) uerror("bad xasm arg number %c", w[1]); if (w[1] == (n + '0')) p = ary[(int)w[1]-'0' - 1]; /* XXX */ else p = ary[(int)w[1]-'0']; p = p->n_left; if (optype(p->n_op) != LTYPE) comperr("bad xarg op %d", p->n_op); q = tcopy(p); if (q->n_op == REG) { if (*w == 'k') { q->n_type = INT; } else if (*w == 'q') { q->n_type = LONG; } else if (*w == 'h' || *w == 'b') { /* Can do this only because we know dx is used */ printf("%%d%c", *w == 'h' ? 'h' : 'l'); tfree(q); return; } else if (*w != 'w') { cerror("targarg"); /* XXX ??? */ if (q->n_type > UCHAR) { regno(q) = regno(q)*2+8; if (*w == 'h') regno(q)++; } q->n_type = INT; } else q->n_type = SHORT; } adrput(stdout, q); tfree(q); } /* * target-specific conversion of numeric arguments. */ int numconv(void *ip, void *p1, void *q1) { NODE *p = p1, *q = q1; int cw = xasmcode(q->n_name); switch (XASMVAL(cw)) { case 'a': case 'b': case 'c': case 'd': p->n_name = tmpcalloc(2); p->n_name[0] = XASMVAL(cw); return 1; default: return 0; } } static struct { char *name; int num; } xcr[] = { { "rax", RAX }, { "rbx", RBX }, { "rcx", RCX }, { "rdx", RDX }, { "rsi", RSI }, { "rdi", RDI }, { "r8", R08 }, { "r9", R09 }, { "r10", R10 }, { "r11", R11 }, { "r12", R12 }, { "r13", R13 }, { "r14", R14 }, { "r15", R15 }, { "st", 040 }, { "st(0)", 040 }, { "st(1)", 041 }, { "st(2)", 042 }, { "st(3)", 043 }, { "st(4)", 044 }, { "st(5)", 045 }, { "st(6)", 046 }, { "st(7)", 047 }, { NULL, 0 }, }; /* * Check for other names of the xasm constraints registers. */ int xasmconstregs(char *s) { int i; for (i = 0; xcr[i].name; i++) if (strcmp(xcr[i].name, s) == 0) return xcr[i].num; return -1; } pcc-20181216/arch/amd64/macdefs.h010064400017500000000000000223231332703467700151050ustar raggewheel/* $Id: macdefs.h,v 1.40 2018/07/28 09:39:11 ragge Exp $ */ /* * Copyright (c) 2008 Michael Shalayeff * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Machine-dependent defines for both passes. */ /* * Convert (multi-)character constant to integer. */ #define makecc(val,i) lastcon = (lastcon<<8)|((val<<24)>>24); #define ARGINIT 128 /* # bits above fp where arguments start */ #define AUTOINIT 0 /* # bits below fp where automatics start */ /* * Storage space requirements */ #define SZCHAR 8 #define SZBOOL 8 #define SZSHORT 16 #define SZINT 32 #define SZLONG 64 #define SZPOINT(t) 64 #define SZLONGLONG 64 #define SZFLOAT 32 #define SZDOUBLE 64 #define SZLDOUBLE 128 /* * Alignment constraints */ #define ALCHAR 8 #define ALBOOL 8 #define ALSHORT 16 #define ALINT 32 #define ALLONG 64 #define ALPOINT 64 #define ALLONGLONG 64 #define ALFLOAT 32 #define ALDOUBLE 64 #define ALLDOUBLE 128 /* #undef ALSTRUCT amd64 struct alignment is member defined */ #define ALSTACK 64 #define ALMAX 128 /* * Min/max values. */ #define MIN_CHAR -128 #define MAX_CHAR 127 #define MAX_UCHAR 255 #define MIN_SHORT -32768 #define MAX_SHORT 32767 #define MAX_USHORT 65535 #define MIN_INT (-0x7fffffff-1) #define MAX_INT 0x7fffffff #define MAX_UNSIGNED 0xffffffffU #define MIN_LONG 0x8000000000000000LL #define MAX_LONG 0x7fffffffffffffffLL #define MAX_ULONG 0xffffffffffffffffULL #define MIN_LONGLONG 0x8000000000000000LL #define MAX_LONGLONG 0x7fffffffffffffffLL #define MAX_ULONGLONG 0xffffffffffffffffULL /* Default char is signed */ #undef CHAR_UNSIGNED #define BOOL_TYPE UCHAR /* what used to store _Bool */ /* * Use large-enough types. */ typedef long long CONSZ; typedef unsigned long long U_CONSZ; typedef long long OFFSZ; #define CONFMT "%lld" /* format for printing constants */ #define LABFMT ".L%d" /* format for printing labels */ #define STABLBL ".LL%d" /* format for stab (debugging) labels */ #ifdef LANG_F77 #define BLANKCOMMON "_BLNK_" #define MSKIREG (M(TYSHORT)|M(TYLONG)) #define TYIREG TYLONG #define FSZLENG FSZLONG #define AUTOREG EBP #define ARGREG EBP #define ARGOFFSET 8 #endif #define TARGET_TIMODE /* has TI/TF/TC types (128 bit) */ #define BACKAUTO /* stack grows negatively for automatics */ #define BACKTEMP /* stack grows negatively for temporaries */ #undef FIELDOPS /* no bit-field instructions */ #define TARGET_ENDIAN TARGET_LE /* little-endian only */ #define FINDMOPS /* i386 has instructions that modifies memory */ #define CC_DIV_0 /* division by zero is safe in the compiler */ #ifdef MACHOABI #define HASP2ALIGN #endif /* Definitions mostly used in pass2 */ #define BYTEOFF(x) ((x)&07) #define wdal(k) (BYTEOFF(k)==0) #define STOARG(p) #define STOFARG(p) #define STOSTARG(p) #define genfcall(a,b) gencall(a,b) /* How many integer registers are needed? (used for stack allocation) */ #define szty(t) (t < LONG || t == FLOAT ? 1 : t == LDOUBLE ? 4 : 2) /* * The amd64 architecture has a much cleaner interface to its registers * than the x86, even though a part of the register block comes from * the x86 architecture. Therefore currently only two non-overlapping * register classes are used; integer and xmm registers. * * All registers are given a sequential number to * identify it which must match rnames[] in local2.c. * * The classes used on amd64 are: * A - integer registers * B - xmm registers * C - x87 registers */ #define RAX 000 #define RDX 001 #define RCX 002 #define RBX 003 #define RSI 004 #define RDI 005 #define RBP 006 #define RSP 007 #define R08 010 #define R09 011 #define R10 012 #define R11 013 #define R12 014 #define R13 015 #define R14 016 #define R15 017 #define XMM0 020 #define XMM1 021 #define XMM2 022 #define XMM3 023 #define XMM4 024 #define XMM5 025 #define XMM6 026 #define XMM7 027 #define XMM8 030 #define XMM9 031 #define XMM10 032 #define XMM11 033 #define XMM12 034 #define XMM13 035 #define XMM14 036 #define XMM15 037 #define MAXREGS 050 /* 40 registers */ #define RSTATUS \ SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|PERMREG, \ SAREG|TEMPREG, SAREG|TEMPREG, 0, 0, \ SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \ SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, \ SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, \ SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, \ SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, \ SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, /* no overlapping registers at all */ #define ROVERLAP \ { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \ { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \ { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \ { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \ { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, /* Return a register class based on the type of the node */ #define PCLASS(p) (p->n_type == FLOAT || p->n_type == DOUBLE ? SBREG : \ p->n_type == LDOUBLE ? SCREG : SAREG) #define NUMCLASS 3 /* highest number of reg classes used */ int COLORMAP(int c, int *r); #define GCLASS(x) (x < 16 ? CLASSA : x < 32 ? CLASSB : CLASSC) #define DECRA(x,y) (((x) >> (y*8)) & 255) /* decode encoded regs */ #define ENCRD(x) (x) /* Encode dest reg in n_reg */ #define ENCRA1(x) ((x) << 8) /* A1 */ #define ENCRA2(x) ((x) << 16) /* A2 */ #define ENCRA(x,y) ((x) << (8+y*8)) /* encode regs in int */ #define RETREG(x) (x == FLOAT || x == DOUBLE ? XMM0 : \ x == LDOUBLE ? 32 : RAX) /* XXX - to die */ #define FPREG RBP /* frame pointer */ #define STKREG RSP /* stack pointer */ #define SHSTR (MAXSPECIAL+1) /* short struct */ #define SFUNCALL (MAXSPECIAL+2) /* struct assign after function call */ #define SPCON (MAXSPECIAL+3) /* positive nonnamed constant */ /* * Specials that indicate the applicability of machine idioms. */ #define SMIXOR (MAXSPECIAL+4) #define SMILWXOR (MAXSPECIAL+5) #define SMIHWXOR (MAXSPECIAL+6) #define SCON32 (MAXSPECIAL+7) /* 32-bit constant */ /* * i386-specific symbol table flags. */ #define ATTR_P1_TARGET ATTR_AMD64_BEENHERE /* * Extended assembler macros. */ int xasmconstregs(char *); void targarg(char *w, void *arg, int n); #define XASM_TARGARG(w, ary) \ (w[1] == 'b' || w[1] == 'h' || w[1] == 'w' || w[1] == 'k' || \ w[1] == 'q' ? w++, targarg(w, ary, n), 1 : 0) int numconv(void *ip, void *p, void *q); #define XASM_NUMCONV(ip, p, q) numconv(ip, p, q) #define XASMCONSTREGS(x) xasmconstregs(x) #define HAVE_WEAKREF #define TARGET_FLT_EVAL_METHOD 0 /* all as their type */ /* * builtins. */ #define TARGET_VALIST #define TARGET_STDARGS #define TARGET_BUILTINS \ { "__builtin_stdarg_start", amd64_builtin_stdarg_start, \ 0, 2, 0, VOID }, \ { "__builtin_va_start", amd64_builtin_stdarg_start, \ 0, 2, 0, VOID }, \ { "__builtin_va_arg", amd64_builtin_va_arg, BTNORVAL|BTNOPROTO, \ 2, 0, 0 }, \ { "__builtin_va_end", amd64_builtin_va_end, 0, 1, 0, VOID }, \ { "__builtin_va_copy", amd64_builtin_va_copy, 0, 2, 0, VOID }, #ifdef LANG_CXX #define P1ND struct node #else #define P1ND struct p1node #endif struct node; struct bitable; P1ND *amd64_builtin_stdarg_start(const struct bitable *, P1ND *a); P1ND *amd64_builtin_va_arg(const struct bitable *, P1ND *a); P1ND *amd64_builtin_va_end(const struct bitable *, P1ND *a); P1ND *amd64_builtin_va_copy(const struct bitable *, P1ND *a); #undef P1ND /* target specific attributes */ #define ATTR_MI_TARGET ATTR_AMD64_CMPLRET, ATTR_AMD64_XORLBL /* m flags */ #define MCSMALL 00200 #define MCMEDIUM 00400 #define MCLARGE 01000 #define MCALL (MCSMALL|MCMEDIUM|MCLARGE) extern int mcmodel; /* floating point definitions */ #define USE_IEEEFP_32 #define FLT_PREFIX IEEEFP_32 #define USE_IEEEFP_64 #define DBL_PREFIX IEEEFP_64 #define USE_IEEEFP_X80 #define LDBL_PREFIX IEEEFP_X80 pcc-20181216/arch/amd64/order.c010064400017500000000000000176331321103262700146020ustar raggewheel/* $Id: order.c,v 1.19 2017/12/03 17:34:15 ragge Exp $ */ /* * Copyright (c) 2008 Michael Shalayeff * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass2.h" #include int canaddr(NODE *); /* is it legal to make an OREG or NAME entry which has an * offset of off, (from a register of r), if the * resulting thing had type t */ int notoff(TWORD t, int r, CONSZ off, char *cp) { if (off > MAX_INT || off < MIN_INT) return 1; /* max signed 32-bit offset */ return(0); /* YES */ } /* * Check if LS and try to make it indexable. * Ignore SCONV to long. * Return 0 if failed. */ static int findls(NODE *p, int check) { CONSZ c; if (p->n_op == SCONV && p->n_type == LONG && p->n_left->n_type == INT) p = p->n_left; /* Ignore pointless SCONVs here */ if (p->n_op != LS || p->n_right->n_op != ICON) return 0; if ((c = getlval(p->n_right)) != 1 && c != 2 && c != 3) return 0; if (check == 1 && p->n_left->n_op != REG) return 0; if (!isreg(p->n_left)) (void)geninsn(p->n_left, INAREG); return 1; } /* * Turn a UMUL-referenced node into OREG. * Be careful about register classes, this is a place where classes change. * * AMD64 (and i386) have a quite powerful addressing scheme: * : 4(%rax) 4 + %rax * : 4(%rbx,%rax,8) 4 + %rbx + %rax * 8 * : 4(,%rax) 4 + %rax * 8 * The 8 above can be 1,2,4 or 8. */ void offstar(NODE *p, int shape) { NODE *l; if (x2debug) { printf("offstar(%p)\n", p); fwalk(p, e2print, 0); } if (isreg(p)) return; /* Matched (%rax) */ if (findls(p, 0)) return; /* Matched (,%rax,8) */ if ((p->n_op == PLUS || p->n_op == MINUS) && p->n_left->n_op == ICON && p->n_left->n_name[0] == '\0' && notoff(0, 0, getlval(p->n_left), 0) == 0) { l = p->n_right; if (isreg(l)) return; /* Matched 4(%rax) */ if (findls(l, 0)) return; /* Matched 4(,%rax,8) */ if (l->n_op == PLUS && isreg(l->n_right)) { if (findls(l->n_left, 0)) return; /* Matched 4(%rbx,%rax,8) */ (void)geninsn(l->n_left, INAREG); return; /* Generate 4(%rbx,%rax) */ } (void)geninsn(l, INAREG); return; /* Generate 4(%rbx) */ } if (p->n_op == PLUS) { if (!isreg(p->n_left)) /* ensure right is REG */ (void)geninsn(p->n_left, INAREG); if (isreg(p->n_right)) return; /* Matched (%rax,%rbx) */ if (findls(p->n_right, 0)) return; /* Matched (%rax,%rbx,4) */ (void)geninsn(p->n_right, INAREG); return; /* Generate (%rbx,%rax) */ } (void)geninsn(p, INAREG); } /* * Do the actual conversion of offstar-found OREGs into real OREGs. * For simple OREGs conversion should already be done. */ void myormake(NODE *q) { static int shtbl[] = { 1,2,4,8 }; NODE *p, *r; CONSZ c = 0; int r1, r2, sh; int mkconv = 0; char *n = ""; #define risreg(p) (p->n_op == REG) if (x2debug) { printf("myormake(%p)\n", q); fwalk(q, e2print, 0); } r1 = r2 = MAXREGS; sh = 1; r = p = q->n_left; if ((p->n_op == PLUS || p->n_op == MINUS) && p->n_left->n_op == ICON) { c = getlval(p->n_left); n = p->n_left->n_name; p = p->n_right; } if (p->n_op == PLUS && risreg(p->n_left)) { r1 = regno(p->n_left); p = p->n_right; } if (findls(p, 1)) { if (p->n_op == SCONV) p = p->n_left; sh = shtbl[(int)getlval(p->n_right)]; r2 = regno(p->n_left); mkconv = 1; } else if (risreg(p)) { r2 = regno(p); mkconv = 1; } //else // comperr("bad myormake tree"); if (mkconv == 0) return; q->n_op = OREG; setlval(q, c); q->n_rval = R2PACK(r1, r2, sh); q->n_name = n; tfree(r); if (x2debug) { printf("myormake converted %p\n", q); fwalk(q, e2print, 0); } } /* * Shape matches for UMUL. Cooperates with offstar(). */ int shumul(NODE *p, int shape) { if (x2debug) printf("shumul(%p)\n", p); /* Turns currently anything into OREG on x86 */ if (shape & SOREG) return SROREG; return SRNOPE; } /* * Rewrite operations on binary operators (like +, -, etc...). * Called as a result of table lookup. */ int setbin(NODE *p) { if (x2debug) printf("setbin(%p)\n", p); return 0; } /* setup for assignment operator */ int setasg(NODE *p, int cookie) { if (x2debug) printf("setasg(%p)\n", p); return(0); } /* setup for unary operator */ int setuni(NODE *p, int cookie) { return 0; } /* * Special handling of some instruction register allocation. */ struct rspecial * nspecial(struct optab *q) { switch (q->op) { case SCONV: if ((q->ltype & TINT) && q->rtype == (TLONGLONG|TULONGLONG|TLONG|TULONG)) { static struct rspecial s[] = { { NLEFT, RAX }, { NRES, RAX }, { 0 } }; return s; } break; case DIV: { static struct rspecial s[] = { { NEVER, RAX }, { NEVER, RDX }, { NLEFT, RAX }, { NRES, RAX }, { NORIGHT, RDX }, { NORIGHT, RAX }, { 0 } }; return s; } break; case MOD: if (q->ltype & TUCHAR) { static struct rspecial s[] = { { NEVER, RAX }, { NLEFT, RAX }, { NRES, RAX }, { NORIGHT, RAX }, { 0 } }; return s; } else { static struct rspecial s[] = { { NEVER, RAX }, { NEVER, RDX }, { NLEFT, RAX }, { NRES, RDX }, { NORIGHT, RDX }, { NORIGHT, RAX }, { 0 } }; return s; } break; case STARG: { static struct rspecial s[] = { { NEVER, RDI }, { NLEFT, RSI }, { NEVER, RCX }, { 0 } }; return s; } case STASG: { static struct rspecial s[] = { { NEVER, RDI }, { NRIGHT, RSI }, { NOLEFT, RSI }, { NOLEFT, RCX }, { NORIGHT, RCX }, { NEVER, RCX }, { 0 } }; return s; } case MUL: if (q->lshape == SAREG) { static struct rspecial s[] = { { NEVER, RAX }, { NLEFT, RAX }, { NRES, RAX }, { 0 } }; return s; } break; case LS: case RS: { static struct rspecial s[] = { { NRIGHT, RCX }, { NOLEFT, RCX }, { 0 } }; return s; } break; default: break; } comperr("nspecial entry %d", q - table); return 0; /* XXX gcc */ } /* * Set evaluation order of a binary node if it differs from default. */ int setorder(NODE *p) { return 0; /* nothing differs on x86 */ } /* * set registers in calling conventions live. */ int * livecall(NODE *p) { static int r[NTEMPREG+1]; NODE *q; int cr = 0; if (optype(p->n_op) != BITYPE) return r[0] = -1, r; for (q = p->n_right; q->n_op == CM; q = q->n_left) { if (q->n_right->n_op == ASSIGN && q->n_right->n_left->n_op == REG) r[cr++] = regno(q->n_right->n_left); } if (q->n_op == ASSIGN && q->n_left->n_op == REG) r[cr++] = regno(q->n_left); r[cr++] = -1; return r; } /* * Signal whether the instruction is acceptable for this target. */ int acceptable(struct optab *op) { if (op->visit & MCALL) return (op->visit & mcmodel) != 0; return 1; } pcc-20181216/arch/amd64/table.c010064400017500000000000000733071337633627300145760ustar raggewheel/* $Id: table.c,v 1.57 2018/11/24 21:03:55 ragge Exp $ */ /* * Copyright (c) 2008 Michael Shalayeff * Copyright (c) 2008 Anders Magnusson (ragge@ludd.ltu.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass2.h" #define TLL TLONG|TULONG # define ANYSIGNED TINT|TSHORT|TCHAR # define ANYUSIGNED TUNSIGNED|TUSHORT|TUCHAR # define ANYFIXED ANYSIGNED|ANYUSIGNED # define TUWORD TUNSIGNED # define TSWORD TINT # define TWORD TUWORD|TSWORD #define TANYINT TLL|ANYFIXED #define SHINT SAREG /* Any integer */ #define ININT INAREG #define SHFL SCREG /* shape for long double */ #define INFL INCREG /* shape for long double */ struct optab table[] = { /* First entry must be an empty entry */ { -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", }, /* PCONVs are usually not necessary */ { PCONV, INAREG, SAREG, TLL|TPOINT, SAREG, TLL|TPOINT, 0, RLEFT, "", }, { PCONV, INAREG, SAREG|SOREG|SNAME, TWORD, SAREG, TPOINT, NASL|NAREG, RESC1, " movl AL,Z1\n", },/* amd64 zero-extends 32-bit movl */ { PCONV, INAREG, SAREG|SOREG|SNAME, TCHAR, SAREG, TPOINT, NAREG|NASL, RESC1, " movsbq AL,A1\n", }, { PCONV, INAREG, SAREG|SOREG|SNAME, TUCHAR, SAREG, TPOINT, NAREG|NASL, RESC1, " movsbq AL,A1\n", }, /* short to ptr */ { PCONV, INAREG, SAREG|SOREG|SNAME, TSHORT, SAREG, TPOINT, NAREG|NASL, RESC1, " movswq AL,A1\n", }, /* ushort to ptr */ { PCONV, INAREG, SAREG|SOREG|SNAME, TUSHORT, SAREG, TPOINT, NAREG|NASL, RESC1, " movzwq AL,A1\n", }, /* * On amd64 casts from larger to smaller integer type in register do nothing. */ /* 64-bit to smaller */ { SCONV, INAREG, SAREG, TLL|TPOINT, SAREG, TANYINT, 0, RLEFT, "", }, /* 32-bit to smaller */ { SCONV, INAREG, SAREG, TWORD, SAREG, ANYFIXED, 0, RLEFT, "", }, /* 16-bit to smaller */ { SCONV, INAREG, SAREG, TSHORT|TUSHORT, SAREG, TUSHORT|TUCHAR|TSHORT|TCHAR, 0, RLEFT, "", }, /* 8-bit to 8-bit */ { SCONV, INAREG, SAREG, TCHAR|TUCHAR, SAREG, TUCHAR|TCHAR, 0, RLEFT, "", }, /* * Casts from memory to same or smaller register is equally simple. */ /* 64-bit to smaller */ { SCONV, INAREG, SNAME|SOREG, TLL|TPOINT, SAREG, TANYINT, NAREG, RESC1, " movZR AL,A1\n", }, /* 32-bit to smaller */ { SCONV, INAREG, SNAME|SOREG, TWORD, SAREG, ANYFIXED, NAREG, RESC1, " movZR AL,A1\n", }, /* 16-bit to smaller */ { SCONV, INAREG, SNAME|SOREG, TSHORT|TUSHORT, SAREG, TUSHORT|TUCHAR|TSHORT|TCHAR, NAREG, RESC1, " movZR AL,A1\n", }, /* 8-bit to 8-bit */ { SCONV, INAREG, SNAME|SOREG, TCHAR|TUCHAR, SAREG, TUCHAR|TCHAR, NAREG, RESC1, " movZR AL,A1\n", }, /* char to something */ /* convert char to (unsigned) short. */ { SCONV, ININT, SAREG|SOREG|SNAME, TCHAR, SAREG, TSHORT|TUSHORT, NASL|NAREG, RESC1, " movsbw AL,A1\n", }, /* convert unsigned char to (u)short. */ { SCONV, ININT, SAREG|SOREG|SNAME, TUCHAR, SAREG, TSHORT|TUSHORT, NASL|NAREG, RESC1, " movzbw AL,A1\n", }, /* convert signed char to int (or pointer). */ { SCONV, ININT, SAREG|SOREG|SNAME, TCHAR, SAREG, TWORD|TPOINT, NASL|NAREG, RESC1, " movsbl AL,A1\n", }, /* convert unsigned char to (u)int. */ { SCONV, ININT, SAREG|SOREG|SNAME, TUCHAR, SAREG, TWORD, NASL|NAREG, RESC1, " movzbl AL,A1\n", }, /* convert char to (u)long long */ { SCONV, INAREG, SAREG|SOREG|SNAME, TCHAR, SANY, TLL, NAREG|NASL, RESC1, " movsbq AL,A1\n", }, /* convert unsigned char to (u)long long */ { SCONV, INAREG, SAREG|SOREG|SNAME, TUCHAR, SANY, TLL, NAREG|NASL, RESC1, " movzbq AL,A1\n", }, /* short to something */ /* convert short to (u)int. */ { SCONV, ININT, SAREG|SOREG|SNAME, TSHORT, SAREG, TWORD, NASL|NAREG, RESC1, " movswl AL,A1\n", }, /* convert unsigned short to (u)int. */ { SCONV, ININT, SAREG|SOREG|SNAME, TUSHORT, SAREG, TWORD, NASL|NAREG, RESC1, " movzwl AL,A1\n", }, /* convert short to (u)long long */ { SCONV, INAREG, SAREG|SOREG|SNAME, TSHORT, SAREG, TLL, NAREG|NASL, RESC1, " movswq AL,A1\n", }, /* convert unsigned short to (u)long long */ { SCONV, INAREG, SAREG|SOREG|SNAME, TUSHORT, SAREG, TLL, NAREG|NASL, RESC1, " movzwq AL,A1\n", }, /* int to something */ /* convert signed int to (u)long long */ { SCONV, INAREG, SAREG, TSWORD, SAREG, TLL, NASL|NAREG, RESC1, " movslq AL,A1\n", }, /* convert unsigned int to (u)long long */ { SCONV, INAREG, SAREG|SOREG|SNAME, TUWORD, SAREG, TLL, NASL|NAREG, RESC1, " movl AL,Z1\n", },/* amd64 zero-extends 32-bit movl */ /* * Floating point casts. amd64 uses xmm for float/double and x87 * for long double calculations. * * Types smaller than int are casted to int/(unsigned). */ /* no casts */ { SCONV, INBREG, SBREG, TFLOAT, SBREG, TFLOAT, 0, RLEFT, "", }, { SCONV, INBREG, SBREG, TDOUBLE, SBREG, TDOUBLE, 0, RLEFT, "", }, { SCONV, INCREG, SCREG, TLDOUBLE, SCREG, TLDOUBLE, 0, RLEFT, "", }, /* convert int/long to float/double */ { SCONV, INBREG, SAREG|SOREG|SNAME, TINT|TLONG, SBREG, TFLOAT|TDOUBLE, NBREG, RESC1, " cvtsi2sZfZq AL,A1\n", }, /* convert unsigned int to float/double */ { SCONV, INBREG, SAREG|SOREG|SNAME, TUNSIGNED, SBREG, TFLOAT|TDOUBLE, NAREG|NBREG, RESC2, " movl AL,Z1\n cvtsi2sZfq A1,A2\n", }, /* convert unsigned long to float/double */ { SCONV, INBREG, SAREG|SOREG|SNAME, TULONG, SBREG, TFLOAT|TDOUBLE, NAREG*2|NASL|NBREG, RESC3, "Zj", }, /* convert float/double to (u)char/(u)short/int */ { SCONV, INAREG, SBREG|SOREG|SNAME, TFLOAT|TDOUBLE, SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|INT, NAREG, RESC1, " cvttsZg2si AL,A1\n", }, /* convert float/double to unsigned int/long */ { SCONV, INAREG, SBREG|SOREG|SNAME, TFLOAT|TDOUBLE, SAREG, TUNSIGNED|TLONG, NAREG, RESC1, " cvttsZg2siq AL,Z8\n", }, /* convert float to double */ { SCONV, INBREG, SBREG|SNAME|SOREG, TFLOAT, SBREG, TDOUBLE, NBREG|NBSL, RESC1, " cvtss2sd AL,A1\n", }, /* convert double to float */ { SCONV, INBREG, SBREG|SNAME|SOREG, TDOUBLE, SBREG, TFLOAT, NBREG|NBSL, RESC1, " cvtsd2ss AL,A1\n", }, /* x87 conversions */ /* float -> ldouble */ { SCONV, INCREG, SBREG, TFLOAT, SCREG, TLDOUBLE, NCREG, RESC1, "\tsubq $4,%rsp\n\tmovss AL,(%rsp)\n" "\tflds (%rsp)\n\taddq $4,%rsp\n", }, /* double -> ldouble */ { SCONV, INCREG, SBREG, TDOUBLE, SCREG, TLDOUBLE, NCREG, RESC1, "\tsubq $8,%rsp\n\tmovsd AL,(%rsp)\n" "\tfldl (%rsp)\n\taddq $8,%rsp\n", }, /* ldouble -> double */ { SCONV, INBREG, SCREG, TLDOUBLE, SBREG, TDOUBLE, NBREG, RESC1, "\tsubq $8,%rsp\n\tfstpl (%rsp)\n" "\tmovsd (%rsp),A1\n\taddq $8,%rsp\n", }, /* ldouble -> float */ { SCONV, INBREG, SCREG, TLDOUBLE, SBREG, TFLOAT, NBREG, RESC1, "\tsubq $4,%rsp\n\tfstps (%rsp)\n" "\tmovss (%rsp),A1\n\taddq $4,%rsp\n", }, /* convert int (in memory) to long double */ { SCONV, INCREG, SOREG|SNAME, TSWORD, SCREG, TLDOUBLE, NCREG, RESC1, " fildl AL\n", }, /* convert unsigned int to long double */ { SCONV, INCREG, SAREG, TUWORD, SCREG, TLDOUBLE, NAREG|NASL|NCREG, RESC2, " subq $16,%rsp\n" " movl AL,Z1\n" " movq A1,(%rsp)\n" " fildll (%rsp)\n" " addq $16,%rsp\n", }, /* convert int (in register) to long double */ { SCONV, INCREG, SAREG, TSWORD, SCREG, TLDOUBLE, NCREG, RESC1, " subq $4,%rsp\n" " movl AL,(%rsp)\n" " fildl (%rsp)\n" " addq $4,%rsp\n", }, /* unsigned long (in reg) to long double */ { SCONV, INCREG, SAREG, TULONG, SCREG, TLDOUBLE, NCREG, RESC1, " subq $16,%rsp\n" " movq AL,(%rsp)\n" " fildll (%rsp)\n" " cmpq $0,AL\n" " jns 1f\n" " movl $1602224128,(%rsp)\n" " fadds (%rsp)\n" " addq $16,%rsp\n" "1:\n", }, /* unsigned long (in mem) to long double */ { SCONV, INCREG, SNAME|SOREG, TULONG, SCREG, TLDOUBLE, NCREG, RESC1, " fildll AL\n" " cmpq $0,AL\n" " jns 1f\n" " push $1602224128\n" " fadds (%rsp)\n" " addq $8,%rsp\n" "1:\n", }, /* convert float/double to unsigned long */ { SCONV, INAREG, SBREG, TFLOAT|TDOUBLE, SAREG, TULONG, (NAREG*2)|NBREG, RESC1, "Zb\n", }, /* long double to unsigned long */ { SCONV, INAREG, SCREG, TLDOUBLE, SAREG, TULONG, NAREG|NTEMP*2, RESC1, " fnstcw A2\n" " fnstcw 4+A2\n" " movb $7,1+A2\n" /* 64-bit, round down */ " fldcw A2\n" " movl $0x5f000000, 8+A2\n" /* (float)(1<<63) */ " fsubs 8+A2\n" /* keep in range of fistpq */ " fistpq 8+A2\n" " xorb $0x80,15+A2\n" /* addq $1>>63 to 8(%esp) */ " movq 8+A2,A1\n" " fldcw 4+A2\n", }, /* ldouble -> long XXX merge with int */ { SCONV, INAREG, SCREG, TLDOUBLE, SAREG, TLONG, NAREG, RESC1, " subq $16,%rsp\n" " fnstcw (%rsp)\n" " fnstcw 4(%rsp)\n" " movb $12,1(%rsp)\n" " fldcw (%rsp)\n" " fistpll 8(%rsp)\n" " movq 8(%rsp),A1\n" " fldcw 4(%rsp)\n" " addq $16,%rsp\n", }, /* ldouble -> (u)int */ { SCONV, INAREG, SCREG, TLDOUBLE, SAREG, TINT|TUNSIGNED, NAREG, RESC1, " subq $16,%rsp\n" " fnstcw (%rsp)\n" " fnstcw 4(%rsp)\n" " movb $12,1(%rsp)\n" " fldcw (%rsp)\n" " fistpq 8(%rsp)\n" " movl 8(%rsp),A1\n" " fldcw 4(%rsp)\n" " addq $16,%rsp\n", }, /* long (in mem) -> ldouble */ { SCONV, INCREG, SNAME|SOREG, TLONG, SCREG, TLDOUBLE, NCREG, RESC1, " fildll AL\n", }, /* long (in reg) -> ldouble */ { SCONV, INCREG, SAREG, TLONG, SCREG, TLDOUBLE, NCREG, RESC1, " subq $16,%rsp\n" " movq AL,(%rsp)\n" " fildll (%rsp)\n" " addq $16,%rsp\n", }, /* slut sconv */ /* * Subroutine calls. */ { CALL, FOREFF|MCSMALL|MCMEDIUM, SCON, TANY, SANY, TANY, 0, 0, " call CL\nZC", }, { UCALL, FOREFF|MCSMALL|MCMEDIUM, SCON, TANY, SANY, TANY, 0, 0, " call CL\n", }, { CALL, INAREG|MCSMALL|MCMEDIUM, SCON, TANY, SAREG, TLL|ANYFIXED|TPOINT, NAREG|NASL, RESC1, /* should be 0 */ " call CL\nZC", }, { UCALL, INAREG|MCSMALL|MCMEDIUM, SCON, TANY, SAREG, TLL|ANYFIXED|TPOINT, NAREG|NASL, RESC1, /* should be 0 */ " call CL\n", }, { CALL, INBREG, SCON, TANY|MCSMALL|MCMEDIUM, SBREG, TANY, NBREG|NBSL, RESC1, /* should be 0 */ " call CL\nZC", }, { UCALL, INBREG|MCSMALL|MCMEDIUM, SCON, TANY, SBREG, TANY, NBREG|NBSL, RESC1, /* should be 0 */ " call CL\nZC", }, { CALL, INCREG|MCSMALL|MCMEDIUM, SCON, TANY, SCREG, TANY, NCREG|NCSL, RESC1, /* should be 0 */ " call CL\nZC", }, { UCALL, INCREG|MCSMALL|MCMEDIUM, SCON, TANY, SCREG, TANY, NCREG|NCSL, RESC1, /* should be 0 */ " call CL\nZC", }, { CALL, FOREFF, SAREG, TANY, SANY, TANY, 0, 0, " call *AL\nZC", }, { UCALL, FOREFF, SAREG, TANY, SANY, TANY, 0, 0, " call *AL\nZC", }, { CALL, INAREG, SAREG, TANY, SANY, TANY, NAREG|NASL, RESC1, /* should be 0 */ " call *AL\nZC", }, { UCALL, INAREG, SAREG, TANY, SANY, TANY, NAREG|NASL, RESC1, /* should be 0 */ " call *AL\nZC", }, { CALL, INBREG, SAREG, TANY, SANY, TANY, NBREG|NBSL, RESC1, /* should be 0 */ " call *AL\nZC", }, { UCALL, INBREG, SAREG, TANY, SANY, TANY, NBREG|NBSL, RESC1, /* should be 0 */ " call *AL\nZC", }, { CALL, INCREG, SAREG, TANY, SANY, TANY, NCREG|NCSL, RESC1, /* should be 0 */ " call *AL\nZC", }, { UCALL, INCREG, SAREG, TANY, SANY, TANY, NCREG|NCSL, RESC1, /* should be 0 */ " call *AL\nZC", }, /* struct return */ { USTCALL, FOREFF, SCON, TANY, SANY, TANY, NAREG|NASL, 0, "ZP call CL\nZC", }, { USTCALL, INAREG, SCON, TANY, SANY, TANY, NAREG|NASL, RESC1, /* should be 0 */ "ZP call CL\nZC", }, { USTCALL, INAREG, SNAME|SAREG, TANY, SANY, TANY, NAREG|NASL, RESC1, /* should be 0 */ "ZP call *AL\nZC", }, { STCALL, FOREFF, SCON, TANY, SANY, TANY, NAREG|NASL, 0, "ZP call CL\nZC", }, { STCALL, INAREG, SCON, TANY, SANY, TANY, NAREG|NASL, RESC1, /* should be 0 */ "ZP call CL\nZC", }, { STCALL, FOREFF, SNAME|SAREG, TANY, SANY, TANY, NAREG|NASL, 0, /* should be 0 */ "ZP call *AL\nZC", }, { STCALL, INAREG, SNAME|SAREG, TANY, SANY, TANY, NAREG|NASL, RESC1, /* should be 0 */ "ZP call *AL\nZC", }, /* * The next rules handle all binop-style operators. */ /* floating point add */ { PLUS, INBREG, SBREG, TFLOAT|TDOUBLE, SBREG|SNAME|SOREG, TFLOAT|TDOUBLE, 0, RLEFT, " addsZf AR,AL\n", }, { PLUS, INCREG|FOREFF, SHFL, TLDOUBLE, SHFL, TLDOUBLE, 0, RLEFT, " faddp\n", }, { PLUS, INAREG|FOREFF, SAREG|SNAME|SOREG, TLL|TPOINT, SONE, TANY, 0, RLEFT, " incq AL\n", }, { PLUS, INAREG|FOREFF, SAREG|SNAME|SOREG, TWORD, SONE, TANY, 0, RLEFT, " incl AL\n", }, { PLUS, INAREG, SAREG, TLL|TPOINT, SCON, TWORD, NAREG|NASL, RESC1, " leaq CR(AL),A1\n", }, #ifdef notdef /* older binutils are missing leal */ { PLUS, INAREG, SAREG, TWORD, SCON, TANY, NAREG|NASL, RESC1, " leal CR(AL),A1\n", }, #endif { PLUS, INAREG|FOREFF, SAREG|SNAME|SOREG, TSHORT|TUSHORT, SONE, TANY, 0, RLEFT, " incw AL\n", }, { PLUS, INAREG|FOREFF, SAREG|SNAME|SOREG, TCHAR|TUCHAR, SONE, TANY, 0, RLEFT, " incb AL\n", }, #ifdef notdef /* older binutils are missing leal */ { PLUS, INAREG, SAREG, TWORD, SAREG, TWORD, NAREG|NASL|NASR, RESC1, " leal (AL,AR),A1\n", }, #endif { MINUS, INAREG|FOREFF, SAREG|SNAME|SOREG, TLL|TPOINT, SONE, TANY, 0, RLEFT, " decq AL\n", }, { MINUS, INAREG|FOREFF, SAREG|SNAME|SOREG, TWORD, SONE, TANY, 0, RLEFT, " decl AL\n", }, { MINUS, INAREG|FOREFF, SAREG|SNAME|SOREG, TSHORT|TUSHORT, SONE, TANY, 0, RLEFT, " decw AL\n", }, { MINUS, INAREG|FOREFF, SAREG|SNAME|SOREG, TCHAR|TUCHAR, SONE, TANY, 0, RLEFT, " decb AL\n", }, /* address as register offset, negative */ { MINUS, INAREG, SAREG, TLL|TPOINT, SPCON, TANY, NAREG|NASL, RESC1, " leaq -CR(AL),A1\n", }, { MINUS, INBREG|FOREFF, SBREG, TDOUBLE|TFLOAT, SBREG|SNAME|SOREG, TDOUBLE|TFLOAT, 0, RLEFT, " subsZf AR,AL\n", }, { MINUS, INCREG|FOREFF, SHFL, TLDOUBLE, SHFL, TLDOUBLE, 0, RLEFT, " fsubZAp\n", }, /* Simple r/m->reg ops */ /* m/r |= r */ { OPSIMP, INAREG|FOREFF|FORCC, SAREG|SNAME|SOREG, TLL|TPOINT, SAREG, TLL|TPOINT, 0, RLEFT|RESCC, " Oq AR,AL\n", }, /* r |= r/m */ { OPSIMP, INAREG|FOREFF|FORCC, SAREG, TLL|TPOINT, SAREG|SNAME|SOREG, TLL|TPOINT, 0, RLEFT|RESCC, " Oq AR,AL\n", }, /* m/r |= r */ { OPSIMP, INAREG|FOREFF|FORCC, SAREG|SNAME|SOREG, TWORD, SAREG, TWORD, 0, RLEFT|RESCC, " Ol AR,AL\n", }, /* r |= r/m */ { OPSIMP, INAREG|FOREFF|FORCC, SAREG, TWORD, SAREG|SNAME|SOREG, TWORD, 0, RLEFT|RESCC, " Ol AR,AL\n", }, /* m/r |= r */ { OPSIMP, INAREG|FOREFF|FORCC, SHINT|SNAME|SOREG, TSHORT|TUSHORT, SHINT, TSHORT|TUSHORT, 0, RLEFT|RESCC, " Ow AR,AL\n", }, /* r |= r/m */ { OPSIMP, INAREG|FOREFF|FORCC, SHINT, TSHORT|TUSHORT, SHINT|SNAME|SOREG, TSHORT|TUSHORT, 0, RLEFT|RESCC, " Ow AR,AL\n", }, /* m/r |= r */ { OPSIMP, INAREG|FOREFF|FORCC, SAREG, TCHAR|TUCHAR, SAREG|SNAME|SOREG, TCHAR|TUCHAR, 0, RLEFT|RESCC, " Ob AR,AL\n", }, /* r |= r/m */ { OPSIMP, INAREG|FOREFF|FORCC, SAREG, TCHAR|TUCHAR, SAREG|SNAME|SOREG, TCHAR|TUCHAR, 0, RLEFT|RESCC, " Ob AR,AL\n", }, /* m/r |= const */ #ifdef notdef /* amd64 lacks immediate 64-bit simple ops */ { OPSIMP, INAREG|FOREFF|FORCC, SAREG|SNAME|SOREG, TLL|TPOINT, SCON, TANY, 0, RLEFT|RESCC, " Oq AR,AL\n", }, #endif { OPSIMP, INAREG|FOREFF|FORCC, SAREG|SNAME|SOREG, TWORD, SCON, TANY, 0, RLEFT|RESCC, " Ol AR,AL\n", }, { OPSIMP, INAREG|FOREFF|FORCC, SHINT|SNAME|SOREG, TSHORT|TUSHORT, SCON, TANY, 0, RLEFT|RESCC, " Ow AR,AL\n", }, { OPSIMP, INAREG|FOREFF|FORCC, SAREG|SNAME|SOREG, TCHAR|TUCHAR, SCON, TANY, 0, RLEFT|RESCC, " Ob AR,AL\n", }, /* * The next rules handle all shift operators. */ /* r/m <<= r */ { LS, INAREG|FOREFF, SAREG|SNAME|SOREG, TLL, SAREG, TCHAR|TUCHAR, NSPECIAL, RLEFT, " salq AR,AL\n", }, /* r/m <<= const */ { LS, INAREG|FOREFF, SAREG|SNAME|SOREG, TLL, SCON, TANY, 0, RLEFT, " salq AR,AL\n", }, /* r/m <<= r */ { LS, INAREG|FOREFF, SAREG|SNAME|SOREG, TWORD, SAREG, TCHAR|TUCHAR, NSPECIAL, RLEFT, " sall AR,AL\n", }, /* r/m <<= const */ { LS, INAREG|FOREFF, SAREG|SNAME|SOREG, TWORD, SCON, TANY, 0, RLEFT, " sall AR,AL\n", }, /* r/m <<= r */ { LS, INAREG|FOREFF, SAREG|SNAME|SOREG, TSHORT|TUSHORT, SAREG, TCHAR|TUCHAR, NSPECIAL, RLEFT, " shlw AR,AL\n", }, /* r/m <<= const */ { LS, INAREG|FOREFF, SAREG|SNAME|SOREG, TSHORT|TUSHORT, SCON, TANY, 0, RLEFT, " shlw AR,AL\n", }, { LS, INAREG|FOREFF, SAREG|SNAME|SOREG, TCHAR|TUCHAR, SAREG, TCHAR|TUCHAR, NSPECIAL, RLEFT, " salb AR,AL\n", }, { LS, INAREG|FOREFF, SAREG|SNAME|SOREG, TCHAR|TUCHAR, SCON, TANY, 0, RLEFT, " salb AR,AL\n", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TLONG|TLONGLONG, SAREG, TCHAR|TUCHAR, NSPECIAL, RLEFT, " sarq AR,AL\n", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TLONG|TLONGLONG, SCON, TANY, 0, RLEFT, " sarq AR,AL\n", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TULONG|TULONGLONG, SAREG, TCHAR|TUCHAR, NSPECIAL, RLEFT, " shrq AR,AL\n", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TULONG|TULONGLONG, SCON, TANY, 0, RLEFT, " shrq AR,AL\n", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TSWORD, SAREG, TCHAR|TUCHAR, NSPECIAL, RLEFT, " sarl AR,AL\n", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TSWORD, SCON, TANY, 0, RLEFT, " sarl AR,AL\n", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TUWORD, SAREG, TCHAR|TUCHAR, NSPECIAL, RLEFT, " shrl AR,AL\n", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TUWORD, SCON, TANY, 0, RLEFT, " shrl AR,AL\n", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TSHORT, SAREG, TCHAR|TUCHAR, NSPECIAL, RLEFT, " sarw AR,AL\n", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TSHORT, SCON, TANY, 0, RLEFT, " sarw AR,AL\n", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TUSHORT, SAREG, TCHAR|TUCHAR, NSPECIAL, RLEFT, " shrw AR,AL\n", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TUSHORT, SCON, TANY, 0, RLEFT, " shrw AR,AL\n", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TCHAR, SAREG, TCHAR|TUCHAR, NSPECIAL, RLEFT, " sarb AR,AL\n", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TCHAR, SCON, TANY, 0, RLEFT, " sarb AR,AL\n", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TUCHAR, SAREG, TCHAR|TUCHAR, NSPECIAL, RLEFT, " shrb AR,AL\n", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TUCHAR, SCON, TANY, 0, RLEFT, " shrb AR,AL\n", }, /* * The next rules takes care of assignments. "=". */ { ASSIGN, FORCC|FOREFF|INAREG, SAREG, TLL|TPOINT, SMIXOR, TANY, 0, RDEST, " xorq AL,AL\n", }, { ASSIGN, FOREFF|INAREG, SAREG, TLL|TPOINT, SCON, TANY, 0, RDEST, " movabs AR,AL\n", }, { ASSIGN, FORCC|FOREFF|INAREG, SAREG, TWORD, SMIXOR, TANY, 0, RDEST, " xorl AL,AL\n", }, { ASSIGN, FOREFF, SAREG|SNAME|SOREG, TWORD, SCON, TANY, 0, 0, " movl AR,AL\n", }, { ASSIGN, FOREFF|INAREG, SAREG, TWORD, SCON, TANY, 0, RDEST, " movl AR,AL\n", }, { ASSIGN, FORCC|FOREFF|INAREG, SAREG, TSHORT|TUSHORT, SMIXOR, TANY, 0, RDEST, " xorw AL,AL\n", }, { ASSIGN, FOREFF, SAREG|SNAME|SOREG, TSHORT|TUSHORT, SCON, TANY, 0, 0, " movw AR,AL\n", }, { ASSIGN, FOREFF|INAREG, SAREG, TSHORT|TUSHORT, SCON, TANY, 0, RDEST, " movw AR,AL\n", }, { ASSIGN, FOREFF, SAREG|SNAME|SOREG, TCHAR|TUCHAR, SCON, TANY, 0, 0, " movb AR,AL\n", }, { ASSIGN, FOREFF|INAREG, SAREG, TCHAR|TUCHAR, SCON, TANY, 0, RDEST, " movb AR,AL\n", }, { ASSIGN, FOREFF|INAREG, SAREG|SNAME|SOREG, TLL|TPOINT, SAREG, TLL|TPOINT, 0, RDEST, " movq AR,AL\n", }, { ASSIGN, FOREFF|INAREG, SAREG|SNAME|SOREG, TWORD, SAREG, TWORD, 0, RDEST, " movl AR,AL\n", }, { ASSIGN, FOREFF|INAREG, SAREG, TWORD, SAREG|SNAME|SOREG, TWORD, 0, RDEST, " movl AR,AL\n", }, { ASSIGN, FOREFF|INAREG, SAREG, TPOINT, SAREG|SNAME|SOREG, TPOINT, 0, RDEST, " movq AR,AL\n", }, { ASSIGN, FOREFF|INAREG, SAREG|SNAME|SOREG, TSHORT|TUSHORT, SAREG, TSHORT|TUSHORT, 0, RDEST, " movw AR,AL\n", }, { ASSIGN, FOREFF|INAREG, SAREG|SNAME|SOREG, TCHAR|TUCHAR, SAREG, TCHAR|TUCHAR|TWORD, 0, RDEST, " movb AR,AL\n", }, { ASSIGN, INBREG|FOREFF, SBREG, TFLOAT|TDOUBLE, SBREG|SOREG|SNAME, TFLOAT|TDOUBLE, 0, RDEST, " movsZf AR,AL\n", }, { ASSIGN, INBREG|FOREFF, SBREG|SOREG|SNAME, TFLOAT|TDOUBLE, SBREG, TFLOAT|TDOUBLE, 0, RDEST, " movsZf AR,AL\n", }, /* x87 entries */ { ASSIGN, INDREG|FOREFF, SHFL, TLDOUBLE, SHFL, TLDOUBLE, 0, RDEST, "", }, /* This will always be in the correct register */ /* order of table entries is very important here! */ { ASSIGN, INFL, SNAME|SOREG, TLDOUBLE, SHFL, TLDOUBLE, 0, RDEST, " fstpt AL\n fldt AL\n", }, /* XXX */ { ASSIGN, FOREFF, SNAME|SOREG, TLDOUBLE, SHFL, TLDOUBLE, 0, 0, " fstpt AL\n", }, /* end very important order */ { ASSIGN, INFL|FOREFF, SHFL, TLDOUBLE, SHFL|SOREG|SNAME, TLDOUBLE, 0, RDEST, " fldt AR\n", }, /* end x87 */ /* Do not generate memcpy if return from funcall */ #if 0 { STASG, INAREG|FOREFF, SOREG|SNAME|SAREG, TPTRTO|TSTRUCT, SFUNCALL, TPTRTO|TSTRUCT, 0, RRIGHT, "", }, #endif { STASG, INAREG|FOREFF, SOREG|SNAME, TANY, SAREG, TPTRTO|TANY, NSPECIAL|NAREG, RDEST, "F movq AR,A1\nZQF movq A1,AR\n", }, /* * DIV/MOD/MUL */ { DIV, INAREG, SAREG, TLONG, SAREG|SNAME|SOREG, TLL, NSPECIAL, RDEST, " cqto\n idivq AR\n", }, { DIV, INAREG, SAREG, TULONG|TPOINT, SAREG|SNAME|SOREG, TLL|TPOINT, NSPECIAL, RDEST, " xorq %rdx,%rdx\n divq AR\n", }, { DIV, INAREG, SAREG, TSWORD, SAREG|SNAME|SOREG, TWORD, NSPECIAL, RDEST, " cltd\n idivl AR\n", }, { DIV, INAREG, SAREG, TUWORD, SAREG|SNAME|SOREG, TWORD, NSPECIAL, RDEST, " xorl %edx,%edx\n divl AR\n", }, { DIV, INAREG, SAREG, TUSHORT, SAREG|SNAME|SOREG, TUSHORT, NSPECIAL, RDEST, " xorl %edx,%edx\n divw AR\n", }, { DIV, INAREG, SAREG, TUCHAR, SAREG|SNAME|SOREG, TUCHAR, NSPECIAL, RDEST, " xorb %ah,%ah\n divb AR\n", }, { DIV, INBREG, SBREG, TFLOAT|TDOUBLE, SBREG|SNAME|SOREG, TFLOAT|TDOUBLE, 0, RLEFT, " divsZf AR,AL\n", }, { DIV, INCREG, SHFL, TLDOUBLE, SHFL, TLDOUBLE, 0, RLEFT, " fdivZAp\n", }, { MOD, INAREG, SAREG, TLONG, SAREG|SNAME|SOREG, TLONG, NAREG|NSPECIAL, RESC1, " cqto\n idivq AR\n", }, { MOD, INAREG, SAREG, TLL|TPOINT, SAREG|SNAME|SOREG, TULONG|TPOINT, NAREG|NSPECIAL, RESC1, " xorq %rdx,%rdx\n divq AR\n", }, { MOD, INAREG, SAREG, TSWORD, SAREG|SNAME|SOREG, TSWORD, NAREG|NSPECIAL, RESC1, " cltd\n idivl AR\n", }, { MOD, INAREG, SAREG, TWORD, SAREG|SNAME|SOREG, TUWORD, NAREG|NSPECIAL, RESC1, " xorl %edx,%edx\n divl AR\n", }, { MOD, INAREG, SAREG, TUSHORT, SAREG|SNAME|SOREG, TUSHORT, NAREG|NSPECIAL, RESC1, " xorl %edx,%edx\n divw AR\n", }, { MOD, INAREG, SAREG, TUCHAR, SAREG|SNAME|SOREG, TUCHAR, NAREG|NSPECIAL, RESC1, " xorb %ah,%ah\n divb AR\n movb %ah,%al\n", }, { MUL, INAREG, SAREG, TLL|TPOINT, SAREG|SNAME|SOREG, TLL|TPOINT, 0, RLEFT, " imulq AR,AL\n", }, { MUL, INAREG, SAREG, TWORD, SAREG|SNAME|SOREG|SCON, TWORD, 0, RLEFT, " imull AR,AL\n", }, { MUL, INAREG, SAREG, TSHORT|TUSHORT, SAREG|SNAME|SOREG, TSHORT|TUSHORT, 0, RLEFT, " imulw AR,AL\n", }, { MUL, INAREG, SAREG, TCHAR|TUCHAR, SAREG|SNAME|SOREG, TCHAR|TUCHAR, NSPECIAL, RLEFT, " imulb AR\n", }, { MUL, INBREG, SBREG, TFLOAT|TDOUBLE, SBREG|SNAME|SOREG, TFLOAT|TDOUBLE, 0, RLEFT, " mulsZf AR,AL\n", }, { MUL, INCREG, SHFL, TLDOUBLE, SHFL, TLDOUBLE, 0, RLEFT, " fmulp\n", }, /* * Indirection operators. */ { UMUL, INAREG, SANY, TANY, SOREG, TLL|TPOINT, NAREG, RESC1, " movq AL,A1\n", }, { UMUL, INAREG, SANY, TWORD, SOREG, TWORD, NAREG|NASL, RESC1, " movl AL,A1\n", }, { UMUL, INAREG, SANY, TANY, SOREG, TCHAR|TUCHAR, NAREG|NASL, RESC1, " movb AL,A1\n", }, { UMUL, INAREG, SANY, TANY, SOREG, TSHORT|TUSHORT, NAREG|NASL, RESC1, " movw AL,A1\n", }, { UMUL, INBREG, SANY, TANY, SOREG, TFLOAT|TDOUBLE, NBREG|NBSL, RESC1, " movsZf AL,A1\n", }, { UMUL, INCREG, SANY, TANY, SOREG, TLDOUBLE, NCREG|NCSL, RESC1, " fldt AL\n", }, /* * Logical/branching operators */ /* Comparisions, take care of everything */ { OPLOG, FORCC, SAREG, TLL|TPOINT, SAREG|SOREG|SNAME, TLL|TPOINT, 0, RESCC, " cmpq AR,AL\n", }, { OPLOG, FORCC, SAREG|SOREG|SNAME, TLL|TPOINT, SAREG, TLL|TPOINT, 0, RESCC, " cmpq AR,AL\n", }, { OPLOG, FORCC, SAREG|SOREG|SNAME, TLL|TPOINT, SCON32, TANY, 0, RESCC, " cmpq AR,AL\n", }, { OPLOG, FORCC, SAREG|SOREG|SNAME, TWORD, SCON|SAREG, TWORD, 0, RESCC, " cmpl AR,AL\n", }, { OPLOG, FORCC, /* SCON| XXX fix switch in tree of L/R */ SAREG, TWORD, SAREG|SOREG|SNAME, TWORD, 0, RESCC, " cmpl AR,AL\n", }, { OPLOG, FORCC, SAREG|SOREG|SNAME, TSHORT|TUSHORT, SCON|SAREG, TANY, 0, RESCC, " cmpw AR,AL\n", }, { OPLOG, FORCC, SAREG|SOREG|SNAME, TCHAR|TUCHAR, SCON|SAREG, TANY, 0, RESCC, " cmpb AR,AL\n", }, { OPLOG, FORCC, SBREG, TDOUBLE|TFLOAT, SBREG|SNAME|SOREG, TDOUBLE|TFLOAT, 0, RNOP, " ucomisZg AR,AL\nZU\n", }, /* x87 */ { OPLOG, FORCC, SCREG, TLDOUBLE, SCREG, TLDOUBLE, 0, RNOP, "ZG", }, { OPLOG, FORCC, SANY, TANY, SANY, TANY, REWRITE, 0, "diediedie!", }, /* AND/OR/ER/NOT */ { AND, INAREG|FOREFF, SAREG|SOREG|SNAME, TLL, SCON, TWORD, 0, RLEFT, " andq AR,AL\n", }, { AND, INAREG|FOREFF, SAREG|SOREG|SNAME, TLL, SAREG, TLL, 0, RLEFT, " andq AR,AL\n", }, { AND, INAREG|FOREFF, SAREG, TLL, SAREG|SOREG|SNAME, TLL, 0, RLEFT, " andq AR,AL\n", }, { AND, INAREG|FOREFF, SAREG|SOREG|SNAME, TWORD, SCON|SAREG, TWORD, 0, RLEFT, " andl AR,AL\n", }, { AND, INAREG|FOREFF, SAREG, TWORD, SAREG|SOREG|SNAME, TWORD, 0, RLEFT, " andl AR,AL\n", }, { AND, INAREG|FOREFF, SAREG|SOREG|SNAME, TSHORT|TUSHORT, SCON|SAREG, TSHORT|TUSHORT, 0, RLEFT, " andw AR,AL\n", }, { AND, INAREG|FOREFF, SAREG, TSHORT|TUSHORT, SAREG|SOREG|SNAME, TSHORT|TUSHORT, 0, RLEFT, " andw AR,AL\n", }, { AND, INAREG|FOREFF, SAREG|SOREG|SNAME, TCHAR|TUCHAR, SCON|SAREG, TCHAR|TUCHAR, 0, RLEFT, " andb AR,AL\n", }, { AND, INAREG|FOREFF, SAREG, TCHAR|TUCHAR, SAREG|SOREG|SNAME, TCHAR|TUCHAR, 0, RLEFT, " andb AR,AL\n", }, /* AND/OR/ER/NOT */ /* * Jumps. */ { GOTO, FOREFF, SCON, TANY, SANY, TANY, 0, RNOP, " jmp LL\n", }, #if defined(GCC_COMPAT) || defined(LANG_F77) { GOTO, FOREFF, SAREG, TANY, SANY, TANY, 0, RNOP, " jmp *AL\n", }, #endif /* * Convert LTYPE to reg. */ { OPLTYPE, FORCC|INAREG, SAREG, TLL|TPOINT, SMIXOR, TANY, NAREG, RESC1, " xorq A1,A1\n", }, { OPLTYPE, INAREG, SANY, TANY, SCON, TLL|TPOINT, NAREG, RESC1, " movabsq AL,A1\n", }, { OPLTYPE, INAREG, SANY, TANY, SAREG|SCON|SOREG|SNAME, TLL|TPOINT, NAREG, RESC1, " movq AL,A1\n", }, { OPLTYPE, FORCC|INAREG, SAREG, TWORD, SMIXOR, TANY, NAREG|NASL, RESC1, " xorl A1,A1\n", }, { OPLTYPE, INAREG, SANY, TANY, SAREG|SCON|SOREG|SNAME, TWORD, NAREG|NASL, RESC1, " movl AL,A1\n", }, { OPLTYPE, INAREG, SANY, TANY, SAREG|SOREG|SNAME|SCON, TCHAR|TUCHAR, NAREG, RESC1, " movb AL,A1\n", }, { OPLTYPE, FORCC|INAREG, SAREG, TSHORT|TUSHORT, SMIXOR, TANY, NAREG, RESC1, " xorw A1,A1\n", }, { OPLTYPE, INAREG, SANY, TANY, SAREG|SOREG|SNAME|SCON, TSHORT|TUSHORT, NAREG, RESC1, " movw AL,A1\n", }, { OPLTYPE, INBREG, SANY, TFLOAT|TDOUBLE, SOREG|SNAME|SBREG, TFLOAT|TDOUBLE, NBREG, RESC1, " movsZf AL,A1\n", }, /* x87 entry */ { OPLTYPE, INCREG, SANY, TLDOUBLE, SOREG|SNAME, TLDOUBLE, NCREG, RESC1, " fldt AL\n", }, /* load float 0.0 */ { FCON, INBREG, SANY, TFLOAT|TDOUBLE, SANY, TFLOAT|TDOUBLE, NBREG, RESC1, " xorpZf A1,A1\n", }, { FCON, INCREG, SANY, TLDOUBLE, SANY, TLDOUBLE, NCREG, RESC1, " fldz\n", }, /* * Negate a word. */ { UMINUS, INAREG|FOREFF, SAREG, TLL|TPOINT, SAREG, TLL|TPOINT, 0, RLEFT, " negq AL\n", }, { UMINUS, INAREG|FOREFF, SAREG, TWORD, SAREG, TWORD, 0, RLEFT, " negl AL\n", }, { UMINUS, INAREG|FOREFF, SAREG, TSHORT|TUSHORT, SAREG, TSHORT|TUSHORT, 0, RLEFT, " negw AL\n", }, { UMINUS, INAREG|FOREFF, SAREG, TCHAR|TUCHAR, SAREG, TCHAR|TUCHAR, 0, RLEFT, " negb AL\n", }, { UMINUS, INBREG, SBREG, TDOUBLE|TFLOAT, SBREG, TDOUBLE|TFLOAT, 0, RLEFT, " xorpZf Zc(%rip),AL\n", }, { UMINUS, INCREG, SCREG, TLDOUBLE, SCREG, TLDOUBLE, 0, RLEFT, " fchs\n", }, { COMPL, INAREG, SAREG, TLL, SANY, TANY, 0, RLEFT, " notq AL\n", }, { COMPL, INAREG, SAREG, TWORD, SANY, TANY, 0, RLEFT, " notl AL\n", }, { COMPL, INAREG, SAREG, TSHORT|TUSHORT, SANY, TANY, 0, RLEFT, " notw AL\n", }, { COMPL, INAREG, SAREG, TCHAR|TUCHAR, SANY, TANY, 0, RLEFT, " notb AL\n", }, { STARG, FOREFF, SAREG|SOREG|SNAME|SCON, TANY, SANY, TSTRUCT, NSPECIAL, 0, "ZF", }, { ADDROF, INAREG, SNAME, TANY, SANY, TANY, NAREG, RESC1, " leaq AL,A1\n", }, # define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,"" { UMUL, DF( UMUL ), }, { ASSIGN, DF(ASSIGN), }, { STASG, DF(STASG), }, { FLD, DF(FLD), }, { OPLEAF, DF(NAME), }, /* { INIT, DF(INIT), }, */ { OPUNARY, DF(UMINUS), }, { OPANY, DF(BITYPE), }, { FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" }, }; int tablesize = sizeof(table)/sizeof(table[0]); pcc-20181216/arch/arm004075500017500000000000000000001340533064000131025ustar raggewheelpcc-20181216/arch/arm/CVS004075500017500000000000000000001340533064000135355ustar raggewheelpcc-20181216/arch/arm/CVS/Root010064400017500000000000000000111340533064000144470ustar raggewheel/cvsroot pcc-20181216/arch/arm/CVS/Repository010064400017500000000000000000151340533064000157070ustar raggewheelpcc/arch/arm pcc-20181216/arch/arm/CVS/Entries010064400017500000000000000003721340533064000151470ustar raggewheel/code.c/1.30/Wed Mar 9 18:19:56 2016// /local.c/1.34/Wed Mar 9 18:19:56 2016// /local2.c/1.40/Mon Sep 26 16:45:42 2016// /macdefs.h/1.20/Sun Dec 2 10:37:21 2018// /order.c/1.10/Wed Mar 9 18:19:56 2016// /table.c/1.20/Sun Nov 13 22:30:18 2011// D pcc-20181216/arch/arm/code.c010064400017500000000000000461731267006451400142560ustar raggewheel/* $Id: code.c,v 1.30 2016/03/09 18:19:56 ragge Exp $ */ /* * Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org). * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Stuff for pass1. */ #include #include "pass1.h" #include "pass2.h" #ifdef LANG_CXX #define p1listf listf #define p1tfree tfree #else #define NODE P1ND #define talloc p1alloc #define tcopy p1tcopy #define nfree p1nfree #endif static int rvnr; /* * Print out assembler segment name. */ void setseg(int seg, char *name) { switch (seg) { case PROG: name = ".text"; break; case DATA: case LDATA: name = ".data"; break; case UDATA: break; case PICLDATA: name = ".section .data.rel.local,\"aw\",@progbits";break; case PICDATA: name = ".section .data.rel.rw,\"aw\",@progbits"; break; case PICRDATA: name = ".section .data.rel.ro,\"aw\",@progbits"; break; case STRNG: case RDATA: name = ".section .rodata"; break; case TLSDATA: name = ".section .tdata,\"awT\",@progbits"; break; case TLSUDATA: name = ".section .tbss,\"awT\",@nobits"; break; case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break; case DTORS: name = ".section\t.dtors,\"aw\",@progbits"; break; case NMSEG: printf("\t.section %s,\"a%c\",@progbits\n", name, cftnsp ? 'x' : 'w'); return; } printf("\t%s\n", name); } /* * Define everything needed to print out some data (or text). * This means segment, alignment, visibility, etc. */ void defloc(struct symtab *sp) { char *n; n = getexname(sp); #ifdef USE_GAS if (ISFTN(t)) printf("\t.type %s,%%function\n", n); #endif if (sp->sclass == EXTDEF) printf("\t.global %s\n", n); if (sp->slevel == 0) printf("%s:\n", n); else printf(LABFMT ":\n", sp->soffset); } /* Put a symbol in a temporary * used by bfcode() and its helpers */ static void putintemp(struct symtab *sym) { NODE *p; p = tempnode(0, sym->stype, sym->sdf, sym->sap); p = buildtree(ASSIGN, p, nametree(sym)); sym->soffset = regno(p->n_left); sym->sflags |= STNODE; ecomp(p); } /* setup a 64-bit parameter (double/ldouble/longlong) * used by bfcode() */ static void param_64bit(struct symtab *sym, int *argofsp, int dotemps) { int argofs = *argofsp; NODE *p, *q; int navail; #if ALLONGLONG == 64 /* alignment */ ++argofs; argofs &= ~1; *argofsp = argofs; #endif navail = NARGREGS - argofs; if (navail < 2) { /* half in and half out of the registers */ if (features(FEATURE_BIGENDIAN)) { cerror("param_64bit"); p = q = NULL; } else { q = block(REG, NIL, NIL, INT, 0, 0); regno(q) = R0 + argofs; if (dotemps) { q = block(SCONV, q, NIL, ULONGLONG, 0, 0); p = nametree(sym); p->n_type = ULONGLONG; p->n_df = 0; p->n_ap = NULL; p = block(LS, p, bcon(32), ULONGLONG, 0, 0); q = block(PLUS, p, q, ULONGLONG, 0, 0); p = tempnode(0, ULONGLONG, 0, 0); sym->soffset = regno(p); sym->sflags |= STNODE; } else { p = nametree(sym); regno(p) = sym->soffset; p->n_type = INT; p->n_df = 0; p->n_ap = NULL; } } p = buildtree(ASSIGN, p, q); ecomp(p); *argofsp = argofs + 2; return; } q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap); regno(q) = R0R1 + argofs; if (dotemps) { p = tempnode(0, sym->stype, sym->sdf, sym->sap); sym->soffset = regno(p); sym->sflags |= STNODE; } else { p = nametree(sym); } p = buildtree(ASSIGN, p, q); ecomp(p); *argofsp = argofs + 2; } /* setup a 32-bit param on the stack * used by bfcode() */ static void param_32bit(struct symtab *sym, int *argofsp, int dotemps) { NODE *p, *q; q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap); regno(q) = R0 + (*argofsp)++; if (dotemps) { p = tempnode(0, sym->stype, sym->sdf, sym->sap); sym->soffset = regno(p); sym->sflags |= STNODE; } else { p = nametree(sym); } p = buildtree(ASSIGN, p, q); ecomp(p); } /* setup a double param on the stack * used by bfcode() */ static void param_double(struct symtab *sym, int *argofsp, int dotemps) { NODE *p, *q, *t; int tmpnr; /* * we have to dump the float from the general register * into a temp, since the register allocator doesn't like * floats to be in CLASSA. This may not work for -xtemps. */ t = tempnode(0, ULONGLONG, 0, 0); tmpnr = regno(t); q = block(REG, NIL, NIL, INT, 0, 0); q->n_rval = R0R1 + (*argofsp)++; p = buildtree(ASSIGN, t, q); ecomp(p); if (dotemps) { sym->soffset = tmpnr; sym->sflags |= STNODE; } else { q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap); p = nametree(sym); p = buildtree(ASSIGN, p, q); ecomp(p); } } /* setup a float param on the stack * used by bfcode() */ static void param_float(struct symtab *sym, int *argofsp, int dotemps) { NODE *p, *q, *t; int tmpnr; /* * we have to dump the float from the general register * into a temp, since the register allocator doesn't like * floats to be in CLASSA. This may not work for -xtemps. */ t = tempnode(0, INT, 0, 0); tmpnr = regno(t); q = block(REG, NIL, NIL, INT, 0, 0); q->n_rval = R0 + (*argofsp)++; p = buildtree(ASSIGN, t, q); ecomp(p); if (dotemps) { sym->soffset = tmpnr; sym->sflags |= STNODE; } else { q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap); p = nametree(sym); p = buildtree(ASSIGN, p, q); ecomp(p); } } /* setup the hidden pointer to struct return parameter * used by bfcode() */ static void param_retstruct(void) { NODE *p, *q; p = tempnode(0, PTR-FTN+cftnsp->stype, 0, cftnsp->sap); rvnr = regno(p); q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap); regno(q) = R0; p = buildtree(ASSIGN, p, q); ecomp(p); } /* setup struct parameter * push the registers out to memory * used by bfcode() */ static void param_struct(struct symtab *sym, int *argofsp) { int argofs = *argofsp; NODE *p, *q; int navail; int sz; int off; int num; int i; navail = NARGREGS - argofs; sz = tsize(sym->stype, sym->sdf, sym->sap) / SZINT; off = ARGINIT/SZINT + argofs; num = sz > navail ? navail : sz; for (i = 0; i < num; i++) { q = block(REG, NIL, NIL, INT, 0, 0); regno(q) = R0 + argofs++; p = block(REG, NIL, NIL, INT, 0, 0); regno(p) = SP; p = block(PLUS, p, bcon(4*off++), INT, 0, 0); p = block(UMUL, p, NIL, INT, 0, 0); p = buildtree(ASSIGN, p, q); ecomp(p); } *argofsp = argofs; } /* * Beginning-of-function code: * * 'sp' is an array of indices in symtab for the arguments * 'cnt' is the number of arguments */ void bfcode(struct symtab **sp, int cnt) { union arglist *usym; int saveallargs = 0; int i, argofs = 0; /* * Detect if this function has ellipses and save all * argument registers onto stack. */ usym = cftnsp->sdf->dfun; while (usym && usym->type != TNULL) { if (usym->type == TELLIPSIS) { saveallargs = 1; break; } ++usym; } /* if returning a structure, move the hidden argument into a TEMP */ if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { param_retstruct(); ++argofs; } /* recalculate the arg offset and create TEMP moves */ for (i = 0; i < cnt; i++) { if (sp[i] == NULL) continue; if ((argofs >= NARGREGS) && !xtemps) break; if (argofs > NARGREGS) { putintemp(sp[i]); } else if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY) { param_struct(sp[i], &argofs); } else if (DEUNSIGN(sp[i]->stype) == LONGLONG) { param_64bit(sp[i], &argofs, xtemps && !saveallargs); } else if (sp[i]->stype == DOUBLE || sp[i]->stype == LDOUBLE) { if (features(FEATURE_HARDFLOAT)) param_double(sp[i], &argofs, xtemps && !saveallargs); else param_64bit(sp[i], &argofs, xtemps && !saveallargs); } else if (sp[i]->stype == FLOAT) { if (features(FEATURE_HARDFLOAT)) param_float(sp[i], &argofs, xtemps && !saveallargs); else param_32bit(sp[i], &argofs, xtemps && !saveallargs); } else { param_32bit(sp[i], &argofs, xtemps && !saveallargs); } } /* if saveallargs, save the rest of the args onto the stack */ while (saveallargs && argofs < NARGREGS) { NODE *p, *q; int off = ARGINIT/SZINT + argofs; q = block(REG, NIL, NIL, INT, 0, 0); regno(q) = R0 + argofs++; p = block(REG, NIL, NIL, INT, 0, 0); regno(p) = FPREG; p = block(PLUS, p, bcon(4*off), INT, 0, 0); p = block(UMUL, p, NIL, INT, 0, 0); p = buildtree(ASSIGN, p, q); ecomp(p); } } /* * End-of-Function code: */ void efcode(void) { NODE *p, *q; int tempnr; if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) return; /* * At this point, the address of the return structure on * has been FORCEd to RETREG, which is R0. * We want to copy the contents from there to the address * we placed into the tempnode "rvnr". */ /* move the pointer out of R0 to a tempnode */ q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap); q->n_rval = R0; p = tempnode(0, PTR+STRTY, 0, cftnsp->sap); tempnr = regno(p); p = buildtree(ASSIGN, p, q); ecomp(p); /* get the address from the tempnode */ q = tempnode(tempnr, PTR+STRTY, 0, cftnsp->sap); q = buildtree(UMUL, q, NIL); /* now, get the structure destination */ p = tempnode(rvnr, PTR+STRTY, 0, cftnsp->sap); p = buildtree(UMUL, p, NIL); /* struct assignment */ p = buildtree(ASSIGN, p, q); ecomp(p); } /* * End-of-job: called just before final exit. */ void ejobcode(int flag) { printf("\t.ident \"PCC: %s\"\n", VERSSTR); } /* * Beginning-of-job: called before compilation starts * * Initialise data structures specific for the local machine. */ void bjobcode(void) { } /* * fix up type of field p */ void fldty(struct symtab *p) { } /* * Build target-dependent switch tree/table. * * Return 1 if successfull, otherwise return 0 and the * target-independent tree will be used. */ int mygenswitch(int num, TWORD type, struct swents **p, int n) { return 0; } /* * Straighten a chain of CM ops so that the CM nodes * only appear on the left node. * * CM CM * CM CM CM b * x y a b CM a * x y */ static NODE * straighten(NODE *p) { NODE *r = p->n_right; if (p->n_op != CM || r->n_op != CM) return p; p->n_right = r->n_left; r->n_left = p; return r; } static NODE * reverse1(NODE *p, NODE *a) { NODE *l = p->n_left; NODE *r = p->n_right; a->n_right = r; p->n_left = a; if (l->n_op == CM) { return reverse1(l, p); } else { p->n_right = l; return p; } } /* * Reverse a chain of CM ops */ static NODE * reverse(NODE *p) { NODE *l = p->n_left; NODE *r = p->n_right; p->n_left = r; if (l->n_op == CM) return reverse1(l, p); p->n_right = l; return p; } /* push arg onto the stack */ /* called by moveargs() */ static NODE * pusharg(NODE *p, int *regp) { NODE *q; int sz; /* convert to register size, if smaller */ sz = tsize(p->n_type, p->n_df, p->n_ap); if (sz < SZINT) p = block(SCONV, p, NIL, INT, 0, 0); q = block(REG, NIL, NIL, INT, 0, 0); regno(q) = SP; if (szty(p->n_type) == 1) { ++(*regp); q = block(MINUSEQ, q, bcon(4), INT, 0, 0); } else { (*regp) += 2; q = block(MINUSEQ, q, bcon(8), INT, 0, 0); } q = block(UMUL, q, NIL, p->n_type, p->n_df, p->n_ap); return buildtree(ASSIGN, q, p); } /* setup call stack with 32-bit argument */ /* called from moveargs() */ static NODE * movearg_32bit(NODE *p, int *regp) { int reg = *regp; NODE *q; q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap); regno(q) = reg++; q = buildtree(ASSIGN, q, p); *regp = reg; return q; } /* setup call stack with 64-bit argument */ /* called from moveargs() */ static NODE * movearg_64bit(NODE *p, int *regp) { int reg = *regp; NODE *q, *r; #if ALLONGLONG == 64 /* alignment */ ++reg; reg &= ~1; *regp = reg; #endif if (reg > R3) { q = pusharg(p, regp); } else if (reg == R3) { /* half in and half out of the registers */ r = tcopy(p); if (!features(FEATURE_BIGENDIAN)) { q = block(SCONV, p, NIL, INT, 0, 0); q = movearg_32bit(q, regp); /* little-endian */ r = buildtree(RS, r, bcon(32)); r = block(SCONV, r, NIL, INT, 0, 0); r = pusharg(r, regp); /* little-endian */ } else { q = buildtree(RS, p, bcon(32)); q = block(SCONV, q, NIL, INT, 0, 0); q = movearg_32bit(q, regp); /* big-endian */ r = block(SCONV, r, NIL, INT, 0, 0); r = pusharg(r, regp); /* big-endian */ } q = straighten(block(CM, q, r, p->n_type, p->n_df, p->n_ap)); } else { q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap); regno(q) = R0R1 + (reg - R0); q = buildtree(ASSIGN, q, p); *regp = reg + 2; } return q; } /* setup call stack with float/double argument */ /* called from moveargs() */ static NODE * movearg_float(NODE *p, int *regp) { NODE *q, *r; TWORD ty = INCREF(p->n_type); int tmpnr; /* * Floats are passed in the general registers for * compatibily with libraries compiled to handle soft-float. */ if (xtemps) { /* bounce on TOS */ r = block(REG, NIL, NIL, ty, p->n_df, p->n_ap); regno(r) = SP; r = block(PLUS, r, bcon(-4), ty, p->n_df, p->n_ap); r = block(UMUL, r, NIL, p->n_type, p->n_df, p->n_ap); r = buildtree(ASSIGN, r, p); ecomp(r); /* bounce into temp */ r = block(REG, NIL, NIL, PTR+INT, 0, 0); regno(r) = SP; r = block(PLUS, r, bcon(-8), PTR+INT, 0, 0); r = block(UMUL, r, NIL, INT, 0, 0); q = tempnode(0, INT, 0, 0); tmpnr = regno(q); r = buildtree(ASSIGN, q, r); ecomp(r); } else { /* copy directly into temp */ q = tempnode(0, p->n_type, p->n_df, p->n_ap); tmpnr = regno(q); r = buildtree(ASSIGN, q, p); ecomp(r); } /* copy from temp to register parameter */ r = tempnode(tmpnr, INT, 0, 0); q = block(REG, NIL, NIL, INT, 0, 0); regno(q) = (*regp)++; p = buildtree(ASSIGN, q, r); return p; } /* setup call stack with float/double argument */ /* called from moveargs() */ static NODE * movearg_double(NODE *p, int *regp) { NODE *q, *r; TWORD ty = INCREF(p->n_type); int tmpnr; if (xtemps) { /* bounce on TOS */ r = block(REG, NIL, NIL, ty, p->n_df, p->n_ap); regno(r) = SP; r = block(PLUS, r, bcon(-8), ty, p->n_df, p->n_ap); r = block(UMUL, r, NIL, p->n_type, p->n_df, p->n_ap); r = buildtree(ASSIGN, r, p); ecomp(r); /* bounce into temp */ r = block(REG, NIL, NIL, PTR+LONGLONG, 0, 0); regno(r) = SP; r = block(PLUS, r, bcon(-8), PTR+LONGLONG, 0, 0); r = block(UMUL, r, NIL, LONGLONG, 0, 0); q = tempnode(0, LONGLONG, 0, 0); tmpnr = regno(q); r = buildtree(ASSIGN, q, r); ecomp(r); } else { /* copy directly into temp */ q = tempnode(0, p->n_type, p->n_df, p->n_ap); tmpnr = regno(q); r = buildtree(ASSIGN, q, p); ecomp(r); } /* copy from temp to register parameter */ r = tempnode(tmpnr, LONGLONG, 0, 0); q = block(REG, NIL, NIL, LONGLONG, 0, 0); regno(q) = R0R1 - R0 + (*regp); p = buildtree(ASSIGN, q, r); (*regp) += 2; return p; } /* setup call stack with a structure */ /* called from moveargs() */ static NODE * movearg_struct(NODE *p, int *regp) { int reg = *regp; NODE *l, *q, *t, *r; int tmpnr; int navail; int num; int sz; int ty; int i; assert(p->n_op == STARG); navail = NARGREGS - (reg - R0); navail = navail < 0 ? 0 : navail; sz = tsize(p->n_type, p->n_df, p->n_ap) / SZINT; num = sz > navail ? navail : sz; /* remove STARG node */ l = p->n_left; nfree(p); ty = l->n_type; /* * put it into a TEMP, rather than tcopy(), since the tree * in p may have side-affects */ t = tempnode(0, ty, l->n_df, l->n_ap); tmpnr = regno(t); q = buildtree(ASSIGN, t, l); /* copy structure into registers */ for (i = 0; i < num; i++) { t = tempnode(tmpnr, ty, 0, 0); t = block(SCONV, t, NIL, PTR+INT, 0, 0); t = block(PLUS, t, bcon(4*i), PTR+INT, 0, 0); t = buildtree(UMUL, t, NIL); r = block(REG, NIL, NIL, INT, 0, 0); regno(r) = reg++; r = buildtree(ASSIGN, r, t); q = block(CM, q, r, INT, 0, 0); } /* put the rest of the structure on the stack */ for (i = num; i < sz; i++) { t = tempnode(tmpnr, ty, 0, 0); t = block(SCONV, t, NIL, PTR+INT, 0, 0); t = block(PLUS, t, bcon(4*i), PTR+INT, 0, 0); t = buildtree(UMUL, t, NIL); r = pusharg(t, ®); q = block(CM, q, r, INT, 0, 0); } q = reverse(q); *regp = reg; return q; } static NODE * moveargs(NODE *p, int *regp) { NODE *r, **rp; int reg; if (p->n_op == CM) { p->n_left = moveargs(p->n_left, regp); r = p->n_right; rp = &p->n_right; } else { r = p; rp = &p; } reg = *regp; if (reg > R3 && r->n_op != STARG) { *rp = pusharg(r, regp); } else if (r->n_op == STARG) { *rp = movearg_struct(r, regp); } else if (DEUNSIGN(r->n_type) == LONGLONG) { *rp = movearg_64bit(r, regp); } else if (r->n_type == DOUBLE || r->n_type == LDOUBLE) { *rp = movearg_double(r, regp); } else if (r->n_type == FLOAT) { *rp = movearg_float(r, regp); } else { *rp = movearg_32bit(r, regp); } return straighten(p); } /* * Fixup arguments to pass pointer-to-struct as first argument. * * called from funcode(). */ static NODE * retstruct(NODE *p) { NODE *l, *r, *t, *q; TWORD ty; l = p->n_left; r = p->n_right; ty = DECREF(l->n_type) - FTN; // assert(tsize(ty, l->n_df, l->n_ap) == SZINT); /* structure assign */ q = tempnode(0, ty, l->n_df, l->n_ap); q = buildtree(ADDROF, q, NIL); /* insert hidden assignment at beginning of list */ if (r->n_op != CM) { p->n_right = block(CM, q, r, INCREF(ty), l->n_df, l->n_ap); } else { for (t = r; t->n_left->n_op == CM; t = t->n_left) ; t->n_left = block(CM, q, t->n_left, INCREF(ty), l->n_df, l->n_ap); } return p; } NODE * builtin_frame_address(const struct bitable *bt, NODE *a) { assert(0); return NULL; } NODE * builtin_return_address(const struct bitable *bt, NODE *a) { assert(0); return NULL; } NODE * builtin_cfa(const struct bitable *bt, NODE *a) { assert(0); return NULL; } /* * Called with a function call with arguments as argument. * This is done early in buildtree() and only done once. */ NODE * funcode(NODE *p) { int reg = R0; if (p->n_type == STRTY+FTN || p->n_type == UNIONTY+FTN) { p = retstruct(p); reg = R1; } p->n_right = moveargs(p->n_right, ®); if (p->n_right == NULL) p->n_op += (UCALL - CALL); return p; } pcc-20181216/arch/arm/local.c010064400017500000000000000354531267006451400144350ustar raggewheel/* $Id: local.c,v 1.34 2016/03/09 18:19:56 ragge Exp $ */ /* * Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org). * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * We define location operations which operate on the expression tree * during the first pass (before sending to the backend for code generation.) */ #include #include "pass1.h" #undef NIL #define NIL NULL #ifdef LANG_CXX #define p1listf listf #define p1tfree tfree #else #define NODE P1ND #define talloc p1alloc #define tcopy p1tcopy #define nfree p1nfree #endif extern void defalign(int); static char * getsoname(struct symtab *sp) { struct attr *ap; return (ap = attr_find(sp->sap, ATTR_SONAME)) ? ap->sarg(0) : sp->sname; } /* * clocal() is called to do local transformations on * an expression tree before being sent to the backend. */ NODE * clocal(NODE *p) { struct symtab *q; NODE *l, *r, *t; int o; int ty; int tmpnr, isptrvoid = 0; char *n; o = p->n_op; switch (o) { case STASG: l = p->n_left; r = p->n_right; if (r->n_op != STCALL && r->n_op != USTCALL) return p; /* assign left node as first argument to function */ nfree(p); t = block(REG, NIL, NIL, r->n_type, r->n_df, r->n_ap); l->n_rval = R0; l = buildtree(ADDROF, l, NIL); l = buildtree(ASSIGN, t, l); if (r->n_right->n_op != CM) { r->n_right = block(CM, l, r->n_right, INT, 0, 0); } else { for (t = r->n_right; t->n_left->n_op == CM; t = t->n_left) ; t->n_left = block(CM, l, t->n_left, INT, 0, 0); } return r; case CALL: case STCALL: case USTCALL: if (p->n_type == VOID) break; /* * if the function returns void*, ecode() invokes * delvoid() to convert it to uchar*. * We just let this happen on the ASSIGN to the temp, * and cast the pointer back to void* on access * from the temp. */ if (p->n_type == PTR+VOID) isptrvoid = 1; r = tempnode(0, p->n_type, p->n_df, p->n_ap); tmpnr = regno(r); r = block(ASSIGN, r, p, p->n_type, p->n_df, p->n_ap); p = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap); if (isptrvoid) { p = block(PCONV, p, NIL, PTR+VOID, p->n_df, 0); } p = buildtree(COMOP, r, p); break; case NAME: if ((q = p->n_sp) == NULL) return p; if (blevel == 0) return p; switch (q->sclass) { case PARAM: case AUTO: /* fake up a structure reference */ r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); slval(r, 0); r->n_rval = FPREG; p = stref(block(STREF, r, p, 0, 0, 0)); break; case REGISTER: p->n_op = REG; slval(p, 0); p->n_rval = q->soffset; break; case STATIC: if (q->slevel > 0) { slval(p, 0); p->n_sp = q; } /* FALL-THROUGH */ default: ty = p->n_type; n = getsoname(p->n_sp); if (strncmp(n, "__builtin", 9) == 0) break; p = block(ADDROF, p, NIL, INCREF(ty), p->n_df, p->n_ap); p = block(UMUL, p, NIL, ty, p->n_df, p->n_ap); break; } break; case STNAME: if ((q = p->n_sp) == NULL) return p; if (q->sclass != STNAME) return p; ty = p->n_type; p = block(ADDROF, p, NIL, INCREF(ty), p->n_df, p->n_ap); p = block(UMUL, p, NIL, ty, p->n_df, p->n_ap); break; case FORCE: /* put return value in return reg */ p->n_op = ASSIGN; p->n_right = p->n_left; p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0); p->n_left->n_rval = p->n_left->n_type == BOOL ? RETREG(BOOL_TYPE) : RETREG(p->n_type); break; case SCONV: l = p->n_left; if (p->n_type == l->n_type) { nfree(p); return l; } if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 && tsize(p->n_type, p->n_df, p->n_ap) == tsize(l->n_type, l->n_df, l->n_ap)) { if (p->n_type != FLOAT && p->n_type != DOUBLE && l->n_type != FLOAT && l->n_type != DOUBLE && l->n_type != LDOUBLE && p->n_type != LDOUBLE) { if (l->n_op == NAME || l->n_op == UMUL || l->n_op == TEMP) { l->n_type = p->n_type; nfree(p); return l; } } } if (l->n_op == ICON) { CONSZ val = glval(l); CONSZ lval; if (!ISPTR(p->n_type)) /* Pointers don't need to be conv'd */ switch (p->n_type) { case BOOL: slval(l, glval(l) != 0); break; case CHAR: lval = (char)val; break; case UCHAR: lval = val & 0377; break; case SHORT: lval = (short)val; break; case USHORT: lval = val & 0177777; break; case ULONG: case UNSIGNED: lval = val & 0xffffffff; break; case LONG: case INT: lval = (int)val; break; case LONGLONG: lval = (long long)val; break; case ULONGLONG: lval = val; break; case VOID: break; case LDOUBLE: case DOUBLE: case FLOAT: l->n_op = FCON; ((FLT *)l->n_dcon)->fp = val; break; default: cerror("unknown type %d", l->n_type); } if (p->n_type < FLOAT) slval(l, lval); l->n_type = p->n_type; l->n_ap = 0; nfree(p); return l; } else if (p->n_op == FCON) { slval(l, ((FLT *)l->n_dcon)->fp); l->n_sp = NULL; l->n_op = ICON; l->n_type = p->n_type; l->n_ap = 0; nfree(p); return clocal(l); } if ((DEUNSIGN(p->n_type) == CHAR || DEUNSIGN(p->n_type) == SHORT) && (l->n_type == FLOAT || l->n_type == DOUBLE || l->n_type == LDOUBLE)) { p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap); p->n_left->n_type = INT; return p; } break; case PCONV: l = p->n_left; if (l->n_op == ICON) { slval(l, (unsigned)glval(l)); goto delp; } if (l->n_type < INT || DEUNSIGN(l->n_type) == LONGLONG) { p->n_left = block(SCONV, l, NIL, UNSIGNED, 0, 0); break; } if (l->n_op == SCONV) break; if (l->n_op == ADDROF && l->n_left->n_op == TEMP) goto delp; if (p->n_type > BTMASK && l->n_type > BTMASK) goto delp; break; delp: l->n_type = p->n_type; l->n_qual = p->n_qual; l->n_df = p->n_df; l->n_ap = p->n_ap; nfree(p); p = l; break; } return p; } /* * Called before sending the tree to the backend. */ void myp2tree(NODE *p) { struct symtab *sp; if (p->n_op != FCON) return; #define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz)) sp = IALLOC(sizeof(struct symtab)); sp->sclass = STATIC; sp->sap = 0; sp->slevel = 1; /* fake numeric label */ sp->soffset = getlab(); sp->sflags = 0; sp->stype = p->n_type; sp->squal = (CON >> TSHIFT); defloc(sp); ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p); p->n_op = NAME; slval(p, 0); p->n_sp = sp; } /* * Called during the first pass to determine if a NAME can be addressed. * * Return nonzero if supported, otherwise return 0. */ int andable(NODE *p) { if (blevel == 0) return 1; if (ISFTN(p->n_type)) return 1; return 0; } /* * Return 1 if a variable of type 't' is OK to put in register. */ int cisreg(TWORD t) { if (t == FLOAT || t == DOUBLE || t == LDOUBLE) return 0; /* not yet */ return 1; } /* * Allocate bits from the stack for dynamic-sized arrays. * * 'p' is the tree which represents the type being allocated. * 'off' is the number of 'p's to be allocated. * 't' is the storeable node where the address is written. */ void spalloc(NODE *t, NODE *p, OFFSZ off) { NODE *sp; p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */ /* sub the size from sp */ sp = block(REG, NIL, NIL, p->n_type, 0, 0); slval(sp, 0); sp->n_rval = SP; ecomp(buildtree(MINUSEQ, sp, p)); /* save the address of sp */ sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap); slval(sp, 0); sp->n_rval = SP; t->n_type = sp->n_type; ecomp(buildtree(ASSIGN, t, sp)); } /* * Print an integer constant node, may be associated with a label. * Do not free the node after use. * 'off' is bit offset from the beginning of the aggregate * 'fsz' is the number of bits this is referring to */ int ninval(CONSZ off, int fsz, NODE *p) { union { float f; double d; int i[2]; } u; struct symtab *q; TWORD t; int i, j; t = p->n_type; if (t > BTMASK) t = p->n_type = INT; /* pointer */ if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT) uerror("element not constant"); switch (t) { case LONGLONG: case ULONGLONG: i = (glval(p) >> 32); j = (glval(p) & 0xffffffff); p->n_type = INT; if (features(FEATURE_BIGENDIAN)) { slval(p, i); ninval(off+32, 32, p); slval(p, j); ninval(off, 32, p); } else { slval(p, j); ninval(off, 32, p); slval(p, i); ninval(off+32, 32, p); } break; case INT: case UNSIGNED: printf("\t.word 0x%x", (int)glval(p)); if ((q = p->n_sp) != NULL) { if ((q->sclass == STATIC && q->slevel > 0)) { printf("+" LABFMT, q->soffset); } else printf("+%s", getexname(q)); } printf("\n"); break; case LDOUBLE: case DOUBLE: u.d = (double)((FLT *)p->n_dcon)->fp; #if defined(HOST_BIG_ENDIAN) if (features(FEATURE_BIGENDIAN)) #else if (!features(FEATURE_BIGENDIAN)) #endif printf("\t.word\t0x%x\n\t.word\t0x%x\n", u.i[0], u.i[1]); else printf("\t.word\t0x%x\n\t.word\t0x%x\n", u.i[1], u.i[0]); break; case FLOAT: u.f = (float)((FLT *)p->n_dcon)->fp; printf("\t.word\t0x%x\n", u.i[0]); break; default: return 0; } return 1; } /* * Prefix a leading underscore to a global variable (if necessary). */ char * exname(char *p) { return (p == NULL ? "" : p); } /* * Map types which are not defined on the local machine. */ TWORD ctype(TWORD type) { switch (BTYPE(type)) { case LONG: MODTYPE(type,INT); break; case ULONG: MODTYPE(type,UNSIGNED); break; } return (type); } /* * Before calling a function do any tree re-writing for the local machine. * * 'p' is the function tree (NAME) * 'q' is the CM-separated list of arguments. */ void calldec(NODE *p, NODE *q) { } /* * While handling uninitialised variables, handle variables marked extern. */ void extdec(struct symtab *q) { } /* make a common declaration for id, if reasonable */ void defzero(struct symtab *sp) { int off; off = tsize(sp->stype, sp->sdf, sp->sap); off = (off+(SZCHAR-1))/SZCHAR; printf(" .%scomm ", sp->sclass == STATIC ? "l" : ""); if (sp->slevel == 0) printf("%s,0%o\n", getexname(sp), off); else printf(LABFMT ",0%o\n", sp->soffset, off); } /* * va_start(ap, last) implementation. * * f is the NAME node for this builtin function. * a is the argument list containing: * CM * ap last */ NODE * arm_builtin_stdarg_start(const struct bitable *bt, NODE *a) { NODE *p, *q; int sz = 1; /* check num args and type */ if (a == NULL || a->n_op != CM || a->n_left->n_op == CM || !ISPTR(a->n_left->n_type)) goto bad; /* must first deal with argument size; use int size */ p = a->n_right; if (p->n_type < INT) { /* round up to word */ sz = SZINT / tsize(p->n_type, p->n_df, p->n_ap); } p = buildtree(ADDROF, p, NIL); /* address of last arg */ p = optim(buildtree(PLUS, p, bcon(sz))); q = block(NAME, NIL, NIL, PTR+VOID, 0, 0); q = buildtree(CAST, q, p); p = q->n_right; nfree(q->n_left); nfree(q); p = buildtree(ASSIGN, a->n_left, p); nfree(a); return p; bad: uerror("bad argument to __builtin_stdarg_start"); return bcon(0); } NODE * arm_builtin_va_arg(const struct bitable *bt, NODE *a) { NODE *p, *q, *r; int sz, tmpnr; /* check num args and type */ if (a == NULL || a->n_op != CM || a->n_left->n_op == CM || !ISPTR(a->n_left->n_type) || a->n_right->n_op != TYPE) goto bad; r = a->n_right; /* get type size */ sz = tsize(r->n_type, r->n_df, r->n_ap) / SZCHAR; if (sz < SZINT/SZCHAR) { werror("%s%s promoted to int when passed through ...", ISUNSIGNED(r->n_type) ? "unsigned " : "", DEUNSIGN(r->n_type) == SHORT ? "short" : "char"); sz = SZINT/SZCHAR; } /* alignment */ p = tcopy(a->n_left); if (sz > SZINT/SZCHAR && r->n_type != UNIONTY && r->n_type != STRTY) { p = buildtree(PLUS, p, bcon(ALSTACK/8 - 1)); p = block(AND, p, bcon(-ALSTACK/8), p->n_type, p->n_df, p->n_ap); } /* create a copy to a temp node */ q = tempnode(0, p->n_type, p->n_df, p->n_ap); tmpnr = regno(q); p = buildtree(ASSIGN, q, p); q = tempnode(tmpnr, p->n_type, p->n_df,p->n_ap); q = buildtree(PLUS, q, bcon(sz)); q = buildtree(ASSIGN, a->n_left, q); q = buildtree(COMOP, p, q); nfree(a->n_right); nfree(a); p = tempnode(tmpnr, INCREF(r->n_type), r->n_df, r->n_ap); p = buildtree(UMUL, p, NIL); p = buildtree(COMOP, q, p); return p; bad: uerror("bad argument to __builtin_va_arg"); return bcon(0); } NODE * arm_builtin_va_end(const struct bitable *bt, NODE *a) { p1tfree(a); return bcon(0); } NODE * arm_builtin_va_copy(const struct bitable *bt, NODE *a) { NODE *f; if (a == NULL || a->n_op != CM || a->n_left->n_op == CM) goto bad; f = buildtree(ASSIGN, a->n_left, a->n_right); nfree(a); return f; bad: uerror("bad argument to __buildtin_va_copy"); return bcon(0); } char *nextsect; static int constructor; static int destructor; /* * Give target the opportunity of handling pragmas. */ int mypragma(char *str) { char *a2 = pragtok(NULL); if (strcmp(str, "tls") == 0) { uerror("thread-local storage not supported for this target"); return 1; } if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) { constructor = 1; return 1; } if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) { destructor = 1; return 1; } if (strcmp(str, "section") == 0 && a2 != NULL) { nextsect = newstring(a2, strlen(a2)); return 1; } return 0; } /* * Called when a identifier has been declared, to give target last word. */ void fixdef(struct symtab *sp) { if ((constructor || destructor) && (sp->sclass != PARAM)) { printf("\t.section .%ctors,\"aw\",@progbits\n", constructor ? 'c' : 'd'); printf("\t.p2align 2\n"); printf("\t.long %s\n", exname(sp->sname)); printf("\t.previous\n"); constructor = destructor = 0; } } void pass1_lastchance(struct interpass *ip) { } pcc-20181216/arch/arm/local2.c010064400017500000000000001114761277225026600145230ustar raggewheel/* $Id: local2.c,v 1.40 2016/09/26 16:45:42 ragge Exp $ */ /* * Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org). * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include "pass2.h" extern void defalign(int); #define exname(x) x char *rnames[] = { "r0", "r1", "r2", "r3","r4","r5", "r6", "r7", "r8", "r9", "r10", "fp", "ip", "sp", "lr", "pc", "r0r1", "r1r2", "r2r3", "r3r4", "r4r5", "r5r6", "r6r7", "r7r8", "r8r9", "r9r10", "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", }; /* * Handling of integer constants. We have 8 bits + an even * number of rotates available as a simple immediate. * If a constant isn't trivially representable, use an ldr * and a subsequent sequence of orr operations. */ static int trepresent(const unsigned int val) { int i; #define rotate_left(v, n) (v << n | v >> (32 - n)) for (i = 0; i < 32; i += 2) if (rotate_left(val, i) <= 0xff) return 1; return 0; } /* * Return values are: * 0 - output constant as is (should be covered by trepresent() above) * 1 - 4 generate 1-4 instructions as needed. */ static int encode_constant(int constant, int *values) { int tmp = constant; int i = 0; int first_bit, value; while (tmp) { first_bit = ffs(tmp); first_bit -= 1; /* ffs indexes from 1, not 0 */ first_bit &= ~1; /* must use even bit offsets */ value = tmp & (0xff << first_bit); values[i++] = value; tmp &= ~value; } return i; } #if 0 static void load_constant(NODE *p) { int v = p->n_lval & 0xffffffff; int reg = DECRA(p->n_reg, 1); load_constant_into_reg(reg, v); } #endif static void load_constant_into_reg(int reg, int v) { if (trepresent(v)) printf("\tmov %s,#%d\n", rnames[reg], v); else if (trepresent(-v)) printf("\tmvn %s,#%d\n", rnames[reg], -v); else { int vals[4], nc, i; nc = encode_constant(v, vals); for (i = 0; i < nc; i++) { if (i == 0) { printf("\tmov %s,#%d" COM "load constant %d\n", rnames[reg], vals[i], v); } else { printf("\torr %s,%s,#%d\n", rnames[reg], rnames[reg], vals[i]); } } } } static TWORD ftype; /* * calculate stack size and offsets */ static int offcalc(struct interpass_prolog *ipp) { int addto; #ifdef PCC_DEBUG if (x2debug) printf("offcalc: p2maxautooff=%d\n", p2maxautooff); #endif addto = p2maxautooff; #if 0 addto += 7; addto &= ~7; #endif #ifdef PCC_DEBUG if (x2debug) printf("offcalc: addto=%d\n", addto); #endif addto -= AUTOINIT / SZCHAR; return addto; } void prologue(struct interpass_prolog *ipp) { int addto; int vals[4], nc, i; #ifdef PCC_DEBUG if (x2debug) printf("prologue: type=%d, lineno=%d, name=%s, vis=%d, ipptype=%d, autos=%d, tmpnum=%d, lblnum=%d\n", ipp->ipp_ip.type, ipp->ipp_ip.lineno, ipp->ipp_name, ipp->ipp_vis, ipp->ipp_type, ipp->ipp_autos, ipp->ip_tmpnum, ipp->ip_lblnum); #endif ftype = ipp->ipp_type; #if 0 printf("\t.align 2\n"); if (ipp->ipp_vis) printf("\t.global %s\n", exname(ipp->ipp_name)); printf("\t.type %s,%%function\n", exname(ipp->ipp_name)); #endif printf("%s:\n", exname(ipp->ipp_name)); /* * We here know what register to save and how much to * add to the stack. */ addto = offcalc(ipp); printf("\tsub %s,%s,#%d\n", rnames[SP], rnames[SP], 16); printf("\tmov %s,%s\n", rnames[IP], rnames[SP]); printf("\tstmfd %s!,{%s,%s,%s,%s}\n", rnames[SP], rnames[FP], rnames[IP], rnames[LR], rnames[PC]); printf("\tsub %s,%s,#4\n", rnames[FP], rnames[IP]); if (addto == 0) return; if (trepresent(addto)) { printf("\tsub %s,%s,#%d\n", rnames[SP], rnames[SP], addto); } else { nc = encode_constant(addto, vals); for (i = 0; i < nc; i++) printf("\tsub %s,%s,#%d\n", rnames[SP], rnames[SP], vals[i]); } } void eoftn(struct interpass_prolog *ipp) { if (ipp->ipp_ip.ip_lbl == 0) return; /* no code needs to be generated */ /* struct return needs special treatment */ if (ftype == STRTY || ftype == UNIONTY) { assert(0); } else { printf("\tldmea %s,{%s,%s,%s}\n", rnames[FP], rnames[FP], rnames[SP], rnames[PC]); printf("\tadd %s,%s,#%d\n", rnames[SP], rnames[SP], 16); } printf("\t.size %s,.-%s\n", exname(ipp->ipp_name), exname(ipp->ipp_name)); } /* * these mnemonics match the order of the preprocessor decls * EQ, NE, LE, LT, GE, GT, ULE, ULT, UGE, UGT */ static char * ccbranches[] = { "beq", /* branch if equal */ "bne", /* branch if not-equal */ "ble", /* branch if less-than-or-equal */ "blt", /* branch if less-than */ "bge", /* branch if greater-than-or-equal */ "bgt", /* branch if greater-than */ /* what should these be ? */ "bls", /* branch if lower-than-or-same */ "blo", /* branch if lower-than */ "bhs", /* branch if higher-than-or-same */ "bhi", /* branch if higher-than */ }; /* * add/sub/... * * Param given: */ void hopcode(int f, int o) { char *str; switch (o) { case PLUS: str = "add"; break; case MINUS: str = "sub"; break; case AND: str = "and"; break; case OR: str = "orr"; break; case ER: str = "eor"; break; default: comperr("hopcode2: %d", o); str = 0; /* XXX gcc */ } printf("%s%c", str, f); } /* * Return type size in bytes. Used by R2REGS, arg 2 to offset(). */ int tlen(NODE *p) { switch(p->n_type) { case CHAR: case UCHAR: return(1); case SHORT: case USHORT: return(SZSHORT/SZCHAR); case DOUBLE: return(SZDOUBLE/SZCHAR); case INT: case UNSIGNED: case LONG: case ULONG: return(SZINT/SZCHAR); case LONGLONG: case ULONGLONG: return SZLONGLONG/SZCHAR; default: if (!ISPTR(p->n_type)) comperr("tlen type %d not pointer"); return SZPOINT(p->n_type)/SZCHAR; } } /* * Emit code to compare two longlong numbers. */ static void twollcomp(NODE *p) { int o = p->n_op; int s = getlab2(); int e = p->n_label; int cb1, cb2; if (o >= ULE) o -= (ULE-LE); switch (o) { case NE: cb1 = 0; cb2 = NE; break; case EQ: cb1 = NE; cb2 = 0; break; case LE: case LT: cb1 = GT; cb2 = LT; break; case GE: case GT: cb1 = LT; cb2 = GT; break; default: cb1 = cb2 = 0; /* XXX gcc */ } if (p->n_op >= ULE) cb1 += 4, cb2 += 4; expand(p, 0, "\tcmp UR,UL" COM "compare 64-bit values (upper)\n"); if (cb1) cbgen(cb1, s); if (cb2) cbgen(cb2, e); expand(p, 0, "\tcmp AR,AL" COM "(and lower)\n"); cbgen(p->n_op, e); deflab(s); } int fldexpand(NODE *p, int cookie, char **cp) { CONSZ val; int shft; if (p->n_op == ASSIGN) p = p->n_left; if (features(FEATURE_BIGENDIAN)) shft = SZINT - UPKFSZ(p->n_rval) - UPKFOFF(p->n_rval); else shft = UPKFOFF(p->n_rval); switch (**cp) { case 'S': printf("#%d", UPKFSZ(p->n_rval)); break; case 'H': printf("#%d", shft); break; case 'M': case 'N': val = (CONSZ)1 << UPKFSZ(p->n_rval); --val; val <<= shft; printf("%lld", (**cp == 'M' ? val : ~val) & 0xffffffff); break; default: comperr("fldexpand"); } return 1; } /* * Structure assignment. */ static void stasg(NODE *p) { NODE *l = p->n_left; int val = getlval(l); /* R0 = dest, R1 = src, R2 = len */ load_constant_into_reg(R2, attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)); if (l->n_op == OREG) { if (R2TEST(regno(l))) { int r = regno(l); printf("\tadd %s,%s,lsl #%d\n", rnames[R0], rnames[R2UPK2(r)], R2UPK3(r)); printf("\tadd %s,%s,%s\n", rnames[R0], rnames[R0], rnames[R2UPK1(r)]); } else { if (trepresent(val)) { printf("\tadd %s,%s,#%d\n", rnames[R0], rnames[regno(l)], val); } else { load_constant_into_reg(R0, val); printf("\tadd %s,%s,%s\n", rnames[R0], rnames[R0], rnames[regno(l)]); } } } else if (l->n_op == NAME) { cerror("not implemented"); } printf("\tbl %s\n", exname("memcpy")); } static void shiftop(NODE *p) { NODE *r = p->n_right; TWORD ty = p->n_type; char *shifttype; if (p->n_op == LS && r->n_op == ICON && getlval(r) < 32) { expand(p, INBREG, "\tmov A1,AL,lsr "); printf(CONFMT COM "64-bit left-shift\n", 32 - getlval(r)); expand(p, INBREG, "\tmov U1,UL,asl AR\n"); expand(p, INBREG, "\torr U1,U1,A1\n"); expand(p, INBREG, "\tmov A1,AL,asl AR\n"); } else if (p->n_op == LS && r->n_op == ICON && getlval(r) < 64) { expand(p, INBREG, "\tmov A1,#0" COM "64-bit left-shift\n"); expand(p, INBREG, "\tmov U1,AL"); if (getlval(r) - 32 != 0) printf(",asl " CONFMT, getlval(r) - 32); printf("\n"); } else if (p->n_op == LS && r->n_op == ICON) { expand(p, INBREG, "\tmov A1,#0" COM "64-bit left-shift\n"); expand(p, INBREG, "\tmov U1,#0\n"); } else if (p->n_op == RS && r->n_op == ICON && getlval(r) < 32) { expand(p, INBREG, "\tmov U1,UL,asl "); printf(CONFMT COM "64-bit right-shift\n", 32 - getlval(r)); expand(p, INBREG, "\tmov A1,AL,lsr AR\n"); expand(p, INBREG, "\torr A1,A1,U1\n"); if (ty == LONGLONG) expand(p, INBREG, "\tmov U1,UL,asr AR\n"); else expand(p, INBREG, "\tmov U1,UL,lsr AR\n"); } else if (p->n_op == RS && r->n_op == ICON && getlval(r) < 64) { if (ty == LONGLONG) { expand(p, INBREG, "\tmvn U1,#1" COM "64-bit right-shift\n"); expand(p, INBREG, "\tmov A1,UL"); shifttype = "asr"; }else { expand(p, INBREG, "\tmov U1,#0" COM "64-bit right-shift\n"); expand(p, INBREG, "\tmov A1,UL"); shifttype = "lsr"; } if (getlval(r) - 32 != 0) printf(",%s " CONFMT, shifttype, getlval(r) - 32); printf("\n"); } else if (p->n_op == RS && r->n_op == ICON) { expand(p, INBREG, "\tmov A1,#0" COM "64-bit right-shift\n"); expand(p, INBREG, "\tmov U1,#0\n"); } } /* * http://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Soft-float-library-routines */ static void fpemul(NODE *p) { NODE *l = p->n_left; char *ch = NULL; if (p->n_op == PLUS && p->n_type == FLOAT) ch = "addsf3"; else if (p->n_op == PLUS && p->n_type == DOUBLE) ch = "adddf3"; else if (p->n_op == PLUS && p->n_type == LDOUBLE) ch = "adddf3"; else if (p->n_op == MINUS && p->n_type == FLOAT) ch = "subsf3"; else if (p->n_op == MINUS && p->n_type == DOUBLE) ch = "subdf3"; else if (p->n_op == MINUS && p->n_type == LDOUBLE) ch = "subdf3"; else if (p->n_op == MUL && p->n_type == FLOAT) ch = "mulsf3"; else if (p->n_op == MUL && p->n_type == DOUBLE) ch = "muldf3"; else if (p->n_op == MUL && p->n_type == LDOUBLE) ch = "muldf3"; else if (p->n_op == DIV && p->n_type == FLOAT) ch = "divsf3"; else if (p->n_op == DIV && p->n_type == DOUBLE) ch = "divdf3"; else if (p->n_op == DIV && p->n_type == LDOUBLE) ch = "divdf3"; else if (p->n_op == UMINUS && p->n_type == FLOAT) ch = "negsf2"; else if (p->n_op == UMINUS && p->n_type == DOUBLE) ch = "negdf2"; else if (p->n_op == UMINUS && p->n_type == LDOUBLE) ch = "negdf2"; else if (p->n_op == EQ && l->n_type == FLOAT) ch = "eqsf2"; else if (p->n_op == EQ && l->n_type == DOUBLE) ch = "eqdf2"; else if (p->n_op == EQ && l->n_type == LDOUBLE) ch = "eqdf2"; else if (p->n_op == NE && l->n_type == FLOAT) ch = "nesf2"; else if (p->n_op == NE && l->n_type == DOUBLE) ch = "nedf2"; else if (p->n_op == NE && l->n_type == LDOUBLE) ch = "nedf2"; else if (p->n_op == GE && l->n_type == FLOAT) ch = "gesf2"; else if (p->n_op == GE && l->n_type == DOUBLE) ch = "gedf2"; else if (p->n_op == GE && l->n_type == LDOUBLE) ch = "gedf2"; else if (p->n_op == LE && l->n_type == FLOAT) ch = "lesf2"; else if (p->n_op == LE && l->n_type == DOUBLE) ch = "ledf2"; else if (p->n_op == LE && l->n_type == LDOUBLE) ch = "ledf2"; else if (p->n_op == GT && l->n_type == FLOAT) ch = "gtsf2"; else if (p->n_op == GT && l->n_type == DOUBLE) ch = "gtdf2"; else if (p->n_op == GT && l->n_type == LDOUBLE) ch = "gtdf2"; else if (p->n_op == LT && l->n_type == FLOAT) ch = "ltsf2"; else if (p->n_op == LT && l->n_type == DOUBLE) ch = "ltdf2"; else if (p->n_op == LT && l->n_type == LDOUBLE) ch = "ltdf2"; else if (p->n_op == SCONV && p->n_type == FLOAT) { if (l->n_type == DOUBLE) ch = "truncdfsf2"; else if (l->n_type == LDOUBLE) ch = "truncdfsf2"; else if (l->n_type == ULONGLONG) ch = "floatunsdisf"; else if (l->n_type == LONGLONG) ch = "floatdisf"; else if (l->n_type == LONG) ch = "floatsisf"; else if (l->n_type == ULONG) ch = "floatunsisf"; else if (l->n_type == INT) ch = "floatsisf"; else if (l->n_type == UNSIGNED) ch = "floatunsisf"; } else if (p->n_op == SCONV && p->n_type == DOUBLE) { if (l->n_type == FLOAT) ch = "extendsfdf2"; else if (l->n_type == LDOUBLE) ch = "trunctfdf2"; else if (l->n_type == ULONGLONG) ch = "floatunsdidf"; else if (l->n_type == LONGLONG) ch = "floatdidf"; else if (l->n_type == LONG) ch = "floatsidf"; else if (l->n_type == ULONG) ch = "floatunsidf"; else if (l->n_type == INT) ch = "floatsidf"; else if (l->n_type == UNSIGNED) ch = "floatunsidf"; } else if (p->n_op == SCONV && p->n_type == LDOUBLE) { if (l->n_type == FLOAT) ch = "extendsfdf2"; else if (l->n_type == DOUBLE) ch = "extenddftd2"; else if (l->n_type == ULONGLONG) ch = "floatunsdidf"; else if (l->n_type == LONGLONG) ch = "floatdidf"; else if (l->n_type == LONG) ch = "floatsidf"; else if (l->n_type == ULONG) ch = "floatunsidf"; else if (l->n_type == INT) ch = "floatsidf"; else if (l->n_type == UNSIGNED) ch = "floatunsidf"; } else if (p->n_op == SCONV && p->n_type == ULONGLONG) { if (l->n_type == FLOAT) ch = "fixunssfdi"; else if (l->n_type == DOUBLE) ch = "fixunsdfdi"; else if (l->n_type == LDOUBLE) ch = "fixunsdfdi"; } else if (p->n_op == SCONV && p->n_type == LONGLONG) { if (l->n_type == FLOAT) ch = "fixsfdi"; else if (l->n_type == DOUBLE) ch = "fixdfdi"; else if (l->n_type == LDOUBLE) ch = "fixdfdi"; } else if (p->n_op == SCONV && p->n_type == LONG) { if (l->n_type == FLOAT) ch = "fixsfsi"; else if (l->n_type == DOUBLE) ch = "fixdfsi"; else if (l->n_type == LDOUBLE) ch = "fixdfsi"; } else if (p->n_op == SCONV && p->n_type == ULONG) { if (l->n_type == FLOAT) ch = "fixunssfdi"; else if (l->n_type == DOUBLE) ch = "fixunsdfdi"; else if (l->n_type == LDOUBLE) ch = "fixunsdfdi"; } else if (p->n_op == SCONV && p->n_type == INT) { if (l->n_type == FLOAT) ch = "fixsfsi"; else if (l->n_type == DOUBLE) ch = "fixdfsi"; else if (l->n_type == LDOUBLE) ch = "fixdfsi"; } else if (p->n_op == SCONV && p->n_type == UNSIGNED) { if (l->n_type == FLOAT) ch = "fixunssfsi"; else if (l->n_type == DOUBLE) ch = "fixunsdfsi"; else if (l->n_type == LDOUBLE) ch = "fixunsdfsi"; } if (ch == NULL) comperr("ZF: op=0x%x (%d)\n", p->n_op, p->n_op); printf("\tbl __%s" COM "softfloat operation\n", exname(ch)); if (p->n_op >= EQ && p->n_op <= GT) printf("\tcmp %s,#0\n", rnames[R0]); } /* * http://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html#Integer-library-routines */ static void emul(NODE *p) { char *ch = NULL; if (p->n_op == LS && DEUNSIGN(p->n_type) == LONGLONG) ch = "ashldi3"; else if (p->n_op == LS && DEUNSIGN(p->n_type) == LONG) ch = "ashlsi3"; else if (p->n_op == LS && DEUNSIGN(p->n_type) == INT) ch = "ashlsi3"; else if (p->n_op == RS && p->n_type == ULONGLONG) ch = "lshrdi3"; else if (p->n_op == RS && p->n_type == ULONG) ch = "lshrsi3"; else if (p->n_op == RS && p->n_type == UNSIGNED) ch = "lshrsi3"; else if (p->n_op == RS && p->n_type == LONGLONG) ch = "ashrdi3"; else if (p->n_op == RS && p->n_type == LONG) ch = "ashrsi3"; else if (p->n_op == RS && p->n_type == INT) ch = "ashrsi3"; else if (p->n_op == DIV && p->n_type == LONGLONG) ch = "divdi3"; else if (p->n_op == DIV && p->n_type == LONG) ch = "divsi3"; else if (p->n_op == DIV && p->n_type == INT) ch = "divsi3"; else if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udivdi3"; else if (p->n_op == DIV && p->n_type == ULONG) ch = "udivsi3"; else if (p->n_op == DIV && p->n_type == UNSIGNED) ch = "udivsi3"; else if (p->n_op == MOD && p->n_type == LONGLONG) ch = "moddi3"; else if (p->n_op == MOD && p->n_type == LONG) ch = "modsi3"; else if (p->n_op == MOD && p->n_type == INT) ch = "modsi3"; else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umoddi3"; else if (p->n_op == MOD && p->n_type == ULONG) ch = "umodsi3"; else if (p->n_op == MOD && p->n_type == UNSIGNED) ch = "umodsi3"; else if (p->n_op == MUL && p->n_type == LONGLONG) ch = "muldi3"; else if (p->n_op == MUL && p->n_type == LONG) ch = "mulsi3"; else if (p->n_op == MUL && p->n_type == INT) ch = "mulsi3"; else if (p->n_op == UMINUS && p->n_type == LONGLONG) ch = "negdi2"; else if (p->n_op == UMINUS && p->n_type == LONG) ch = "negsi2"; else if (p->n_op == UMINUS && p->n_type == INT) ch = "negsi2"; else ch = 0, comperr("ZE"); printf("\tbl __%s" COM "emulated operation\n", exname(ch)); } static void halfword(NODE *p) { NODE *r = getlr(p, 'R'); NODE *l = getlr(p, 'L'); int idx0 = 0, idx1 = 1; CONSZ lval; if (features(FEATURE_BIGENDIAN)) { idx0 = 1; idx1 = 0; } if (p->n_op == ASSIGN && r->n_op == OREG) { /* load */ lval = getlval(r); expand(p, 0, "\tldrb A1,"); printf("[%s," CONFMT "]\n", rnames[r->n_rval], lval+idx0); expand(p, 0, "\tldrb AL,"); printf("[%s," CONFMT "]\n", rnames[r->n_rval], lval+idx1); expand(p, 0, "\torr AL,A1,AL,asl #8\n"); } else if (p->n_op == ASSIGN && l->n_op == OREG) { /* store */ lval = getlval(l); expand(p, 0, "\tstrb AR,"); printf("[%s," CONFMT "]\n", rnames[l->n_rval], lval+idx0); expand(p, 0, "\tmov A1,AR,asr #8\n"); expand(p, 0, "\tstrb A1,"); printf("[%s," CONFMT "]\n", rnames[l->n_rval], lval+idx1); } else if (p->n_op == SCONV || p->n_op == UMUL) { /* load */ lval = getlval(l); expand(p, 0, "\tldrb A1,"); printf("[%s," CONFMT "]\n", rnames[l->n_rval], lval+idx0); expand(p, 0, "\tldrb A2,"); printf("[%s," CONFMT "]\n", rnames[l->n_rval], lval+idx1); expand(p, 0, "\torr A1,A1,A2,asl #8\n"); } else if (p->n_op == NAME || p->n_op == ICON || p->n_op == OREG) { /* load */ lval = getlval(p); expand(p, 0, "\tldrb A1,"); printf("[%s," CONFMT "]\n", rnames[p->n_rval], lval+idx0); expand(p, 0, "\tldrb A2,"); printf("[%s," CONFMT "]\n", rnames[p->n_rval], lval+idx1); expand(p, 0, "\torr A1,A1,A2,asl #8\n"); } else { comperr("halfword"); } } static void bfext(NODE *p) { int sz; if (ISUNSIGNED(p->n_right->n_type)) return; sz = 32 - UPKFSZ(p->n_left->n_rval); expand(p, 0, "\tmov AD,AD,asl "); printf("#%d\n", sz); expand(p, 0, "\tmov AD,AD,asr "); printf("#%d\n", sz); } static int argsiz(NODE *p) { TWORD t = p->n_type; if (t < LONGLONG || t == FLOAT || t > BTMASK) return 4; if (t == LONGLONG || t == ULONGLONG) return 8; if (t == DOUBLE || t == LDOUBLE) return 8; if (t == STRTY || t == UNIONTY) return attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0); comperr("argsiz"); return 0; } void zzzcode(NODE *p, int c) { int pr; switch (c) { case 'B': /* bit-field sign extension */ bfext(p); break; case 'C': /* remove from stack after subroutine call */ pr = p->n_qual; #if 0 if (p->n_op == STCALL || p->n_op == USTCALL) pr += 4; #endif if (p->n_op == UCALL) return; /* XXX remove ZC from UCALL */ if (pr > 0) printf("\tadd %s,%s,#%d\n", rnames[SP], rnames[SP], pr); break; case 'D': /* Long long comparision */ twollcomp(p); break; case 'E': /* print out emulated ops */ emul(p); break; case 'F': /* print out emulated floating-point ops */ fpemul(p); break; case 'H': /* do halfword access */ halfword(p); break; case 'I': /* init constant */ if (p->n_name[0] != '\0') comperr("named init"); load_constant_into_reg(DECRA(p->n_reg, 1), getlval(p) & 0xffffffff); break; case 'J': /* init longlong constant */ load_constant_into_reg(DECRA(p->n_reg, 1) - R0R1, getlval(p) & 0xffffffff); load_constant_into_reg(DECRA(p->n_reg, 1) - R0R1 + 1, (getlval(p) >> 32)); break; case 'O': /* 64-bit left and right shift operators */ shiftop(p); break; case 'Q': /* emit struct assign */ stasg(p); break; default: comperr("zzzcode %c", c); } } /*ARGSUSED*/ int rewfld(NODE *p) { return(1); } /* * Does the bitfield shape match? */ int flshape(NODE *p) { int o = p->n_op; if (o == OREG || o == REG || o == NAME) return SRDIR; /* Direct match */ if (o == UMUL && shumul(p->n_left, SOREG)) return SROREG; /* Convert into oreg */ return SRREG; /* put it into a register */ } /* INTEMP shapes must not contain any temporary registers */ /* XXX should this go away now? */ int shtemp(NODE *p) { return 0; #if 0 int r; if (p->n_op == STARG ) p = p->n_left; switch (p->n_op) { case REG: return (!istreg(p->n_rval)); case OREG: r = p->n_rval; if (R2TEST(r)) { if (istreg(R2UPK1(r))) return(0); r = R2UPK2(r); } return (!istreg(r)); case UMUL: p = p->n_left; return (p->n_op != UMUL && shtemp(p)); } if (optype(p->n_op) != LTYPE) return(0); return(1); #endif } void adrcon(CONSZ val) { printf(CONFMT, val); } void conput(FILE *fp, NODE *p) { char *s; int val = getlval(p); switch (p->n_op) { case ICON: #if 0 if (p->n_sp) printf(" [class=%d,level=%d] ", p->n_sp->sclass, p->n_sp->slevel); #endif #ifdef notdef /* ICON cannot ever use sp here */ /* If it does, it's a giant bug */ if (p->n_sp == NULL || ( (p->n_sp->sclass == STATIC && p->n_sp->slevel > 0))) s = p->n_name; else s = exname(p->n_name); #else s = p->n_name; #endif if (*s != '\0') { fprintf(fp, "%s", s); if (val > 0) fprintf(fp, "+%d", val); else if (val < 0) fprintf(fp, "-%d", -val); } else fprintf(fp, CONFMT, (CONSZ)val); return; default: comperr("illegal conput, p %p", p); } } /*ARGSUSED*/ void insput(NODE *p) { comperr("insput"); } /* * Write out the upper address, like the upper register of a 2-register * reference, or the next memory location. */ void upput(NODE *p, int size) { size /= SZCHAR; switch (p->n_op) { case REG: printf("%s", rnames[p->n_rval-R0R1+1]); break; case NAME: case OREG: setlval(p, getlval(p) + size); adrput(stdout, p); setlval(p, getlval(p) - size); break; case ICON: printf(CONFMT, getlval(p) >> 32); break; default: comperr("upput bad op %d size %d", p->n_op, size); } } void adrput(FILE *io, NODE *p) { int r; /* output an address, with offsets, from p */ if (p->n_op == FLD) p = p->n_left; switch (p->n_op) { case NAME: if (p->n_name[0] != '\0') { fputs(p->n_name, io); if (getlval(p) != 0) fprintf(io, "+%lld", getlval(p)); } else fprintf(io, CONFMT, getlval(p)); return; case OREG: r = p->n_rval; if (R2TEST(r)) fprintf(io, "[%s, %s, lsl #%d]", rnames[R2UPK1(r)], rnames[R2UPK2(r)], R2UPK3(r)); else fprintf(io, "[%s,#%d]", rnames[p->n_rval], (int)getlval(p)); return; case ICON: /* addressable value of the constant */ conput(io, p); return; case REG: switch (p->n_type) { case DOUBLE: case LDOUBLE: if (features(FEATURE_HARDFLOAT)) { fprintf(io, "%s", rnames[p->n_rval]); break; } /* FALLTHROUGH */ case LONGLONG: case ULONGLONG: fprintf(io, "%s", rnames[p->n_rval-R0R1]); break; default: fprintf(io, "%s", rnames[p->n_rval]); } return; default: comperr("illegal address, op %d, node %p", p->n_op, p); return; } } /* printf conditional and unconditional branches */ void cbgen(int o, int lab) { if (o < EQ || o > UGT) comperr("bad conditional branch: %s", opst[o]); printf("\t%s " LABFMT COM "conditional branch\n", ccbranches[o-EQ], lab); } /* * The arm can only address 4k to get a NAME, so there must be some * rewriting here. Strategy: * For first 1000 nodes found, print out the word directly. * For the following 1000 nodes, group them together in asm statements * and create a jump over. * For the last <1000 statements, print out the words last. */ struct addrsymb { SLIST_ENTRY(addrsymb) link; char *name; /* symbol name */ int num; /* symbol offset */ char *str; /* replace label */ }; SLIST_HEAD(, addrsymb) aslist; static struct interpass *ipbase; static int prtnumber, nodcnt, notfirst; #define PRTLAB ".LY%d" /* special for here */ static struct interpass * anode(char *p) { extern int thisline; struct interpass *ip = tmpalloc(sizeof(struct interpass)); ip->ip_asm = p; ip->type = IP_ASM; ip->lineno = thisline; return ip; } static void flshlab(void) { struct interpass *ip; struct addrsymb *el; int lab = prtnumber++; char *c; if (SLIST_FIRST(&aslist) == NULL) return; snprintf(c = tmpalloc(32), 32, "\tb " PRTLAB "\n", lab); ip = anode(c); DLIST_INSERT_BEFORE(ipbase, ip, qelem); SLIST_FOREACH(el, &aslist, link) { /* insert each node as asm */ int l = 32+strlen(el->name); c = tmpalloc(l); if (el->num) snprintf(c, l, "%s:\n\t.word %s+%d\n", el->str, el->name, el->num); else snprintf(c, l, "%s:\n\t.word %s\n", el->str, el->name); ip = anode(c); DLIST_INSERT_BEFORE(ipbase, ip, qelem); } /* generate asm label */ snprintf(c = tmpalloc(32), 32, PRTLAB ":\n", lab); ip = anode(c); DLIST_INSERT_BEFORE(ipbase, ip, qelem); } static void prtaddr(NODE *p, void *arg) { NODE *l = p->n_left; struct addrsymb *el; int found = 0; int lab; nodcnt++; if (p->n_op == ASSIGN && p->n_right->n_op == ICON && p->n_right->n_name[0] != '\0') { /* named constant */ p = p->n_right; /* Restore addrof */ l = mklnode(NAME, getlval(p), 0, 0); l->n_name = p->n_name; p->n_left = l; p->n_op = ADDROF; } if (p->n_op != ADDROF || l->n_op != NAME) return; /* if we passed 1k nodes printout list */ if (nodcnt > 1000) { if (notfirst) flshlab(); SLIST_INIT(&aslist); notfirst = 1; nodcnt = 0; } /* write address to byte stream */ SLIST_FOREACH(el, &aslist, link) { if (el->num == getlval(l) && el->name[0] == l->n_name[0] && strcmp(el->name, l->n_name) == 0) { found = 1; break; } } if (!found) { /* we know that this is text segment */ lab = prtnumber++; if (nodcnt <= 1000 && notfirst == 0) { if (getlval(l)) printf(PRTLAB ":\n\t.word %s+%lld\n", lab, l->n_name, getlval(l)); else printf(PRTLAB ":\n\t.word %s\n", lab, l->n_name); } el = tmpalloc(sizeof(struct addrsymb)); el->num = getlval(l); el->name = l->n_name; el->str = tmpalloc(32); snprintf(el->str, 32, PRTLAB, lab); SLIST_INSERT_LAST(&aslist, el, link); } nfree(l); p->n_op = NAME; setlval(p, 0); p->n_name = el->str; } void myreader(struct interpass *ipole) { struct interpass *ip; SLIST_INIT(&aslist); notfirst = nodcnt = 0; DLIST_FOREACH(ip, ipole, qelem) { switch (ip->type) { case IP_NODE: lineno = ip->lineno; ipbase = ip; walkf(ip->ip_node, prtaddr, 0); break; case IP_EPILOG: ipbase = ip; if (notfirst) flshlab(); break; default: break; } } if (x2debug) printip(ipole); } /* * Remove some PCONVs after OREGs are created. */ static void pconv2(NODE *p, void *arg) { NODE *q; if (p->n_op == PLUS) { if (p->n_type == (PTR+SHORT) || p->n_type == (PTR+USHORT)) { if (p->n_right->n_op != ICON) return; if (p->n_left->n_op != PCONV) return; if (p->n_left->n_left->n_op != OREG) return; q = p->n_left->n_left; nfree(p->n_left); p->n_left = q; /* * This will be converted to another OREG later. */ } } } void mycanon(NODE *p) { walkf(p, pconv2, 0); } void myoptim(struct interpass *ipp) { } /* * Register move: move contents of register 's' to register 'r'. */ void rmove(int s, int d, TWORD t) { switch (t) { case DOUBLE: case LDOUBLE: if (features(FEATURE_HARDFLOAT)) { printf("\tfmr %s,%s" COM "rmove\n", rnames[d], rnames[s]); break; } /* FALLTHROUGH */ case LONGLONG: case ULONGLONG: #define LONGREG(x, y) rnames[(x)-(R0R1-(y))] if (s == d+1) { /* dh = sl, copy low word first */ printf("\tmov %s,%s" COM "rmove\n", LONGREG(d,0), LONGREG(s,0)); printf("\tmov %s,%s\n", LONGREG(d,1), LONGREG(s,1)); } else { /* copy high word first */ printf("\tmov %s,%s" COM "rmove\n", LONGREG(d,1), LONGREG(s,1)); printf("\tmov %s,%s\n", LONGREG(d,0), LONGREG(s,0)); } #undef LONGREG break; case FLOAT: if (features(FEATURE_HARDFLOAT)) { printf("\tmr %s,%s" COM "rmove\n", rnames[d], rnames[s]); break; } /* FALLTHROUGH */ default: printf("\tmov %s,%s" COM "rmove\n", rnames[d], rnames[s]); } } /* * Can we assign a register from class 'c', given the set * of number of assigned registers in each class 'r'. * * On ARM, we have: * 11 CLASSA registers (32-bit hard registers) * 10 CLASSB registers (64-bit composite registers) * 8 or 32 CLASSC registers (floating-point) * * There is a problem calculating the available composite registers * (ie CLASSB). The algorithm below assumes that given any two * registers, we can make a composite register. But this isn't true * here (or with other targets), since the number of combinations * of register pairs could become very large. Additionally, * having so many combinations really isn't so practical, since * most register pairs cannot be used to pass function arguments. * Consequently, when there is pressure composite registers, * "beenhere" compilation failures are common. * * [We need to know which registers are allocated, not simply * the number in each class] */ int COLORMAP(int c, int *r) { int num = 0; /* number of registers used */ #if 0 static const char classes[] = { 'X', 'A', 'B', 'C', 'D' }; printf("COLORMAP: requested class %c\n", classes[c]); printf("COLORMAP: class A: %d\n", r[CLASSA]); printf("COLORMAP: class B: %d\n", r[CLASSB]); #endif switch (c) { case CLASSA: num += r[CLASSA]; num += 2*r[CLASSB]; return num < 11; case CLASSB: num += 2*r[CLASSB]; num += r[CLASSA]; return num < 6; /* XXX see comments above */ case CLASSC: num += r[CLASSC]; if (features(FEATURE_FPA)) return num < 8; else if (features(FEATURE_VFP)) return num < 8; else cerror("colormap 1"); } cerror("colormap 2"); return 0; /* XXX gcc */ } /* * Return a class suitable for a specific type. */ int gclass(TWORD t) { if (t == DOUBLE || t == LDOUBLE) { if (features(FEATURE_HARDFLOAT)) return CLASSC; else return CLASSB; } if (t == FLOAT) { if (features(FEATURE_HARDFLOAT)) return CLASSC; else return CLASSA; } if (DEUNSIGN(t) == LONGLONG) return CLASSB; return CLASSA; } int retreg(int t) { int c = gclass(t); if (c == CLASSB) return R0R1; else if (c == CLASSC) return F0; return R0; } /* * Calculate argument sizes. */ void lastcall(NODE *p) { NODE *op = p; int size = 0; p->n_qual = 0; if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) return; for (p = p->n_right; p->n_op == CM; p = p->n_left) size += argsiz(p->n_right); size += argsiz(p); op->n_qual = size - 16; /* XXX */ } /* * Special shapes. */ int special(NODE *p, int shape) { return SRNOPE; } /* * default to ARMv2 */ #ifdef TARGET_BIG_ENDIAN #define DEFAULT_FEATURES FEATURE_BIGENDIAN | FEATURE_MUL #else #define DEFAULT_FEATURES FEATURE_MUL #endif static int fset = DEFAULT_FEATURES; /* * Target-dependent command-line options. */ void mflags(char *str) { if (strcasecmp(str, "little-endian") == 0) { fset &= ~FEATURE_BIGENDIAN; } else if (strcasecmp(str, "big-endian") == 0) { fset |= FEATURE_BIGENDIAN; } else if (strcasecmp(str, "fpe=fpa") == 0) { fset &= ~(FEATURE_VFP | FEATURE_FPA); fset |= FEATURE_FPA; } else if (strcasecmp(str, "fpe=vfp") == 0) { fset &= ~(FEATURE_VFP | FEATURE_FPA); fset |= FEATURE_VFP; } else if (strcasecmp(str, "fpe=vfpv3-d16") == 0) { fset &= ~(FEATURE_VFP | FEATURE_FPA); fset |= FEATURE_VFP; } else if (strcasecmp(str, "soft-float") == 0) { fset &= ~(FEATURE_VFP | FEATURE_FPA); } else if (strcasecmp(str, "arch=armv1") == 0) { fset &= ~FEATURE_HALFWORDS; fset &= ~FEATURE_EXTEND; fset &= ~FEATURE_MUL; fset &= ~FEATURE_MULL; fset &= ~FEATURE_DIV; } else if (strcasecmp(str, "arch=armv2") == 0) { fset &= ~FEATURE_HALFWORDS; fset &= ~FEATURE_EXTEND; fset |= FEATURE_MUL; fset &= ~FEATURE_MULL; fset &= ~FEATURE_DIV; } else if (strcasecmp(str, "arch=armv2a") == 0) { fset &= ~FEATURE_HALFWORDS; fset &= ~FEATURE_EXTEND; fset |= FEATURE_MUL; fset &= ~FEATURE_MULL; fset &= ~FEATURE_DIV; } else if (strcasecmp(str, "arch=armv3") == 0) { fset &= ~FEATURE_HALFWORDS; fset &= ~FEATURE_EXTEND; fset |= FEATURE_MUL; fset &= ~FEATURE_MULL; fset &= ~FEATURE_DIV; } else if (strcasecmp(str, "arch=armv4") == 0) { fset |= FEATURE_HALFWORDS; fset &= ~FEATURE_EXTEND; fset |= FEATURE_MUL; fset |= FEATURE_MULL; fset &= ~FEATURE_DIV; } else if (strcasecmp(str, "arch=armv4t") == 0) { fset |= FEATURE_HALFWORDS; fset &= ~FEATURE_EXTEND; fset |= FEATURE_MUL; fset |= FEATURE_MULL; fset &= ~FEATURE_DIV; } else if (strcasecmp(str, "arch=armv4tej") == 0) { fset |= FEATURE_HALFWORDS; fset &= ~FEATURE_EXTEND; fset |= FEATURE_MUL; fset |= FEATURE_MULL; fset &= ~FEATURE_DIV; } else if (strcasecmp(str, "arch=armv5") == 0) { fset |= FEATURE_HALFWORDS; fset &= ~FEATURE_EXTEND; fset |= FEATURE_MUL; fset |= FEATURE_MULL; fset &= ~FEATURE_DIV; } else if (strcasecmp(str, "arch=armv5te") == 0) { fset |= FEATURE_HALFWORDS; fset &= ~FEATURE_EXTEND; fset |= FEATURE_MUL; fset |= FEATURE_MULL; fset &= ~FEATURE_DIV; } else if (strcasecmp(str, "arch=armv5tej") == 0) { fset |= FEATURE_HALFWORDS; fset &= ~FEATURE_EXTEND; fset |= FEATURE_MUL; fset |= FEATURE_MULL; fset &= ~FEATURE_DIV; } else if (strcasecmp(str, "arch=armv6") == 0) { fset |= FEATURE_HALFWORDS; fset |= FEATURE_EXTEND; fset |= FEATURE_MUL; fset |= FEATURE_MULL; fset &= ~FEATURE_DIV; } else if (strcasecmp(str, "arch=armv6t2") == 0) { fset |= FEATURE_HALFWORDS; fset |= FEATURE_EXTEND; fset |= FEATURE_MUL; fset |= FEATURE_MULL; fset &= ~FEATURE_DIV; } else if (strcasecmp(str, "arch=armv6kz") == 0) { fset |= FEATURE_HALFWORDS; fset |= FEATURE_EXTEND; fset |= FEATURE_MUL; fset |= FEATURE_MULL; fset &= ~FEATURE_DIV; } else if (strcasecmp(str, "arch=armv6k") == 0) { fset |= FEATURE_HALFWORDS; fset |= FEATURE_EXTEND; fset |= FEATURE_MUL; fset |= FEATURE_MULL; fset &= ~FEATURE_DIV; } else if (strcasecmp(str, "arch=armv7") == 0) { fset |= FEATURE_HALFWORDS; fset |= FEATURE_EXTEND; fset |= FEATURE_MUL; fset |= FEATURE_MULL; fset |= FEATURE_DIV; } else if (strcasecmp(str, "arch=armv7-m") == 0 || strcasecmp(str, "arch=armv7e-m") == 0) { fset |= FEATURE_HALFWORDS; fset |= FEATURE_EXTEND; fset |= FEATURE_MUL; fset |= FEATURE_MULL; fset |= FEATURE_DIV; } else if (strcasecmp(str, "arch=armv7-a") == 0) { fset |= FEATURE_HALFWORDS; fset |= FEATURE_EXTEND; fset |= FEATURE_MUL; fset |= FEATURE_MULL; fset &= ~FEATURE_DIV; } else { fprintf(stderr, "unknown m option '%s'\n", str); exit(1); } } int features(int mask) { if (mask == FEATURE_HARDFLOAT) return ((fset & mask) != 0); return ((fset & mask) == mask); } /* * Define the current location as an internal label. */ void deflab(int label) { printf(LABFMT ":\n", label); } /* * Do something target-dependent for xasm arguments. * Supposed to find target-specific constraints and rewrite them. */ int myxasm(struct interpass *ip, NODE *p) { return 0; } pcc-20181216/arch/arm/macdefs.h010064400017500000000000000165421340073274100147440ustar raggewheel/* $Id: macdefs.h,v 1.20 2018/12/02 10:37:21 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Machine-dependent defines for both passes. */ /* * Convert (multi-)character constant to integer. */ #define makecc(val,i) lastcon = (lastcon<<8)|((val<<24)>>24); /* * Storage space requirements */ #define SZCHAR 8 #define SZBOOL 32 #define SZINT 32 #define SZFLOAT 32 #define SZDOUBLE 64 #define SZLDOUBLE 64 #define SZLONG 32 #define SZSHORT 16 #define SZLONGLONG 64 #define SZPOINT(t) 32 /* * Alignment constraints */ #define ALCHAR 8 #define ALBOOL 32 #define ALINT 32 #define ALFLOAT 32 #define ALDOUBLE 32 #define ALLDOUBLE 32 #define ALLONG 32 #define ALLONGLONG 32 #define ALSHORT 16 #define ALPOINT 32 #define ALSTRUCT 32 #define ALSTACK 32 /* * Min/max values. */ #define MIN_CHAR -128 #define MAX_CHAR 127 #define MAX_UCHAR 255 #define MIN_SHORT -32768 #define MAX_SHORT 32767 #define MAX_USHORT 65535 #define MIN_INT -1 #define MAX_INT 0x7fffffff #define MAX_UNSIGNED 0xffffffff #define MIN_LONG MIN_INT #define MAX_LONG MAX_INT #define MAX_ULONG MAX_UNSIGNED #define MIN_LONGLONG 0x8000000000000000LL #define MAX_LONGLONG 0x7fffffffffffffffLL #define MAX_ULONGLONG 0xffffffffffffffffULL #define BOOL_TYPE INT /* what used to store _Bool */ /* * Use large-enough types. */ typedef long long CONSZ; typedef unsigned long long U_CONSZ; typedef long long OFFSZ; #define CONFMT "#%lld" /* format for printing constants */ #define LABFMT ".L%d" /* format for printing labels */ #define STABLBL "LL%d" /* format for stab (debugging) labels */ #define STAB_LINE_ABSOLUTE /* S_LINE fields use absolute addresses */ #undef FIELDOPS /* no bit-field instructions */ /* Definitions mostly used in pass2 */ #define BYTEOFF(x) ((x)&03) #define wdal(k) (BYTEOFF(k)==0) #define STOARG(p) #define STOFARG(p) #define STOSTARG(p) #define szty(t) (((t) == DOUBLE || (t) == LDOUBLE || \ (t) == LONGLONG || (t) == ULONGLONG) ? 2 : 1) #define R0 0 #define R1 1 #define R2 2 #define R3 3 #define R4 4 #define R5 5 #define R6 6 #define R7 7 #define R8 8 #define R9 9 #define R10 10 #define R11 11 #define R12 12 #define R13 13 #define R14 14 #define R15 15 #define SL R10 #define FP R11 #define IP R12 #define SP R13 #define LR R14 #define PC R15 #define R0R1 16 #define R1R2 17 #define R2R3 18 #define R3R4 19 #define R4R5 20 #define R5R6 21 #define R6R7 22 #define R7R8 23 #define R8R9 24 #define R9R10 25 #define F0 26 #define F1 27 #define F2 28 #define F3 29 #define F4 30 #define F5 31 #define F6 32 #define F7 33 #define NUMCLASS 3 #define MAXREGS 34 #define RSTATUS \ SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \ SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \ 0, 0, 0, 0, 0, \ SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, SBREG, \ SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \ SCREG, SCREG, SCREG, SCREG, \ SCREG, SCREG, SCREG, SCREG, \ #define ROVERLAP \ { R0R1, -1 }, \ { R0R1, R1R2, -1 }, \ { R1R2, R2R3, -1 }, \ { R2R3, R3R4, -1 }, \ { R3R4, R4R5, -1 }, \ { R4R5, R5R6, -1 }, \ { R5R6, R6R7, -1 }, \ { R6R7, R7R8, -1 }, \ { R7R8, R8R9, -1 }, \ { R8R9, R9R10, -1 }, \ { R9R10, -1 }, \ { -1 }, \ { -1 }, \ { -1 }, \ { -1 }, \ { -1 }, \ { R0, R1, R1R2, -1 }, \ { R1, R2, R0R1, R2R3, -1 }, \ { R2, R3, R1R2, R3R4, -1 }, \ { R3, R4, R2R3, R4R5, -1 }, \ { R4, R5, R3R4, R5R6, -1 }, \ { R5, R6, R4R5, R6R7, -1 }, \ { R6, R7, R5R6, R7R8, -1 }, \ { R7, R8, R6R7, R8R9, -1 }, \ { R8, R9, R7R8, R9R10, -1 }, \ { R9, R10, R8R9, -1 }, \ { -1, }, \ { -1, }, \ { -1, }, \ { -1, }, \ { -1, }, \ { -1, }, \ { -1, }, \ { -1, }, \ #define BACKTEMP /* stack grows negatively for temporaries */ #define BACKAUTO /* stack grows negatively for automatics */ #define ARGINIT (4*8) /* # bits above fp where arguments start */ #define AUTOINIT (12*8) /* # bits above fp where automatics start */ #undef FIELDOPS /* no bit-field instructions */ #define TARGET_ENDIAN TARGET_LE /* XXX - to die */ #define FPREG FP /* frame pointer */ /* Return a register class based on the type of the node */ #define PCLASS(p) (1 << gclass((p)->n_type)) #define GCLASS(x) (x < 16 ? CLASSA : x < 26 ? CLASSB : CLASSC) #define DECRA(x,y) (((x) >> (y*6)) & 63) /* decode encoded regs */ #define ENCRD(x) (x) /* Encode dest reg in n_reg */ #define ENCRA1(x) ((x) << 6) /* A1 */ #define ENCRA2(x) ((x) << 12) /* A2 */ #define ENCRA(x,y) ((x) << (6+y*6)) /* encode regs in int */ #define RETREG(x) retreg(x) int COLORMAP(int c, int *r); int retreg(int ty); int features(int f); #define FEATURE_BIGENDIAN 0x00010000 #define FEATURE_HALFWORDS 0x00020000 /* ldrsh/ldrh, ldrsb */ #define FEATURE_EXTEND 0x00040000 /* sxth, sxtb, uxth, uxtb */ #define FEATURE_MUL 0x00080000 #define FEATURE_MULL 0x00100000 #define FEATURE_DIV 0x00200000 #define FEATURE_FPA 0x10000000 #define FEATURE_VFP 0x20000000 #define FEATURE_HARDFLOAT (FEATURE_FPA|FEATURE_VFP) #if 0 #define TARGET_STDARGS #define TARGET_BUILTINS \ { "__builtin_stdarg_start", arm_builtin_stdarg_start }, \ { "__builtin_va_arg", arm_builtin_va_arg }, \ { "__builtin_va_end", arm_builtin_va_end }, \ { "__builtin_va_copy", arm_builtin_va_copy }, #endif #undef NODE #ifdef LANG_CXX #define NODE struct node #else #define NODE struct p1node #endif struct node; struct bitable; NODE *arm_builtin_stdarg_start(const struct bitable *bt, NODE *a); NODE *arm_builtin_va_arg(const struct bitable *bt, NODE *a); NODE *arm_builtin_va_end(const struct bitable *bt, NODE *a); NODE *arm_builtin_va_copy(const struct bitable *bt, NODE *a); #undef NODE #define COM "\t@ " #define NARGREGS 4 /* floating point definitions */ #define USE_IEEEFP_32 #define FLT_PREFIX IEEEFP_32 #define USE_IEEEFP_64 #define DBL_PREFIX IEEEFP_64 #define LDBL_PREFIX IEEEFP_64 pcc-20181216/arch/arm/order.c010064400017500000000000000167341267006451400144570ustar raggewheel/* $Id: order.c,v 1.10 2016/03/09 18:19:56 ragge Exp $ */ /* * Copyright (c) 2007 Gregory McGarry (g.mcgarry@ieee.org). * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Machine-dependent code-generation strategy (pass 2). */ #include #include #include "pass2.h" /* * Check size of offset in OREG. Called by oregok() to see if an * OREG can be generated. */ int notoff(TWORD ty, int r, CONSZ off, char *cp) { if (cp && cp[0]) return 1; if (DEUNSIGN(ty) == INT || ty == UCHAR) return !(off < 4096 && off > -4096); else return !(off < 256 && off > -256); } /* * Generate instructions for an OREG. Why is this routine MD? * Called by swmatch(). */ void offstar(NODE *p, int shape) { NODE *r; if (isreg(p)) return; /* Is already OREG */ r = p->n_right; if( p->n_op == PLUS || p->n_op == MINUS ){ if( r->n_op == ICON ){ if (isreg(p->n_left) == 0) (void)geninsn(p->n_left, INAREG); /* Converted in ormake() */ return; } /* usually for arraying indexing: */ if (r->n_op == LS && r->n_right->n_op == ICON && getlval(r->n_right) == 2 && p->n_op == PLUS) { if (isreg(p->n_left) == 0) (void)geninsn(p->n_left, INAREG); if (isreg(r->n_left) == 0) (void)geninsn(r->n_left, INAREG); return; } } (void)geninsn(p, INAREG); } /* * Unable to convert to OREG (notoff() returned failure). Output * suitable instructions to replace OREG. */ void myormake(NODE *q) { NODE *p, *r; if (x2debug) printf("myormake(%p)\n", q); p = q->n_left; /* * This handles failed OREGs conversions, due to the offset * being too large for an OREG. */ if ((p->n_op == PLUS || p->n_op == MINUS) && p->n_right->n_op == ICON) { if (isreg(p->n_left) == 0) (void)geninsn(p->n_left, INAREG); if (isreg(p->n_right) == 0) (void)geninsn(p->n_right, INAREG); (void)geninsn(p, INAREG); } else if (p->n_op == REG) { q->n_op = OREG; setlval(q, getlval(p)); q->n_rval = p->n_rval; tfree(p); } else if (p->n_op == PLUS && (r = p->n_right)->n_op == LS && r->n_right->n_op == ICON && getlval(r->n_right) == 2 && p->n_left->n_op == REG && r->n_left->n_op == REG) { q->n_op = OREG; setlval(q, 0); q->n_rval = R2PACK(p->n_left->n_rval, r->n_left->n_rval, getlval(r->n_right)); tfree(p); } } /* * Check to if the UMUL node can be converted into an OREG. */ int shumul(NODE *p, int shape) { /* Turns currently anything into OREG */ if (shape & SOREG) return SROREG; return SRNOPE; } /* * Rewrite operations on binary operators (like +, -, etc...). * Called as a result of a failed table lookup. * * Return nonzero to retry table search on new tree, or zero to fail. */ int setbin(NODE *p) { return 0; } /* * Rewrite assignment operations. * Called as a result of a failed table lookup. * * Return nonzero to retry table search on new tree, or zero to fail. */ int setasg(NODE *p, int cookie) { return 0; } /* * Rewrite UMUL operation. * Called as a result of a failed table lookup. * * Return nonzero to retry table search on new tree, or zero to fail. */ int setuni(NODE *p, int cookie) { return 0; } /* * Special handling of some instruction register allocation. * * Called as a result of specifying NSPECIAL in the table. */ struct rspecial * nspecial(struct optab *q) { switch (q->op) { #if !defined(ARM_HAS_FPA) && !defined(ARM_HAS_VFP) case UMINUS: case SCONV: if (q->lshape == SBREG && q->rshape == SAREG) { static struct rspecial s[] = { { NLEFT, R0R1 }, { NRES, R0 }, { 0 } }; return s; } else if (q->lshape == SAREG && q->rshape == SBREG) { static struct rspecial s[] = { { NLEFT, R0 }, { NRES, R0R1 }, { 0 } }; return s; } else if (q->lshape == SAREG && q->rshape == SAREG) { static struct rspecial s[] = { { NLEFT, R0 }, { NRES, R0 }, { 0 } }; return s; } else if (q->lshape == SBREG && q->rshape == SBREG) { static struct rspecial s[] = { { NLEFT, R0R1 }, { NRES, R0R1 }, { 0 } }; return s; } case OPLOG: if (q->lshape == SBREG) { static struct rspecial s[] = { { NLEFT, R0R1 }, { NRIGHT, R2R3 }, { NRES, R0 }, { 0 } }; return s; } else if (q->lshape == SAREG) { static struct rspecial s[] = { { NLEFT, R0 }, { NRIGHT, R1 }, { NRES, R0 }, { 0 } }; return s; } case PLUS: case MINUS: case MUL: #endif case MOD: case DIV: if (q->lshape == SBREG) { static struct rspecial s[] = { { NLEFT, R0R1 }, { NRIGHT, R2R3 }, { NRES, R0R1 }, { 0 } }; return s; } else if (q->lshape == SAREG) { static struct rspecial s[] = { { NLEFT, R0 }, { NRIGHT, R1 }, { NRES, R0 }, { 0 } }; return s; } case LS: case RS: if (q->lshape == SBREG) { static struct rspecial s[] = { { NLEFT, R0R1 }, { NRIGHT, R2 }, { NRES, R0R1 }, { 0 } }; return s; } else if (q->lshape == SAREG) { static struct rspecial s[] = { { NLEFT, R0 }, { NRIGHT, R1 }, { NRES, R0 }, { 0 } }; return s; } case STASG: { static struct rspecial s[] = { { NEVER, R0 }, { NRIGHT, R1 }, { NEVER, R2 }, { 0 } }; return s; } break; default: break; } #ifdef PCC_DEBUG comperr("nspecial entry %d [0x%x]: %s", q - table, q->op, q->cstring); #endif return 0; /* XXX gcc */ } /* * Set evaluation order of a binary node ('+','-', '*', '/', etc) if it * differs from default. */ int setorder(NODE *p) { return 0; } /* * Set registers "live" at function calls (like arguments in registers). * This is for liveness analysis of registers. */ int * livecall(NODE *p) { static int r[] = { R3, R2, R1, R0, -1 }; int num = 1; if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) return &r[4-0]; for (p = p->n_right; p->n_op == CM; p = p->n_left) num += szty(p->n_right->n_type); num += szty(p->n_right->n_type); num = (num > 4 ? 4 : num); return &r[4 - num]; } /* * Signal whether the instruction is acceptable for this target. */ int acceptable(struct optab *op) { return features(op->visit & 0xffff0000); } pcc-20181216/arch/arm/table.c010064400017500000000000001137421166004237200144240ustar raggewheel/* $Id: table.c,v 1.20 2011/11/13 22:30:18 gmcgarry Exp $ */ /*- * Copyright (c) 2007 Gregory McGarry * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * A template has five logical sections: * * 1) subtree (operator); goal to achieve (cookie) * 2) left node descendent of operator (node class; type) * 3) right node descendent of operator (node class; type) * 4) resource requirements (number of scratch registers); * subtree rewriting rule * 5) emitted instructions */ #include "pass2.h" #define TUWORD TUNSIGNED|TULONG #define TSWORD TINT|TLONG #define TWORD TUWORD|TSWORD struct optab table[] = { /* First entry must be an empty entry */ { -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", }, /* PCONVs are not necessary */ { PCONV, INAREG, SAREG, TWORD|TPOINT, SAREG, TWORD|TPOINT, 0, RLEFT, COM "pointer conversion\n", }, /* * Conversions of integral types * * For each deunsigned type, they look something like this: * * signed -> bigger signed - nothing to do * signed -> bigger unsigned - clear the top bits (of source type) * * signed -> smaller signed - sign-extend the bits (to dest type) * signed -> smaller unsigned - clear the top bits (of dest type) * unsigned -> smaller signed - sign-extend top bits (to dest type) * unsigned -> smaller unsigned - clear the top bits (of dest type) * * unsigned -> bigger - nothing to do */ { SCONV, INAREG, SAREG, TCHAR, SAREG, TSWORD|TSHORT, 0, RLEFT, COM "convert char to short/int\n", }, { SCONV, INAREG, SAREG, TCHAR, SAREG, TUWORD|TUSHORT|TUCHAR, NAREG|NASL, RESC1, " and A1,AL,#255" COM "convert char to uchar/ushort/uint\n", }, { SCONV, INAREG | FEATURE_EXTEND, SAREG, TUCHAR, SAREG, TCHAR, NAREG|NASL, RESC1, " sxtb A1,AL" COM "convert uchar to char\n", }, { SCONV, INAREG, SAREG, TUCHAR, SAREG, TCHAR, NAREG|NASL, RESC1, " mov A1,AL,asl #24" COM "convert uchar to char\n" " mov A1,A1,asr #24\n", }, { SCONV, INAREG, SAREG, TUCHAR, SAREG, TWORD|TSHORT|TUSHORT, 0, RLEFT, COM "convert uchar to (u)short/(u)int\n", }, { SCONV, INAREG, SAREG, TSHORT, SAREG, TSWORD, 0, RLEFT, COM "convert short to int\n", }, { SCONV, INAREG | FEATURE_EXTEND, SAREG, TSHORT, SAREG, TUWORD|TUSHORT, NAREG|NASL, RESC1, " uxth A1,AL" COM "convert short to uint\n", }, { SCONV, INAREG, SAREG, TSHORT, SAREG, TUWORD|TUSHORT, NAREG|NASL, RESC1, " mov A1,AL,asl #16" COM "convert short to uint\n" " mov A1,AL,lsr #16\n", }, { SCONV, INAREG | FEATURE_EXTEND, SAREG, TUSHORT, SAREG, TSHORT, NAREG|NASL, RESC1, " sxth A1,AL" COM "convert ushort to short\n", }, { SCONV, INAREG, SAREG, TUSHORT, SAREG, TSHORT, NAREG|NASL, RESC1, " mov A1,AL,asl #16" COM "convert ushort to short\n" " mov A1,A1,asr #16\n", }, { SCONV, INAREG | FEATURE_EXTEND, SAREG, TSHORT|TUSHORT, SAREG, TCHAR, NAREG|NASL, RESC1, " sxtb A1,AL" COM "convert (u)short to char\n", }, { SCONV, INAREG, SAREG, TSHORT|TUSHORT, SAREG, TCHAR, NAREG|NASL, RESC1, " mov A1,AL,asl #24" COM "convert (u)short to char\n" " mov A1,A1,asr #24\n", }, { SCONV, INAREG, SAREG, TSHORT|TUSHORT, SAREG, TCHAR, NAREG|NASL, RESC1, " sxtb A1,AL" COM "convert (u)short to char\n", }, { SCONV, INAREG, SAREG, TSHORT|TUSHORT, SAREG, TUCHAR, NAREG|NASL, RESC1, " and A1,AL,#255" COM "convert (u)short to uchar\n", }, { SCONV, INAREG, SAREG, TUSHORT, SAREG, TWORD, 0, RLEFT, COM "convert ushort to (u)int\n", }, { SCONV, INAREG | FEATURE_EXTEND, SAREG, TWORD, SAREG, TCHAR, NAREG|NASL, RESC1, " sxtb A1,AL" COM "convert (u)int to char\n", }, { SCONV, INAREG, SAREG, TWORD, SAREG, TCHAR, NAREG|NASL, RESC1, " mov A1,AL,asl #24" COM "convert (u)int to char\n" " mov A1,A1,asr #24\n", }, { SCONV, INAREG | FEATURE_EXTEND, SAREG, TWORD, SAREG, TSHORT, NAREG|NASL, RESC1, " sxth A1,AL" COM "convert (u)int to short\n", }, { SCONV, INAREG, SAREG, TWORD, SAREG, TSHORT, NAREG|NASL, RESC1, " mov A1,AL,asl #16" COM "convert (u)int to short\n" " mov A1,A1,asr #16\n", }, { SCONV, INAREG, SAREG, TWORD, SAREG, TUCHAR, NAREG|NASL, RESC1, " and A1,AL,#255" COM "convert uchar to char\n", }, { SCONV, INAREG | FEATURE_EXTEND, SAREG, TWORD, SAREG, TUSHORT, NAREG|NASL, RESC1, " uxth A1,AL" COM "convert int to ushort\n", }, { SCONV, INAREG, SAREG, TWORD, SAREG, TUSHORT, NAREG|NASL, RESC1, " mov A1,AL,asl #16" COM "convert int to ushort\n" " mov A1,AL,lsr #16\n", }, { SCONV, INAREG, SAREG, TPOINT|TWORD, SAREG, TWORD|TPOINT, 0, RLEFT, COM "convert between pointers and words\n", }, { SCONV, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, 0, RLEFT, COM "convert (u)longlong to (u)longlong\n", }, /* convert (u)char/(u)short/(u)int to longlong */ { SCONV, INBREG, SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, SBREG, TLONGLONG|TULONGLONG, NBREG|NBSL, RESC1, " mov A1,AL" COM "convert (u)char/(u)short/(u)int to (u)longlong\n" " mov U1,AL,asr #31\n", }, { SCONV, INAREG | FEATURE_EXTEND, SBREG, TLONGLONG|TULONGLONG, SAREG, TCHAR, NAREG, RESC1, " sxtb A1,AL" COM "convert (u)longlong to char\n", }, { SCONV, INAREG, SBREG, TLONGLONG|TULONGLONG, SAREG, TCHAR, NAREG, RESC1, " mov A1,AL,asl #24" COM "convert (u)longlong to char\n" " mov A1,A1,asr #24\n", }, { SCONV, INAREG | FEATURE_EXTEND, SBREG, TLONGLONG|TULONGLONG, SAREG, TSHORT, NAREG, RESC1, " sxth A1,AL" COM "convert (u)longlong to short\n", }, { SCONV, INAREG, SBREG, TLONGLONG|TULONGLONG, SAREG, TSHORT, NAREG, RESC1, " mov A1,AL,asl #16" COM "convert (u)longlong to short\n" " mov A1,A1,asr #16\n", }, { SCONV, INAREG, SBREG, TLONGLONG|TULONGLONG, SAREG, TWORD, NAREG, RESC1, " mov A1,AL" COM "convert (u)longlong to (u)int\n", }, { SCONV, INAREG, SBREG, TLONGLONG|TULONGLONG, SAREG, TUCHAR, NAREG, RESC1, " and A1,AL,#255" COM "convert (u)longlong to uchar\n", }, { SCONV, INAREG | FEATURE_EXTEND, SBREG, TLONGLONG|TULONGLONG, SAREG, TUSHORT, NAREG, RESC1, " uxth A1,AL" COM "convert (u)longlong to ushort\n", }, { SCONV, INAREG, SBREG, TLONGLONG|TULONGLONG, SAREG, TUSHORT, NAREG, RESC1, " mov A1,AL,asl #16" COM "convert (u)longlong to ushort\n" " mov A1,A1,lsr #16\n", }, /* conversions on load from memory */ /* char */ { SCONV, INAREG, SOREG, TCHAR, SAREG, TWORD, NASL|NAREG, RESC1, " ldrsb A1,AL" COM "convert char to int/long\n", }, /* uchar */ { SCONV, INAREG, SOREG, TUCHAR, SAREG, TWORD, NASL|NAREG, RESC1, " ldrb A1,AL" COM "convert uchar to int/long\n", }, /* short */ { SCONV, INAREG | FEATURE_HALFWORDS, SOREG, TSHORT, SAREG, TWORD, NASL|NAREG, RESC1, " ldrsh A1,AL" COM "convert short to int/long\n", }, /* ushort */ { SCONV, INAREG | FEATURE_HALFWORDS, SOREG, TSHORT, SAREG, TWORD, NASL|NAREG, RESC1, " ldrh A1,AL" COM "convert ushort to int/long\n", }, /* short */ { SCONV, INAREG, SOREG, TSHORT|TUSHORT, SAREG, TWORD, 2*NAREG|NASL, RESC1, "ZH", }, { SCONV, INAREG | FEATURE_FPA, SCREG, TFLOAT, SAREG, TWORD, NAREG, RESC1, " fix AL,AR" COM "convert float to int\n", }, { SCONV, INAREG | FEATURE_VFP, SCREG, TFLOAT, SAREG, TSWORD, NAREG, RESC1, " ftosis AL,AR" COM "convert float to int\n", }, { SCONV, INAREG | FEATURE_VFP, SCREG, TFLOAT, SAREG, TSWORD, NAREG, RESC1, " ftouis AL,AR" COM "convert float to int\n", }, { SCONV, INAREG, SAREG, TFLOAT, SAREG, TWORD, NSPECIAL|NAREG, RESC1, "ZF", }, { SCONV, INBREG | FEATURE_FPA, SCREG, TFLOAT, SBREG, TULONGLONG|TLONGLONG, NBREG, RESC1, COM "unimplemented\n", }, { SCONV, INBREG | FEATURE_VFP, SCREG, TFLOAT, SBREG, TULONGLONG|TLONGLONG, NBREG, RESC1, COM "unimplemented\n", }, { SCONV, INBREG, SAREG, TFLOAT, SBREG, TULONGLONG|TLONGLONG, NSPECIAL|NBREG, RESC1, "ZF", }, { SCONV, INAREG | FEATURE_FPA, SCREG, TDOUBLE|TLDOUBLE, SAREG, TWORD, NAREG, RESC1, " fix AL,AR" COM "convert double/ldouble to int\n", }, { SCONV, INAREG | FEATURE_VFP, SCREG, TDOUBLE|TLDOUBLE, SAREG, TSWORD, NAREG, RESC1, " ftosid AL,AR" COM "convert double/ldouble to int\n", }, { SCONV, INAREG | FEATURE_VFP, SCREG, TDOUBLE|TLDOUBLE, SAREG, TUWORD, NAREG, RESC1, " ftouid AL,AR" COM "convert double/ldouble to int\n", }, { SCONV, INAREG, SBREG, TDOUBLE|TLDOUBLE, SAREG, TWORD, NSPECIAL|NAREG, RESC1, "ZF", }, { SCONV, INBREG | FEATURE_FPA, SCREG, TDOUBLE|TLDOUBLE, SBREG, TLONGLONG|TULONGLONG, NBREG, RESC1, COM "unimplemented\n", }, { SCONV, INBREG | FEATURE_VFP, SCREG, TDOUBLE|TLDOUBLE, SBREG, TULONGLONG|TLONGLONG, NBREG, RESC1, COM "unimplemented\n", }, { SCONV, INBREG, SBREG, TDOUBLE|TLDOUBLE, SBREG, TULONGLONG|TLONGLONG, NSPECIAL|NBREG, RESC1, "ZF", }, { SCONV, INCREG | FEATURE_FPA, SAREG, TWORD, SCREG, TFLOAT, NCREG, RESC1, " flts AL,AR" COM "convert int to float\n" }, { SCONV, INCREG | FEATURE_VFP, SAREG, TSWORD, SCREG, TFLOAT, NCREG, RESC1, " fsitos AL,AR" COM "convert int to float\n" }, { SCONV, INCREG | FEATURE_VFP, SAREG, TUWORD, SCREG, TFLOAT, NCREG, RESC1, " fuitos AL,AR" COM "convert int to float\n" }, { SCONV, INAREG, SAREG, TWORD, SAREG, TFLOAT, NSPECIAL|NAREG, RESC1, "ZF", }, { SCONV, INCREG | FEATURE_FPA, SBREG, TULONGLONG|TLONGLONG, SCREG, TFLOAT, NCREG, RESC1, COM "unimplemented\n", }, { SCONV, INCREG | FEATURE_VFP, SBREG, TULONGLONG|TLONGLONG, SCREG, TFLOAT, NCREG, RESC1, COM "unimplemented\n", }, { SCONV, INAREG, SBREG, TULONGLONG|TLONGLONG, SAREG, TFLOAT, NAREG, RESC1, COM "unimplemented\n", }, { SCONV, INCREG | FEATURE_FPA, SAREG, TWORD, SCREG, TDOUBLE, NCREG, RESC1, " fltd AL,AR" COM "convert int to double\n" }, { SCONV, INCREG | FEATURE_VFP, SAREG, TSWORD, SCREG, TDOUBLE, NCREG, RESC1, " fsitod AL,AR" COM "convert int to double\n" }, { SCONV, INCREG | FEATURE_VFP, SAREG, TUWORD, SCREG, TDOUBLE, NCREG, RESC1, " fuitod AL,AR" COM "convert int to double\n" }, { SCONV, INBREG, SAREG, TWORD, SBREG, TDOUBLE, NSPECIAL|NBREG, RESC1, "ZF", }, { SCONV, INCREG | FEATURE_FPA, SBREG, TLONGLONG|TULONGLONG, SCREG, TDOUBLE, NCREG, RESC1, COM "unimplemented\n", }, { SCONV, INCREG | FEATURE_VFP, SBREG, TLONGLONG|TULONGLONG, SCREG, TDOUBLE, NCREG, RESC1, COM "unimplemented\n", }, { SCONV, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TDOUBLE, NSPECIAL|NBREG, RESC1, "ZF", }, { SCONV, INCREG | FEATURE_FPA, SAREG, TWORD, SCREG, TLDOUBLE, NCREG, RESC1, " flte AL,AR" COM "convert int to ldouble\n" }, { SCONV, INCREG | FEATURE_VFP, SAREG, TSWORD, SCREG, TLDOUBLE, NCREG, RESC1, " fsitod AL,AR" COM "convert int to ldouble\n" }, { SCONV, INCREG | FEATURE_VFP, SAREG, TUWORD, SCREG, TLDOUBLE, NCREG, RESC1, " fuitod AL,AR" COM "convert uint to ldouble\n" }, { SCONV, INBREG, SAREG, TWORD, SBREG, TLDOUBLE, NSPECIAL|NBREG, RESC1, "ZF", }, { SCONV, INCREG | FEATURE_FPA, SBREG, TLONGLONG|TULONGLONG, SCREG, TLDOUBLE, NCREG, RESC1, COM "unimplemented\n", }, { SCONV, INCREG | FEATURE_VFP, SBREG, TLONGLONG|TULONGLONG, SCREG, TLDOUBLE, NCREG, RESC1, COM "unimplemented\n", }, { SCONV, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLDOUBLE, NSPECIAL|NBREG, RESC1, "ZF", }, { SCONV, INCREG | FEATURE_FPA, SCREG, TDOUBLE|TLDOUBLE, SCREG, TFLOAT, NCREG, RESC1, COM "unimplemented\n", }, { SCONV, INCREG | FEATURE_VFP, SCREG, TDOUBLE|TLDOUBLE, SCREG, TFLOAT, NCREG, RESC1, " fcvtds AL,AR" COM "convert float to double\n" }, { SCONV, INAREG, SBREG, TDOUBLE|TLDOUBLE, SAREG, TFLOAT, NSPECIAL|NAREG, RESC1, "ZF", }, { SCONV, INCREG | FEATURE_FPA, SCREG, TFLOAT, SCREG, TDOUBLE|TLDOUBLE, NCREG, RESC1, COM "unimplemented\n", }, { SCONV, INCREG | FEATURE_VFP, SCREG, TFLOAT, SCREG, TDOUBLE|TLDOUBLE, NCREG, RESC1, " fcvtsd AL,AR" COM "convert float to double\n" }, { SCONV, INBREG, SAREG, TFLOAT, SBREG, TDOUBLE|TLDOUBLE, NSPECIAL|NBREG, RESC1, "ZF", }, { SCONV, INCREG | FEATURE_FPA, SCREG, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, 0, RLEFT, COM "convert (l)double to (l)double", }, { SCONV, INCREG | FEATURE_VFP, SCREG, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, 0, RLEFT, COM "convert (l)double to (l)double", }, { SCONV, INBREG, SBREG, TDOUBLE|TLDOUBLE, SBREG, TDOUBLE|TLDOUBLE, 0, RLEFT, COM "convert (l)double to (l)double", }, /* * Subroutine calls. */ { CALL, FOREFF, SCON|SNAME, TANY, SANY, TANY, 0, 0, " bl CL" COM "call (args, no result) to scon/sname (CL)\n" "ZC", }, { UCALL, FOREFF, SCON|SNAME, TANY, SANY, TANY, 0, 0, " bl CL" COM "call (no args, no result) to scon/sname (CL)\n", }, { CALL, INAREG, SCON|SNAME, TANY, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, /* should be 0 */ " bl CL" COM "call (args, result in r0) to scon/sname (CL)\n" "ZC", }, { CALL, INBREG, SCON|SNAME, TANY, SBREG, TLONGLONG|TULONGLONG, NBREG|NBSL, RESC1, /* should be 0 */ " bl CL" COM "call (args, result in r0:r1) to scon/sname (CL)\n" "ZC", }, { CALL, INCREG | FEATURE_FPA, SCON|SNAME, TANY, SCREG, TFLOAT, NCREG|NCSL, RESC1, /* should be 0 */ " bl CL" COM "call (args, result r0) to scon/sname (CL)\n" "ZC", }, { CALL, INCREG | FEATURE_FPA, SCON|SNAME, TANY, SCREG, TDOUBLE|TLDOUBLE, NCREG|NCSL, RESC1, /* should be 0 */ " bl CL" COM "call (args, result in r0:r1) to scon/sname (CL)\n" "ZC", }, { CALL, INAREG, SCON|SNAME, TANY, SAREG, TFLOAT, NAREG|NASL, RESC1, /* should be 0 */ " bl CL" COM "call (args, result r0) to scon/sname (CL)\n" "ZC", }, { CALL, INBREG, SCON|SNAME, TANY, SBREG, TDOUBLE|TLDOUBLE, NBREG|NBSL, RESC1, /* should be 0 */ " bl CL" COM "call (args, result in r0:r1) to scon/sname (CL)\n" "ZC", }, { UCALL, INAREG, SCON|SNAME, TANY, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, /* should be 0 */ " bl CL" COM "call (no args, result in r0) to scon/sname (CL)\n", }, { UCALL, INBREG, SCON|SNAME, TANY, SBREG, TLONGLONG|TULONGLONG, NBREG|NBSL, RESC1, /* should be 0 */ " bl CL" COM "call (no args, result in r0:r1) to scon/sname (CL)\n", }, { UCALL, INCREG | FEATURE_FPA, SCON|SNAME, TANY, SCREG, TFLOAT, NCREG|NCSL, RESC1, /* should be 0 */ " bl CL" COM "call (no args, result in r0) to scon/sname (CL)\n", }, { UCALL, INCREG | FEATURE_FPA, SCON|SNAME, TANY, SCREG, TDOUBLE|TLDOUBLE, NCREG|NCSL, RESC1, /* should be 0 */ " bl CL" COM "call (no args, result in r0:r1) to scon/sname (CL)\n", }, { CALL, FOREFF, SAREG, TANY, SANY, TANY, 0, 0, " mov lr,pc\n" " mov pc,AL\n" "ZC", }, { UCALL, FOREFF, SAREG, TANY, SANY, TANY, 0, 0, " mov lr,pc\n" " mov pc,AL\n", }, { CALL, INAREG, SAREG, TANY, SANY, TANY, NAREG, RESC1, " mov lr,pc\n" " mov pc,AL\n" "ZC", }, { UCALL, INAREG, SAREG, TANY, SANY, TANY, NAREG, RESC1, " mov lr,pc\n" " mov pc,AL\n", }, { CALL, INBREG, SAREG, TANY, SANY, TANY, NBREG, RESC1, " mov lr,pc\n" " mov pc,AL\n" "ZC", }, { UCALL, INBREG, SAREG, TANY, SANY, TANY, NBREG, RESC1, " mov lr,pc\n" " mov pc,AL\n", }, /* struct return */ { USTCALL, FOREFF, SCON, TANY, SANY, TANY, 0, 0, " bl CL\n", }, { USTCALL, INAREG, SCON, TANY, SANY, TANY, NAREG|NASL, RESC1, /* should be 0 */ " bl CL\n", }, { USTCALL, INAREG, SNAME|SAREG, TANY, SANY, TANY, NAREG|NASL, RESC1, /* should be 0 */ " mov lr,pc\n" " mov pc,AL\n", }, { STCALL, FOREFF, SCON, TANY, SANY, TANY, 0, 0, " bl CL\n" "ZC", }, { STCALL, INAREG, SCON, TANY, SANY, TANY, NAREG|NASL, RESC1, /* should be 0 */ " bl CL\n" "ZC", }, { STCALL, INAREG, SNAME|SAREG, TANY, SANY, TANY, NAREG|NASL, RESC1, /* should be 0 */ " mov lr,pc\n" " mov pc,AL\n" "ZC", }, /* * The next rules handle all binop-style operators. */ { PLUS, INAREG, SAREG, TWORD|TPOINT, SCCON, TANY, NAREG, RESC1, " add A1,AL,AR" COM "addition of constant\n", }, { PLUS, INBREG, SBREG, TLONGLONG|TULONGLONG, SSCON, TANY, NBREG|NBSL, RESC1, " adds A1,AL,AR" COM "64-bit addition of constant\n" " adc U1,UL,UR\n", }, { PLUS, INAREG, SAREG, TWORD|TPOINT, SAREG, TWORD|TPOINT, NAREG|NASL, RESC1, " add A1,AL,AR" COM "addition\n", }, { PLUS, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, NBREG|NBSL, RESC1, " adds A1,AL,AR" COM "64-bit addition\n" " adc U1,UL,UR\n", }, { PLUS, INCREG | FEATURE_FPA, SCREG, TFLOAT, SCREG, TFLOAT, NCREG, RESC1, " adfs A1,AL,AR" COM "float add\n", }, { PLUS, INCREG | FEATURE_VFP, SCREG, TFLOAT, SCREG, TFLOAT, NCREG, RESC1, " fadds A1,AL,AR" COM "float add\n", }, { PLUS, INAREG, SAREG, TFLOAT, SAREG, TFLOAT, NSPECIAL|NAREG, RESC1, "ZF", }, { PLUS, INCREG | FEATURE_FPA, SCREG, TDOUBLE, SCREG, TDOUBLE, NCREG, RESC1, " adfd A1,AL,AR" COM "double add\n", }, { PLUS, INCREG | FEATURE_VFP, SCREG, TDOUBLE, SCREG, TDOUBLE, NCREG, RESC1, " faddd A1,AL,AR" COM "double add\n", }, { PLUS, INBREG, SBREG, TDOUBLE, SBREG, TDOUBLE, NSPECIAL|NBREG, RESC1, "ZF", }, { PLUS, INCREG | FEATURE_FPA, SCREG, TLDOUBLE, SCREG, TLDOUBLE, NCREG, RESC1, " adfe A1,AL,AR" COM "ldouble add\n", }, { PLUS, INCREG | FEATURE_VFP, SCREG, TLDOUBLE, SCREG, TLDOUBLE, NCREG, RESC1, " faddd A1,AL,AR" COM "ldouble add\n", }, { PLUS, INBREG, SBREG, TLDOUBLE, SBREG, TLDOUBLE, NSPECIAL|NBREG, RESC1, "ZF", }, { MINUS, INAREG, SAREG, TWORD|TPOINT, SCCON, TANY, NAREG|NASL, RESC1, " sub A1,AL,AR" COM "subtraction of constant\n", }, { MINUS, INAREG, SAREG, TWORD|TPOINT, SAREG, TWORD|TPOINT, NAREG|NASL, RESC1, " sub A1,AL,AR" COM "subtraction\n", }, { MINUS, INBREG, SBREG, TLONGLONG|TULONGLONG, SCCON, TANY, NBREG|NBSL, RESC1, " subs A1,AL,AR" COM "64-bit subtraction of constant\n" " rsc U1,UL,AR\n", }, { MINUS, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, NBREG|NBSL, RESC1, " subs A1,AL,AR" COM "64-bit subtraction\n" " sbc U1,UL,AR\n", }, { MINUS, INCREG | FEATURE_FPA, SCREG, TFLOAT, SCREG, TFLOAT, NCREG, RESC1, " sufs A1,AL,AR" COM "float subtraction\n", }, { MINUS, INCREG | FEATURE_VFP, SCREG, TFLOAT, SCREG, TFLOAT, NCREG, RESC1, " fsubs A1,AL,AR" COM "float subtraction\n", }, { MINUS, INAREG, SAREG, TFLOAT, SAREG, TFLOAT, NSPECIAL|NAREG, RESC1, "ZF", }, { MINUS, INCREG | FEATURE_FPA, SCREG, TDOUBLE, SCREG, TDOUBLE, NCREG, RESC1, " sufd A1,AL,AR" COM "double subtraction\n", }, { MINUS, INCREG | FEATURE_VFP, SCREG, TDOUBLE, SCREG, TDOUBLE, NCREG, RESC1, " fsubd A1,AL,AR" COM "double subtraction\n", }, { MINUS, INBREG, SBREG, TDOUBLE, SBREG, TDOUBLE, NSPECIAL|NBREG, RESC1, "ZF", }, { MINUS, INCREG | FEATURE_FPA, SCREG, TLDOUBLE, SCREG, TLDOUBLE, NCREG, RESC1, " sufe A1,AL,AR" COM "ldouble subtraction\n", }, { MINUS, INCREG | FEATURE_VFP, SCREG, TLDOUBLE, SCREG, TLDOUBLE, NCREG, RESC1, " fsubd A1,AL,AR" COM "double subtraction\n", }, { MINUS, INBREG, SBREG, TLDOUBLE, SBREG, TLDOUBLE, NSPECIAL|NBREG, RESC1, "ZF", }, /* * The next rules handle all shift operators. */ { LS, INAREG, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TANY, NAREG|NASL, RESC1, " mov A1,AL,asl AR" COM "left shift\n", }, { LS, INAREG, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, SCCON, TANY, NAREG|NASL, RESC1, " mov A1,AL,asl AR" COM "left shift by constant\n", }, { LS, INBREG, SBREG, TLONGLONG|TULONGLONG, SCON, TANY, NBREG, RESC1, "ZO" }, { LS, INBREG, SBREG, TLONGLONG|TULONGLONG, SAREG, TANY, NSPECIAL|NBREG, RESC1, "ZE" }, { RS, INAREG, SAREG, TSWORD|TSHORT|TCHAR, SAREG, TANY, NAREG|NASL, RESC1, " mov A1,AL,asr AR" COM "right shift\n", }, { RS, INAREG, SAREG, TUWORD|TUSHORT|TUCHAR, SAREG, TANY, NAREG|NASL, RESC1, " mov A1,AL,lsr AR" COM "right shift\n", }, { RS, INAREG, SAREG, TSWORD|TSHORT|TCHAR, SCCON, TANY, NAREG|NASL, RESC1, " mov A1,AL,asr AR" COM "right shift by constant\n", }, { RS, INAREG, SAREG, TUWORD|TUSHORT|TUCHAR, SCCON, TANY, NAREG|NASL, RESC1, " mov A1,AL,lsr AR" COM "right shift by constant\n", }, { RS, INBREG, SBREG, TLONGLONG|TULONGLONG, SCON, TANY, NBREG, RESC1, "ZO" }, { RS, INBREG, SBREG, TLONGLONG|TULONGLONG, SAREG, TANY, NSPECIAL|NBREG, RESC1, "ZE" }, /* * The next rules takes care of assignments. "=". */ { ASSIGN, FOREFF|INAREG, SOREG|SNAME, TWORD|TPOINT, SAREG, TWORD|TPOINT, 0, RDEST, " str AR,AL" COM "assign word\n", }, { ASSIGN, FOREFF|INBREG, SOREG|SNAME, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, 0, RDEST, " str AR,AL" COM "assign 64-bit value\n" " str UR,UL\n", }, /* XXX don't know if this works */ { ASSIGN, FOREFF|INBREG, SAREG, TPTRTO|TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, 0, RDEST, " stmdb AL,{AR-UR}" COM "assign 64-bit value\n", }, { ASSIGN, FOREFF|INAREG, SOREG|SNAME, TCHAR|TUCHAR, SAREG, TCHAR|TUCHAR, 0, RDEST, " strb AR,AL" COM "assign (u)char\n", }, { ASSIGN, FOREFF|INAREG | FEATURE_HALFWORDS, SOREG|SNAME, TSHORT|TUSHORT, SAREG, TSHORT|TUSHORT, 0, RDEST, " strh AR,AL" COM "assign (u)short\n", }, { ASSIGN, FOREFF|INAREG, SOREG|SNAME, TSHORT|TUSHORT, SAREG, TSHORT|TUSHORT, NAREG|NASL, RDEST, "ZH", }, { ASSIGN, FOREFF|INCREG | FEATURE_FPA, SOREG|SNAME, TFLOAT, SCREG, TFLOAT, 0, RDEST, " stfs AR,AL" COM "assign float\n", }, { ASSIGN, FOREFF|INCREG | FEATURE_VFP, SOREG|SNAME, TFLOAT, SCREG, TFLOAT, 0, RDEST, COM "unimplemented\n", }, { ASSIGN, FOREFF|INAREG, SOREG|SNAME, TFLOAT, SAREG, TFLOAT, 0, RDEST, " str AR,AL" COM "assign float (soft-float)\n", }, { ASSIGN, FOREFF|INCREG | FEATURE_FPA, SOREG|SNAME, TDOUBLE, SCREG, TDOUBLE, 0, RDEST, " stfd AR,AL" COM "assign double\n", }, { ASSIGN, FOREFF|INCREG | FEATURE_VFP, SOREG|SNAME, TDOUBLE, SCREG, TDOUBLE, 0, RDEST, COM "unimplemented\n", }, { ASSIGN, FOREFF|INBREG, SOREG|SNAME, TDOUBLE, SBREG, TDOUBLE, 0, RDEST, " str AR,AL" COM "assign double (soft-float)\n" " str UR,UL\n", }, { ASSIGN, FOREFF|INCREG | FEATURE_FPA, SOREG|SNAME, TLDOUBLE, SCREG, TLDOUBLE, 0, RDEST, " stfe AR,AL" COM "assign ldouble\n", }, { ASSIGN, FOREFF|INCREG | FEATURE_VFP, SOREG|SNAME, TLDOUBLE, SCREG, TLDOUBLE, 0, RDEST, COM "not implemented", }, { ASSIGN, FOREFF|INBREG, SOREG|SNAME, TLDOUBLE, SBREG, TLDOUBLE, 0, RDEST, " str AR,AL" COM "assign ldouble (soft-float)\n" " str UR,UL\n", }, /* assign register to register */ { ASSIGN, FOREFF|INAREG, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, 0, RDEST, " mov AL,AR" COM "assign AR to AL\n", }, { ASSIGN, FOREFF|INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, 0, RDEST, " mov AL,AR" COM "assign UR:AR to UL:AL\n" " mov UL,UR\n", }, { ASSIGN, FOREFF|INCREG | FEATURE_FPA, SCREG, TFLOAT, SCREG, TFLOAT, 0, RDEST, " mvf AL,AR" COM "assign float reg to float reg\n", }, { ASSIGN, FOREFF|INCREG | FEATURE_VFP, SCREG, TFLOAT, SCREG, TFLOAT, 0, RDEST, " fcpys AL,AR" COM "assign float reg to float reg\n", }, { ASSIGN, FOREFF|INAREG, SAREG, TFLOAT, SAREG, TFLOAT, 0, RDEST, " mov AL,AR" COM "assign float reg to float reg\n", }, { ASSIGN, FOREFF|INCREG | FEATURE_FPA, SCREG, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, 0, RDEST, " mvf AL,AR" COM "assign float reg to float reg\n", }, { ASSIGN, FOREFF|INCREG | FEATURE_VFP, SCREG, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, 0, RDEST, " fcpyd AL,AR" COM "assign float reg to float reg\n", }, { ASSIGN, FOREFF|INBREG, SBREG, TDOUBLE|TLDOUBLE, SBREG, TDOUBLE|TLDOUBLE, 0, RDEST, " mov AL,AR" COM "assign (l)double reg to (l)double reg\n" " mov UL,UR\n", }, { ASSIGN, FOREFF|INAREG, SFLD, TANY, SOREG|SNAME, TANY, 3*NAREG, RDEST, " ldr A1,AR" COM "bit-field assignment\n" " ldr A2,AL\n" " ldr A3,=M\n" " mov A1,A1,asl H\n" " and A1,A1,A3\n" " bic A2,A2,A3\n" " orr A3,A2,A1\n" " str A3,AL\n" "F ldr AD,AR\n" "FZB", }, { ASSIGN, FOREFF|INAREG, SFLD, TANY, SAREG, TANY, 3*NAREG, RDEST, " ldr A2,AL" COM "bit-field assignment\n" " ldr A3,=M\n" " mov A1,AR,asl H\n" " and A1,A1,A3\n" " bic A2,A2,A3\n" " orr A3,A2,A1\n" " str A3,AL\n" "F mov AD,AR\n" "FZB", }, { STASG, INAREG|FOREFF, SOREG|SNAME, TANY, SAREG, TPTRTO|TANY, NSPECIAL, RDEST, "ZQ", }, /* * DIV/MOD/MUL */ { DIV, INAREG, SAREG, TWORD, SAREG, TWORD, NSPECIAL|NAREG|NASL, RESC1, "ZE", }, { DIV, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, NSPECIAL|NBREG|NBSL, RESC1, "ZE", }, { DIV, INCREG | FEATURE_FPA, SCREG, TFLOAT, SCREG, TFLOAT, NCREG, RESC1, " dvfs A1,AL,AL" COM "fast (float) divide\n", }, { DIV, INCREG | FEATURE_VFP, SCREG, TFLOAT, SCREG, TFLOAT, NCREG, RESC1, " fdivs A1,AL,AL" COM "fast (float) divide\n", }, { DIV, INAREG, SAREG, TFLOAT, SAREG, TFLOAT, NSPECIAL|NAREG, RESC1, "ZF", }, { DIV, INCREG | FEATURE_FPA, SCREG, TDOUBLE, SCREG, TDOUBLE, NCREG, RESC1, " dvfd A1,AL,AL" COM "double divide\n", }, { DIV, INCREG | FEATURE_VFP, SCREG, TDOUBLE, SCREG, TDOUBLE, NCREG, RESC1, " fdivd A1,AL,AL" COM "double divide\n", }, { DIV, INBREG, SBREG, TDOUBLE, SBREG, TDOUBLE, NSPECIAL|NBREG, RESC1, "ZF", }, { DIV, INCREG | FEATURE_FPA, SCREG, TLDOUBLE, SCREG, TLDOUBLE, NCREG, RESC1, " dvfe A1,AL,AR" COM "long double load\n", }, { DIV, INCREG | FEATURE_VFP, SCREG, TLDOUBLE, SCREG, TLDOUBLE, NCREG, RESC1, " fdivd A1,AL,AL" COM "double divide\n", }, { DIV, INBREG, SBREG, TLDOUBLE, SBREG, TLDOUBLE, NSPECIAL|NBREG, RESC1, "ZF", }, { MOD, INAREG, SAREG, TWORD, SAREG, TWORD, NSPECIAL|NAREG, RESC1, "ZE", }, { MOD, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, NSPECIAL|NBREG, RESC1, "ZE", }, { MUL, INAREG | FEATURE_MUL, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG, RESC1, " mul A1,AL,AR\n", }, { MUL, INAREG, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, NSPECIAL|NAREG, RESC1, "ZE", }, { MUL, INBREG | FEATURE_MULL, SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, NBREG, RESC1, " smull U1,A1,AL,AR\n", }, { MUL, INBREG | FEATURE_MUL, SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, NBREG, RESC1, " mul A1,AL,AR\n" " mov U1,A1,asr #31\n", }, { MUL, INBREG, SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, NSPECIAL|NBREG, RESC1, "ZE", }, { MUL, INBREG | FEATURE_MULL, SAREG, TSWORD|TSHORT|TCHAR, SAREG, TSWORD|TSHORT|TCHAR, NBREG, RESC1, " umull U1,A1,AL,AR\n", }, { MUL, INBREG | FEATURE_MUL, SAREG, TSWORD|TSHORT|TCHAR, SAREG, TSWORD|TSHORT|TCHAR, NBREG, RESC1, " mul A1,AL,AR\n" " mov U1,#0\n", }, { MUL, INBREG, SAREG, TSWORD|TSHORT|TCHAR, SAREG, TSWORD|TSHORT|TCHAR, NSPECIAL|NBREG, RESC1, "ZE", }, { MUL, INBREG | FEATURE_MULL, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, NBREG, RESC1, " umull U1,A1,AL,AR\n", }, { MUL, INBREG | FEATURE_MUL, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, NBREG, RESC1, " mul A1,AL,AR\n" " mov U1,A1,asr #31\n", }, { MUL, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, NSPECIAL|NBREG, RESC1, "ZE", }, { MUL, INCREG | FEATURE_FPA, SCREG, TFLOAT, SCREG, TFLOAT, NCREG, RESC1, " fmls A1,AL,AL" COM "fast (float) multiply\n", }, { MUL, INCREG | FEATURE_VFP, SCREG, TFLOAT, SCREG, TFLOAT, NCREG, RESC1, " fmuls A1,AL,AL" COM "float multiply\n", }, { MUL, INAREG, SAREG, TFLOAT, SAREG, TFLOAT, NSPECIAL|NAREG, RESC1, "ZF", }, { MUL, INCREG | FEATURE_FPA, SCREG, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, NCREG, RESC1, " mufd A1,AL,AL" COM "fast (l)double multiply\n", }, { MUL, INCREG | FEATURE_VFP, SCREG, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, NCREG, RESC1, " muld A1,AL,AL" COM "(l)double multiply\n", }, { MUL, INBREG, SBREG, TDOUBLE|TLDOUBLE, SBREG, TDOUBLE|TLDOUBLE, NSPECIAL|NBREG, RESC1, "ZF", }, /* * Indirection operators. */ { UMUL, INAREG, SANY, TANY, SOREG|SNAME, TWORD|TPOINT, NAREG, RESC1, " ldr A1,AL" COM "word load\n", }, { UMUL, INAREG, SANY, TANY, SOREG|SNAME, TCHAR, NAREG, RESC1, " ldrsb A1,AL" COM "char load\n", }, { UMUL, INAREG, SANY, TANY, SOREG|SNAME, TUCHAR, NAREG, RESC1, " ldrb A1,AL" COM "uchar load\n", }, { UMUL, INAREG | FEATURE_HALFWORDS, SANY, TANY, SOREG|SNAME, TUSHORT, NAREG, RESC1, " ldrh A1,AL" COM "short load\n", }, { UMUL, INAREG | FEATURE_HALFWORDS, SANY, TANY, SOREG|SNAME, TSHORT, NAREG, RESC1, " ldrsh A1,AL" COM "short load\n", }, { UMUL, INAREG, SANY, TANY, SOREG|SNAME, TSHORT|TUSHORT, 2*NAREG|NASL, RESC1, "ZH", }, { UMUL, INBREG, SANY, TANY, SOREG|SNAME, TLONGLONG|TULONGLONG, NBREG, RESC1, " ldr A1,AL" COM "64-bit load\n" " ldr U1,UL\n", }, { UMUL, INCREG | FEATURE_FPA, SANY, TANY, SOREG|SNAME, TFLOAT, NCREG, RESC1, " ldfs A1,AL" COM "float load\n", }, { UMUL, INCREG | FEATURE_VFP, SANY, TANY, SOREG|SNAME, TFLOAT, NCREG, RESC1, COM "not implemented\n", }, { UMUL, INAREG, SANY, TANY, SOREG|SNAME, TFLOAT, NAREG, RESC1, " ldr A1,AL" COM "float load\n", }, { UMUL, INCREG | FEATURE_FPA, SANY, TANY, SOREG|SNAME, TDOUBLE, NCREG, RESC1, " ldfd A1,AL" COM "double load\n", }, { UMUL, INCREG | FEATURE_VFP, SANY, TANY, SOREG|SNAME, TDOUBLE, NCREG, RESC1, COM "not implemented\n", }, { UMUL, INBREG, SANY, TANY, SOREG|SNAME, TDOUBLE, NBREG, RESC1, " ldr A1,AL" COM "double load\n" " ldr U1,UL\n", }, { UMUL, INCREG | FEATURE_FPA, SANY, TANY, SOREG|SNAME, TLDOUBLE, NCREG, RESC1, " ldfe A1,AL" COM "long double load\n", }, { UMUL, INCREG | FEATURE_VFP, SANY, TANY, SOREG|SNAME, TLDOUBLE, NCREG, RESC1, COM "not implemented\n", }, { UMUL, INBREG, SANY, TANY, SOREG|SNAME, TLDOUBLE, NBREG, RESC1, " ldr A1,AL" COM "long double load (soft-float)\n" " ldr U1,UL\n", }, /* * Logical/branching operators */ /* compare with register */ { OPLOG, FORCC, SAREG, TSWORD|TSHORT|TCHAR, SAREG, TSWORD|TSHORT|TCHAR, 0, RESCC, " cmp AL,AR" COM "AR-AL (sets flags)\n", }, /* compare with register */ { OPLOG, FORCC, SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, 0, RESCC, " cmp AL,AR" COM "AR-AL (sets flags)\n", }, /* compare with register */ { OPLOG, FORCC, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, 0, RESCC, "ZD", }, { OPLOG, FORCC | FEATURE_FPA, SCREG, TFLOAT, SCREG, TFLOAT, NSPECIAL, RESCC, " cmfs AL,AR" COM "float compare\n", }, { OPLOG, FORCC | FEATURE_VFP, SCREG, TFLOAT, SCREG, TFLOAT, 0, RESCC, " fcmps AL,AR" COM "float compare\n", }, { OPLOG, FORCC, SAREG, TFLOAT, SAREG, TFLOAT, NSPECIAL, RESCC, "ZF", }, { OPLOG, FORCC | FEATURE_FPA, SCREG, TDOUBLE, SCREG, TDOUBLE, NSPECIAL, RESCC, " cmfd AL,AR" COM "double compare\n", }, { OPLOG, FORCC | FEATURE_VFP, SCREG, TDOUBLE, SCREG, TDOUBLE, 0, RESCC, " fcmpd AL,AR" COM "double compare\n", }, { OPLOG, FORCC, SBREG, TDOUBLE, SBREG, TDOUBLE, NSPECIAL, RESCC, "ZF", }, { OPLOG, FORCC | FEATURE_FPA, SCREG, TLDOUBLE, SCREG, TLDOUBLE, NSPECIAL, RESCC, " cmfe AL,AR" COM "ldouble compare\n", }, { OPLOG, FORCC | FEATURE_VFP, SCREG, TLDOUBLE, SCREG, TLDOUBLE, 0, RESCC, " fcmpd AL,AR" COM "double compare\n", }, { OPLOG, FORCC, SBREG, TLDOUBLE, SBREG, TLDOUBLE, NSPECIAL, RESCC, "ZF", }, /* AND/OR/ER */ { AND, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, NBREG|NBSL, RESC1|RESCC, " and A1,AL,AR" COM "64-bit and\n" " and U1,UL,UR\n", }, { OR, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, NBREG|NBSL, RESC1, " orr A1,AL,AR" COM "64-bit or\n" " orr U1,UL,UR\n" }, { ER, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, NBREG|NBSL, RESC1, " eor A1,AL,AR" COM "64-bit xor\n" " eor U1,UL,UR\n" }, { OPSIMP, INAREG, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1|RESCC, " O A1,AL,AR\n", }, { OPSIMP, INAREG|FORCC, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, " Os A1,AL,AR\n", }, /* * Jumps. */ { GOTO, FOREFF, SCON, TANY, SANY, TANY, 0, RNOP, " b LL\n", }, #if 0 { GOTO, FOREFF, SAREG, TANY, SANY, TANY, 0, RNOP, " mov pc,AL\n", }, #endif /* * Convert LTYPE to reg. */ { OPLTYPE, INAREG, SANY, TANY, SOREG|SNAME, TWORD|TPOINT, NAREG, RESC1, " ldr A1,AL" COM "load word from memory\n", }, { OPLTYPE, INBREG, SANY, TANY, SOREG|SNAME, TLONGLONG|TULONGLONG, NBREG, RESC1, " ldr A1,AL" COM "load long long from memory\n" " ldr U1,UL\n", }, { OPLTYPE, INAREG, SANY, TANY, SOREG|SNAME, TCHAR, NAREG, RESC1, " ldrsb A1,AL" COM "load char from memory\n" }, { OPLTYPE, INAREG, SANY, TANY, SOREG|SNAME, TUCHAR, NAREG, RESC1, " ldrb A1,AL" COM "load uchar from memory\n", }, { OPLTYPE, INAREG | FEATURE_HALFWORDS, SANY, TANY, SOREG|SNAME, TSHORT, NAREG, RESC1, " ldrsh A1,AL" COM "load short from memory\n", }, { OPLTYPE, INAREG | FEATURE_HALFWORDS, SANY, TANY, SOREG|SNAME, TUSHORT, NAREG, RESC1, " ldrh A1,AL" COM "load ushort from memory\n", }, { OPLTYPE, INAREG, SANY, TANY, SOREG|SNAME, TSHORT|TUSHORT, 2*NAREG, RESC1, "ZH", }, #if 0 { OPLTYPE, INAREG, SANY, TANY, SCON, TPOINT, NAREG, RESC1, " ldr A1,AL" COM "load integer constant\n", }, #endif { OPLTYPE, INAREG, SANY, TANY, SCON, TANY, NAREG, RESC1, "ZI", }, { OPLTYPE, INBREG, SANY, TANY, SCON, TANY, NBREG, RESC1, "ZJ", }, { OPLTYPE, INAREG, SANY, TANY, SAREG, TANY, NAREG, RESC1, " mov A1,AL" COM "load AL into A1\n" }, { OPLTYPE, INBREG, SANY, TANY, SBREG, TLONGLONG|TULONGLONG, NBREG, RESC1, " mov A1,AL" COM "load UL:AL into U1:A1\n" " mov U1,UL\n", }, { OPLTYPE, INCREG | FEATURE_FPA, SANY, TANY, SOREG|SNAME, TFLOAT, NCREG, RESC1, " ldfs A1,AL" COM "load float\n", }, { OPLTYPE, INCREG | FEATURE_VFP, SANY, TANY, SOREG|SNAME, TFLOAT, NCREG, RESC1, COM "not implemented\n", }, { OPLTYPE, INAREG, SANY, TANY, SOREG|SNAME, TFLOAT, NAREG, RESC1, " ldr A1,AL" COM "load float (soft-float)\n", }, { OPLTYPE, INCREG | FEATURE_FPA, SANY, TANY, SOREG|SNAME, TDOUBLE, NCREG, RESC1, " ldfd A1,AL" COM "load double\n", }, { OPLTYPE, INCREG | FEATURE_VFP, SANY, TANY, SOREG|SNAME, TDOUBLE, NCREG, RESC1, COM "not implemented\n" }, { OPLTYPE, INBREG, SANY, TANY, SOREG|SNAME, TDOUBLE, NBREG, RESC1, " ldr A1,AL" COM "load double (soft-float)\n" " ldr U1,UL\n", }, { OPLTYPE, INCREG | FEATURE_FPA, SANY, TANY, SOREG|SNAME, TLDOUBLE, NCREG, RESC1, " ldfe A1,AL" COM "load ldouble\n", }, { OPLTYPE, INCREG | FEATURE_VFP, SANY, TANY, SOREG|SNAME, TLDOUBLE, NCREG, RESC1, COM "not implemented\n", }, { OPLTYPE, INBREG, SANY, TANY, SOREG|SNAME, TLDOUBLE, NBREG, RESC1, " ldr A1,AL" COM "load ldouble (soft-float)\n" " ldr U1,UL\n", }, /* * Negate a word. */ { UMINUS, INAREG, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, " rsb A1,AL,#0" COM "negation\n", }, { UMINUS, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, NBREG|NBSL, RESC1, " rsbs A1,AL,#0" COM "64-bit negation\n" " rsc U1,UL,#0\n", }, { UMINUS, INCREG | FEATURE_FPA, SCREG, TFLOAT, SCREG, TFLOAT, NCREG, RESC1, " mvfs A1,AL" COM "float negation\n", }, { UMINUS, INCREG | FEATURE_VFP, SCREG, TFLOAT, SCREG, TFLOAT, NCREG, RESC1, " negs A1,AL" COM "float negation\n", }, { UMINUS, INAREG, SAREG, TFLOAT, SAREG, TFLOAT, NSPECIAL|NAREG, RESC1, "ZF", }, { UMINUS, INCREG | FEATURE_FPA, SCREG, TDOUBLE, SCREG, TDOUBLE, NCREG, RESC1, " mvfd A1,AL" COM "double negation\n", }, { UMINUS, INCREG | FEATURE_VFP, SCREG, TDOUBLE, SCREG, TDOUBLE, NCREG, RESC1, " negd A1,AL" COM "double negation\n", }, { UMINUS, INBREG, SBREG, TDOUBLE, SBREG, TDOUBLE, NSPECIAL|NBREG, RESC1, "ZF", }, { UMINUS, INCREG | FEATURE_FPA, SCREG, TLDOUBLE, SCREG, TLDOUBLE, NCREG, RESC1, " mvfe A1,AL" COM "ldouble negation\n", }, { UMINUS, INCREG | FEATURE_VFP, SCREG, TLDOUBLE, SCREG, TLDOUBLE, NCREG, RESC1, " negd A1,AL" COM "ldouble negation\n", }, { UMINUS, INBREG, SBREG, TLDOUBLE, SBREG, TLDOUBLE, NSPECIAL|NBREG, RESC1, "ZF", }, { COMPL, INAREG, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, SANY, TANY, NAREG|NASL, RESC1, " mvn A1,AL" COM "complement\n", }, { COMPL, INBREG, SBREG, TLONGLONG|TULONGLONG, SANY, TANY, NBREG|NBSL, RESC1, " mvn A1,AL" COM "64-bit complement\n" " mvn U1,UL\n", }, /* * Arguments to functions. */ { FUNARG, FOREFF, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SANY, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, 0, 0, " stmfd sp!,{AL}" COM "save function arg to stack\n", }, { FUNARG, FOREFF, SBREG, TLONGLONG|TULONGLONG, SANY, TLONGLONG|TULONGLONG, 0, 0, " stmfd sp!,{AL,UL}" COM "save function arg to stack (endianness problem here?)\n", }, { FUNARG, FOREFF, SCREG, TFLOAT, SANY, TFLOAT, 0, 0, " stmfd sp!,{AL}" COM "save function arg to stack\n", }, { FUNARG, FOREFF, SCREG, TDOUBLE|TLDOUBLE, SANY, TDOUBLE|TLDOUBLE, 0, 0, " stmfd sp!,{AL,UL}" COM "save function arg to stack (endianness problem here?)\n", }, # define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,"" { UMUL, DF( UMUL ), }, { ASSIGN, DF(ASSIGN), }, { STASG, DF(STASG), }, { FLD, DF(FLD), }, { OPLEAF, DF(NAME), }, /* { INIT, DF(INIT), }, */ { OPUNARY, DF(UMINUS), }, { OPANY, DF(BITYPE), }, { FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" }, }; int tablesize = sizeof(table)/sizeof(table[0]); pcc-20181216/arch/hppa004075500017500000000000000000001340533064000132535ustar raggewheelpcc-20181216/arch/hppa/CVS004075500017500000000000000000001340533064000137065ustar raggewheelpcc-20181216/arch/hppa/CVS/Root010064400017500000000000000000111340533064000146200ustar raggewheel/cvsroot pcc-20181216/arch/hppa/CVS/Repository010064400017500000000000000000161340533064000160610ustar raggewheelpcc/arch/hppa pcc-20181216/arch/hppa/CVS/Entries010064400017500000000000000003721340533064000153200ustar raggewheel/code.c/1.28/Wed Jun 6 09:28:01 2012// /local.c/1.41/Tue Aug 18 10:15:08 2015// /local2.c/1.32/Mon Sep 26 16:45:42 2016// /macdefs.h/1.22/Sat Mar 5 15:53:04 2016// /order.c/1.10/Sun Jun 5 08:54:42 2011// /table.c/1.16/Tue Sep 18 10:57:10 2012// D pcc-20181216/arch/hppa/code.c010064400017500000000000000141541176362124100144170ustar raggewheel/* $Id: code.c,v 1.28 2012/06/06 09:28:01 ragge Exp $ */ /* $OpenBSD: code.c,v 1.2 2007/11/22 15:06:43 stefan Exp $ */ /* * Copyright (c) 2007 Michael Shalayeff * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass1.h" NODE *funarg(NODE *, int *); int argreg(TWORD, int *); static const char *const loctbl[] = { "text", "data", "section .rodata" }; /* * Define everything needed to print out some data (or text). * This means segment, alignment, visibility, etc. */ void defloc(struct symtab *sp) { extern char *nextsect; static int lastloc = -1; TWORD t; char *n; int s; if (sp == NULL) { lastloc = -1; return; } t = sp->stype; s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? RDATA : DATA; if (nextsect) { printf("\t.section %s\n", nextsect); nextsect = NULL; s = -1; } else if (s != lastloc) printf("\t.%s\n", loctbl[s]); lastloc = s; while (ISARY(t)) t = DECREF(t); s = ISFTN(t) ? ALINT : talign(t, sp->ssue); if (s > ALCHAR) printf("\t.align\t%d\n", s / ALCHAR); n = sp->soname ? sp->soname : sp->sname; if (sp->sclass == EXTDEF) printf("\t.export %s, %s\n", n, ISFTN(t)? "code" : "data"); if (sp->slevel == 0) printf("\t.type\t%s, @%s\n\t.label %s\n", n, ISFTN(t)? "function" : "object", n); else printf("\t.type\t" LABFMT ", @%s\n\t.label\t" LABFMT "\n", sp->soffset, ISFTN(t)? "function" : "object", sp->soffset); } /* * code for the end of a function * deals with struct return here */ void efcode(void) { NODE *p, *q; int sz; if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) return; /* address of return struct is in %ret0 */ /* create a call to memcpy() */ /* will get the result in %ret0 */ p = block(REG, NIL, NIL, CHAR+PTR, 0, 0); p->n_rval = RET0; q = block(OREG, NIL, NIL, CHAR+PTR, 0, 0); q->n_rval = FP; q->n_lval = 8; /* return buffer offset */ p = block(CM, q, p, INT, 0, 0); sz = (tsize(STRTY, cftnsp->sdf, cftnsp->ssue)+SZCHAR-1)/SZCHAR; p = block(CM, p, bcon(sz), INT, 0, 0); p->n_right->n_name = ""; p = block(CALL, bcon(0), p, CHAR+PTR, 0, 0); p->n_left->n_name = "memcpy"; p = clocal(p); send_passt(IP_NODE, p); } int argreg(TWORD t, int *n) { switch (t) { case FLOAT: return FR7L - 2 * (*n)++; case DOUBLE: case LDOUBLE: *n += 2; return FR6 - *n - 2; case LONGLONG: case ULONGLONG: *n += 2; return AD1 - (*n - 2) / 2; default: return ARG0 - (*n)++; } } /* * code for the beginning of a function; 'a' is an array of * indices in symtab for the arguments; n is the number */ void bfcode(struct symtab **a, int cnt) { struct symtab *sp; NODE *p, *q; int i, n, sz; if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { /* Function returns struct, adjust arg offset */ for (i = 0; i < cnt; i++) a[i]->soffset += SZPOINT(LONG); } /* recalculate the arg offset and create TEMP moves */ for (n = 0, i = 0; i < cnt; i++) { sp = a[i]; sz = szty(sp->stype); if (n % sz) n++; /* XXX LDOUBLE */ if (n < 4) { p = tempnode(0, sp->stype, sp->sdf, sp->ssue); /* TODO p->n_left->n_lval = -(32 + n * 4); */ q = block(REG, NIL, NIL, sp->stype, sp->sdf, sp->ssue); q->n_rval = argreg(sp->stype, &n); p = buildtree(ASSIGN, p, q); sp->soffset = regno(p->n_left); sp->sflags |= STNODE; ecomp(p); } else { sp->soffset += SZINT * n; if (xtemps) { /* put stack args in temps if optimizing */ p = tempnode(0, sp->stype, sp->sdf, sp->ssue); p = buildtree(ASSIGN, p, buildtree(NAME, 0, 0)); sp->soffset = regno(p->n_left); sp->sflags |= STNODE; ecomp(p); } } } } /* called just before final exit */ /* flag is 1 if errors, 0 if none */ void ejobcode(int flag) { if (flag) return; printf("\t.end\n"); } void bjobcode(void) { printf("\t.level\t1.1\n" "\t.import $global$, data\n" "\t.import $$dyncall, millicode\n"); } /* fix up type of field p */ void fldty(struct symtab *p) { } /* * XXX - fix genswitch. */ int mygenswitch(int num, TWORD type, struct swents **p, int n) { return 0; } NODE * funarg(NODE *p, int *n) { NODE *r; int sz; if (p->n_op == CM) { p->n_left = funarg(p->n_left, n); p->n_right = funarg(p->n_right, n); return p; } sz = szty(p->n_type); if (*n % sz) (*n)++; /* XXX LDOUBLE */ if (*n >= 4) { *n += sz; r = block(OREG, NIL, NIL, p->n_type|PTR, 0, 0); r->n_rval = SP; r->n_lval = -(32 + *n * 4); } else { r = block(REG, NIL, NIL, p->n_type, 0, 0); r->n_lval = 0; r->n_rval = argreg(p->n_type, n); } p = block(ASSIGN, r, p, p->n_type, 0, 0); clocal(p); return p; } /* * Called with a function call with arguments as argument. * This is done early in buildtree() and only done once. */ NODE * funcode(NODE *p) { int n = 0; p->n_right = funarg(p->n_right, &n); return p; } pcc-20181216/arch/hppa/local.c010064400017500000000000000451641256460265400146130ustar raggewheel/* $Id: local.c,v 1.41 2015/08/18 10:15:08 ragge Exp $ */ /* $OpenBSD: local.c,v 1.2 2007/11/18 17:39:55 ragge Exp $ */ /* * Copyright (c) 2007 Michael Shalayeff * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "pass1.h" #include "pass2.h" /* this file contains code which is dependent on the target machine */ #define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz)) struct symtab *makememcpy(void); /* clocal() is called to do local transformations on * an expression tree preparitory to its being * written out in intermediate code. * * the major essential job is rewriting the * automatic variables and arguments in terms of * REG and OREG nodes * conversion ops which are not necessary are also clobbered here * in addition, any special features (such as rewriting * exclusive or) are easily handled here as well */ NODE * clocal(NODE *p) { register struct symtab *q, *sp; register NODE *r, *l, *s; register int o, m, rn; char *ch, name[16], *n; TWORD t; #ifdef PCC_DEBUG if (xdebug) { printf("clocal: %p\n", p); fwalk(p, eprint, 0); } #endif switch (o = p->n_op) { case NAME: if ((q = p->n_sp) == NULL) break; /* Nothing to care about */ switch (q->sclass) { case PARAM: /* first four integral args are in regs */ rn = (q->soffset >> 5) - 8; if (rn < 4) { r = block(REG, NIL, NIL, p->n_type, 0, 0); r->n_lval = 0; switch (p->n_type) { case FLOAT: r->n_rval = FR7L - rn; break; case DOUBLE: case LDOUBLE: r->n_rval = FR6 - rn; break; case LONGLONG: case ULONGLONG: r->n_rval = AD1 - rn / 2; break; default: r->n_rval = ARG0 - rn; } r->n_sue = p->n_sue; p->n_sue = NULL; nfree(p); p = r; break; } /* FALLTHROUGH */ case AUTO: /* fake up a structure reference */ r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); r->n_lval = 0; r->n_rval = FPREG; p = stref(block(STREF, r, p, 0, 0, 0)); break; case REGISTER: p->n_op = REG; p->n_lval = 0; p->n_rval = q->soffset; break; case STATIC: case EXTERN: if (p->n_sp->sflags & SSTRING) break; n = p->n_sp->soname ? p->n_sp->soname : p->n_sp->sname; if (strncmp(n, "__builtin", 9) == 0) break; l = block(REG, NIL, NIL, INT, 0, 0); l->n_lval = 0; l->n_rval = R1; l = block(ASSIGN, l, p, INT, 0, 0); r = xbcon(0, p->n_sp, INT); p = block(UMUL, block(PLUS, l, r, INT, 0, 0), NIL, p->n_type, p->n_df, p->n_sue); break; } break; case ADDROF: l = p->n_left; if (!l->n_sp) break; if (l->n_sp->sclass != EXTERN && l->n_sp->sclass != STATIC && l->n_sp->sclass != USTATIC && l->n_sp->sclass != EXTDEF) break; l = block(REG, NIL, NIL, INT, 0, 0); l->n_lval = 0; l->n_rval = R1; l = block(ASSIGN, l, p->n_left, INT, 0, 0); r = xbcon(0, p->n_left->n_sp, INT); l = block(PLUS, l, r, p->n_type, p->n_df, p->n_sue); nfree(p); p = l; break; case CBRANCH: l = p->n_left; /* * Remove unnecessary conversion ops. */ if (clogop(l->n_op) && l->n_left->n_op == SCONV) { if (coptype(l->n_op) != BITYPE) break; if (l->n_right->n_op == ICON) { r = l->n_left->n_left; if (r->n_type >= FLOAT && r->n_type <= LDOUBLE) break; /* Type must be correct */ t = r->n_type; nfree(l->n_left); l->n_left = r; l->n_type = t; l->n_right->n_type = t; } } break; case PCONV: /* Remove redundant PCONV's. Be careful */ l = p->n_left; if (l->n_op == ICON) { l->n_lval = (unsigned)l->n_lval; goto delp; } if (l->n_type < INT || l->n_type == LONGLONG || l->n_type == ULONGLONG) { /* float etc? */ p->n_left = block(SCONV, l, NIL, UNSIGNED, 0, 0); break; } /* if left is SCONV, cannot remove */ if (l->n_op == SCONV) break; /* avoid ADDROF TEMP */ if (l->n_op == ADDROF && l->n_left->n_op == TEMP) break; /* if conversion to another pointer type, just remove */ if (p->n_type > BTMASK && l->n_type > BTMASK) goto delp; break; delp: l->n_type = p->n_type; l->n_qual = p->n_qual; l->n_df = p->n_df; l->n_sue = p->n_sue; nfree(p); p = l; break; case SCONV: l = p->n_left; if (p->n_type == l->n_type) { nfree(p); p = l; break; } if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 && btdims[p->n_type].suesize == btdims[l->n_type].suesize) { if (p->n_type != FLOAT && p->n_type != DOUBLE && l->n_type != FLOAT && l->n_type != DOUBLE && l->n_type != LDOUBLE && p->n_type != LDOUBLE) { if (l->n_op == UMUL || l->n_op == TEMP || l->n_op == NAME) { l->n_type = p->n_type; nfree(p); p = l; break; } } } if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT && coptype(l->n_op) == BITYPE) { l->n_type = p->n_type; nfree(p); p = l; break; } o = l->n_op; m = p->n_type; if (o == ICON) { CONSZ val = l->n_lval; if (!ISPTR(m)) /* Pointers don't need to be conv'd */ switch (m) { case BOOL: l->n_lval = l->n_lval != 0; break; case CHAR: l->n_lval = (char)val; break; case UCHAR: l->n_lval = val & 0377; break; case SHORT: l->n_lval = (short)val; break; case USHORT: l->n_lval = val & 0177777; break; case ULONG: case UNSIGNED: l->n_lval = val & 0xffffffff; break; case LONG: case INT: l->n_lval = (int)val; break; case LONGLONG: l->n_lval = (long long)val; break; case ULONGLONG: l->n_lval = val; break; case VOID: break; case LDOUBLE: case DOUBLE: case FLOAT: l->n_op = FCON; l->n_dcon = val; break; default: cerror("unknown type %d", m); } l->n_type = m; l->n_sue = 0; nfree(p); return l; } else if (l->n_op == FCON) { l->n_lval = l->n_dcon; l->n_sp = NULL; l->n_op = ICON; l->n_type = m; l->n_sue = 0; nfree(p); return clocal(l); } if (DEUNSIGN(p->n_type) == SHORT && DEUNSIGN(l->n_type) == SHORT) { nfree(p); p = l; } if ((p->n_type == CHAR || p->n_type == UCHAR || p->n_type == SHORT || p->n_type == USHORT) && (l->n_type == FLOAT || l->n_type == DOUBLE || l->n_type == LDOUBLE)) { p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_sue); p->n_left->n_type = INT; break; } break; case MOD: case DIV: if (o == DIV && p->n_type != CHAR && p->n_type != SHORT) break; if (o == MOD && p->n_type != CHAR && p->n_type != SHORT) break; /* make it an int division by inserting conversions */ p->n_left = block(SCONV, p->n_left, NIL, INT, 0, 0); p->n_right = block(SCONV, p->n_right, NIL, INT, 0, 0); p = block(SCONV, p, NIL, p->n_type, 0, 0); p->n_left->n_type = INT; break; case LS: case RS: /* shift count must be in an int */ if (p->n_right->n_op == ICON || p->n_right->n_lval <= 32) break; /* do not do anything */ if (p->n_right->n_type != INT || p->n_right->n_lval > 32) p->n_right = block(SCONV, p->n_right, NIL, INT, 0, 0); break; #if 0 case FLD: /* already rewritten (in ASSIGN) */ if (p->n_left->n_op == TEMP) break; r = tempnode(0, p->n_type, p->n_df, p->n_sue); l = block(ASSIGN, r, p->n_left, p->n_type, p->n_df, p->n_sue); p->n_left = tcopy(r); p = block(COMOP, l, p, p->n_type, p->n_df, p->n_sue); break; #endif case FORCE: /* put return value in return reg */ p->n_op = ASSIGN; p->n_right = p->n_left; p->n_left = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_sue); p->n_left->n_rval = p->n_left->n_type == BOOL ? RETREG(CHAR) : RETREG(p->n_type); if (p->n_right->n_op != FLD) break; break; case ASSIGN: r = p->n_right; l = p->n_left; /* rewrite ICON#0 into %r0 */ if (r->n_op == ICON && r->n_lval == 0 && (l->n_op == REG || l->n_op == OREG)) { r->n_op = REG; r->n_rval = R0; } /* rewrite FCON#0 into %fr0 */ if (r->n_op == FCON && r->n_lval == 0 && l->n_op == REG) { r->n_op = REG; r->n_rval = r->n_type == FLOAT? FR0L : FR0; } if (p->n_left->n_op != FLD) break; r = tempnode(0, l->n_type, l->n_df, l->n_sue); p = block(COMOP, block(ASSIGN, r, l->n_left, l->n_type, l->n_df, l->n_sue), p, p->n_type, p->n_df, p->n_sue); s = tcopy(l->n_left); p = block(COMOP, p, block(ASSIGN, s, tcopy(r), l->n_type, l->n_df, l->n_sue), p->n_type, p->n_df, p->n_sue); l->n_left = tcopy(r); break; case STASG: /* memcpy(left, right, size) */ sp = makememcpy(); l = p->n_left; /* guess struct return */ if (l->n_op == NAME && ISFTN(l->n_sp->stype)) { l = block(REG, NIL, NIL, VOID|PTR, 0, 0); l->n_lval = 0; l->n_rval = RET0; } else if (l->n_op == UMUL) l = tcopy(l->n_left); else if (l->n_op == NAME) l = block(ADDROF,tcopy(l),NIL,PTR|STRTY,0,0); l = block(CALL, block(ADDROF, (s = block(NAME, NIL, NIL, FTN, 0, 0)), NIL, PTR|FTN, 0, 0), block(CM, block(CM, l, tcopy(p->n_right), STRTY|PTR, 0, 0), (r = block(ICON, NIL, NIL, INT, 0, 0)), 0, 0, 0), INT, 0, 0); r->n_lval = p->n_sue->suesize/SZCHAR; s->n_sp = sp; s->n_df = s->n_sp->sdf; defid(s, EXTERN); tfree(p); p = l; p->n_left = clocal(p->n_left); p->n_right = clocal(p->n_right); calldec(p->n_left, p->n_right); funcode(p); break; case STARG: /* arg = memcpy(argN-size, src, size) */ sp = makememcpy(); l = block(CALL, block(ADDROF, (s = block(NAME, NIL, NIL, FTN, 0, 0)),NIL,0,0,0), block(CM, block(CM, tcopy(p), tcopy(p->n_left), 0, 0, 0), (r = block(ICON, NIL, NIL, INT, 0, 0)), 0, 0, 0), INT, 0, 0); r->n_lval = p->n_sue->suesize/SZCHAR; s->n_sp = sp; s->n_df = s->n_sp->sdf; defid(s, EXTERN); tfree(p); p = l; p->n_left = clocal(p->n_left); calldec(p->n_left, p->n_right); funcode(p); break; case STCALL: case CALL: for (r = p->n_right; r->n_op == CM; r = r->n_left) { if (r->n_right->n_op == ASSIGN && r->n_right->n_right->n_op == CALL) { s = r->n_right->n_right; l = tempnode(0, s->n_type, s->n_df, s->n_sue); ecode(buildtree(ASSIGN, l, s)); r->n_right->n_right = tcopy(l); } if (r->n_left->n_op == ASSIGN && r->n_left->n_right->n_op == CALL) { s = r->n_left->n_right; l = tempnode(0, s->n_type, s->n_df, s->n_sue); ecode(buildtree(ASSIGN, l, s)); r->n_left->n_right = tcopy(l); } } break; } /* second pass - rewrite long ops */ switch (o) { case DIV: case MOD: case MUL: case RS: case LS: if (!(p->n_type == LONGLONG || p->n_type == ULONGLONG) || !((o == DIV || o == MOD || o == MUL) && p->n_type < FLOAT)) break; if (o == DIV && p->n_type == ULONGLONG) ch = "udiv"; else if (o == DIV) ch = "div"; else if (o == MUL) ch = "mul"; else if (o == MOD && p->n_type == ULONGLONG) ch = "umod"; else if (o == MOD) ch = "mod"; else if (o == RS && p->n_type == ULONGLONG) ch = "lshr"; else if (o == RS) ch = "ashr"; else if (o == LS) ch = "ashl"; else break; snprintf(name, sizeof(name), "__%sdi3", ch); p->n_right = block(CM, p->n_left, p->n_right, 0, 0, 0); p->n_left = block(ADDROF, block(NAME, NIL, NIL, FTN, 0, 0), NIL, PTR|FTN, 0, 0); p->n_left->n_left->n_sp = lookup(addname(name), 0); defid(p->n_left->n_left, EXTERN); p->n_left = clocal(p->n_left); calldec(p->n_left, p->n_right); p->n_op = CALL; funcode(p); break; } #ifdef PCC_DEBUG if (xdebug) { printf("clocal end: %p\n", p); fwalk(p, eprint, 0); } #endif return(p); } struct symtab * makememcpy(void) { NODE *memcpy, *args, *t, *u; struct symtab *sp; /* TODO check that it's a func proto */ if ((sp = lookup(addname("memcpy"), SNORMAL))) return sp; memcpy = block(NAME, NIL, NIL, 0, 0, 0); memcpy->n_sp = sp = lookup(addname("memcpy"), SNORMAL); defid(memcpy, EXTERN); args = block(CM, block(CM, block(NAME, NIL, NIL, VOID|PTR, 0, 0), block(NAME, NIL, NIL, VOID|PTR, 0, 0), 0, 0, 0), block(NAME, NIL, NIL, LONG, 0, 0), 0, 0, 0); tymerge(t = block(TYPE, NIL, NIL, VOID|PTR, 0, 0), (u = block(UMUL, block(CALL, memcpy, args, LONG, 0, 0), NIL, LONG, 0, 0))); tfree(t); tfree(u); return sp; } void myp2tree(NODE *p) { struct symtab *sp; int o = p->n_op; if (o != FCON) return; /* Write float constants to memory */ /* Should be volontary per architecture */ #if 0 setloc1(RDATA); defalign(p->n_type == FLOAT ? ALFLOAT : p->n_type == DOUBLE ? ALDOUBLE : ALLDOUBLE ); deflab1(i = getlab()); #endif sp = tmpalloc(sizeof(struct symtab)); sp->sclass = STATIC; sp->ssue = 0; sp->slevel = 1; /* fake numeric label */ sp->soffset = getlab(); sp->sflags = 0; sp->stype = p->n_type; sp->squal = (CON >> TSHIFT); defloc(sp); ninval(0, btdims[p->n_type].suesize, p); p->n_op = NAME; p->n_lval = 0; p->n_sp = sp; } /*ARGSUSED*/ int andable(NODE *p) { return(1); /* all names can have & taken on them */ } /* * Return 1 if a variable of type "t" is OK to put in register. */ int cisreg(TWORD t) { return 1; } /* * Allocate off bits on the stack. p is a tree that when evaluated * is the multiply count for off, t is a storeable node where to write * the allocated address. */ void spalloc(NODE *t, NODE *p, OFFSZ off) { NODE *sp; p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */ /* sub the size from sp */ sp = block(REG, NIL, NIL, p->n_type, 0, 0); sp->n_lval = 0; sp->n_rval = STKREG; ecomp(buildtree(PLUSEQ, sp, p)); /* save the address of sp */ sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_sue); sp->n_lval = 0; sp->n_rval = STKREG; t->n_type = sp->n_type; ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */ } /* * print out a constant node, may be associated with a label. * Do not free the node after use. * off is bit offset from the beginning of the aggregate * fsz is the number of bits this is referring to * * XXX this relies on the host fp numbers representation */ int ninval(CONSZ off, int fsz, NODE *p) { union { float f; double d; long double l; int i[3]; } u; struct symtab *q; TWORD t; int i; t = p->n_type; if (t > BTMASK) p->n_type = t = INT; /* pointer */ if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT) uerror("element not constant"); switch (t) { case LONGLONG: case ULONGLONG: i = (p->n_lval >> 32); p->n_lval &= 0xffffffff; p->n_type = INT; ninval(off, 32, p); p->n_lval = i; ninval(off+32, 32, p); break; case INT: case UNSIGNED: printf("\t.long 0x%x", (int)p->n_lval); if ((q = p->n_sp) != NULL) { if ((q->sclass == STATIC && q->slevel > 0)) { printf("+" LABFMT, q->soffset); } else printf("+%s", q->soname ? q->soname : exname(q->sname)); } printf("\n"); break; case LDOUBLE: case DOUBLE: u.d = (double)p->n_dcon; printf("\t.long\t0x%x,0x%x\n", u.i[0], u.i[1]); break; case FLOAT: u.f = (float)p->n_dcon; printf("\t.long\t0x%x\n", u.i[0]); break; default: return 0; } return 1; } /* make a name look like an external name in the local machine */ char * exname(char *p) { if (p == NULL) return ""; return p; } /* * map types which are not defined on the local machine */ TWORD ctype(TWORD type) { switch (BTYPE(type)) { case LONG: MODTYPE(type,INT); break; case ULONG: MODTYPE(type,UNSIGNED); } return (type); } void calldec(NODE *f, NODE *a) { struct symtab *q; if (f->n_op == UMUL && f->n_left->n_op == PLUS && f->n_left->n_right->n_op == ICON) q = f->n_left->n_right->n_sp; else if (f->n_op == PLUS && f->n_right->n_op == ICON) q = f->n_right->n_sp; else { fwalk(f, eprint, 0); cerror("unknown function"); return; } printf("\t.import\t%s,code\n", q->soname ? q->soname : exname(q->sname)); } void extdec(struct symtab *q) { printf("\t.import\t%s,data\n", q->soname ? q->soname : exname(q->sname)); } /* make a common declaration for id, if reasonable */ void defzero(struct symtab *sp) { int off; off = tsize(sp->stype, sp->sdf, sp->ssue); off = (off + (SZCHAR - 1)) / SZCHAR; printf("\t.%scomm\t", sp->sclass == STATIC ? "l" : ""); if (sp->slevel == 0) printf("%s,0%o\n", sp->soname ? sp->soname : exname(sp->sname), off); else printf(LABFMT ",0%o\n", sp->soffset, off); } static char * section2string(char *name) { int len = strlen(name); if (strncmp(name, "link_set", 8) == 0) { const char postfix[] = ",\"aw\",@progbits"; char *s; s = IALLOC(len + sizeof(postfix)); memcpy(s, name, len); memcpy(s + len, postfix, sizeof(postfix)); return s; } return newstring(name, len); } char *nextsect; char *alias; int constructor; int destructor; #define SSECTION 010000 /* * Give target the opportunity of handling pragmas. */ int mypragma(char *str) { char *a2 = pragtok(NULL); if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) { constructor = 1; return 1; } if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) { destructor = 1; return 1; } if (strcmp(str, "section") == 0 && a2 != NULL) { nextsect = section2string(a2); return 1; } if (strcmp(str, "alias") == 0 && a2 != NULL) { alias = tmpstrdup(a2); return 1; } return 0; } /* * Called when a identifier has been declared, to give target last word. */ void fixdef(struct symtab *sp) { if (alias != NULL && (sp->sclass != PARAM)) { printf("\t.globl %s\n%s = %s\n", exname(sp->soname), exname(sp->soname), exname(alias)); alias = NULL; } if ((constructor || destructor) && (sp->sclass != PARAM)) { printf("\t.section .%ctors,\"aw\",@progbits\n" "\t.p2align 2\n\t.long %s\n\t.previous\n", constructor ? 'c' : 'd', exname(sp->sname)); constructor = destructor = 0; } } void pass1_lastchance(struct interpass *ip) { } pcc-20181216/arch/hppa/local2.c010064400017500000000000000417551277225026600146760ustar raggewheel/* $Id: local2.c,v 1.32 2016/09/26 16:45:42 ragge Exp $ */ /* * Copyright (c) 2007 Michael Shalayeff * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass2.h" # include # include void acon(NODE *p); void prtprolog(struct interpass_prolog *, int); int countargs(NODE *p, int *); void fixcalls(NODE *p, void *); static int stkpos; int p2calls; static const int rl[] = { R0, R1, R1, R1, R1, R1, R31, R31, R31, R31, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16, R17, R18, T1, T4, T3, T2, ARG3, ARG1, RET1 }; static const int rh[] = { R0, R31, T4, T3, T2, T1, T4, T3, T2, T1, R18, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16, R17, T4, T3, T2, T1, ARG2, ARG0, RET0 }; void deflab(int label) { printf("\t.label\t" LABFMT "\n", label); } static int regoff[MAXREGS]; static TWORD ftype; /* * Print out the prolog assembler. * addto and regoff are already calculated. */ void prtprolog(struct interpass_prolog *ipp, int addto) { int i; /* if this functions calls nothing -- no frame is needed */ if (p2calls || p2maxautooff > 4) { printf("\tcopy\t%%r3,%%r1\n\tcopy\t%%sp,%%r3\n"); if (addto < 0x2000) printf("\tstw,ma\t%%r1,%d(%%sp)\n", addto); else if (addto < 0x802000) printf("\tstw,ma\t%%r1,8192(%%sp)\n" "\taddil\t%d-8192,%%sp\n" "\tcopy\t%%r1,%%sp\n", addto); else comperr("too much local allocation"); if (p2calls) printf("\tstw\t%%rp,-20(%%r3)\n"); } for (i = 0; i < MAXREGS; i++) if (TESTBIT(p2env.p_regs, i)) { if (i <= R31) printf("\tstw\t%s,%d(%%r3)\n", rnames[i], regoff[i]); else if (i <= RETD0) printf("\tstw\t%s,%d(%%r3)\n" "\tstw\t%s,%d(%%r3)\n", rnames[rl[i - RD0]], regoff[i] + 0, rnames[rh[i - RD0]], regoff[i] + 4); else if (i <= FR31) printf("\tfstws\t%s,%d(%%r3)\n", rnames[i], regoff[i]); else printf("\tfstds\t%s,%d(%%r3)\n", rnames[i], regoff[i]); } } /* * calculate stack size and offsets */ static int offcalc(struct interpass_prolog *ipp) { int i, addto, off; addto = 32; if (p2calls) { i = p2calls - 1; /* round up to 4 args */ if (i < 4) i = 4; addto += i * 4; } for (off = 4, i = 0; i < MAXREGS; i++) if (TESTBIT(p2env.p_regs, i)) { regoff[i] = off; off += szty(PERMTYPE(i)) * SZINT/SZCHAR; } addto += off + p2maxautooff; return (addto + 63) & ~63; } void prologue(struct interpass_prolog *ipp) { int addto; ftype = ipp->ipp_type; /* * We here know what registers to save and how much to * add to the stack. */ addto = offcalc(ipp); printf("\t.proc\ncallinfo frame=%d, save_rp, save_sp\n\t.entry\n", addto); prtprolog(ipp, addto); } void eoftn(struct interpass_prolog *ipp) { int i; if (ipp->ipp_ip.ip_lbl == 0) return; /* no code needs to be generated */ /* return from function code */ for (i = 0; i < MAXREGS; i++) if (TESTBIT(p2env.p_regs, i)) { if (i <= R31) printf("\tldw\t%d(%%r3),%s\n", regoff[i], rnames[i]); else if (i <= RETD0) printf("\tldw\t%d(%%r3),%s\n" "\tldw\t%d(%%r3),%s\n", regoff[i] + 0, rnames[rl[i - RD0]], regoff[i] + 4, rnames[rh[i - RD0]]); else if (i <= FR31) printf("\tfldws\t%d(%%r3),%s\n", regoff[i], rnames[i]); else printf("\tfldds\t%d(%%r3),%s\n", regoff[i], rnames[i]); } if (p2calls || p2maxautooff > 4) { if (p2calls) printf("\tldw\t-20(%%r3),%%rp\n"); printf("\tcopy\t%%r3,%%r1\n" "\tldw\t0(%%r3),%%r3\n" "\tbv\t%%r0(%%rp)\n" "\tcopy\t%%r1,%%sp\n"); } else printf("\tbv\t%%r0(%%rp)\n\tnop\n"); printf("\t.exit\n\t.procend\n\t.size\t%s, .-%s\n", ipp->ipp_name, ipp->ipp_name); } /* * add/sub/... * * Param given: */ void hopcode(int f, int o) { char *str; switch (o) { case PLUS: str = "add"; break; case MINUS: str = "sub"; break; case AND: str = "and"; break; case OR: str = "or"; break; case ER: str = "xor"; break; case EQ: str = "="; break; case NE: str = "<>"; break; case LE: str = "<"; break; case LT: str = "<="; break; case ULE: str = "<<"; break; case ULT: str = "<<="; break; case GE: str = ">="; break; case GT: str = ">"; break; case UGE: str = ">>"; break; case UGT: str = ">>="; break; default: comperr("hopcode2: %d", o); str = 0; /* XXX gcc */ } printf("%s%c", str, f); } /* * Return type size in bytes. Used by R2REGS, arg 2 to offset(). */ int tlen(p) NODE *p; { switch(p->n_type) { case CHAR: case UCHAR: return(1); case SHORT: case USHORT: return(SZSHORT/SZCHAR); case FLOAT: return(SZFLOAT/SZCHAR); case DOUBLE: return(SZDOUBLE/SZCHAR); case INT: case UNSIGNED: case LONG: case ULONG: return(SZINT/SZCHAR); case LONGLONG: case ULONGLONG: return SZLONGLONG/SZCHAR; default: if (!ISPTR(p->n_type)) comperr("tlen type %d not pointer", p->n_type); return SZPOINT(p->n_type)/SZCHAR; } } static int argsiz(NODE *p) { NODE *q; TWORD t = p->n_type; if (t < LONGLONG || t == FLOAT || t > BTMASK) return 4; if (t == LONGLONG || t == ULONGLONG || t == DOUBLE) return 8; if (t == LDOUBLE) return 8; /* LDOUBLE is 16 */ if ((t == STRTY || t == UNIONTY) && p->n_right->n_op == STARG) return 4 + attr_find(p->n_right->n_ap, ATTR_P2STRUCT)->iarg(0); /* perhaps it's down there somewhere -- let me take another look! */ if ((t == STRTY || t == UNIONTY) && p->n_right->n_op == CALL) { q = p->n_right->n_right->n_left->n_left->n_right; if (q->n_op == STARG) return 4 + attr_find(q->n_ap, ATTR_P2STRUCT)->iarg(0); } comperr("argsiz %p", p); return 0; } /* * Emit code to compare two longlong numbers. */ static void twollcomp(NODE *p) { int o = p->n_op; int s = getlab2(); int e = p->n_label; int cb1, cb2; if (o >= ULE) o -= (ULE-LE); switch (o) { case NE: cb1 = 0; cb2 = NE; break; case EQ: cb1 = NE; cb2 = 0; break; case LE: case LT: cb1 = GT; cb2 = LT; break; case GE: case GT: cb1 = LT; cb2 = GT; break; default: cb1 = cb2 = 0; /* XXX gcc */ } if (p->n_op >= ULE) cb1 += 4, cb2 += 4; if (cb1) { p->n_op = cb1; p->n_label = s; expand(p, 0, "\tcomb,O\tUR,UL,LC\n\tnop\n"); p->n_label = e; p->n_op = o; } if (cb2) { p->n_op = cb2; expand(p, 0, "\tcomb,O\tUR,UL,LC\n\tnop\n"); p->n_op = o; } expand(p, 0, "\tcomb,O\tAR,AL,LC\n\tnop\n"); deflab(s); } void zzzcode(NODE *p, int c) { int n; switch (c) { case 'C': /* after-call fixup */ n = p->n_qual; /* args */ break; case 'P': /* returning struct-call setup */ n = p->n_qual; /* args */ break; case 'D': /* Long long comparision */ twollcomp(p); break; case 'F': /* struct as an arg */ default: comperr("zzzcode %c", c); } } int canaddr(NODE *); int canaddr(NODE *p) { int o = p->n_op; if (o == NAME || o == REG || o == ICON || o == OREG || (o == UMUL && shumul(p->n_left, SOREG))) return(1); return(0); } int fldexpand(NODE *p, int cookie, char **cp) { return 0; } /* * Does the bitfield shape match? */ int flshape(NODE *p) { if (isreg(p)) return SRDIR; /* Direct match */ return SRREG; /* put it into a register */ } /* INTEMP shapes must not contain any temporary registers */ /* XXX should this go away now? */ int shtemp(NODE *p) { return 0; #if 0 int r; if (p->n_op == STARG ) p = p->n_left; switch (p->n_op) { case REG: return (!istreg(p->n_rval)); case OREG: r = p->n_rval; if (R2TEST(r)) { if (istreg(R2UPK1(r))) return(0); r = R2UPK2(r); } return (!istreg(r)); case UMUL: p = p->n_left; return (p->n_op != UMUL && shtemp(p)); } if (optype(p->n_op) != LTYPE) return(0); return(1); #endif } void adrcon(CONSZ val) { /* fix for L% and R% */ printf(CONFMT, val); } void conput(FILE *fp, NODE *p) { CONSZ val = p->n_lval; switch (p->n_op) { case ICON: if (p->n_name[0] != '\0') { fprintf(fp, "RR'%s-$global$", p->n_name); if (val) fprintf(fp, "+" CONFMT, val); } else fprintf(fp, CONFMT, val); return; default: comperr("illegal conput, p %p", p); } } /*ARGSUSED*/ void insput(NODE *p) { comperr("insput"); } /* * Write out the upper address, like the upper register of a 2-register * reference, or the next memory location. */ void upput(NODE *p, int size) { size /= SZCHAR; switch (p->n_op) { case REG: printf("%s", rnames[rh[p->n_rval - RD0]]); break; case OREG: p->n_lval += size; adrput(stdout, p); p->n_lval -= size; break; case ICON: case NAME: if (p->n_name[0] != '\0') { printf("LR'%s-$global$", p->n_name); if (p->n_lval != 0) printf("+" CONFMT, p->n_lval); } else printf("L%%" CONFMT, p->n_lval >> 32); break; default: comperr("upput bad op %d size %d", p->n_op, size); } } void adrput(FILE *io, NODE *p) { int r; /* output an address, with offsets, from p */ if (p->n_op == FLD) p = p->n_left; switch (p->n_op) { case ICON: case NAME: if (p->n_name[0] != '\0') { fprintf(io, "RR'%s-$global$", p->n_name); if (p->n_lval != 0) fprintf(io, "+" CONFMT, p->n_lval); } else fprintf(io, "R%%" CONFMT, p->n_lval); return; case OREG: r = p->n_rval; if (p->n_name[0] != '\0') { fprintf(io, "RR'%s-$global$", p->n_name); if (p->n_lval != 0) fprintf(io, "+" CONFMT, p->n_lval); } else fprintf(io, "%d", (int)p->n_lval); if (R2TEST(r)) { fprintf(io, "%s(%s)", rnames[R2UPK1(r)], rnames[R2UPK2(r)]); } else fprintf(io, "(%s)", rnames[p->n_rval]); return; case REG: if (RD0 <= p->n_rval && p->n_rval <= RETD0) fprintf(io, "%s", rnames[rl[p->n_rval - RD0]]); else fprintf(io, "%s", rnames[p->n_rval]); return; default: comperr("illegal address, op %d, node %p", p->n_op, p); return; } } /* not used */ void cbgen(int o, int lab) { } int countargs(NODE *p, int *n) { int sz; if (p->n_op == CM) { countargs(p->n_left, n); countargs(p->n_right, n); return *n; } sz = argsiz(p) / 4; if (*n % (sz > 4? 4 : sz)) (*n)++; /* XXX */ return *n += sz; } void fixcalls(NODE *p, void *arg) { int n, o; /* Prepare for struct return by allocating bounce space on stack */ switch (o = p->n_op) { case STCALL: case USTCALL: if (attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0) + p2autooff > stkpos) stkpos = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0) + p2autooff; /* FALLTHROGH */ case CALL: case UCALL: n = 0; n = 1 + countargs(p->n_right, &n); if (n > p2calls) p2calls = n; break; } } void myreader(struct interpass *ipole) { struct interpass *ip; stkpos = p2autooff; DLIST_FOREACH(ip, ipole, qelem) { switch (ip->type) { case IP_PROLOG: p2calls = 0; break; case IP_NODE: walkf(ip->ip_node, fixcalls, 0); break; } } if (stkpos > p2autooff) p2autooff = stkpos; if (stkpos > p2maxautooff) p2maxautooff = stkpos; if (x2debug) printip(ipole); } /* * Remove some PCONVs after OREGs are created. */ static void pconv2(NODE *p, void *arg) { NODE *q; if (p->n_op == PLUS) { if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) { if (p->n_right->n_op != ICON) return; if (p->n_left->n_op != PCONV) return; if (p->n_left->n_left->n_op != OREG) return; q = p->n_left->n_left; nfree(p->n_left); p->n_left = q; /* * This will be converted to another OREG later. */ } } } void mycanon(NODE *p) { walkf(p, pconv2, 0); } void myoptim(struct interpass *ipole) { } void rmove(int s, int d, TWORD t) { int sl, sh, dl, dh; switch (t) { case LONGLONG: case ULONGLONG: sl = rl[s-RD0]; sh = rh[s-RD0]; dl = rl[d-RD0]; dh = rh[d-RD0]; #define SW(x,y) { int i = x; x = y; y = i; } if (sl == dh || sh == dl) { /* Swap if moving to itself */ SW(sl, sh); SW(dl, dh); } if (sl != dl) printf("\tcopy\t%s,%s\n", rnames[sl], rnames[dl]); if (sh != dh) printf("\tcopy\t%s,%s\n", rnames[sh], rnames[dh]); break; case FLOAT: printf("\tfcpy,sgl\t%s,%s\n", rnames[s], rnames[d]); break; case DOUBLE: case LDOUBLE: printf("\tfcpy,dbl\t%s,%s\n", rnames[s], rnames[d]); break; default: printf("\tcopy\t%s,%s\n", rnames[s], rnames[d]); } } /* * For class c, find worst-case displacement of the number of * registers in the array r[] indexed by class. */ int COLORMAP(int c, int *r) { int num; switch (c) { case CLASSA: num = 2 * r[CLASSB]; num += r[CLASSA]; return num < 28; case CLASSB: num = r[CLASSA]; num += r[CLASSB] * 2; return num < 28; case CLASSC: num = (r[CLASSD] > 8? 8 : r[CLASSD]) * 2; num += r[CLASSC]; return num < 28; case CLASSD: num = (r[CLASSC] + 1) / 2; num += r[CLASSD]; return num < 28; } return 0; /* XXX gcc */ } char * rnames[MAXREGS] = { "%r0", "%r1", "%rp", "%r3", "%r4", "%r5", "%r6", "%r7", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "%r16", "%r17", "%r18", "%t4", "%t3", "%t2", "%t1", "%arg3", "%arg2", "%arg1", "%arg0", "%dp", "%ret0", "%ret1", "%sp", "%r31", "%rd0", "%rd1", "%rd2", "%rd3", "%rd4", "%rd5", "%rd6", "%rd7", "%rd8", "%rd9", "%rd10", "%rd11", "%rd12", "%rd13", "%rd14", "%rd15", "%rd16", "%rd17", "%rd18", "%rd19", "%rd20", "%rd21", "%rd22", "%rd23", "%rd24", "%td4", "%td3", "%td2", "%td1", "%ad1", "%ad0", "%retd0", "%fr0", "%fr4", "%fr5", "%fr6", "%fr7", "%fr8", "%fr9", "%fr10", "%fr11", "%fr12", "%fr13", "%fr14", "%fr15", "%fr16", "%fr17", "%fr18", "%fr19", "%fr20", "%fr21", "%fr22", "%fr23", "%fr24", "%fr25", "%fr26", "%fr27", "%fr28", "%fr29", "%fr30", "%fr31", "%fr0l", "%fr0r", "%fr4l", "%fr4r", "%fr5l", "%fr5r", "%fr6l", "%fr6r", "%fr7l", "%fr7r", "%fr8l", "%fr8r", "%fr9l", "%fr9r", "%fr10l", "%fr10r", "%fr11l", "%fr11r", "%fr12l", "%fr12r", "%fr13l", "%fr13r", "%fr14l", "%fr14r", "%fr15l", "%fr15r", "%fr16l", "%fr16r", "%fr17l", "%fr17r", "%fr18l", "%fr18r", #ifdef __hppa64__ "%fr19l", "%fr19r", "%fr20l", "%fr20r", "%fr21l", "%fr21r", "%fr22l", "%fr22r", "%fr23l", "%fr23r", "%fr24l", "%fr24r", "%fr25l", "%fr25r", "%fr26l", "%fr26r", "%fr27l", "%fr27r", "%fr28l", "%fr28r", "%fr29l", "%fr29r", "%fr30l", "%fr30r", "%fr31l", "%fr31r", #endif }; /* * Return a class suitable for a specific type. */ int gclass(TWORD t) { switch (t) { case LONGLONG: case ULONGLONG: return CLASSB; case FLOAT: return CLASSC; case DOUBLE: case LDOUBLE: return CLASSD; default: return CLASSA; } } /* * Calculate argument sizes. */ void lastcall(NODE *p) { NODE *op = p; int size = 64; p->n_qual = size; if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) return; for (p = p->n_right; p->n_op == CM; p = p->n_left) size += argsiz(p->n_right); size += argsiz(p); op->n_qual = size; /* XXX */ } /* * Special shapes. */ int special(NODE *p, int shape) { int o = p->n_op; switch (shape) { case SFUNCALL: if (o == STCALL || o == USTCALL) return SRREG; break; case SPIMM: if (o != ICON || p->n_name[0] || p->n_lval < -31 || p->n_lval >= 32) break; return SRDIR; case SPICON: if (o != ICON || p->n_name[0] || p->n_lval < -1024 || p->n_lval >= 1024) break; return SRDIR; case SPCNHW: if (o != ICON || p->n_name[0] || (p->n_lval & 0xffffffffLL)) break; return SRDIR; case SPCNLW: if (o != ICON || p->n_name[0] || (p->n_lval & ~0xffffffffLL)) break; return SRDIR; case SPCNHI: if (o != ICON || p->n_name[0] || (p->n_lval & ~0xfffff800LL)) break; return SRDIR; case SPCON: if (o != ICON || p->n_name[0] || p->n_lval < -8192 || p->n_lval >= 8192) break; return SRDIR; case SPNAME: if (o != ICON || !p->n_name[0]) break; return SRDIR; } return SRNOPE; } /* * Target-dependent command-line options. */ void mflags(char *str) { } /* * Do something target-dependent for xasm arguments. * Supposed to find target-specific constraints and rewrite them. */ int myxasm(struct interpass *ip, NODE *p) { return 0; } pcc-20181216/arch/hppa/macdefs.h010064400017500000000000000306031266660034000151110ustar raggewheel/* $Id: macdefs.h,v 1.22 2016/03/05 15:53:04 ragge Exp $ */ /* * Copyright (c) 2007 Michael Shalayeff * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Convert (multi-)character constant to integer. */ #define makecc(val,i) (lastcon = (lastcon<<8)|((val<<24)>>24)) #define ARGINIT (32*8) /* bits below fp where args start */ #define AUTOINIT (4*8) /* bits above fp where locals start */ /* * storage sizes */ #define SZCHAR 8 #define SZBOOL 8 #define SZINT 32 #define SZFLOAT 32 #define SZDOUBLE 64 #define SZLDOUBLE 64 /* or later 128 */ #define SZLONG 32 #define SZSHORT 16 #define SZLONGLONG 64 #define SZPOINT(t) 32 /* * alignment requirements */ #define ALCHAR 8 #define ALBOOL 8 #define ALINT 32 #define ALFLOAT 32 #define ALDOUBLE 64 #define ALLDOUBLE 64 /* 128 later */ #define ALLONG 32 #define ALLONGLONG 32 #define ALSHORT 16 #define ALPOINT 32 #define ALSTRUCT 32 #define ALSTACK 64 /* * type value limits */ #define MIN_CHAR -128 #define MAX_CHAR 127 #define MAX_UCHAR 255 #define MIN_SHORT -32768 #define MAX_SHORT 32767 #define MAX_USHORT 65535 #define MIN_INT (-0x7fffffff-1) #define MAX_INT 0x7fffffff #define MAX_UNSIGNED 0xffffffff #define MIN_LONG MIN_INT #define MAX_LONG MAX_INT #define MAX_ULONG MAX_UNSIGNED #define MIN_LONGLONG (-0x7fffffffffffffffLL-1) #define MAX_LONGLONG 0x7fffffffffffffffLL #define MAX_ULONGLONG 0xffffffffffffffffULL #undef CHAR_UNSIGNED #define BOOL_TYPE CHAR typedef long long CONSZ; typedef unsigned long long U_CONSZ; typedef long long OFFSZ; #define CONFMT "%lld" /* format for printing constants */ #define LABFMT ".L%d" /* format for printing labels */ #define STABLBL ".LL%d" /* format for stab (debugging) labels */ #undef BACKAUTO /* stack grows upwards */ #undef BACKTEMP /* stack grows upwards */ #define FIELDOPS /* have bit field ops */ #define TARGET_ENDIAN TARGET_BE #define TARGET_FLT_EVAL_METHOD 0 /* all as their type */ #define BYTEOFF(x) ((x)&03) #define wdal(k) (BYTEOFF(k)==0) #define STOARG(p) #define STOFARG(p) #define STOSTARG(p) #define szty(t) (((t) == DOUBLE || (t) == LONGLONG || (t) == ULONGLONG) ? 2 : \ (t) == LDOUBLE ? 2 : 1) #define R0 0 #define R1 1 #define RP 2 #define FP 3 #define R4 4 #define R5 5 #define R6 6 #define R7 7 #define R8 8 #define R9 9 #define R10 10 #define R11 11 #define R12 12 #define R13 13 #define R14 14 #define R15 15 #define R16 16 #define R17 17 #define R18 18 #define T4 19 #define T3 20 #define T2 21 #define T1 22 #define ARG3 23 #define ARG2 24 #define ARG1 25 #define ARG0 26 #define DP 27 #define RET0 28 #define RET1 29 #define SP 30 #define R31 31 /* double regs overlay */ #define RD0 32 /* r0:r0 */ #define RD1 33 /* r1:r31 */ #define RD2 34 /* r1:t4 */ #define RD3 35 /* r1:t3 */ #define RD4 36 /* r1:t2 */ #define RD5 37 /* r1:t1 */ #define RD6 38 /* r31:t4 */ #define RD7 39 /* r31:t3 */ #define RD8 40 /* r31:t2 */ #define RD9 41 /* r31:t1 */ #define RD10 42 /* r4:r18 */ #define RD11 43 /* r5:r4 */ #define RD12 44 /* r6:r5 */ #define RD13 45 /* r7:r6 */ #define RD14 46 /* r8:r7 */ #define RD15 47 /* r9:r8 */ #define RD16 48 /* r10:r9 */ #define RD17 49 /* r11:r10 */ #define RD18 50 /* r12:r11 */ #define RD19 51 /* r13:r12 */ #define RD20 52 /* r14:r13 */ #define RD21 53 /* r15:r14 */ #define RD22 54 /* r16:r15 */ #define RD23 55 /* r17:r16 */ #define RD24 56 /* r18:r17 */ #define TD4 57 /* t1:t4 */ #define TD3 58 /* t4:t3 */ #define TD2 59 /* t3:t2 */ #define TD1 60 /* t2:t1 */ #define AD2 61 /* arg3:arg2 */ #define AD1 62 /* arg1:arg0 */ #define RETD0 63 /* ret1:ret0 */ /* FPU regs */ #define FR0 64 #define FR4 65 #define FR5 66 #define FR6 67 #define FR7 68 #define FR8 69 #define FR9 70 #define FR10 71 #define FR11 72 #define FR12 73 #define FR13 74 #define FR14 75 #define FR15 76 #define FR16 77 #define FR17 78 #define FR18 79 #define FR19 80 #define FR20 81 #define FR21 82 #define FR22 83 #define FR23 84 #define FR24 85 #define FR25 86 #define FR26 87 #define FR27 88 #define FR28 89 #define FR29 90 #define FR30 91 #define FR31 92 #define FR0L 93 #define FR0R 94 #define FR4L 95 #define FR4R 96 #define FR5L 97 #define FR5R 98 #define FR6L 99 #define FR6R 100 #define FR7L 101 #define FR7R 102 #define FR8L 103 #define FR8R 104 #define FR9L 105 #define FR9R 106 #define FR10L 107 #define FR10R 108 #define FR11L 109 #define FR11R 110 #define FR12L 111 #define FR12R 112 #define FR13L 113 #define FR13R 114 #define FR14L 115 #define FR14R 116 #define FR15L 117 #define FR15R 118 #define FR16L 119 #define FR16R 120 #define FR17L 121 #define FR17R 122 #define FR18L 123 #define FR18R 124 #ifdef __hppa64__ #define FR19L 125 #define FR19R 126 #define FR20L 127 #define FR20R 128 #define FR21L 129 #define FR21R 130 #define FR22L 131 #define FR22R 132 #define FR23L 133 #define FR23R 134 #define FR24L 135 #define FR24R 136 #define FR25L 137 #define FR25R 138 #define FR26L 139 #define FR26R 140 #define FR27L 141 #define FR27R 142 #define FR28L 143 #define FR28R 144 #define FR29L 145 #define FR29R 146 #define FR30L 147 #define FR30R 148 #define FR31L 149 #define FR31R 150 #define MAXREGS 151 #else #define MAXREGS 125 #endif #define RSTATUS \ 0, SAREG|TEMPREG, 0, 0, SAREG|PERMREG, SAREG|PERMREG, \ SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \ SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \ SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \ SAREG|PERMREG, \ SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ 0, SAREG|TEMPREG, SAREG|TEMPREG, 0, SAREG|TEMPREG, \ /* double overlays */ \ 0, \ SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \ SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \ SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \ SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \ /* double-precision floats */ \ 0, \ SDREG|TEMPREG, SDREG|TEMPREG, SDREG|TEMPREG, SDREG|TEMPREG, \ SDREG|TEMPREG, SDREG|TEMPREG, SDREG|TEMPREG, SDREG|TEMPREG, \ SDREG|PERMREG, SDREG|PERMREG, SDREG|PERMREG, SDREG|PERMREG, \ SDREG|PERMREG, SDREG|PERMREG, SDREG|PERMREG, SDREG|PERMREG, \ SDREG|PERMREG, SDREG|PERMREG, \ SDREG|TEMPREG, SDREG|TEMPREG, SDREG|TEMPREG, SDREG|TEMPREG, \ SDREG|TEMPREG, SDREG|TEMPREG, SDREG|TEMPREG, SDREG|TEMPREG, \ SDREG|TEMPREG, SDREG|TEMPREG, \ /* single-precision floats */ \ 0, 0, \ SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \ SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \ SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \ SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, #ifdef __hppa64__ SCREG, SCREG, \ SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \ SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \ SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, #endif #define ROVERLAP \ { -1 }, \ { RD1, RD2, RD3, RD4, RD5, -1 },\ { -1 }, { -1 }, \ { RD10, RD11, -1 }, \ { RD11, RD12, -1 }, \ { RD12, RD13, -1 }, \ { RD13, RD14, -1 }, \ { RD14, RD15, -1 }, \ { RD15, RD16, -1 }, \ { RD16, RD17, -1 }, \ { RD17, RD18, -1 }, \ { RD18, RD19, -1 }, \ { RD19, RD20, -1 }, \ { RD20, RD21, -1 }, \ { RD21, RD22, -1 }, \ { RD22, RD23, -1 }, \ { RD23, RD24, -1 }, \ { RD24, RD10, -1 }, \ { TD1, TD4, -1 }, \ { TD3, TD2, -1 }, \ { TD1, TD2, -1 }, \ { TD1, TD4, -1 }, \ { AD2, -1 }, { AD2, -1 }, \ { AD1, -1 }, { AD1, -1 }, \ { -1 }, \ { RETD0, -1 }, { RETD0, -1 }, \ { -1 }, \ { RD1, RD5, RD6, RD7, RD8, -1 },\ { -1 }, \ { R1, R31, -1 }, \ { R1, T4, -1 }, \ { R1, T3, -1 }, \ { R1, T2, -1 }, \ { R1, T1, -1 }, \ { R31, T4, -1 }, \ { R31, T3, -1 }, \ { R31, T2, -1 }, \ { R31, T1, -1 }, \ { R4, R18, -1 }, \ { R5, R4, -1 }, \ { R6, R5, -1 }, \ { R7, R6, -1 }, \ { R8, R7, -1 }, \ { R9, R8, -1 }, \ { R10, R9, -1 }, \ { R11, R10, -1 }, \ { R12, R11, -1 }, \ { R13, R12, -1 }, \ { R14, R15, -1 }, \ { R15, R14, -1 }, \ { R16, R15, -1 }, \ { R17, R16, -1 }, \ { R18, R17, -1 }, \ { T1, T4, -1 }, \ { T4, T3, -1 }, \ { T3, T2, -1 }, \ { T2, T1, -1 }, \ { ARG3, ARG2, -1 }, \ { ARG1, ARG0, -1 }, \ { RET1, RET0, -1 }, \ { -1 }, \ { FR4L, FR4R, -1 }, \ { FR5L, FR5R, -1 }, \ { FR6L, FR6R, -1 }, \ { FR7L, FR7R, -1 }, \ { FR8L, FR8R, -1 }, \ { FR9L, FR9R, -1 }, \ { FR10L, FR10R, -1 }, \ { FR11L, FR11R, -1 }, \ { FR12L, FR12R, -1 }, \ { FR13L, FR13R, -1 }, \ { FR14L, FR14R, -1 }, \ { FR15L, FR15R, -1 }, \ { FR16L, FR16R, -1 }, \ { FR17L, FR17R, -1 }, \ { FR18L, FR18R, -1 }, \ { -1 }, \ { -1 }, \ { -1 }, \ { -1 }, \ { -1 }, \ { -1 }, \ { -1 }, \ { -1 }, \ { -1 }, \ { -1 }, \ { -1 }, \ { -1 }, \ { -1 }, \ { -1 }, { -1 }, \ { FR4, -1 }, { FR4, -1 }, \ { FR5, -1 }, { FR5, -1 }, \ { FR6, -1 }, { FR6, -1 }, \ { FR7, -1 }, { FR7, -1 }, \ { FR8, -1 }, { FR8, -1 }, \ { FR9, -1 }, { FR9, -1 }, \ { FR10, -1 }, { FR10, -1 }, \ { FR11, -1 }, { FR11, -1 }, \ { FR12, -1 }, { FR12, -1 }, \ { FR13, -1 }, { FR13, -1 }, \ { FR14, -1 }, { FR14, -1 }, \ { FR15, -1 }, { FR15, -1 }, \ { FR16, -1 }, { FR16, -1 }, \ { FR17, -1 }, { FR17, -1 }, \ { FR18, -1 }, { FR18, -1 }, #ifdef __hppa64__ { FR19, -1 }, { FR19, -1 }, \ { FR20, -1 }, { FR20, -1 }, \ { FR21, -1 }, { FR21, -1 }, \ { FR22, -1 }, { FR22, -1 }, \ { FR23, -1 }, { FR23, -1 }, \ { FR24, -1 }, { FR24, -1 }, \ { FR25, -1 }, { FR25, -1 }, \ { FR26, -1 }, { FR26, -1 }, \ { FR27, -1 }, { FR27, -1 }, \ { FR28, -1 }, { FR28, -1 }, \ { FR29, -1 }, { FR29, -1 }, \ { FR30, -1 }, { FR30, -1 }, \ { FR31, -1 }, { FR31, -1 }, #endif #define PCLASS(p) \ (p->n_type == LONGLONG || p->n_type == ULONGLONG ? SBREG : \ (p->n_type == FLOAT ? SCREG : \ (p->n_type == DOUBLE || p->n_type == LDOUBLE ? SDREG : SAREG))) #define NUMCLASS 4 /* highest number of reg classes used */ int COLORMAP(int c, int *r); #define PERMTYPE(x) ((x) < 32? INT : ((x) < 64? LONGLONG : ((x) < 93? LDOUBLE : FLOAT))) #define GCLASS(x) ((x) < 32? CLASSA : ((x) < 64? CLASSB : ((x) < 93? CLASSD : CLASSC))) #define DECRA(x,y) (((x) >> (y*8)) & 255) /* decode encoded regs */ #define ENCRD(x) (x) /* Encode dest reg in n_reg */ #define ENCRA1(x) ((x) << 8) /* A1 */ #define ENCRA2(x) ((x) << 16) /* A2 */ #define ENCRA(x,y) ((x) << (8+y*8)) /* encode regs in int */ #define RETREG(x) (x == LONGLONG || x == ULONGLONG ? RETD0 : \ x == FLOAT? FR4L : \ x == DOUBLE || x == LDOUBLE ? FR4 : RET0) #define FPREG FP /* frame pointer */ #define STKREG SP /* stack pointer */ #define MYREADER(p) myreader(p) #define MYCANON(p) mycanon(p) #define MYOPTIM #define SFUNCALL (MAXSPECIAL+1) /* struct assign after function call */ #define SPCNHI (MAXSPECIAL+2) /* high 21bits constant */ #define SPCON (MAXSPECIAL+3) /* smaller constant */ #define SPICON (MAXSPECIAL+4) /* even smaller constant */ #define SPCNHW (MAXSPECIAL+5) /* LL const w/ 0 in low word */ #define SPCNLW (MAXSPECIAL+6) /* LL const w/ 0 in high word */ #define SPIMM (MAXSPECIAL+7) /* immidiate const for depi/comib */ #define SPNAME (MAXSPECIAL+8) /* ext symbol reference load/store */ pcc-20181216/arch/hppa/order.c010064400017500000000000000116441157264212200146200ustar raggewheel/* $Id: order.c,v 1.10 2011/06/05 08:54:42 plunky Exp $ */ /* * Copyright (c) 2007 Michael Shalayeff * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass2.h" #include int canaddr(NODE *); /* is it legal to make an OREG or NAME entry which has an * offset of off, (from a register of r), if the * resulting thing had type t */ int notoff(TWORD t, int r, CONSZ off, char *cp) { return(0); /* YES */ } /* * Turn a UMUL-referenced node into OREG. * Be careful about register classes, this is a place where classes change. */ void offstar(NODE *p, int shape) { NODE *r; if (x2debug) printf("offstar(%p)\n", p); if (isreg(p)) return; /* Is already OREG */ r = p->n_right; if (p->n_op == PLUS || p->n_op == MINUS) { if (r->n_op == ICON) { if (isreg(p->n_left) == 0) (void)geninsn(p->n_left, INAREG); /* Converted in ormake() */ return; } } (void)geninsn(p, INAREG); } /* * Do the actual conversion of offstar-found OREGs into real OREGs. */ void myormake(NODE *q) { NODE *p, *r; if (x2debug) printf("myormake(%p)\n", q); p = q->n_left; if (p->n_op == PLUS && (r = p->n_right)->n_op == LS && r->n_right->n_op == ICON && r->n_right->n_lval == 2 && p->n_left->n_op == REG && r->n_left->n_op == REG) { q->n_op = OREG; q->n_lval = 0; q->n_rval = R2PACK(p->n_left->n_rval, r->n_left->n_rval, 0); tfree(p); } } /* * Shape matches for UMUL. Cooperates with offstar(). */ int shumul(NODE *p, int shape) { if (x2debug) printf("shumul(%p)\n", p); /* Turns currently anything into OREG on hppa */ if (shape & SOREG) return SOREG; return SRNOPE; } /* * Rewrite operations on binary operators (like +, -, etc...). * Called as a result of table lookup. */ int setbin(NODE *p) { if (x2debug) printf("setbin(%p)\n", p); return 0; } /* setup for assignment operator */ int setasg(NODE *p, int cookie) { if (x2debug) printf("setasg(%p,%s)\n", p, prcook(cookie)); if (p->n_left->n_op == FLD && !isreg(p->n_left->n_left)) { NODE *l, *r; int reg; geninsn(p->n_left->n_left, INAREG); reg = DECRA(p->n_left->n_left->n_reg, 0); l = tcopy(p->n_left->n_left); p->n_left->n_left->n_op = REG; p->n_left->n_left->n_rval = reg; p->n_left->n_left->n_lval = 0; r = tcopy(p->n_left->n_left); geninsn(p->n_left, INAREG); l = mkbinode(ASSIGN, l, r, l->n_type); geninsn(l, INAREG); return (1); } return (0); } /* setup for unary operator */ int setuni(NODE *p, int cookie) { if (x2debug) printf("setuni(%p,%s)\n", p, prcook(cookie)); return 0; } /* * Special handling of some instruction register allocation. */ struct rspecial * nspecial(struct optab *q) { comperr("nspecial entry %d", q - table); return 0; /* XXX gcc */ } /* * Set evaluation order of a binary node if it differs from default. */ int setorder(NODE *p) { return 0; /* nothing differs on hppa */ } /* * Set registers "live" at function calls (like arguments in registers). * This is for liveness analysis of registers. */ int * livecall(NODE *p) { static int r[5], *s = &r[4]; *s = -1; if (p->n_op == UCALL || p->n_op == UFORTCALL || p->n_op == USTCALL || p->n_op == FORTCALL) return s; for (p = p->n_right; p->n_op == CM; p = p->n_left) if (p->n_right->n_op == ASSIGN && p->n_right->n_left->n_op == REG) *--s = p->n_right->n_left->n_rval; if (p->n_op == ASSIGN && p->n_left->n_op == REG) *--s = p->n_left->n_rval; return s; } /* * Signal whether the instruction is acceptable for this target. */ int acceptable(struct optab *op) { return 1; } pcc-20181216/arch/hppa/table.c010064400017500000000000000453611202605160600145730ustar raggewheel/* $Id: table.c,v 1.16 2012/09/18 10:57:10 mickey Exp $ */ /* $OpenBSD: table.c,v 1.2 2007/12/19 20:19:54 otto Exp $ */ /* * Copyright (c) 2007 Michael Shalayeff * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "pass2.h" #define TLL TLONGLONG|TULONGLONG #define ANYSIGNED TINT|TLONG|TSHORT|TCHAR #define ANYUSIGNED TUNSIGNED|TULONG|TUSHORT|TUCHAR #define ANYFIXED ANYSIGNED|ANYUSIGNED #define TUWORD TUNSIGNED|TULONG #define TSWORD TINT|TLONG #define TWORD TUWORD|TSWORD #define THWORD TUSHORT|TSHORT #define TBYTE TUCHAR|TCHAR #define SHINT SAREG /* char, short and int */ #define ININT INAREG #define SHLL SBREG /* shape for long long */ #define INLL INBREG #define SHFL SCREG /* shape for float */ #define INFL INCREG #define SHDBL SDREG /* shape for double */ #define INDBL INDREG struct optab table[] = { /* First entry must be an empty entry */ { -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", }, /* PCONVs are usually not necessary */ { PCONV, INAREG, SAREG, TWORD|TPOINT, SAREG, TWORD|TPOINT, 0, RLEFT, "", }, /* * A bunch conversions of integral<->integral types * There are lots of them, first in table conversions to itself * and then conversions from each type to the others. */ /* itself to itself, including pointers */ /* convert int,short,char <-> int,short,char. */ { SCONV, ININT, SHINT, TBYTE, SHINT, TBYTE, 0, RLEFT, "", }, { SCONV, ININT, SHINT, THWORD, SHINT, THWORD, 0, RLEFT, "", }, { SCONV, ININT, SHINT, TWORD, SHINT, TWORD, 0, RLEFT, "", }, /* convert pointers to int. */ { SCONV, ININT, SHINT, TWORD|TPOINT, SANY, TWORD, 0, RLEFT, "", }, /* convert (u)longlong to (u)longlong. */ { SCONV, INLL, SHLL, TLL, SHLL, TLL, 0, RLEFT, "", }, /* convert pointers to pointers. */ { SCONV, ININT, SHINT, TPOINT, SANY, TPOINT, 0, RLEFT, "", }, /* convert double <-> ldouble. nothing to do here (or support quads later) */ { SCONV, INDBL, SHDBL, TDOUBLE|TLDOUBLE, SHDBL, TDOUBLE|TLDOUBLE, 0, RLEFT, "", }, /* convert float -> double */ { SCONV, INFL, SHFL, TFLOAT, SHDBL, TDOUBLE|TLDOUBLE, 0, 0, "\tfcnvff,sgl,dbl AL,AR\n", }, /* convert double -> float */ { SCONV, INDBL, SHDBL, TDOUBLE|TLDOUBLE, SHFL, TFLOAT, 0, 0, "\tfcnvff,dbl,sgl\tAL,AR\n", }, /* convert int,short,char to (u)long long */ { SCONV, INLL, SHINT, ANYSIGNED, SANY, TLL, NBREG, RESC1, "\tcopy\tAL,A1\n" "\textrs\tAL,0,1,U1\n", }, /* convert unsigned int,short,char to (u)long long */ { SCONV, INLL, SHINT, TWORD, SANY, TLL, NBREG, RESC1, "\tcopy\tAL,A1\n" "\tcopy\t%r0,U1\n", }, /* convert int,short,char (in memory) to float */ { SCONV, INFL, SOREG, ANYSIGNED, SHFL, TFLOAT, NCREG, RESC1, "\tfldws\tAL,A1\n" "\tfcnvxf,sgl,sgl\tA1,A1\n", }, /* convert int,short,char (in memory) to double */ { SCONV, INDBL, SOREG, TSWORD, SHDBL, TDOUBLE|TLDOUBLE, NDREG, RESC1, "\tfldws\tAL,A1\n" "\tfcnvxf,sgl,dbl\tA1,A1\n", }, /* convert (u)long (in memory) to double */ { SCONV, INDBL, SOREG, TLL, SHDBL, TDOUBLE|TLDOUBLE, NDREG, RESC1, "\tfldds\tAL,A1\n" "\tfcnvxf,dbl,dbl\tA1,A1\n", }, /* convert int,short,char (in register) to float */ { SCONV, INFL, SHINT, TSWORD, SHFL, TFLOAT, NCREG, RESC1, "\tstw,ma\tAL,4(%sp)\n" "\tfldws,ma\t-4(%sp),A1\n" "\tfcnvxf,sgl,sgl\tA1,A1\n", }, /* convert int,short,char (in register) to double */ { SCONV, INDBL, SHINT, TSWORD, SHDBL, TDOUBLE|TLDOUBLE, NDREG, RESC1, "\tstw,ma\tAL,4(%sp)\n" "\tfldws,mb\t-4(%sp),AR\n" "\tfcnvxf,sgl,dbl\tA1,A1\n", }, /* convert (u)long (in register) to double */ { SCONV, INDBL, SHLL, TLL, SHDBL, TDOUBLE|TLDOUBLE, NDREG, RESC1, "\tldo\t8(%sp),%sp\n" "\tstw\tAL,-8(%sp)\n" "\tstw\tUL,-4(%sp)\n" "\tfldds,mb\t-8(%sp),A1\n" "\tfcnvxf,dbl,dbl\tA1,A1\n", }, /* convert char to (unsigned) short/int. */ { SCONV, ININT, SAREG, TCHAR, SAREG, THWORD|TWORD, NASL|NAREG, RESC1, "\textrs\tAL,31,8,A1\n", }, /* convert unsigned char to (unsigned) short/int. */ { SCONV, ININT, SAREG, TUCHAR, SAREG, THWORD|TWORD, NASL|NAREG, RESC1, "\textru\tAL,31,8,A1\n", }, /* convert char to (unsigned) long long. */ { SCONV, INLL, SAREG, TCHAR, SBREG, TLL, NBSL|NBREG, RESC1, "\textrs\tAL,31,8,A1\n\textrs\tA1,0,1,U1", }, /* convert unsigned char to (unsigned) long long. */ { SCONV, INLL, SAREG, TUCHAR, SBREG, TLL, NBSL|NBREG, RESC1, "\textru\tAL,31,8,A1\n\tcopy\t%r0,U1", }, /* convert short to (unsigned) int. */ { SCONV, ININT, SAREG, TSHORT, SAREG, TWORD, NASL|NAREG, RESC1, "\textrs\tAL,31,16,A1\n", }, /* convert unsigned short to (unsigned) int. */ { SCONV, ININT, SAREG, TUSHORT, SAREG, THWORD, NASL|NAREG, RESC1, "\textru\tAL,31,16,A1\n", }, /* convert short to (unsigned) long long. */ { SCONV, INLL, SAREG, TSHORT, SBREG, TLL, NBSL|NBREG, RESC1, "\textrs\tAL,31,16,A1\n\textrs\tA1,0,1,U1", }, /* convert unsigned short to (unsigned) long long. */ { SCONV, INLL, SAREG, TUSHORT, SBREG, TLL, NBSL|NBREG, RESC1, "\textru\tAL,31,16,A1\n\tcopy\t%r0,U1", }, /* convert int,short,char (in memory) to int,short,char */ { SCONV, ININT, SOREG, TBYTE, SHINT, TBYTE|TPOINT, NAREG|NASL, RESC1, "\tldb\tAL,A1\n", }, { SCONV, ININT, SOREG, THWORD, SHINT, THWORD|TPOINT, NAREG|NASL, RESC1, "\tldh\tAL,A1\n", }, { SCONV, ININT, SOREG, TWORD, SHINT, TWORD|TPOINT, NAREG|NASL, RESC1, "\tldw\tAL,A1\n", }, /* convert (u)long long (in register) to int,short,char */ { SCONV, ININT, SHLL, TLL, SHINT, ANYFIXED, NAREG|NASL, RESC1, "\tcopy\tAL,A1\n", }, /* convert (u)long (in memory) to int,short,char */ { SCONV, ININT, SOREG, TLL, SHINT, ANYFIXED, NAREG|NASL, RESC1, "\tldw\tAL,A1\n", }, /* convert float (in register) to (u)int */ { SCONV, ININT, SHFL, TFLOAT, SHINT, TWORD, NAREG, RESC1, "\tfcnvfxt,sgl,sgl\tAL,AL\n" "\tfstws,ma\tAL,4(%sp)\n" "\tldw,mb\t-4(%sp),A1\n", }, /* convert double (in register) to (u)int */ { SCONV, ININT, SHDBL, TDOUBLE|TLDOUBLE, SHINT, TWORD, NCREG|NCSL|NAREG, RESC1, "\tfcnvfxt,dbl,sgl\tAL,A1\n" "\tfstws,ma\tA1,4(%sp)\n" "\tldw,mb\t-4(%sp),A2\n", }, /* convert float (in register) to (u)long */ { SCONV, INLL, SHFL, TFLOAT, SHLL, TLL, NDREG|NDSL|NBREG, RESC1, "\tfcnvfxt,sgl,dbl\tAL,A1\n" "\tfstds,ma\tA1,8(%sp)\n" "\tldw\t-8(%sp),A2\n" "\tldw\t-4(%sp),U2\n" "\tldo\t-8(%sp),%sp)\n", }, /* convert double (in register) to (u)long */ { SCONV, INLL, SHDBL, TDOUBLE|TLDOUBLE, SHLL, TLL, NBREG, RESC1, "\tfcnvfxt,dbl,dbl\tAL,AL\n" "\tfstds,ma\tAL,8(%sp)\n" "\tldw\t-8(%sp),A1\n" "\tldw\t-4(%sp),U1\n" "\tldo\t-8(%sp),%sp)\n", }, /* * Subroutine calls. */ { CALL, FOREFF, SAREG, TANY, SANY, TANY, 0, 0, "ZP\tblr\t%r0, %rp\n" "\tbv,n\t%r0(AL)\n" "\tnop\nZC", }, { UCALL, FOREFF, SAREG, TANY, SANY, TANY, 0, 0, "ZP\tblr\t%r0, %rp\n" "\tbv,n\t%r0(AL)\n" "\tnop\nZC", }, { CALL, ININT, SAREG, TANY, SHINT, ANYFIXED|TPOINT, NAREG|NASL, RESC1, "ZP\tblr\t%r0, %rp\n" "\tbv,n\t%r0(AL)\n" "\tnop\nZC", }, { UCALL, ININT, SAREG, TANY, SHINT, ANYFIXED|TPOINT, NAREG|NASL, RESC1, "ZP\tblr\t%r0, %rp\n" "\tbv,n\t%r0(AL)\n" "\tnop\nZC", }, { CALL, INLL, SAREG, TANY, SHLL, TLL, NBREG|NBSL, RESC1, "ZP\tblr\t%r0, %rp\n" "\tbv,n\t%r0(AL)\n" "\tnop\nZC", }, { UCALL, INLL, SAREG, TANY, SHLL, TLL, NBREG|NBSL, RESC1, "ZP\tblr\t%r0, %rp\n" "\tbv,n\t%r0(AL)\n" "\tnop\nZC", }, { CALL, INFL, SAREG, TANY, SHFL, TFLOAT, NCREG|NCSL, RESC1, "ZP\tblr\t%r0, %rp\n" "\tbv,n\t%r0(AL)\n" "\tnop\nZC", }, { UCALL, INFL, SAREG, TANY, SHFL, TFLOAT, NCREG|NCSL, RESC1, "ZP\tblr\t%r0, %rp\n" "\tbv,n\t%r0(AL)\n" "\tnop\nZC", }, { CALL, INDBL, SAREG, TANY, SHDBL, TDOUBLE|TLDOUBLE, NDREG|NDSL, RESC1, "ZP\tblr\t%r0, %rp\n" "\tbv,n\t%r0(AL)\n" "\tnop\nZC", }, { UCALL, INDBL, SAREG, TANY, SHDBL, TDOUBLE|TLDOUBLE, NDREG|NDSL, RESC1, "ZP\tblr\t%r0, %rp\n" "\tbv,n\t%r0(AL)\n" "\tnop\nZC", }, /* * The next rules handle all binop-style operators. */ /* TODO fix char/short overflows */ { PLUS, INLL, SHLL, TLL, SPICON, TANY, NBREG|NBSL, RESC1, "\taddi\tAL,AR,A1\n" "\taddc\tUL,%r0,U1\n", }, { PLUS, INLL, SHLL, TLL, SHLL, TLL, NBREG|NBSL|NBSR, RESC1, "\tadd\tAL,AR,A1\n" "\taddc\tUL,UR,U1\n", }, { PLUS, INFL, SHFL, TFLOAT, SHFL, TFLOAT, NCREG|NCSL|NCSR, RESC1, "\tfadd,sgl\tAL,AR,A1\n", }, { PLUS, INDBL, SHDBL, TDOUBLE|TLDOUBLE, SHDBL, TDOUBLE|TLDOUBLE, NDREG|NDSL|NDSR, RESC1, "\tfadd,dbl\tAL,AR,A1\n", }, { PLUS, ININT, SHINT, ANYFIXED|TPOINT, SONE, TANY, NAREG|NASL, RESC1, "\tldo\t1(AL),A1\n", }, { PLUS, ININT, SHINT, ANYFIXED|TPOINT, SPCON, TANY, NAREG|NASL, RESC1, "\tldo\tCR(AL),A1\n", }, { MINUS, INLL, SHLL, TLL, SPICON, TANY, NBREG|NBSL|NBSR, RESC1, "\tsubi\tAL,AR,A1\n" "\tsubb\tUL,%r0,U1\n", }, { PLUS, ININT, SHINT, TANY|TPOINT, SPNAME, TANY, NAREG|NASL, RESC1, "\tldo\tAR(AL),A1\n", }, { MINUS, INLL, SHLL, TLL, SHLL, TLL, NBREG|NBSL|NBSR, RESC1, "\tsub\tAL,AR,A1\n" "\tsubb\tUL,UR,U1\n", }, { MINUS, INFL, SHFL, TFLOAT, SHFL, TFLOAT, NCREG|NCSL|NCSR, RESC1, "\tfsub,sgl\tAL,AR,A1\n", }, { MINUS, INDBL, SHDBL, TDOUBLE|TLDOUBLE, SHDBL, TDOUBLE|TLDOUBLE, NDREG|NDSL|NDSR, RESC1, "\tfsub,dbl\tAL,AR,A1\n", }, { MINUS, ININT, SHINT, ANYFIXED|TPOINT, SONE, TANY, NAREG|NASL, RESC1, "\tldo\t-1(AL),A1\n", }, { MINUS, ININT, SHINT, ANYFIXED|TPOINT, SPCON, TANY, NAREG|NASL, RESC1, "\tldo\t-CR(AL),A1\n", }, /* Simple reg->reg ops */ { OPSIMP, ININT, SAREG, TWORD|TPOINT, SAREG, TWORD|TPOINT, NAREG|NASL, RESC1, "\tO\tAL,AR,A1\n", }, { OPSIMP, INLL, SHLL, TLL, SHLL, TLL, NBREG|NBSL|NBSR, RESC1, "\tO\tAL,AR,A1\n" "\tO\tUL,UR,U1\n", }, /* * The next rules handle all shift operators. */ { LS, ININT, SHINT, ANYFIXED, SCON, ANYFIXED, NAREG|NASL, RESC1, "\tzdep\tAL,31-AR,32-AR,A1\n", }, { LS, ININT, SHINT, ANYFIXED, SHINT, ANYFIXED, NAREG|NASR, RESC1, "\tsubi\t31,AR,A1\n" "\tmtsar\tA1\n" "\tzvdep\tAL,32,A1\n", }, { RS, INLL, SHLL, TLONGLONG, SCON, ANYFIXED, NBREG|NBSL, RESC1, "\tshd\tUL,AL,31-AR,A1\n" "\textrs\tUL,31-AR,32,U1\n", }, { RS, INLL, SHLL, TULONGLONG, SCON, ANYFIXED, NBREG|NBSL, RESC1, "\tshd\tUL,AL,AR,A1\n" "\textru\tUL,31-AR,32,U1\n", }, { RS, ININT, SHINT, ANYSIGNED, SCON, ANYFIXED, NAREG|NASL, RESC1, "\textrs\tAL,31-AR,32,A1\n", }, { RS, ININT, SHINT, ANYUSIGNED, SCON, ANYFIXED, NAREG|NASL, RESC1, "\textru\tAL,31-AR,32,A1\n", }, /* TODO the following should be split into mtsar and actual shift parts */ { RS, ININT, SHINT, ANYSIGNED, SHINT, ANYFIXED, NAREG|NASR, RESC1, "\tsubi\t31,AR,A1\n" "\tmtsar\tA1\n" "\tvextrs\tAL,32,A1\n", }, { RS, ININT, SHINT, ANYUSIGNED, SHINT, ANYFIXED, NAREG|NASR, RESC1, "\tsubi\t31,AR,A1\n" "\tmtsar\tA1\n" "\tvextru\tAL,32,A1\n", }, /* * The next rules takes care of assignments. "=". */ { ASSIGN, FOREFF|INAREG, SAREG, TWORD|TPOINT, SPCON, TANY, 0, RDEST, "\tldi\tAR,AL\n", }, { ASSIGN, FOREFF|INAREG, SOREG, TBYTE, SHINT, TBYTE, 0, RDEST, "\tstb\tAR,AL\n", }, { ASSIGN, FOREFF|INAREG, SOREG, THWORD, SHINT, THWORD, 0, RDEST, "\tsth\tAR,AL\n", }, { ASSIGN, FOREFF|INAREG, SOREG, TWORD|TPOINT, SHINT, TWORD|TPOINT, 0, RDEST, "\tstw\tAR,AL\n", }, { ASSIGN, FOREFF|INLL, SOREG, TLL, SHLL, TLL, 0, RDEST, "\tstw\tAR,AL\n" "\tstw\tUR,UL\n", }, { ASSIGN, FOREFF|INAREG, SHINT, TBYTE, SOREG, TBYTE, 0, RDEST, "\tldb\tAR,AL\n", }, { ASSIGN, FOREFF|INAREG, SHINT, THWORD, SOREG, THWORD, 0, RDEST, "\tldh\tAR,AL\n", }, { ASSIGN, FOREFF|INAREG, SHINT, TWORD|TPOINT, SOREG, TWORD|TPOINT, 0, RDEST, "\tldw\tAR,AL\n", }, { ASSIGN, FOREFF|INLL, SHLL, TLL, SOREG, TLL, 0, RDEST, "\tldw\tAR,AL\n" "\tldw\tUR,UL\n", }, { ASSIGN, FOREFF|ININT, SHINT, TWORD|TPOINT, SHINT, TWORD|TPOINT, 0, RDEST, "\tcopy\tAR,AL\n", }, { ASSIGN, FOREFF|ININT, SHINT, ANYFIXED, SHINT, ANYFIXED, 0, RDEST, "\tcopy\tAR,AL\n", }, { ASSIGN, FOREFF|ININT, SFLD, TANY, SPIMM, TANY, 0, RDEST, "\tdepi\tAR,31-H,S,AL\n", }, { ASSIGN, FOREFF|ININT, SFLD, TANY, SHINT, TANY, 0, RDEST, "\tdep\tAR,31-H,S,AL\n", }, { ASSIGN, FOREFF|INLL, SHLL, TLL, SHLL, TLL, 0, RDEST, "\tcopy\tAR,AL\n" "\tcopy\tUR,UL\n", }, { ASSIGN, FOREFF|INFL, SHFL, TFLOAT, SHFL, TFLOAT, 0, RDEST, "\tfcpy,sgl\tAR,AL\n", }, { ASSIGN, FOREFF|INDBL, SHDBL, TDOUBLE|TLDOUBLE, SHDBL, TDOUBLE|TLDOUBLE, 0, RDEST, "\tfcpy,dbl\tAR,AL\n", }, { ASSIGN, FOREFF|INFL, SHFL, TFLOAT, SOREG, TFLOAT, 0, RDEST, "\tfldws\tAR,AL\n", }, { ASSIGN, FOREFF|INDBL, SHDBL, TDOUBLE|TLDOUBLE, SOREG, TDOUBLE|TLDOUBLE, 0, RDEST, "\tfldds\tAR,AL\n", }, { ASSIGN, FOREFF|INFL, SOREG, TFLOAT, SHFL, TFLOAT, 0, RDEST, "\tfstws\tAR,AL\n", }, { ASSIGN, FOREFF|INDBL, SOREG, TDOUBLE|TLDOUBLE, SHDBL, TDOUBLE|TLDOUBLE, 0, RDEST, "\tfstds\tAR,AL\n", }, /* * DIV/MOD/MUL */ { DIV, INFL, SHFL, TFLOAT, SHFL, TFLOAT, NCREG|NCSL|NCSR, RESC1, "\tfdiv,sgl\tAL,AR,A1\n", }, { DIV, INDBL, SHDBL, TDOUBLE|TLDOUBLE, SHDBL, TDOUBLE|TLDOUBLE, NDREG|NDSL|NDSR, RESC1, "\tfdiv,dbl\tAL,AR,A1\n", }, { MUL, INFL, SHFL, TFLOAT, SHFL, TFLOAT, NCREG|NCSL|NCSR, RESC1, "\tfmul,sgl\tAL,AR,A1\n", }, { MUL, INDBL, SHDBL, TDOUBLE|TLDOUBLE, SHDBL, TDOUBLE|TLDOUBLE, NDREG|NDSL|NDSR, RESC1, "\tfmul,dbl\tAL,AR,A1\n", }, /* * Indirection operators. */ { UMUL, INLL, SANY, TANY, SOREG, TLL, NBREG, RESC1, "\tldw\tAL,A1\n" "\tldw\tUL,U1\n", }, { UMUL, ININT, SANY, TPOINT|TWORD, SOREG, TPOINT|TWORD, NAREG|NASL, RESC1, "\tldw\tAL,A1\n", }, { UMUL, ININT, SANY, TANY, SOREG, THWORD, NAREG|NASL, RESC1, "\tldh\tAL,A1\n", }, { UMUL, ININT, SANY, TANY, SOREG, TBYTE, NAREG|NASL, RESC1, "\tldb\tAL,A1\n", }, { UMUL, INDBL, SANY, TANY, SOREG, TDOUBLE|TLDOUBLE, NDREG|NDSL, RESC1, "\tfldds\tAL,A1\n", }, { UMUL, INFL, SANY, TANY, SOREG, TFLOAT, NCREG|NCSL, RESC1, "\tfldws\tAL,A1\n", }, /* * Logical/branching operators */ { OPLOG, FORCC, SHLL, TLL, SHLL, TLL, 0, 0, "ZD", }, { OPLOG, FORCC, SHINT, ANYFIXED|TPOINT, SPIMM, ANYFIXED|TPOINT, 0, 0, "\tcomib,O\tAR,AL,LC\n\tnop\n", }, { OPLOG, FORCC, SHINT, ANYFIXED|TPOINT, SHINT, ANYFIXED|TPOINT, 0, 0, "\tcomb,O\tAR,AL,LC\n\tnop\n", }, { OPLOG, FORCC, SHFL, TFLOAT, SHFL, TFLOAT, 0, RESCC, "\tfcmp,sgl,!O\tAR,AL\n" "\tftest\n" "\tb\tLC\n" "\tnop", }, { OPLOG, FORCC, SHDBL, TDOUBLE|TLDOUBLE, SHDBL, TDOUBLE|TLDOUBLE, 0, RESCC, "\tfcmp,dbl,!O\tAR,AL\n" "\tftest\n" "\tb\tLC\n" "\tnop", }, /* * Jumps. */ { GOTO, FOREFF, SCON, TANY, SANY, TANY, 0, RNOP, "\tb\tLL\n\tnop\n", }, #ifdef GCC_COMPAT { GOTO, FOREFF, SAREG, TANY, SANY, TANY, 0, RNOP, "\tbv\t%r0(AL)\n\tnop\n", }, #endif /* * Convert LTYPE to reg. */ { OPLTYPE, INAREG, SAREG, TANY, SNAME, TANY, 0, RDEST, "\taddil\tUR,%r27\n", }, { OPLTYPE, INAREG, SAREG, TANY, SCON, TPOINT, 0, RDEST, "\taddil\tUR,%r27\n", }, { OPLTYPE, INLL, SANY, TANY, SOREG, TLL, NBREG|NBSL, RESC1, "\tldw\tAL,A1\n" "\tldw\tUL,U1\n", }, { OPLTYPE, INAREG, SANY, TANY, SOREG, TWORD|TPOINT, NAREG|NASL, RESC1, "\tldw\tAL,A1\n", }, { OPLTYPE, INAREG, SANY, TANY, SAREG, TWORD|TPOINT, NAREG|NASL, RESC1, "\tcopy\tAL,A1\n", }, { OPLTYPE, INAREG, SANY, TANY, SPCNHI, ANYFIXED, NAREG, RESC1, "\tldil\tUR,A1\n", }, { OPLTYPE, INAREG, SANY, TANY, SPCON, ANYFIXED, NAREG, RESC1, "\tldi\tAR,A1\n", }, { OPLTYPE, INLL, SANY, TANY, SPCON, TLL, NBREG, RESC1, "\tldi\tAR,A1\n" "\tcopy\t%r0,U1\n", }, { OPLTYPE, ININT, SANY, TANY, SCON, TWORD, NAREG, RESC1, "\tldil\tUR,A1\n" "\tldo\tAR(A1),A1\n", }, { OPLTYPE, INLL, SHLL, TLL, SPCNHW, TLL, NBREG, RESC1, "\tldil\tUR>>32,U1\n" "\tldo\tAR>>32(U1),U1\n" "\tcopy\t%r0,A1\n", }, { OPLTYPE, INLL, SHLL, TLL, SPCNLW, TLL, NBREG, RESC1, "\tcopy\t%r0,U1\n" "\tldil\tUR,A1\n" "\tldo\tAR(A1),A1\n", }, { OPLTYPE, INLL, SHLL, TLL, SCON, TLL, NBREG, RESC1, "\tldil\tUR,A1\n" "\tldo\tAR(A1),A1\n" "\tldil\tUR>>32,U1\n" "\tldo\tAR>>32(U1),U1\n", }, { OPLTYPE, INCREG, SANY, TFLOAT, SHFL, TFLOAT, NCREG, RESC1, "\tfldws\tAL,A1\n", }, { OPLTYPE, INDREG, SANY, TDOUBLE|TLDOUBLE, SHDBL, TDOUBLE|TLDOUBLE, NDREG, RESC1, "\tfldds\tAL,A1\n", }, /* * Negate a word. */ { UMINUS, INLL, SHLL, TLL, SHLL, TLL, NBREG|NBSL, RESC1, "\tsub\t%r0,AL,A1\n" "\tsubb\t%r0,UL,A1\n", }, { UMINUS, ININT, SHINT, TWORD, SHINT, TWORD, NAREG|NASL, RESC1, "\tsub\t%r0,AL,A1\n", }, { UMINUS, INFL, SHFL, TFLOAT, SHFL, TFLOAT, NCREG|NCSL, RESC1, "\tfsub,sgl\t%fr0,AL,A1\n", }, { UMINUS, INDBL, SHDBL, TDOUBLE|TLDOUBLE, SHDBL, TDOUBLE|TLDOUBLE, NDREG|NDSL, RESC1, "\tfsub,dbl\t%fr0,AL,A1\n", }, { COMPL, INLL, SHLL, TLL, SANY, TANY, NBREG|NBSL, RESC1, "\tuaddcm\t%r0,AL,A1\n" "\tuaddcm\t%r0,UL,U1\n", }, { COMPL, ININT, SHINT, ANYFIXED, SANY, TANY, NAREG|NASL, RESC1, "\tuaddcm\t%r0,AL,A1\n", }, /* * Arguments to functions. */ { STARG, FOREFF, SAREG|SOREG|SNAME|SCON, TANY, SANY, TSTRUCT, NAREG | RNULL, 0, "ZS", }, /* * struct field ops */ { FLD, ININT, SHINT, TANY, SFLD, ANYSIGNED, NAREG|NASL, RESC1, "\textrs\tAL,31-H,S,A1\n", }, { FLD, ININT, SHINT, TANY, SFLD, ANYUSIGNED, NAREG|NASL, RESC1, "\textru\tAL,31-H,S,A1\n", }, # define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,"" { UMUL, DF( UMUL ), }, { ASSIGN, DF(ASSIGN), }, { STASG, DF(STASG), }, { FLD, DF(FLD), }, { OPLEAF, DF(NAME), }, /* { INIT, DF(INIT), }, */ { OPUNARY, DF(UMINUS), }, { OPANY, DF(BITYPE), }, { FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "HELP; I'm in trouble\n" }, }; int tablesize = sizeof(table)/sizeof(table[0]); pcc-20181216/arch/i386004075500017500000000000000000001340533064000130145ustar raggewheelpcc-20181216/arch/i386/CVS004075500017500000000000000000001340533064000134475ustar raggewheelpcc-20181216/arch/i386/CVS/Root010064400017500000000000000000111340533064000143610ustar raggewheel/cvsroot pcc-20181216/arch/i386/CVS/Repository010064400017500000000000000000161340533064000156220ustar raggewheelpcc/arch/i386 pcc-20181216/arch/i386/CVS/Entries010064400017500000000000000004501340533064000150560ustar raggewheel/code.c/1.101/Wed Nov 21 18:21:34 2018// /flocal.c/1.17/Sun Apr 22 21:07:40 2012// /local.c/1.207/Wed Nov 21 18:22:33 2018// /local2.c/1.192/Wed Nov 21 18:20:31 2018// /macdefs.h/1.99/Sat Jul 28 09:39:11 2018// /order.c/1.64/Sat Mar 11 09:22:09 2017// /table.c/1.150/Wed Nov 21 18:20:31 2018// D pcc-20181216/arch/i386/code.c010064400017500000000000000422521337532105600141620ustar raggewheel/* $Id: code.c,v 1.101 2018/11/21 18:21:34 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass1.h" #ifdef LANG_CXX #define p1listf listf #define p1tfree tfree #else #define NODE P1ND #define talloc p1alloc #endif /* * Print out assembler segment name. */ void setseg(int seg, char *name) { switch (seg) { case PROG: name = ".text"; break; case DATA: case LDATA: name = ".data"; break; case UDATA: break; #ifdef MACHOABI case PICLDATA: case PICDATA: name = ".section .data.rel.rw,\"aw\""; break; case PICRDATA: name = ".section .data.rel.ro,\"aw\""; break; case STRNG: name = ".cstring"; break; case RDATA: name = ".const_data"; break; #else case PICLDATA: name = ".section .data.rel.local,\"aw\",@progbits";break; case PICDATA: name = ".section .data.rel.rw,\"aw\",@progbits"; break; case PICRDATA: name = ".section .data.rel.ro,\"aw\",@progbits"; break; case STRNG: #ifdef AOUTABI case RDATA: name = ".data"; break; #else case RDATA: name = ".section .rodata"; break; #endif #endif case TLSDATA: name = ".section .tdata,\"awT\",@progbits"; break; case TLSUDATA: name = ".section .tbss,\"awT\",@nobits"; break; #ifdef MACHOABI case CTORS: name = ".mod_init_func\n\t.align 2"; break; case DTORS: name = ".mod_term_func\n\t.align 2"; break; #else case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break; case DTORS: name = ".section\t.dtors,\"aw\",@progbits"; break; #endif case NMSEG: printf(PRTPREF "\t.section %s,\"a%c\",@progbits\n", name, cftnsp ? 'x' : 'w'); return; } printf(PRTPREF "\t%s\n", name); } #ifdef MACHOABI void defalign(int al) { printf(PRTPREF "\t.align %d\n", ispow2(al/ALCHAR)); } #endif /* * Define everything needed to print out some data (or text). * This means segment, alignment, visibility, etc. */ void defloc(struct symtab *sp) { char *name; name = getexname(sp); if (sp->sclass == EXTDEF) { printf(PRTPREF " .globl %s\n", name); #if defined(ELFABI) printf(PRTPREF "\t.type %s,@%s\n", name, ISFTN(sp->stype)? "function" : "object"); #endif } #if defined(ELFABI) if (!ISFTN(sp->stype)) { if (sp->slevel == 0) printf(PRTPREF "\t.size %s,%d\n", name, (int)tsize(sp->stype, sp->sdf, sp->sap)/SZCHAR); else printf(PRTPREF "\t.size " LABFMT ",%d\n", sp->soffset, (int)tsize(sp->stype, sp->sdf, sp->sap)/SZCHAR); } #endif if (sp->slevel == 0) printf(PRTPREF "%s:\n", name); else printf(PRTPREF LABFMT ":\n", sp->soffset); } int structrettemp; /* * code for the end of a function * deals with struct return here */ void efcode(void) { extern int gotnr; NODE *p, *q; int sz; gotnr = 0; /* new number for next fun */ if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) return; /* struct return for small structs */ sz = (int)tsize(BTYPE(cftnsp->stype), cftnsp->sdf, cftnsp->sap); #if defined(os_openbsd) if (sz == SZCHAR || sz == SZSHORT || sz == SZINT || sz == SZLONGLONG) { #else if (sz == SZLONGLONG && attr_find(cftnsp->sap, ATTR_COMPLEX)) { #endif /* Pointer to struct in eax */ if (sz == SZLONGLONG) { q = block(OREG, NIL, NIL, INT, 0, 0); slval(q, 4); p = block(REG, NIL, NIL, INT, 0, 0); p->n_rval = EDX; ecomp(buildtree(ASSIGN, p, q)); } if (sz < SZSHORT) sz = CHAR; else if (sz > SZSHORT) sz = INT; else sz = SHORT; q = block(OREG, NIL, NIL, sz, 0, 0); if (sz < SZINT) q = cast(q, INT, 0); p = block(REG, NIL, NIL, INT, 0, 0); p = (buildtree(ASSIGN, p, q)); ecomp(p); return; } /* Create struct assignment */ q = tempnode(structrettemp, PTR+STRTY, 0, cftnsp->sap); q = buildtree(UMUL, q, NIL); p = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap); p = buildtree(UMUL, p, NIL); p = buildtree(ASSIGN, q, p); ecomp(p); /* put hidden arg in eax on return */ q = tempnode(structrettemp, INT, 0, 0); p = block(REG, NIL, NIL, INT, 0, 0); regno(p) = EAX; ecomp(buildtree(ASSIGN, p, q)); } #ifdef GCC_COMPAT static TWORD reparegs[] = { EAX, EDX, ECX }; static TWORD fastregs[] = { ECX, EDX }; #endif static TWORD longregs[] = { EAXEDX, EDXECX }; #ifdef NOBREGS static TWORD charregs[] = { EAX, EDX, ECX }; #else static TWORD charregs[] = { AL, DL, CL }; #endif static TWORD *regpregs; /* * code for the beginning of a function; a is an array of * indices in symtab for the arguments; n is the number * * Classifying args on i386; not simple: * - Args may be on stack or in registers (regparm) * - There may be a hidden first arg, unless OpenBSD struct return. * - Regparm syntax is not well documented. * - There may be stdcall functions, where the called function pops stack * - ...probably more */ void bfcode(struct symtab **sp, int cnt) { extern int argstacksize; #ifdef GCC_COMPAT struct attr *ap; #endif struct symtab *sp2; extern int gotnr; NODE *n, *p; int i, regparmarg; int argbase, nrarg, sz; /* Take care of PIC stuff first */ if (kflag) { #define STL 200 char *str = xmalloc(STL); #if !defined(MACHOABI) int l = getlab(); #else char *name; #endif /* Generate extended assembler for PIC prolog */ p = tempnode(0, INT, 0, 0); gotnr = regno(p); p = block(XARG, p, NIL, INT, 0, 0); p->n_name = "=g"; p = block(XASM, p, bcon(0), INT, 0, 0); #if defined(MACHOABI) if ((name = cftnsp->soname) == NULL) name = cftnsp->sname; if (snprintf(str, STL, "call L%s$pb\nL%s$pb:\n\tpopl %%0\n", name, name) >= STL) cerror("bfcode"); #else if (snprintf(str, STL, "call " LABFMT ";" LABFMT ":;\tpopl %%0;" "\taddl $_GLOBAL_OFFSET_TABLE_+[.-" LABFMT "], %%0;", l, l, l) >= STL) cerror("bfcode"); #endif p->n_name = addstring(str); p->n_right->n_type = STRTY; free(str); ecomp(p); } argbase = ARGINIT; nrarg = regparmarg = 0; argstacksize = 0; #ifdef GCC_COMPAT regpregs = reparegs; if ((ap = attr_find(cftnsp->sap, GCC_ATYP_REGPARM))) regparmarg = ap->iarg(0); if ((ap = attr_find(cftnsp->sap, GCC_ATYP_FASTCALL))) regparmarg = 2, regpregs = fastregs; #endif /* Function returns struct, create return arg node */ if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { sz = (int)tsize(BTYPE(cftnsp->stype), cftnsp->sdf, cftnsp->sap); #if defined(os_openbsd) /* OpenBSD uses non-standard return for small structs */ if (sz > SZLONGLONG) #else if (sz != SZLONGLONG || attr_find(cftnsp->sap, ATTR_COMPLEX) == 0) #endif { if (regparmarg) { n = block(REG, 0, 0, INT, 0, 0); regno(n) = regpregs[nrarg++]; } else { n = block(OREG, 0, 0, INT, 0, 0); slval(n, argbase/SZCHAR); argbase += SZINT; regno(n) = FPREG; argstacksize += 4; /* popped by callee */ } p = tempnode(0, INT, 0, 0); structrettemp = regno(p); p = buildtree(ASSIGN, p, n); ecomp(p); } } /* * Find where all params are so that they end up at the right place. * At the same time recalculate their arg offset on stack. * We also get the "pop size" for stdcall. */ for (i = 0; i < cnt; i++) { sp2 = sp[i]; sz = (int)tsize(sp2->stype, sp2->sdf, sp2->sap); SETOFF(sz, SZINT); if (cisreg(sp2->stype) == 0 || ((regparmarg - nrarg) * SZINT < sz)) { /* not in reg */ sp2->soffset = argbase; argbase += sz; nrarg = regparmarg; /* no more in reg either */ } else { /* in reg */ sp2->soffset = regpregs[nrarg]; nrarg += sz/SZINT; sp2->sclass = REGISTER; } } /* * Now (argbase - ARGINIT) is used space on stack. * Move (if necessary) the args to something new. */ for (i = 0; i < cnt; i++) { int reg, j; sp2 = sp[i]; if ((ISSOU(sp2->stype) && sp2->sclass == REGISTER) || (sp2->sclass == REGISTER && xtemps == 0)) { /* must move to stack */ sz = (int)tsize(sp2->stype, sp2->sdf, sp2->sap); SETOFF(sz, SZINT); SETOFF(autooff, SZINT); reg = sp2->soffset; sp2->sclass = AUTO; sp2->soffset = NOOFFSET; oalloc(sp2, &autooff); for (j = 0; j < sz/SZCHAR; j += 4) { p = block(OREG, 0, 0, INT, 0, 0); slval(p, sp2->soffset/SZCHAR + j); regno(p) = FPREG; n = block(REG, 0, 0, INT, 0, 0); regno(n) = regpregs[reg++]; p = block(ASSIGN, p, n, INT, 0, 0); ecomp(p); } } else if (cisreg(sp2->stype) && !ISSOU(sp2->stype) && ((cqual(sp2->stype, sp2->squal) & VOL) == 0) && xtemps) { /* just put rest in temps */ if (sp2->sclass == REGISTER) { n = block(REG, 0, 0, sp2->stype, sp2->sdf, sp2->sap); if (ISLONGLONG(sp2->stype)) regno(n) = longregs[sp2->soffset]; else if (DEUNSIGN(sp2->stype) == CHAR || sp2->stype == BOOL) regno(n) = charregs[sp2->soffset]; else regno(n) = regpregs[sp2->soffset]; } else { n = block(OREG, 0, 0, sp2->stype, sp2->sdf, sp2->sap); slval(n, sp2->soffset/SZCHAR); regno(n) = FPREG; } p = tempnode(0, sp2->stype, sp2->sdf, sp2->sap); sp2->soffset = regno(p); sp2->sflags |= STNODE; n = buildtree(ASSIGN, p, n); ecomp(n); } } if (attr_find(cftnsp->sap, GCC_ATYP_STDCALL)) { #ifdef PECOFFABI char buf[256]; char *name; #endif /* XXX interaction STDCALL and struct return? */ argstacksize += (argbase - ARGINIT)/SZCHAR; #ifdef PECOFFABI /* * mangle name in symbol table as a callee. */ if ((name = cftnsp->soname) == NULL) name = exname(cftnsp->sname); snprintf(buf, 256, "%s@%d", name, argstacksize); cftnsp->soname = addname(buf); #endif } } #if defined(MACHOABI) struct stub stublist; struct stub nlplist; #endif /* called just before final exit */ /* flag is 1 if errors, 0 if none */ void ejobcode(int flag) { #if defined(MACHOABI) /* * iterate over the stublist and output the PIC stubs ` */ if (kflag) { struct stub *p; DLIST_FOREACH(p, &stublist, link) { printf(PRTPREF "\t.section __IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5\n"); printf(PRTPREF "L%s$stub:\n", p->name); printf(PRTPREF "\t.indirect_symbol %s\n", p->name); printf(PRTPREF "\thlt ; hlt ; hlt ; hlt ; hlt\n"); printf(PRTPREF "\t.subsections_via_symbols\n"); } printf(PRTPREF "\t.section __IMPORT,__pointers,non_lazy_symbol_pointers\n"); DLIST_FOREACH(p, &nlplist, link) { printf(PRTPREF "L%s$non_lazy_ptr:\n", p->name); printf(PRTPREF "\t.indirect_symbol %s\n", p->name); printf(PRTPREF "\t.long 0\n"); } } #endif printf(PRTPREF "\t.ident \"PCC: %s\"\n", VERSSTR); } void bjobcode(void) { #ifdef os_sunos astypnames[SHORT] = astypnames[USHORT] = "\t.2byte"; #endif astypnames[INT] = astypnames[UNSIGNED] = "\t.long"; #if defined(MACHOABI) DLIST_INIT(&stublist, link); DLIST_INIT(&nlplist, link); #endif #if defined(__GNUC__) || defined(__PCC__) /* Be sure that the compiler uses full x87 */ /* XXX cross-compiling will fail here */ volatile int fcw; __asm("fstcw (%0)" : : "r"(&fcw)); fcw |= 0x300; __asm("fldcw (%0)" : : "r"(&fcw)); #endif } /* * Convert FUNARG to assign in case of regparm. */ static int regcvt, rparg, fcall; static void addreg(NODE *p) { TWORD t; NODE *q; int sz, r; sz = (int)tsize(p->n_type, p->n_df, p->n_ap)/SZCHAR; sz = (sz + 3) >> 2; /* sz in regs */ if ((regcvt+sz) > rparg) { regcvt = rparg; return; } if (sz > 2) uerror("cannot put struct in 3 regs (yet)"); if (sz == 2) r = regcvt == 0 ? EAXEDX : EDXECX; else if (fcall) r = regcvt == 0 ? ECX : EDX; else r = regcvt == 0 ? EAX : regcvt == 1 ? EDX : ECX; if (p->n_op == FUNARG) { /* at most 2 regs */ if (p->n_type < INT) { p->n_left = ccast(p->n_left, INT, 0, 0, 0); p->n_type = INT; } p->n_op = ASSIGN; p->n_right = p->n_left; } else if (p->n_op == STARG) { /* convert to ptr, put in reg */ q = p->n_left; t = sz == 2 ? LONGLONG : INT; q = cast(q, INCREF(t), 0); q = buildtree(UMUL, q, NIL); p->n_op = ASSIGN; p->n_type = t; p->n_right = q; } else cerror("addreg"); p->n_left = block(REG, 0, 0, p->n_type, 0, 0); regno(p->n_left) = r; regcvt += sz; } /* * Called with a function call with arguments as argument. * This is done early in buildtree() and only done once. * Returns p. */ NODE * funcode(NODE *p) { extern int gotnr; struct attr *ap; NODE *r, *l; TWORD t = DECREF(DECREF(p->n_left->n_type)); int stcall; stcall = ISSOU(t); /* * We may have to prepend: * - Hidden arg0 for struct return (in reg or on stack). * - ebx in case of PIC code. */ /* Fix function call arguments. On x86, just add funarg */ for (r = p->n_right; r->n_op == CM; r = r->n_left) { if (r->n_right->n_op != STARG) r->n_right = block(FUNARG, r->n_right, NIL, r->n_right->n_type, r->n_right->n_df, r->n_right->n_ap); } if (r->n_op != STARG) { l = talloc(); *l = *r; r->n_op = FUNARG; r->n_left = l; r->n_type = l->n_type; } #ifdef os_openbsd if (stcall && (ap = strattr(p->n_left->n_ap)) && ap->amsize != SZCHAR && ap->amsize != SZSHORT && ap->amsize != SZINT && ap->amsize != SZLONGLONG) #else if (stcall && (attr_find(p->n_left->n_ap, ATTR_COMPLEX) == 0 || ((ap = strattr(p->n_left->n_ap)) && ap->amsize > SZLONGLONG))) #endif { /* Prepend a placeholder for struct address. */ /* Use EBP, can never show up under normal circumstances */ l = talloc(); *l = *r; r->n_op = CM; r->n_right = l; r->n_type = INT; l = block(REG, 0, 0, INCREF(VOID), 0, 0); regno(l) = EBP; l = block(FUNARG, l, 0, INCREF(VOID), 0, 0); r->n_left = l; } #ifdef GCC_COMPAT fcall = 0; if ((ap = attr_find(p->n_left->n_ap, GCC_ATYP_REGPARM))) rparg = ap->iarg(0); else if ((ap = attr_find(p->n_left->n_ap, GCC_ATYP_FASTCALL))) fcall = rparg = 2; else #endif rparg = 0; regcvt = 0; if (rparg) p1listf(p->n_right, addreg); if (kflag == 0) return p; #if defined(ELFABI) /* Create an ASSIGN node for ebx */ l = block(REG, NIL, NIL, INT, 0, 0); l->n_rval = EBX; l = buildtree(ASSIGN, l, tempnode(gotnr, INT, 0, 0)); if (p->n_right->n_op != CM) { p->n_right = block(CM, l, p->n_right, INT, 0, 0); } else { for (r = p->n_right; r->n_left->n_op == CM; r = r->n_left) ; r->n_left = block(CM, l, r->n_left, INT, 0, 0); } #endif return p; } /* fix up type of field p */ void fldty(struct symtab *p) { } /* * XXX - fix genswitch. */ int mygenswitch(int num, TWORD type, struct swents **p, int n) { return 0; } NODE * builtin_return_address(const struct bitable *bt, NODE *a) { int nframes; NODE *f; if (a->n_op != ICON) goto bad; nframes = (int)glval(a); p1tfree(a); f = block(REG, NIL, NIL, PTR+VOID, 0, 0); regno(f) = FPREG; while (nframes--) f = block(UMUL, f, NIL, PTR+VOID, 0, 0); f = block(PLUS, f, bcon(4), INCREF(PTR+VOID), 0, 0); f = buildtree(UMUL, f, NIL); return f; bad: uerror("bad argument to __builtin_return_address"); return bcon(0); } NODE * builtin_frame_address(const struct bitable *bt, NODE *a) { int nframes; NODE *f; if (a->n_op != ICON) goto bad; nframes = (int)glval(a); p1tfree(a); f = block(REG, NIL, NIL, PTR+VOID, 0, 0); regno(f) = FPREG; while (nframes--) f = block(UMUL, f, NIL, PTR+VOID, 0, 0); return f; bad: uerror("bad argument to __builtin_frame_address"); return bcon(0); } /* * Return "canonical frame address". */ NODE * builtin_cfa(const struct bitable *bt, NODE *a) { uerror("missing builtin_cfa"); return bcon(0); } pcc-20181216/arch/i386/flocal.c010064400017500000000000000111031174507143400145000ustar raggewheel/* $Id: flocal.c,v 1.17 2012/04/22 21:07:40 plunky Exp $ */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code and documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditionsand the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "defines.h" #include "defs.h" void prchars(int *s) { printf("\t.byte 0%o,0%o\n", s[0], s[1]); } void setloc(int l) { static int lastloc = -1; static char *loctbl[] = { "text", "data", "section .rodata", "section .rodata", "bss" }; if (l == lastloc) return; printf("\t.%s\n", loctbl[l]); lastloc = l; } #ifdef FCOM /* PDP11-780/VAX - SPECIFIC PRINTING ROUTINES */ /* * Called just before return from a subroutine. */ void goret(int type) { } /* * Print out a label. */ void prlabel(int k) { printf(LABFMT ":\n", k); } /* * Print naming for location. * name[0] is location type. */ void prnloc(char *name) { if (*name == '0') setloc(DATA); else fatal("unhandled prnloc %c", *name); printf("%s:\n", name+1); } /* * Print integer constant. */ void prconi(FILE *fp, int type, ftnint n) { fprintf(fp, "\t%s\t%ld\n", (type==TYSHORT ? ".word" : ".long"), n); } /* * Print address constant, given as a label number. */ void prcona(ftnint a) { printf("\t.long\t" LABFMT "\n", (int)a); } /* * Print out a floating constant. */ void prconr(FILE *fp, int type, double x) { fprintf(fp, "\t%s\t0f%e\n", (type==TYREAL ? ".float" : ".double"), x); } void preven(int k) { if (k > 1) printf("\t.align\t%d\n", k); } /* * Convert a tag and offset into the symtab table to a string. * An external string is never longer than XL bytes. */ char * memname(int stg, int mem) { #define MLEN (XL + 10) char *s = malloc(MLEN); switch(stg) { case STGCOMMON: case STGEXT: snprintf(s, MLEN, "%s", varstr(XL, extsymtab[mem].extname)); break; case STGBSS: case STGINIT: snprintf(s, MLEN, "v.%d", mem); break; case STGCONST: snprintf(s, MLEN, ".L%d", mem); break; case STGEQUIV: snprintf(s, MLEN, "q.%d", mem); break; default: fatal1("memname: invalid vstg %d", stg); } return(s); } void prlocvar(char *s, ftnint len) { printf("\t.lcomm\t%s,%ld\n", s, len); } void prext(char *name, ftnint leng, int init) { if(leng == 0) printf("\t.globl\t%s\n", name); else printf("\t.comm\t%s,%ld\n", name, leng); } void prendproc(void) { } void prtail(void) { } void prolog(struct entrypoint *ep, struct bigblock *argvec) { /* Ignore for now. ENTRY is not supported */ } void prdbginfo(void) { } static void fcheck(NODE *p, void *arg) { NODE *r, *l; switch (p->n_op) { case CALL: /* fix arguments */ for (r = p->n_right; r->n_op == CM; r = r->n_left) { r->n_right = mkunode(FUNARG, r->n_right, 0, r->n_right->n_type); } l = talloc(); *l = *r; r->n_op = FUNARG; r->n_left = l; r->n_type = l->n_type; break; } } /* * Called just before the tree is written out to pass2. */ void p2tree(NODE *p); void p2tree(NODE *p) { walkf(p, fcheck, 0); } #endif /* FCOM */ pcc-20181216/arch/i386/local.c010064400017500000000000000663221337532115100143420ustar raggewheel/* $Id: local.c,v 1.207 2018/11/21 18:22:33 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "pass1.h" #undef NIL #define NIL NULL #ifdef LANG_CXX #define P1ND NODE #define p1nfree nfree #define p1fwalk fwalk #define p1tcopy tcopy #endif /* this file contains code which is dependent on the target machine */ #ifdef notyet /* * Check if a constant is too large for a type. */ static int toolarge(TWORD t, CONSZ con) { U_CONSZ ucon = con; switch (t) { case ULONGLONG: case LONGLONG: break; /* cannot be too large */ #define SCHK(i) case i: if (con > MAX_##i || con < MIN_##i) return 1; break #define UCHK(i) case i: if (ucon > MAX_##i) return 1; break SCHK(INT); SCHK(SHORT); case BOOL: SCHK(CHAR); UCHK(UNSIGNED); UCHK(USHORT); UCHK(UCHAR); default: cerror("toolarge"); } return 0; } #endif static char * getsoname(struct symtab *sp) { struct attr *ap; return (ap = attr_find(sp->sap, ATTR_SONAME)) ? ap->sarg(0) : sp->sname; } #if defined(MACHOABI) /* * Keep track of PIC stubs. */ void addstub(struct stub *list, char *name) { struct stub *s; DLIST_FOREACH(s, list, link) { if (strcmp(s->name, name) == 0) return; } s = permalloc(sizeof(struct stub)); s->name = newstring(name, strlen(name)); DLIST_INSERT_BEFORE(list, s, link); } #endif #define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz)) /* * Make a symtab entry for PIC use. */ static struct symtab * picsymtab(char *p, char *s, char *s2) { struct symtab *sp = IALLOC(sizeof(struct symtab)); size_t len = strlen(p) + strlen(s) + strlen(s2) + 1; sp->sname = IALLOC(len); strlcpy(sp->sname, p, len); strlcat(sp->sname, s, len); strlcat(sp->sname, s2, len); sp->sap = attr_new(ATTR_SONAME, 1); sp->sap->sarg(0) = sp->sname; sp->sclass = EXTERN; sp->sflags = sp->slevel = 0; sp->stype = 0xdeadbeef; return sp; } #ifdef PECOFFABI static P1ND * import(P1ND *p) { struct attr *ap; P1ND *q; char *name; struct symtab *sp; name = getexname(p->n_sp); sp = picsymtab("__imp_", name, ""); q = xbcon(0, sp, PTR+VOID); q = block(UMUL, q, 0, PTR|VOID, 0, 0); q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); q->n_sp = p->n_sp; /* for init */ p1nfree(p); return q; } #endif int gotnr; /* tempnum for GOT register */ int argstacksize; /* * Create a reference for an extern variable. */ static P1ND * picext(P1ND *p) { struct attr *ap; #if defined(ELFABI) P1ND *q, *r; struct symtab *sp; char *name; q = tempnode(gotnr, PTR|VOID, 0, 0); name = getexname(p->n_sp); #ifdef GCC_COMPAT if ((ap = attr_find(p->n_sp->sap, GCC_ATYP_VISIBILITY)) && strcmp(ap->sarg(0), "hidden") == 0) { /* For hidden vars use GOTOFF */ sp = picsymtab("", name, "@GOTOFF"); r = xbcon(0, sp, INT); q = buildtree(PLUS, q, r); q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); q->n_sp = p->n_sp; /* for init */ p1nfree(p); return q; } #endif sp = picsymtab("", name, "@GOT"); sp->sap = attr_add(p->n_sp->sap, sp->sap); r = xbcon(0, sp, INT); q = buildtree(PLUS, q, r); q = block(UMUL, q, 0, PTR|VOID, 0, 0); q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); q->n_sp = p->n_sp; /* for init */ p1nfree(p); return q; #elif defined(MACHOABI) P1ND *q, *r; struct symtab *sp; char buf2[256], *name, *pspn; name = getsoname(cftnsp); pspn = getexname(p->n_sp); if (p->n_sp->sclass == EXTDEF) { snprintf(buf2, 256, "-L%s$pb", name); sp = picsymtab("", pspn, buf2); } else { snprintf(buf2, 256, "$non_lazy_ptr-L%s$pb", name); sp = picsymtab("L", pspn, buf2); addstub(&nlplist, pspn); } sp->stype = p->n_sp->stype; q = tempnode(gotnr, PTR+VOID, 0, 0); r = xbcon(0, sp, INT); q = buildtree(PLUS, q, r); if (p->n_sp->sclass != EXTDEF) q = block(UMUL, q, 0, PTR+VOID, 0, 0); q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); q->n_sp = p->n_sp; /* for init */ p1nfree(p); return q; #else /* defined(PECOFFABI) || defined(AOUTABI) */ return p; #endif } /* * Create a reference for a static variable. */ static P1ND * picstatic(P1ND *p) { #if defined(ELFABI) P1ND *q, *r; struct symtab *sp; q = tempnode(gotnr, PTR|VOID, 0, 0); if (p->n_sp->slevel > 0) { char buf[32]; if ((p->n_sp->sflags & SMASK) == SSTRING) p->n_sp->sflags |= SASG; snprintf(buf, 32, LABFMT, (int)p->n_sp->soffset); sp = picsymtab("", buf, "@GOTOFF"); } else sp = picsymtab("", getsoname(p->n_sp), "@GOTOFF"); sp->sclass = STATIC; sp->stype = p->n_sp->stype; r = xbcon(0, sp, INT); q = buildtree(PLUS, q, r); q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); q->n_sp = p->n_sp; /* for init */ p1nfree(p); return q; #elif defined(MACHOABI) P1ND *q, *r; struct symtab *sp; char buf2[256]; snprintf(buf2, 256, "-L%s$pb", cftnsp->soname ? cftnsp->soname : cftnsp->sname); if (p->n_sp->slevel > 0) { char buf1[32]; snprintf(buf1, 32, LABFMT, (int)p->n_sp->soffset); sp = picsymtab("", buf1, buf2); } else { char *name = getexname(p->n_sp); sp = picsymtab("", name, buf2); } sp->sclass = STATIC; sp->stype = p->n_sp->stype; q = tempnode(gotnr, PTR+VOID, 0, 0); r = xbcon(0, sp, INT); q = buildtree(PLUS, q, r); q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); q->n_sp = p->n_sp; p1nfree(p); return q; #else /* defined(PECOFFABI) || defined(AOUTABI) */ return p; #endif } #ifdef TLS /* * Create a reference for a TLS variable. */ static P1ND * tlspic(P1ND *p) { P1ND *q, *r; struct symtab *sp, *sp2; char *name; /* * creates: * leal var@TLSGD(%ebx),%eax * call ___tls_get_addr@PLT */ /* calc address of var@TLSGD */ q = tempnode(gotnr, PTR|VOID, 0, 0); name = getsoname(p->n_sp); sp = picsymtab("", name, "@TLSGD"); r = xbcon(0, sp, INT); q = buildtree(PLUS, q, r); /* assign to %eax */ r = block(REG, NIL, NIL, PTR|VOID, 0, 0); r->n_rval = EAX; q = buildtree(ASSIGN, r, q); /* call ___tls_get_addr */ sp2 = lookup("___tls_get_addr@PLT", 0); sp2->stype = EXTERN|INT|FTN; r = nametree(sp2); r = buildtree(ADDROF, r, NIL); r = block(UCALL, r, NIL, INT, 0, 0); /* fusion both parts together */ q = buildtree(COMOP, q, r); q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); q->n_sp = p->n_sp; /* for init */ p1nfree(p); return q; } static P1ND * tlsnonpic(P1ND *p) { P1ND *q, *r; struct symtab *sp, *sp2; int ext = p->n_sp->sclass; char *name; name = getsoname(p->n_sp); sp = picsymtab("", name, ext == EXTERN ? "@INDNTPOFF" : "@NTPOFF"); q = xbcon(0, sp, INT); if (ext == EXTERN) q = block(UMUL, q, NIL, PTR|VOID, 0, 0); sp2 = lookup("%gs:0", 0); sp2->stype = EXTERN|INT; r = nametree(sp2); q = buildtree(PLUS, q, r); q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); q->n_sp = p->n_sp; /* for init */ p1nfree(p); return q; } static P1ND * tlsref(P1ND *p) { if (kflag) return (tlspic(p)); else return (tlsnonpic(p)); } #endif /* clocal() is called to do local transformations on * an expression tree preparitory to its being * written out in intermediate code. * * the major essential job is rewriting the * automatic variables and arguments in terms of * REG and OREG nodes * conversion ops which are not necessary are also clobbered here * in addition, any special features (such as rewriting * exclusive or) are easily handled here as well */ P1ND * clocal(P1ND *p) { struct attr *ap; register struct symtab *q; register P1ND *r, *l, *n, *s; register int o; register int m; #ifdef PCC_DEBUG if (xdebug) { printf("clocal: %p\n", p); p1fwalk(p, eprint, 0); } #endif switch( o = p->n_op ){ case NAME: if ((q = p->n_sp) == NULL) return p; /* Nothing to care about */ switch (q->sclass) { case PARAM: case AUTO: /* fake up a structure reference */ r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); slval(r, 0); r->n_rval = FPREG; p = stref(block(STREF, r, p, 0, 0, 0)); break; case USTATIC: if (kflag == 0) break; /* FALLTHROUGH */ case STATIC: #ifdef TLS if (q->sflags & STLS) { p = tlsref(p); break; } #endif if (kflag == 0) { if (q->slevel == 0) break; } else if (kflag && !statinit && blevel > 0 && #ifdef GCC_COMPAT attr_find(q->sap, GCC_ATYP_WEAKREF)) { #else 0) { #endif /* extern call */ p = picext(p); } else if (blevel > 0 && !statinit) p = picstatic(p); break; case REGISTER: p->n_op = REG; slval(p, 0); p->n_rval = q->soffset; break; case EXTERN: case EXTDEF: #ifdef TLS if (q->sflags & STLS) { p = tlsref(p); break; } #endif #ifdef PECOFFABI if (attr_find(q->sap, ATTR_i386_SDLLINDIRECT)) p = import(p); #endif #ifdef GCC_COMPAT if ((ap = attr_find(q->sap, GCC_ATYP_VISIBILITY)) != NULL && strcmp(ap->sarg(0), "hidden") == 0) printf(PRTPREF "\t.hidden %s\n", getsoname(q)); #endif if (kflag == 0) break; if (blevel > 0 && !statinit) p = picext(p); break; } break; case ADDROF: if (kflag == 0 || blevel == 0 || statinit) break; /* char arrays may end up here */ l = p->n_left; if (l->n_op != NAME || (l->n_type != ARY+CHAR && l->n_type != ARY+WCHAR_TYPE)) break; l = p; p = picstatic(p->n_left); p1nfree(l); if (p->n_op != UMUL) cerror("ADDROF error"); l = p; p = p->n_left; p1nfree(l); break; case UCALL: if (kflag == 0) break; l = block(REG, NIL, NIL, INT, 0, 0); l->n_rval = EBX; p->n_right = buildtree(ASSIGN, l, tempnode(gotnr, INT, 0, 0)); p->n_op -= (UCALL-CALL); break; case USTCALL: #if defined(os_openbsd) ap = strattr(p->n_left->n_ap); if (ap->amsize == SZCHAR || ap->amsize == SZSHORT || ap->amsize == SZINT || ap->amsize == SZLONGLONG) #else if (attr_find(p->n_left->n_ap, ATTR_COMPLEX) && (ap = strattr(p->n_left->n_ap)) && ap->amsize == SZLONGLONG) #endif { /* float complex */ /* fake one arg to make pass2 happy */ p->n_right = block(FUNARG, bcon(0), NIL, INT, 0, 0); p->n_op -= (UCALL-CALL); break; } /* Add hidden arg0 */ r = block(REG, NIL, NIL, INCREF(VOID), 0, 0); regno(r) = EBP; #ifdef GCC_COMPAT if ((ap = attr_find(p->n_ap, GCC_ATYP_REGPARM)) != NULL && ap->iarg(0) > 0) { l = block(REG, NIL, NIL, INCREF(VOID), 0, 0); regno(l) = EAX; p->n_right = buildtree(ASSIGN, l, r); } else #endif p->n_right = block(FUNARG, r, NIL, INCREF(VOID), 0, 0); p->n_op -= (UCALL-CALL); if (kflag == 0) break; l = block(REG, NIL, NIL, INT, 0, 0); regno(l) = EBX; r = buildtree(ASSIGN, l, tempnode(gotnr, INT, 0, 0)); p->n_right = block(CM, r, p->n_right, INT, 0, 0); break; /* FALLTHROUGH */ #if defined(MACHOABI) case CALL: case STCALL: if (p->n_type == VOID) break; r = tempnode(0, p->n_type, p->n_df, p->n_ap); l = tcopy(r); p = buildtree(COMOP, buildtree(ASSIGN, r, p), l); #endif break; #ifdef notyet /* XXX breaks sometimes */ case CBRANCH: l = p->n_left; /* * Remove unnecessary conversion ops. */ if (!clogop(l->n_op) || l->n_left->n_op != SCONV) break; if (coptype(l->n_op) != BITYPE) break; if (l->n_right->n_op != ICON) break; r = l->n_left->n_left; if (r->n_type >= FLOAT) break; if (toolarge(r->n_type, l->n_right->n_lval)) break; l->n_right->n_type = r->n_type; if (l->n_op >= ULE && l->n_op <= UGT) l->n_op -= (UGT-ULE); p->n_left = buildtree(l->n_op, r, l->n_right); p1nfree(l->n_left); p1nfree(l); break; #endif case PCONV: l = p->n_left; /* Make int type before pointer */ if (l->n_type < INT || l->n_type == LONGLONG || l->n_type == ULONGLONG || l->n_type == BOOL) { /* float etc? */ p->n_left = block(SCONV, l, NIL, UNSIGNED, 0, 0); } break; case SCONV: if (p->n_left->n_op == COMOP) break; /* may propagate wrong type later */ l = p->n_left; if (p->n_type == l->n_type) { p1nfree(p); return l; } if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 && tsize(p->n_type, p->n_df, p->n_ap) == tsize(l->n_type, l->n_df, l->n_ap)) { if (p->n_type != FLOAT && p->n_type != DOUBLE && l->n_type != FLOAT && l->n_type != DOUBLE && l->n_type != LDOUBLE && p->n_type != LDOUBLE) { if (l->n_op == NAME || l->n_op == UMUL || l->n_op == TEMP) { l->n_type = p->n_type; p1nfree(p); return l; } } } if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT && coptype(l->n_op) == BITYPE && l->n_op != COMOP && l->n_op != QUEST && l->n_op != ASSIGN && l->n_op != RS) { l->n_type = p->n_type; p1nfree(p); return l; } o = l->n_op; m = p->n_type; if (o == ICON) { /* * Can only end up here if o is an address, * and in that case the only compile-time conversion * possible is to int. */ if ((TMASK & l->n_type) == 0 && l->n_sp == NULL) cerror("SCONV ICON"); if (l->n_sp == 0) { p->n_type = UNSIGNED; concast(l, m); } else if (m != INT && m != UNSIGNED) break; l->n_type = m; l->n_ap = 0; p1nfree(p); return l; } else if (l->n_op == FCON) cerror("SCONV FCON"); if ((p->n_type == CHAR || p->n_type == UCHAR || p->n_type == SHORT || p->n_type == USHORT) && (l->n_type == FLOAT || l->n_type == DOUBLE || l->n_type == LDOUBLE)) { p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap); p->n_left->n_type = INT; return p; } break; case MOD: case DIV: if (o == DIV && p->n_type != CHAR && p->n_type != SHORT) break; if (o == MOD && p->n_type != CHAR && p->n_type != SHORT) break; /* make it an int division by inserting conversions */ p->n_left = makety(p->n_left, INT, 0, 0, 0); p->n_right = makety(p->n_right, INT, 0, 0, 0); o = p->n_type; p->n_type = INT; p = makety(p, o, 0, 0, 0); break; case FORCE: /* put return value in return reg */ p->n_op = ASSIGN; p->n_right = p->n_left; p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0); p->n_left->n_rval = p->n_left->n_type == BOOL ? RETREG(CHAR) : RETREG(p->n_type); break; #ifndef NOBREGS case LS: case RS: /* shift count must be in a char */ if (p->n_right->n_type == CHAR || p->n_right->n_type == UCHAR) break; p->n_right = block(SCONV, p->n_right, NIL, CHAR, 0, 0); break; #endif /* If not using pcc struct return */ case STASG: r = p->n_right; if (r->n_op != STCALL && r->n_op != USTCALL) break; m = (int)tsize(BTYPE(r->n_type), r->n_df, r->n_ap); if (m == SZCHAR) m = CHAR; else if (m == SZSHORT) m = SHORT; else if (m == SZINT) m = INT; else if (m == SZLONGLONG) m = LONGLONG; else break; #if !defined(os_openbsd) if (attr_find(r->n_ap, ATTR_COMPLEX) == 0) break; /* float _Complex always in regs */ #endif l = buildtree(ADDROF, p->n_left, NIL); p1nfree(p); r->n_op -= (STCALL-CALL); r->n_type = m; /* r = long, l = &struct */ n = tempnode(0, m, r->n_df, r->n_ap); r = buildtree(ASSIGN, p1tcopy(n), r); s = tempnode(0, l->n_type, l->n_df, l->n_ap); l = buildtree(ASSIGN, p1tcopy(s), l); p = buildtree(COMOP, r, l); l = buildtree(CAST, block(NAME, NIL, NIL, m|PTR, 0, 0), p1tcopy(s)); r = l->n_right; p1nfree(l->n_left); p1nfree(l); r = buildtree(ASSIGN, buildtree(UMUL, r, NIL), n); p = buildtree(COMOP, p, r); p = buildtree(COMOP, p, s); break; } #ifdef PCC_DEBUG if (xdebug) { printf("clocal end: %p\n", p); p1fwalk(p, eprint, 0); } #endif return(p); } /* * Change CALL references to either direct (static) or PLT. */ static void fixnames(P1ND *p, void *arg) { #if defined(ELFABI) || defined(MACHOABI) struct symtab *sp; struct attr *ap, *ap2; P1ND *q; char *c; int isu; if ((cdope(p->n_op) & CALLFLG) == 0) return; isu = 0; q = p->n_left; ap = q->n_ap; if (q->n_op == UMUL) q = q->n_left, isu = 1; if (q->n_op == PLUS && q->n_left->n_op == TEMP && q->n_right->n_op == ICON) { sp = q->n_right->n_sp; if (sp == NULL) return; /* nothing to do */ if (sp->sclass == STATIC && !ISFTN(sp->stype)) return; /* function pointer */ if (sp->sclass != STATIC && sp->sclass != EXTERN && sp->sclass != EXTDEF) cerror("fixnames"); c = NULL; #if defined(ELFABI) if ((ap2 = attr_find(sp->sap, ATTR_SONAME)) == NULL || (c = strstr(ap2->sarg(0), "@GOT")) == NULL) cerror("fixnames2: %p %s", ap2, c); if (isu) { memcpy(c, "@PLT", sizeof("@PLT")); } else *c = 0; #elif defined(MACHOABI) if (sp->soname == NULL || ((c = strstr(sp->soname, "$non_lazy_ptr")) == NULL && (c = strstr(sp->soname, "-L")) == NULL)) cerror("fixnames2"); if (!ISFTN(sp->stype)) return; /* function pointer */ if (isu) { *c = 0; addstub(&stublist, sp->soname+1); memcpy(c, "$stub", sizeof("$stub")); } else *c = 0; #endif p1nfree(q->n_left); q = q->n_right; if (isu) p1nfree(p->n_left->n_left); p1nfree(p->n_left); p->n_left = q; q->n_ap = ap; } #endif } static void mangle(P1ND *p); void myp2tree(P1ND *p) { struct symtab *sp; if (kflag) fixnames(p, 0); mangle(p); if ((p->n_op == STCALL || p->n_op == USTCALL) && attr_find(p->n_ap, ATTR_COMPLEX) && strmemb(p->n_ap)->stype == FLOAT) p->n_ap = attr_add(p->n_ap, attr_new(ATTR_I386_FCMPLRET, 1)); if (p->n_op != FCON) return; sp = IALLOC(sizeof(struct symtab)); sp->sclass = STATIC; sp->sap = 0; sp->slevel = 1; /* fake numeric label */ sp->soffset = getlab(); sp->sflags = 0; sp->stype = p->n_type; sp->squal = (CON >> TSHIFT); sp->sname = NULL; locctr(DATA, sp); defloc(sp); inval(0, tsize(sp->stype, sp->sdf, sp->sap), p); p->n_op = NAME; slval(p, 0); p->n_sp = sp; if (kflag) { P1ND *q = optim(picstatic(p1tcopy(p))); *p = *q; p1nfree(q); } } /*ARGSUSED*/ int andable(P1ND *p) { return(1); /* all names can have & taken on them */ } /* * Return 1 if a variable of type type is OK to put in register. */ int cisreg(TWORD t) { if (t == FLOAT || t == DOUBLE || t == LDOUBLE) return 0; /* not yet */ return 1; } /* * Allocate off bits on the stack. p is a tree that when evaluated * is the multiply count for off, t is a storeable node where to write * the allocated address. */ void spalloc(P1ND *t, P1ND *p, OFFSZ off) { P1ND *sp; p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */ /* sub the size from sp */ sp = block(REG, NIL, NIL, p->n_type, 0, 0); slval(sp, 0); sp->n_rval = STKREG; ecomp(buildtree(MINUSEQ, sp, p)); #ifdef MACHOABI /* align to 16 bytes */ sp = block(REG, NIL, NIL, p->n_type, 0, 0); sp->n_lval = 0; sp->n_rval = STKREG; ecomp(buildtree(PLUSEQ, sp, bcon(15))); sp = block(REG, NIL, NIL, p->n_type, 0, 0); sp->n_lval = 0; sp->n_rval = STKREG; ecomp(buildtree(RSEQ, sp, bcon(4))); sp = block(REG, NIL, NIL, p->n_type, 0, 0); sp->n_lval = 0; sp->n_rval = STKREG; ecomp(buildtree(LSEQ, sp, bcon(4))); #endif /* save the address of sp */ sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap); slval(sp, 0); sp->n_rval = STKREG; t->n_type = sp->n_type; ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */ } /* * print out a constant node, may be associated with a label. * Do not free the node after use. * off is bit offset from the beginning of the aggregate * fsz is the number of bits this is referring to */ int ninval(CONSZ off, int fsz, P1ND *p) { int i; switch (p->n_type) { case LONGLONG: case ULONGLONG: i = (int)(glval(p) >> 32); slval(p, glval(p) & 0xffffffff); p->n_type = INT; inval(off, 32, p); slval(p, i); inval(off+32, 32, p); break; default: return 0; } return 1; } /* make a name look like an external name in the local machine */ char * exname(char *p) { #if !defined(ELFABI) #define NCHNAM 256 static char text[NCHNAM+1]; int i; if (p == NULL) return ""; text[0] = '_'; for (i=1; *p && istype, sp->sap)/SZCHAR; off = (int)tsize(sp->stype, sp->sdf, sp->sap); SETOFF(off,SZCHAR); off /= SZCHAR; #if defined(MACHOABI) || defined(PECOFFABI)/* && binutils>2.20 */ al = ispow2(al); if (sp->sclass == STATIC) { if (sp->slevel == 0) printf(PRTPREF "\t.lcomm %s,0%o,%d\n", name, off, al); else printf(PRTPREF "\t.lcomm " LABFMT ",0%o,%d\n", sp->soffset, off, al); } else { if (sp->slevel == 0) printf(PRTPREF "\t.comm %s,0%o,%d\n", name, off, al); else printf(PRTPREF "\t.comm " LABFMT ",0%o,%d\n", sp->soffset, off, al); } #elif defined(ELFABI) #ifdef GCC_COMPAT if (attr_find(sp->sap, GCC_ATYP_WEAKREF) != NULL) return; #endif if (sp->sclass == STATIC) { if (sp->slevel == 0) { printf(PRTPREF "\t.local %s\n", name); } else printf(PRTPREF "\t.local " LABFMT "\n", sp->soffset); } if (sp->slevel == 0) printf(PRTPREF "\t.comm %s,0%o,%d\n", name, off, al); else printf(PRTPREF "\t.comm " LABFMT ",0%o,%d\n", sp->soffset, off, al); #else if (attr_find(sp->sap, GCC_ATYP_WEAKREF) != NULL) return; if (sp->slevel == 0) printf(PRTPREF "\t.%scomm %s,0%o\n", sp->sclass == STATIC ? "l" : "", name, off); else printf(PRTPREF "\t.%scomm " LABFMT ",0%o\n", sp->sclass == STATIC ? "l" : "", sp->soffset, off); #endif } #ifdef TLS static int gottls; #endif #ifdef PECOFFABI static int dllindirect; #endif static char *alias; static int constructor; static int destructor; /* * Give target the opportunity of handling pragmas. */ int mypragma(char *str) { char *a2 = pragtok(NULL); #ifdef TLS if (strcmp(str, "tls") == 0 && a2 == NULL) { gottls = 1; return 1; } #endif #ifdef PECOFFABI if (strcmp(str, "dllimport") == 0) { dllindirect = 1; return 1; } if (strcmp(str, "dllexport") == 0) { dllindirect = 1; return 1; } #endif #ifndef AOUTABI if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) { constructor = 1; return 1; } if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) { destructor = 1; return 1; } #endif if (strcmp(str, "alias") == 0 && a2 != NULL) { alias = tmpstrdup(a2); return 1; } return 0; } /* * Called when a identifier has been declared. */ void fixdef(struct symtab *sp) { #ifdef GCC_COMPAT struct attr *ap; #endif #ifdef TLS /* may have sanity checks here */ if (gottls) sp->sflags |= STLS; gottls = 0; #endif #ifdef GCC_COMPAT #ifdef HAVE_WEAKREF /* not many as'es have this directive */ if ((ap = attr_find(sp->sap, GCC_ATYP_WEAKREF)) != NULL) { char *wr = ap->sarg(0); char *sn = getsoname(sp); if (sp->sclass != STATIC && sp->sclass != USTATIC) uerror("weakref %s must be static", sp->sname); if (wr == NULL) { if ((ap = attr_find(sp->sap, GCC_ATYP_ALIAS))) { wr = ap->sarg(0); } } if (wr == NULL) printf(PRTPREF "\t.weak %s\n", sn); else printf(PRTPREF "\t.weakref %s,%s\n", sn, wr); } else #endif if ((ap = attr_find(sp->sap, GCC_ATYP_ALIAS)) != NULL) { char *an = ap->sarg(0); char *v; char *sn = getsoname(sp); v = attr_find(sp->sap, GCC_ATYP_WEAK) ? "weak" : "globl"; printf(PRTPREF "\t.%s %s\n", v, sn); printf(PRTPREF "\t.set %s,%s\n", sn, an); } #endif if (alias != NULL && (sp->sclass != PARAM)) { char *name = getexname(sp); printf(PRTPREF "\t.globl %s\n", name); printf(PRTPREF "%s = ", name); printf("%s\n", exname(alias)); alias = NULL; } if ((constructor || destructor) && (sp->sclass != PARAM)) { #if defined(ELFABI) printf(PRTPREF "\t.section .%ctors,\"aw\",@progbits\n", constructor ? 'c' : 'd'); #elif defined(PECOFFABI) printf(PRTPREF "\t.section .%ctors,\"w\"\n", constructor ? 'c' : 'd'); #elif defined(MACHOABI) if (kflag) { if (constructor) printf(PRTPREF "\t.mod_init_func\n"); else printf(PRTPREF "\t.mod_term_func\n"); } else { if (constructor) printf(PRTPREF "\t.constructor\n"); else printf(PRTPREF "\t.destructor\n"); } #elif defined(AOUTABI) uerror("constructor/destructor are not supported for this target"); #endif printf(PRTPREF "\t.p2align 2\n"); printf(PRTPREF "\t.long %s\n", exname(sp->sname)); #if defined(ELFABI) printf(PRTPREF "\t.previous\n"); #else printf(PRTPREF "\t.text\n"); #endif constructor = destructor = 0; } #ifdef PECOFFABI if (dllindirect && (sp->sclass != PARAM)) { sp->sap = attr_add(sp->sap, attr_new(ATTR_I386_DLLINDIRECT, 1)); dllindirect = 0; } #endif } /* * Postfix external functions with the arguments size. */ static void mangle(P1ND *p) { P1ND *l; if (p->n_op != CALL && p->n_op != STCALL && p->n_op != UCALL && p->n_op != USTCALL) return; l = p->n_left; while (cdope(l->n_op) & CALLFLG) l = l->n_left; if (l->n_op == TEMP) return; if (l->n_op == ADDROF) l = l->n_left; if (l->n_sp == NULL) return; #ifdef PECOFFABI if (attr_find(l->n_sp->sap, GCC_ATYP_STDCALL)) { if (strchr(l->n_name, '@') == NULL) { int size = 0; char buf[256]; P1ND *r; TWORD t; if (p->n_op == CALL || p->n_op == STCALL) { for (r = p->n_right; r->n_op == CM; r = r->n_left) { t = r->n_type; if (t == STRTY || t == UNIONTY) size += tsize(t, r->n_df, r->n_ap); else size += szty(t) * SZINT / SZCHAR; } t = r->n_type; if (t == STRTY || t == UNIONTY) size += tsize(t, r->n_df, r->n_ap); else size += szty(t) * SZINT / SZCHAR; } size = snprintf(buf, 256, "%s@%d", l->n_name, size) + 1; l->n_name = IALLOC(size); memcpy(l->n_name, buf, size); } } #endif } void pass1_lastchance(struct interpass *ip) { /* remove stray cast due to (void)foo() */ if (ip->type == IP_NODE && ip->ip_node->n_op == SCONV) ip->ip_node = nfree(ip->ip_node); if (ip->type == IP_NODE && (ip->ip_node->n_op == CALL || ip->ip_node->n_op == UCALL) && ISFTY(ip->ip_node->n_type)) ip->ip_node->n_ap = attr_add(ip->ip_node->n_ap, attr_new(ATTR_I386_FPPOP, 1)); if (ip->type == IP_EPILOG) { struct interpass_prolog *ipp = (struct interpass_prolog *)ip; ipp->ipp_argstacksize = argstacksize; } } #ifdef PASS1 void mflags(char *s) { } #endif pcc-20181216/arch/i386/local2.c010064400017500000000000000771321337532075700144400ustar raggewheel/* $Id: local2.c,v 1.192 2018/11/21 18:20:31 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass2.h" # include # include #if defined(PECOFFABI) || defined(MACHOABI) || defined(AOUTABI) #define EXPREFIX "_" #else #define EXPREFIX "" #endif int msettings = MI686; static int stkpos; static int flabwrtn, loadlab; void deflab(int label) { printf(LABFMT ":\n", label); } static int regoff[7]; static TWORD ftype; /* * Print out the prolog assembler. * addto and regoff are already calculated. */ static void prtprolog(struct interpass_prolog *ipp, int addto) { int i; #if 1 #if defined(MACHOABI) addto += 8; #endif if (addto == 0 || addto > 65535) { printf(" pushl %%ebp\n\tmovl %%esp,%%ebp\n"); if (addto) printf(" subl $%d,%%esp\n", addto); } else printf(" enter $%d,$0\n", addto); #endif for (i = 0; i < MAXREGS; i++) if (TESTBIT(p2env.p_regs, i)) printf(" movl %s,-%d(%s)\n", rnames[i], regoff[i], rnames[FPREG]); } /* * calculate stack size and offsets */ static int offcalc(struct interpass_prolog *ipp) { int i, addto; addto = p2maxautooff; if (addto >= AUTOINIT/SZCHAR) addto -= AUTOINIT/SZCHAR; for (i = 0; i < MAXREGS; i++) if (TESTBIT(p2env.p_regs, i)) { addto += SZINT/SZCHAR; regoff[i] = addto; } return addto; } void prologue(struct interpass_prolog *ipp) { int addto; ftype = ipp->ipp_type; #ifdef LANG_F77 if (ipp->ipp_vis) printf(" .globl %s\n", ipp->ipp_name); printf(" .align 4\n"); printf("%s:\n", ipp->ipp_name); #endif /* * We here know what register to save and how much to * add to the stack. */ addto = offcalc(ipp); #if defined(MACHOABI) addto = (addto + 15) & ~15; /* stack alignment */ #endif prtprolog(ipp, addto); } void eoftn(struct interpass_prolog *ipp) { int i; if (ipp->ipp_ip.ip_lbl == 0) return; /* no code needs to be generated */ /* return from function code */ for (i = 0; i < MAXREGS; i++) if (TESTBIT(p2env.p_regs, i)) printf(" movl -%d(%s),%s\n", regoff[i], rnames[FPREG], rnames[i]); /* struct return needs special treatment */ if (ftype == STRTY || ftype == UNIONTY) { printf(" movl 8(%%ebp),%%eax\n"); printf(" leave\n"); printf(" ret $%d\n", 4 + ipp->ipp_argstacksize); } else { printf(" leave\n"); if (ipp->ipp_argstacksize) printf(" ret $%d\n", ipp->ipp_argstacksize); else printf(" ret\n"); } #if defined(ELFABI) printf("\t.size " EXPREFIX "%s,.-" EXPREFIX "%s\n", ipp->ipp_name, ipp->ipp_name); #endif if (flabwrtn == 0 && loadlab) { printf(" .data\n"); printf(LABFMT ": .long 0x5f800000\n", loadlab); printf(" .text\n"); flabwrtn = 1; } } /* * add/sub/... * * Param given: */ void hopcode(int f, int o) { char *str; switch (o) { case PLUS: str = "add"; break; case MINUS: str = "sub"; break; case AND: str = "and"; break; case OR: str = "or"; break; case ER: str = "xor"; break; default: comperr("hopcode2: %d", o); str = 0; /* XXX gcc */ } printf("%s%c", str, f); } /* * Return type size in bytes. Used by R2REGS, arg 2 to offset(). */ int tlen(NODE *p) { switch(p->n_type) { case CHAR: case UCHAR: return(1); case SHORT: case USHORT: return(SZSHORT/SZCHAR); case DOUBLE: return(SZDOUBLE/SZCHAR); case INT: case UNSIGNED: case LONG: case ULONG: return(SZINT/SZCHAR); case LONGLONG: case ULONGLONG: return SZLONGLONG/SZCHAR; default: if (!ISPTR(p->n_type)) comperr("tlen type %d not pointer"); return SZPOINT(p->n_type)/SZCHAR; } } /* * Emit code to compare two longlong numbers. */ static void twollcomp(NODE *p) { int u; int s = getlab2(); int e = p->n_label; int cb1, cb2; u = p->n_op; switch (p->n_op) { case NE: cb1 = 0; cb2 = NE; break; case EQ: cb1 = NE; cb2 = 0; break; case LE: case LT: u += (ULE-LE); /* FALLTHROUGH */ case ULE: case ULT: cb1 = GT; cb2 = LT; break; case GE: case GT: u += (ULE-LE); /* FALLTHROUGH */ case UGE: case UGT: cb1 = LT; cb2 = GT; break; default: cb1 = cb2 = 0; /* XXX gcc */ } if (p->n_op >= ULE) cb1 += 4, cb2 += 4; expand(p, 0, " cmpl UR,UL\n"); if (cb1) cbgen(cb1, s); if (cb2) cbgen(cb2, e); expand(p, 0, " cmpl AR,AL\n"); cbgen(u, e); deflab(s); } int fldexpand(NODE *p, int cookie, char **cp) { comperr("fldexpand"); return 0; } /* * Push a structure on stack as argument. * the scratch registers are already free here */ static void starg(NODE *p) { struct attr *ap; NODE *q = p->n_left; ap = attr_find(p->n_ap, ATTR_P2STRUCT); printf(" subl $%d,%%esp\n", (ap->iarg(0) + 3) & ~3); p->n_left = mklnode(OREG, 0, ESP, INT); zzzcode(p, 'Q'); tfree(p->n_left); p->n_left = q; } /* * Compare two floating point numbers. */ static void fcomp(NODE *p) { int swap = ((p->n_su & DORIGHT) != 0); int failjump = attr_find(p->n_ap, ATTR_FP_SWAPPED) != 0; //printf("fcomp: DOR %d op %s\n", swap, opst[p->n_op]); if (p->n_op == GT || p->n_op == GE) { swap ^= 1; p->n_op = (p->n_op == GT ? LT : LE); } //printf("fcomp2: DOR %d op %s\n", swap, opst[p->n_op]); if (swap) expand(p, 0, "\tfxch\n"); if (msettings & MI686) { expand(p, 0, "\tfucomip %st(1),%st\n"); /* emit compare insn */ expand(p, 0, "\tfstp %st(0)\n"); /* pop fromstack */ } else { expand(p, 0, "\tfucompp\n"); expand(p, 0, "\tfnstsw %%ax\n"); expand(p, 0, "\tsahf\n"); } switch (p->n_op) { case EQ: /* jump if: Z is set and P is clear */ expand(p, 0, "\tjne 1f\n"); expand(p, 0, "\tjnp LC\n"); expand(p, 0, "\t1:\n"); break; case NE: /* jump if: Z is clear or P is set */ expand(p, 0, "\tjne LC\n"); expand(p, 0, "\tjp LC\n"); break; case LT: expand(p, 0, "\tja LC\n"); if (failjump) expand(p, 0, "\tjp LC\n"); break; case LE: expand(p, 0, "\tjae LC\n"); if (failjump) expand(p, 0, "\tjp LC\n"); break; } } /* * Convert an unsigned long long to floating point number. */ static void ulltofp(NODE *p) { int jmplab = getlab2(); if (loadlab == 0) loadlab = getlab2(); expand(p, 0, " movl UL,4+A2\n movl AL,A2\n"); expand(p, 0, " fildq A2\n"); expand(p, 0, " test UL,UL\n"); printf(" jge " LABFMT "\n", jmplab); printf(" fadds " LABFMT "%s\n", loadlab, kflag ? "@GOTOFF" : ""); printf(LABFMT ":\n", jmplab); } static int argsiz(NODE *p) { TWORD t = p->n_type; if (t < LONGLONG || t == FLOAT || t > BTMASK) return 4; if (t == LONGLONG || t == ULONGLONG || t == DOUBLE) return 8; if (t == LDOUBLE) return 12; if (t == STRTY || t == UNIONTY) return attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0) & ~3; comperr("argsiz"); return 0; } static void fcast(NODE *p) { TWORD t = p->n_type; int sz, c; if (t >= p->n_left->n_type) return; /* cast to more precision */ if (t == FLOAT) sz = 4, c = 's'; else sz = 8, c = 'l'; printf(" sub $%d,%%esp\n", sz); printf(" fstp%c (%%esp)\n", c); printf(" fld%c (%%esp)\n", c); printf(" add $%d,%%esp\n", sz); } static void llshft(NODE *p) { char *d[3]; if (p->n_op == LS) { d[0] = "l", d[1] = "%eax", d[2] = "%edx"; } else d[0] = "r", d[1] = "%edx", d[2] = "%eax"; printf("\tsh%sdl %s,%s\n",d[0], d[1], d[2]); printf("\ts%s%sl %%cl,%s\n", p->n_op == RS && p->n_left->n_type == ULONGLONG ? "h" : "a", d[0], d[1]); printf("\ttestb $32,%%cl\n"); printf("\tje 1f\n"); printf("\tmovl %s,%s\n", d[1], d[2]); if (p->n_op == RS && p->n_left->n_type == LONGLONG) printf("\tsarl $31,%%edx\n"); else printf("\txorl %s,%s\n",d[1],d[1]); printf("1:\n"); } void zzzcode(NODE *p, int c) { struct attr *ap; NODE *l; int pr, lr; char *ch; switch (c) { case 'A': /* swap st0 and st1 if right is evaluated second */ if ((p->n_su & DORIGHT) == 0) { if (logop(p->n_op)) printf(" fxch\n"); else printf("r"); } break; case 'C': /* remove from stack after subroutine call */ #ifdef GCC_COMPAT if (attr_find(p->n_left->n_ap, GCC_ATYP_STDCALL)) break; #endif pr = p->n_qual; if (attr_find(p->n_ap, ATTR_I386_FPPOP)) printf(" fstp %%st(0)\n"); if (p->n_op == UCALL) return; /* XXX remove ZC from UCALL */ if (pr) printf(" addl $%d, %s\n", pr, rnames[ESP]); #if defined(os_openbsd) ap = attr_find(p->n_ap, ATTR_P2STRUCT); if (p->n_op == STCALL && (ap->iarg(0) == 1 || ap->iarg(0) == 2 || ap->iarg(0) == 4 || ap->iarg(0) == 8)) { /* save on stack */ printf("\tmovl %%eax,-%d(%%ebp)\n", stkpos); printf("\tmovl %%edx,-%d(%%ebp)\n", stkpos+4); printf("\tleal -%d(%%ebp),%%eax\n", stkpos); } #endif break; case 'D': /* Long long comparision */ twollcomp(p); break; case 'F': /* Structure argument */ starg(p); break; case 'G': /* Floating point compare */ fcomp(p); break; case 'H': /* assign of longlong between regs */ rmove(DECRA(p->n_right->n_reg, 0), DECRA(p->n_left->n_reg, 0), LONGLONG); break; case 'I': /* float casts */ fcast(p); break; case 'J': /* convert unsigned long long to floating point */ ulltofp(p); break; case 'K': /* Load longlong reg into another reg */ rmove(regno(p), DECRA(p->n_reg, 0), LONGLONG); break; #ifndef NOBREGS case 'M': /* Output sconv move, if needed */ l = getlr(p, 'L'); /* XXX fixneed: regnum */ pr = DECRA(p->n_reg, 0); lr = DECRA(l->n_reg, 0); if ((pr == AL && lr == EAX) || (pr == BL && lr == EBX) || (pr == CL && lr == ECX) || (pr == DL && lr == EDX)) ; else printf(" movb %%%cl,%s\n", rnames[lr][2], rnames[pr]); l->n_rval = l->n_reg = p->n_reg; /* XXX - not pretty */ break; #endif case 'N': /* output extended reg name */ printf("%s", rnames[getlr(p, '1')->n_rval]); break; case 'O': /* print out emulated ops */ pr = 16; if (p->n_op == RS || p->n_op == LS) { llshft(p); break; } else if (p->n_op == MUL) { printf("\timull %%ecx, %%edx\n"); printf("\timull %%eax, %%esi\n"); printf("\taddl %%edx, %%esi\n"); printf("\tmull %%ecx\n"); printf("\taddl %%esi, %%edx\n"); break; } expand(p, INCREG, "\tpushl UR\n\tpushl AR\n"); expand(p, INCREG, "\tpushl UL\n\tpushl AL\n"); if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udiv"; else if (p->n_op == DIV) ch = "div"; else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umod"; else if (p->n_op == MOD) ch = "mod"; else ch = 0, comperr("ZO"); #ifdef ELFABI printf("\tcall " EXPREFIX "__%sdi3%s\n\taddl $%d,%s\n", ch, (kflag ? "@PLT" : ""), pr, rnames[ESP]); #else printf("\tcall " EXPREFIX "__%sdi3\n\taddl $%d,%s\n", ch, pr, rnames[ESP]); #endif break; case 'Q': /* emit struct assign */ /* * Put out some combination of movs{b,w,l} * esi/edi/ecx are available. */ expand(p, INAREG, " leal AL,%edi\n"); ap = attr_find(p->n_ap, ATTR_P2STRUCT); if (ap->iarg(0) < 32) { int i = ap->iarg(0) >> 2; while (i) { expand(p, INAREG, " movsl\n"); i--; } } else { printf("\tmovl $%d,%%ecx\n", ap->iarg(0) >> 2); printf(" rep movsl\n"); } if (ap->iarg(0) & 2) printf(" movsw\n"); if (ap->iarg(0) & 1) printf(" movsb\n"); break; case 'S': /* emit eventual move after cast from longlong */ pr = DECRA(p->n_reg, 0); lr = p->n_left->n_rval; switch (p->n_type) { #ifdef NOBREGS case CHAR: case UCHAR: /* Go via stack. XXX - optimize */ expand(p, INAREG, "\tmovl AL,A2\n"); if (ISUNSIGNED(p->n_type)) expand(p, INAREG, "\tmovzbl A2,A1\n"); else expand(p, INAREG, "\tmovsbl A2,A1\n"); break; #else case CHAR: case UCHAR: if (rnames[pr][2] == 'l' && rnames[lr][2] == 'x' && rnames[pr][1] == rnames[lr][1]) break; if (rnames[lr][2] == 'x') { printf("\tmovb %%%cl,%s\n", rnames[lr][1], rnames[pr]); break; } /* Must go via stack */ expand(p, INAREG, "\tmovl AL,A2\n"); expand(p, INBREG, "\tmovb A2,A1\n"); #ifdef notdef /* cannot use freetemp() in instruction emission */ s = freetemp(1); printf("\tmovl %%e%ci,%d(%%ebp)\n", rnames[lr][1], s); printf("\tmovb %d(%%ebp),%s\n", s, rnames[pr]); #endif break; #endif case SHORT: case USHORT: if (rnames[lr][1] == rnames[pr][2] && rnames[lr][2] == rnames[pr][3]) break; printf("\tmovw %%%c%c,%%%s\n", rnames[lr][1], rnames[lr][2], rnames[pr]+2); break; case INT: case UNSIGNED: if (rnames[lr][1] == rnames[pr][2] && rnames[lr][2] == rnames[pr][3]) break; printf("\tmovl %%e%c%c,%s\n", rnames[lr][1], rnames[lr][2], rnames[pr]); break; default: if (rnames[lr][1] == rnames[pr][2] && rnames[lr][2] == rnames[pr][3]) break; comperr("SCONV2 %s->%s", rnames[lr], rnames[pr]); break; } break; case 'T': /* Print out 8-bit reg name for assign */ switch (regno(getlr(p, 'R'))) { case EAX: ch = "%al"; break; case EBX: ch = "%bl"; break; case ECX: ch = "%cl"; break; case EDX: ch = "%dl"; break; default: ch = "ERROR"; break; } printf("%s", ch); break; case 'U': /* print a/h for right shift */ printf("%c", ISUNSIGNED(p->n_type) ? 'h' : 'a'); break; default: comperr("zzzcode %c", c); } } int canaddr(NODE *); int canaddr(NODE *p) { int o = p->n_op; if (o==NAME || o==REG || o==ICON || o==OREG || (o==UMUL && shumul(p->n_left, SOREG))) return(1); return(0); } /* * Does the bitfield shape match? */ int flshape(NODE *p) { comperr("flshape"); return 0; } /* INTEMP shapes must not contain any temporary registers */ /* XXX should this go away now? */ int shtemp(NODE *p) { return 0; #if 0 int r; if (p->n_op == STARG ) p = p->n_left; switch (p->n_op) { case REG: return (!istreg(p->n_rval)); case OREG: r = p->n_rval; if (R2TEST(r)) { if (istreg(R2UPK1(r))) return(0); r = R2UPK2(r); } return (!istreg(r)); case UMUL: p = p->n_left; return (p->n_op != UMUL && shtemp(p)); } if (optype(p->n_op) != LTYPE) return(0); return(1); #endif } void adrcon(CONSZ val) { printf("$" CONFMT, val); } void conput(FILE *fp, NODE *p) { int val = (int)getlval(p); switch (p->n_op) { case ICON: if (p->n_name[0] != '\0') { fprintf(fp, "%s", p->n_name); if (val) fprintf(fp, "+%d", val); } else fprintf(fp, "%d", val); return; default: comperr("illegal conput, p %p", p); } } /*ARGSUSED*/ void insput(NODE *p) { comperr("insput"); } /* * Write out the upper address, like the upper register of a 2-register * reference, or the next memory location. */ void upput(NODE *p, int size) { size /= SZCHAR; switch (p->n_op) { case REG: printf("%%%s", &rnames[p->n_rval][3]); break; case NAME: case OREG: setlval(p, getlval(p) + size); adrput(stdout, p); setlval(p, getlval(p) - size); break; case ICON: printf("$" CONFMT, getlval(p) >> 32); break; default: comperr("upput bad op %d size %d", p->n_op, size); } } void adrput(FILE *io, NODE *p) { int r; /* output an address, with offsets, from p */ switch (p->n_op) { case NAME: if (p->n_name[0] != '\0') { fputs(p->n_name, io); if (getlval(p) != 0) fprintf(io, "+" CONFMT, getlval(p)); } else fprintf(io, CONFMT, getlval(p)); return; case OREG: r = p->n_rval; if (p->n_name[0]) printf("%s%s", p->n_name, getlval(p) ? "+" : ""); if (getlval(p)) fprintf(io, "%d", (int)getlval(p)); if (R2TEST(r)) { fprintf(io, "(%s,%s,4)", rnames[R2UPK1(r)], rnames[R2UPK2(r)]); } else fprintf(io, "(%s)", rnames[p->n_rval]); return; case ICON: #ifdef PCC_DEBUG /* Sanitycheck for PIC, to catch adressable constants */ if (kflag && p->n_name[0] && 0) { static int foo; if (foo++ == 0) { printf("\nfailing...\n"); fwalk(p, e2print, 0); comperr("pass2 conput"); } } #endif /* addressable value of the constant */ fputc('$', io); conput(io, p); return; case REG: switch (p->n_type) { case LONGLONG: case ULONGLONG: fprintf(io, "%%%c%c%c", rnames[p->n_rval][0], rnames[p->n_rval][1], rnames[p->n_rval][2]); break; case SHORT: case USHORT: fprintf(io, "%%%s", &rnames[p->n_rval][2]); break; default: fprintf(io, "%s", rnames[p->n_rval]); } return; default: comperr("illegal address, op %d, node %p", p->n_op, p); return; } } static char * ccbranches[] = { "je", /* jumpe */ "jne", /* jumpn */ "jle", /* jumple */ "jl", /* jumpl */ "jge", /* jumpge */ "jg", /* jumpg */ "jbe", /* jumple (jlequ) */ "jb", /* jumpl (jlssu) */ "jae", /* jumpge (jgequ) */ "ja", /* jumpg (jgtru) */ }; /* printf conditional and unconditional branches */ void cbgen(int o, int lab) { if (o < EQ || o > UGT) comperr("bad conditional branch: %s", opst[o]); printf(" %s " LABFMT "\n", ccbranches[o-EQ], lab); } static void fixcalls(NODE *p, void *arg) { struct attr *ap; /* Prepare for struct return by allocating bounce space on stack */ switch (p->n_op) { case STCALL: case USTCALL: ap = attr_find(p->n_ap, ATTR_P2STRUCT); if (ap->iarg(0)+p2autooff > stkpos) stkpos = ap->iarg(0)+p2autooff; if (8+p2autooff > stkpos) stkpos = ap->iarg(0)+p2autooff; break; case LS: case RS: if (p->n_type != LONGLONG && p->n_type != ULONGLONG) break; if (p->n_right->n_op == ICON) /* constants must be char */ p->n_right->n_type = CHAR; break; } } /* * Must store floats in memory if there are two function calls involved. */ static int storefloat(struct interpass *ip, NODE *p) { int l, r; switch (optype(p->n_op)) { case BITYPE: l = storefloat(ip, p->n_left); r = storefloat(ip, p->n_right); if (p->n_op == CM) return 0; /* arguments, don't care */ if (callop(p->n_op)) return 1; /* found one */ #define ISF(p) ((p)->n_type == FLOAT || (p)->n_type == DOUBLE || \ (p)->n_type == LDOUBLE) if (ISF(p->n_left) && ISF(p->n_right) && l && r) { /* must store one. store left */ struct interpass *nip; TWORD t = p->n_left->n_type; NODE *ll; int off; off = freetemp(szty(t)); ll = mklnode(OREG, off, FPREG, t); nip = ipnode(mkbinode(ASSIGN, ll, p->n_left, t)); p->n_left = mklnode(OREG, off, FPREG, t); DLIST_INSERT_BEFORE(ip, nip, qelem); } return l|r; case UTYPE: l = storefloat(ip, p->n_left); if (callop(p->n_op)) l = 1; return l; default: return 0; } } static void outfargs(struct interpass *ip, NODE **ary, int num, int *cwp, int c) { struct interpass *ip2; NODE *q, *r; int i; for (i = 0; i < num; i++) if (XASMVAL(cwp[i]) == c && (cwp[i] & (XASMASG|XASMINOUT))) break; if (i == num) return; q = ary[i]->n_left; r = mklnode(REG, 0, c == 'u' ? 040 : 037, q->n_type); ary[i]->n_left = tcopy(r); ip2 = ipnode(mkbinode(ASSIGN, q, r, q->n_type)); DLIST_INSERT_AFTER(ip, ip2, qelem); } static void infargs(struct interpass *ip, NODE **ary, int num, int *cwp, int c) { struct interpass *ip2; NODE *q, *r; int i; for (i = 0; i < num; i++) if (XASMVAL(cwp[i]) == c && (cwp[i] & XASMASG) == 0) break; if (i == num) return; q = ary[i]->n_left; q = (cwp[i] & XASMINOUT) ? tcopy(q) : q; r = mklnode(REG, 0, c == 'u' ? 040 : 037, q->n_type); if ((cwp[i] & XASMINOUT) == 0) ary[i]->n_left = tcopy(r); ip2 = ipnode(mkbinode(ASSIGN, r, q, q->n_type)); DLIST_INSERT_BEFORE(ip, ip2, qelem); } /* * Extract float args to XASM and ensure that they are put on the stack * in correct order. * This should be done sow other way. */ static void fixxfloat(struct interpass *ip, NODE *p) { NODE *w, **ary; int nn, i, c, *cwp; nn = 1; w = p->n_left; if (w->n_op == ICON && w->n_type == STRTY) return; /* index all xasm args first */ for (; w->n_op == CM; w = w->n_left) nn++; ary = tmpcalloc(nn * sizeof(NODE *)); cwp = tmpcalloc(nn * sizeof(int)); for (i = 0, w = p->n_left; w->n_op == CM; w = w->n_left) { ary[i] = w->n_right; cwp[i] = xasmcode(ary[i]->n_name); i++; } ary[i] = w; cwp[i] = xasmcode(ary[i]->n_name); for (i = 0; i < nn; i++) if (XASMVAL(cwp[i]) == 't' || XASMVAL(cwp[i]) == 'u') break; if (i == nn) return; for (i = 0; i < nn; i++) { c = XASMVAL(cwp[i]); if (c >= '0' && c <= '9') cwp[i] = (cwp[i] & ~0377) | XASMVAL(cwp[c-'0']); } infargs(ip, ary, nn, cwp, 'u'); infargs(ip, ary, nn, cwp, 't'); outfargs(ip, ary, nn, cwp, 't'); outfargs(ip, ary, nn, cwp, 'u'); } static NODE * lptr(NODE *p) { if (p->n_op == ASSIGN && p->n_right->n_op == REG && regno(p->n_right) == EBP) return p->n_right; if (p->n_op == FUNARG && p->n_left->n_op == REG && regno(p->n_left) == EBP) return p->n_left; return NIL; } /* * Find arg reg that should be struct reference instead. */ static void updatereg(NODE *p, void *arg) { NODE *q; if (p->n_op != STCALL) return; #if defined(os_openbsd) struct attr *ap = attr_find(p->n_ap, ATTR_P2STRUCT); if (ap->iarg(0) == 1 || ap->iarg(0) == 2 || ap->iarg(0) == 4 || ap->iarg(0) == 8) return; #endif if (attr_find(p->n_ap, ATTR_I386_FCMPLRET)) return; if (p->n_right->n_op != CM) p = p->n_right; else for (p = p->n_right; p->n_op == CM && p->n_left->n_op == CM; p = p->n_left) ; if (p->n_op == CM) { if ((q = lptr(p->n_left))) ; else q = lptr(p->n_right); } else q = lptr(p); if (q == NIL) comperr("bad STCALL hidden reg"); /* q is now the hidden arg */ q->n_op = MINUS; q->n_type = INCREF(CHAR); q->n_left = mklnode(REG, 0, EBP, INCREF(CHAR)); q->n_right = mklnode(ICON, stkpos, 0, INT); } void myreader(struct interpass *ipole) { struct interpass *ip; stkpos = p2autooff; DLIST_FOREACH(ip, ipole, qelem) { if (ip->type != IP_NODE) continue; walkf(ip->ip_node, fixcalls, 0); storefloat(ip, ip->ip_node); if (ip->ip_node->n_op == XASM) fixxfloat(ip, ip->ip_node); } if (stkpos != p2autooff) { DLIST_FOREACH(ip, ipole, qelem) { if (ip->type != IP_NODE) continue; walkf(ip->ip_node, updatereg, 0); } } if (stkpos > p2autooff) p2autooff = stkpos; if (stkpos > p2maxautooff) p2maxautooff = stkpos; if (x2debug) printip(ipole); } /* * Remove some PCONVs after OREGs are created. */ static void pconv2(NODE *p, void *arg) { NODE *q; if (p->n_op == PLUS) { if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) { if (p->n_right->n_op != ICON) return; if (p->n_left->n_op != PCONV) return; if (p->n_left->n_left->n_op != OREG) return; q = p->n_left->n_left; nfree(p->n_left); p->n_left = q; /* * This will be converted to another OREG later. */ } } } void mycanon(NODE *p) { walkf(p, pconv2, 0); } void myoptim(struct interpass *ip) { } static char rl[] = { EAX, EAX, EAX, EAX, EAX, EDX, EDX, EDX, EDX, ECX, ECX, ECX, EBX, EBX, ESI }; static char rh[] = { EDX, ECX, EBX, ESI, EDI, ECX, EBX, ESI, EDI, EBX, ESI, EDI, ESI, EDI, EDI }; void rmove(int s, int d, TWORD t) { int sl, sh, dl, dh; switch (t) { case LONGLONG: case ULONGLONG: #if 1 sl = rl[s-EAXEDX]; sh = rh[s-EAXEDX]; dl = rl[d-EAXEDX]; dh = rh[d-EAXEDX]; /* sanity checks, remove when satisfied */ if (memcmp(rnames[s], rnames[sl]+1, 3) != 0 || memcmp(rnames[s]+3, rnames[sh]+1, 3) != 0) comperr("rmove source error"); if (memcmp(rnames[d], rnames[dl]+1, 3) != 0 || memcmp(rnames[d]+3, rnames[dh]+1, 3) != 0) comperr("rmove dest error"); #define SW(x,y) { int i = x; x = y; y = i; } if (sh == dl) { /* Swap if overwriting */ SW(sl, sh); SW(dl, dh); } if (sl != dl) printf(" movl %s,%s\n", rnames[sl], rnames[dl]); if (sh != dh) printf(" movl %s,%s\n", rnames[sh], rnames[dh]); #else if (memcmp(rnames[s], rnames[d], 3) != 0) printf(" movl %%%c%c%c,%%%c%c%c\n", rnames[s][0],rnames[s][1],rnames[s][2], rnames[d][0],rnames[d][1],rnames[d][2]); if (memcmp(&rnames[s][3], &rnames[d][3], 3) != 0) printf(" movl %%%c%c%c,%%%c%c%c\n", rnames[s][3],rnames[s][4],rnames[s][5], rnames[d][3],rnames[d][4],rnames[d][5]); #endif break; #ifndef NOBREGS case CHAR: case UCHAR: printf(" movb %s,%s\n", rnames[s], rnames[d]); break; #endif case FLOAT: case DOUBLE: case LDOUBLE: #ifdef notdef /* a=b()*c(); will generate this */ comperr("bad float rmove: %d %d", s, d); #endif break; default: printf(" movl %s,%s\n", rnames[s], rnames[d]); } } /* * For class c, find worst-case displacement of the number of * registers in the array r[] indexed by class. */ int COLORMAP(int c, int *r) { int num; switch (c) { case CLASSA: num = r[CLASSB] > 4 ? 4 : r[CLASSB]; num += 2*r[CLASSC]; num += r[CLASSA]; return num < 6; #ifndef NOBREGS case CLASSB: num = r[CLASSA]; num += 2*r[CLASSC]; num += r[CLASSB]; return num < 4; #endif case CLASSC: num = r[CLASSA]; num += r[CLASSB] > 4 ? 4 : r[CLASSB]; num += 2*r[CLASSC]; return num < 5; case CLASSD: return r[CLASSD] < DREGCNT; } return 0; /* XXX gcc */ } char *rnames[] = { "%eax", "%edx", "%ecx", "%ebx", "%esi", "%edi", "%ebp", "%esp", "%al", "%ah", "%dl", "%dh", "%cl", "%ch", "%bl", "%bh", "eaxedx", "eaxecx", "eaxebx", "eaxesi", "eaxedi", "edxecx", "edxebx", "edxesi", "edxedi", "ecxebx", "ecxesi", "ecxedi", "ebxesi", "ebxedi", "esiedi", "%st0", "%st1", "%st2", "%st3", "%st4", "%st5", "%st6", "%st7", }; /* * Return a class suitable for a specific type. */ int gclass(TWORD t) { #ifndef NOBREGS if (t == CHAR || t == UCHAR) return CLASSB; #endif if (t == LONGLONG || t == ULONGLONG) return CLASSC; if (t == FLOAT || t == DOUBLE || t == LDOUBLE) return CLASSD; return CLASSA; } /* * Calculate argument sizes. */ void lastcall(NODE *p) { NODE *op = p; int nr = 0, size = 0; p->n_qual = 0; if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) return; for (p = p->n_right; p->n_op == CM; p = p->n_left) { if (p->n_right->n_op != ASSIGN) size += argsiz(p->n_right); else nr = 1; } if (p->n_op != ASSIGN) size += argsiz(p); else nr++; if (op->n_op == STCALL) { if (kflag) nr--; if (nr == 0) size -= 4; /* XXX OpenBSD? */ } #if defined(MACHOABI) int newsize = (size + 15) & ~15; /* stack alignment */ int align = newsize-size; if (align != 0) printf(" subl $%d,%%esp\n", align); size=newsize; #endif op->n_qual = size; /* XXX */ } /* * Special shapes. */ int special(NODE *p, int shape) { int o = p->n_op; switch (shape) { case SFUNCALL: if (o == STCALL || o == USTCALL) return SRREG; break; case SPCON: if (o != ICON || p->n_name[0] || getlval(p) < 0 || getlval(p) > 0x7fffffff) break; return SRDIR; case SMIXOR: return tshape(p, SZERO); case SMILWXOR: if (o != ICON || p->n_name[0] || getlval(p) == 0 || getlval(p) & 0xffffffff) break; return SRDIR; case SMIHWXOR: if (o != ICON || p->n_name[0] || getlval(p) == 0 || (getlval(p) >> 32) != 0) break; return SRDIR; } return SRNOPE; } /* * Target-dependent command-line options. */ void mflags(char *str) { #define MSET(s,a) if (strcmp(str, s) == 0) \ msettings = (msettings & ~MCPUMSK) | a MSET("arch=i386",MI386); MSET("arch=i486",MI486); MSET("arch=i586",MI586); MSET("arch=i686",MI686); } /* * Do something target-dependent for xasm arguments. */ int myxasm(struct interpass *ip, NODE *p) { struct interpass *ip2; int Cmax[] = { 31, 63, 127, 0xffff, 3, 255 }; NODE *in = 0, *ut = 0; TWORD t; char *w; int reg; int c, cw; CONSZ v; cw = xasmcode(p->n_name); if (cw & (XASMASG|XASMINOUT)) ut = p->n_left; if ((cw & XASMASG) == 0) in = p->n_left; c = XASMVAL(cw); switch (c) { case 'D': reg = EDI; break; case 'S': reg = ESI; break; case 'a': reg = EAX; break; case 'b': reg = EBX; break; case 'c': reg = ECX; break; case 'd': reg = EDX; break; case 't': case 'u': p->n_name = tmpstrdup(p->n_name); w = strchr(p->n_name, XASMVAL(cw)); *w = 'r'; /* now reg */ return 1; case 'A': reg = EAXEDX; break; case 'q': { /* Set edges in MYSETXARG */ if (p->n_left->n_op == REG || p->n_left->n_op == TEMP) return 1; t = p->n_left->n_type; if (in && ut) in = tcopy(in); p->n_left = mklnode(TEMP, 0, p2env.epp->ip_tmpnum++, t); if (ut) { ip2 = ipnode(mkbinode(ASSIGN, ut, tcopy(p->n_left), t)); DLIST_INSERT_AFTER(ip, ip2, qelem); } if (in) { ip2 = ipnode(mkbinode(ASSIGN, tcopy(p->n_left), in, t)); DLIST_INSERT_BEFORE(ip, ip2, qelem); } return 1; } case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': if (p->n_left->n_op != ICON) { if ((c = XASMVAL1(cw)) != 0) { p->n_name++; return 0; /* Try again */ } uerror("xasm arg not constant"); } v = getlval(p->n_left); if ((c == 'K' && v < -128) || (c == 'L' && v != 0xff && v != 0xffff) || (c != 'K' && v < 0) || (v > Cmax[c-'I'])) uerror("xasm val out of range"); p->n_name = "i"; return 1; default: return 0; } /* If there are requested either memory or register, delete memory */ w = p->n_name = tmpstrdup(p->n_name); if (*w == '=') w++; *w++ = 'r'; *w = 0; t = p->n_left->n_type; if (reg == EAXEDX) { ; } else { if (t == CHAR || t == UCHAR) { reg = reg * 2 + 8; } } if (t == FLOAT || t == DOUBLE || t == LDOUBLE) { reg += 037; } if (in && ut) in = tcopy(in); p->n_left = mklnode(REG, 0, reg, t); if (ut) { ip2 = ipnode(mkbinode(ASSIGN, ut, tcopy(p->n_left), t)); DLIST_INSERT_AFTER(ip, ip2, qelem); } if (in) { ip2 = ipnode(mkbinode(ASSIGN, tcopy(p->n_left), in, t)); DLIST_INSERT_BEFORE(ip, ip2, qelem); } return 1; } void targarg(char *w, void *arg) { NODE **ary = arg; NODE *p, *q; if (ary[(int)w[1]-'0'] == 0) p = ary[(int)w[1]-'0'-1]->n_left; /* XXX */ else p = ary[(int)w[1]-'0']->n_left; if (optype(p->n_op) != LTYPE) comperr("bad xarg op %d", p->n_op); q = tcopy(p); if (q->n_op == REG) { if (*w == 'k') { q->n_type = INT; } else if (*w != 'w') { if (q->n_type > UCHAR) { regno(q) = regno(q)*2+8; if (*w == 'h') regno(q)++; } q->n_type = INT; } else q->n_type = SHORT; } adrput(stdout, q); tfree(q); } /* * target-specific conversion of numeric arguments. */ int numconv(void *ip, void *p1, void *q1) { NODE *p = p1, *q = q1; int cw = xasmcode(q->n_name); switch (XASMVAL(cw)) { case 'a': case 'b': case 'c': case 'd': p->n_name = tmpcalloc(2); p->n_name[0] = (char)XASMVAL(cw); return 1; default: return 0; } } static struct { char *name; int num; } xcr[] = { { "eax", EAX }, { "ebx", EBX }, { "ecx", ECX }, { "edx", EDX }, { "esi", ESI }, { "edi", EDI }, { "ax", EAX }, { "bx", EBX }, { "cx", ECX }, { "dx", EDX }, { NULL, 0 }, }; /* * Check for other names of the xasm constraints registers. */ /* * Check for other names of the xasm constraints registers. */ int xasmconstregs(char *s) { int i; if (strncmp(s, "st", 2) == 0) { int off =0; if (s[2] == '(' && s[4] == ')') off = s[3] - '0'; return ESIEDI + 1 + off; } for (i = 0; xcr[i].name; i++) if (strcmp(xcr[i].name, s) == 0) return xcr[i].num; return -1; } pcc-20181216/arch/i386/macdefs.h010064400017500000000000000361201332703467700146630ustar raggewheel/* $Id: macdefs.h,v 1.99 2018/07/28 09:39:11 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Machine-dependent defines for both passes. */ #undef NOBREGS /* * Convert (multi-)character constant to integer. */ #define makecc(val,i) lastcon = (lastcon<<8)|((val<<24)>>24); #define ARGINIT 64 /* # bits above fp where arguments start */ #define AUTOINIT 0 /* # bits below fp where automatics start */ /* * Storage space requirements */ #define SZCHAR 8 #define SZBOOL 8 #define SZINT 32 #define SZFLOAT 32 #define SZDOUBLE 64 #ifdef MACHOABI #define SZLDOUBLE 128 #else #define SZLDOUBLE 96 #endif #define SZLONG 32 #define SZSHORT 16 #define SZLONGLONG 64 #define SZPOINT(t) 32 /* * Alignment constraints */ #define ALCHAR 8 #define ALBOOL 8 #define ALINT 32 #define ALFLOAT 32 #define ALDOUBLE 32 #ifdef MACHOABI #define ALLDOUBLE 128 #else #define ALLDOUBLE 32 #endif #define ALLONG 32 #define ALLONGLONG 32 #define ALSHORT 16 #define ALPOINT 32 #undef ALSTRUCT /* Not defined if ELF ABI */ #define ALSTACK 32 #define ALMAX 128 /* not yet supported type */ /* * Min/max values. */ #define MIN_CHAR -128 #define MAX_CHAR 127 #define MAX_UCHAR 255 #define MIN_SHORT -32768 #define MAX_SHORT 32767 #define MAX_USHORT 65535 #define MIN_INT (-0x7fffffff-1) #define MAX_INT 0x7fffffff #define MAX_UNSIGNED 0xffffffff #define MIN_LONG MIN_INT #define MAX_LONG MAX_INT #define MAX_ULONG MAX_UNSIGNED #define MIN_LONGLONG 0x8000000000000000LL #define MAX_LONGLONG 0x7fffffffffffffffLL #define MAX_ULONGLONG 0xffffffffffffffffULL /* Default char is signed */ #undef CHAR_UNSIGNED #define BOOL_TYPE UCHAR /* what used to store _Bool */ #undef UNALIGNED_ACCESS /* * Use large-enough types. */ typedef long long CONSZ; typedef unsigned long long U_CONSZ; typedef long long OFFSZ; #define CONFMT "%lld" /* format for printing constants */ #if defined(ELFABI) #define LABFMT ".L%d" /* format for printing labels */ #define STABLBL ".LL%d" /* format for stab (debugging) labels */ #else #define LABFMT "L%d" /* format for printing labels */ #define STABLBL "LL%d" /* format for stab (debugging) labels */ #endif #ifdef LANG_F77 #define BLANKCOMMON "_BLNK_" #define MSKIREG (M(TYSHORT)|M(TYLONG)) #define TYIREG TYLONG #define FSZLENG FSZLONG #define AUTOREG EBP #define ARGREG EBP #define ARGOFFSET 8 #endif #define TARGET_TIMODE /* has TI/TF/TC types (128 bit) */ #ifdef MACHOABI #define STAB_LINE_ABSOLUTE /* S_LINE fields use absolute addresses */ #define MYALIGN /* user power-of-2 alignment */ #endif #define BACKAUTO /* stack grows negatively for automatics */ #define BACKTEMP /* stack grows negatively for temporaries */ #undef FIELDOPS /* no bit-field instructions */ #define TARGET_ENDIAN TARGET_LE #define FINDMOPS /* i386 has instructions that modifies memory */ #define CC_DIV_0 /* division by zero is safe in the compiler */ /* Definitions mostly used in pass2 */ #define BYTEOFF(x) ((x)&03) #define wdal(k) (BYTEOFF(k)==0) #define STOARG(p) #define STOFARG(p) #define STOSTARG(p) #define genfcall(a,b) gencall(a,b) #define szty(t) (((t) == DOUBLE || (t) == FLOAT || \ (t) == LONGLONG || (t) == ULONGLONG) ? 2 : (t) == LDOUBLE ? 3 : 1) /* * The x86 has a bunch of register classes, most of them interfering * with each other. All registers are given a sequential number to * identify it which must match rnames[] in local2.c. * Class membership and overlaps are defined in the macros RSTATUS * and ROVERLAP below. * * The classes used on x86 are: * A - short and int regs * B - char regs * C - long long regs * D - floating point */ #define EAX 000 /* Scratch and return register */ #define EDX 001 /* Scratch and secondary return register */ #define ECX 002 /* Scratch (and shift count) register */ #define EBX 003 /* GDT pointer or callee-saved temporary register */ #define ESI 004 /* Callee-saved temporary register */ #define EDI 005 /* Callee-saved temporary register */ #define EBP 006 /* Frame pointer */ #define ESP 007 /* Stack pointer */ #ifndef NOBREGS #define AL 010 #define AH 011 #define DL 012 #define DH 013 #define CL 014 #define CH 015 #define BL 016 #define BH 017 #endif #define EAXEDX 020 #define EAXECX 021 #define EAXEBX 022 #define EAXESI 023 #define EAXEDI 024 #define EDXECX 025 #define EDXEBX 026 #define EDXESI 027 #define EDXEDI 030 #define ECXEBX 031 #define ECXESI 032 #define ECXEDI 033 #define EBXESI 034 #define EBXEDI 035 #define ESIEDI 036 /* The 8 math registers in class D lacks names */ #define MAXREGS 047 /* 39 registers */ #ifdef NOBREGS #define RSTATUS \ SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|PERMREG, \ SAREG|PERMREG, SAREG|PERMREG, 0, 0, \ 0, 0, 0, 0, 0, 0, 0, 0, \ SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \ SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \ SDREG, SDREG, SDREG, SDREG, SDREG, SDREG, SDREG, SDREG, #else #define RSTATUS \ SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|PERMREG, \ SAREG|PERMREG, SAREG|PERMREG, 0, 0, \ SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \ SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \ SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \ SDREG, SDREG, SDREG, SDREG, SDREG, SDREG, SDREG, SDREG, #endif #ifdef NOBREGS #define ROVERLAP \ /* 8 basic registers */\ { EAXEDX, EAXECX, EAXEBX, EAXESI, EAXEDI, -1 },\ { EAXEDX, EDXECX, EDXEBX, EDXESI, EDXEDI, -1 },\ { EAXECX, EDXECX, ECXEBX, ECXESI, ECXEDI, -1 },\ { EAXEBX, EDXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\ { EAXESI, EDXESI, ECXESI, EBXESI, ESIEDI, -1 },\ { EAXEDI, EDXEDI, ECXEDI, EBXEDI, ESIEDI, -1 },\ { -1 },\ { -1 },\ \ /* 8 char registers */\ { EAX, EAXEDX, EAXECX, EAXEBX, EAXESI, EAXEDI, -1 },\ { EAX, EAXEDX, EAXECX, EAXEBX, EAXESI, EAXEDI, -1 },\ { EDX, EAXEDX, EDXECX, EDXEBX, EDXESI, EDXEDI, -1 },\ { EDX, EAXEDX, EDXECX, EDXEBX, EDXESI, EDXEDI, -1 },\ { ECX, EAXECX, EDXECX, ECXEBX, ECXESI, ECXEDI, -1 },\ { ECX, EAXECX, EDXECX, ECXEBX, ECXESI, ECXEDI, -1 },\ { EBX, EAXEBX, EDXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\ { EBX, EAXEBX, EDXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\ \ /* 15 long-long-emulating registers */\ { EAX, EDX, EAXECX, EAXEBX, EAXESI, /* eaxedx */\ EAXEDI, EDXECX, EDXEBX, EDXESI, EDXEDI, -1, },\ { EAX, ECX, EAXEDX, EAXEBX, EAXESI, /* eaxecx */\ EAXEDI, EDXECX, ECXEBX, ECXESI, ECXEDI, -1 },\ { EAX, EBX, EAXEDX, EAXECX, EAXESI, /* eaxebx */\ EAXEDI, EDXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\ { EAX, ESI, EAXEDX, EAXECX, EAXEBX, EAXEDI, /* eaxesi */\ EDXESI, ECXESI, EBXESI, ESIEDI, -1 },\ { EAX, EDI, EAXEDX, EAXECX, EAXEBX, EAXESI, /* eaxedi */\ EDXEDI, ECXEDI, EBXEDI, ESIEDI, -1 },\ { EDX, ECX, EAXEDX, EAXECX, EDXEBX, /* edxecx */\ EDXESI, EDXEDI, ECXEBX, ECXESI, ECXEDI, -1 },\ { EDX, EBX, EAXEDX, EDXECX, EDXESI, /* edxebx */\ EDXEDI, EAXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\ { EDX, ESI, EAXEDX, EDXECX, EDXEBX, EDXEDI, /* edxesi */\ EAXESI, ECXESI, EBXESI, ESIEDI, -1 },\ { EDX, EDI, EAXEDX, EDXECX, EDXEBX, EDXESI, /* edxedi */\ EAXEDI, ECXEDI, EBXEDI, ESIEDI, -1 },\ { ECX, EBX, EAXECX, EDXECX, ECXESI, /* ecxebx */\ ECXEDI, EAXEBX, EDXEBX, EBXESI, EBXEDI, -1 },\ { ECX, ESI, EAXECX, EDXECX, ECXEBX, ECXEDI, /* ecxesi */\ EAXESI, EDXESI, EBXESI, ESIEDI, -1 },\ { ECX, EDI, EAXECX, EDXECX, ECXEBX, ECXESI, /* ecxedi */\ EAXEDI, EDXEDI, EBXEDI, ESIEDI, -1 },\ { EBX, ESI, EAXEBX, EDXEBX, ECXEBX, EBXEDI, /* ebxesi */\ EAXESI, EDXESI, ECXESI, ESIEDI, -1 },\ { EBX, EDI, EAXEBX, EDXEBX, ECXEBX, EBXESI, /* ebxedi */\ EAXEDI, EDXEDI, ECXEDI, ESIEDI, -1 },\ { ESI, EDI, EAXESI, EDXESI, ECXESI, EBXESI, /* esiedi */\ EAXEDI, EDXEDI, ECXEDI, EBXEDI, -1 },\ \ /* The fp registers do not overlap with anything */\ { -1 },\ { -1 },\ { -1 },\ { -1 },\ { -1 },\ { -1 },\ { -1 },\ { -1 }, #else #define ROVERLAP \ /* 8 basic registers */\ { AL, AH, EAXEDX, EAXECX, EAXEBX, EAXESI, EAXEDI, -1 },\ { DL, DH, EAXEDX, EDXECX, EDXEBX, EDXESI, EDXEDI, -1 },\ { CL, CH, EAXECX, EDXECX, ECXEBX, ECXESI, ECXEDI, -1 },\ { BL, BH, EAXEBX, EDXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\ { EAXESI, EDXESI, ECXESI, EBXESI, ESIEDI, -1 },\ { EAXEDI, EDXEDI, ECXEDI, EBXEDI, ESIEDI, -1 },\ { -1 },\ { -1 },\ \ /* 8 char registers */\ { EAX, EAXEDX, EAXECX, EAXEBX, EAXESI, EAXEDI, -1 },\ { EAX, EAXEDX, EAXECX, EAXEBX, EAXESI, EAXEDI, -1 },\ { EDX, EAXEDX, EDXECX, EDXEBX, EDXESI, EDXEDI, -1 },\ { EDX, EAXEDX, EDXECX, EDXEBX, EDXESI, EDXEDI, -1 },\ { ECX, EAXECX, EDXECX, ECXEBX, ECXESI, ECXEDI, -1 },\ { ECX, EAXECX, EDXECX, ECXEBX, ECXESI, ECXEDI, -1 },\ { EBX, EAXEBX, EDXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\ { EBX, EAXEBX, EDXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\ \ /* 15 long-long-emulating registers */\ { EAX, AL, AH, EDX, DL, DH, EAXECX, EAXEBX, EAXESI, /* eaxedx */\ EAXEDI, EDXECX, EDXEBX, EDXESI, EDXEDI, -1, },\ { EAX, AL, AH, ECX, CL, CH, EAXEDX, EAXEBX, EAXESI, /* eaxecx */\ EAXEDI, EDXECX, ECXEBX, ECXESI, ECXEDI, -1 },\ { EAX, AL, AH, EBX, BL, BH, EAXEDX, EAXECX, EAXESI, /* eaxebx */\ EAXEDI, EDXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\ { EAX, AL, AH, ESI, EAXEDX, EAXECX, EAXEBX, EAXEDI, /* eaxesi */\ EDXESI, ECXESI, EBXESI, ESIEDI, -1 },\ { EAX, AL, AH, EDI, EAXEDX, EAXECX, EAXEBX, EAXESI, /* eaxedi */\ EDXEDI, ECXEDI, EBXEDI, ESIEDI, -1 },\ { EDX, DL, DH, ECX, CL, CH, EAXEDX, EAXECX, EDXEBX, /* edxecx */\ EDXESI, EDXEDI, ECXEBX, ECXESI, ECXEDI, -1 },\ { EDX, DL, DH, EBX, BL, BH, EAXEDX, EDXECX, EDXESI, /* edxebx */\ EDXEDI, EAXEBX, ECXEBX, EBXESI, EBXEDI, -1 },\ { EDX, DL, DH, ESI, EAXEDX, EDXECX, EDXEBX, EDXEDI, /* edxesi */\ EAXESI, ECXESI, EBXESI, ESIEDI, -1 },\ { EDX, DL, DH, EDI, EAXEDX, EDXECX, EDXEBX, EDXESI, /* edxedi */\ EAXEDI, ECXEDI, EBXEDI, ESIEDI, -1 },\ { ECX, CL, CH, EBX, BL, BH, EAXECX, EDXECX, ECXESI, /* ecxebx */\ ECXEDI, EAXEBX, EDXEBX, EBXESI, EBXEDI, -1 },\ { ECX, CL, CH, ESI, EAXECX, EDXECX, ECXEBX, ECXEDI, /* ecxesi */\ EAXESI, EDXESI, EBXESI, ESIEDI, -1 },\ { ECX, CL, CH, EDI, EAXECX, EDXECX, ECXEBX, ECXESI, /* ecxedi */\ EAXEDI, EDXEDI, EBXEDI, ESIEDI, -1 },\ { EBX, BL, BH, ESI, EAXEBX, EDXEBX, ECXEBX, EBXEDI, /* ebxesi */\ EAXESI, EDXESI, ECXESI, ESIEDI, -1 },\ { EBX, BL, BH, EDI, EAXEBX, EDXEBX, ECXEBX, EBXESI, /* ebxedi */\ EAXEDI, EDXEDI, ECXEDI, ESIEDI, -1 },\ { ESI, EDI, EAXESI, EDXESI, ECXESI, EBXESI, /* esiedi */\ EAXEDI, EDXEDI, ECXEDI, EBXEDI, -1 },\ \ /* The fp registers do not overlap with anything */\ { -1 },\ { -1 },\ { -1 },\ { -1 },\ { -1 },\ { -1 },\ { -1 },\ { -1 }, #endif #ifdef NOBREGS /* Return a register class based on the type of the node */ #define PCLASS(p) ((p->n_type == LONGLONG || p->n_type == ULONGLONG ? SCREG : \ (p->n_type >= FLOAT && p->n_type <= LDOUBLE ? SDREG : SAREG))) #else /* Return a register class based on the type of the node */ #define PCLASS(p) (p->n_type <= UCHAR ? SBREG : \ (p->n_type == LONGLONG || p->n_type == ULONGLONG ? SCREG : \ (p->n_type >= FLOAT && p->n_type <= LDOUBLE ? SDREG : SAREG))) #endif #define NUMCLASS 4 /* highest number of reg classes used */ int COLORMAP(int c, int *r); #define GCLASS(x) (x < 8 ? CLASSA : x < 16 ? CLASSB : x < 31 ? CLASSC : CLASSD) #define DECRA(x,y) (((x) >> (y*6)) & 63) /* decode encoded regs */ #define ENCRD(x) (x) /* Encode dest reg in n_reg */ #define ENCRA1(x) ((x) << 6) /* A1 */ #define ENCRA2(x) ((x) << 12) /* A2 */ #define ENCRA(x,y) ((x) << (6+y*6)) /* encode regs in int */ /* XXX - return char in al? */ #ifdef NOBREGS #define RETREG(x) (x == LONGLONG || x == ULONGLONG ? EAXEDX : \ x == FLOAT || x == DOUBLE || x == LDOUBLE ? 31 : EAX) #else #define RETREG(x) (x == CHAR || x == UCHAR ? AL : \ x == LONGLONG || x == ULONGLONG ? EAXEDX : \ x == FLOAT || x == DOUBLE || x == LDOUBLE ? 31 : EAX) #endif #if 0 #define R2REGS 1 /* permit double indexing */ #endif /* XXX - to die */ #define FPREG EBP /* frame pointer */ #define STKREG ESP /* stack pointer */ #define SHSTR (MAXSPECIAL+1) /* short struct */ #define SFUNCALL (MAXSPECIAL+2) /* struct assign after function call */ #define SPCON (MAXSPECIAL+3) /* positive nonnamed constant */ /* * Specials that indicate the applicability of machine idioms. */ #define SMIXOR (MAXSPECIAL+4) #define SMILWXOR (MAXSPECIAL+5) #define SMIHWXOR (MAXSPECIAL+6) /* * i386-specific pass1 attributes. */ #define ATTR_P1_TARGET ATTR_I386_DLLINDIRECT /* * i386-specific interpass stuff. */ #define TARGET_IPP_MEMBERS \ int ipp_argstacksize; #define target_members_print_prolog(ipp) printf("%d", ipp->ipp_argstacksize) #define target_members_print_epilog(ipp) printf("%d", ipp->ipp_argstacksize) #define target_members_read_prolog(ipp) ipp->ipp_argstacksize = rdint(&p) #define target_members_read_epilog(ipp) ipp->ipp_argstacksize = rdint(&p) #define HAVE_WEAKREF #define TARGET_FLT_EVAL_METHOD 2 /* all as long double */ /* * Extended assembler macros. */ void targarg(char *w, void *arg); #define XASM_TARGARG(w, ary) \ (w[1] == 'b' || w[1] == 'h' || w[1] == 'w' || w[1] == 'k' ? \ w++, targarg(w, ary), 1 : 0) int numconv(void *ip, void *p, void *q); #define XASM_NUMCONV(ip, p, q) numconv(ip, p, q) int xasmconstregs(char *); #define XASMCONSTREGS(x) xasmconstregs(x) #define MYSETXARG if (XASMVAL(cw) == 'q') { \ c = 'r'; addalledges(&ablock[ESI]); addalledges(&ablock[EDI]); } #if defined(MACHOABI) struct stub { struct { struct stub *q_forw, *q_back; } link; char *name; }; extern struct stub stublist; extern struct stub nlplist; void addstub(struct stub *list, char *name); #endif /* -m flags */ extern int msettings; #define MI386 0x001 #define MI486 0x002 #define MI586 0x004 #define MI686 0x008 #define MCPUMSK 0x00f /* target specific attributes */ #define ATTR_MI_TARGET ATTR_I386_FCMPLRET, ATTR_I386_FPPOP #define NEWNEED /* floating point definitions */ #define USE_IEEEFP_32 #define FLT_PREFIX IEEEFP_32 #define USE_IEEEFP_64 #define DBL_PREFIX IEEEFP_64 #define USE_IEEEFP_X80 #define LDBL_PREFIX IEEEFP_X80 pcc-20181216/arch/i386/order.c010064400017500000000000000102231306074070100143450ustar raggewheel/* $Id: order.c,v 1.64 2017/03/11 09:22:09 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass2.h" #include int canaddr(NODE *); /* is it legal to make an OREG or NAME entry which has an * offset of off, (from a register of r), if the * resulting thing had type t */ int notoff(TWORD t, int r, CONSZ off, char *cp) { return(0); /* YES */ } /* * Turn a UMUL-referenced node into OREG. * Be careful about register classes, this is a place where classes change. */ void offstar(NODE *p, int shape) { NODE *r; if (x2debug) printf("offstar(%p)\n", p); if (isreg(p)) return; /* Is already OREG */ r = p->n_right; if( p->n_op == PLUS || p->n_op == MINUS ){ if( r->n_op == ICON ){ if (isreg(p->n_left) == 0) (void)geninsn(p->n_left, INAREG); /* Converted in ormake() */ return; } if (r->n_op == LS && r->n_right->n_op == ICON && getlval(r->n_right) == 2 && p->n_op == PLUS) { if (isreg(p->n_left) == 0) (void)geninsn(p->n_left, INAREG); if (isreg(r->n_left) == 0) (void)geninsn(r->n_left, INAREG); return; } } (void)geninsn(p, INAREG); } /* * Do the actual conversion of offstar-found OREGs into real OREGs. */ void myormake(NODE *q) { NODE *p, *r; if (x2debug) printf("myormake(%p)\n", q); p = q->n_left; if (p->n_op == PLUS && (r = p->n_right)->n_op == LS && r->n_right->n_op == ICON && getlval(r->n_right) == 2 && p->n_left->n_op == REG && r->n_left->n_op == REG) { q->n_op = OREG; setlval(q, 0); q->n_rval = R2PACK(p->n_left->n_rval, r->n_left->n_rval, 0); tfree(p); } } /* * Shape matches for UMUL. Cooperates with offstar(). */ int shumul(NODE *p, int shape) { if (x2debug) printf("shumul(%p)\n", p); /* Turns currently anything into OREG on x86 */ if (shape & SOREG) return SROREG; return SRNOPE; } /* * Rewrite operations on binary operators (like +, -, etc...). * Called as a result of table lookup. */ int setbin(NODE *p) { if (x2debug) printf("setbin(%p)\n", p); return 0; } /* setup for assignment operator */ int setasg(NODE *p, int cookie) { if (x2debug) printf("setasg(%p)\n", p); return(0); } /* setup for unary operator */ int setuni(NODE *p, int cookie) { return 0; } /* * Set evaluation order of a binary node if it differs from default. */ int setorder(NODE *p) { return 0; /* nothing differs on x86 */ } /* * set registers in calling conventions live. */ int * livecall(NODE *p) { static int r[] = { EAX, EBX, -1 }; int off = 1; #ifdef TLS if (p->n_left->n_op == ICON && strcmp(p->n_left->n_name, "___tls_get_addr@PLT") == 0) off--; #endif return kflag ? &r[off] : &r[2]; } /* * Signal whether the instruction is acceptable for this target. */ int acceptable(struct optab *op) { return 1; } pcc-20181216/arch/i386/table.c010064400017500000000000001223541337532075700143500ustar raggewheel/* $Id: table.c,v 1.150 2018/11/21 18:20:31 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass2.h" # define TLL TLONGLONG|TULONGLONG # define ANYSIGNED TINT|TLONG|TSHORT|TCHAR # define ANYUSIGNED TUNSIGNED|TULONG|TUSHORT|TUCHAR # define ANYFIXED ANYSIGNED|ANYUSIGNED # define TUWORD TUNSIGNED|TULONG # define TSWORD TINT|TLONG # define TWORD TUWORD|TSWORD #define TAREG TINT|TSHORT|TCHAR|TUNSIGNED|TUSHORT|TUCHAR #define SHINT SAREG /* short and int */ #define ININT INAREG #ifndef NOBREGS #define SHCH SBREG /* shape for char */ #define INCH INBREG #endif #define SHLL SCREG /* shape for long long */ #define INLL INCREG #define SHFL SDREG /* shape for float/double */ #define INFL INDREG /* shape for float/double */ #define XSL(c) NEEDS(NREG(c, 1), NSL(c)) struct optab table[] = { /* First entry must be an empty entry */ { -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", }, /* PCONVs are usually not necessary */ { PCONV, INAREG, SAREG, TWORD|TPOINT, SAREG, TWORD|TPOINT, 0, RLEFT, "", }, /* * A bunch conversions of integral<->integral types * There are lots of them, first in table conversions to itself * and then conversions from each type to the others. */ /* itself to itself, including pointers */ #ifdef NOBREGS /* convert (u)char to (u)char. */ { SCONV, INAREG, SAREG, TCHAR|TUCHAR, SAREG, TCHAR|TUCHAR, 0, RLEFT, "", }, #else /* convert (u)char to (u)char. */ { SCONV, INCH, SHCH, TCHAR|TUCHAR, SHCH, TCHAR|TUCHAR, 0, RLEFT, "", }, #endif /* convert pointers to int. */ { SCONV, ININT, SHINT, TPOINT|TWORD, SANY, TWORD, 0, RLEFT, "", }, /* convert (u)longlong to (u)longlong. */ { SCONV, INLL, SHLL, TLL, SHLL, TLL, 0, RLEFT, "", }, /* convert between float/double/long double. */ { SCONV, INFL, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, 0, RLEFT, "ZI", }, /* convert pointers to pointers. */ { SCONV, ININT, SHINT, TPOINT, SANY, TPOINT, 0, RLEFT, "", }, /* char to something */ #ifdef NOBREGS /* convert char to (unsigned) short. */ /* Done when reg is loaded */ { SCONV, INAREG, SAREG, TCHAR|TUCHAR, SAREG, TSHORT|TUSHORT, 0, RLEFT, "", }, /* convert char to (unsigned) short. */ { SCONV, INAREG, SOREG|SNAME, TCHAR, SAREG, TSHORT|TUSHORT, XSL(A), RESC1, " movsbl AL,A1\n", }, /* convert unsigned char to (u)short. */ { SCONV, INAREG, SOREG|SNAME, TUCHAR, SAREG, TSHORT|TUSHORT, NEEDS(NREG(A, 1), NSL(A)), RESC1, " movzbl AL,A1\n", }, #else /* convert char to (unsigned) short. */ { SCONV, ININT, SBREG|SOREG|SNAME, TCHAR, SAREG, TSHORT|TUSHORT, XSL(A), RESC1, " movsbw AL,A1\n", }, /* convert unsigned char to (u)short. */ { SCONV, ININT, SHCH|SOREG|SNAME, TUCHAR, SAREG, TSHORT|TUSHORT, NEEDS(NREG(A, 1), NSL(A)), RESC1, " movzbw AL,A1\n", }, #endif /* convert signed char to int (or pointer). */ #ifdef NOBREGS { SCONV, ININT, SAREG, TCHAR|TUCHAR, SAREG, TWORD|TPOINT, 0, RLEFT, "", }, { SCONV, ININT, SOREG|SNAME, TCHAR, SAREG, TWORD|TPOINT, NEEDS(NREG(A, 1), NSL(A)), RESC1, " movsbl AL,A1\n", }, /* convert unsigned char to (u)int. */ { SCONV, ININT, SOREG|SNAME, TUCHAR, SAREG, TWORD, NEEDS(NREG(A, 1), NSL(A)), RESC1, " movzbl AL,A1\n", }, /* convert char to (u)long long */ { SCONV, INLL, SAREG, TCHAR, SANY, TLL, NEEDS(NREG(C, 1), NSL(C), NRES(EAXEDX), NLEFT(EAX)), RESC1, " cltd\n", }, /* convert unsigned char (in mem) to (u)long long */ { SCONV, INLL, SOREG|SNAME, TUCHAR, SANY, TLL, NEEDS(NREG(C, 1), NSL(C)), RESC1, " movzbl AL,A1\n xorl U1,U1\n", }, /* convert unsigned char to (u)long long */ { SCONV, INLL, SAREG, TUCHAR, SANY, TLL, NEEDS(NREG(C, 1), NSL(C)), RESC1, " movl AL,A1\n xorl U1,U1\n", }, /* convert (u)char (in register) to double */ { SCONV, INFL, SAREG, TCHAR|TUCHAR, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, NEEDS(NREG(D, 1), NTEMP(1)), RESC1, " movl AL,A2\n fildl A2\n", }, #else { SCONV, ININT, SHCH|SOREG|SNAME, TCHAR, SAREG, TWORD|TPOINT, NEEDS(NREG(A, 1), NSL(A)), RESC1, " movsbl AL,A1\n", }, /* convert unsigned char to (u)int. */ { SCONV, ININT, SHCH|SOREG|SNAME, TUCHAR, SAREG, TWORD, NEEDS(NREG(A, 1), NSL(A)), RESC1, " movzbl AL,A1\n", }, /* convert char to (u)long long */ { SCONV, INLL, SHCH|SOREG|SNAME, TCHAR, SANY, TLL, NEEDS(NREG(C, 1), NSL(C), NRES(EAXEDX), NEVER(EAX), NEVER(EDX)), RESC1, " movsbl AL,%eax\n cltd\n", }, /* convert unsigned char to (u)long long */ { SCONV, INLL, SHCH|SOREG|SNAME, TUCHAR, SANY, TLL, NEEDS(NREG(C, 1), NSL(C)), RESC1, " movzbl AL,A1\n xorl U1,U1\n", }, /* convert char (in register) to double XXX - use NTEMP */ { SCONV, INFL, SHCH|SOREG|SNAME, TCHAR, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, NEEDS(NREG(A, 1), NSL(A), NREG(D, 1)), RESC2, " movsbl AL,A1\n pushl A1\n" " fildl (%esp)\n addl $4,%esp\n", }, /* convert (u)char (in register) to double XXX - use NTEMP */ { SCONV, INFL, SHCH|SOREG|SNAME, TUCHAR, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, NEEDS(NREG(A, 1), NSL(A), NREG(D, 1)), RESC2, " movzbl AL,A1\n pushl A1\n" " fildl (%esp)\n addl $4,%esp\n", }, #endif /* short to something */ /* convert (u)short to (u)short. */ { SCONV, INAREG, SAREG, TSHORT|TUSHORT, SAREG, TSHORT|TUSHORT, 0, RLEFT, "", }, #ifdef NOBREGS /* convert short (in memory) to char */ { SCONV, INAREG, SNAME|SOREG, TSHORT|TUSHORT, SAREG, TCHAR|TUCHAR, XSL(A), RESC1, " movzbl AL,A1\n", }, /* convert short (in reg) to char. */ { SCONV, INAREG, SAREG, TSHORT|TUSHORT, SAREG, TCHAR|TUCHAR, NEEDS(NOLEFT(ESI), NOLEFT(EDI)), RLEFT, " movsbl AL,AL\n", }, /* convert short to (u)int. */ { SCONV, ININT, SOREG|SNAME, TSHORT, SAREG, TWORD, NEEDS(NREG(A, 1), NSL(A)), RESC1, " movswl AL,A1\n", }, /* convert unsigned short to (u)int. */ { SCONV, ININT, SOREG|SNAME, TUSHORT, SAREG, TWORD, NEEDS(NREG(A, 1), NSL(A)), RESC1, " movzwl AL,A1\n", }, /* convert unsigned short to (u)int (in reg) */ { SCONV, INAREG, SAREG, TSHORT|TUSHORT, SAREG, TWORD, 0, RLEFT, "", }, #else /* convert short (in memory) to char */ { SCONV, INCH, SNAME|SOREG, TSHORT|TUSHORT, SHCH, TCHAR|TUCHAR, NEEDS(NREG(B, 1), NSL(B)), RESC1, " movb AL,A1\n", }, /* convert short (in reg) to char. */ { SCONV, INCH, SAREG|SNAME|SOREG, TSHORT|TUSHORT, SHCH, TCHAR|TUCHAR, NEEDS(NREG(B, 1), NSL(B), NOLEFT(ESI), NOLEFT(EDI)), RESC1, "ZM", }, /* convert short to (u)int. */ { SCONV, ININT, SAREG|SOREG|SNAME, TSHORT, SAREG, TWORD, NEEDS(NREG(A, 1), NSL(A)), RESC1, " movswl AL,A1\n", }, /* convert unsigned short to (u)int. */ { SCONV, ININT, SAREG|SOREG|SNAME, TUSHORT, SAREG, TWORD, NEEDS(NREG(A, 1), NSL(A)), RESC1, " movzwl AL,A1\n", }, #endif /* convert short to (u)long long */ { SCONV, INLL, SAREG|SOREG|SNAME, TSHORT, SHLL, TLL, NEEDS(NREG(C, 1), NSL(C), NRES(EAXEDX), NEVER(EAX), NEVER(EDX)), RESC1, " movswl AL,%eax\n cltd\n", }, /* convert unsigned short to (u)long long */ { SCONV, INLL, SAREG|SOREG|SNAME, TUSHORT, SHLL, TLL, NEEDS(NREG(C, 1), NSL(C)), RESC1, " movzwl AL,A1\n xorl U1,U1\n", }, /* convert short (in memory) to float/double */ { SCONV, INFL, SOREG|SNAME, TSHORT, SDREG, TLDOUBLE|TDOUBLE|TFLOAT, NEEDS(NREG(D, 1)), RESC1, " fild AL\n", }, /* convert short (in register) to float/double */ { SCONV, INFL, SAREG, TSHORT, SDREG, TLDOUBLE|TDOUBLE|TFLOAT, NEEDS(NREG(D, 1), NTEMP(1)), RESC1, " pushw AL\n fild (%esp)\n addl $2,%esp\n", }, /* convert unsigned short to double XXX - use NTEMP */ { SCONV, INFL, SAREG|SOREG|SNAME, TUSHORT, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, NEEDS(NREG(A, 1), NSL(A), NREG(D, 1), NTEMP(1)), RESC2, " movzwl AL,A1\n movl A1,A3\n" " fildl A3\n", }, /* int to something */ /* convert int to char. This is done when register is loaded */ #ifdef NOBREGS { SCONV, INAREG, SAREG, TWORD|TPOINT, SAREG, TCHAR|TUCHAR, #if 0 NEEDS(NOLEFT(ESI), NOLEFT(EDI)), RLEFT, " movsbl ZT,AL\n", }, #else 0, RLEFT, "", }, #endif #else { SCONV, INCH, SAREG, TWORD|TPOINT, SANY, TCHAR|TUCHAR, NEEDS(NREG(B, 1), NSL(B), NOLEFT(ESI), NOLEFT(EDI)), RESC1, "ZM", }, #endif /* convert int to short. Nothing to do */ { SCONV, INAREG, SAREG, TWORD|TPOINT, SANY, TSHORT|TUSHORT, 0, RLEFT, "", }, /* convert signed int to (u)long long */ { SCONV, INLL, SHINT, TSWORD, SHLL, TLL, NEEDS(NREG(C, 1), NSL(C), NLEFT(EAX), NEVER(EAX), NEVER(EDX), NRES(EAXEDX)), RESC1, " cltd\n", }, /* convert unsigned int to (u)long long */ { SCONV, INLL, SHINT|SOREG|SNAME, TUWORD|TPOINT, SHLL, TLL, NEEDS(NREG(C, 1), NSL(C)), RESC1, " movl AL,A1\n xorl U1,U1\n", }, /* convert signed int (in memory) to double */ { SCONV, INFL, SOREG|SNAME, TSWORD, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, NEEDS(NREG(D, 1)), RESC1, " fildl AL\n", }, /* convert signed int (in register) to double */ { SCONV, INFL, SAREG, TSWORD, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, NEEDS(NREG(D, 1), NTEMP(1)), RESC1, " movl AL,A2\n fildl A2\n", }, /* convert unsigned int (reg&mem) to double */ { SCONV, INFL, SOREG|SNAME|SAREG, TUWORD, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, NEEDS(NREG(D, 1), NTEMP(1)), RESC1, " pushl $0\n" " pushl AL\n" " fildq (%esp)\n" " addl $8,%esp\n", }, /* long long to something */ #ifdef NOBREGS /* convert (u)long long to (u)char (mem->reg) */ { SCONV, INAREG, SOREG|SNAME, TLL, SANY, TUCHAR, XSL(A), RESC1, " movzbl AL,A1\n", }, { SCONV, INAREG, SOREG|SNAME, TLL, SANY, TCHAR, XSL(A), RESC1, " movsbl AL,A1\n", }, /* convert (u)long long to (u)char (reg->reg, hopefully nothing) */ { SCONV, INAREG, SHLL, TLL, SANY, TCHAR|TUCHAR, NEEDS(NREG(A, 1), NSL(A), NTEMP(1)), RESC1, "ZS", }, #else /* convert (u)long long to (u)char (mem->reg) */ { SCONV, INCH, SOREG|SNAME, TLL, SANY, TCHAR|TUCHAR, NEEDS(NREG(B, 1), NSL(B)), RESC1, " movb AL,A1\n", }, /* convert (u)long long to (u)char (reg->reg, hopefully nothing) */ { SCONV, INCH, SHLL, TLL, SANY, TCHAR|TUCHAR, NEEDS(NREG(B, 1), NSL(B), NTEMP(1)), RESC1, "ZS", }, #endif /* convert (u)long long to (u)short (mem->reg) */ { SCONV, INAREG, SOREG|SNAME, TLL, SAREG, TSHORT|TUSHORT, NEEDS(NREG(A, 1), NSL(A)), RESC1, " movw AL,A1\n", }, /* convert (u)long long to (u)short (reg->reg, hopefully nothing) */ { SCONV, INAREG, SHLL|SOREG|SNAME, TLL, SAREG, TSHORT|TUSHORT, NEEDS(NREG(A, 1), NSL(A), NTEMP(1)), RESC1, "ZS", }, /* convert long long to int (mem->reg) */ { SCONV, INAREG, SOREG|SNAME, TLL, SAREG, TWORD|TPOINT, NEEDS(NREG(A, 1), NSL(A)), RESC1, " movl AL,A1\n", }, /* convert long long to int (reg->reg, hopefully nothing) */ { SCONV, INAREG, SHLL|SOREG|SNAME, TLL, SAREG, TWORD|TPOINT, NEEDS(NREG(A, 1), NSL(A), NTEMP(1)), RESC1, "ZS", }, /* convert long long (in memory) to floating */ { SCONV, INFL, SOREG|SNAME, TLONGLONG, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, NEEDS(NREG(D, 1)), RESC1, " fildq AL\n", }, /* convert long long (in register) to floating */ { SCONV, INFL, SHLL, TLONGLONG, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, NEEDS(NREG(D, 1), NTEMP(1)), RESC1, " pushl UL\n pushl AL\n" " fildq (%esp)\n addl $8,%esp\n", }, /* convert unsigned long long to floating */ { SCONV, INFL, SCREG, TULONGLONG, SDREG, TLDOUBLE|TDOUBLE|TFLOAT, NEEDS(NREG(D, 1), NTEMP(1)), RESC1, "ZJ", }, /* float to something */ #if 0 /* go via int by adding an extra sconv in clocal() */ /* convert float/double to (u) char. XXX should use NTEMP here */ { SCONV, INCH, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, SHCH, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NEEDS(NREG(B, 1)), RESC1, " subl $4,%esp\n fistpl (%esp)\n popl A1\n", }, /* convert float/double to (u) int/short/char. XXX should use NTEMP here */ { SCONV, INCH, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, SHCH, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NEEDS(NREG(C, 1)), RESC1, " subl $4,%esp\n fistpl (%esp)\n popl A1\n", }, #endif /* convert float/double to int. XXX should use NTEMP here */ { SCONV, INAREG, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, SAREG, TSWORD, NEEDS(NREG(A, 1), NTEMP(3)), RESC1, " fnstcw A2\n" " fnstcw 4+A2\n" " movb $12,1+A2\n" " fldcw A2\n" " fistpl 8+A2\n" " movl 8+A2,A1\n" " fldcw 4+A2\n", }, /* convert float/double to unsigned int. */ { SCONV, INAREG, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, SAREG, TUWORD, NEEDS(NREG(A, 1), NTEMP(4)), RESC1, " fnstcw A2\n" " fnstcw 4+A2\n" " movb $12,1+A2\n" " fldcw A2\n" " fistpq 8+A2\n" " movl 8+A2,A1\n" " fldcw 4+A2\n", }, /* convert float/double (in register) to long long */ { SCONV, INLL, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, SHLL, TLONGLONG, NEEDS(NREG(C, 1), NTEMP(4)), RESC1, " fnstcw A2\n" " fnstcw 4+A2\n" " movb $12,1+A2\n" " fldcw A2\n" " fistpq 8+A2\n" " movl 8+A2,A1\n" " movl 12+A2,U1\n" " fldcw 4+A2\n", }, /* convert float/double (in register) to unsigned long long */ { SCONV, INLL, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, SHLL, TULONGLONG, NEEDS(NREG(C, 1), NTEMP(4)), RESC1, " fnstcw A2\n" " fnstcw 4+A2\n" " movb $7,1+A2\n" /* 64-bit, round down */ " fldcw A2\n" " movl $0x5f000000, 8+A2\n" /* (float)(1<<63) */ " fsubs 8+A2\n" /* keep in range of fistpq */ " fistpq 8+A2\n" " xorb $0x80,15+A2\n" /* addq $1>>63 to 8(%esp) */ " movl 8+A2,A1\n" " movl 12+A2,U1\n" " fldcw 4+A2\n", }, /* slut sconv */ /* * Subroutine calls. */ { UCALL, FOREFF, SCON, TANY, SANY, TANY, 0, 0, " call CL\nZC", }, { CALL, FOREFF, SCON, TANY, SANY, TANY, 0, 0, " call CL\nZC", }, { UCALL, FOREFF, SCON, TANY, SAREG, TWORD|TPOINT, 0, 0, " call CL\nZC", }, { CALL, INAREG, SCON, TANY, SAREG, TSHORT|TUSHORT|TWORD|TPOINT, NEEDS(NREG(A, 1), NSL(A)), RESC1, /* should be 0 */ " call CL\nZC", }, { UCALL, INAREG, SCON, TANY, SAREG, TSHORT|TUSHORT|TWORD|TPOINT, NEEDS(NREG(A, 1), NSL(A)), RESC1, /* should be 0 */ " call CL\nZC", }, { CALL, INBREG, SCON, TANY, SBREG, TCHAR|TUCHAR, NEEDS(NREG(B, 1)), RESC1, /* should be 0 */ " call CL\nZC", }, { UCALL, INBREG, SCON, TANY, SBREG, TCHAR|TUCHAR, NEEDS(NREG(B, 1)), RESC1, /* should be 0 */ " call CL\nZC", }, { CALL, INCREG, SCON, TANY, SCREG, TANY, NEEDS(NREG(C, 1), NSL(C)), RESC1, /* should be 0 */ " call CL\nZC", }, { UCALL, INCREG, SCON, TANY, SCREG, TANY, NEEDS(NREG(C, 1), NSL(C)), RESC1, /* should be 0 */ " call CL\nZC", }, { CALL, INDREG, SCON, TANY, SDREG, TANY, NEEDS(NREG(D, 1), NSL(D)), RESC1, /* should be 0 */ " call CL\nZC", }, { UCALL, INDREG, SCON, TANY, SDREG, TANY, NEEDS(NREG(D, 1), NSL(D)), RESC1, /* should be 0 */ " call CL\nZC", }, { CALL, FOREFF, SAREG, TANY, SANY, TANY, 0, 0, " call *AL\nZC", }, { UCALL, FOREFF, SAREG, TANY, SANY, TANY, 0, 0, " call *AL\nZC", }, { CALL, INAREG, SAREG, TANY, SANY, TANY, XSL(A), RESC1, /* should be 0 */ " call *AL\nZC", }, { UCALL, INAREG, SAREG, TANY, SANY, TANY, XSL(A), RESC1, /* should be 0 */ " call *AL\nZC", }, { CALL, INBREG, SAREG, TANY, SANY, TANY, XSL(B), RESC1, /* should be 0 */ " call *AL\nZC", }, { UCALL, INBREG, SAREG, TANY, SANY, TANY, XSL(B), RESC1, /* should be 0 */ " call *AL\nZC", }, { CALL, INCREG, SAREG, TANY, SANY, TANY, XSL(C), RESC1, /* should be 0 */ " call *AL\nZC", }, { UCALL, INCREG, SAREG, TANY, SANY, TANY, XSL(C), RESC1, /* should be 0 */ " call *AL\nZC", }, { CALL, INDREG, SAREG, TANY, SANY, TANY, XSL(D), RESC1, /* should be 0 */ " call *AL\nZC", }, { UCALL, INDREG, SAREG, TANY, SANY, TANY, XSL(D), RESC1, /* should be 0 */ " call *AL\nZC", }, { STCALL, FOREFF, SCON, TANY, SANY, TANY, XSL(A), 0, " call CL\nZC", }, { STCALL, INAREG, SCON, TANY, SANY, TANY, XSL(A), RESC1, /* should be 0 */ " call CL\nZC", }, { STCALL, INAREG, SNAME|SAREG, TANY, SANY, TANY, XSL(A), RESC1, /* should be 0 */ " call *AL\nZC", }, /* * The next rules handle all binop-style operators. */ /* Special treatment for long long */ { PLUS, INLL|FOREFF, SHLL, TLL, SHLL|SNAME|SOREG, TLL, 0, RLEFT, " addl AR,AL\n adcl UR,UL\n", }, { PLUS, INLL|FOREFF, SHLL|SNAME|SOREG, TLL, SHLL|SCON, TLL, 0, RLEFT, " addl AR,AL\n adcl UR,UL\n", }, /* Special treatment for long long XXX - fix commutative check */ { PLUS, INLL|FOREFF, SHLL|SNAME|SOREG, TLL, SHLL, TLL, 0, RRIGHT, " addl AL,AR\n adcl UL,UR\n", }, { PLUS, INFL, SHFL, TDOUBLE, SNAME|SOREG, TDOUBLE, 0, RLEFT, " faddl AR\n", }, { PLUS, INFL|FOREFF, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, 0, RLEFT, " faddp\n", }, #ifdef NOBREGS { PLUS, INAREG|FOREFF, SAREG|SNAME|SOREG, TAREG|TPOINT, SONE, TANY, 0, RLEFT, " incl AL\n", }, { PLUS, FOREFF, SNAME|SOREG, TSHORT|TUSHORT, SONE, TANY, 0, RLEFT, " incw AL\n", }, { PLUS, FOREFF, SNAME|SOREG, TCHAR|TUCHAR, SONE, TANY, 0, RLEFT, " incb AL\n", }, #else { PLUS, INAREG|FOREFF, SAREG|SNAME|SOREG, TWORD|TPOINT, SONE, TANY, 0, RLEFT, " incl AL\n", }, { PLUS, INAREG|FOREFF, SAREG|SNAME|SOREG, TSHORT|TUSHORT, SONE, TANY, 0, RLEFT, " incw AL\n", }, { PLUS, INCH|FOREFF, SHCH|SNAME|SOREG, TCHAR|TUCHAR, SONE, TANY, 0, RLEFT, " incb AL\n", }, #endif { PLUS, INAREG, SAREG, TAREG, SAREG, TAREG, NEEDS(NREG(A,1),NSL(A),NSR(A)), RESC1, " leal (AL,AR),A1\n", }, #ifdef NOBREGS { MINUS, INAREG|FOREFF, SAREG|SNAME|SOREG, TAREG|TPOINT, SONE, TANY, 0, RLEFT, " decl AL\n", }, { MINUS, FOREFF, SNAME|SOREG, TSHORT|TUSHORT, SONE, TANY, 0, RLEFT, " decw AL\n", }, { MINUS, FOREFF, SNAME|SOREG, TCHAR|TUCHAR, SONE, TANY, 0, RLEFT, " decb AL\n", }, #else { MINUS, INAREG|FOREFF, SAREG|SNAME|SOREG, TWORD|TPOINT, SONE, TANY, 0, RLEFT, " decl AL\n", }, { MINUS, INAREG|FOREFF, SAREG|SNAME|SOREG, TSHORT|TUSHORT, SONE, TANY, 0, RLEFT, " decw AL\n", }, { MINUS, INCH|FOREFF, SHCH|SNAME|SOREG, TCHAR|TUCHAR, SONE, TANY, 0, RLEFT, " decb AL\n", }, #endif /* address as register offset, negative */ { MINUS, INLL|FOREFF, SHLL, TLL, SHLL|SNAME|SOREG, TLL, 0, RLEFT, " subl AR,AL\n sbbl UR,UL\n", }, { MINUS, INLL|FOREFF, SHLL|SNAME|SOREG, TLL, SHLL|SCON, TLL, 0, RLEFT, " subl AR,AL\n sbbl UR,UL\n", }, { MINUS, INFL, SHFL, TDOUBLE, SNAME|SOREG, TDOUBLE, 0, RLEFT, " fsubl AR\n", }, { MINUS, INFL|FOREFF, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, 0, RLEFT, " fsubZAp\n", }, /* Simple r/m->reg ops */ /* m/r |= r */ { OPSIMP, INAREG|FOREFF|FORCC, SAREG|SNAME|SOREG, TWORD|TPOINT, SAREG, TWORD|TPOINT, 0, RLEFT|RESCC, " Ol AR,AL\n", }, /* r |= r/m */ { OPSIMP, INAREG|FOREFF|FORCC, SAREG, TWORD|TPOINT, SAREG|SNAME|SOREG, TWORD|TPOINT, 0, RLEFT|RESCC, " Ol AR,AL\n", }, #ifdef NOBREGS /* m/r |= r */ { OPSIMP, INAREG|FOREFF|FORCC, SNAME|SOREG, TSHORT|TUSHORT, SAREG, TSHORT|TUSHORT, 0, RLEFT|RESCC, " Ow AR,AL\n", }, /* r |= r/m */ { OPSIMP, INAREG|FOREFF|FORCC, SAREG, TSHORT|TUSHORT, SNAME|SOREG, TSHORT|TUSHORT, 0, RLEFT|RESCC, " Ow AR,AL\n", }, /* m/r |= r */ { OPSIMP, INAREG|FOREFF|FORCC, SAREG, TCHAR|TUCHAR, SAREG, TCHAR|TUCHAR, 0, RLEFT|RESCC, " Ol AR,AL\n", }, { OPSIMP, FOREFF|FORCC, SNAME|SOREG, TCHAR|TUCHAR, SCON, TANY, 0, RLEFT|RESCC, " Ob AR,AL\n", }, { OPSIMP, INAREG|FOREFF|FORCC, SAREG, TSHORT|TUSHORT, SCON, TANY, 0, RLEFT|RESCC, " Ol AR,AL\n", }, #else /* m/r |= r */ { OPSIMP, INAREG|FOREFF|FORCC, SHINT|SNAME|SOREG, TSHORT|TUSHORT, SHINT, TSHORT|TUSHORT, 0, RLEFT|RESCC, " Ow AR,AL\n", }, /* r |= r/m */ { OPSIMP, INAREG|FOREFF|FORCC, SHINT, TSHORT|TUSHORT, SHINT|SNAME|SOREG, TSHORT|TUSHORT, 0, RLEFT|RESCC, " Ow AR,AL\n", }, /* m/r |= r */ { OPSIMP, INCH|FOREFF|FORCC, SHCH, TCHAR|TUCHAR, SHCH|SNAME|SOREG, TCHAR|TUCHAR, 0, RLEFT|RESCC, " Ob AR,AL\n", }, /* r |= r/m */ { OPSIMP, INCH|FOREFF|FORCC, SHCH, TCHAR|TUCHAR, SHCH|SNAME|SOREG, TCHAR|TUCHAR, 0, RLEFT|RESCC, " Ob AR,AL\n", }, { OPSIMP, INCH|FOREFF|FORCC, SHCH|SNAME|SOREG, TCHAR|TUCHAR, SCON, TANY, 0, RLEFT|RESCC, " Ob AR,AL\n", }, { OPSIMP, INAREG|FOREFF|FORCC, SHINT|SNAME|SOREG, TSHORT|TUSHORT, SCON, TANY, 0, RLEFT|RESCC, " Ow AR,AL\n", }, #endif /* m/r |= const */ { OPSIMP, INAREG|FOREFF|FORCC, SAREG|SNAME|SOREG, TWORD|TPOINT, SCON, TWORD|TPOINT, 0, RLEFT|RESCC, " Ol AR,AL\n", }, /* r |= r/m */ { OPSIMP, INLL|FOREFF, SHLL, TLL, SHLL|SNAME|SOREG, TLL, 0, RLEFT, " Ol AR,AL\n Ol UR,UL\n", }, /* m/r |= r/const */ { OPSIMP, INLL|FOREFF, SHLL|SNAME|SOREG, TLL, SHLL|SCON, TLL, 0, RLEFT, " Ol AR,AL\n Ol UR,UL\n", }, /* Try use-reg instructions first */ { PLUS, INAREG, SAREG, TWORD|TPOINT, SCON, TANY, XSL(A), RESC1, " leal CR(AL),A1\n", }, { MINUS, INAREG, SAREG, TWORD|TPOINT, SPCON, TANY, XSL(A), RESC1, " leal -CR(AL),A1\n", }, /* * The next rules handle all shift operators. */ #ifdef NOBREGS /* (u)longlong left shift is emulated */ { LS, INCREG, SCREG, TLL, SAREG, TAREG, NEEDS(NLEFT(EAXEDX), NRIGHT(ECX), NRES(EAXEDX)), RLEFT, "ZO", }, /* r/m <<= r */ { LS, INAREG|FOREFF, SAREG|SNAME|SOREG, TWORD, SAREG, TAREG, NEEDS(NOLEFT(ECX), NRIGHT(ECX)), RLEFT, " sall ZT,AL\n", }, /* r/m <<= const */ { LS, INAREG|FOREFF, SAREG|SNAME|SOREG, TWORD, SCON, TANY, 0, RLEFT, " sall AR,AL\n", }, /* r/m <<= r */ { LS, FOREFF, SNAME|SOREG, TSHORT|TUSHORT, SAREG, TAREG, NEEDS(NOLEFT(ECX), NRIGHT(ECX)), RLEFT, " shlw ZT,AL\n", }, /* r/m <<= r */ { LS, FOREFF, SNAME|SOREG, TCHAR|TUCHAR, SAREG, TAREG, NEEDS(NOLEFT(ECX), NRIGHT(ECX)), RLEFT, " shlb ZT,AL\n", }, /* r/m <<= const */ { LS, INAREG|FOREFF, SAREG, TAREG, SCON, TANY, 0, RLEFT, " shll AR,AL\n", }, { LS, INAREG|FOREFF, SAREG, TAREG, SAREG, TAREG, NEEDS(NOLEFT(ECX), NRIGHT(ECX)), RLEFT, " shll ZT,AL\n", }, #else /* (u)longlong left shift is emulated */ { LS, INCREG, SCREG, TLL, SHCH, TCHAR|TUCHAR, NEEDS(NLEFT(EAXEDX), NRIGHT(CL),NRES(EAXEDX)), RLEFT, "ZO", }, /* r/m <<= r */ { LS, INAREG|FOREFF, SAREG|SNAME|SOREG, TWORD, SHCH, TCHAR|TUCHAR, NEEDS(NOLEFT(ECX), NRIGHT(CL)), RLEFT, " sall AR,AL\n", }, /* r/m <<= const */ { LS, INAREG|FOREFF, SAREG|SNAME|SOREG, TWORD, SCON, TANY, 0, RLEFT, " sall AR,AL\n", }, /* r/m <<= r */ { LS, INAREG|FOREFF, SAREG|SNAME|SOREG, TSHORT|TUSHORT, SHCH, TCHAR|TUCHAR, NEEDS(NOLEFT(ECX), NRIGHT(CL)), RLEFT, " shlw AR,AL\n", }, /* r/m <<= const */ { LS, INAREG|FOREFF, SAREG|SNAME|SOREG, TSHORT|TUSHORT, SCON, TANY, 0, RLEFT, " shlw AR,AL\n", }, { LS, INCH|FOREFF, SHCH|SNAME|SOREG, TCHAR|TUCHAR, SHCH, TCHAR|TUCHAR, NEEDS(NOLEFT(ECX), NRIGHT(CL)), RLEFT, " salb AR,AL\n", }, { LS, INCH|FOREFF, SHCH|SNAME|SOREG, TCHAR|TUCHAR, SCON, TANY, 0, RLEFT, " salb AR,AL\n", }, #endif #ifdef NOBREGS /* (u)longlong right shift is emulated */ { RS, INCREG, SCREG, TLL, SAREG, TAREG, NEEDS(NLEFT(EAXEDX), NRIGHT(ECX),NRES(EAXEDX)), RLEFT, "ZO", }, /* right-shift word in memory or reg */ { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TWORD, SAREG, TAREG, NEEDS(NOLEFT(ECX), NRIGHT(ECX)), RLEFT, " sZUrl ZT,AL\n", }, /* as above but using a constant */ { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TWORD, SCON, TAREG, 0, RLEFT, " sZUrl AR,AL\n", }, /* short in memory */ { RS, FOREFF, SNAME|SOREG, TSHORT|TUSHORT, SAREG, TAREG, NEEDS(NOLEFT(ECX), NRIGHT(ECX)), RLEFT, " sZUrw ZT,AL\n", }, { RS, FOREFF, SNAME|SOREG, TSHORT|TUSHORT, SCON, TAREG, 0, RLEFT, " sZUrw AR,AL\n", }, { RS, FOREFF, SNAME|SOREG, TCHAR|TUCHAR, SAREG, TAREG, NEEDS(NOLEFT(ECX), NRIGHT(ECX)), RLEFT, " sZUrl ZT,AL\n", }, #else /* (u)longlong right shift is emulated */ { RS, INCREG, SCREG, TLL, SHCH, TCHAR|TUCHAR, NEEDS(NLEFT(EAXEDX), NRIGHT(CL),NRES(EAXEDX)), RLEFT, "ZO", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TSWORD, SHCH, TCHAR|TUCHAR, NEEDS(NOLEFT(ECX), NRIGHT(CL)), RLEFT, " sarl AR,AL\n", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TSWORD, SCON, TANY, 0, RLEFT, " sarl AR,AL\n", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TUWORD, SHCH, TCHAR|TUCHAR, NEEDS(NOLEFT(ECX), NRIGHT(CL)), RLEFT, " shrl AR,AL\n", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TUWORD, SCON, TANY, 0, RLEFT, " shrl AR,AL\n", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TSHORT, SHCH, TCHAR|TUCHAR, NEEDS(NOLEFT(ECX), NRIGHT(CL)), RLEFT, " sarw AR,AL\n", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TSHORT, SCON, TANY, 0, RLEFT, " sarw AR,AL\n", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TUSHORT, SHCH, TCHAR|TUCHAR, NEEDS(NOLEFT(ECX), NRIGHT(CL)), RLEFT, " shrw AR,AL\n", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TUSHORT, SCON, TANY, 0, RLEFT, " shrw AR,AL\n", }, { RS, INCH|FOREFF, SHCH|SNAME|SOREG, TCHAR, SHCH, TCHAR|TUCHAR, NEEDS(NOLEFT(ECX), NRIGHT(CL)), RLEFT, " sarb AR,AL\n", }, { RS, INCH|FOREFF, SHCH|SNAME|SOREG, TCHAR, SCON, TANY, 0, RLEFT, " sarb AR,AL\n", }, { RS, INCH|FOREFF, SHCH|SNAME|SOREG, TUCHAR, SHCH, TCHAR|TUCHAR, NEEDS(NOLEFT(ECX), NRIGHT(CL)), RLEFT, " shrb AR,AL\n", }, { RS, INCH|FOREFF, SHCH|SNAME|SOREG, TUCHAR, SCON, TANY, 0, RLEFT, " shrb AR,AL\n", }, #endif /* * The next rules takes care of assignments. "=". */ { ASSIGN, FORCC|FOREFF|INLL, SHLL, TLL, SZERO, TANY, 0, RDEST, " xorl AL,AL\n xorl UL,UL\n", }, { ASSIGN, FORCC|FOREFF|INLL, SHLL, TLL, SMILWXOR, TANY, 0, RDEST, " xorl AL,AL\n movl UR,UL\n", }, { ASSIGN, FORCC|FOREFF|INLL, SHLL, TLL, SMIHWXOR, TANY, 0, RDEST, " movl AR,AL\n xorl UL,UL\n", }, { ASSIGN, FOREFF|INLL, SHLL, TLL, SCON, TANY, 0, RDEST, " movl AR,AL\n movl UR,UL\n", }, { ASSIGN, FOREFF, SHLL|SNAME|SOREG, TLL, SCON, TANY, 0, 0, " movl AR,AL\n movl UR,UL\n", }, { ASSIGN, FOREFF, SNAME|SOREG, TLL, SZERO, TANY, 0, 0, " andl $0,AL\n andl $0,UL\n", }, { ASSIGN, FORCC|FOREFF|INAREG, SAREG, TWORD|TPOINT, SZERO, TANY, 0, RDEST, " xorl AL,AL\n", }, { ASSIGN, FOREFF, SOREG|SNAME, TWORD|TPOINT, SZERO, TANY, 0, 0, " andl $0,AL\n", }, { ASSIGN, FOREFF, SAREG|SNAME|SOREG, TWORD|TPOINT, SCON, TANY, 0, 0, " movl AR,AL\n", }, { ASSIGN, FOREFF|INAREG, SAREG, TWORD|TPOINT, SCON, TANY, 0, RDEST, " movl AR,AL\n", }, { ASSIGN, FORCC|FOREFF|INAREG, SAREG, TSHORT|TUSHORT, SMIXOR, TANY, 0, RDEST, " xorw AL,AL\n", }, { ASSIGN, FOREFF, SAREG|SNAME|SOREG, TSHORT|TUSHORT, SCON, TANY, 0, 0, " movw AR,AL\n", }, { ASSIGN, FOREFF|INAREG, SAREG, TSHORT|TUSHORT, SCON, TANY, 0, RDEST, " movw AR,AL\n", }, #ifdef NOBREGS { ASSIGN, INAREG|FOREFF, SAREG, TUCHAR, SNAME|SOREG, TUCHAR, 0, RDEST, " movzbl AR,AL\n", }, { ASSIGN, INAREG|FOREFF, SAREG, TCHAR, SNAME|SOREG, TCHAR, 0, RDEST, " movsbl AR,AL\n", }, { ASSIGN, INAREG|FOREFF, SOREG|SNAME, TCHAR|TUCHAR, SAREG, TCHAR|TUCHAR, NEEDS(NORIGHT(ESI), NORIGHT(EDI)), RDEST, " movb ZT,AL\n", }, #else { ASSIGN, FOREFF, SHCH|SNAME|SOREG, TCHAR|TUCHAR, SCON, TANY, 0, 0, " movb AR,AL\n", }, { ASSIGN, FOREFF|INCH, SHCH, TCHAR|TUCHAR, SCON, TANY, 0, RDEST, " movb AR,AL\n", }, #endif { ASSIGN, FOREFF|INLL, SNAME|SOREG, TLL, SHLL, TLL, 0, RDEST, " movl AR,AL\n movl UR,UL\n", }, { ASSIGN, FOREFF|INLL, SHLL, TLL, SHLL, TLL, 0, RDEST, "ZH", }, { ASSIGN, FOREFF|INAREG, SAREG|SNAME|SOREG, TWORD|TPOINT, SAREG, TWORD|TPOINT, 0, RDEST, " movl AR,AL\n", }, { ASSIGN, FOREFF|INAREG, SAREG, TWORD|TPOINT, SAREG|SNAME|SOREG, TWORD|TPOINT, 0, RDEST, " movl AR,AL\n", }, { ASSIGN, FOREFF|INAREG, SAREG|SNAME|SOREG, TSHORT|TUSHORT, SAREG, TSHORT|TUSHORT, 0, RDEST, " movw AR,AL\n", }, #ifdef NOBREGS { ASSIGN, FOREFF|INAREG, SNAME|SOREG, TCHAR|TUCHAR, SAREG, TCHAR|TUCHAR|TWORD, NEEDS(NORIGHT(ESI), NORIGHT(EDI)), RDEST, " movb ZT,AL\n", }, { ASSIGN, FOREFF|INAREG, SAREG, TUCHAR, SAREG, TCHAR|TUCHAR|TWORD, NEEDS(NORIGHT(ESI), NORIGHT(EDI)), RDEST, " movzbl ZT,AL\n", }, { ASSIGN, FOREFF|INAREG, SAREG, TCHAR, SAREG, TCHAR|TUCHAR|TWORD, NEEDS(NORIGHT(ESI), NORIGHT(EDI)), RDEST, " movsbl ZT,AL\n", }, #else { ASSIGN, FOREFF|INCH, SHCH|SNAME|SOREG, TCHAR|TUCHAR, SHCH, TCHAR|TUCHAR|TWORD, 0, RDEST, " movb AR,AL\n", }, #endif { ASSIGN, INDREG|FOREFF, SHFL, TFLOAT|TDOUBLE|TLDOUBLE, SHFL, TFLOAT|TDOUBLE|TLDOUBLE, 0, RDEST, "", }, /* This will always be in the correct register */ /* order of table entries is very important here! */ { ASSIGN, INFL, SNAME|SOREG, TLDOUBLE, SHFL, TFLOAT|TDOUBLE|TLDOUBLE, 0, RDEST, " fstpt AL\n fldt AL\n", }, /* XXX */ { ASSIGN, FOREFF, SNAME|SOREG, TLDOUBLE, SHFL, TFLOAT|TDOUBLE|TLDOUBLE, 0, 0, " fstpt AL\n", }, { ASSIGN, INFL, SNAME|SOREG, TDOUBLE, SHFL, TFLOAT|TDOUBLE|TLDOUBLE, 0, RDEST, " fstl AL\n", }, { ASSIGN, FOREFF, SNAME|SOREG, TDOUBLE, SHFL, TFLOAT|TDOUBLE|TLDOUBLE, 0, 0, " fstpl AL\n", }, { ASSIGN, INFL, SNAME|SOREG, TFLOAT, SHFL, TFLOAT|TDOUBLE|TLDOUBLE, 0, RDEST, " fsts AL\n", }, { ASSIGN, FOREFF, SNAME|SOREG, TFLOAT, SHFL, TFLOAT|TDOUBLE|TLDOUBLE, 0, 0, " fstps AL\n", }, /* end very important order */ { ASSIGN, INFL|FOREFF, SHFL, TLDOUBLE, SHFL|SOREG|SNAME, TLDOUBLE, 0, RDEST, " fldt AR\n", }, { ASSIGN, INFL|FOREFF, SHFL, TDOUBLE, SHFL|SOREG|SNAME, TDOUBLE, 0, RDEST, " fldl AR\n", }, { ASSIGN, INFL|FOREFF, SHFL, TFLOAT, SHFL|SOREG|SNAME, TFLOAT, 0, RDEST, " flds AR\n", }, /* Do not generate memcpy if return from funcall */ #if 0 { STASG, INAREG|FOREFF, SOREG|SNAME|SAREG, TPTRTO|TSTRUCT, SFUNCALL, TPTRTO|TSTRUCT, 0, RRIGHT, "", }, #endif { STASG, INAREG|FOREFF, SOREG|SNAME, TANY, SAREG, TPTRTO|TANY, NEEDS(NEVER(EDI), NEVER(ESI), NRIGHT(ESI), NOLEFT(ESI), NOLEFT(ECX), NORIGHT(ECX), NEVER(ECX), NREG(A,1)), RDEST, "F movl %esi,A1\nZQF movl A1,%esi\n", }, /* * DIV/MOD/MUL */ /* long long div is emulated */ { DIV, INCREG, SCREG|SNAME|SOREG|SCON, TLL, SCREG|SNAME|SOREG|SCON, TLL, NEEDS(NREG(C,1), NSL(C), NSR(C), NEVER(EAX), NEVER(EDX), NEVER(ECX), NRES(EAXEDX)), RESC1, "ZO", }, { DIV, INAREG, SAREG, TSWORD, SAREG|SNAME|SOREG, TWORD, NEEDS(NEVER(EAX), NEVER(EDX), NLEFT(EAX), NRES(EAX), NORIGHT(EAX), NORIGHT(EDX)), RDEST, " cltd\n idivl AR\n", }, { DIV, INAREG, SAREG, TUWORD|TPOINT, SAREG|SNAME|SOREG, TUWORD|TPOINT, NEEDS(NEVER(EAX), NEVER(EDX), NLEFT(EAX), NRES(EAX), NORIGHT(EAX), NORIGHT(EDX)), RDEST, " xorl %edx,%edx\n divl AR\n", }, { DIV, INAREG, SAREG, TUSHORT, SAREG|SNAME|SOREG, TUSHORT, NEEDS(NEVER(EAX), NEVER(EDX), NLEFT(EAX), NRES(EAX), NORIGHT(EAX), NORIGHT(EDX)), RDEST, " xorl %edx,%edx\n divw AR\n", }, #ifdef NOBREGS { DIV, INAREG, SAREG, TUCHAR, SAREG, TUCHAR, NEEDS(NEVER(EAX), NEVER(EDX), NLEFT(EAX), NRES(EAX), NORIGHT(EAX), NORIGHT(EDX)), RDEST, " xorl %edx,%edx\n divl AR\n", }, #else { DIV, INCH, SHCH, TUCHAR, SHCH|SNAME|SOREG, TUCHAR, NEEDS(NEVER(AL), NEVER(AH), NLEFT(AL), NRES(AL), NORIGHT(AL), NORIGHT(AH)), RDEST, " xorb %ah,%ah\n divb AR\n", }, #endif { DIV, INFL, SHFL, TDOUBLE, SNAME|SOREG, TDOUBLE, 0, RLEFT, " fdivl AR\n", }, { DIV, INFL, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, 0, RLEFT, " fdivZAp\n", }, /* (u)longlong mod is emulated */ { MOD, INCREG, SCREG|SNAME|SOREG|SCON, TLL, SCREG|SNAME|SOREG|SCON, TLL, NEEDS(NREG(C,1), NSL(C), NSR(C), NEVER(EAX), NEVER(EDX), NEVER(ECX), NRES(EAXEDX)), RESC1, "ZO", }, { MOD, INAREG, SAREG, TSWORD, SAREG|SNAME|SOREG, TSWORD, NEEDS(NREG(A,1), NEVER(EAX), NEVER(EDX), NLEFT(EAX), NRES(EDX), NORIGHT(EAX), NORIGHT(EDX)), RESC1, " cltd\n idivl AR\n", }, { MOD, INAREG, SAREG, TWORD|TPOINT, SAREG|SNAME|SOREG, TUWORD|TPOINT, NEEDS(NREG(A,1), NEVER(EAX), NEVER(EDX), NLEFT(EAX), NRES(EDX), NORIGHT(EAX), NORIGHT(EDX)), RESC1, " xorl %edx,%edx\n divl AR\n", }, { MOD, INAREG, SAREG, TUSHORT, SAREG|SNAME|SOREG, TUSHORT, NEEDS(NREG(A,1), NEVER(EAX), NEVER(EDX), NLEFT(EAX), NRES(EDX), NORIGHT(EAX), NORIGHT(EDX)), RESC1, " xorl %edx,%edx\n divw AR\n", }, #ifdef NOBREGS { MOD, INAREG, SAREG, TUCHAR, SAREG, TUCHAR, NEEDS(NREG(A,1), NEVER(EAX), NEVER(EDX), NLEFT(EAX), NRES(EDX), NORIGHT(EAX), NORIGHT(EDX)), RESC1, " xorl %edx,%edx\n divl AR\n", }, #else { MOD, INCH, SHCH, TUCHAR, SHCH|SNAME|SOREG, TUCHAR, NEEDS(NREG(B,1), NEVER(AL), NEVER(AH), NLEFT(AL), NRES(AH), NORIGHT(AL), NORIGHT(AH)), RESC1, " xorb %ah,%ah\n divb AR\n", }, #endif /* (u)longlong mul is emulated */ { MUL, INCREG, SCREG, TLL, SCREG, TLL, NEEDS(NEVER(ESI), NRIGHT(ECXESI), NLEFT(EAXEDX), NRES(EAXEDX)), RDEST, "ZO", }, { MUL, INAREG, SAREG, TWORD|TPOINT, SAREG|SNAME|SOREG|SCON, TWORD|TPOINT, 0, RLEFT, " imull AR,AL\n", }, { MUL, INAREG, SAREG, TSHORT|TUSHORT, SAREG|SNAME|SOREG, TSHORT|TUSHORT, 0, RLEFT, " imulw AR,AL\n", }, #ifdef NOBREGS { MUL, INAREG, SAREG, TCHAR|TUCHAR, SAREG|SCON, TCHAR|TUCHAR, 0, RLEFT, " imull AR,AL\n", }, #else { MUL, INCH, SHCH, TCHAR|TUCHAR, SHCH|SNAME|SOREG, TCHAR|TUCHAR, NEEDS(NLEFT(AL), NEVER(AL), NEVER(AH), NRES(AL)), RDEST, " imulb AR\n", }, #endif { MUL, INFL, SHFL, TDOUBLE, SNAME|SOREG, TDOUBLE, 0, RLEFT, " fmull AR\n", }, { MUL, INFL, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, 0, RLEFT, " fmulp\n", }, /* * Indirection operators. */ { UMUL, INLL, SANY, TANY, SOREG, TLL, NEEDS(NREG(C, 1)), RESC1, " movl UL,U1\n movl AL,A1\n", }, { UMUL, INAREG, SANY, TPOINT|TWORD, SOREG, TPOINT|TWORD, XSL(A), RESC1, " movl AL,A1\n", }, #ifdef NOBREGS { UMUL, INAREG, SANY, TANY, SOREG, TCHAR, XSL(A), RESC1, " movsbl AL,A1\n", }, { UMUL, INAREG, SANY, TANY, SOREG, TUCHAR, XSL(A), RESC1, " movzbl AL,A1\n", }, #else { UMUL, INCH, SANY, TANY, SOREG, TCHAR|TUCHAR, XSL(B), RESC1, " movb AL,A1\n", }, #endif { UMUL, INAREG, SANY, TANY, SOREG, TSHORT|TUSHORT, XSL(A), RESC1, " movw AL,A1\n", }, { UMUL, INFL, SANY, TANY, SOREG, TLDOUBLE, XSL(D), RESC1, " fldt AL\n", }, { UMUL, INFL, SANY, TANY, SOREG, TDOUBLE, XSL(D), RESC1, " fldl AL\n", }, { UMUL, INFL, SANY, TANY, SOREG, TFLOAT, XSL(D), RESC1, " flds AL\n", }, /* * Logical/branching operators */ /* Comparisions, take care of everything */ { OPLOG, FORCC, SHLL|SOREG|SNAME, TLL, SHLL, TLL, 0, 0, "ZD", }, { OPLOG, FORCC, SAREG|SOREG|SNAME, TWORD|TPOINT, SCON|SAREG, TWORD|TPOINT, 0, RESCC, " cmpl AR,AL\n", }, #if 0 { OPLOG, FORCC, SCON|SAREG, TWORD|TPOINT, SAREG|SOREG|SNAME, TWORD|TPOINT, 0, RESCC, " cmpl AR,AL\n", }, #endif { OPLOG, FORCC, SAREG|SOREG|SNAME, TSHORT|TUSHORT, SCON|SAREG, TANY, 0, RESCC, " cmpw AR,AL\n", }, { OPLOG, FORCC, SBREG|SOREG|SNAME, TCHAR|TUCHAR, SCON|SBREG, TANY, 0, RESCC, " cmpb AR,AL\n", }, { OPLOG, FORCC, SDREG, TLDOUBLE|TDOUBLE|TFLOAT, SDREG, TLDOUBLE|TDOUBLE|TFLOAT, NEEDS(NEVER(EAX)), RNOP, "ZG", }, { OPLOG, FORCC, SANY, TANY, SANY, TANY, NEEDS(NREWRITE), 0, "diediedie!", }, /* AND/OR/ER/NOT */ { AND, INAREG|FOREFF, SAREG|SOREG|SNAME, TWORD, SCON|SAREG, TWORD, 0, RLEFT, " andl AR,AL\n", }, { AND, INCREG|FOREFF, SCREG, TLL, SCREG|SOREG|SNAME, TLL, 0, RLEFT, " andl AR,AL\n andl UR,UL\n", }, { AND, INAREG|FOREFF, SAREG, TWORD, SAREG|SOREG|SNAME, TWORD, 0, RLEFT, " andl AR,AL\n", }, { AND, INAREG|FOREFF, SAREG|SOREG|SNAME, TSHORT|TUSHORT, SCON|SAREG, TSHORT|TUSHORT, 0, RLEFT, " andw AR,AL\n", }, { AND, INAREG|FOREFF, SAREG, TSHORT|TUSHORT, SAREG|SOREG|SNAME, TSHORT|TUSHORT, 0, RLEFT, " andw AR,AL\n", }, { AND, INBREG|FOREFF, SBREG|SOREG|SNAME, TCHAR|TUCHAR, SCON|SBREG, TCHAR|TUCHAR, 0, RLEFT, " andb AR,AL\n", }, { AND, INBREG|FOREFF, SBREG, TCHAR|TUCHAR, SBREG|SOREG|SNAME, TCHAR|TUCHAR, 0, RLEFT, " andb AR,AL\n", }, /* AND/OR/ER/NOT */ /* * Jumps. */ { GOTO, FOREFF, SCON, TANY, SANY, TANY, 0, RNOP, " jmp LL\n", }, #if defined(GCC_COMPAT) || defined(LANG_F77) { GOTO, FOREFF, SAREG, TANY, SANY, TANY, 0, RNOP, " jmp *AL\n", }, #endif /* * Convert LTYPE to reg. */ { OPLTYPE, FORCC|INLL, SCREG, TLL, SMIXOR, TANY, NEEDS(NREG(C,1)), RESC1, " xorl U1,U1\n xorl A1,A1\n", }, { OPLTYPE, FORCC|INLL, SCREG, TLL, SMILWXOR, TANY, NEEDS(NREG(C,1)), RESC1, " movl UL,U1\n xorl A1,A1\n", }, { OPLTYPE, FORCC|INLL, SCREG, TLL, SMIHWXOR, TANY, NEEDS(NREG(C,1)), RESC1, " xorl U1,U1\n movl AL,A1\n", }, { OPLTYPE, INLL, SANY, TANY, SCREG, TLL, NEEDS(NREG(C,1)), RESC1, "ZK", }, { OPLTYPE, INLL, SANY, TANY, SCON|SOREG|SNAME, TLL, NEEDS(NREG(C,1)), RESC1, " movl UL,U1\n movl AL,A1\n", }, { OPLTYPE, FORCC|INAREG, SAREG, TWORD|TPOINT, SMIXOR, TANY, XSL(A), RESC1, " xorl A1,A1\n", }, { OPLTYPE, INAREG, SANY, TANY, SAREG|SCON|SOREG|SNAME, TWORD|TPOINT, XSL(A), RESC1, " movl AL,A1\n", }, #ifdef NOBREGS { OPLTYPE, INAREG, SANY, TANY, SCON, TCHAR|TUCHAR, XSL(A), RESC1, " movl AL,A1\n", }, { OPLTYPE, INAREG, SANY, TANY, SOREG|SNAME, TUCHAR, XSL(A), RESC1, " movzbl AL,A1\n", }, { OPLTYPE, INAREG, SANY, TANY, SOREG|SNAME, TCHAR, XSL(A), RESC1, " movsbl AL,A1\n", }, { OPLTYPE, INAREG, SANY, TANY, SAREG, TCHAR|TUCHAR, XSL(A), RESC1, " movl AL,A1\n", }, #else { OPLTYPE, INBREG, SANY, TANY, SBREG|SOREG|SNAME|SCON, TCHAR|TUCHAR, XSL(B), RESC1, " movb AL,A1\n", }, #endif { OPLTYPE, FORCC|INAREG, SAREG, TSHORT|TUSHORT, SMIXOR, TANY, XSL(A), RESC1, " xorw A1,A1\n", }, { OPLTYPE, INAREG, SANY, TANY, SAREG|SOREG|SNAME|SCON, TSHORT|TUSHORT, XSL(A), RESC1, " movw AL,A1\n", }, { OPLTYPE, INDREG, SANY, TLDOUBLE, SOREG|SNAME, TLDOUBLE, XSL(D), RESC1, " fldt AL\n", }, { OPLTYPE, INDREG, SANY, TDOUBLE, SOREG|SNAME, TDOUBLE, XSL(D), RESC1, " fldl AL\n", }, { OPLTYPE, INDREG, SANY, TFLOAT, SOREG|SNAME, TFLOAT, XSL(D), RESC1, " flds AL\n", }, /* Only used in ?: constructs. The stack already contains correct value */ { OPLTYPE, INDREG, SANY, TFLOAT|TDOUBLE|TLDOUBLE, SDREG, TFLOAT|TDOUBLE|TLDOUBLE, XSL(D), RESC1, "", }, /* * Negate a word. */ { UMINUS, INCREG|FOREFF, SCREG, TLL, SCREG, TLL, 0, RLEFT, " negl AL\n adcl $0,UL\n negl UL\n", }, { UMINUS, INAREG|FOREFF, SAREG, TWORD|TPOINT, SAREG, TWORD|TPOINT, 0, RLEFT, " negl AL\n", }, { UMINUS, INAREG|FOREFF, SAREG, TSHORT|TUSHORT, SAREG, TSHORT|TUSHORT, 0, RLEFT, " negw AL\n", }, { UMINUS, INBREG|FOREFF, SBREG, TCHAR|TUCHAR, SBREG, TCHAR|TUCHAR, 0, RLEFT, " negb AL\n", }, { UMINUS, INFL|FOREFF, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, 0, RLEFT, " fchs\n", }, { COMPL, INCREG, SCREG, TLL, SANY, TANY, 0, RLEFT, " notl AL\n notl UL\n", }, { COMPL, INAREG, SAREG, TWORD, SANY, TANY, 0, RLEFT, " notl AL\n", }, { COMPL, INAREG, SAREG, TSHORT|TUSHORT, SANY, TANY, 0, RLEFT, " notw AL\n", }, { COMPL, INBREG, SBREG, TCHAR|TUCHAR, SANY, TANY, 0, RLEFT, " notb AL\n", }, /* * Arguments to functions. */ { FUNARG, FOREFF, SCON|SCREG|SNAME|SOREG, TLL, SANY, TLL, 0, RNULL, " pushl UL\n pushl AL\n", }, { FUNARG, FOREFF, SCON|SAREG|SNAME|SOREG, TWORD|TPOINT, SANY, TWORD|TPOINT, 0, RNULL, " pushl AL\n", }, { FUNARG, FOREFF, SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, SANY, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, 0, RNULL, " pushl AL\n", }, { FUNARG, FOREFF, SAREG|SNAME|SOREG, TSHORT, SANY, TSHORT, XSL(A), 0, " movswl AL,ZN\n pushl ZN\n", }, { FUNARG, FOREFF, SAREG|SNAME|SOREG, TUSHORT, SANY, TUSHORT, XSL(A), 0, " movzwl AL,ZN\n pushl ZN\n", }, #ifdef NOBREGS { FUNARG, FOREFF, SAREG|SNAME|SOREG, TUCHAR|TCHAR, SANY, TUCHAR|TCHAR, XSL(A), 0, " pushl AL\n", }, #else { FUNARG, FOREFF, SHCH|SNAME|SOREG, TCHAR, SANY, TCHAR, XSL(A), 0, " movsbl AL,A1\n pushl A1\n", }, { FUNARG, FOREFF, SHCH|SNAME|SOREG, TUCHAR, SANY, TUCHAR, XSL(A), 0, " movzbl AL,A1\n pushl A1\n", }, #endif { FUNARG, FOREFF, SNAME|SOREG, TDOUBLE, SANY, TDOUBLE, 0, 0, " pushl UL\n pushl AL\n", }, { FUNARG, FOREFF, SDREG, TDOUBLE, SANY, TDOUBLE, 0, 0, " subl $8,%esp\n fstpl (%esp)\n", }, { FUNARG, FOREFF, SNAME|SOREG, TFLOAT, SANY, TFLOAT, 0, 0, " pushl AL\n", }, { FUNARG, FOREFF, SDREG, TFLOAT, SANY, TFLOAT, 0, 0, " subl $4,%esp\n fstps (%esp)\n", }, { FUNARG, FOREFF, SDREG, TLDOUBLE, SANY, TLDOUBLE, 0, 0, " subl $12,%esp\n fstpt (%esp)\n", }, { STARG, FOREFF, SAREG, TPTRTO|TSTRUCT, SANY, TSTRUCT, NEEDS(NEVER(EDI), NLEFT(ESI), NEVER(ECX)), 0, "ZF", }, # define DF(x) FORREW,SANY,TANY,SANY,TANY,NEEDS(NREWRITE),x,"" { UMUL, DF( UMUL ), }, { ASSIGN, DF(ASSIGN), }, { STASG, DF(STASG), }, { FLD, DF(FLD), }, { OPLEAF, DF(NAME), }, /* { INIT, DF(INIT), }, */ { OPUNARY, DF(UMINUS), }, { OPANY, DF(BITYPE), }, { FREE, FREE, FREE, FREE, FREE, FREE, 0, FREE, "help; I'm in trouble\n" }, }; int tablesize = sizeof(table)/sizeof(table[0]); pcc-20181216/arch/i86004075500017500000000000000000001340533064000127315ustar raggewheelpcc-20181216/arch/i86/CVS004075500017500000000000000000001340533064000133645ustar raggewheelpcc-20181216/arch/i86/CVS/Root010064400017500000000000000000111340533064000142760ustar raggewheel/cvsroot pcc-20181216/arch/i86/CVS/Repository010064400017500000000000000000151340533064000155360ustar raggewheelpcc/arch/i86 pcc-20181216/arch/i86/CVS/Entries010064400017500000000000000005021340533064000147710ustar raggewheel/TODO/1.2/Sat Dec 27 21:18:19 2014// /code.c/1.3/Tue Nov 13 17:47:32 2018// /flocal.c/1.1/Tue Sep 16 10:47:35 2014// /local.c/1.4/Tue Nov 13 17:47:32 2018// /local2.c/1.9/Tue Nov 13 17:47:32 2018// /macdefs.h/1.8/Tue Nov 13 17:47:32 2018// /order.c/1.4/Tue Nov 13 17:47:32 2018// /table.c/1.5/Sat Dec 27 21:18:19 2014// D pcc-20181216/arch/i86/TODO010064400017500000000000000036301244762103300135030ustar raggewheel 8086/80186 ---------- Add CPU options Make push immediate, imul, shift immediate and enter/leave 186 specific Optimise >> 8 and friends as register moves (note that the core compiler code also goes off and turns * 256 into << 8) Unstarted --------- Float Struct/Union testing Maths optimisation. Div/mul on 8086 are *slow* so generate stack/double and other optimised forms Long helper methods (out of line 32bit mul etc) Make long long a class E with 64bit types and four virtual registers rewritten as memory. Other call formats Optimisation ------------ Avoid sp,bp set up if we can on entry/exit Delayed sp adjustments Don't adjust sp then reload it from bp! Register constant tracking (especially important as we often know where a zero word or byte is and we can use it for push immediate #0) Spotting two halves of a 32bit value being the same and merging Allow moves between half registers and their full shadow (al->ax) for char to short etc. How to balance compilers tendancy to allocate AL, AH, etc which is good for register freedom and bad for chars ? Better uchar handling - if we allocated xL before xH somehow in all cases then we would be able to do xL -> xX efficiently. We get very poor code because the compiler doesn't understand that type converting al does not destroy al, only ah and the al/ax relationship. In particular with char args it loves to write crap like mov bl, 1 ... mov al, bl cbw push ax mov al, bl cbw inc ax push ax not mov al, 1 cbw push ax inc al cbw push ax Questions --------- An assembler programmer would not mov al, #14 cbw but would mov ax, #0014 not obvious how we do that optimisation with pcc in all cases but its important Can we optimise compare with zero cases ? How do we make use of rep and loopXX, these are rather useful on 8086 but need indexes to tend to use the right register Should there be a CPU type/feature match in table.c ?pcc-20181216/arch/i86/code.c010064400017500000000000000257021337260706400141030ustar raggewheel/* $Id: code.c,v 1.3 2018/11/13 17:47:32 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass1.h" #ifdef LANG_CXX #define P1ND NODE #define p1alloc talloc #define p1tfree tfree #define p1listf listf #endif /* * Print out assembler segment name. */ void setseg(int seg, char *name) { switch (seg) { case PROG: name = ".TEXT"; break; case DATA: case LDATA: name = ".DATA"; break; case UDATA: break; case STRNG: case RDATA: name = ".DATA"; break; case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break; case DTORS: name = ".section\t.dtors,\"aw\",@progbits"; break; case NMSEG: printf("\t.section %s,\"a%c\",@progbits\n", name, cftnsp ? 'x' : 'w'); return; } printf("\t%s\n", name); } /* * Define everything needed to print out some data (or text). * This means segment, alignment, visibility, etc. */ void defloc(struct symtab *sp) { char *name; name = getexname(sp); if (sp->sclass == EXTDEF) { printf(" .globl %s\n", name); } if (sp->slevel == 0) printf("%s:\n", name); else printf(LABFMT ":\n", sp->soffset); } int structrettemp; /* * code for the end of a function * deals with struct return here */ void efcode(void) { extern int gotnr; P1ND *p, *q; gotnr = 0; /* new number for next fun */ if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) return; /* Create struct assignment */ q = tempnode(structrettemp, PTR+STRTY, 0, cftnsp->sap); q = buildtree(UMUL, q, NULL); p = block(REG, NULL, NULL, PTR+STRTY, 0, cftnsp->sap); p = buildtree(UMUL, p, NULL); p = buildtree(ASSIGN, q, p); ecomp(p); /* put hidden arg in ax on return */ q = tempnode(structrettemp, INT, 0, 0); p = block(REG, NULL, NULL, INT, 0, 0); regno(p) = AX; ecomp(buildtree(ASSIGN, p, q)); } static TWORD longregs[] = { AXDX, DXCX }; static TWORD regpregs[] = { AX, DX, CX }; static TWORD charregs[] = { AL, DL, CL }; /* * code for the beginning of a function; a is an array of * indices in symtab for the arguments; n is the number * * Classifying args on i386; not simple: * - Args may be on stack or in registers (regparm) * - There may be a hidden first arg, unless OpenBSD struct return. * - Regparm syntax is not well documented. * - There may be stdcall functions, where the called function pops stack * - ...probably more */ void bfcode(struct symtab **sp, int cnt) { extern int argstacksize; #ifdef GCC_COMPAT struct attr *ap; #endif struct symtab *sp2; extern int gotnr; P1ND *n, *p; int i, regparmarg; int argbase, nrarg, sz; argbase = ARGINIT; nrarg = regparmarg = 0; #ifdef GCC_COMPAT #if 0 if (attr_find(cftnsp->sap, GCC_ATYP_STDCALL) != NULL) cftnsp->sflags |= SSTDCALL; #endif if ((ap = attr_find(cftnsp->sap, GCC_ATYP_REGPARM))) regparmarg = ap->iarg(0); #endif /* Function returns struct, create return arg node */ if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { { if (regparmarg) { n = block(REG, 0, 0, INT, 0, 0); regno(n) = regpregs[nrarg++]; } else { n = block(OREG, 0, 0, INT, 0, 0); slval(n, argbase/SZCHAR); argbase += SZINT; regno(n) = FPREG; } p = tempnode(0, INT, 0, 0); structrettemp = regno(p); p = buildtree(ASSIGN, p, n); ecomp(p); } } /* * Find where all params are so that they end up at the right place. * At the same time recalculate their arg offset on stack. * We also get the "pop size" for stdcall. */ for (i = 0; i < cnt; i++) { sp2 = sp[i]; sz = tsize(sp2->stype, sp2->sdf, sp2->sap); SETOFF(sz, SZINT); if (cisreg(sp2->stype) == 0 || ((regparmarg - nrarg) * SZINT < sz)) { /* not in reg */ sp2->soffset = argbase; argbase += sz; nrarg = regparmarg; /* no more in reg either */ } else { /* in reg */ sp2->soffset = nrarg; nrarg += sz/SZINT; sp2->sclass = REGISTER; } } /* * Now (argbase - ARGINIT) is used space on stack. * Move (if necessary) the args to something new. */ for (i = 0; i < cnt; i++) { int reg, j; sp2 = sp[i]; if (ISSOU(sp2->stype) && sp2->sclass == REGISTER) { /* must move to stack */ sz = tsize(sp2->stype, sp2->sdf, sp2->sap); SETOFF(sz, SZINT); SETOFF(autooff, SZINT); reg = sp2->soffset; sp2->sclass = AUTO; sp2->soffset = NOOFFSET; oalloc(sp2, &autooff); for (j = 0; j < sz/SZCHAR; j += 4) { p = block(OREG, 0, 0, INT, 0, 0); slval(p, sp2->soffset/SZCHAR + j); regno(p) = FPREG; n = block(REG, 0, 0, INT, 0, 0); regno(n) = regpregs[reg++]; p = block(ASSIGN, p, n, INT, 0, 0); ecomp(p); } } else if (cisreg(sp2->stype) && !ISSOU(sp2->stype) && ((cqual(sp2->stype, sp2->squal) & VOL) == 0)) { /* just put rest in temps */ if (sp2->sclass == REGISTER) { n = block(REG, 0, 0, sp2->stype, sp2->sdf, sp2->sap); if (ISLONGLONG(sp2->stype)|| sp2->stype == LONG || sp2->stype == ULONG) regno(n) = longregs[sp2->soffset]; else if (DEUNSIGN(sp2->stype) == CHAR || sp2->stype == BOOL) regno(n) = charregs[sp2->soffset]; else regno(n) = regpregs[sp2->soffset]; } else { n = block(OREG, 0, 0, sp2->stype, sp2->sdf, sp2->sap); slval(n, sp2->soffset/SZCHAR); regno(n) = FPREG; } p = tempnode(0, sp2->stype, sp2->sdf, sp2->sap); sp2->soffset = regno(p); sp2->sflags |= STNODE; n = buildtree(ASSIGN, p, n); ecomp(n); } } argstacksize = 0; if (attr_find(cftnsp->sap, GCC_ATYP_STDCALL)) { argstacksize = (argbase - ARGINIT)/SZCHAR; } } /* called just before final exit */ /* flag is 1 if errors, 0 if none */ void ejobcode(int flag) { printf("\t.asciz \"PCC: %s\"\n", VERSSTR); } void bjobcode(void) { astypnames[INT] = astypnames[UNSIGNED] = "\t.long"; } /* * Convert FUNARG to assign in case of regparm. */ static int regcvt, rparg; static void addreg(P1ND *p) { TWORD t; P1ND *q; int sz, r; sz = tsize(p->n_type, p->n_df, p->n_ap)/SZCHAR; sz = (sz + 3) >> 2; /* sz in regs */ if ((regcvt+sz) > rparg) { regcvt = rparg; return; } if (sz > 2) uerror("cannot put struct in 3 regs (yet)"); if (sz == 2) r = regcvt == 0 ? AXDX : DXCX; else r = regcvt == 0 ? AX : regcvt == 1 ? DX : CX; if (p->n_op == FUNARG) { /* at most 2 regs */ if (p->n_type < INT) { p->n_left = ccast(p->n_left, INT, 0, 0, 0); p->n_type = INT; } p->n_op = ASSIGN; p->n_right = p->n_left; } else if (p->n_op == STARG) { /* convert to ptr, put in reg */ q = p->n_left; t = sz == 2 ? LONGLONG : INT; q = cast(q, INCREF(t), 0); q = buildtree(UMUL, q, NULL); p->n_op = ASSIGN; p->n_type = t; p->n_right = q; } else cerror("addreg"); p->n_left = block(REG, 0, 0, p->n_type, 0, 0); regno(p->n_left) = r; regcvt += sz; } /* * Called with a function call with arguments as argument. * This is done early in buildtree() and only done once. * Returns p. */ P1ND * funcode(P1ND *p) { extern int gotnr; #ifdef GCC_COMPAT struct attr *ap; #endif P1ND *r, *l; TWORD t = DECREF(DECREF(p->n_left->n_type)); int stcall; stcall = ISSOU(t); /* * We may have to prepend: * - Hidden arg0 for struct return (in reg or on stack). * - ebx in case of PIC code. */ /* Fix function call arguments. On x86, just add funarg */ for (r = p->n_right; r->n_op == CM; r = r->n_left) { if (r->n_right->n_op != STARG) { r->n_right = intprom(r->n_right); r->n_right = block(FUNARG, r->n_right, NULL, r->n_right->n_type, r->n_right->n_df, r->n_right->n_ap); } } if (r->n_op != STARG) { l = p1alloc(); *l = *r; r->n_op = FUNARG; r->n_left = l; r->n_left = intprom(r->n_left); r->n_type = r->n_left->n_type; } if (stcall) { /* Prepend a placeholder for struct address. */ /* Use BP, can never show up under normal circumstances */ l = p1alloc(); *l = *r; r->n_op = CM; r->n_right = l; r->n_type = INT; l = block(REG, 0, 0, INCREF(VOID), 0, 0); regno(l) = BP; l = block(FUNARG, l, 0, INCREF(VOID), 0, 0); r->n_left = l; } #ifdef GCC_COMPAT if ((ap = attr_find(p->n_left->n_ap, GCC_ATYP_REGPARM))) rparg = ap->iarg(0); else #endif rparg = 0; regcvt = 0; if (rparg) p1listf(p->n_right, addreg); return p; } /* fix up type of field p */ void fldty(struct symtab *p) { } /* * XXX - fix genswitch. */ int mygenswitch(int num, TWORD type, struct swents **p, int n) { return 0; } P1ND * builtin_return_address(const struct bitable *bt, P1ND *a) { int nframes; P1ND *f; if (a->n_op != ICON) goto bad; nframes = glval(a); p1tfree(a); f = block(REG, NULL, NULL, PTR+VOID, 0, 0); regno(f) = FPREG; while (nframes--) f = block(UMUL, f, NULL, PTR+VOID, 0, 0); f = block(PLUS, f, bcon(2), INCREF(PTR+VOID), 0, 0); f = buildtree(UMUL, f, NULL); return f; bad: uerror("bad argument to __builtin_return_address"); return bcon(0); } P1ND * builtin_frame_address(const struct bitable *bt, P1ND *a) { int nframes; P1ND *f; if (a->n_op != ICON) goto bad; nframes = glval(a); p1tfree(a); f = block(REG, NULL, NULL, PTR+VOID, 0, 0); regno(f) = FPREG; while (nframes--) f = block(UMUL, f, NULL, PTR+VOID, 0, 0); return f; bad: uerror("bad argument to __builtin_frame_address"); return bcon(0); } /* * Return "canonical frame address". */ P1ND * builtin_cfa(const struct bitable *bt, P1ND *a) { uerror("missing builtin_cfa"); return bcon(0); } pcc-20181216/arch/i86/flocal.c010064400017500000000000000110401240601250700144040ustar raggewheel/* $Id: flocal.c,v 1.1 2014/09/16 10:47:35 ragge Exp $ */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code and documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditionsand the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "defines.h" #include "defs.h" void prchars(int *s) { printf("\t.byte 0%o,0%o\n", s[0], s[1]); } void setloc(int l) { static int lastloc = -1; static char *loctbl[] = { "text", "data", "data", "data", "bss" }; if (l == lastloc) return; printf("\t.%s\n", loctbl[l]); lastloc = l; } #ifdef FCOM /* 8086 - SPECIFIC PRINTING ROUTINES */ /* * Called just before return from a subroutine. */ void goret(int type) { } /* * Print out a label. */ void prlabel(int k) { printf(LABFMT ":\n", k); } /* * Print naming for location. * name[0] is location type. */ void prnloc(char *name) { if (*name == '0') setloc(DATA); else fatal("unhandled prnloc %c", *name); printf("%s:\n", name+1); } /* * Print integer constant. */ void prconi(FILE *fp, int type, ftnint n) { fprintf(fp, "\t%s\t%ld\n", (type==TYSHORT ? ".word" : ".long"), n); } /* * Print address constant, given as a label number. */ void prcona(ftnint a) { printf("\t.long\t" LABFMT "\n", (int)a); } /* * Print out a floating constant. */ void prconr(FILE *fp, int type, double x) { fprintf(fp, "\t%s\t0f%e\n", (type==TYREAL ? ".float" : ".double"), x); } void preven(int k) { if (k > 1) printf("\t.align\t%d\n", k); } /* * Convert a tag and offset into the symtab table to a string. * An external string is never longer than XL bytes. */ char * memname(int stg, int mem) { #define MLEN (XL + 10) char *s = malloc(MLEN); switch(stg) { case STGCOMMON: case STGEXT: snprintf(s, MLEN, "%s", varstr(XL, extsymtab[mem].extname)); break; case STGBSS: case STGINIT: snprintf(s, MLEN, "v.%d", mem); break; case STGCONST: snprintf(s, MLEN, ".L%d", mem); break; case STGEQUIV: snprintf(s, MLEN, "q.%d", mem); break; default: fatal1("memname: invalid vstg %d", stg); } return(s); } void prlocvar(char *s, ftnint len) { printf("%s:\t.blkb\t%ld\n", s, len); } void prext(char *name, ftnint leng, int init) { if(leng == 0) printf("\t.globl\t%s\n", name); else printf("%s:\t.blkb %ld\n", name, leng); } void prendproc(void) { } void prtail(void) { } void prolog(struct entrypoint *ep, struct bigblock *argvec) { /* Ignore for now. ENTRY is not supported */ } void prdbginfo(void) { } static void fcheck(NODE *p, void *arg) { NODE *r, *l; switch (p->n_op) { case CALL: /* fix arguments */ for (r = p->n_right; r->n_op == CM; r = r->n_left) { r->n_right = mkunode(FUNARG, r->n_right, 0, r->n_right->n_type); } l = talloc(); *l = *r; r->n_op = FUNARG; r->n_left = l; r->n_type = l->n_type; break; } } /* * Called just before the tree is written out to pass2. */ void p2tree(NODE *p); void p2tree(NODE *p) { walkf(p, fcheck, 0); } #endif /* FCOM */ pcc-20181216/arch/i86/local.c010064400017500000000000000340721337260706400142630ustar raggewheel/* $Id: local.c,v 1.4 2018/11/13 17:47:32 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "pass1.h" /* this file contains code which is dependent on the target machine */ #ifdef LANG_CXX #define P1ND NODE #define p1alloc talloc #define p1tfree tfree #define p1nfree nfree #define p1listf listf #define p1fwalk fwalk #endif #ifdef notyet /* * Check if a constant is too large for a type. */ static int toolarge(TWORD t, CONSZ con) { U_CONSZ ucon = con; switch (t) { case ULONGLONG: case LONGLONG: break; /* cannot be too large */ #define SCHK(i) case i: if (con > MAX_##i || con < MIN_##i) return 1; break #define UCHK(i) case i: if (ucon > MAX_##i) return 1; break SCHK(INT); SCHK(SHORT); case BOOL: SCHK(CHAR); UCHK(UNSIGNED); UCHK(USHORT); UCHK(UCHAR); default: cerror("toolarge"); } return 0; } #endif #define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz)) static char * getsoname(struct symtab *sp) { struct attr *ap; return (ap = attr_find(sp->sap, ATTR_SONAME)) ? ap->sarg(0) : sp->sname; } int gotnr; /* tempnum for GOT register */ int argstacksize; /* clocal() is called to do local transformations on * an expression tree preparitory to its being * written out in intermediate code. * * the major essential job is rewriting the * automatic variables and arguments in terms of * REG and OREG nodes * conversion ops which are not necessary are also clobbered here * in addition, any special features (such as rewriting * exclusive or) are easily handled here as well */ P1ND * clocal(P1ND *p) { struct attr *ap; register struct symtab *q; register P1ND *r, *l; register int o; register int m; #ifdef PCC_DEBUG if (xdebug) { printf("clocal: %p\n", p); p1fwalk(p, eprint, 0); } #endif switch( o = p->n_op ){ case NAME: if ((q = p->n_sp) == NULL) return p; /* Nothing to care about */ switch (q->sclass) { case PARAM: case AUTO: /* fake up a structure reference */ r = block(REG, NULL, NULL, PTR+STRTY, 0, 0); slval(r, 0); r->n_rval = FPREG; p = stref(block(STREF, r, p, 0, 0, 0)); break; case USTATIC: break; case STATIC: break; case REGISTER: p->n_op = REG; slval(p, 0); p->n_rval = q->soffset; break; case EXTERN: case EXTDEF: break; } break; case ADDROF: break; case UCALL: break; case USTCALL: /* Add hidden arg0 */ r = block(REG, NULL, NULL, INCREF(VOID), 0, 0); regno(r) = BP; if ((ap = attr_find(p->n_ap, GCC_ATYP_REGPARM)) != NULL && ap->iarg(0) > 0) { l = block(REG, NULL, NULL, INCREF(VOID), 0, 0); regno(l) = AX; p->n_right = buildtree(ASSIGN, l, r); } else p->n_right = block(FUNARG, r, NULL, INCREF(VOID), 0, 0); p->n_op -= (UCALL-CALL); if (kflag == 0) break; l = block(REG, NULL, NULL, INT, 0, 0); regno(l) = BX; r = buildtree(ASSIGN, l, tempnode(gotnr, INT, 0, 0)); p->n_right = block(CM, r, p->n_right, INT, 0, 0); break; #ifdef notyet /* XXX breaks sometimes */ case CBRANCH: l = p->n_left; /* * Remove unnecessary conversion ops. */ if (!clogop(l->n_op) || l->n_left->n_op != SCONV) break; if (coptype(l->n_op) != BITYPE) break; if (l->n_right->n_op != ICON) break; r = l->n_left->n_left; if (r->n_type >= FLOAT) break; if (toolarge(r->n_type, glval(l->n_right))) break; l->n_right->n_type = r->n_type; if (l->n_op >= ULE && l->n_op <= UGT) l->n_op -= (UGT-ULE); p->n_left = buildtree(l->n_op, r, l->n_right); p1nfree(l->n_left); p1nfree(l); break; #endif case PCONV: l = p->n_left; /* Make int type before pointer */ if (l->n_type < INT || l->n_type == LONGLONG || l->n_type == ULONGLONG || l->n_type == BOOL) { /* float etc? */ p->n_left = block(SCONV, l, NULL, UNSIGNED, 0, 0); } break; case SCONV: if (p->n_left->n_op == COMOP) break; /* may propagate wrong type later */ l = p->n_left; if (p->n_type == l->n_type) { p1nfree(p); return l; } if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 && tsize(p->n_type, p->n_df, p->n_ap) == tsize(l->n_type, l->n_df, l->n_ap)) { if (p->n_type != FLOAT && p->n_type != DOUBLE && l->n_type != FLOAT && l->n_type != DOUBLE && l->n_type != LDOUBLE && p->n_type != LDOUBLE) { if (l->n_op == NAME || l->n_op == UMUL || l->n_op == TEMP) { l->n_type = p->n_type; p1nfree(p); return l; } } } if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT && coptype(l->n_op) == BITYPE && l->n_op != COMOP && l->n_op != QUEST) { l->n_type = p->n_type; p1nfree(p); return l; } o = l->n_op; m = p->n_type; if (o == ICON) { /* * Can only end up here if o is an address, * and in that case the only compile-time conversion * possible is to int. */ if ((TMASK & l->n_type) == 0 && l->n_sp == NULL) cerror("SCONV ICON"); if (l->n_sp == 0) { p->n_type = UNSIGNED; concast(l, m); } else if (m != INT && m != UNSIGNED) break; l->n_type = m; l->n_ap = 0; p1nfree(p); return l; } else if (l->n_op == FCON) cerror("SCONV FCON"); if ((p->n_type == CHAR || p->n_type == UCHAR || p->n_type == SHORT || p->n_type == USHORT) && (l->n_type == FLOAT || l->n_type == DOUBLE || l->n_type == LDOUBLE)) { p = block(SCONV, p, NULL, p->n_type, p->n_df, p->n_ap); p->n_left->n_type = INT; return p; } break; case MOD: case DIV: if (o == DIV && p->n_type != CHAR && p->n_type != SHORT) break; if (o == MOD && p->n_type != CHAR && p->n_type != SHORT) break; /* make it an int division by inserting conversions */ p->n_left = makety(p->n_left, INT, 0, 0, 0); p->n_right = makety(p->n_right, INT, 0, 0, 0); o = p->n_type; p->n_type = INT; p = makety(p, o, 0, 0, 0); break; case FORCE: /* put return value in return reg */ p->n_op = ASSIGN; p->n_right = p->n_left; p->n_left = block(REG, NULL, NULL, p->n_type, 0, 0); p->n_left->n_rval = p->n_left->n_type == BOOL ? RETREG(CHAR) : RETREG(p->n_type); break; case LS: case RS: /* shift count must be in a char */ if (p->n_right->n_type == CHAR || p->n_right->n_type == UCHAR) break; p->n_right = block(SCONV, p->n_right, NULL, CHAR, 0, 0); break; } #ifdef PCC_DEBUG if (xdebug) { printf("clocal end: %p\n", p); p1fwalk(p, eprint, 0); } #endif return(p); } static void mangle(P1ND *p); void myp2tree(P1ND *p) { struct symtab *sp; mangle(p); if (p->n_op != FCON) return; sp = IALLOC(sizeof(struct symtab)); sp->sclass = STATIC; sp->sap = 0; sp->slevel = 1; /* fake numeric label */ sp->soffset = getlab(); sp->sflags = 0; sp->stype = p->n_type; sp->squal = (CON >> TSHIFT); sp->sname = NULL; locctr(DATA, sp); defloc(sp); ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p); p->n_op = NAME; slval(p, 0); p->n_sp = sp; } /*ARGSUSED*/ int andable(P1ND *p) { return(1); /* all names can have & taken on them */ } /* * Return 1 if a variable of type type is OK to put in register. */ int cisreg(TWORD t) { if (t == FLOAT || t == DOUBLE || t == LDOUBLE) return 0; /* not yet */ return 1; } /* * Allocate off bits on the stack. p is a tree that when evaluated * is the multiply count for off, t is a storeable node where to write * the allocated address. */ void spalloc(P1ND *t, P1ND *p, OFFSZ off) { P1ND *sp; p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */ /* sub the size from sp */ sp = block(REG, NULL, NULL, p->n_type, 0, 0); slval(sp, 0); sp->n_rval = STKREG; ecomp(buildtree(MINUSEQ, sp, p)); /* save the address of sp */ sp = block(REG, NULL, NULL, PTR+INT, t->n_df, t->n_ap); slval(sp, 0); sp->n_rval = STKREG; t->n_type = sp->n_type; ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */ } /* * print out a constant node, may be associated with a label. * Do not free the node after use. * off is bit offset from the beginning of the aggregate * fsz is the number of bits this is referring to */ int ninval(CONSZ off, int fsz, P1ND *p) { union { float f; double d; long double l; int i[3]; } u; int i; switch (p->n_type) { case LONGLONG: case ULONGLONG: i = (int)(glval(p) >> 32); slval(p, glval(p) & 0xffffffff); p->n_type = INT; inval(off, 32, p); slval(p, i); inval(off+32, 32, p); break; case LDOUBLE: u.i[2] = 0; u.l = (long double)((FLT *)p->n_dcon)->fp; #if defined(HOST_BIG_ENDIAN) /* XXX probably broken on most hosts */ printf("\t.long\t0x%x,0x%x,0x%x\n", u.i[2], u.i[1], u.i[0]); #else printf("\t.long\t%d,%d,%d\n", u.i[0], u.i[1], u.i[2] & 0177777); #endif break; case DOUBLE: u.d = (double)((FLT *)p->n_dcon)->fp; #if defined(HOST_BIG_ENDIAN) printf("\t.long\t0x%x,0x%x\n", u.i[1], u.i[0]); #else printf("\t.long\t%d,%d\n", u.i[0], u.i[1]); #endif break; case FLOAT: u.f = (float)((FLT *)p->n_dcon)->fp; printf("\t.long\t%d\n", u.i[0]); break; default: return 0; } return 1; } /* make a name look like an external name in the local machine */ char * exname(char *p) { #define NCHNAM 256 static char text[NCHNAM+1]; int i; if (p == NULL) return ""; text[0] = '_'; for (i=1; *p && istype, sp->sap)/SZCHAR; off = (int)tsize(sp->stype, sp->sdf, sp->sap); SETOFF(off,SZCHAR); off /= SZCHAR; printf("\t.align %d\n", al); printf("%s:\t.blkb %d\n", name, off); } static int stdcall; static char *alias; static int constructor; static int destructor; /* * Give target the opportunity of handling pragmas. */ int mypragma(char *str) { char *a2 = pragtok(NULL); if (strcmp(str, "stdcall") == 0) { stdcall = 1; return 1; } if (strcmp(str, "cdecl") == 0) { stdcall = 0; return 1; } #ifndef AOUTABI if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) { constructor = 1; return 1; } if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) { destructor = 1; return 1; } #endif if (strcmp(str, "alias") == 0 && a2 != NULL) { alias = tmpstrdup(a2); return 1; } return 0; } /* * Called when a identifier has been declared. */ void fixdef(struct symtab *sp) { #ifdef GCC_COMPAT struct attr *ap; #endif #ifdef GCC_COMPAT #ifdef HAVE_WEAKREF /* not many as'es have this directive */ if ((ap = attr_find(sp->sap, GCC_ATYP_WEAKREF)) != NULL) { char *wr = ap->sarg(0); char *sn = getsoname(sp); if (sp->sclass != STATIC && sp->sclass != USTATIC) uerror("weakref %s must be static", sp->sname); if (wr == NULL) { if ((ap = attr_find(sp->sap, GCC_ATYP_ALIAS))) { wr = ap->sarg(0); } } if (wr == NULL) printf("\t.weak %s\n", sn); else printf("\t.weakref %s,%s\n", sn, wr); } else #endif if ((ap = attr_find(sp->sap, GCC_ATYP_ALIAS)) != NULL) { char *an = ap->sarg(0); char *sn = getsoname(sp); char *v; v = attr_find(sp->sap, GCC_ATYP_WEAK) ? "weak" : "globl"; printf("\t.%s %s\n", v, sn); printf("\t.set %s,%s\n", sn, an); } #endif if (alias != NULL && (sp->sclass != PARAM)) { char *name = getexname(sp); printf("\t.globl %s\n", name); printf("%s = ", name); printf("%s\n", exname(alias)); alias = NULL; } if ((constructor || destructor) && (sp->sclass != PARAM)) { printf("\t.section .%ctors,\"w\"\n", constructor ? 'c' : 'd'); printf("\t.p2align 2\n"); printf("\t.long %s\n", exname(sp->sname)); printf("\t.previous\n"); constructor = destructor = 0; } #if 0 if (stdcall && (sp->sclass != PARAM)) { sp->sflags |= SSTDCALL; stdcall = 0; } #endif } /* * Postfix external functions with the arguments size. */ static void mangle(P1ND *p) { P1ND *l; if (p->n_op != CALL && p->n_op != STCALL && p->n_op != UCALL && p->n_op != USTCALL) return; l = p->n_left; while (cdope(l->n_op) & CALLFLG) l = l->n_left; if (l->n_op == TEMP) return; if (l->n_op == ADDROF) l = l->n_left; if (l->n_sp == NULL) return; #ifdef GCC_COMPAT #if 0 if (attr_find(l->n_sp->sap, GCC_ATYP_STDCALL) != NULL) l->n_sp->sflags |= SSTDCALL; #endif #endif } void pass1_lastchance(struct interpass *ip) { if (ip->type == IP_NODE && (ip->ip_node->n_op == CALL || ip->ip_node->n_op == UCALL) && ISFTY(ip->ip_node->n_type)) ip->ip_node->n_ap = attr_add(ip->ip_node->n_ap, attr_new(ATTR_I86_FPPOP, 1)); if (ip->type == IP_EPILOG) { struct interpass_prolog *ipp = (struct interpass_prolog *)ip; ipp->ipp_argstacksize = argstacksize; } } pcc-20181216/arch/i86/local2.c010064400017500000000000000767121337260706400143540ustar raggewheel/* $Id: local2.c,v 1.9 2018/11/13 17:47:32 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass2.h" # include # include #define EXPREFIX "_" static int stkpos; static int suppress_type; /* Don't display a type on the next expansion */ void deflab(int label) { printf(LABFMT ":\n", label); } static int regoff[7]; static TWORD ftype; /* * Print out the prolog assembler. * addto and regoff are already calculated. */ static void prtprolog(struct interpass_prolog *ipp, int addto) { int i; #if 1 /* FIXME: can't use enter/leave if generating i8086 */ if (addto == 0 || addto > 65535 || 1) { printf(" push bp\n\tmov bp,sp\n"); if (addto) printf(" sub sp,#%d\n", addto); } else printf(" enter %d,0\n", addto); #endif for (i = 0; i < MAXREGS; i++) if (TESTBIT(p2env.p_regs, i)) printf(" mov -%d[%s],%s\n", regoff[i], rnames[FPREG], rnames[i]); } /* * calculate stack size and offsets */ static int offcalc(struct interpass_prolog *ipp) { int i, addto; addto = p2maxautooff; if (addto >= AUTOINIT/SZCHAR) addto -= AUTOINIT/SZCHAR; for (i = 0; i < MAXREGS; i++) if (TESTBIT(p2env.p_regs, i)) { addto += SZINT/SZCHAR; regoff[i] = addto; } return addto; } void prologue(struct interpass_prolog *ipp) { int addto; ftype = ipp->ipp_type; #ifdef LANG_F77 if (ipp->ipp_vis) printf(" .globl %s\n", ipp->ipp_name); printf(" .align 4\n"); printf("%s:\n", ipp->ipp_name); #endif /* * We here know what register to save and how much to * add to the stack. */ addto = offcalc(ipp); prtprolog(ipp, addto); } void eoftn(struct interpass_prolog *ipp) { int i; if (ipp->ipp_ip.ip_lbl == 0) return; /* no code needs to be generated */ /* return from function code */ for (i = 0; i < MAXREGS; i++) if (TESTBIT(p2env.p_regs, i)) printf(" mov %s,-%d[%s]\n", rnames[i],regoff[i], rnames[FPREG]); /* struct return needs special treatment */ if (ftype == STRTY || ftype == UNIONTY) { printf(" mov ax, 8[bp]\n"); printf(" leave\n"); /* FIXME: ret n is not in 8086 */ printf(" ret %d\n", 4 + ipp->ipp_argstacksize); } else { printf(" mov sp, bp\n"); printf(" pop bp\n"); if (ipp->ipp_argstacksize) /* CHECK ME */ printf(" add sp, #%d\n", ipp->ipp_argstacksize); printf(" ret\n"); } } /* * add/sub/... * * Param given: */ void hopcode(int f, int o) { char *str; switch (o) { case PLUS: str = "add"; break; case MINUS: str = "sub"; break; case AND: str = "and"; break; case OR: str = "or"; break; case ER: str = "xor"; break; default: comperr("hopcode2: %d", o); str = 0; /* XXX gcc */ } printf("%s", str); /* don't need %c f as far as I can see */ } /* * Return type size in bytes. Used by R2REGS, arg 2 to offset(). */ int tlen(NODE *p) { switch(p->n_type) { case CHAR: case UCHAR: return(1); case SHORT: case USHORT: case INT: case UNSIGNED: return(SZINT/SZCHAR); case DOUBLE: return(SZDOUBLE/SZCHAR); case LONG: case ULONG: return(SZLONG/SZCHAR); case LONGLONG: case ULONGLONG: return SZLONGLONG/SZCHAR; default: if (!ISPTR(p->n_type)) comperr("tlen type %d not pointer"); return SZPOINT(p->n_type)/SZCHAR; } } /* * Emit code to compare two long numbers. */ static void twollcomp(NODE *p) { int u; int s = getlab2(); int e = p->n_label; int cb1, cb2; u = p->n_op; switch (p->n_op) { case NE: cb1 = 0; cb2 = NE; break; case EQ: cb1 = NE; cb2 = 0; break; case LE: case LT: u += (ULE-LE); /* FALLTHROUGH */ case ULE: case ULT: cb1 = GT; cb2 = LT; break; case GE: case GT: u += (ULE-LE); /* FALLTHROUGH */ case UGE: case UGT: cb1 = LT; cb2 = GT; break; default: cb1 = cb2 = 0; /* XXX gcc */ } if (p->n_op >= ULE) cb1 += 4, cb2 += 4; expand(p, 0, " cmp UL,UR\n"); if (cb1) cbgen(cb1, s); if (cb2) cbgen(cb2, e); expand(p, 0, " cmp AL,AR\n"); cbgen(u, e); deflab(s); } int fldexpand(NODE *p, int cookie, char **cp) { comperr("fldexpand"); return 0; } /* * Push a structure on stack as argument. * the scratch registers are already free here */ static void starg(NODE *p) { NODE *q = p->n_left; int s = (attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0) + 1) & ~1; if (s == 2) printf(" dec sp\n dec sp\n"); else printf(" sub sp,#%d\n", s); p->n_left = mklnode(OREG, 0, SP, INT); zzzcode(p, 'Q'); tfree(p->n_left); p->n_left = q; } /* * Compare two floating point numbers. */ static void fcomp(NODE *p) { static char *fpcb[] = { "jz", "jnz", "jbe", "jc", "jnc", "ja" }; if ((p->n_su & DORIGHT) == 0) expand(p, 0, "\tfxch\n"); expand(p, 0, "\tfucomip %st(1),%st\n"); /* emit compare insn */ expand(p, 0, "\tfstp %st(0)\n"); /* pop fromstack */ if (p->n_op == NE || p->n_op == GT || p->n_op == GE) expand(p, 0, "\tjp LC\n"); else if (p->n_op == EQ) printf("\tjp 1f\n"); printf(" %s ", fpcb[p->n_op - EQ]); expand(p, 0, "LC\n"); if (p->n_op == EQ) printf("1:\n"); } /* * Convert an unsigned long long to floating point number. */ static void ulltofp(NODE *p) { int jmplab; jmplab = getlab2(); expand(p, 0, " push UL\n push AL\n"); expand(p, 0, " fildq [sp]\n"); expand(p, 0, " add sp, #8\n"); expand(p, 0, " cmp UL, #0\n"); printf(" jge " LABFMT "\n", jmplab); printf(" faddp %%st,%%st(1)\n"); printf(LABFMT ":\n", jmplab); } static int argsiz(NODE *p) { TWORD t = p->n_type; if (t < LONG) return 2; if (t == LONG || t == ULONG || t == LONGLONG || t == ULONGLONG) return 4; if (t == FLOAT) return 4; if (t > BTMASK) return 2; if (t == DOUBLE) return 8; if (t == LDOUBLE) return 12; if (t == STRTY || t == UNIONTY) return (attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)+1) & ~1; comperr("argsiz"); return 0; } static void fcast(NODE *p) { TWORD t = p->n_type; int sz, c; if (t >= p->n_left->n_type) return; /* cast to more precision */ if (t == FLOAT) sz = 4, c = 's'; else sz = 8, c = 'l'; printf(" sub sp, #%d\n", sz); printf(" fstp%c (%%sp)\n", c); printf(" fld%c (%%sp)\n", c); printf(" add sp, #%d\n", sz); } #if 0 static void llshft(NODE *p) { NODE *r = p->n_right; /* FIXME: we have sal/shl/sar/shr but we are limited to shift right or left 1 shift right or left by CL */ char *d[3]; /* We ought to shortcut this earlier but it's not obivous how to do a match and say 'any old register pair' FIXME */ if (r->n_op == ICON) { /* FIXME: we need different versions of this for signed right shifting. Just test code - register setup needs checking for ordering etc yet */ if (getrval(r) == 16) { if (p->n_op == RS) printf("\tmov ax, dx\n\txor dx,dx\n"); else printf("\tmov dx, ax\n\txor ax,ax\n"); return; } if (getrval(r) == 8) { if (p->n_op == RS) printf("\tmov al, ah\n\tmov ah, dl\n\tmov dl, dh\n\txor dh,dh\n"); else printf("\tmov ah, al\n\tmov dl, ah\n\tmov dh, dl\n\txor al, al\n"); return; } if (getrval(r) == 24) { if (p->n_op == RS) printf("\txor dx,dx\n\tmov al, dh\n\txor ax,ax\n"); else printf("\txor ax,ax\n\tmov dh, al\n\txor dx,dx\n"); return; } } if (p->n_op == LS) { d[0] = "l", d[1] = "ax", d[2] = "dx"; } else d[0] = "r", d[1] = "dx", d[2] = "ax"; printf("\tsh%sdl %s,%s\n",d[0], d[1], d[2]); printf("\ts%s%sl %%cl,%s\n", p->n_op == RS && (p->n_left->n_type == ULONG || p->n_left->n_type == ULONGLONG) ? "h" : "a", d[0], d[1]); printf("\ttestb $16,%%cl\n"); printf("\tje 1f\n"); printf("\tmov %s,%s\n", d[1], d[2]); if (p->n_op == RS && (p->n_left->n_type == LONGLONG|| p->n_left->n_type == LONG)) printf("\tsarl $31,%%edx\n"); else printf("\txor %s,%s\n",d[1],d[1]); printf("1:\n"); } #endif void zzzcode(NODE *p, int c) { struct attr *ap; NODE *l; int pr, lr; char *ch; char sv; switch (c) { case 'A': /* swap st0 and st1 if right is evaluated second */ if ((p->n_su & DORIGHT) == 0) { if (logop(p->n_op)) printf(" fxch\n"); else printf("r"); } break; case 'C': /* remove from stack after subroutine call */ #ifdef notdef if (p->n_left->n_flags & FSTDCALL) break; #endif pr = p->n_qual; if (attr_find(p->n_ap, ATTR_I86_FPPOP)) printf(" fstp st(0)\n"); if (p->n_op == UCALL) return; /* XXX remove ZC from UCALL */ if (pr) { if (pr == 2) printf(" inc sp\n inc sp\n"); else printf(" add sp,#%d\n", pr); } break; case 'D': /* Long comparision */ twollcomp(p); break; case 'F': /* Structure argument */ starg(p); break; case 'G': /* Floating point compare */ fcomp(p); break; case 'H': /* assign of long between regs */ rmove(DECRA(p->n_right->n_reg, 0), DECRA(p->n_left->n_reg, 0), LONGLONG); break; case 'I': /* float casts */ fcast(p); break; case 'J': /* convert unsigned long long to floating point */ ulltofp(p); break; case 'K': /* Load long reg into another reg */ rmove(regno(p), DECRA(p->n_reg, 0), LONGLONG); break; case 'M': /* Output sconv move, if needed */ l = getlr(p, 'L'); /* XXX fixneed: regnum */ pr = DECRA(p->n_reg, 0); lr = DECRA(l->n_reg, 0); if ((pr == AL && lr == AX) || (pr == BL && lr == BX) || (pr == CL && lr == CX) || (pr == DL && lr == DX)) ; else printf(" mov %s, %cL\n", rnames[pr], rnames[lr][1]); l->n_rval = l->n_reg = p->n_reg; /* XXX - not pretty */ break; case 'N': /* output extended reg name */ printf("%s", rnames[getlr(p, '1')->n_rval]); break; case 'O': /* print out emulated ops */ pr = 8; sv = 'l'; #if 0 if (p->n_op == RS || p->n_op == LS) { llshft(p); break; } #endif if (p->n_op != RS && p->n_op != LS) { /* For 64bit we will need to push pointers not u64 */ expand(p, INCREG, "\tpush UR\n\tpush AR\n"); expand(p, INCREG, "\tpush UL\n\tpush AL\n"); } else { /* AR is a BREG so this goes wrong.. need an AREG but putting an AREG in the table rule makes the compiler shit itself - FIXME */ expand(p, INAREG, "\tpush AR\n"); expand(p, INCREG, "\tpush UL\n\tpush AL\n"); pr = 6; } if (p->n_type == LONGLONG || p->n_type == ULONGLONG) sv = 'L'; if (p->n_op == DIV && (p->n_type == ULONG || p->n_type == ULONGLONG)) ch = "udiv"; else if (p->n_op == MUL && (p->n_type == ULONG || p->n_type == ULONGLONG)) ch = "umul"; else if (p->n_op == DIV) ch = "div"; else if (p->n_op == MUL) ch = "mul"; else if (p->n_op == MOD && (p->n_type == ULONG || p->n_type == ULONGLONG)) ch = "umod"; else if (p->n_op == MOD) ch = "mod"; else if (p->n_op == LS) ch = "ls"; else if (p->n_op == RS && (p->n_type == ULONG || p->n_type == ULONGLONG)) ch = "rs"; else if (p->n_op == RS) ch = "urs"; else ch = 0, comperr("ZO"); printf("\tcall " EXPREFIX "__%c%sdi3\n\tadd %s,#%d\n", sv, ch, rnames[SP], pr); break; case 'P': /* typeless right hand */ suppress_type = 1; break; case 'Q': /* emit struct assign */ /* * Put out some combination of movs{b,w} * si/di/cx are available. * FIXME: review es: and direction flag implications */ expand(p, INAREG, " lea al,di\n"); ap = attr_find(p->n_ap, ATTR_P2STRUCT); if (ap->iarg(0) < 32) { int i = ap->iarg(0) >> 1; while (i) { expand(p, INAREG, " movsw\n"); i--; } } else { printf("\tmov cx, #%d\n", ap->iarg(0) >> 1); printf(" rep movsw\n"); } if (ap->iarg(0) & 2) printf(" movsw\n"); if (ap->iarg(0) & 1) printf(" movsb\n"); break; case 'S': /* emit eventual move after cast from long */ pr = DECRA(p->n_reg, 0); lr = p->n_left->n_rval; switch (p->n_type) { case CHAR: case UCHAR: if (rnames[pr][1] == 'L' && rnames[lr][1] == 'X' && rnames[pr][0] == rnames[lr][0]) break; if (rnames[lr][1] == 'X') { printf("\tmov %s, %cL\n", rnames[pr], rnames[lr][0]); break; } /* Must go via stack */ expand(p, INAREG, "\tmov A2,AL\n"); expand(p, INBREG, "\tmov A1,A2\n"); #ifdef notdef /* cannot use freetemp() in instruction emission */ s = freetemp(1); printf("\tmov %ci,%d(bp)\n", rnames[lr][0], s); printf("\tmov %s, %d(bp)\n", rnames[pr], s); #endif break; case INT: case UNSIGNED: if (rnames[lr][0] == rnames[pr][1] && rnames[lr][1] == rnames[pr][2]) break; printf("\tmov %s, %c%c\n", rnames[pr], rnames[lr][0], rnames[lr][1]); break; default: if (rnames[lr][0] == rnames[pr][1] && rnames[lr][1] == rnames[pr][2]) break; comperr("SCONV2 %s->%s", rnames[lr], rnames[pr]); break; } break; case 'T': /* Conversions from unsigned char to int/ptr */ /* Cannot be in DI or SI */ l = getlr(p, 'L'); lr = regno(l); pr = regno(getlr(p, '1')); if (l->n_op != REG) { /* NAME or OREG */ /* Need to force a mov into the low half, using a movw might fail in protected mode or with mmio spaces */ printf(" mov %cl, ", rnames[pr][0]); expand(p, INAREG, "AL\n"); } else { if ((lr == AL && pr == AX) || (lr == BL && pr == BX) || (lr == CL && pr == CX) || (lr == DL && pr == DX)) ; else printf(" mov %cl,%cl\n", rnames[pr][0],rnames[lr][0]); } printf(" xor %ch,%ch\n", rnames[pr][0], rnames[pr][0]); break; break; default: comperr("zzzcode %c", c); } } int canaddr(NODE *); int canaddr(NODE *p) { int o = p->n_op; if (o==NAME || o==REG || o==ICON || o==OREG || (o==UMUL && shumul(p->n_left, SOREG))) return(1); return(0); } /* * Does the bitfield shape match? */ int flshape(NODE *p) { comperr("flshape"); return 0; } /* INTEMP shapes must not contain any temporary registers */ /* XXX should this go away now? */ int shtemp(NODE *p) { return 0; #if 0 int r; if (p->n_op == STARG ) p = p->n_left; switch (p->n_op) { case REG: return (!istreg(p->n_rval)); case OREG: r = p->n_rval; if (R2TEST(r)) { if (istreg(R2UPK1(r))) return(0); r = R2UPK2(r); } return (!istreg(r)); case UMUL: p = p->n_left; return (p->n_op != UMUL && shtemp(p)); } if (optype(p->n_op) != LTYPE) return(0); return(1); #endif } void adrcon(CONSZ val) { printf("$" CONFMT, val); } void conput(FILE *fp, NODE *p) { int val = getlval(p); switch (p->n_op) { case ICON: if (p->n_name[0] != '\0') { fprintf(fp, "#%s", p->n_name); if (val) fprintf(fp, "+%d", val); } else fprintf(fp, "#%d", val); return; default: comperr("illegal conput, p %p", p); } } /*ARGSUSED*/ void insput(NODE *p) { comperr("insput"); } /* * Write out the upper address, like the upper register of a 2-register * reference, or the next memory location. */ void upput(NODE *p, int size) { size /= SZCHAR; switch (p->n_op) { case REG: printf("%s", &rnames[p->n_rval][2]); break; case NAME: case OREG: setlval(p, getlval(p) + size); adrput(stdout, p); setlval(p, getlval(p) - size); break; case ICON: printf("#"CONFMT, getlval(p) >> 16); break; default: comperr("upput bad op %d size %d", p->n_op, size); } } static void do_adrput(FILE *io, NODE *p, int ut) { int r; /* output an address, with offsets, from p */ switch (p->n_op) { case NAME: if (!ut) { switch (p->n_type) { case SHORT: case USHORT: case INT: case UNSIGNED: printf("word ptr "); break; case CHAR: case UCHAR: printf("byte ptr "); } } if (p->n_name[0] != '\0') { fputs(p->n_name, io); if (getlval(p) != 0) fprintf(io, "+" CONFMT, getlval(p)); } else fprintf(io, "#"CONFMT, getlval(p)); return; case OREG: r = p->n_rval; if (p->n_name[0]) printf("%s%s", p->n_name, getlval(p) ? "+" : ""); if (getlval(p)) fprintf(io, "%d", (int)getlval(p)); printf("["); if (R2TEST(r)) { fprintf(io, "%s,%s,4", rnames[R2UPK1(r)], rnames[R2UPK2(r)]); } else fprintf(io, "%s", rnames[p->n_rval]); printf("]"); return; case ICON: /* addressable value of the constant */ if (!ut) { switch (p->n_type) { case SHORT: case USHORT: case INT: case UNSIGNED: printf("word "); break; case CHAR: case UCHAR: printf("byte "); } } conput(io, p); return; case REG: switch (p->n_type) { case LONGLONG: case ULONGLONG: case LONG: case ULONG: fprintf(io, "%c%c", rnames[p->n_rval][0], rnames[p->n_rval][1]); break; default: fprintf(io, "%s", rnames[p->n_rval]); } return; default: comperr("illegal address, op %d, node %p", p->n_op, p); return; } } void adrput(FILE *io, NODE *p) { do_adrput(io, p, suppress_type); suppress_type = 0; } static char * ccbranches[] = { "je", /* jumpe */ "jne", /* jumpn */ "jle", /* jumple */ "jl", /* jumpl */ "jge", /* jumpge */ "jg", /* jumpg */ "jbe", /* jumple (jlequ) */ "jb", /* jumpl (jlssu) */ "jae", /* jumpge (jgequ) */ "ja", /* jumpg (jgtru) */ }; /* printf conditional and unconditional branches */ void cbgen(int o, int lab) { if (o < EQ || o > UGT) comperr("bad conditional branch: %s", opst[o]); printf(" %s " LABFMT "\n", ccbranches[o-EQ], lab); } static void fixcalls(NODE *p, void *arg) { /* Prepare for struct return by allocating bounce space on stack */ switch (p->n_op) { case STCALL: case USTCALL: if (attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)+p2autooff > stkpos) stkpos = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)+p2autooff; break; case LS: case RS: if (p->n_type != LONGLONG && p->n_type != ULONGLONG && p->n_type != LONG && p->n_type != ULONG) break; if (p->n_right->n_op == ICON) /* constants must be char */ p->n_right->n_type = CHAR; break; } } /* * Must store floats in memory if there are two function calls involved. */ static int storefloat(struct interpass *ip, NODE *p) { int l, r; switch (optype(p->n_op)) { case BITYPE: l = storefloat(ip, p->n_left); r = storefloat(ip, p->n_right); if (p->n_op == CM) return 0; /* arguments, don't care */ if (callop(p->n_op)) return 1; /* found one */ #define ISF(p) ((p)->n_type == FLOAT || (p)->n_type == DOUBLE || \ (p)->n_type == LDOUBLE) if (ISF(p->n_left) && ISF(p->n_right) && l && r) { /* must store one. store left */ struct interpass *nip; TWORD t = p->n_left->n_type; NODE *ll; int off; off = freetemp(szty(t)); ll = mklnode(OREG, off, FPREG, t); nip = ipnode(mkbinode(ASSIGN, ll, p->n_left, t)); p->n_left = mklnode(OREG, off, FPREG, t); DLIST_INSERT_BEFORE(ip, nip, qelem); } return l|r; case UTYPE: l = storefloat(ip, p->n_left); if (callop(p->n_op)) l = 1; return l; default: return 0; } } static void outfargs(struct interpass *ip, NODE **ary, int num, int *cwp, int c) { struct interpass *ip2; NODE *q, *r; int i; for (i = 0; i < num; i++) if (XASMVAL(cwp[i]) == c && (cwp[i] & (XASMASG|XASMINOUT))) break; if (i == num) return; q = ary[i]->n_left; r = mklnode(REG, 0, c == 'u' ? 040 : 037, q->n_type); ary[i]->n_left = tcopy(r); ip2 = ipnode(mkbinode(ASSIGN, q, r, q->n_type)); DLIST_INSERT_AFTER(ip, ip2, qelem); } static void infargs(struct interpass *ip, NODE **ary, int num, int *cwp, int c) { struct interpass *ip2; NODE *q, *r; int i; for (i = 0; i < num; i++) if (XASMVAL(cwp[i]) == c && (cwp[i] & XASMASG) == 0) break; if (i == num) return; q = ary[i]->n_left; q = (cwp[i] & XASMINOUT) ? tcopy(q) : q; r = mklnode(REG, 0, c == 'u' ? 040 : 037, q->n_type); if ((cwp[i] & XASMINOUT) == 0) ary[i]->n_left = tcopy(r); ip2 = ipnode(mkbinode(ASSIGN, r, q, q->n_type)); DLIST_INSERT_BEFORE(ip, ip2, qelem); } /* * Extract float args to XASM and ensure that they are put on the stack * in correct order. * This should be done sow other way. */ static void fixxfloat(struct interpass *ip, NODE *p) { NODE *w, **ary; int nn, i, c, *cwp; nn = 1; w = p->n_left; if (w->n_op == ICON && w->n_type == STRTY) return; /* index all xasm args first */ for (; w->n_op == CM; w = w->n_left) nn++; ary = tmpcalloc(nn * sizeof(NODE *)); cwp = tmpcalloc(nn * sizeof(int)); for (i = 0, w = p->n_left; w->n_op == CM; w = w->n_left) { ary[i] = w->n_right; cwp[i] = xasmcode(ary[i]->n_name); i++; } ary[i] = w; cwp[i] = xasmcode(ary[i]->n_name); for (i = 0; i < nn; i++) if (XASMVAL(cwp[i]) == 't' || XASMVAL(cwp[i]) == 'u') break; if (i == nn) return; for (i = 0; i < nn; i++) { c = XASMVAL(cwp[i]); if (c >= '0' && c <= '9') cwp[i] = (cwp[i] & ~0377) | XASMVAL(cwp[c-'0']); } infargs(ip, ary, nn, cwp, 'u'); infargs(ip, ary, nn, cwp, 't'); outfargs(ip, ary, nn, cwp, 't'); outfargs(ip, ary, nn, cwp, 'u'); } static NODE * lptr(NODE *p) { if (p->n_op == ASSIGN && p->n_right->n_op == REG && regno(p->n_right) == BP) return p->n_right; if (p->n_op == FUNARG && p->n_left->n_op == REG && regno(p->n_left) == BP) return p->n_left; return NIL; } /* * Find arg reg that should be struct reference instead. */ static void updatereg(NODE *p, void *arg) { NODE *q; if (p->n_op != STCALL) return; if (p->n_right->n_op != CM) p = p->n_right; else for (p = p->n_right; p->n_op == CM && p->n_left->n_op == CM; p = p->n_left) ; if (p->n_op == CM) { if ((q = lptr(p->n_left))) ; else q = lptr(p->n_right); } else q = lptr(p); if (q == NIL) comperr("bad STCALL hidden reg"); /* q is now the hidden arg */ q->n_op = MINUS; q->n_type = INCREF(CHAR); q->n_left = mklnode(REG, 0, BP, INCREF(CHAR)); q->n_right = mklnode(ICON, stkpos, 0, INT); } void myreader(struct interpass *ipole) { struct interpass *ip; stkpos = p2autooff; DLIST_FOREACH(ip, ipole, qelem) { if (ip->type != IP_NODE) continue; walkf(ip->ip_node, fixcalls, 0); storefloat(ip, ip->ip_node); if (ip->ip_node->n_op == XASM) fixxfloat(ip, ip->ip_node); } if (stkpos != p2autooff) { DLIST_FOREACH(ip, ipole, qelem) { if (ip->type != IP_NODE) continue; walkf(ip->ip_node, updatereg, 0); } } if (stkpos > p2autooff) p2autooff = stkpos; if (stkpos > p2maxautooff) p2maxautooff = stkpos; if (x2debug) printip(ipole); } /* * Remove some PCONVs after OREGs are created. */ static void pconv2(NODE *p, void *arg) { NODE *q; if (p->n_op == PLUS) { if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) { if (p->n_right->n_op != ICON) return; if (p->n_left->n_op != PCONV) return; if (p->n_left->n_left->n_op != OREG) return; q = p->n_left->n_left; nfree(p->n_left); p->n_left = q; /* * This will be converted to another OREG later. */ } } } void mycanon(NODE *p) { walkf(p, pconv2, 0); } void myoptim(struct interpass *ip) { } static char rl[] = { AX, AX, AX, AX, AX, DX, DX, DX, DX, CX, CX, CX, BX, BX, SI }; static char rh[] = { DX, CX, BX, SI, DI, CX, BX, SI, DI, BX, SI, DI, SI, DI, DI }; void rmove(int s, int d, TWORD t) { int sl, sh, dl, dh; switch (t) { case LONGLONG: case ULONGLONG: case LONG: case ULONG: /* ?? FIXME check */ #if 1 sl = rl[s-AXDX]; sh = rh[s-AXDX]; dl = rl[d-AXDX]; dh = rh[d-AXDX]; /* sanity checks, remove when satisfied */ if (memcmp(rnames[s], rnames[sl], 2) != 0 || memcmp(rnames[s]+2, rnames[sh], 2) != 0) comperr("rmove source error"); if (memcmp(rnames[d], rnames[dl], 2) != 0 || memcmp(rnames[d]+2, rnames[dh], 2) != 0) comperr("rmove dest error"); #define SW(x,y) { int i = x; x = y; y = i; } if (sh == dl) { /* Swap if overwriting */ SW(sl, sh); SW(dl, dh); } if (sl != dl) printf(" mov %s,%s\n", rnames[dl], rnames[sl]); if (sh != dh) printf(" mov %s,%s\n", rnames[dh], rnames[sh]); #else if (memcmp(rnames[s], rnames[d], 2) != 0) printf(" mov %c%c,%c%c\n", rnames[d][0],rnames[d][1], rnames[s][0],rnames[s][1]); if (memcmp(&rnames[s][2], &rnames[d][2], 2) != 0) printf(" mov %c%c,%c%c\n", rnames[d][2],rnames[d][3] rnames[s][2],rnames[s][3]); #endif break; case CHAR: case UCHAR: printf(" mov %s,%s\n", rnames[d], rnames[s]); break; case FLOAT: case DOUBLE: case LDOUBLE: #ifdef notdef /* a=b()*c(); will generate this */ comperr("bad float rmove: %d %d", s, d); #endif break; default: printf(" mov %s,%s\n", rnames[d], rnames[s]); } } /* * For class c, find worst-case displacement of the number of * registers in the array r[] indexed by class. */ int COLORMAP(int c, int *r) { int num; switch (c) { case CLASSA: num = r[CLASSB] > 4 ? 4 : r[CLASSB]; num += 2*r[CLASSC]; num += r[CLASSA]; return num < 6; case CLASSB: num = r[CLASSA]; num += 2*r[CLASSC]; num += r[CLASSB]; return num < 4; case CLASSC: num = r[CLASSA]; num += r[CLASSB] > 4 ? 4 : r[CLASSB]; num += 2*r[CLASSC]; return num < 5; case CLASSD: return r[CLASSD] < DREGCNT; } return 0; /* XXX gcc */ } char *rnames[] = { "ax", "dx", "cx", "bx", "si", "di", "bp", "sp", "al", "ah", "dl", "dh", "cl", "ch", "bl", "bh", "axdx", "axcx", "axbx", "axsi", "axdi", "dxcx", "dxbx", "dxsi", "dxdi", "cxbx", "cxsi", "cxdi", "bxsi", "bxdi", "sidi", "st0", "st1", "st2", "st3", "st4", "st5", "st6", "st7", }; /* * Return a class suitable for a specific type. */ int gclass(TWORD t) { if (t == CHAR || t == UCHAR) return CLASSB; if (t == LONGLONG || t == ULONGLONG || t == LONG || t == ULONG) return CLASSC; if (t == FLOAT || t == DOUBLE || t == LDOUBLE) return CLASSD; return CLASSA; } /* * Calculate argument sizes. */ void lastcall(NODE *p) { NODE *op = p; int size = 0; p->n_qual = 0; if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) return; for (p = p->n_right; p->n_op == CM; p = p->n_left) { if (p->n_right->n_op != ASSIGN) size += argsiz(p->n_right); } if (p->n_op != ASSIGN) size += argsiz(p); op->n_qual = size; /* XXX */ } /* * Special shapes. */ int special(NODE *p, int shape) { int o = p->n_op; switch (shape) { case SFUNCALL: if (o == STCALL || o == USTCALL) return SRREG; break; case SPCON: if (o != ICON || p->n_name[0] || getlval(p) < 0 || getlval(p) > 0x7fffffff) break; return SRDIR; case SMIXOR: return tshape(p, SZERO); case SMILWXOR: if (o != ICON || p->n_name[0] || getlval(p) == 0 || getlval(p) & 0xffffffff) break; return SRDIR; case SMIHWXOR: if (o != ICON || p->n_name[0] || getlval(p) == 0 || (getlval(p) >> 32) != 0) break; return SRDIR; case STWO: if (o == ICON && p->n_name[0] == 0 && getlval(p) == 2) return SRDIR; break; case SMTWO: if (o == ICON && p->n_name[0] == 0 && getlval(p) == -2) return SRDIR; break; } return SRNOPE; } /* * Target-dependent command-line options. */ void mflags(char *str) { } /* * Do something target-dependent for xasm arguments. */ int myxasm(struct interpass *ip, NODE *p) { struct interpass *ip2; int Cmax[] = { 31, 63, 127, 0xffff, 3, 255 }; NODE *in = 0, *ut = 0; TWORD t; char *w; int reg; int c, cw; CONSZ v; cw = xasmcode(p->n_name); if (cw & (XASMASG|XASMINOUT)) ut = p->n_left; if ((cw & XASMASG) == 0) in = p->n_left; c = XASMVAL(cw); switch (c) { case 'D': reg = DI; break; case 'S': reg = SI; break; case 'a': reg = AX; break; case 'b': reg = BX; break; case 'c': reg = CX; break; case 'd': reg = DX; break; case 't': case 'u': p->n_name = tmpstrdup(p->n_name); w = strchr(p->n_name, XASMVAL(cw)); *w = 'r'; /* now reg */ return 1; case 'A': reg = AXDX; break; case 'q': { /* Set edges in MYSETXARG */ if (p->n_left->n_op == REG || p->n_left->n_op == TEMP) return 1; t = p->n_left->n_type; if (in && ut) in = tcopy(in); p->n_left = mklnode(TEMP, 0, p2env.epp->ip_tmpnum++, t); if (ut) { ip2 = ipnode(mkbinode(ASSIGN, ut, tcopy(p->n_left), t)); DLIST_INSERT_AFTER(ip, ip2, qelem); } if (in) { ip2 = ipnode(mkbinode(ASSIGN, tcopy(p->n_left), in, t)); DLIST_INSERT_BEFORE(ip, ip2, qelem); } return 1; } case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': if (p->n_left->n_op != ICON) { if ((c = XASMVAL1(cw)) != 0) { p->n_name++; return 0; /* Try again */ } uerror("xasm arg not constant"); } v = getlval(p->n_left); if ((c == 'K' && v < -128) || (c == 'L' && v != 0xff && v != 0xffff) || (c != 'K' && v < 0) || (v > Cmax[c-'I'])) uerror("xasm val out of range"); p->n_name = "i"; return 1; default: return 0; } /* If there are requested either memory or register, delete memory */ w = p->n_name = tmpstrdup(p->n_name); if (*w == '=') w++; *w++ = 'r'; *w = 0; t = p->n_left->n_type; if (reg == AXDX) { ; } else { if (t == CHAR || t == UCHAR) { reg = reg * 2 + 8; } } if (t == FLOAT || t == DOUBLE || t == LDOUBLE) { reg += 037; } if (in && ut) in = tcopy(in); p->n_left = mklnode(REG, 0, reg, t); if (ut) { ip2 = ipnode(mkbinode(ASSIGN, ut, tcopy(p->n_left), t)); DLIST_INSERT_AFTER(ip, ip2, qelem); } if (in) { ip2 = ipnode(mkbinode(ASSIGN, tcopy(p->n_left), in, t)); DLIST_INSERT_BEFORE(ip, ip2, qelem); } return 1; } void targarg(char *w, void *arg) { NODE **ary = arg; NODE *p, *q; if (ary[(int)w[1]-'0'] == 0) p = ary[(int)w[1]-'0'-1]->n_left; /* XXX */ else p = ary[(int)w[1]-'0']->n_left; if (optype(p->n_op) != LTYPE) comperr("bad xarg op %d", p->n_op); q = tcopy(p); if (q->n_op == REG) { if (*w == 'k') { q->n_type = INT; } else if (*w != 'w') { if (q->n_type > UCHAR) { regno(q) = regno(q)*2+8; if (*w == 'h') regno(q)++; } q->n_type = INT; } else q->n_type = SHORT; } adrput(stdout, q); tfree(q); } /* * target-specific conversion of numeric arguments. */ int numconv(void *ip, void *p1, void *q1) { NODE *p = p1, *q = q1; int cw = xasmcode(q->n_name); switch (XASMVAL(cw)) { case 'a': case 'b': case 'c': case 'd': p->n_name = tmpcalloc(2); p->n_name[0] = (char)XASMVAL(cw); return 1; default: return 0; } } static struct { char *name; int num; } xcr[] = { { "ax", AX }, { "bx", BX }, { "cx", CX }, { "dx", DX }, { "si", SI }, { "di", DI }, { NULL, 0 }, }; /* * Check for other names of the xasm constraints registers. */ /* * Check for other names of the xasm constraints registers. */ int xasmconstregs(char *s) { int i; if (strncmp(s, "st", 2) == 0) { int off =0; if (s[2] == '(' && s[4] == ')') off = s[3] - '0'; return SIDI + 1 + off; } for (i = 0; xcr[i].name; i++) if (strcmp(xcr[i].name, s) == 0) return xcr[i].num; return -1; } pcc-20181216/arch/i86/macdefs.h010064400017500000000000000251301337260706400145730ustar raggewheel/* $Id: macdefs.h,v 1.8 2018/11/13 17:47:32 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Machine-dependent defines for both passes. */ /* * Convert (multi-)character constant to integer. */ #define makecc(val,i) lastcon = (lastcon<<8)|((val<<24)>>24); #define ARGINIT 64 /* # bits above fp where arguments start */ #define AUTOINIT 0 /* # bits below fp where automatics start */ /* * Storage space requirements */ #define SZCHAR 8 #define SZBOOL 8 #define SZINT 16 #define SZFLOAT 32 #define SZDOUBLE 64 #define SZLDOUBLE 96 #define SZLONG 32 #define SZSHORT 16 #define SZLONGLONG 64 /* Doesn't work usefully yet */ #define SZPOINT(t) 16 /* FIXME: 32 for large model work */ /* * Alignment constraints */ #define ALCHAR 8 #define ALBOOL 8 #define ALINT 16 #define ALFLOAT 32 #define ALDOUBLE 32 #define ALLDOUBLE 32 #define ALLONG 16 #define ALLONGLONG 16 #define ALSHORT 16 #define ALPOINT 16 #undef ALSTRUCT /* Not defined if ELF ABI */ #define ALSTACK 16 #define ALMAX 128 /* not yet supported type */ /* * Min/max values. */ #define MIN_CHAR -128 #define MAX_CHAR 127 #define MAX_UCHAR 255 #define MIN_SHORT -32768 #define MAX_SHORT 32767 #define MAX_USHORT 65535 #define MIN_INT MIN_SHORT #define MAX_INT MAX_SHORT #define MAX_UNSIGNED MAX_USHORT #define MIN_LONG (-0x7fffffff-1) #define MAX_LONG 0x7fffffff #define MAX_ULONG 0xffffffff #define MIN_LONGLONG MIN_LONG #define MAX_LONGLONG MAX_LONG #define MAX_ULONGLONG MAX_ULONG /* Default char is signed */ #undef CHAR_UNSIGNED #define BOOL_TYPE UCHAR /* what used to store _Bool */ #undef UNALIGNED_ACCESS /* * Use large-enough types. */ typedef long long CONSZ; typedef unsigned long long U_CONSZ; typedef long long OFFSZ; #define CONFMT "%lld" /* format for printing constants */ #define LABFMT "L%d" /* format for printing labels */ #define STABLBL "LL%d" /* format for stab (debugging) labels */ #ifdef LANG_F77 #define BLANKCOMMON "_BLNK_" #define MSKIREG (M(TYSHORT)|M(TYLONG)) #define TYIREG TYLONG #define FSZLENG FSZLONG #define AUTOREG BP #define ARGREG BP #define ARGOFFSET 4 #endif #define BACKAUTO /* stack grows negatively for automatics */ #define BACKTEMP /* stack grows negatively for temporaries */ #undef FIELDOPS /* no bit-field instructions */ #define TARGET_ENDIAN TARGET_LE #define FINDMOPS /* i86 has instructions that modifies memory */ #define CC_DIV_0 /* division by zero is safe in the compiler */ /* Definitions mostly used in pass2 */ #define BYTEOFF(x) ((x)&03) #define wdal(k) (BYTEOFF(k)==0) #define STOARG(p) #define STOFARG(p) #define STOSTARG(p) #define genfcall(a,b) gencall(a,b) /* FIXME: float sizes wrong at this point ? */ #define szty(t) (((t) == DOUBLE || (t) == FLOAT || \ (t) == LONG || t == ULONG || (t) == LONGLONG || (t) == ULONGLONG) ? 2 : (t) == LDOUBLE ? 3 : 1) /* * The x86 has a bunch of register classes, most of them interfering * with each other. All registers are given a sequential number to * identify it which must match rnames[] in local2.c. * Class membership and overlaps are defined in the macros RSTATUS * and ROVERLAP below. * * The classes used on x86 are: * A - short and int regs * B - char regs * C - long and longlong regs * D - floating point */ #define AX 000 /* Scratch and return register */ #define DX 001 /* Scratch and secondary return register */ #define CX 002 /* Scratch (and shift count) register */ #define BX 003 /* GDT pointer or callee-saved temporary register */ #define SI 004 /* Callee-saved temporary register */ #define DI 005 /* Callee-saved temporary register */ #define BP 006 /* Frame pointer */ #define SP 007 /* Stack pointer */ #define AL 010 #define AH 011 #define DL 012 #define DH 013 #define CL 014 #define CH 015 #define BL 016 #define BH 017 #define AXDX 020 #define AXCX 021 #define AXBX 022 #define AXSI 023 #define AXDI 024 #define DXCX 025 #define DXBX 026 #define DXSI 027 #define DXDI 030 #define CXBX 031 #define CXSI 032 #define CXDI 033 #define BXSI 034 #define BXDI 035 #define SIDI 036 /* The 8 math registers in class D lacks names */ #define MAXREGS 047 /* 39 registers */ #define RSTATUS \ SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|PERMREG, \ SAREG|PERMREG, SAREG|PERMREG, 0, 0, \ SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \ SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \ SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \ SDREG, SDREG, SDREG, SDREG, SDREG, SDREG, SDREG, SDREG, #define ROVERLAP \ /* 8 basic registers */\ { AL, AH, AXDX, AXCX, AXBX, AXSI, AXDI, -1 },\ { DL, DH, AXDX, DXCX, DXBX, DXSI, DXDI, -1 },\ { CL, CH, AXCX, DXCX, CXBX, CXSI, CXDI, -1 },\ { BL, BH, AXBX, DXBX, CXBX, BXSI, BXDI, -1 },\ { AXSI, DXSI, CXSI, BXSI, SIDI, -1 },\ { AXDI, DXDI, CXDI, BXDI, SIDI, -1 },\ { -1 },\ { -1 },\ \ /* 8 char registers */\ { AX, AXDX, AXCX, AXBX, AXSI, AXDI, -1 },\ { AX, AXDX, AXCX, AXBX, AXSI, AXDI, -1 },\ { DX, AXDX, DXCX, DXBX, DXSI, DXDI, -1 },\ { DX, AXDX, DXCX, DXBX, DXSI, DXDI, -1 },\ { CX, AXCX, DXCX, CXBX, CXSI, CXDI, -1 },\ { CX, AXCX, DXCX, CXBX, CXSI, CXDI, -1 },\ { BX, AXBX, DXBX, CXBX, BXSI, BXDI, -1 },\ { BX, AXBX, DXBX, CXBX, BXSI, BXDI, -1 },\ \ /* 15 long emulating registers */\ { AX, AL, AH, DX, DL, DH, AXCX, AXBX, AXSI, /* axdx */\ AXDI, DXCX, DXBX, DXSI, DXDI, -1, },\ { AX, AL, AH, CX, CL, CH, AXDX, AXBX, AXSI, /* axcx */\ AXDI, DXCX, CXBX, CXSI, CXDI, -1 },\ { AX, AL, AH, BX, BL, BH, AXDX, AXCX, AXSI, /* axbx */\ AXDI, DXBX, CXBX, BXSI, BXDI, -1 },\ { AX, AL, AH, SI, AXDX, AXCX, AXBX, AXDI, /* axsi */\ DXSI, CXSI, BXSI, SIDI, -1 },\ { AX, AL, AH, DI, AXDX, AXCX, AXBX, AXSI, /* axdi */\ DXDI, CXDI, BXDI, SIDI, -1 },\ { DX, DL, DH, CX, CL, CH, AXDX, AXCX, DXBX, /* dxcx */\ DXSI, DXDI, CXBX, CXSI, CXDI, -1 },\ { DX, DL, DH, BX, BL, BH, AXDX, DXCX, DXSI, /* dxbx */\ DXDI, AXBX, CXBX, BXSI, BXDI, -1 },\ { DX, DL, DH, SI, AXDX, DXCX, DXBX, DXDI, /* dxsi */\ AXSI, CXSI, BXSI, SIDI, -1 },\ { DX, DL, DH, DI, AXDX, DXCX, DXBX, DXSI, /* dxdi */\ AXDI, CXDI, BXDI, SIDI, -1 },\ { CX, CL, CH, BX, BL, BH, AXCX, DXCX, CXSI, /* cxbx */\ CXDI, AXBX, DXBX, BXSI, BXDI, -1 },\ { CX, CL, CH, SI, AXCX, DXCX, CXBX, CXDI, /* cxsi */\ AXSI, DXSI, BXSI, SIDI, -1 },\ { CX, CL, CH, DI, AXCX, DXCX, CXBX, CXSI, /* cxdi */\ AXDI, DXDI, BXDI, SIDI, -1 },\ { BX, BL, BH, SI, AXBX, DXBX, CXBX, BXDI, /* bxsi */\ AXSI, DXSI, CXSI, SIDI, -1 },\ { BX, BL, BH, DI, AXBX, DXBX, CXBX, BXSI, /* bxdi */\ AXDI, DXDI, CXDI, SIDI, -1 },\ { SI, DI, AXSI, DXSI, CXSI, BXSI, /* sidi */\ AXDI, DXDI, CXDI, BXDI, -1 },\ \ /* The fp registers do not overlap with anything */\ { -1 },\ { -1 },\ { -1 },\ { -1 },\ { -1 },\ { -1 },\ { -1 },\ { -1 }, /* Return a register class based on the type of the node */ /* FIXME: <= UCHAR includes long ?? check */ #define PCLASS(p) (p->n_type <= UCHAR ? SBREG : \ (p->n_type == LONG || p->n_type == ULONG || p->n_type == LONGLONG || p->n_type == ULONGLONG ? SCREG : \ (p->n_type >= FLOAT && p->n_type <= LDOUBLE ? SDREG : SAREG))) #define NUMCLASS 4 /* highest number of reg classes used */ int COLORMAP(int c, int *r); #define GCLASS(x) (x < 8 ? CLASSA : x < 16 ? CLASSB : x < 31 ? CLASSC : CLASSD) #define DECRA(x,y) (((x) >> (y*6)) & 63) /* decode encoded regs */ #define ENCRD(x) (x) /* Encode dest reg in n_reg */ #define ENCRA1(x) ((x) << 6) /* A1 */ #define ENCRA2(x) ((x) << 12) /* A2 */ #define ENCRA(x,y) ((x) << (6+y*6)) /* encode regs in int */ /* XXX - return char in al? */ #define RETREG(x) (x == CHAR || x == UCHAR ? AL : \ x == LONG || x == ULONG || x == LONGLONG || x == ULONGLONG ? AXDX : \ x == FLOAT || x == DOUBLE || x == LDOUBLE ? 31 : AX) #if 0 #define R2REGS 1 /* permit double indexing */ #endif /* XXX - to die */ #define FPREG BP /* frame pointer */ #define STKREG SP /* stack pointer */ #define SHSTR (MAXSPECIAL+1) /* short struct */ #define SFUNCALL (MAXSPECIAL+2) /* struct assign after function call */ #define SPCON (MAXSPECIAL+3) /* positive nonnamed constant */ /* * Specials that indicate the applicability of machine idioms. */ #define SMIXOR (MAXSPECIAL+4) #define SMILWXOR (MAXSPECIAL+5) #define SMIHWXOR (MAXSPECIAL+6) #define STWO (MAXSPECIAL+7) /* exactly two */ #define SMTWO (MAXSPECIAL+8) /* exactly minus two */ /* * i86-specific symbol table flags. */ #define SSECTION SLOCAL1 #define SSTDCALL SLOCAL2 #define SDLLINDIRECT SLOCAL3 /* * i86-specific interpass stuff. */ #define TARGET_IPP_MEMBERS \ int ipp_argstacksize; #define HAVE_WEAKREF #define TARGET_FLT_EVAL_METHOD 2 /* all as long double */ /* * Extended assembler macros. */ void targarg(char *w, void *arg); #define XASM_TARGARG(w, ary) \ (w[1] == 'b' || w[1] == 'h' || w[1] == 'w' || w[1] == 'k' ? \ w++, targarg(w, ary), 1 : 0) int numconv(void *ip, void *p, void *q); #define XASM_NUMCONV(ip, p, q) numconv(ip, p, q) int xasmconstregs(char *); #define XASMCONSTREGS(x) xasmconstregs(x) #define MYSETXARG if (XASMVAL(cw) == 'q') { \ c = 'r'; addalledges(&ablock[SI]); addalledges(&ablock[DI]); } /* target specific attributes */ #define ATTR_MI_TARGET ATTR_I86_FPPOP /* floating point definitions */ #define USE_IEEEFP_32 #define FLT_PREFIX IEEEFP_32 #define USE_IEEEFP_64 #define DBL_PREFIX IEEEFP_64 #define USE_IEEEFP_X80 #define LDBL_PREFIX IEEEFP_X80 pcc-20181216/arch/i86/order.c010064400017500000000000000176421337260706400143100ustar raggewheel/* $Id: order.c,v 1.4 2018/11/13 17:47:32 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass2.h" #include int canaddr(NODE *); /* is it legal to make an OREG or NAME entry which has an * offset of off, (from a register of r), if the * resulting thing had type t */ int notoff(TWORD t, int r, CONSZ off, char *cp) { return(0); /* YES */ } /* * Turn a UMUL-referenced node into OREG. * Be careful about register classes, this is a place where classes change. */ void offstar(NODE *p, int shape) { NODE *r; if (x2debug) printf("offstar(%p)\n", p); if (isreg(p)) return; /* Is already OREG */ r = p->n_right; if( p->n_op == PLUS || p->n_op == MINUS ){ if( r->n_op == ICON ){ if (isreg(p->n_left) == 0) (void)geninsn(p->n_left, INAREG); /* Converted in ormake() */ return; } if (r->n_op == LS && r->n_right->n_op == ICON && getlval(r->n_right) == 2 && p->n_op == PLUS) { if (isreg(p->n_left) == 0) (void)geninsn(p->n_left, INAREG); if (isreg(r->n_left) == 0) (void)geninsn(r->n_left, INAREG); return; } } (void)geninsn(p, INAREG); } /* * Do the actual conversion of offstar-found OREGs into real OREGs. */ void myormake(NODE *q) { NODE *p, *r; if (x2debug) printf("myormake(%p)\n", q); p = q->n_left; if (p->n_op == PLUS && (r = p->n_right)->n_op == LS && r->n_right->n_op == ICON && getlval(r->n_right) == 2 && p->n_left->n_op == REG && r->n_left->n_op == REG) { q->n_op = OREG; setlval(q, 0); q->n_rval = R2PACK(p->n_left->n_rval, r->n_left->n_rval, 0); tfree(p); } } /* * Shape matches for UMUL. Cooperates with offstar(). */ int shumul(NODE *p, int shape) { if (x2debug) printf("shumul(%p)\n", p); /* Turns currently anything into OREG on x86 */ if (shape & SOREG) return SROREG; return SRNOPE; } /* * Rewrite operations on binary operators (like +, -, etc...). * Called as a result of table lookup. */ int setbin(NODE *p) { if (x2debug) printf("setbin(%p)\n", p); return 0; } /* setup for assignment operator */ int setasg(NODE *p, int cookie) { if (x2debug) printf("setasg(%p)\n", p); return(0); } /* setup for unary operator */ int setuni(NODE *p, int cookie) { return 0; } /* * Special handling of some instruction register allocation. * * FIXME: review 32bit specials, a lot can go as we use helpers */ struct rspecial * nspecial(struct optab *q) { switch (q->op) { case OPLOG: { static struct rspecial s[] = { { NEVER, AX }, { 0 } }; return s; } case STASG: { static struct rspecial s[] = { { NEVER, DI }, { NRIGHT, SI }, { NOLEFT, SI }, { NOLEFT, CX }, { NORIGHT, CX }, { NEVER, CX }, { 0 } }; return s; } case STARG: { static struct rspecial s[] = { { NEVER, DI }, { NEVER, CX }, { NLEFT, SI }, { 0 } }; return s; } case SCONV: /* Force signed conversions into al/ax to use cbw */ if ((q->ltype & TCHAR) && q->rtype == (TINT|TUNSIGNED)) { static struct rspecial s[] = { { NLEFT, AL }, { NRES, AX }, { NEVER, AX }, { NEVER, AH}, {NEVER, AL }, { 0 } }; return s; } /* FIXME: do we need this rule with and based moves ? */ /* Force signed unconversions to avoid si and di */ if ((q->ltype & TUCHAR) && q->rtype == (TINT|TUNSIGNED)) { static struct rspecial s[] = { { NEVER, SI }, { NEVER, DI }, { 0 } }; return s; } else if ((q->ltype & (TINT|TUNSIGNED)) && q->rtype == (TCHAR|TUCHAR)) { static struct rspecial s[] = { { NOLEFT, SI }, { NOLEFT, DI }, { 0 } }; return s; /* Need to be able to use cwd */ } else if ((q->ltype & (TINT|TSHORT)) && q->rtype == (TLONG|TULONG)) { static struct rspecial s[] = { { NLEFT, AX }, { NRES, AXDX }, { NEVER, AX }, { NEVER, DX }, { 0 } }; return s; /* Need to be use cbw cwd */ } else if (q->ltype == TCHAR && q->rtype == (TLONG|TULONG)) { static struct rspecial s[] = { { NRES, AXDX }, { NLEFT, AL }, { NEVER, AX }, { NEVER, DX }, { NEVER, AH }, { NEVER, AL }, { 0 } }; return s; } break; case DIV: if (q->lshape == SBREG) { static struct rspecial s[] = { { NEVER, AL }, { NEVER, AH }, { NLEFT, AL }, { NRES, AL }, { NORIGHT, AH }, { NORIGHT, AL }, { 0 } }; return s; } else if (q->lshape == SAREG) { static struct rspecial s[] = { { NEVER, AX }, { NEVER, DX }, { NLEFT, AX }, { NRES, AX }, { NORIGHT, DX }, { NORIGHT, AX }, { 0 } }; return s; } /* using helpers */ else if (q->lshape & SCREG) { static struct rspecial s[] = { { NEVER, AX }, { NEVER, DX }, { NEVER, CX }, { NRES, AXDX }, { 0 } }; return s; } break; case MOD: if (q->lshape == SBREG) { static struct rspecial s[] = { { NEVER, AL }, { NEVER, AH }, { NLEFT, AL }, { NRES, AH }, { NORIGHT, AH }, { NORIGHT, AL }, { 0 } }; return s; } else if (q->lshape == SAREG) { static struct rspecial s[] = { { NEVER, AX }, { NEVER, DX }, { NLEFT, AX }, { NRES, DX }, { NORIGHT, DX }, { NORIGHT, AX }, { 0 } }; return s; } else if (q->lshape & SCREG) { static struct rspecial s[] = { { NEVER, AX }, { NEVER, DX }, { NEVER, CX }, { NRES, AXDX }, { 0 } }; return s; } break; case MUL: if (q->lshape == SAREG) { static struct rspecial s[] = { { NEVER, AX }, { NEVER, DX }, { NLEFT, AX }, { NRES, AX }, { NORIGHT, DX }, {NORIGHT, AX }, { 0 } }; return s; } if (q->lshape == SBREG) { static struct rspecial s[] = { { NEVER, AL }, { NEVER, AH }, { NLEFT, AL }, { NRES, AL }, { 0 } }; return s; } else if (q->lshape & SCREG) { static struct rspecial s[] = { { NEVER, AX }, { NEVER, DX }, { NEVER, CX }, { NRES, AXDX }, { 0 } }; return s; } break; case LS: case RS: if (q->visit & (INAREG|INBREG)) { static struct rspecial s[] = { { NRIGHT, CL }, { NOLEFT, CX }, { 0 } }; return s; } else if (q->visit & INCREG) { static struct rspecial s[] = { { NLEFT, AXDX }, { NRIGHT, CL }, { NRES, AXDX }, { 0 } }; return s; } break; default: break; } comperr("nspecial entry %d", q - table); return 0; /* XXX gcc */ } /* * Set evaluation order of a binary node if it differs from default. */ int setorder(NODE *p) { return 0; /* nothing differs on x86 */ } /* * set registers in calling conventions live. */ int * livecall(NODE *p) { static int r[] = { AX, BX, -1 }; int off = 1; return kflag ? &r[off] : &r[2]; } /* * Signal whether the instruction is acceptable for this target. */ int acceptable(struct optab *op) { return 1; } pcc-20181216/arch/i86/table.c010064400017500000000000001014231244762103300142450ustar raggewheel/* $Id: table.c,v 1.5 2014/12/27 21:18:19 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * Copyright (c) 2014 Alan Cox (alan@lxorguk.ukuu.org.uk). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass2.h" /* * TODO * - clean up TLL usage so we are ready for 64bit longlong (T32 and T64?) * - Clean up all the SHINT SHCH etc oddities for clarity * - Better optimisation of constant multiply/divide etc on 8086 * - some how lose the final bogus sp adjust we generate * - write helper lib for long and longlong ops * - add an E class and virtual 4 register longlong model * - bcc fastcall format * * - How to do configurable code-gen * For 80186 we want to use the better shifts, push constant, mul/div * features and enter/leave * For 80286 it's not clear we need to do anything for real mode. However * for large data/huge models protected mode means minimising ds/es * reloads with the same data * With 80386 there is lots more - but who wants 80386/16bit optimised * code ! * * - FPU has not been tackled. FPU/FPU should be fine (barring the odd * gnu style instruction forms), but FPU/other is quite different * because the 4 byte conversions are now long not int and two register * while 8 byte longlong ones are going to need some gymnastics once * we support the virtual 64bit registers * * - FPU/noFPU option. Assuming FPU present on 8086 is a bit obnoxious * as a default. Need to be able to generate entirely soft-float calls. * * - We can't currently do various conversions we'd like to have, notably * things like "and ax, $ff" to convert AL into AX from uchar to uint * (that needs core changes and also allocator changes to try and avoid * high bits being occupied by other users) * * - Shifts should be optimised for 8/16/24/32 cases * * - No attempt is made to deal with larger models than tiny * * small mode should work (just keep constant data in data segments) * * large code/small data should be fine-ish. Really that implies 32bit * void * but for most uses you want 32bit only to be function pointers * even if its not to spec. Function entry/exit needs to allow for the * extra 2 bytes, call becomes call far, call ptr becomes a bit trickier * but not a lot. Not that ld86 can link large model yet! * * large data is much harder because an address is 32bit, half of which * needs to keep getting stuck into a segment register. However we often * (usually) work with multiple pointers to the same object. Any given * object has a single segment so we will badly need optimisations to * "share" segment data and avoid lots of duplicate register uses and * mov es, foo statements. * * huge model makes all pointers 32bit and all objects 32bit sized. That * probably makes the sharing es issue go away somewhat, but raises the * ugly problems of pointer normalisation (00:10 is the same as 01:00 * which b*ggers up comparisons royally) and also protected mode where * your segment jump as you go over 64K boundaries is different. On the * bright side huge model performance will suck whatever the compiler * does. * */ /* 64bit values */ # define T64 TLONGLONG|TULONGLONG /* 32bit values */ # define T32 TLONG|TULONG /* 16bit values */ # define T16 TINT|TUNSIGNED /* 16bit values including pointers */ # define TP16 TINT|TUNSIGNED|TPOINT /* 8bit values */ # define T8 TCHAR|TUCHAR #define SHINT SAREG /* short and int */ #define ININT INAREG #define SHCH SBREG /* shape for char */ #define INCH INBREG #define SHLL SCREG /* shape for long long FIXME */ #define INLL INCREG #define SHL SCREG /* shape for long*/ #define INL INCREG #define SHFL SDREG /* shape for float/double */ #define INFL INDREG /* shape for float/double */ struct optab table[] = { /* First entry must be an empty entry */ { -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", }, /* PCONVs are usually not necessary */ { PCONV, INAREG, SAREG, T16|TPOINT, SAREG, T16|TPOINT, 0, RLEFT, "", }, /* * A bunch conversions of integral<->integral types * There are lots of them, first in table conversions to itself * and then conversions from each type to the others. */ /* itself to itself, including pointers */ /* convert (u)char to (u)char. */ { SCONV, INCH, SHCH, T8, SHCH, T8, 0, RLEFT, "", }, /* convert pointers to int. */ { SCONV, ININT, SHINT, TPOINT|T16, SANY, T16, 0, RLEFT, "", }, /* convert (u)long to (u)long. */ { SCONV, INL, SHL, T32, SHL, T32, 0, RLEFT, "", }, /* convert (u)long and (u)longlong to (u)longlong. */ { SCONV, INLL, SHLL, T64, SHLL, T64, 0, RLEFT, "", }, /* convert between float/double/long double. */ { SCONV, INFL, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, 0, RLEFT, "ZI", }, /* convert pointers to pointers. */ { SCONV, ININT, SHINT, TPOINT, SANY, TPOINT, 0, RLEFT, "", }, /* char to something */ /* convert char to 16bit types. */ /* 8086: Only as op on AL,AX */ { SCONV, ININT, SBREG, TCHAR, SAREG, T16, NSPECIAL|NAREG|NASL, RESC1, " cbw\n", }, /* convert unsigned char to 16bit types. We can do this one with any register */ { SCONV, ININT, SHCH|SOREG|SNAME, TUCHAR, SAREG, T16, NSPECIAL|NAREG, RESC1, "ZT", }, /* convert char to (u)long 8086 can only do cbw/cwd on AX and AX:DX pair */ { SCONV, INL, SHCH, TCHAR, SCREG, T32, NSPECIAL|NCREG|NCSL, RESC1, "; using AL\n cbw\n cwd\n", }, /* convert unsigned char to (u)long we can do this with any register */ { SCONV, INL, SHCH|SOREG|SNAME, TUCHAR, SANY, T32, NCREG|NCSL, RESC1, "ZT xor U1,U1\n", }, /* convert char (in register) to double XXX - use NTEMP */ /* FIXME : need NSPECIAL to force into AL check AX:DX right way around ! */ { SCONV, INFL, SHCH|SOREG|SNAME, TCHAR, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, NAREG|NASL|NDREG, RESC2, " cbw\n cwd\n push ax\n push dx\n" " fildl [sp]\n add sp, #4\n", }, /* convert (u)char (in register) to double XXX - use NTEMP */ /* FIXME : needs to use ZT to get sizes right, need a register from somewhere to put 0 on the stack for the high bits */ { SCONV, INFL, SHCH|SOREG|SNAME, TUCHAR, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, NAREG|NASL|NDREG, RESC2, " mov A1 AL\n and A1, #0xff\n push A1\npush #0\n" " fildl [sp]\n add sp,#4\n", }, /* 16bit to something */ /* convert 16bit to 16bit. */ { SCONV, INAREG, SAREG, T16, SAREG, T16, 0, RLEFT, "", }, /* convert 16bit (in memory) to char */ /* NOTE: uses new 'ZP' type for 'untyped right' */ { SCONV, INCH, SNAME|SOREG, TP16, SHCH, T8, NBREG|NBSL, RESC1, " mov A1,ZP AL\n", }, /* convert 16bit (in reg) to char. Done as a special but basically a mov */ { SCONV, INCH, SAREG|SNAME|SOREG, TP16, SHCH, T8, NSPECIAL|NBREG|NBSL, RESC1, "ZM", }, /* convert short/int to (u)long This must go via AX so we can use cwd */ { SCONV, INL, SAREG, TINT, SHL, T32, NSPECIAL|NCREG|NCSL, RESC1, " mov A1, AL\n cwd\n", }, /* convert unsigned short/int to (u)long Any pair will do. Note currently the compiler can't optimise out the reg->reg move involved */ { SCONV, INLL, SAREG|SOREG|SNAME, TUNSIGNED|TPOINT, SHL, T32, NCREG|NCSL, RESC1, " mov A1,AL\n xor U1,U1\n", }, /* convert short/int (in memory) to float/double */ { SCONV, INFL, SOREG|SNAME, TINT, SDREG, TLDOUBLE|TDOUBLE|TFLOAT, NDREG, RESC1, " fild AL\n", }, /* convert short/int (in register) to float/double */ { SCONV, INFL, SAREG, TINT, SDREG, TLDOUBLE|TDOUBLE|TFLOAT, NTEMP|NDREG, RESC1, " push AL\n fild [sp]\n" " inc sp\n inc sp\n", }, /* convert unsigned short/int/ptr to double XXX - use NTEMP */ /* FIXME: need to force this via AX so we can cwd, fix stack setup to push both ax.dx*/ { SCONV, INFL, SAREG|SOREG|SNAME, TUNSIGNED|TPOINT, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, NAREG|NASL|NDREG|NTEMP, RESC2, " cwd\n push ax\n" " fild [sp]\n inc sp\n" " inc sp\n", }, /* long to something */ /* convert (u)long to (u)char (mem->reg) */ { SCONV, INCH, SOREG|SNAME, T32, SANY, T8, NBREG|NBSL, RESC1, " mov A1, AL\n", }, /* convert (u)long to (u)char (reg->reg, hopefully nothing) */ { SCONV, INCH, SHL, T32, SANY, T8, NBREG|NBSL|NTEMP, RESC1, "ZS", }, /* convert (u)long to (u)short (mem->reg) */ { SCONV, INAREG, SOREG|SNAME, T32, SAREG, TP16, NAREG|NASL, RESC1, " mov A1,AL\n", }, /* convert (u)long to 16bit (reg->reg, hopefully nothing) */ { SCONV, INAREG, SHL|SOREG|SNAME, T32, SAREG, T16, NAREG|NASL|NTEMP, RESC1, "ZS", }, /* FIXME: float stuff is all TODO */ /* convert long long (in memory) to floating */ { SCONV, INFL, SOREG|SNAME, TLONGLONG, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, NDREG, RESC1, " fild AL\n", }, /* convert long (in register) to floating */ { SCONV, INFL, SHL, TLONGLONG, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, NTEMP|NDREG, RESC1, " push UL\n push AL\n" " fild [sp]\n add sp, #8\n", }, /* convert unsigned long to floating */ { SCONV, INFL, SCREG, TULONGLONG, SDREG, TLDOUBLE|TDOUBLE|TFLOAT, NDREG, RESC1, "ZJ", }, /* float to something */ #if 0 /* go via int by adding an extra sconv in clocal() */ /* convert float/double to (u) char. XXX should use NTEMP here */ { SCONV, INCH, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, SHCH, T16|T8, NBREG, RESC1, " sub sp,#4\n fistpl [sp]\n pop A1\n pop U1\n", }, /* convert float/double to (u) int/short/char. XXX should use NTEMP here */ { SCONV, INCH, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, SHCH, T16|T8, NCREG, RESC1, " sub sp,#4\n fistpl (%sp)\n pop A1\n inc sp\n inc sp\n", }, #endif /* convert float/double to long XXX should use NTEMP here */ { SCONV, INAREG, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, SAREG, TLONG, NAREG, RESC1, " sub sp, #12\n" " fstcw sp\n" " fstcw 4[sp]\n" " mov byte ptr 1[sp], #12\n" " fldcw sp\n" " fistp 8[sp]\n" " movl A1, 8(p)\n" " fldcw 4[sp]\n" " add sp, #4\n", }, /* convert float/double to unsigned long. XXX should use NTEMP here */ { SCONV, INAREG, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, SAREG, TULONG, NAREG, RESC1, " sub sp, #16\n" " fnstcw [sp]\n" " fnstcw 4[sp]\n" " mov byte ptr 1[sp], #12\n" " fldcw [sp[\n" " fistpq 8[sp]\n" " mov word ptr 8[sp],A1\n" " mov word ptr 10[sp],U1\n" " fldcw 4[sp]\n" " add sp, #16\n", }, /* convert float/double (in register) to long long */ { SCONV, INLL, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, SHLL, TLONGLONG, NCREG, RESC1, " sub sp, #16\n" " fnstcw [sp]\n" " fnstcw [sp]\n" " mov byte ptr 1[sp], #12\n" " fldcw [sp]\n" " fistpq 8[sp]\n" " movl 8[sp],A1\n" " movl 10[sp],U1\n" /* need to put 12/14 somewhere FIXME */ " fldcw 4[sp]\n" " add sp, #16\n", }, /* convert float/double (in register) to unsigned long long */ { SCONV, INLL, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, SHLL, TULONGLONG, NCREG, RESC1, " sub sp, #16\n" " fnstcw [sp]\n" " fnstcw 4[sp]\n" " mov byte ptr 1[sp], #15\n" /* 64-bit prec */ " fldcw [sp]\n" " movl $0x5f000000, 8(%sp)\n" /* (float)(1<<63) */ " fsubs 8[sp]\n" /* keep in range of fistpq */ " fistpq 8[sp]\n" " xor byte ptr 15[sp], #0x80\n" /* addq $1>>63 to 8(%sp) */ " movl A1, 8[sp]\n" " movl U1, 10[sp]\n" " fldcw 4[sp]\n" " add sp, #16\n", }, /* slut sconv */ /* * Subroutine calls. */ { UCALL, FOREFF, SCON, TANY, SANY, TANY, 0, 0, " call CL\nZC", }, { CALL, FOREFF, SCON, TANY, SANY, TANY, 0, 0, " call CL\nZC", }, //{ UCALL, FOREFF, // SCON, TANY, // SAREG, TP16, // 0, 0, // " call CL\nZC", }, { CALL, INAREG, SCON, TANY, SAREG, TP16, NAREG|NASL, RESC1, /* should be 0 */ " call CL\nZC", }, { UCALL, INAREG, SCON, TANY, SAREG, TP16, NAREG|NASL, RESC1, /* should be 0 */ " call CL\nZC", }, { CALL, INBREG, SCON, TANY, SBREG, T8, NBREG, RESC1, /* should be 0 */ " call CL\nZC", }, { UCALL, INBREG, SCON, TANY, SBREG, T8, NBREG, RESC1, /* should be 0 */ " call CL\nZC", }, { CALL, INCREG, SCON, TANY, SCREG, TANY, NCREG|NCSL, RESC1, /* should be 0 */ " call CL\nZC", }, { UCALL, INCREG, SCON, TANY, SCREG, TANY, NCREG|NCSL, RESC1, /* should be 0 */ " call CL\nZC", }, { CALL, INDREG, SCON, TANY, SDREG, TANY, NDREG|NDSL, RESC1, /* should be 0 */ " call CL\nZC", }, { UCALL, INDREG, SCON, TANY, SDREG, TANY, NDREG|NDSL, RESC1, /* should be 0 */ " call CL\nZC", }, { CALL, FOREFF, SAREG, TANY, SANY, TANY, 0, 0, " call *AL\nZC", }, { UCALL, FOREFF, SAREG, TANY, SANY, TANY, 0, 0, " call *AL\nZC", }, { CALL, INAREG, SAREG, TANY, SANY, TANY, NAREG|NASL, RESC1, /* should be 0 */ " call *AL\nZC", }, { UCALL, INAREG, SAREG, TANY, SANY, TANY, NAREG|NASL, RESC1, /* should be 0 */ " call *AL\nZC", }, { CALL, INBREG, SAREG, TANY, SANY, TANY, NBREG|NBSL, RESC1, /* should be 0 */ " call *AL\nZC", }, { UCALL, INBREG, SAREG, TANY, SANY, TANY, NBREG|NBSL, RESC1, /* should be 0 */ " call *AL\nZC", }, { CALL, INCREG, SAREG, TANY, SANY, TANY, NCREG|NCSL, RESC1, /* should be 0 */ " call *AL\nZC", }, { UCALL, INCREG, SAREG, TANY, SANY, TANY, NCREG|NCSL, RESC1, /* should be 0 */ " call *AL\nZC", }, { CALL, INDREG, SAREG, TANY, SANY, TANY, NDREG|NDSL, RESC1, /* should be 0 */ " call *AL\nZC", }, { UCALL, INDREG, SAREG, TANY, SANY, TANY, NDREG|NDSL, RESC1, /* should be 0 */ " call *AL\nZC", }, { STCALL, FOREFF, SCON, TANY, SANY, TANY, NAREG|NASL, 0, " call CL\nZC", }, { STCALL, INAREG, SCON, TANY, SANY, TANY, NAREG|NASL, RESC1, /* should be 0 */ " call CL\nZC", }, { STCALL, INAREG, SNAME|SAREG, TANY, SANY, TANY, NAREG|NASL, RESC1, /* should be 0 */ " call *AL\nZC", }, /* * The next rules handle all binop-style operators. * * 8 and 16bit we do directly, 32bit is a mix of helpers and * direct operations. 64bit TODO, FPU lives in it's own little * world. */ { PLUS, INL|FOREFF, SHL, T32, SHL|SNAME|SOREG, T32, 0, RLEFT, " add AL,AR\n adc UL,UR\n", }, { PLUS, INL|FOREFF, SHL|SNAME|SOREG, T32, SHL|SCON, T32, 0, RLEFT, " add AL,AR\n adc UL,UR\n", }, /* Special treatment for long XXX - fix commutative check */ { PLUS, INL|FOREFF, SHL|SNAME|SOREG, T32, SHL, T32, 0, RRIGHT, " add AL,AR\n adc UL,UR\n", }, { PLUS, INFL, SHFL, TDOUBLE, SNAME|SOREG, TDOUBLE, 0, RLEFT, " faddl AR\n", }, { PLUS, INFL|FOREFF, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, 0, RLEFT, " faddp\n", }, { PLUS, INAREG|FOREFF, SAREG|SNAME|SOREG, TP16, SONE, TANY, 0, RLEFT, " inc AL\n", }, { PLUS, INAREG|FOREFF, SAREG|SNAME|SOREG, TP16, STWO, TANY, 0, RLEFT, " inc AL\n inc AL\n", }, { PLUS, INCH|FOREFF, SHCH|SNAME|SOREG, T8, SONE, TANY, 0, RLEFT, " inc AL\n", }, { PLUS, INCH|FOREFF, SHCH|SNAME|SOREG, T8, STWO, TANY, 0, RLEFT, " inc AL\n inc AL\n", }, { PLUS, INAREG, SAREG, T16, SAREG, T16, NAREG|NASL|NASR, RESC1, " lea A1, [AL+AR]\n", }, { MINUS, INAREG|FOREFF, SAREG|SNAME|SOREG, TP16, SONE, TANY, 0, RLEFT, " dec AL\n", }, { MINUS, INAREG|FOREFF, SAREG|SNAME|SOREG, TP16, STWO, TANY, 0, RLEFT, " dec AL\n dec AL\n", }, { MINUS, INCH|FOREFF, SHCH|SNAME|SOREG, T8, SONE, TANY, 0, RLEFT, " dec AL\n", }, { MINUS, INCH|FOREFF, SHCH|SNAME|SOREG, T8, STWO, TANY, 0, RLEFT, " dec AL\n decl AL\n", }, /* address as register offset, negative */ { MINUS, INLL|FOREFF, SHL, T32, SHL|SNAME|SOREG, T32, 0, RLEFT, " sub AL,AR\n sbb UL,UR\n", }, { MINUS, INL|FOREFF, SHL|SNAME|SOREG, T32, SHL|SCON, T32, 0, RLEFT, " sub AL,AR\n sbb UL,UR\n", }, { MINUS, INFL, SHFL, TDOUBLE, SNAME|SOREG, TDOUBLE, 0, RLEFT, " fsubl AR\n", }, { MINUS, INFL|FOREFF, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, 0, RLEFT, " fsubZAp\n", }, /* Simple r/m->reg ops */ /* m/r |= r */ { OPSIMP, INAREG|FOREFF|FORCC, SHINT|SNAME|SOREG, TP16, SHINT, TP16, 0, RLEFT|RESCC, " Ow AL,AR\n", }, /* r |= r/m */ { OPSIMP, INAREG|FOREFF|FORCC, SHINT, T16, SHINT|SNAME|SOREG, T16, 0, RLEFT|RESCC, " Ow AL,AR\n", }, /* m/r |= r */ { OPSIMP, INCH|FOREFF|FORCC, SHCH, T8, SHCH|SNAME|SOREG, T8, 0, RLEFT|RESCC, " Ob AL,AR\n", }, /* r |= r/m */ { OPSIMP, INCH|FOREFF|FORCC, SHCH, T8, SHCH|SNAME|SOREG, T8, 0, RLEFT|RESCC, " Ob AL,AR\n", }, /* m/r |= const */ { OPSIMP, INAREG|FOREFF|FORCC, SHINT|SNAME|SOREG, TP16, SCON, TANY, 0, RLEFT|RESCC, " Ow AL,AR\n", }, { OPSIMP, INCH|FOREFF|FORCC, SHCH|SNAME|SOREG, T8, SCON, TANY, 0, RLEFT|RESCC, " Ob AL,AR\n", }, /* r |= r/m */ { OPSIMP, INL|FOREFF, SHL, T32, SHL|SNAME|SOREG, T32, 0, RLEFT, " Ow AL,AR\n Ow UL,UR\n", }, /* m/r |= r/const */ { OPSIMP, INL|FOREFF, SHL|SNAME|SOREG, T32, SHL|SCON, T32, 0, RLEFT, " Ow AL,AR\n Ow UL,UR\n", }, /* Try use-reg instructions first */ { PLUS, INAREG, SAREG, TP16, SCON, TANY, NAREG|NASL, RESC1, " lea A1, CR[AL]\n", }, { MINUS, INAREG, SAREG, TP16, SPCON, TANY, NAREG|NASL, RESC1, " lea A1, -CR[AL]\n", }, /* * The next rules handle all shift operators. */ /* (u)long left shift is emulated, longlong to do */ /* For 8086 we only have shift by 1 or shift by CL We need a way to optimise shifts by 8/16/24/32/etc shifts by 8 16 24 and 32 as moves between registers for the bigger types. (eg >> 16 on a long might be mov dx, ax, xor ax, ax) */ { LS, INCREG, SCREG, T32, SHCH, T8, 0, RLEFT, "ZO", }, /* Register 8086 timing is 2 for #1 versus 8 + 4/bin for multiple so a lot of shifts would in fact best be done without using the cl variant, especially including the cost of a) loading cl b) probably having to boot something out of cx in the first place. For memory its 15+EA v 20 + EA + 4/bit, so the other way. 8,16,24 should of course be done by loads.. FIXME Also the compiler keeps generating mov dh, #8, mov cl, dh.. FIXME For 80186 onwards we have shl reg, immediate (other than 1), 186 shift is also much faster */ /* r/m <<= const 1*/ { LS, INAREG|FOREFF, SAREG|SNAME|SOREG, T16, SONE, TANY, 0, RLEFT, " shl AL,#1\n", }, /* r <<= const 2 */ { LS, INAREG|FOREFF, SAREG, T16, STWO, TANY, 0, RLEFT, " shl AL,#1\n shl AL,#1\n", }, /* r/m <<= r */ { LS, INAREG|FOREFF, SAREG|SNAME|SOREG, T16, SHCH, T8, NSPECIAL, RLEFT, " shl AL,AR\n", }, { LS, INCH|FOREFF, SHCH|SNAME|SOREG, T8, SONE, TANY, NSPECIAL, RLEFT, " sal AL,#1\n", }, { LS, INCH|FOREFF, SHCH, T8, STWO, TANY, NSPECIAL, RLEFT, " sal AL,#1\n sal AL,#1", }, { LS, INCH|FOREFF, SHCH|SNAME|SOREG, T8, SHCH, T8, NSPECIAL, RLEFT, " sal AL,AR\n", }, /* (u)long right shift is emulated. Use a 16bit register so the push comes out sanely */ { RS, INCREG, SCREG, T32, SHCH, T8, 0, RLEFT, "ZO", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TINT, SHCH, T8, NSPECIAL, RLEFT, " sar AL,AR\n", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TINT, SONE, TANY, NSPECIAL, RLEFT, " sar AL,#1\n", }, { RS, INAREG|FOREFF, SAREG, TINT, STWO, TANY, NSPECIAL, RLEFT, " sar AL,#1\n sar AL,#1", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TUNSIGNED|TPOINT, SHCH, T8, NSPECIAL, RLEFT, " shr AL,AR\n", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TUNSIGNED, SONE, TANY, 0, RLEFT, " shr AL,#1\n", }, { RS, INAREG|FOREFF, SAREG, TUNSIGNED, STWO, TANY, 0, RLEFT, " shr AL,#1 shr AL,#1\n", }, { RS, INCH|FOREFF, SHCH|SNAME|SOREG, TCHAR, SHCH, T8, NSPECIAL, RLEFT, " sar AL,AR\n", }, { RS, INCH|FOREFF, SHCH|SNAME|SOREG, TCHAR, SONE, TANY, NSPECIAL, RLEFT, " sar AL,#1\n", }, { RS, INCH|FOREFF, SHCH|SNAME|SOREG, TCHAR, STWO, TANY, NSPECIAL, RLEFT, " sar AL,#1\n sar AL,#1\n", }, { RS, INCH|FOREFF, SHCH|SNAME|SOREG, TUCHAR, SHCH, T8, NSPECIAL, RLEFT, " shr AL,AR\n", }, { RS, INCH|FOREFF, SHCH|SNAME|SOREG, TUCHAR, SONE, TANY, NSPECIAL, RLEFT, " shr AL,#1\n", }, { RS, INCH|FOREFF, SHCH|SNAME|SOREG, TUCHAR, STWO, TANY, NSPECIAL, RLEFT, " shr AL,#1\n shr AL,#1\n", }, /* * The next rules takes care of assignments. "=". */ { ASSIGN, FORCC|FOREFF|INL, SHL, T32, SMIXOR, TANY, 0, RDEST, " xor AL,AL\n xor UL,UL\n", }, { ASSIGN, FORCC|FOREFF|INL, SHL, T32, SMILWXOR, TANY, 0, RDEST, " xor AL,AL\n mov UR,UL\n", }, { ASSIGN, FORCC|FOREFF|INL, SHL, T32, SMIHWXOR, TANY, 0, RDEST, " mov AL,AR\n xor UL,UL\n", }, { ASSIGN, FOREFF|INL, SHL, T32, SCON, TANY, 0, RDEST, " mov AL,AR\n mov UL,UR\n", }, { ASSIGN, FOREFF, SHL|SNAME|SOREG, T32, SCON, TANY, 0, 0, " mov AL,AR\n mov UL,UR\n", }, { ASSIGN, FOREFF, SAREG|SNAME|SOREG, TP16, SCON, TANY, 0, 0, " mov AL, AR\n", }, { ASSIGN, FOREFF|INAREG, SAREG, TP16, SCON, TANY, 0, RDEST, " mov AL, AR\n", }, { ASSIGN, FOREFF, SHCH|SNAME|SOREG, T8, SCON, TANY, 0, 0, " mov AL, AR\n", }, { ASSIGN, FOREFF|INCH, SHCH, T8, SCON, TANY, 0, RDEST, " mov AL, AR\n", }, { ASSIGN, FOREFF|INL, SNAME|SOREG, T32, SHL, T32, 0, RDEST, " mov AL,AR\n mov UL,UR\n", }, { ASSIGN, FOREFF|INL, SHL, T32, SHL, T32, 0, RDEST, "ZH", }, { ASSIGN, FOREFF|INAREG, SAREG|SNAME|SOREG, TP16, SAREG, TP16, 0, RDEST, " mov AL,AR\n", }, { ASSIGN, FOREFF|INAREG, SAREG, TP16, SAREG|SNAME|SOREG, TP16, 0, RDEST, " mov AL,AR\n", }, { ASSIGN, FOREFF|INCH, SHCH|SNAME|SOREG, T8, SHCH, T8|T16, 0, RDEST, " mov AL,AR\n", }, { ASSIGN, INDREG|FOREFF, SHFL, TFLOAT|TDOUBLE|TLDOUBLE, SHFL, TFLOAT|TDOUBLE|TLDOUBLE, 0, RDEST, "", }, /* This will always be in the correct register */ /* order of table entries is very important here! */ { ASSIGN, INFL, SNAME|SOREG, TLDOUBLE, SHFL, TFLOAT|TDOUBLE|TLDOUBLE, 0, RDEST, " fstpt AL\n fldt AL\n", }, /* XXX */ { ASSIGN, FOREFF, SNAME|SOREG, TLDOUBLE, SHFL, TFLOAT|TDOUBLE|TLDOUBLE, 0, 0, " fstpt AL\n", }, { ASSIGN, INFL, SNAME|SOREG, TDOUBLE, SHFL, TFLOAT|TDOUBLE|TLDOUBLE, 0, RDEST, " fstl AL\n", }, { ASSIGN, FOREFF, SNAME|SOREG, TDOUBLE, SHFL, TFLOAT|TDOUBLE|TLDOUBLE, 0, 0, " fstpl AL\n", }, { ASSIGN, INFL, SNAME|SOREG, TFLOAT, SHFL, TFLOAT|TDOUBLE|TLDOUBLE, 0, RDEST, " fsts AL\n", }, { ASSIGN, FOREFF, SNAME|SOREG, TFLOAT, SHFL, TFLOAT|TDOUBLE|TLDOUBLE, 0, 0, " fstps AL\n", }, /* end very important order */ { ASSIGN, INFL|FOREFF, SHFL, TLDOUBLE, SHFL|SOREG|SNAME, TLDOUBLE, 0, RDEST, " fldt AR\n", }, { ASSIGN, INFL|FOREFF, SHFL, TDOUBLE, SHFL|SOREG|SNAME, TDOUBLE, 0, RDEST, " fldl AR\n", }, { ASSIGN, INFL|FOREFF, SHFL, TFLOAT, SHFL|SOREG|SNAME, TFLOAT, 0, RDEST, " flds AR\n", }, /* Do not generate memcpy if return from funcall */ #if 0 { STASG, INAREG|FOREFF, SOREG|SNAME|SAREG, TPTRTO|TSTRUCT, SFUNCALL, TPTRTO|TSTRUCT, 0, RRIGHT, "", }, #endif { STASG, INAREG|FOREFF, SOREG|SNAME, TANY, SAREG, TPTRTO|TANY, NSPECIAL|NAREG, RDEST, "F mov A1,si\nZQF mov si,A1\n", }, /* * DIV/MOD/MUL */ /* long div is emulated */ { DIV, INCREG, SCREG|SNAME|SOREG|SCON, T32, SCREG|SNAME|SOREG|SCON, T32, NSPECIAL|NCREG|NCSL|NCSR, RESC1, "ZO", }, /* REVIEW We can only do (i)divb ax/byte and (i)divw (dx:ax)/word and the results are always in ah/al (remainer/mod) or dx:ax (dx = remainer, ax = mod) Power of two needs to be done by shifts. For other cases of constants we need to implement two things 1. Spotting add sequences for constants with few 1 bits on one side 2. Spotting cases we can compute the magic constant to multiply with for the same result */ { DIV, INAREG, SAREG, TUNSIGNED|TPOINT, SAREG|SNAME|SOREG, TUNSIGNED|TPOINT, NSPECIAL, RDEST, " xor dx,dx\n divw AR\n", }, { DIV, INCH, SHCH, TUCHAR, SHCH|SNAME|SOREG, TUCHAR, NSPECIAL, RDEST, " xor ah,ah\n divb AR\n", }, { DIV, INFL, SHFL, TDOUBLE, SNAME|SOREG, TDOUBLE, 0, RLEFT, " fdivl AR\n", }, { DIV, INFL, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, 0, RLEFT, " fdivZAp\n", }, /* (u)long mod is emulated */ { MOD, INCREG, SCREG|SNAME|SOREG|SCON, T32, SCREG|SNAME|SOREG|SCON, T32, NSPECIAL|NCREG|NCSL|NCSR, RESC1, "ZO", }, { MOD, INAREG, SAREG, TP16, SAREG|SNAME|SOREG, TP16, NAREG|NSPECIAL, RESC1, " xor dx,dx\n divw AR\n", }, { MOD, INCH, SHCH, TUCHAR, SHCH|SNAME|SOREG, TUCHAR, NBREG|NSPECIAL, RESC1, " xor ah,ah\n divb AR\n", }, /* (u)long mul is emulated */ /* On 8086 we can only do multiplies of al * value into ax (for 8bit) or ax * value into dx:ax for 16bit 80186 allows us to do a signed multiply of a register with a constant into a second register Same about shifts, and add optimisations applies here too */ /* 32bit mul is emulated (for now) */ { MUL, INCREG, SCREG|SNAME|SOREG|SCON, T32, SCREG|SNAME|SOREG|SCON, T32, NSPECIAL|NCREG|NCSL|NCSR, RESC1, "ZO", }, /* FIMXE: need special rules */ { MUL, INAREG, SAREG, T16|TPOINT, SAREG|SNAME|SOREG, T16|TPOINT, NSPECIAL, RDEST, " mul AR\n", }, { MUL, INCH, SHCH, T8, SHCH|SNAME|SOREG, T8, NSPECIAL, RDEST, " mulb AR\n", }, { MUL, INFL, SHFL, TDOUBLE, SNAME|SOREG, TDOUBLE, 0, RLEFT, " fmull AR\n", }, { MUL, INFL, SHFL , TLDOUBLE|TDOUBLE|TFLOAT, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, 0, RLEFT, " fmulp\n", }, /* * Indirection operators. */ { UMUL, INLL, SANY, TANY, SOREG, T32, NCREG, RESC1, " mov UL,U1\n mov AL,A1\n", }, { UMUL, INAREG, SANY, TP16, SOREG, TP16, NAREG|NASL, RESC1, " mov AL,A1\n", }, { UMUL, INCH, SANY, TANY, SOREG, T8, NBREG|NBSL, RESC1, " mov AL,A1\n", }, { UMUL, INAREG, SANY, TANY, SOREG, T16, NAREG|NASL, RESC1, " mov AL,A1\n", }, { UMUL, INFL, SANY, TANY, SOREG, TLDOUBLE, NDREG|NDSL, RESC1, " fldt AL\n", }, { UMUL, INFL, SANY, TANY, SOREG, TDOUBLE, NDREG|NDSL, RESC1, " fldl AL\n", }, { UMUL, INFL, SANY, TANY, SOREG, TFLOAT, NDREG|NDSL, RESC1, " flds AL\n", }, /* * Logical/branching operators */ /* Comparisions, take care of everything */ { OPLOG, FORCC, SHL|SOREG|SNAME, T32, SHL, T32, 0, 0, "ZD", }, { OPLOG, FORCC, SAREG|SOREG|SNAME, TP16, SCON|SAREG, TP16, 0, RESCC, " cmp AL,AR\n", }, { OPLOG, FORCC, SCON|SAREG, TP16, SAREG|SOREG|SNAME, TP16, 0, RESCC, " cmp AL,AR\n", }, { OPLOG, FORCC, SBREG|SOREG|SNAME, T8, SCON|SBREG, TANY, 0, RESCC, " cmpb AL,AR\n", }, { OPLOG, FORCC, SCON|SBREG, T8, SBREG|SOREG|SNAME, TANY, 0, RESCC, " cmpb AL,AR\n", }, { OPLOG, FORCC, SDREG, TLDOUBLE|TDOUBLE|TFLOAT, SDREG, TLDOUBLE|TDOUBLE|TFLOAT, 0, RNOP, "ZG", }, { OPLOG, FORCC, SANY, TANY, SANY, TANY, REWRITE, 0, "diediedie!", }, /* AND/OR/ER/NOT */ /* FIXME: pcc generates nonsense ands, but they should be fixed somewhere if possible. In particular it will do the classic 32bit and with a 16bit 0xFFFF by generating and ax,#ffff and bx,#0 eg compiling sum1 = (sum1 & 0xFFFF) + (sum1 >> 16); writes a pile of crap code. */ { AND, INCREG|FOREFF, SCREG, T32, SCREG|SOREG|SNAME, T32, 0, RLEFT, " and AR,AL\n and UR,UL\n", }, { AND, INAREG|FOREFF, SAREG, T16, SAREG|SOREG|SNAME, T16, 0, RLEFT, " and AR,AL\n", }, { AND, INAREG|FOREFF, SAREG|SOREG|SNAME, T16, SCON|SAREG, T16, 0, RLEFT, " and AR,AL\n", }, { AND, INBREG|FOREFF, SBREG|SOREG|SNAME, T8, SCON|SBREG, T8, 0, RLEFT, " and AR,AL\n", }, { AND, INBREG|FOREFF, SBREG, T8, SBREG|SOREG|SNAME, T8, 0, RLEFT, " and AR,AL\n", }, /* AND/OR/ER/NOT */ /* * Jumps. */ { GOTO, FOREFF, SCON, TANY, SANY, TANY, 0, RNOP, " jmp LL\n", }, #if defined(GCC_COMPAT) || defined(LANG_F77) { GOTO, FOREFF, SAREG, TANY, SANY, TANY, 0, RNOP, " jmp *AL\n", }, #endif /* * Convert LTYPE to reg. */ { OPLTYPE, FORCC|INL, SCREG, T32, SMIXOR, TANY, NCREG, RESC1, " xor U1,U1\n xor A1,A1\n", }, { OPLTYPE, FORCC|INL, SCREG, T32, SMILWXOR, TANY, NCREG, RESC1, " mov U1,UL\n xor A1,A1\n", }, { OPLTYPE, FORCC|INL, SCREG, T32, SMIHWXOR, TANY, NCREG, RESC1, " xor U1,U1\n mov A1,AL\n", }, { OPLTYPE, INL, SANY, TANY, SCREG, T32, NCREG, RESC1, "ZK", }, { OPLTYPE, INL, SANY, TANY, SCON|SOREG|SNAME, T32, NCREG, RESC1, " mov U1,UL\n mov A1,AL\n", }, { OPLTYPE, FORCC|INAREG, SAREG, TP16, SMIXOR, TANY, NAREG|NASL, RESC1, " xor A1,A1\n", }, { OPLTYPE, INAREG, SANY, TANY, SAREG|SCON|SOREG|SNAME, TP16, NAREG|NASL, RESC1, " mov A1,AL\n", }, { OPLTYPE, INBREG, SANY, TANY, SBREG|SOREG|SNAME|SCON, T8, NBREG, RESC1, " mov A1,AL\n", }, { OPLTYPE, FORCC|INAREG, SAREG, T16, SMIXOR, TANY, NAREG, RESC1, " xor A1,A1\n", }, { OPLTYPE, INAREG, SANY, TANY, SAREG|SOREG|SNAME|SCON, T16, NAREG, RESC1, " mov A1,AL\n", }, { OPLTYPE, INDREG, SANY, TLDOUBLE, SOREG|SNAME, TLDOUBLE, NDREG, RESC1, " fldt AL\n", }, { OPLTYPE, INDREG, SANY, TDOUBLE, SOREG|SNAME, TDOUBLE, NDREG, RESC1, " fldl AL\n", }, { OPLTYPE, INDREG, SANY, TFLOAT, SOREG|SNAME, TFLOAT, NDREG, RESC1, " flds AL\n", }, /* Only used in ?: constructs. The stack already contains correct value */ { OPLTYPE, INDREG, SANY, TFLOAT|TDOUBLE|TLDOUBLE, SDREG, TFLOAT|TDOUBLE|TLDOUBLE, NDREG, RESC1, "", }, /* * Negate a word. */ { UMINUS, INCREG|FOREFF, SCREG, T32, SCREG, T32, 0, RLEFT, " neg AL\n adc UL,#0\n neg UL\n", }, { UMINUS, INAREG|FOREFF, SAREG, TP16, SAREG, TP16, 0, RLEFT, " neg AL\n", }, { UMINUS, INBREG|FOREFF, SBREG, T8, SBREG, T8, 0, RLEFT, " neg AL\n", }, { UMINUS, INFL|FOREFF, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, 0, RLEFT, " fchs\n", }, { COMPL, INCREG, SCREG, T32, SANY, TANY, 0, RLEFT, " not AL\n not UL\n", }, { COMPL, INAREG, SAREG, T16, SANY, TANY, 0, RLEFT, " not AL\n", }, { COMPL, INBREG, SBREG, T8, SANY, TANY, 0, RLEFT, " not AL\n", }, /* * Arguments to functions. * * char has already been promoted to integer types */ /* Push immediate not 8086... Loading a register and pushing costs us 4 + 11 clocks, loading memory would cost us 16 + EA */ { FUNARG, FOREFF, /*SCON|*/SCREG|SNAME|SOREG, T32, SANY, T32, 0, RNULL, " push UL\n push AL\n", }, { FUNARG, FOREFF, /*SCON|*/SAREG|SNAME|SOREG, T16|TPOINT, SANY, TP16, 0, RNULL, " push AL\n", }, /* FIXME: FPU needs reworking into 4 regs or a memcpy */ { FUNARG, FOREFF, SNAME|SOREG, TDOUBLE, SANY, TDOUBLE, 0, 0, " pushl UL\n pushl AL\n", }, { FUNARG, FOREFF, SDREG, TDOUBLE, SANY, TDOUBLE, 0, 0, " sub sp,#8\n fstpl [sp]\n", }, { FUNARG, FOREFF, SNAME|SOREG, TFLOAT, SANY, TFLOAT, 0, 0, " push UL\n push AL\n", }, { FUNARG, FOREFF, SDREG, TFLOAT, SANY, TFLOAT, 0, 0, " sub sp,#4\n fstps [sp]\n", }, { FUNARG, FOREFF, SDREG, TLDOUBLE, SANY, TLDOUBLE, 0, 0, " sub sp,#12\n fstpt [sp]\n", }, { STARG, FOREFF, SAREG, TPTRTO|TSTRUCT, SANY, TSTRUCT, NSPECIAL, 0, "ZF", }, # define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,"" { UMUL, DF( UMUL ), }, { ASSIGN, DF(ASSIGN), }, { STASG, DF(STASG), }, { FLD, DF(FLD), }, { OPLEAF, DF(NAME), }, /* { INIT, DF(INIT), }, */ { OPUNARY, DF(UMINUS), }, { OPANY, DF(BITYPE), }, { FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" }, }; int tablesize = sizeof(table)/sizeof(table[0]); pcc-20181216/arch/m16c004075500017500000000000000000001340533064000130715ustar raggewheelpcc-20181216/arch/m16c/CVS004075500017500000000000000000001340533064000135245ustar raggewheelpcc-20181216/arch/m16c/CVS/Root010064400017500000000000000000111340533064000144360ustar raggewheel/cvsroot pcc-20181216/arch/m16c/CVS/Repository010064400017500000000000000000161340533064000156770ustar raggewheelpcc/arch/m16c pcc-20181216/arch/m16c/CVS/Entries010064400017500000000000000004371340533064000151400ustar raggewheel/TODO/1.3/Mon Feb 6 09:33:09 2006// /code.c/1.25/Thu May 29 19:20:02 2014// /local.c/1.22/Tue Aug 18 10:15:08 2015// /local2.c/1.44/Mon Sep 26 16:45:42 2016// /macdefs.h/1.27/Sat Mar 5 15:53:04 2016// /order.c/1.22/Sun Jun 1 11:35:02 2014// /table.c/1.35/Sun Jun 5 08:54:42 2011// D pcc-20181216/arch/m16c/TODO010064400017500000000000000000301037161372500136350ustar raggewheel* Mul/Div does not work.pcc-20181216/arch/m16c/code.c010064400017500000000000000160101234170414200142210ustar raggewheel/* $Id: code.c,v 1.25 2014/05/29 19:20:02 plunky Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass1.h" /* * cause the alignment to become a multiple of n */ void defalign(int n) { #if 0 char *s; n /= SZCHAR; if (lastloc == PROG || n == 1) return; s = (isinlining ? permalloc(40) : tmpalloc(40)); sprintf(s, "\t.align %d\n", n); send_passt(IP_ASM, s); #endif } /* * define the current location as the name p->soname */ void defnam(struct symtab *p) { char *c = p->soname; if (p->sclass == EXTDEF) printf(" PUBLIC %s\n", c); printf("%s:\n", c); } /* * code for the end of a function * deals with struct return here */ void efcode(void) { NODE *p, *q; int sz; if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) return; /* address of return struct is in eax */ /* create a call to memcpy() */ /* will get the result in eax */ p = block(REG, NIL, NIL, CHAR+PTR, 0, 0); p->n_rval = R0; q = block(OREG, NIL, NIL, CHAR+PTR, 0, 0); q->n_rval = FB; q->n_lval = 8; /* return buffer offset */ p = block(CM, q, p, INT, 0, 0); sz = (tsize(STRTY, cftnsp->sdf, cftnsp->ssue)+SZCHAR-1)/SZCHAR; p = block(CM, p, bcon(sz), INT, 0, 0); p->n_right->n_name = ""; p = block(CALL, bcon(0), p, CHAR+PTR, 0, 0); p->n_left->n_name = "memcpy"; send_passt(IP_NODE, p); } /* * helper for bfcode() to put register arguments on stack. */ static void argmove(struct symtab *s, int regno) { NODE *p, *r; s->sclass = AUTO; s->soffset = NOOFFSET; oalloc(s, &autooff); p = nametree(s); r = bcon(0); r->n_op = REG; r->n_rval = regno; r->n_type = p->n_type; r->n_sue = p->n_sue; r->n_df = p->n_df; ecode(buildtree(ASSIGN, p, r)); } /* * code for the beginning of a function; a is an array of * indices in symtab for the arguments; n is the number * On m16k, space is allocated on stack for register arguments, * arguments are moved to the stack and symtab is updated accordingly. */ void bfcode(struct symtab **a, int n) { struct symtab *s; int i, r0l, r0h, a0, r2, sz, hasch, stk; int argoff = ARGINIT; if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { /* Function returns struct, adjust arg offset */ for (i = 0; i < n; i++) a[i]->soffset += SZPOINT(INT); } /* first check if there are 1-byte parameters */ for (hasch = i = 0; i < n && i < 6; i++) if (DEUNSIGN(a[i]->stype) == CHAR) hasch = 1; stk = r0l = r0h = a0 = r2 = 0; for (i = 0; i < n; i++) { s = a[i]; sz = tsize(s->stype, s->sdf, s->ssue); if (ISPTR(s->stype) && ISFTN(DECREF(s->stype))) sz = SZLONG; /* function pointers are always 32 */ if (stk == 0) switch (sz) { case SZCHAR: if (r0l) { if (r0h) break; argmove(s, 1); r0h = 1; } else { argmove(s, 0); r0l = 1; } continue; case SZINT: if (s->stype > BTMASK) { /* is a pointer */ if (a0) { if (r0l || hasch) { if (r2) break; argmove(s, R2); r2 = 1; } else { argmove(s, R0); r0l = r0h = 1; } } else { argmove(s, A0); a0 = 1; } } else if (r0l || hasch) { if (r2) { if (a0) break; argmove(s, A0); a0 = 1; } else { argmove(s, R2); r2 = 1; } } else { argmove(s, R0); r0l = r0h = 1; } continue; case SZLONG: if (r0l||r0h||r2) break; argmove(s, R0); r0l = r0h = r2 = 1; continue; default: break; } stk = 1; s->soffset = argoff; argoff += sz; } } /* * Add a symbol to an internal list printed out at the end. */ void addsym(struct symtab *); static struct symlst { struct symlst *next; struct symtab *sp; } *sympole; void addsym(struct symtab *q) { struct symlst *w = sympole; if (q == NULL) return; while (w) { if (q == w->sp) return; /* exists */ w = w->next; } w = permalloc(sizeof(struct symlst)); w->sp = q; w->next = sympole; sympole = w; } struct caps { char *cap, *stat; } caps[] = { { "__64bit_doubles", "Disabled" }, { "__calling_convention", "Normal" }, { "__constant_data", "near" }, { "__data_alignment", "2" }, { "__data_model", "near" }, { "__processor", "M16C" }, { "__rt_version", "1" }, { "__variable_data", "near" }, { NULL, NULL }, }; /* * Called before parsing begins. */ void bjobcode(void) { struct caps *c; printf(" NAME gurka.c\n"); /* Don't have the name */ for (c = caps; c->cap; c++) printf(" RTMODEL \"%s\", \"%s\"\n", c->cap, c->stat); //printf(" RSEG CODE:CODE:REORDER:NOROOT(0)\n"); } /* called just before final exit */ /* flag is 1 if errors, 0 if none */ void ejobcode(int flag) { struct symlst *w = sympole; for (w = sympole; w; w = w->next) { if (w->sp->sclass != EXTERN) continue; printf(" EXTERN %s\n", w->sp->soname); } printf(" END\n"); } /* * Print character t at position i in one string, until t == -1. * Locctr & label is already defined. */ void bycode(int t, int i) { static int lastoctal = 0; /* put byte i+1 in a string */ if (t < 0) { if (i != 0) puts("\""); } else { if (i == 0) printf("\t.ascii \""); if (t == '\\' || t == '"') { lastoctal = 0; putchar('\\'); putchar(t); } else if (t < 040 || t >= 0177) { lastoctal++; printf("\\%o",t); } else if (lastoctal && '0' <= t && t <= '9') { lastoctal = 0; printf("\"\n\t.ascii \"%c", t); } else { lastoctal = 0; putchar(t); } } } /* fix up type of field p */ void fldty(struct symtab *p) { } /* * XXX - fix genswitch. */ int mygenswitch(int num, TWORD type, struct swents **p, int n) { return 0; } /* * Called with a function call with arguments as argument. * This is done early in buildtree() and only done once. */ NODE * funcode(NODE *p) { return p; } pcc-20181216/arch/m16c/local.c010064400017500000000000000214471256460265400144270ustar raggewheel/* $Id: local.c,v 1.22 2015/08/18 10:15:08 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass1.h" /* this file contains code which is dependent on the target machine */ NODE * clocal(NODE *p) { /* this is called to do local transformations on an expression tree preparitory to its being written out in intermediate code. */ /* the major essential job is rewriting the automatic variables and arguments in terms of REG and OREG nodes */ /* conversion ops which are not necessary are also clobbered here */ /* in addition, any special features (such as rewriting exclusive or) are easily handled here as well */ struct symtab *q; NODE *l, *r; int o; TWORD ml; switch( o = p->n_op ){ case NAME: if ((q = p->n_sp) == NULL) return p; /* Nothing to care about */ switch (q->sclass) { case PARAM: case AUTO: /* fake up a structure reference */ r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); r->n_lval = 0; r->n_rval = FPREG; p = stref(block(STREF, r, p, 0, 0, 0)); break; case STATIC: if (q->slevel == 0) break; p->n_lval = 0; p->n_sp = q; break; case REGISTER: p->n_op = REG; p->n_lval = 0; p->n_rval = q->soffset; break; } break; case PCONV: ml = p->n_left->n_type; l = p->n_left; if ((ml == CHAR || ml == UCHAR) && l->n_op != ICON) break; l->n_type = p->n_type; l->n_qual = p->n_qual; l->n_df = p->n_df; l->n_sue = p->n_sue; nfree(p); p = l; break; case SCONV: l = p->n_left; if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT) { nfree(p); return l; } if (l->n_op == ICON) { CONSZ val = l->n_lval; switch (p->n_type) { case CHAR: l->n_lval = (char)val; break; case UCHAR: l->n_lval = val & 0377; break; case SHORT: case INT: l->n_lval = (short)val; break; case USHORT: case UNSIGNED: l->n_lval = val & 0177777; break; case ULONG: case ULONGLONG: l->n_lval = val & 0xffffffff; break; case LONG: case LONGLONG: l->n_lval = (int)val; break; case VOID: break; case LDOUBLE: case DOUBLE: case FLOAT: l->n_op = FCON; l->n_dcon = val; break; default: cerror("unknown type %d", p->n_type); } l->n_type = p->n_type; nfree(p); return l; } break; } return(p); } /*ARGSUSED*/ int andable(NODE *p) { return(1); /* all names can have & taken on them */ } /* * is an automatic variable of type t OK for a register variable */ int cisreg(TWORD t) { if (t == INT || t == UNSIGNED || t == CHAR || t == UCHAR || ISPTR(t)) return(1); return 0; /* XXX - fix reg assignment in pftn.c */ } /* * Allocate off bits on the stack. p is a tree that when evaluated * is the multiply count for off, t is a NAME node where to write * the allocated address. */ void spalloc(NODE *t, NODE *p, OFFSZ off) { NODE *sp; if ((off % SZINT) == 0) p = buildtree(MUL, p, bcon(off/SZINT)); else if ((off % SZSHORT) == 0) { p = buildtree(MUL, p, bcon(off/SZSHORT)); p = buildtree(PLUS, p, bcon(1)); p = buildtree(RS, p, bcon(1)); } else if ((off % SZCHAR) == 0) { p = buildtree(MUL, p, bcon(off/SZCHAR)); p = buildtree(PLUS, p, bcon(3)); p = buildtree(RS, p, bcon(2)); } else cerror("roundsp"); /* save the address of sp */ sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_sue); sp->n_lval = 0; sp->n_rval = STKREG; t->n_type = sp->n_type; ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */ /* add the size to sp */ sp = block(REG, NIL, NIL, p->n_type, 0, 0); sp->n_lval = 0; sp->n_rval = STKREG; ecomp(buildtree(PLUSEQ, sp, p)); } /* * print out a constant node * mat be associated with a label */ int ninval(NODE *p) { struct symtab *q; TWORD t; p = p->n_left; t = p->n_type; if (t > BTMASK) t = p->n_type = INT; /* pointer */ switch (t) { case LONGLONG: case ULONGLONG: inval(p->n_lval & 0xffffffff); inval(p->n_lval >> 32); break; case LONG: case ULONG: case INT: case UNSIGNED: printf("\t.long 0x%x", (int)p->n_lval); if ((q = p->n_sp) != NULL) { if ((q->sclass == STATIC && q->slevel > 0)) { printf("+" LABFMT, q->soffset); } else printf("+%s", exname(q->soname)); } printf("\n"); break; default: fwalk(p, eprint, 0); return 0; } return 1; } /* make a name look like an external name in the local machine */ char * exname(char *p) { if (p == NULL) return ""; return p; } /* * map types which are not defined on the local machine */ TWORD ctype(TWORD type) { switch (BTYPE(type)) { case SHORT: MODTYPE(type,INT); break; case USHORT: MODTYPE(type,UNSIGNED); break; case LONGLONG: MODTYPE(type,LONG); break; case ULONGLONG: MODTYPE(type,ULONG); break; case LDOUBLE: MODTYPE(type,DOUBLE); break; } return (type); } /* curid is a variable which is defined but * is not initialized (and not a function ); * This routine returns the storage class for an uninitialized declaration */ int noinit() { return(EXTERN); } /* * Extern variable not necessary common. */ void extdec(struct symtab *q) { extern void addsym(struct symtab *); addsym(q); } /* * Call to a function */ void calldec(NODE *p, NODE *r) { struct symtab *q = p->n_sp; extern void addsym(struct symtab *); addsym(q); } /* make a common declaration for id, if reasonable */ void commdec(struct symtab *q) { int off; char *c = q->soname; off = tsize(q->stype, q->sdf, q->ssue); off = (off+(SZCHAR-1))/SZCHAR; printf(" PUBLIC %s\n", c); /* XXX - NOROOT??? */ printf(" RSEG DATA16_Z:NEARDATA:SORT:NOROOT(1)\n"); printf("%s:\n", c); printf(" DS8 %d\n", off); printf(" REQUIRE __data16_zero\n"); } /* make a local common declaration for id, if reasonable */ void lcommdec(struct symtab *q) { int off; off = tsize(q->stype, q->sdf, q->ssue); off = (off+(SZCHAR-1))/SZCHAR; if (q->slevel == 0) printf(" .lcomm %s,0%o\n", exname(q->soname), off); else printf(" .lcomm " LABFMT ",0%o\n", q->soffset, off); } /* * print a (non-prog) label. */ void deflab1(int label) { printf(LABFMT ":\n", label); } void setloc1(int locc) { if (locc == lastloc) return; lastloc = locc; } /* * special handling before tree is written out. */ void myp2tree(NODE *p) { struct symtab *sp; union dimfun *df; union arglist *al; NODE *q; int i; switch (p->n_op) { case MOD: case DIV: if (p->n_type == LONG || p->n_type == ULONG) { /* Swap arguments for hardops() later */ q = p->n_left; p->n_left = p->n_right; p->n_right = q; } break; case CALL: case STCALL: /* * inform pass2 about varargs. * store first variadic argument number in n_stalign * in the CM node. */ if (p->n_right->n_op != CM) break; /* nothing to care about */ df = p->n_left->n_df; if (df && (al = df->dfun)) { for (i = 0; i < 6; i++, al++) { if (al->type == TELLIPSIS || al->type == TNULL) break; } p->n_right->n_stalign = al->type == TELLIPSIS ? i : 0; } else p->n_right->n_stalign = 0; break; case FCON: /* Write float constants to memory */ sp = tmpalloc(sizeof(struct symtab)); sp->sclass = STATIC; sp->ssue = 0; sp->slevel = 1; /* fake numeric label */ sp->soffset = getlab(); sp->sflags = 0; sp->stype = p->n_type; sp->squal = (CON >> TSHIFT); defloc(sp); ninval(0, sp->ssue->suesize, p); p->n_op = NAME; p->n_lval = 0; p->n_sp = sp; break; } } /* * Give target the opportunity of handling pragmas. */ int mypragma(char **ary) { return 0; } /* * Called when a identifier has been declared, to give target last word. */ void fixdef(struct symtab *sp) { } void pass1_lastchance(struct interpass *ip) { } pcc-20181216/arch/m16c/local2.c010064400017500000000000000303031277225026600144770ustar raggewheel/* $Id: local2.c,v 1.44 2016/09/26 16:45:42 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass2.h" # include void acon(NODE *p); int argsize(NODE *p); void genargs(NODE *p); static int ftlab1, ftlab2; void deflab(int label) { printf(LABFMT ":\n", label); } static TWORD ftype; static int addto; void prologue(struct interpass_prolog *ipp) { ftype = ipp->ipp_type; #if 0 if (p2env.p_regs > 0 && p2env.p_regs != MINRVAR) comperr("fix prologue register savings", p2env.p_regs); #endif printf(" RSEG CODE:CODE:REORDER:NOROOT(0)\n"); if (ipp->ipp_vis) printf(" PUBLIC %s\n", ipp->ipp_name); printf("%s:\n", ipp->ipp_name); #if 0 if (xsaveip) { /* Optimizer running, save space on stack */ addto = (p2maxautooff - AUTOINIT)/SZCHAR; printf(" enter #%d\n", addto); } else { #endif /* non-optimized code, jump to epilogue for code generation */ ftlab1 = getlab2(); ftlab2 = getlab2(); printf(" jmp.w " LABFMT "\n", ftlab1); deflab(ftlab2); } /* * End of block. */ void eoftn(struct interpass_prolog *ipp) { #if 0 if (p2env.p_regs != MINRVAR) comperr("fix eoftn register savings %x", p2env.p_regs); #endif // if (xsaveip == 0) addto = (p2maxautooff - AUTOINIT)/SZCHAR; /* return from function code */ //deflab(ipp->ipp_ip.ip_lbl); //XXX - is this necessary? /* If retval is a pointer and not a function pointer, put in A0 */ if (ISPTR(DECREF(ipp->ipp_type)) && !ISFTN(DECREF(DECREF(ipp->ipp_type)))) printf(" mov.w r0,a0\n"); /* struct return needs special treatment */ if (ftype == STRTY || ftype == UNIONTY) { comperr("fix struct return in eoftn"); } else printf(" exitd\n"); /* Prolog code */ // if (xsaveip == 0) { deflab(ftlab1); printf(" enter #%d\n", addto); printf(" jmp.w " LABFMT "\n", ftlab2); //} } /* * add/sub/... * * Param given: */ void hopcode(int f, int o) { char *str; switch (o) { case PLUS: str = "add"; break; case MINUS: str = "sub"; break; case AND: str = "and"; break; case OR: str = "or"; break; case ER: str = "xor"; break; default: comperr("hopcode2: %d", o); str = 0; /* XXX gcc */ } printf("%s.%c", str, f); } char * rnames[] = { /* keyed to register number tokens */ "r0", "r2", "r1", "r3", "a0", "a1", "fb", "sp", "r0h", "r0l", "r1h", "r1l", }; /* * Return the size (in bytes) of some types. */ int tlen(p) NODE *p; { switch(p->n_type) { case CHAR: case UCHAR: return(1); case INT: case UNSIGNED: case FLOAT: return 2; case DOUBLE: case LONG: case ULONG: return 4; default: if (!ISPTR(p->n_type)) comperr("tlen type %d not pointer"); return SZPOINT(p->n_type)/SZCHAR; } } /* * Emit code to compare two longlong numbers. */ static void twollcomp(NODE *p) { int o = p->n_op; int s = getlab2(); int e = p->n_label; int cb1, cb2; if (o >= ULE) o -= (ULE-LE); switch (o) { case NE: cb1 = 0; cb2 = NE; break; case EQ: cb1 = NE; cb2 = 0; break; case LE: case LT: cb1 = GT; cb2 = LT; break; case GE: case GT: cb1 = LT; cb2 = GT; break; default: cb1 = cb2 = 0; /* XXX gcc */ } if (p->n_op >= ULE) cb1 += 4, cb2 += 4; expand(p, 0, " cmp.w UR,UL\n"); if (cb1) cbgen(cb1, s); if (cb2) cbgen(cb2, e); expand(p, 0, " cmp.w AR,AL\n"); cbgen(p->n_op, e); deflab(s); } void zzzcode(NODE *p, int c) { NODE *l; switch (c) { case 'A': /* print negative shift constant */ p = getlr(p, 'R'); if (p->n_op != ICON) comperr("ZA bad use"); p->n_lval = -p->n_lval; adrput(stdout, p); p->n_lval = -p->n_lval; break; case 'B': if (p->n_rval) printf(" add.b #%d,%s\n", p->n_rval, rnames[STKREG]); break; case 'C': /* Print label address */ p = p->n_left; if (p->n_lval) printf(LABFMT, (int)p->n_lval); else printf("%s", p->n_name); break; case 'D': /* copy function pointers */ l = p->n_left; printf("\tmov.w #HWRD(%s),%s\n\tmov.w #LWRD(%s),%s\n", p->n_right->n_name, rnames[l->n_rval+1], p->n_right->n_name, rnames[l->n_rval]); break; case 'E': /* double-reg printout */ /* XXX - always r0r2 here */ printf("%s%s", rnames[R0], rnames[R2]); break; case 'F': /* long comparisions */ twollcomp(p); break; case 'G': printf("R0R2"); break; case 'H': /* push 32-bit address (for functions) */ printf("\tpush.w #HWRD(%s)\n\tpush.w #LWRD(%s)\n", p->n_left->n_name, p->n_left->n_name); break; case 'I': /* push 32-bit address (for functions) */ l = p->n_left; printf("\tpush.w %d[%s]\n\tpush.w %d[%s]\n", (int)l->n_lval, rnames[l->n_rval], (int)l->n_lval+2, rnames[l->n_rval]); break; default: comperr("bad zzzcode %c", c); } } /*ARGSUSED*/ int rewfld(NODE *p) { return(1); } int canaddr(NODE *); int canaddr(NODE *p) { int o = p->n_op; if (o==NAME || o==REG || o==ICON || o==OREG || (o==UMUL && shumul(p->n_left, SOREG) == SRDIR)) return(1); return(0); } int fldexpand(NODE *p, int cookie, char **cp) { return 0; } /* * Does the bitfield shape match? */ int flshape(NODE *p) { int o = p->n_op; if (o == OREG || o == REG || o == NAME) return SRDIR; /* Direct match */ if (o == UMUL && shumul(p->n_left, SOREG)) return SROREG; /* Convert into oreg */ return SRREG; /* put it into a register */ } /* INTEMP shapes must not contain any temporary registers */ /* XXX should this go away now? */ int shtemp(NODE *p) { return 0; } void adrcon(CONSZ val) { printf("$" CONFMT, val); } void conput(FILE *fp, NODE *p) { int val = p->n_lval; switch (p->n_op) { case ICON: if (p->n_name[0] != '\0') { fprintf(fp, "%s", p->n_name); if (val) fprintf(fp, "+%d", val); } else fprintf(fp, "%d", val); return; default: comperr("illegal conput"); } } /*ARGSUSED*/ void insput(NODE *p) { comperr("insput"); } /* * Write out the upper address, like the upper register of a 2-register * reference, or the next memory location. */ void upput(NODE *p, int size) { size /= SZINT; switch (p->n_op) { case REG: printf("%s", rnames[p->n_rval + 1]); break; case NAME: case OREG: p->n_lval += size; adrput(stdout, p); p->n_lval -= size; break; case ICON: printf("#" CONFMT, p->n_lval >> 16); break; default: comperr("upput bad op %d size %d", p->n_op, size); } } void adrput(FILE *io, NODE *p) { /* output an address, with offsets, from p */ if (p->n_op == FLD) p = p->n_left; switch (p->n_op) { case NAME: if (p->n_name[0] != '\0') fputs(p->n_name, io); if (p->n_lval != 0) fprintf(io, "+" CONFMT, p->n_lval); return; case OREG: if (p->n_lval) fprintf(io, "%d", (int)p->n_lval); fprintf(io, "[%s]", rnames[p->n_rval]); return; case ICON: /* addressable value of the constant */ fputc('#', io); conput(io, p); return; case REG: /*if (DEUNSIGN(p->n_type) == CHAR) { fprintf(io, "R%c%c", p->n_rval < 2 ? '0' : '1', (p->n_rval & 1) ? 'H' : 'L'); } else*/ fprintf(io, "%s", rnames[p->n_rval]); return; default: comperr("illegal address, op %d, node %p", p->n_op, p); return; } } static char * ccbranches[] = { "jeq", /* jumpe */ "jne", /* jumpn */ "jle", /* jumple */ "jlt", /* jumpl */ "jge", /* jumpge */ "jgt", /* jumpg */ "jleu", /* jumple (jlequ) */ "jltu", /* jumpl (jlssu) */ "jgeu", /* jumpge (jgequ) */ "jgtu", /* jumpg (jgtru) */ }; /* printf conditional and unconditional branches */ void cbgen(int o, int lab) { if (o < EQ || o > UGT) comperr("bad conditional branch: %s", opst[o]); printf(" %s " LABFMT "\n", ccbranches[o-EQ], lab); } void mycanon(NODE *p) { } void myoptim(struct interpass *ip) { } #if 0 void mygenregs(NODE *p) { if (p->n_op == MINUS && p->n_type == DOUBLE && (p->n_su & (LMASK|RMASK)) == (LREG|RREG)) { p->n_su |= DORIGHT; } /* Must walk down correct node first for logops to work */ if (p->n_op != CBRANCH) return; p = p->n_left; if ((p->n_su & (LMASK|RMASK)) != (LREG|RREG)) return; p->n_su &= ~DORIGHT; } #endif struct hardops hardops[] = { { PLUS, FLOAT, "?F_ADD_L04" }, { MUL, LONG, "?L_MUL_L03" }, { MUL, ULONG, "?L_MUL_L03" }, { DIV, LONG, "?SL_DIV_L03" }, { DIV, ULONG, "?UL_DIV_L03" }, { MOD, LONG, "?SL_MOD_L03" }, { MOD, ULONG, "?UL_MOD_L03" }, { RS, LONGLONG, "__ashrdi3" }, { RS, ULONGLONG, "__lshrdi3" }, { LS, LONGLONG, "__ashldi3" }, { LS, ULONGLONG, "__ashldi3" }, { 0 }, }; int special(NODE *p, int shape) { switch (shape) { case SFTN: if (ISPTR(p->n_type) && ISFTN(DECREF(p->n_type))) { if (p->n_op == NAME || p->n_op == OREG) return SRDIR; else return SRREG; } break; } return SRNOPE; } void myreader(NODE *p) { NODE *q, *r, *s, *right; if (optype(p->n_op) == LTYPE) return; if (optype(p->n_op) != UTYPE) myreader(p->n_right); myreader(p->n_left); switch (p->n_op) { case PLUS: case MINUS: if (p->n_type != LONG && p->n_type != ULONG) break; if (p->n_right->n_op == NAME || p->n_right->n_op == OREG) break; /* Must convert right into OREG */ right = p->n_right; q = mklnode(OREG, (freetemp(szty(right->n_type))), FPREG, right->n_type); s = mkbinode(ASSIGN, q, right, right->n_type); r = talloc(); *r = *q; p->n_right = r; pass2_compile(ipnode(s)); break; } } void rmove(int s, int d, TWORD t) { switch (t) { case CHAR: case UCHAR: printf(" mov.b %s,%s\n", rnames[s], rnames[d]); break; default: printf(" mov.w %s,%s\n", rnames[s], rnames[d]); } } /* * For class c, find worst-case displacement of the number of * registers in the array r[] indexed by class. */ int COLORMAP(int c, int *r) { int num; switch (c) { case CLASSA: num = r[CLASSA]; num += r[CLASSC]; return num < 4; case CLASSB: num = r[CLASSB]; return num < 2; case CLASSC: num = 2*r[CLASSA]; num += r[CLASSC]; return num < 4; } return 0; /* XXX gcc */ } /* * Return a class suitable for a specific type. */ int gclass(TWORD t) { if (t == CHAR || t == UCHAR) return CLASSC; if(ISPTR(t)) return CLASSB; return CLASSA; } static int sizen; /* XXX: Fix this. */ static int argsiz(NODE *p) { TWORD t = p->n_type; if (t < LONGLONG || t > MAXTYPES) return 4; if (t == LONGLONG || t == ULONGLONG || t == DOUBLE) return 8; if (t == LDOUBLE) return 12; if (t == STRTY) return attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0); comperr("argsiz"); return 0; } /* * Calculate argument sizes. * XXX: Fix this. */ void lastcall(NODE *p) { sizen = 0; for (p = p->n_right; p->n_op == CM; p = p->n_left) sizen += argsiz(p->n_right); sizen += argsiz(p); } /* * Target-dependent command-line options. */ void mflags(char *str) { } /* * Do something target-dependent for xasm arguments. * Supposed to find target-specific constraints and rewrite them. */ int myxasm(struct interpass *ip, NODE *p) { return 0; } pcc-20181216/arch/m16c/macdefs.h010064400017500000000000000122231266660034000147250ustar raggewheel/* $Id: macdefs.h,v 1.27 2016/03/05 15:53:04 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Machine-dependent defines for both passes. */ #define makecc(val,i) lastcon = (lastcon<<8)|((val<<8)>>8); #define ARGINIT 40 /* # bits above fp where arguments start */ #define AUTOINIT 0 /* # bits below fp where automatics start */ /* * Convert (multi-)character constant to integer. * Assume: If only one value; store at left side (char size), otherwise * treat it as an integer. */ /* * Storage space requirements */ #define SZCHAR 8 #define SZINT 16 #define SZFLOAT 16 #define SZDOUBLE 16 #define SZLDOUBLE 16 #define SZLONG 32 #define SZSHORT 16 #define SZLONGLONG 32 /* pointers are of different sizes on m16c */ #define SZPOINT(t) (ISFTN(DECREF(t)) ? 32 : 16) /* * Alignment constraints */ #define ALCHAR 8 #define ALINT 16 #define ALFLOAT 16 #define ALDOUBLE 16 #define ALLDOUBLE 16 #define ALLONG 16 #define ALLONGLONG 16 #define ALSHORT 16 #define ALPOINT 16 #define ALSTRUCT 16 #define ALSTACK 16 /* * Min/max values. */ #define MIN_CHAR -128 #define MAX_CHAR 127 #define MAX_UCHAR 255 #define MIN_SHORT -32768 #define MAX_SHORT 32767 #define MAX_USHORT 65535 #define MIN_INT -32768 #define MAX_INT 32767 #define MAX_UNSIGNED 65535 #define MIN_LONG -2147483648 #define MAX_LONG 2147483647 #define MAX_ULONG 4294967295UL #define MIN_LONGLONG -2147483648 #define MAX_LONGLONG 2147483647 #define MAX_ULONGLONG 4294967295UL /* Default char is unsigned */ #undef CHAR_UNSIGNED /* * Use large-enough types. */ typedef long long CONSZ; typedef unsigned long long U_CONSZ; typedef long long OFFSZ; #define CONFMT "%lld" /* format for printing constants */ #define LABFMT "L%d" /* format for printing labels */ #define BACKAUTO /* stack grows negatively for automatics */ #define BACKTEMP /* stack grows negatively for temporaries */ #undef FIELDOPS /* no bit-field instructions */ #define TARGET_ENDIAN TARGET_LE /* Definitions mostly used in pass2 */ #define BYTEOFF(x) 1 #define STOARG(p) #define STOFARG(p) #define STOSTARG(p) #define genfcall(a,b) gencall(a,b) #define szty(t) (((t) == LONG || (t) == ULONG || \ (ISPTR(t) && ISFTN(DECREF(t)))) ? 2 : 1) /* * m16c register classes: * A - 16-bit data registers R0-R3 * B - 16-bit address registers A0-A1 * C - 8-bit data registers R0H, R0L, R1H, R1L */ #define R0 0 #define R2 1 #define R1 2 #define R3 3 #define A0 4 #define A1 5 #define FB 6 #define SP 7 #define R0H 8 #define R0L 9 #define R1H 10 #define R1L 11 #define NUMCLASS 4 /* Number of register classes */ #define RETREG(x) (x == CHAR || x == UCHAR ? R0L : R0) #define FPREG FB /* frame pointer */ #define STKREG SP /* stack pointer */ #if 0 #define REGSZ 8 /* Number of registers */ #define MINRVAR R1 /* first register variable */ #define MAXRVAR R2 /* last register variable */ #endif #define MAXREGS 12 /* 12 registers */ #define RSTATUS \ SAREG|TEMPREG, SAREG|PERMREG, SAREG|TEMPREG, SAREG|PERMREG, \ SBREG|TEMPREG, SBREG|PERMREG, 0, 0, SCREG, SCREG, SCREG, SCREG, #define ROVERLAP \ {R0H, R0L, -1},\ {-1},\ {R1H, R1L, -1},\ {-1},\ \ {-1},\ {-1},\ \ {-1},\ {-1},\ \ {R0, -1},\ {R0, -1},\ {R1, -1},\ {R1, -1}, #define PCLASS(p) (p->n_type <= UCHAR ? SCREG : ISPTR(p->n_type) ? SBREG:SAREG) int COLORMAP(int c, int *r); #define GCLASS(x) (x < 4 ? CLASSA : x < 6 ? CLASSB : x < 12 ? CLASSC : CLASSD) #define DECRA(x,y) (((x) >> (y*6)) & 63) /* decode encoded regs */ #define ENCRD(x) (x) /* Encode dest reg in n_reg */ #define ENCRA1(x) ((x) << 6) /* A1 */ #define ENCRA2(x) ((x) << 12) /* A2 */ #define ENCRA(x,y) ((x) << (6+y*6)) /* encode regs in int */ #define MYADDEDGE(x, t) #ifndef NEW_READER //#define TAILCALL #endif #define SFTN (SPECIAL|6) pcc-20181216/arch/m16c/order.c010064400017500000000000000326641234260774600144540ustar raggewheel/* $Id: order.c,v 1.22 2014/06/01 11:35:02 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass2.h" # include int canaddr(NODE *); /* * should the assignment op p be stored, * given that it lies as the right operand of o * (or the left, if o==UNARY MUL) */ /* void stoasg(NODE *p, int o) { if (x2debug) printf("stoasg(%p, %o)\n", p, o); } */ /* should we delay the INCR or DECR operation p */ int deltest(NODE *p) { return 0; } /* * Check if p can be autoincremented. * XXX - nothing can be autoincremented for now. */ int autoincr(NODE *p) { return 0; } /* is it legal to make an OREG or NAME entry which has an * offset of off, (from a register of r), if the * resulting thing had type t */ int notoff(TWORD t, int r, CONSZ off, char *cp) { return(0); /* YES */ } /* * Turn a UMUL-referenced node into OREG. */ int offstar(NODE *p, int shape) { if (x2debug) printf("offstar(%p)\n", p); if( p->n_op == PLUS || p->n_op == MINUS ){ if( p->n_right->n_op == ICON ){ geninsn(p->n_left, INBREG); p->n_su = -1; return 1; } } geninsn(p, INBREG); return 0; } /* * Shape matches for UMUL. Cooperates with offstar(). */ int shumul(NODE *p, int shape) { // NODE *l = p->n_left; #ifdef PCC_DEBUG if (x2debug) { printf("shumul(%p)\n", p); fwalk(p, e2print, 0); } #endif /* XXX - fix */ /* Can only generate OREG of BREGs (or FB) */ if (p->n_op == REG && (isbreg(p->n_rval) || p->n_rval == FB)) return SROREG; #if 0 if ((p->n_op == PLUS || p->n_op == MINUS) && (l->n_op == REG && (isbreg(l->n_rval) || l->n_rval == FB)) && p->n_right->n_op == ICON) return SOREG; return 0; #else return SROREG; #endif } /* * Rewrite increment/decrement operation. */ int setincr(NODE *p) { if (x2debug) printf("setincr(%p)\n", p); return(0); } /* * Rewrite operations on binary operators (like +, -, etc...). * Called as a result of table lookup. */ int setbin(NODE *p) { if (x2debug) printf("setbin(%p)\n", p); return 0; } /* setup for assignment operator */ int setasg(NODE *p, int cookie) { if (x2debug) printf("setasg(%p)\n", p); return(0); } /* setup for unary operator */ int setuni(NODE *p, int cookie) { return 0; } #if 0 /* * register allocation for instructions with special preferences. */ regcode regalloc(NODE *p, struct optab *q, int wantreg) { regcode regc; if (q->op == DIV || q->op == MOD) { /* * 16-bit div. */ if (regblk[R0] & 1 || regblk[R2] & 1) comperr("regalloc: needed regs inuse, node %p", p); if (p->n_su & DORIGHT) { regc = alloregs(p->n_right, A0); if (REGNUM(regc) != A0) { p->n_right = movenode(p->n_right, A0); if ((p->n_su & RMASK) == ROREG) { p->n_su &= ~RMASK; p->n_su |= RREG; p->n_right->n_su &= ~LMASK; p->n_right->n_su |= LOREG; } freeregs(regc); regblk[A0] |= 1; } } regc = alloregs(p->n_left, R0); if (REGNUM(regc) != R0) { p->n_left = movenode(p->n_left, R0); freeregs(regc); regblk[R0] |= 1; } if ((p->n_su & RMASK) && !(p->n_su & DORIGHT)) { regc = alloregs(p->n_right, A0); if (REGNUM(regc) != A0) { p->n_right = movenode(p->n_right, A0); if ((p->n_su & RMASK) == ROREG) { p->n_su &= ~RMASK; p->n_su |= RREG; p->n_right->n_su &= ~LMASK; p->n_right->n_su |= LOREG; } } } regblk[A0] &= ~1; regblk[R0] &= ~1; regblk[R2] &= ~1; if (q->op == DIV) { MKREGC(regc, R0, 1); regblk[R0] |= 1; } else { MKREGC(regc, R2, 1); regblk[R2] |= 1; } } else comperr("regalloc"); p->n_rall = REGNUM(regc); return regc; } #endif /* * Special handling of some instruction register allocation. * - left is the register that left node wants. * - right is the register that right node wants. * - res is in which register the result will end up. * - mask is registers that will be clobbered. * * XXX - Fix this function */ struct rspecial * nspecial(struct optab *q) { switch (q->op) { case DIV: case MOD: if(q->ltype & (TINT|TSHORT)){ static struct rspecial s[] = { { NRES, R0 }, { NRES, R2}, { 0 } }; return s; } /* else if(q->ltype & TCHAR) { static struct rspecial s[] = { { NRES, R0L }, { NRES, R0H}, { 0 } }; return s; }*/ break; case MUL: /* if(q->ltype & (TINT|TSHORT)){ static struct rspecial s[] = { { NRES, R0 }, { NRES, R2}, { 0 } }; return s; }*/ comperr("multiplication not implemented"); break; default: break; } comperr("nspecial entry %d", q - table); return 0; /* XXX gcc */ } /* * Splitup a function call and give away its arguments first. * Calling convention used ("normal" in IAR syntax) is: * - 1-byte parameters in R0L if possible, otherwise in R0H. * - 2-byte pointers in A0. * - 2-byte non-pointers in R0 if no byte-size arguments are found in * in the first 6 bytes of parameters, otherwise R2 or at last A0. * - 4-byte parameters in R2R0. */ void gencall(NODE *p, NODE *prev) { NODE *n = 0; /* XXX gcc */ static int storearg(NODE *); int o = p->n_op; int ty = optype(o); if (ty == LTYPE) return; switch (o) { case CALL: /* swap arguments on some hardop-converted insns */ /* Normal call, just push args and be done with it */ p->n_op = UCALL; //printf("call\n"); /* Check if left can be evaluated directly */ if (p->n_left->n_op == UMUL) { TWORD t = p->n_left->n_type; int k = (freetemp(szty(t))); NODE *n = mklnode(OREG, k, FB, t); NODE *q = tcopy(n); pass2_compile(ipnode(mkbinode(ASSIGN, n, p->n_left,t))); p->n_left = q; } gencall(p->n_left, p); p->n_rval = storearg(p->n_right); //printf("end call\n"); break; case UFORTCALL: case FORTCALL: comperr("FORTCALL"); case USTCALL: case STCALL: /* * Structure return. Look at the node above * to decide about buffer address: * - FUNARG, allocate space on stack, don't remove. * - nothing, allocate space on stack and remove. * - STASG, get the address of the left side as arg. * - FORCE, this ends up in a return, get supplied addr. * (this is not pretty, but what to do?) */ if (prev == NULL || prev->n_op == FUNARG) { /* Create nodes to generate stack space */ n = mkbinode(ASSIGN, mklnode(REG, 0, STKREG, INT), mkbinode(MINUS, mklnode(REG, 0, STKREG, INT), mklnode(ICON, p->n_stsize, 0, INT), INT), INT); //printf("stsize %d\n", p->n_stsize); pass2_compile(ipnode(n)); } else if (prev->n_op == STASG) { n = prev->n_left; if (n->n_op == UMUL) n = nfree(n); else if (n->n_op == NAME) { n->n_op = ICON; /* Constant reference */ n->n_type = INCREF(n->n_type); } else comperr("gencall stasg"); } else if (prev->n_op == FORCE) { ; /* do nothing here */ } else { comperr("gencall bad op %d", prev->n_op); } /* Deal with standard arguments */ gencall(p->n_left, p); if (o == STCALL) { p->n_op = USTCALL; p->n_rval = storearg(p->n_right); } else p->n_rval = 0; /* push return struct address */ if (prev == NULL || prev->n_op == FUNARG) { n = mklnode(REG, 0, STKREG, INT); if (p->n_rval) n = mkbinode(PLUS, n, mklnode(ICON, p->n_rval, 0, INT), INT); pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT))); if (prev == NULL) p->n_rval += p->n_stsize/4; } else if (prev->n_op == FORCE) { /* return value for this function */ n = mklnode(OREG, 8, FPREG, INT); pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT))); p->n_rval++; } else { pass2_compile(ipnode(mkunode(FUNARG, n, 0, INT))); n = p; *prev = *p; nfree(n); } //printf("end stcall\n"); break; default: if (ty != UTYPE) gencall(p->n_right, p); gencall(p->n_left, p); break; } } /* * Create separate node trees for function arguments. * This is partly ticky, the strange calling convention * may cause a bunch of code reorganization here. */ static int storearg(NODE *p) { NODE *n, *q, **narry; int nch, k, i, nn, rary[4]; int r0l, r0h, r2, a0, stk, sz; TWORD t; int maxrargs = 0; if (p->n_op == CM) maxrargs = p->n_stalign; /* count the arguments */ for (i = 1, q = p; q->n_op == CM; q = q->n_left) i++; nn = i; /* allocate array to store arguments */ narry = tmpalloc(sizeof(NODE *)*nn); /* enter nodes into array */ for (q = p; q->n_op == CM; q = q->n_left) narry[--i] = q->n_right; narry[--i] = q; /* free CM nodes */ for (q = p; q->n_op == CM; ) { n = q->n_left; nfree(q); q = n; } /* count char args */ r0l = r0h = r2 = a0 = 0; for (sz = nch = i = 0; i < nn && i < 6; i++) { TWORD t = narry[i]->n_type; if (sz >= 6) break; if (t == CHAR || t == UCHAR) { nch++; sz++; } else if ((t >= SHORT && t <= UNSIGNED) || t > BTMASK || t == FLOAT) { sz += 2; } else /* long, double */ sz += 4; } /* * Now the tricky part. The parameters that should be on stack * must be found and pushed first, then the register parameters. * For the latter, be sure that evaluating them do not use any * registers where argument values already are inserted. * XXX - function pointers? * XXX foo(long a, char b) ??? */ for (stk = 0; stk < 4; stk++) { TWORD t; if (stk == nn) break; t = narry[stk]->n_type; if (ISFTN(DECREF(t))) t = LONG; switch (t) { case CHAR: case UCHAR: if (r0l) { if (r0h) break; rary[stk] = R2; /* char talk for 'R0H' */ r0h = 1; } else { rary[stk] = R0; r0l = 1; } continue; case INT: case UNSIGNED: if (r0l || nch) { if (r2) { if (a0) break; rary[stk] = A0; a0 = 1; } else { rary[stk] = R2; r2 = 1; } } else { rary[stk] = R0; r0l = r0h = 1; } continue; case LONG: case ULONG: if (r0l || r2) break; rary[stk] = R0; r0l = r0h = r2 = 1; continue; default: if (ISPTR(narry[stk]->n_type) && !ISFTN(DECREF(narry[stk]->n_type))) { if (a0) { if (r0l || nch) { if (r2) break; rary[stk] = R2; r2 = 1; } else { rary[stk] = R0; r0l = r0h = 1; } } else { rary[stk] = A0; a0 = 1; } continue; } break; } break; } /* * The arguments that must be on stack are stk->nn args. * Argument 0->stk-1 should be put in the rary[] register. */ for (sz = 0, i = nn-1; i >= stk; i--) { /* first stack args */ NODE nod; pass2_compile(ipnode(mkunode(FUNARG, narry[i], 0, narry[i]->n_type))); nod.n_type = narry[i]->n_type; sz += tlen(&nod); } /* if param cannot be addressed directly, evaluate and put on stack */ for (i = 0; i < stk; i++) { if (canaddr(narry[i])) continue; t = narry[i]->n_type; k = (freetemp(szty(t))); n = mklnode(OREG, k, FB, t); q = tcopy(n); pass2_compile(ipnode(mkbinode(ASSIGN, n, narry[i], t))); narry[i] = q; } /* move args to registers */ for (i = 0; i < stk; i++) { t = narry[i]->n_type; pass2_compile(ipnode(mkbinode(ASSIGN, mklnode(REG, 0, rary[i], t), narry[i], t))); } return sz; } /* * Tell if a register can hold a specific datatype. */ #if 0 int mayuse(int reg, TWORD type) { return 1; /* Everything is OK */ } #endif #ifdef TAILCALL void mktailopt(struct interpass *ip1, struct interpass *ip2) { extern int earlylab; extern char *cftname; char *fn; NODE *p; p = ip1->ip_node->n_left->n_left; if (p->n_op == ICON) { fn = p->n_name; /* calling ourselves */ p = ip1->ip_node->n_left; if (p->n_op == CALL) { if (storearg(p->n_right)) comperr("too many args: fix mktailopt"); p->n_op = UCALL; } tfree(ip1->ip_node); p = ip2->ip_node->n_left; if (strcmp(fn, cftname)) { /* Not us, must generate fake prologue */ ip1->type = IP_ASM; ip1->ip_asm = "\tmov.w FB,SP\n\tpop.w FB\n"; pass2_compile(ip1); p->n_lval = p->n_rval = 0; p->n_name = fn; } else p->n_lval = earlylab; } else { pass2_compile(ip1); } pass2_compile(ip2); } #endif /* * Set registers "live" at function calls (like arguments in registers). * This is for liveness analysis of registers. */ int * livecall(NODE *p) { static int r[1] = { -1 }; /* Terminate with -1 */ return &r[0]; } /* * Signal whether the instruction is acceptable for this target. */ int acceptable(struct optab *op) { return 1; } pcc-20181216/arch/m16c/table.c010064400017500000000000000246351157264212200144160ustar raggewheel/* $Id: table.c,v 1.35 2011/06/05 08:54:42 plunky Exp $ */ #include "pass2.h" # define ANYSIGNED TINT|TLONG|TCHAR # define ANYUSIGNED TUNSIGNED|TULONG|TUCHAR # define ANYFIXED ANYSIGNED|ANYUSIGNED # define TL TLONG|TULONG # define TWORD TUNSIGNED|TINT # define TCH TCHAR|TUCHAR struct optab table[] = { /* First entry must be an empty entry */ { -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", }, /* (signed) char -> int/pointer */ { SCONV, INAREG, SCREG, TCHAR, SANY, TINT|TPOINT, NAREG, RESC1, " mov.b AL, A1\n\texts.b A1\n", }, /* (unsigned) char -> int/pointer */ { SCONV, INAREG, SCREG, TUCHAR, SANY, TINT|TPOINT, NAREG, RESC1, " mov.b AL, A1\n", }, /* unsigned char -> long */ { SCONV, INAREG, SCREG, TUCHAR, SANY, TL, NAREG|NASL, RESC1, " mov.b AL, A1\n mov.w #0,U1\n", }, /* int or pointer -> (unsigned) long */ { SCONV, INAREG, SAREG|SNAME, TWORD|TPOINT, SANY, TL, NAREG|NASL, RESC1, " mov.w AL,A1\n mov.w #0,U1\n", }, /* char -> (signed) long */ { SCONV, INAREG, SAREG|SNAME, TCHAR, SANY, TLONG, NAREG|NASL, RESC1, " exts.b AL\n exts.w AL\n", }, /* long -> ulong */ { SCONV, INAREG, SAREG, TL, SANY, TL, 0, RLEFT, "", }, /* long -> int or pointer */ { SCONV, INAREG, SAREG|SOREG|SNAME, TL, SANY, TWORD|TPOINT, NAREG|NASL, RESC1, " mov.w AL,A1\n", }, /* int -> char */ { SCONV, INCREG, SAREG, TWORD, SANY, TCH, NCREG, RESC1, " mov.b AL, A1\n", }, /* int -> long */ { SCONV, INAREG, SAREG, TWORD, SANY, TLONG, NAREG|NASL, RESC1, " exts.w AL", }, /* long -> char */ { SCONV, INAREG, SAREG, TL, SANY, TCH, NAREG|NASL, RESC1, "", }, { SCONV, INAREG, SAREG, TPOINT, SANY, TWORD, 0, RLEFT, "", }, { PLUS, INAREG|FOREFF, SAREG, TL, SCON|SNAME|SOREG, TL, 0, RLEFT, " add.w AR,AL\n adc.w UR,UL\n", }, { MINUS, INAREG|FOREFF, SAREG, TL, SCON|SNAME|SOREG, TL, 0, RLEFT, " sub.w AR,AL\n sbb.w UR,UL\n", }, { AND, INAREG|FOREFF, SAREG, TL, SAREG|SNAME|SOREG, TL, 0, RLEFT, " and.w AR,AL\n and.w UR,UL\n", }, { ER, INAREG|FOREFF, SAREG, TL, SAREG|SNAME|SOREG, TL, 0, RLEFT, " xor.w AR,AL\n xor.w UR,UL\n", }, { OR, INAREG|FOREFF, SAREG, TL, SAREG|SNAME|SOREG, TL, 0, RLEFT, " xor.w AR,AL\n xor.w UR,UL\n", }, { COMPL, INAREG|FOREFF, SAREG, TL, SAREG|SNAME|SOREG, TL, 0, RLEFT, " not.w AR,AL\n not.w UR,UL\n", }, { OPSIMP, INAREG|FOREFF, SAREG, TWORD|TPOINT, SAREG|SNAME|SOREG|SCON, TWORD|TPOINT, 0, RLEFT, " Ow AR,AL\n", }, /* XXX - Is this rule really correct? Having a SAREG shape seems kind of strange. Doesn't work. Gives a areg as A1. */ #if 0 { OPSIMP, INBREG, SAREG, TWORD|TPOINT, SAREG|SBREG|SNAME|SOREG|SCON, TWORD|TPOINT, NBREG, RESC1, " ++Ow AR,A1\n", }, #endif { OPSIMP, INBREG, SBREG, TWORD|TPOINT, SAREG|SBREG|SNAME|SOREG|SCON, TWORD|TPOINT, 0, RLEFT, " Ow AR,AL\n", }, { OPSIMP, INCREG|FOREFF, SCREG, TCH, SCREG|SNAME|SOREG|SCON, TCH, 0, RLEFT, " Ob AR,AL\n", }, /* XXX - Do these work? check nspecial in order.c */ /* signed integer division */ { DIV, INAREG, SAREG, TINT, SAREG|SNAME|SOREG, TWORD, /*2*NAREG|NASL|*/NSPECIAL, RLEFT, " div.w AR\n mov.w r0,AL\n", }, // " xor.w r2\n div.w AR\n", }, /* signed integer/char division - separate entry for FOREFF */ { DIV, FOREFF, SAREG, TINT, SAREG|SNAME|SOREG, TWORD, 0, 0, "", }, #if 0 /* signed char division */ { DIV, INCREG, SCREG, TCHAR, SCREG|SNAME|SOREG, TCH, 2*NCREG|NCSL|NSPECIAL, RLEFT, " div.b AR\n\tmov.b r0l,AL\n", }, // " xor.w r2\n div.w AR\n", }, #endif /* signed integer modulus, equal to above */ { MOD, INAREG, SAREG, TINT, SAREG|SNAME|SOREG, TWORD, /*2*NAREG|NASL|*/NSPECIAL, RLEFT, " div.w AR\n\tmov r2,AL\n", }, /* signed integer modulus - separate entry for FOREFF */ { MOD, FOREFF, SAREG, TINT, SAREG|SNAME|SOREG, TWORD, 0, 0, "", }, /* signed integer multiplication */ { MUL, INAREG, SAREG, TINT, SAREG|SNAME|SOREG, TWORD, 2*NAREG|NASL|NSPECIAL, RESC1, " mul.w AL,AR\n", }, { MUL, FOREFF, SAREG, TINT, SAREG|SNAME|SOREG, TWORD, 0, 0, "", }, #if 0 { LS, INAREG, SAREG, TWORD, SCON, TANY, 0, RLEFT, " shl.w AR,AL\n", }, #endif { LS, INAREG, SAREG, TWORD, SAREG, TWORD, 0, RLEFT, " push.b r1h\n" " mov.b AR,r1h\n" " shl.w r1h,AL\n" " pop.b r1h\n", }, { LS, INAREG, SAREG, TL, SAREG, TWORD, 0, RLEFT, " push.b r1h\n" " mov.b AR,r1h\n" " shl.l r1h,ZG\n" " pop.b r1h\n", }, { RS, INAREG, SAREG, TWORD, SAREG, TWORD, 0, RLEFT, " push.b r1h\n" " mov.b AR,r1h\n" " neg.b r1h\n" " shl.w r1h,AL\n" " pop.b r1h\n", }, { RS, INAREG, SAREG, TL, SAREG, TWORD, 0, RLEFT, " push.b r1h\n" " mov.b AR,r1h\n" " neg.b r1h\n" " shl.l r1h,ZG\n" " pop.b r1h\n", }, #if 0 { RS, INAREG, SAREG, TUNSIGNED, SCON, TANY, 0, RLEFT, " shl ZA,AL\n", }, { RS, INAREG, SAREG, TINT, SCON, TANY, 0, RLEFT, " sha ZA,AL\n", }, #endif { OPLOG, FORCC, SAREG|SBREG|SOREG|SNAME, TL, SAREG|SBREG|SOREG|SNAME, TL, 0, 0, "ZF", }, { OPLOG, FORCC, SBREG|SOREG, TWORD|TPOINT, SCON, TWORD|TPOINT, 0, RESCC, " cmp.w AR,AL\n", }, { OPLOG, FORCC, SAREG|SBREG|SOREG|SNAME, TWORD|TPOINT, SAREG|SBREG|SOREG|SNAME, TWORD|TPOINT, 0, RESCC, " cmp.w AR,AL\n", }, { OPLOG, FORCC, SCREG|SOREG|SNAME, TCH, SCREG|SOREG|SNAME, TCH, 0, RESCC, " cmp.b AR,AL\n", }, { OPLOG, FORCC, SCREG|SOREG|SNAME, TCH, SCREG|SOREG|SNAME, TCH, 0, RESCC, " cmp.b AR,AL\n", }, { GOTO, FOREFF, SCON, TANY, SANY, TANY, 0, RNOP, " jmp.w ZC\n", }, { OPLTYPE, INAREG, SANY, TANY, SCON|SNAME|SOREG|SAREG, TL|TFTN, NAREG, RESC1, " mov.w AR,A1\n mov.w UR,U1\n", }, { OPLTYPE, INAREG, SANY, TANY, SCON|SNAME|SOREG|SAREG|SBREG, TWORD|TPOINT, NAREG, RESC1, " mov.w AR,A1\n", }, { OPLTYPE, INBREG, SANY, TANY, SBREG|SCON|SNAME|SOREG|SAREG, TWORD|TPOINT, NBREG, RESC1, " mov.w AR,A1\n", }, /* { OPLTYPE, INAREG, SANY, TANY, SCON|SNAME|SOREG, TCH, NAREG, RESC1, " mov.b AR, A1\n", }, { OPLTYPE, INBREG, SANY, TANY, SCON|SNAME|SOREG, TCHAR|TUCHAR, NBREG, RESC1, " mov.b AR,A1\n", }, */ { OPLTYPE, INCREG, SANY, TANY, SCON|SNAME|SOREG, TCHAR|TUCHAR, NCREG, RESC1, " mov.b AR,A1\n", }, { COMPL, INAREG, SAREG, TWORD, SANY, TANY, 0, RLEFT, " not.w AL\n", }, { COMPL, INCREG, SCREG, TCH, SANY, TANY, 0, RLEFT, " not.b AL\n", }, /* Push function address */ { FUNARG, FOREFF, SCON, TFTN, SANY, TANY, 0, RNULL, "ZH", }, { FUNARG, FOREFF, SOREG, TFTN, SANY, TANY, 0, RNULL, "ZI", }, { FUNARG, FOREFF, SNAME|SAREG, TL|TFTN, SANY, TANY, 0, RNULL, " push.w UL\n push.w AL\n", }, { FUNARG, FOREFF, SCON|SAREG|SNAME|SOREG, TWORD|TPOINT, SANY, TANY, 0, RNULL, " push.w AL\n", }, { FUNARG, FOREFF, SAREG|SNAME|SOREG, TCHAR|TUCHAR, SANY, TANY, 0, RNULL, " push.b AL\n", }, /* Match function pointers first */ #if 0 { ASSIGN, FOREFF, SFTN, TWORD|TPOINT, SFTN, TWORD|TPOINT, NAREG, 0, "ZD", }, #endif { ASSIGN, INAREG, SAREG, TFTN, SCON, TFTN, 0, RLEFT, "ZD", }, { ASSIGN, INBREG, SBREG, TFTN, SCON, TFTN, 0, RLEFT, "ZD", }, { ASSIGN, INAREG, SAREG, TFTN, SBREG|SAREG|SOREG|SNAME, TFTN, 0, RLEFT, " mov.w AR,AL\n mov.w UR,UL\n", }, { ASSIGN, INBREG, SBREG, TFTN, SBREG|SAREG|SOREG|SNAME, TFTN, 0, RLEFT, " mov.w AR,AL\n mov.w UR,UL\n", }, { ASSIGN, INAREG, SBREG|SAREG|SOREG|SNAME, TFTN, SAREG, TFTN, 0, RRIGHT, " mov.w AR,AL\n mov.w UR,UL\n", }, { ASSIGN, INBREG, SBREG|SAREG|SOREG|SNAME, TFTN, SBREG, TFTN, 0, RRIGHT, " mov.w AR,AL\n mov.w UR,UL\n", }, /* a reg -> a reg */ { ASSIGN, FOREFF|INAREG, SAREG, TWORD|TPOINT, SAREG, TWORD|TPOINT, 0, RLEFT, " mov.w AR,AL\n", }, { ASSIGN, INAREG, SBREG|SAREG|SOREG|SNAME, TL, SAREG, TL, 0, RRIGHT, " mov.w AR,AL\n mov.w UR,UL\n", }, { ASSIGN, INBREG, SBREG|SAREG|SOREG|SNAME, TL, SBREG, TL, 0, RRIGHT, " mov.w AR,AL\n mov.w UR,UL\n", }, { ASSIGN, FOREFF, SBREG|SAREG|SOREG|SNAME, TL, SCON|SBREG|SAREG|SOREG|SNAME, TL, 0, 0, " mov.w AR,AL\n mov.w UR,UL\n", }, { ASSIGN, INAREG|FOREFF, SAREG, TWORD|TPOINT, SCON, TANY, 0, RLEFT, " mov.w AR,AL\n", }, { ASSIGN, INBREG|FOREFF, SBREG, TWORD|TPOINT, SCON, TANY, 0, RLEFT, " mov.w AR,AL\n", }, { ASSIGN, FOREFF, SNAME|SOREG, TWORD|TPOINT, SCON, TANY, 0, 0, " mov.w AR,AL\n", }, /* char, oreg/name -> c reg */ { ASSIGN, FOREFF|INCREG, SCREG, TCHAR|TUCHAR, SOREG|SNAME|SCON, TCHAR|TUCHAR, 0, RLEFT, " mov.b AR,AL\n", }, /* int, oreg/name -> a reg */ { ASSIGN, FOREFF|INAREG, SAREG, TWORD|TPOINT, SOREG|SNAME, TWORD|TPOINT, 0, RLEFT, " mov.w AR,AL\n", }, { ASSIGN, FOREFF|INBREG, SBREG, TWORD|TPOINT, SOREG|SNAME, TWORD|TPOINT, 0, RLEFT, " mov.w AR,AL\n", }, { ASSIGN, FOREFF|INAREG, SOREG|SNAME, TWORD|TPOINT, SAREG, TWORD|TPOINT, 0, RRIGHT, " mov.w AR,AL\n", }, { ASSIGN, FOREFF|INBREG, SOREG|SNAME, TWORD|TPOINT, SBREG, TWORD|TPOINT, 0, RRIGHT, " mov.w AR,AL\n", }, { ASSIGN, FOREFF|INCREG, SOREG|SNAME, TCHAR|TUCHAR, SCREG, TCHAR|TUCHAR, 0, RRIGHT, " mov.b AR,AL\n", }, { ASSIGN, FOREFF|INCREG, SCREG, TCHAR|TUCHAR, SCREG, TCHAR|TUCHAR, 0, RRIGHT, " mov.b AR,AL\n", }, { ASSIGN, FOREFF|INBREG, SBREG, TWORD|TPOINT, SBREG, TWORD|TPOINT, 0, RRIGHT, " mov.w AR,AL\n", }, { UMUL, INAREG, SBREG, TPOINT|TWORD, SANY, TFTN, NAREG, RESC1, " mov.w [AL],A1\n mov.w 2[AL],U1\n", }, { UMUL, INAREG, SBREG, TPOINT|TWORD, SANY, TPOINT|TWORD, NAREG, RESC1, " mov.w [AL],A1\n", }, { UMUL, INBREG, SBREG, TPOINT|TWORD, SANY, TPOINT|TWORD, NBREG|NBSL, RESC1, " mov.w [AL],A1\n", }, { UMUL, INAREG, SBREG, TCHAR|TUCHAR|TPTRTO, SANY, TCHAR|TUCHAR, NAREG, RESC1, " mov.b [AL], A1\n", }, { UCALL, FOREFF, SCON, TANY, SANY, TANY, 0, 0, " jsr.w CL\nZB", }, { UCALL, INAREG, SCON, TANY, SANY, TANY, NAREG, RESC1, " jsr.w CL\nZB", }, { UCALL, INAREG, SNAME|SOREG, TANY, SANY, TANY, NAREG|NASL, RESC1, /* should be 0 */ " jsri.a AL\nZB", }, { UCALL, FOREFF, SNAME|SOREG, TANY, SANY, TANY, 0, 0, " jsri.a AL\nZB", }, { UCALL, INAREG, SBREG, TANY, SANY, TANY, NAREG|NASL, RESC1, /* should be 0 */ " jsri.a [AL]\nZB", }, { UCALL, FOREFF, SBREG, TANY, SANY, TANY, 0, 0, " jsri.a [AL]\nZB", }, { FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" }, }; int tablesize = sizeof(table)/sizeof(table[0]); pcc-20181216/arch/m68k004075500017500000000000000000001340533064000131105ustar raggewheelpcc-20181216/arch/m68k/CVS004075500017500000000000000000001340533064000135435ustar raggewheelpcc-20181216/arch/m68k/CVS/Root010064400017500000000000000000111340533064000144550ustar raggewheel/cvsroot pcc-20181216/arch/m68k/CVS/Repository010064400017500000000000000000161340533064000157160ustar raggewheelpcc/arch/m68k pcc-20181216/arch/m68k/CVS/Entries010064400017500000000000000003701340533064000151530ustar raggewheel/code.c/1.8/Sat Jan 30 17:26:19 2016// /local.c/1.17/Sun Dec 2 10:50:00 2018// /local2.c/1.18/Mon Sep 26 16:45:42 2016// /macdefs.h/1.12/Sun Dec 2 10:50:00 2018// /order.c/1.5/Sat Jan 30 17:26:19 2016// /table.c/1.13/Tue Oct 27 14:48:50 2015// D pcc-20181216/arch/m68k/code.c010064400017500000000000000156551265317107300142650ustar raggewheel/* $Id: code.c,v 1.8 2016/01/30 17:26:19 ragge Exp $ */ /* * Copyright (c) 2014 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass1.h" #ifdef LANG_CXX #define p1listf listf #define p1tfree tfree #else #define NODE P1ND #define talloc p1alloc #define tfree p1tfree #endif extern int gotnr; /* * Print out assembler segment name. */ void setseg(int seg, char *name) { switch (seg) { case PROG: name = ".text"; break; case DATA: case LDATA: name = ".data"; break; case STRNG: case RDATA: name = ".section .rodata"; break; case UDATA: break; case PICLDATA: case PICDATA: name = ".section .data.rel.rw,\"aw\",@progbits"; break; case PICRDATA: name = ".section .data.rel.ro,\"aw\",@progbits"; break; case TLSDATA: name = ".section .tdata,\"awT\",@progbits"; break; case TLSUDATA: name = ".section .tbss,\"awT\",@nobits"; break; case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break; case DTORS: name = ".section\t.dtors,\"aw\",@progbits"; break; case NMSEG: printf("\t.section %s,\"a%c\",@progbits\n", name, cftnsp ? 'x' : 'w'); return; } printf("\t%s\n", name); } /* * Define everything needed to print out some data (or text). * This means segment, alignment, visibility, etc. */ void defloc(struct symtab *sp) { char *name; name = getexname(sp); if (sp->sclass == EXTDEF) { printf("\t.globl %s\n", name); if (ISFTN(sp->stype)) { printf("\t.type %s,@function\n", name); } else { printf("\t.type %s,@object\n", name); printf("\t.size %s,%d\n", name, (int)tsize(sp->stype, sp->sdf, sp->sap)/SZCHAR); } } if (sp->slevel == 0) printf("%s:\n", name); else printf(LABFMT ":\n", sp->soffset); } /* * code for the end of a function * deals with struct return here * The return value is in (or pointed to by) RETREG. */ int sttemp; void efcode(void) { NODE *p, *q; gotnr = 0; if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) return; /* use stasg to get call to memcpy() */ p = buildtree(UMUL, tempnode(sttemp, INCREF(STRTY), cftnsp->sdf, cftnsp->sap), NIL); q = block(REG, 0, 0, INCREF(STRTY), cftnsp->sdf, cftnsp->sap); regno(q) = A0; q = buildtree(UMUL, q, NIL); p = buildtree(ASSIGN, p, q); ecomp(p); } /* * code for the beginning of a function; a is an array of * indices in symtab for the arguments; n is the number */ void bfcode(struct symtab **s, int cnt) { struct symtab *sp2; NODE *n, *p; int i; if (kflag) { /* PIC code */ /* Generate extended assembler for PIC prolog */ p = tempnode(0, CHAR|PTR, 0, 0); gotnr = regno(p); p = block(XARG, p, NIL, INT, 0, 0); p->n_name = "=r"; p = block(XASM, p, bcon(0), INT, 0, 0); p->n_name = "lea (%%pc,_GLOBAL_OFFSET_TABLE_@GOTPC),%0\n"; p->n_right->n_type = STRTY; ecomp(p); } if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { n = tempnode(0, INCREF(CHAR), 0, 0); p = block(REG, 0, 0, INCREF(CHAR), 0, 0); regno(p) = A0; sttemp = regno(n); ecomp(buildtree(ASSIGN, n, p)); } if (xtemps == 0) return; /* put arguments in temporaries */ for (i = 0; i < cnt; i++) { if (s[i]->stype == STRTY || s[i]->stype == UNIONTY || cisreg(s[i]->stype) == 0) continue; if (cqual(s[i]->stype, s[i]->squal) & VOL) continue; sp2 = s[i]; n = tempnode(0, s[i]->stype, s[i]->sdf, s[i]->sap); n = buildtree(ASSIGN, n, nametree(sp2)); s[i]->soffset = regno(n->n_left); s[i]->sflags |= STNODE; ecomp(n); } } /* called just before final exit */ /* flag is 1 if errors, 0 if none */ void ejobcode(int flag) { if (flag) return; printf("\t.ident \"PCC: %s\"\n", VERSSTR); } void bjobcode(void) { /* Set correct names for our types */ astypnames[SHORT] = astypnames[USHORT] = "\t.word"; astypnames[INT] = astypnames[UNSIGNED] = "\t.long"; } /* * Called with a function call with arguments as argument. * This is done early in buildtree() and only done once. * Returns p. */ NODE * funcode(NODE *p) { NODE *r, *l; /* Fix function call arguments. On m68k, just add funarg */ for (r = p->n_right; r->n_op == CM; r = r->n_left) { if (r->n_right->n_op != STARG) { r->n_right = intprom(r->n_right); r->n_right = block(FUNARG, r->n_right, NIL, r->n_right->n_type, r->n_right->n_df, r->n_right->n_ap); } } if (r->n_op != STARG) { l = talloc(); *l = *r; r->n_op = FUNARG; r->n_left = l; r->n_left = intprom(r->n_left); r->n_type = r->n_left->n_type; } return p; } /* fix up type of field p */ void fldty(struct symtab *p) { } /* * XXX - fix genswitch. */ int mygenswitch(int num, TWORD type, struct swents **p, int n) { return 0; } /* * Return return as given by a. */ NODE * builtin_return_address(const struct bitable *bt, NODE *a) { int nframes; NODE *f; cerror((char *)__func__); nframes = glval(a); tfree(a); f = block(REG, NIL, NIL, PTR+VOID, 0, 0); regno(f) = FPREG; while (nframes--) f = block(UMUL, f, NIL, PTR+VOID, 0, 0); f = block(PLUS, f, bcon(8), INCREF(PTR+VOID), 0, 0); f = buildtree(UMUL, f, NIL); return f; } /* * Return frame as given by a. */ NODE * builtin_frame_address(const struct bitable *bt, NODE *a) { int nframes; NODE *f; cerror((char *)__func__); nframes = glval(a); tfree(a); f = block(REG, NIL, NIL, PTR+VOID, 0, 0); regno(f) = FPREG; while (nframes--) f = block(UMUL, f, NIL, PTR+VOID, 0, 0); return f; } /* * Return "canonical frame address". */ NODE * builtin_cfa(const struct bitable *bt, NODE *a) { NODE *f; cerror((char *)__func__); f = block(REG, NIL, NIL, PTR+VOID, 0, 0); regno(f) = FPREG; return block(PLUS, f, bcon(16), INCREF(PTR+VOID), 0, 0); } pcc-20181216/arch/m68k/local.c010064400017500000000000000267451340073433000144370ustar raggewheel/* $Id: local.c,v 1.17 2018/12/02 10:50:00 ragge Exp $ */ /* * Copyright (c) 2014 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "pass1.h" #undef NIL #define NIL NULL #ifdef LANG_CXX #define P1ND NODE #define p1nfree nfree #define p1fwalk fwalk #define p1tcopy tcopy #define p1alloc talloc #else #define NODE P1ND #define nfree p1nfree #define fwalk p1fwalk #endif /* this file contains code which is dependent on the target machine */ int gotnr; /* * Make a symtab entry for PIC use. */ static struct symtab * picsymtab(char *p, char *s, char *s2) { struct symtab *sp = permalloc(sizeof(struct symtab)); size_t len = strlen(p) + strlen(s) + strlen(s2) + 1; sp->sname = permalloc(len); strlcpy(sp->sname, p, len); strlcat(sp->sname, s, len); strlcat(sp->sname, s2, len); sp->sap = attr_new(ATTR_SONAME, 1); sp->sap->sarg(0) = sp->sname; sp->sclass = EXTERN; sp->sflags = sp->slevel = 0; sp->stype = 0xdeadbeef; return sp; } /* * Create a reference for an extern variable. */ static NODE * picext(NODE *p) { NODE *q, *r; struct symtab *sp; char *name; q = tempnode(gotnr, PTR|VOID, 0, 0); name = getexname(p->n_sp); #ifdef notdef struct attr *ga; if ((ga = attr_find(p->n_sp->sap, GCC_ATYP_VISIBILITY)) && strcmp(ga->sarg(0), "hidden") == 0) { /* For hidden vars use GOTOFF */ sp = picsymtab("", name, "@GOTOFF"); r = xbcon(0, sp, INT); q = buildtree(PLUS, q, r); q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); q->n_sp = p->n_sp; /* for init */ nfree(p); return q; } #endif sp = picsymtab("", name, "@GOT"); r = xbcon(0, sp, INT); q = buildtree(PLUS, q, r); q = block(UMUL, q, 0, PTR|VOID, 0, 0); q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); q->n_sp = p->n_sp; /* for init */ nfree(p); return q; } static char * getsoname(struct symtab *sp) { struct attr *ap; return (ap = attr_find(sp->sap, ATTR_SONAME)) ? ap->sarg(0) : sp->sname; } static NODE * picstatic(NODE *p) { NODE *q, *r; struct symtab *sp; q = tempnode(gotnr, PTR|VOID, 0, 0); if (p->n_sp->slevel > 0) { char buf[32]; if ((p->n_sp->sflags & SMASK) == SSTRING) p->n_sp->sflags |= SASG; snprintf(buf, 32, LABFMT, (int)p->n_sp->soffset); sp = picsymtab("", buf, "@GOT"); } else { sp = picsymtab("", getsoname(p->n_sp), "@GOT"); } sp->sclass = STATIC; sp->stype = p->n_sp->stype; r = xbcon(0, sp, INT); q = buildtree(PLUS, q, r); q = block(UMUL, q, 0, PTR|VOID, 0, 0); q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); q->n_sp = p->n_sp; /* for init */ nfree(p); return q; } /* clocal() is called to do local transformations on * an expression tree preparitory to its being * written out in intermediate code. * * the major essential job is rewriting the * automatic variables and arguments in terms of * REG and OREG nodes * conversion ops which are not necessary are also clobbered here * in addition, any special features (such as rewriting * exclusive or) are easily handled here as well */ NODE * clocal(NODE *p) { register struct symtab *q; register NODE *r, *l; register int o; TWORD t; #ifdef PCC_DEBUG if (xdebug) { printf("clocal: %p\n", p); fwalk(p, eprint, 0); } #endif switch( o = p->n_op ){ case NAME: if ((q = p->n_sp) == NULL) return p; /* Nothing to care about */ switch (q->sclass) { case PARAM: case AUTO: /* fake up a structure reference */ r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); slval(r, 0); r->n_rval = FPREG; p = stref(block(STREF, r, p, 0, 0, 0)); break; case REGISTER: p->n_op = REG; slval(p, 0); p->n_rval = q->soffset; break; case USTATIC: case STATIC: if (kflag == 0) break; if (blevel > 0 && !statinit) p = picstatic(p); break; case EXTERN: case EXTDEF: if (kflag == 0) break; if (blevel > 0 && !statinit) p = picext(p); break; } break; case ADDROF: if (kflag == 0 || blevel == 0 || statinit) break; /* char arrays may end up here */ l = p->n_left; if (l->n_op != NAME || (l->n_type != ARY+CHAR && l->n_type != ARY+WCHAR_TYPE)) break; l = p; p = picstatic(p->n_left); nfree(l); if (p->n_op != UMUL) cerror("ADDROF error"); l = p; p = p->n_left; nfree(l); break; case STASG: /* convert struct assignment to call memcpy */ l = p->n_left; if (l->n_op == NAME && ISFTN(l->n_sp->stype)) break; /* struct return, do nothing */ /* first construct arg list */ p->n_left = buildtree(ADDROF, p->n_left, 0); r = bcon(tsize(STRTY, p->n_df, p->n_ap)/SZCHAR); p->n_left = buildtree(CM, p->n_left, p->n_right); p->n_right = r; p->n_op = CM; p->n_type = INT; r = block(NAME, NIL, NIL, INT, 0, 0); r->n_sp = lookup(addname("memcpy"), SNORMAL); if (r->n_sp->sclass == SNULL) { r->n_sp->sclass = EXTERN; r->n_sp->stype = INCREF(VOID+PTR)+(FTN-PTR); } r->n_type = r->n_sp->stype; p = buildtree(CALL, r, p); break; case SCONV: l = p->n_left; if (l->n_op == ICON && ISPTR(l->n_type)) { /* Do immediate cast here */ /* Should be common code */ q = l->n_sp; l->n_sp = NULL; l->n_type = UNSIGNED; if (concast(l, p->n_type) == 0) cerror("clocal"); p = nfree(p); p->n_sp = q; } break; case FORCE: /* put return value in return reg */ p->n_op = ASSIGN; p->n_right = p->n_left; p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0); t = p->n_type; if (ISITY(t)) t = t - (FIMAG-FLOAT); p->n_left->n_rval = RETREG(t); break; } #ifdef PCC_DEBUG if (xdebug) { printf("clocal end: %p\n", p); fwalk(p, eprint, 0); } #endif return(p); } #define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz)) void myp2tree(NODE *p) { struct symtab *sp; NODE *l; if (cdope(p->n_op) & CALLFLG) { if (p->n_left->n_op == ADDROF && p->n_left->n_left->n_op == NAME) { p->n_left = nfree(p->n_left); l = p->n_left; l->n_op = ICON; if (l->n_sp->sclass != STATIC && l->n_sp->sclass != USTATIC) l->n_sp = picsymtab(l->n_sp->sname, "@PLTPC", ""); } } if (p->n_op != FCON) return; sp = IALLOC(sizeof(struct symtab)); sp->sclass = STATIC; sp->sap = 0; sp->slevel = 1; /* fake numeric label */ sp->soffset = getlab(); sp->sflags = 0; sp->stype = p->n_type; sp->squal = (CON >> TSHIFT); sp->sname = NULL; locctr(DATA, sp); defloc(sp); ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p); p->n_op = NAME; slval(p, 0); p->n_sp = sp; } /* * Convert ADDROF NAME to ICON? */ int andable(NODE *p) { #ifdef notdef /* shared libraries cannot have direct referenced static syms */ if (p->n_sp->sclass == STATIC || p->n_sp->sclass == USTATIC) return 1; #endif return 1; } /* * Return 1 if a variable of type type is OK to put in register. */ int cisreg(TWORD t) { return 1; } /* * Allocate off bits on the stack. p is a tree that when evaluated * is the multiply count for off, t is a storeable node where to write * the allocated address. */ void spalloc(NODE *t, NODE *p, OFFSZ off) { NODE *sp; p = buildtree(MUL, p, bcon(off/SZCHAR)); p = buildtree(PLUS, p, bcon(30)); p = buildtree(AND, p, xbcon(-16, NULL, UNSIGNED)); p = cast(p, UNSIGNED, 0); /* sub the size from sp */ sp = block(REG, NIL, NIL, UNSIGNED+PTR, 0, 0); slval(sp, 0); sp->n_rval = STKREG; p = (buildtree(MINUSEQ, sp, p)); ecomp(p); /* save the address of sp */ sp = block(REG, NIL, NIL, PTR+UNSIGNED, t->n_df, t->n_ap); slval(sp, 0); sp->n_rval = STKREG; t->n_type = sp->n_type; p = (buildtree(ASSIGN, t, sp)); /* Emit! */ ecomp(p); } /* * print out a constant node, may be associated with a label. * Do not free the node after use. * off is bit offset from the beginning of the aggregate * fsz is the number of bits this is referring to */ int ninval(CONSZ off, int fsz, NODE *p) { union { float f; double d; long double l; int i[3]; } u; switch (p->n_type) { case LONGLONG: case ULONGLONG: printf("\t.long\t0x%x\n", (int)(off >> 32) & 0xffffffff); printf("\t.long\t0x%x\n", (int)(off) & 0xffffffff); break; default: return 0; } return 1; } /* make a name look like an external name in the local machine */ char * exname(char *p) { return (p == NULL ? "" : p); } /* * map types which are not defined on the local machine */ TWORD ctype(TWORD type) { switch (BTYPE(type)) { case LONG: MODTYPE(type,INT); break; case ULONG: MODTYPE(type,UNSIGNED); } return (type); } void calldec(NODE *p, NODE *q) { } void extdec(struct symtab *q) { } /* make a common declaration for id, if reasonable */ void defzero(struct symtab *sp) { int off, al; char *name; name = getexname(sp); off = tsize(sp->stype, sp->sdf, sp->sap); SETOFF(off,SZCHAR); off /= SZCHAR; al = talign(sp->stype, sp->sap)/SZCHAR; if (sp->sclass == STATIC) { if (sp->slevel == 0) { printf("\t.local %s\n", name); } else printf("\t.local " LABFMT "\n", sp->soffset); } if (sp->slevel == 0) { printf("\t.comm %s,0%o,%d\n", name, off, al); } else printf("\t.comm " LABFMT ",0%o,%d\n", sp->soffset, off, al); } char *nextsect; static char *alias; static int constructor; static int destructor; /* * Give target the opportunity of handling pragmas. */ int mypragma(char *str) { return 0; } /* * Called when a identifier has been declared. */ void fixdef(struct symtab *sp) { struct attr *ga; #ifdef HAVE_WEAKREF /* not many as'es have this directive */ if ((ga = attr_find(sp->sap, GCC_ATYP_WEAKREF)) != NULL) { char *wr = ga->sarg(0); char *sn = getsoname(sp); if (wr == NULL) { if ((ga = attr_find(sp->sap, GCC_ATYP_ALIAS))) { wr = ga->sarg(0); } } if (wr == NULL) printf("\t.weak %s\n", sn); else printf("\t.weakref %s,%s\n", sn, wr); } else if ((ga = attr_find(sp->sap, GCC_ATYP_ALIAS)) != NULL) { char *an = ga->sarg(0); char *sn = getsoname(sp); char *v; v = attr_find(sp->sap, GCC_ATYP_WEAK) ? "weak" : "globl"; printf("\t.%s %s\n", v, sn); printf("\t.set %s,%s\n", sn, an); } if (alias != NULL && (sp->sclass != PARAM)) { char *name = getexname(sp); printf("\t.globl %s\n", name); printf("%s = ", name); printf("%s\n", exname(alias)); alias = NULL; } if ((constructor || destructor) && (sp->sclass != PARAM)) { NODE *p = p1alloc(); p->n_op = NAME; p->n_sp = (struct symtab *)(constructor ? "constructor" : "destructor"); sp->sap = attr_add(sp->sap, gcc_attr_parse(p)); constructor = destructor = 0; } #endif } void pass1_lastchance(struct interpass *ip) { } pcc-20181216/arch/m68k/local2.c010064400017500000000000000367471277225026600145400ustar raggewheel/* $Id: local2.c,v 1.18 2016/09/26 16:45:42 ragge Exp $ */ /* * Copyright (c) 2014 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass2.h" # include # include static int stkpos; void deflab(int label) { printf(LABFMT ":\n", label); } static int regm, regf, fpsub, nfp; void prologue(struct interpass_prolog *ipp) { int i; /* * Subtract both space for automatics and permanent regs. * XXX - no struct return yet. */ fpsub = p2maxautooff; if (fpsub >= AUTOINIT/SZCHAR) fpsub -= AUTOINIT/SZCHAR; regm = regf = nfp = 0; for (i = 0; i < MAXREGS; i++) if (TESTBIT(p2env.p_regs, i)) { if (i <= A7) { regm |= (1 << i); fpsub += 4; } else if (i >= FP0) { regf |= (1 << (i - FP0)); fpsub += 12; nfp += 12; } else comperr("bad reg range"); } printf(" link.%c %%fp,#%d\n", fpsub > 32768 ? 'l' : 'w', -fpsub); if (regm) printf(" movem.l #%d,%d(%%fp)\n", regm, -fpsub + nfp); if (regf) printf(" fmovem #%d,%d(%%fp)\n", regf, -fpsub); } void eoftn(struct interpass_prolog *ipp) { if (ipp->ipp_ip.ip_lbl == 0) return; /* no code needs to be generated */ if (regm) printf(" movem.l %d(%%fp),#%d\n", -fpsub + nfp, regm); if (regf) printf(" fmovem %d(%%fp),#%d\n", -fpsub, regf); printf(" unlk %%fp\n rts\n"); } /* * add/sub/... * * Param given: */ void hopcode(int f, int o) { char *str; switch (o) { case PLUS: str = "add"; break; case MINUS: str = "sub"; break; case AND: str = "and"; break; case OR: str = "or"; break; case ER: str = "eor"; break; default: comperr("hopcode2: %d", o); str = 0; /* XXX gcc */ } printf("%s", str); } /* * Return type size in bytes. Used by R2REGS, arg 2 to offset(). */ int tlen(NODE *p) { switch(p->n_type) { case CHAR: case UCHAR: return(1); case SHORT: case USHORT: return(SZSHORT/SZCHAR); case DOUBLE: return(SZDOUBLE/SZCHAR); case INT: case UNSIGNED: return(SZINT/SZCHAR); case LONG: case ULONG: case LONGLONG: case ULONGLONG: return SZLONGLONG/SZCHAR; default: if (!ISPTR(p->n_type)) comperr("tlen type %d not pointer"); return SZPOINT(p->n_type)/SZCHAR; } } int fldexpand(NODE *p, int cookie, char **cp) { comperr("fldexpand"); return 0; } static void starg(NODE *p) { int sz = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0); int subsz = (sz + 3) & ~3; int fr, tr, cr; fr = regno(getlr(p, 'L')); /* from reg (struct pointer) */ cr = regno(getlr(p, '1')); /* count reg (number of words) */ tr = regno(getlr(p, '2')); /* to reg (stack) */ /* Sub from stack and put in toreg */ printf(" sub.l #%d,%%sp\n", subsz); printf(" move.l %%sp,%s\n", rnames[tr]); /* Gen an even copy start */ if (sz & 1) expand(p, INBREG, " move.b (AL)+,(A2)+\n"); if (sz & 2) expand(p, INBREG, " move.w (AL)+,(A2)+\n"); sz -= (sz & 3); /* if more than 4 words, use loop, otherwise output instructions */ if (sz > 16) { printf(" move.l #%d,%s\n", (sz/4)-1, rnames[cr]); expand(p, INBREG, "1: move.l (AL)+,(A2)+\n"); expand(p, INBREG, " dbra A1,1b\n"); } else { if (sz > 12) expand(p, INBREG, " move.l (AL)+,(A2)+\n"), sz -= 4; if (sz > 8) expand(p, INBREG, " move.l (AL)+,(A2)+\n"), sz -= 4; if (sz > 4) expand(p, INBREG, " move.l (AL)+,(A2)+\n"), sz -= 4; if (sz == 4) expand(p, INBREG, " move.l (AL)+,(A2)+\n"); } } void zzzcode(NODE *p, int c) { TWORD t = p->n_type; char *s; switch (c) { case 'L': t = p->n_left->n_type; /* FALLTHROUGH */ case 'A': s = (t == CHAR || t == UCHAR ? "b" : t == SHORT || t == USHORT ? "w" : t == FLOAT ? "s" : t == DOUBLE ? "d" : t == LDOUBLE ? "x" : "l"); printf("%s", s); break; case 'B': if (p->n_qual) printf(" add.l #%d,%%sp\n", (int)p->n_qual); break; case 'C': /* jsr or bsr.l XXX - type of CPU? */ printf("%s", kflag ? "bsr.l" : "jsr"); break; case 'F': /* Emit float branches */ switch (p->n_op) { case GT: s = "fjnle"; break; case GE: s = "fjnlt"; break; case LE: s = "fjngt"; break; case LT: s = "fjnge"; break; case NE: s = "fjne"; break; case EQ: s = "fjeq"; break; default: comperr("ZF"); s = 0; } printf("%s " LABFMT "\n", s, p->n_label); break; case 'P': printf(" lea -%d(%%fp),%%a0\n", stkpos); break; case 'Q': /* struct assign */ printf(" move.l %d,-(%%sp)\n", attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)); expand(p, INAREG, " move.l AR,-(%sp)\n"); expand(p, INAREG, " move.l AL,-(%sp)\n"); printf(" jsr memcpy\n"); printf(" add.l #12,%%sp\n"); break; case 'S': /* struct arg */ starg(p); break; case '2': if (regno(getlr(p, '2')) != regno(getlr(p, 'L'))) expand(p, INAREG, " fmove.x AL,A2\n"); break; default: comperr("zzzcode %c", c); } } #if 0 int canaddr(NODE *); int canaddr(NODE *p) { int o = p->n_op; if (o==NAME || o==REG || o==ICON || o==OREG || (o==UMUL && shumul(p->n_left, SOREG))) return(1); return(0); } #endif /* * Does the bitfield shape match? */ int flshape(NODE *p) { comperr("flshape"); return(0); } /* INTEMP shapes must not contain any temporary registers */ /* XXX should this go away now? */ int shtemp(NODE *p) { return 0; #if 0 int r; if (p->n_op == STARG ) p = p->n_left; switch (p->n_op) { case REG: return (!istreg(p->n_rval)); case OREG: r = p->n_rval; if (R2TEST(r)) { if (istreg(R2UPK1(r))) return(0); r = R2UPK2(r); } return (!istreg(r)); case UMUL: p = p->n_left; return (p->n_op != UMUL && shtemp(p)); } if (optype(p->n_op) != LTYPE) return(0); return(1); #endif } void adrcon(CONSZ val) { printf("#" CONFMT, val); } void conput(FILE *fp, NODE *p) { long val = getlval(p); if (p->n_type <= UCHAR) val &= 255; else if (p->n_type <= USHORT) val &= 65535; switch (p->n_op) { case ICON: fprintf(fp, "%ld", val); if (p->n_name[0]) printf("+%s", p->n_name); break; default: comperr("illegal conput, p %p", p); } } /*ARGSUSED*/ void insput(NODE *p) { comperr("insput"); } /* * Write out the upper address, like the upper register of a 2-register * reference, or the next memory location. */ void upput(NODE *p, int size) { switch (p->n_op) { case REG: printf("%%%s", &rnames[p->n_rval][2]); break; case NAME: case OREG: setlval(p, getlval(p) + 4); adrput(stdout, p); setlval(p, getlval(p) - 4); break; case ICON: printf("#%d", (int)getlval(p)); break; default: comperr("upput bad op %d size %d", p->n_op, size); } } void adrput(FILE *io, NODE *p) { int r; /* output an address, with offsets, from p */ switch (p->n_op) { case NAME: if (getlval(p)) fprintf(io, CONFMT "%s", getlval(p), *p->n_name ? "+" : ""); if (p->n_name[0]) printf("%s", p->n_name); else comperr("adrput"); return; case OREG: r = p->n_rval; if (getlval(p)) fprintf(io, CONFMT "%s", getlval(p), *p->n_name ? "+" : ""); if (p->n_name[0]) printf("%s", p->n_name); if (R2TEST(r)) { int r1 = R2UPK1(r); int r2 = R2UPK2(r); int sh = R2UPK3(r); fprintf(io, "(%s,%s,%d)", r1 == MAXREGS ? "" : rnames[r1], r2 == MAXREGS ? "" : rnames[r2], sh); } else fprintf(io, "(%s)", rnames[p->n_rval]); return; case ICON: /* addressable value of the constant */ if (p->n_type == LONGLONG || p->n_type == ULONGLONG) { fprintf(io, "#" CONFMT, getlval(p) >> 32); } else { fputc('#', io); conput(io, p); } return; case REG: if ((p->n_type == LONGLONG || p->n_type == ULONGLONG) && /* XXX allocated reg may get wrong type here */ (p->n_rval > A7 && p->n_rval < FP0)) { fprintf(io, "%%%c%c", rnames[p->n_rval][0], rnames[p->n_rval][1]); } else fprintf(io, "%s", rnames[p->n_rval]); return; default: comperr("illegal address, op %d, node %p", p->n_op, p); return; } } static char * ccbranches[] = { "jeq", /* jumpe */ "jne", /* jumpn */ "jle", /* jumple */ "jlt", /* jumpl */ "jge", /* jumpge */ "jgt", /* jumpg */ "jls", /* jumple (jlequ) */ "jcs", /* jumpl (jlssu) */ "jcc", /* jumpge (jgequ) */ "jhi", /* jumpg (jgtru) */ }; /* printf conditional and unconditional branches */ void cbgen(int o, int lab) { if (o < EQ || o > UGT) comperr("bad conditional branch: %s", opst[o]); printf(" %s " LABFMT "\n", ccbranches[o-EQ], lab); } static void mkcall(NODE *p, char *name) { p->n_op = CALL; p->n_right = mkunode(FUNARG, p->n_left, 0, p->n_left->n_type); p->n_left = mklnode(ICON, 0, 0, FTN|p->n_type); p->n_left->n_name = name; } static void mkcall2(NODE *p, char *name) { p->n_op = CALL; p->n_right = mkunode(FUNARG, p->n_right, 0, p->n_right->n_type); p->n_left = mkunode(FUNARG, p->n_left, 0, p->n_left->n_type); p->n_right = mkbinode(CM, p->n_left, p->n_right, INT); p->n_left = mklnode(ICON, 0, 0, FTN|p->n_type); p->n_left->n_name = name; } static void fixcalls(NODE *p, void *arg) { struct attr *ap; TWORD lt; switch (p->n_op) { case STCALL: case USTCALL: ap = attr_find(p->n_ap, ATTR_P2STRUCT); if (ap->iarg(0)+p2autooff > stkpos) stkpos = ap->iarg(0)+p2autooff; break; case DIV: if (p->n_type == LONGLONG) mkcall2(p, "__divdi3"); else if (p->n_type == ULONGLONG) mkcall2(p, "__udivdi3"); break; case MOD: if (p->n_type == LONGLONG) mkcall2(p, "__moddi3"); else if (p->n_type == ULONGLONG) mkcall2(p, "__umoddi3"); break; case MUL: if (p->n_type == LONGLONG || p->n_type == ULONGLONG) mkcall2(p, "__muldi3"); break; case LS: if (p->n_type == LONGLONG || p->n_type == ULONGLONG) mkcall2(p, "__ashldi3"); break; case RS: if (p->n_type == LONGLONG) mkcall2(p, "__ashrdi3"); else if (p->n_type == ULONGLONG) mkcall2(p, "__lshrdi3"); break; case SCONV: lt = p->n_left->n_type; switch (p->n_type) { case LONGLONG: if (lt == FLOAT) mkcall(p, "__fixsfdi"); else if (lt == DOUBLE) mkcall(p, "__fixdfdi"); else if (lt == LDOUBLE) mkcall(p, "__fixxfdi"); break; case ULONGLONG: if (lt == FLOAT) mkcall(p, "__fixunssfdi"); else if (lt == DOUBLE) mkcall(p, "__fixunsdfdi"); else if (lt == LDOUBLE) mkcall(p, "__fixunsxfdi"); break; case FLOAT: if (lt == LONGLONG) mkcall(p, "__floatdisf"); else if (lt == ULONGLONG) mkcall(p, "__floatundisf"); break; case DOUBLE: if (lt == LONGLONG) mkcall(p, "__floatdidf"); else if (lt == ULONGLONG) mkcall(p, "__floatundidf"); break; case LDOUBLE: if (lt == LONGLONG) mkcall(p, "__floatdixf"); else if (lt == ULONGLONG) mkcall(p, "__floatundixf"); break; } break; #if 0 case XASM: p->n_name = adjustname(p->n_name); break; #endif } } void myreader(struct interpass *ipole) { struct interpass *ip; stkpos = p2autooff; DLIST_FOREACH(ip, ipole, qelem) { if (ip->type != IP_NODE) continue; walkf(ip->ip_node, fixcalls, 0); } if (stkpos > p2autooff) p2autooff = stkpos; if (stkpos > p2maxautooff) p2maxautooff = stkpos; if (x2debug) printip(ipole); } /* * Remove some PCONVs after OREGs are created. */ static void pconv2(NODE *p, void *arg) { NODE *q; if (p->n_op == PLUS) { if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) { if (p->n_right->n_op != ICON) return; if (p->n_left->n_op != PCONV) return; if (p->n_left->n_left->n_op != OREG) return; q = p->n_left->n_left; nfree(p->n_left); p->n_left = q; /* * This will be converted to another OREG later. */ } } } void mycanon(NODE *p) { walkf(p, pconv2, 0); } void myoptim(struct interpass *ip) { } void rmove(int s, int d, TWORD t) { if (s >= D0D1 && s <= D6D7) { printf(" move.l %s,%s\n", rnames[s-D0D1], rnames[d-D0D1]); printf(" move.l %s,%s\n", rnames[s+1-D0D1], rnames[d+1-D0D1]); } else if (t >= FLOAT && t <= TDOUBLE) printf(" fmove.x %s,%s\n", rnames[s], rnames[d]); else printf(" move.l %s,%s\n", rnames[s], rnames[d]); } /* * For class cc, find worst-case displacement of the number of * registers in the array r[] indexed by class. */ int COLORMAP(int cc, int *r) { int a,c; a = r[CLASSA]; c = r[CLASSC]; switch (cc) { case CLASSA: if (c * 2 + a < 8) return 1; break; case CLASSB: return r[CLASSB] < 6; case CLASSC: if (c > 2) return 0; if (c == 2 && a > 0) return 0; if (c == 1 && a > 1) return 0; if (c == 0 && a > 3) return 0; return 1; } return 0; } char *rnames[] = { "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%a7", "d0d1", "d1d2", "d2d3", "d3d4", "d4d5", "d5d6", "d6d7", "%fp0", "%fp1", "%fp2", "%fp3", "%fp4", "%fp5", "%fp6", "%fp7", }; /* * Return a class suitable for a specific type. */ int gclass(TWORD t) { if (t > BTMASK) return CLASSB; if (t == LONGLONG || t == ULONGLONG) return CLASSC; if (t == FLOAT || t == DOUBLE || t == LDOUBLE) return CLASSD; return CLASSA; } static int argsiz(NODE *p) { TWORD t = p->n_type; if (t < LONGLONG || t == FLOAT || t > BTMASK) return 4; if (t == LONGLONG || t == ULONGLONG || t == DOUBLE) return 8; if (t == LDOUBLE) return 12; if (t == STRTY || t == UNIONTY) return (attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)+3) & ~3; comperr("argsiz"); return 0; } /* * Calculate argument sizes. */ void lastcall(NODE *p) { NODE *op = p; int size = 0; p->n_qual = 0; if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) return; for (p = p->n_right; p->n_op == CM; p = p->n_left) size += argsiz(p->n_right); size += argsiz(p); op->n_qual = size; /* XXX */ } /* * Special shapes. */ int special(NODE *p, int shape) { return SRNOPE; } /* * Target-dependent command-line options. */ void mflags(char *str) { } /* * Do something target-dependent for xasm arguments. */ int myxasm(struct interpass *ip, NODE *p) { int cw = xasmcode(p->n_name); int ww; char *w; ww = XASMVAL(cw); again: switch (ww) { case 'd': /* Just convert to reg */ case 'a': p->n_name = tmpstrdup(p->n_name); w = strchr(p->n_name, XASMVAL(cw)); *w = 'r'; /* now reg */ break; case 'o': /* offsetable reg */ if (p->n_left->n_op == UMUL || p->n_left->n_op == OREG || p->n_left->n_op == NAME) { return 1; } if (ww == XASMVAL(cw)) ww = XASMVAL1(cw); else ww = XASMVAL2(cw); goto again; } return 0; } /* * Handle special characters following % in gcc extended assembler. */ int targarg(char *w, void *arg) { switch (w[1]) { case '.': /* Remove dot if not needed */ printf("."); break; default: return 0; } return 1; } pcc-20181216/arch/m68k/macdefs.h010064400017500000000000000150641340073433000147440ustar raggewheel/* * Copyright (c) 2011 Janne Johansson * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Machine-dependent defines for both passes. */ /* * Convert (multi-)character constant to integer. */ #define makecc(val,i) lastcon = i ? (val<<8)|lastcon : val #define ARGINIT 64 /* # bits above fp where arguments start */ #define AUTOINIT 0 /* # bits below fp where automatics start */ /* * Storage space requirements */ #define SZCHAR 8 #define SZBOOL 8 #define SZSHORT 16 #define SZINT 32 #define SZLONG 32 #define SZPOINT(t) 32 #define SZLONGLONG 64 #define SZFLOAT 32 #define SZDOUBLE 64 #define SZLDOUBLE 128 /* * Alignment constraints */ #define ALCHAR 8 #define ALBOOL 8 #define ALSHORT 16 #define ALINT 32 #define ALLONG 32 #define ALPOINT 32 #define ALLONGLONG 64 #define ALFLOAT 32 #define ALDOUBLE 64 #define ALLDOUBLE 32 /* ???? */ /* #undef ALSTRUCT m68k struct alignment is member defined */ #define ALSTACK 32 #define ALMAX 64 /* * Min/max values. */ #define MIN_CHAR -128 #define MAX_CHAR 127 #define MAX_UCHAR 255 #define MIN_SHORT -32768 #define MAX_SHORT 32767 #define MAX_USHORT 65535 #define MIN_INT (-0x7fffffff-1) #define MAX_INT 0x7fffffff #define MAX_UNSIGNED 0xffffffffU #define MIN_LONG MIN_INT #define MAX_LONG MAX_INT #define MAX_ULONG MAX_UNSIGNED #define MIN_LONGLONG 0x8000000000000000LL #define MAX_LONGLONG 0x7fffffffffffffffLL #define MAX_ULONGLONG 0xffffffffffffffffULL /* Default char is signed */ #undef CHAR_UNSIGNED #define BOOL_TYPE UCHAR /* what used to store _Bool */ /* * Use large-enough types. */ typedef long long CONSZ; typedef unsigned long long U_CONSZ; typedef long long OFFSZ; #define CONFMT "%lld" /* format for printing constants */ #define LABFMT ".L%d" /* format for printing labels */ #define STABLBL ".LL%d" /* format for stab (debugging) labels */ #ifdef LANG_F77 #define BLANKCOMMON "_BLNK_" #define MSKIREG (M(TYSHORT)|M(TYLONG)) #define TYIREG TYLONG #define FSZLENG FSZLONG #define AUTOREG EBP #define ARGREG EBP #define ARGOFFSET 8 #endif #define BACKAUTO /* stack grows negatively for automatics */ #define BACKTEMP /* stack grows negatively for temporaries */ #undef FIELDOPS /* no bit-field instructions */ #define TARGET_ENDIAN TARGET_BE /* big-endian */ #undef FINDMOPS /* XXX FIXME */ #define CC_DIV_0 /* division by zero is safe in the compiler */ /* Definitions mostly used in pass2 */ #define BYTEOFF(x) ((x)&03) #define wdal(k) (BYTEOFF(k)==0) #define STOARG(p) #define STOFARG(p) #define STOSTARG(p) #define genfcall(a,b) gencall(a,b) /* How many integer registers are needed? (used for stack allocation) */ #define szty(t) ((t) == LDOUBLE ? 3 : \ (t) == DOUBLE || DEUNSIGN(t) == LONGLONG ? 2 : 1) /* * All registers are given a sequential number to * identify it which must match rnames[] in local2.c. * * The classes used on m68k are: * A - 32-bit data registers * B - 32-bit address registers * C - 64-bit combined registers * D - 80-bit floating point registers */ #define D0 0 #define D1 1 #define D2 2 #define D3 3 #define D4 4 #define D5 5 #define D6 6 #define D7 7 /* no support yet for using A registers for data calculations */ #define A0 8 #define A1 9 #define A2 10 #define A3 11 #define A4 12 #define A5 13 #define A6 14 /* frame pointer? Isnt it A4 on amigaos.. */ #define A7 15 /* Stack pointer */ #define D0D1 16 #define D1D2 17 #define D2D3 18 #define D3D4 19 #define D4D5 20 #define D5D6 21 #define D6D7 22 #define FP0 23 #define FP1 24 #define FP2 25 #define FP3 26 #define FP4 27 #define FP5 28 #define FP6 29 #define FP7 30 #define MAXREGS 31 /* 31 registers */ #define RSTATUS \ SAREG|TEMPREG, SAREG|TEMPREG, SAREG|PERMREG, SAREG|PERMREG, \ SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \ SBREG|TEMPREG, SBREG|TEMPREG, SBREG|PERMREG, SBREG|PERMREG, \ SBREG|PERMREG, SBREG|PERMREG, 0, 0, /* fp and sp are ignored here */ \ SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \ SDREG|TEMPREG, SDREG|TEMPREG, SDREG|PERMREG, SDREG|PERMREG, \ SDREG|PERMREG, SDREG|PERMREG, SDREG|PERMREG, SDREG|PERMREG, /* no overlapping registers at all */ #define ROVERLAP \ /* 8 data registers */ \ { D0D1, -1},\ { D1D2, D0D1, -1},\ { D2D3, D1D2,-1},\ { D3D4, D2D3,-1},\ { D4D5, D3D4,-1},\ { D5D6, D4D5,-1},\ { D6D7, D5D6,-1},\ { D6D7, -1},\ /* 8 adress registers */ \ { -1}, \ { -1}, \ { -1}, \ { -1}, \ { -1}, \ { -1}, \ { -1}, \ { -1}, \ { D0, D1, D1D2, -1}, \ { D1, D2, D0D1, D2D3, -1}, \ { D2, D3, D1D2, D3D4, -1}, \ { D3, D4, D2D3, D4D5, -1}, \ { D4, D5, D3D4, D5D6, -1}, \ { D5, D6, D4D5, D6D7, -1}, \ { D6, D7, D5D6, -1}, \ { -1}, \ { -1}, \ { -1}, \ { -1}, \ { -1}, \ { -1}, \ { -1}, \ { -1}, /* Return a register class based on the type of the node */ #define PCLASS(p) (p->n_type == FLOAT || p->n_type == DOUBLE || \ p->n_type == LDOUBLE ? SDREG : p->n_type == LONGLONG || \ p->n_type == ULONGLONG ? SCREG : p->n_type > BTMASK ? SBREG : SAREG) #define NUMCLASS 4 /* highest number of reg classes used */ int COLORMAP(int c, int *r); #define GCLASS(x) (x < 8 ? CLASSA : x < 16 ? CLASSB : x < 23 ? CLASSC : CLASSD) #define DECRA(x,y) (((x) >> (y*6)) & 63) /* decode encoded regs */ #define ENCRD(x) (x) /* Encode dest reg in n_reg */ #define ENCRA1(x) ((x) << 12) /* A1 */ #define ENCRA2(x) ((x) << 18) /* A2 */ #define ENCRA(x,y) ((x) << (6+y*6)) /* encode regs in int */ #define RETREG(x) ((x) == FLOAT || (x) == DOUBLE || (x) == LDOUBLE ? FP0 : \ (x) == LONGLONG || (x) == ULONGLONG ? D0D1 : (x) > BTMASK ? A0 : D0) #define FPREG A6 /* frame pointer */ #define STKREG A7 /* stack pointer */ #define HAVE_WEAKREF #define TARGET_FLT_EVAL_METHOD 2 /* all as long double */ /* * Extended assembler macros. */ int targarg(char *w, void *arg); #define XASM_TARGARG(w, ary) (w[1] == 'b' ? w++, 0 : targarg(w, ary)) /* floating point definitions */ #define USE_IEEEFP_32 #define FLT_PREFIX IEEEFP_32 #define USE_IEEEFP_64 #define DBL_PREFIX IEEEFP_64 #define LDBL_PREFIX IEEEFP_64 pcc-20181216/arch/m68k/order.c010064400017500000000000000100411265317107300144460ustar raggewheel/* $Id: order.c,v 1.5 2016/01/30 17:26:19 ragge Exp $ */ /* * Copyright (c) 2014 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass2.h" #include int canaddr(NODE *); /* is it legal to make an OREG or NAME entry which has an * offset of off, (from a register of r), if the * resulting thing had type t */ int notoff(TWORD t, int r, CONSZ off, char *cp) { if (off > MAX_SHORT || off < MIN_SHORT) return 1; /* max signed 16-bit offset */ return(0); /* YES */ } /* * Turn a UMUL-referenced node into OREG. * Be careful about register classes, this is a place where classes change. * Especially on m68k we must be careful about class changes; * Pointers can only have a scalar added to it if PLUS, but when * MINUS may be either only pointers or left pointer and right scalar. * * So far we only handle the trivial OREGs here. */ void offstar(NODE *p, int shape) { NODE *q; if (x2debug) { printf("offstar(%p)\n", p); fwalk(p, e2print, 0); } if (isreg(p)) return; /* Matched (%a0) */ q = p->n_right; if ((p->n_op == PLUS || p->n_op == MINUS) && q->n_op == ICON && notoff(0, 0, getlval(q), 0) == 0 && !isreg(p->n_left)) { (void)geninsn(p->n_left, INBREG); return; } (void)geninsn(p, INBREG); } /* * Do the actual conversion of offstar-found OREGs into real OREGs. * For simple OREGs conversion should already be done. */ void myormake(NODE *q) { } /* * Shape matches for UMUL. Cooperates with offstar(). */ int shumul(NODE *p, int shape) { if (x2debug) printf("shumul(%p)\n", p); /* Turns currently anything into OREG on x86 */ if (shape & SOREG) return SROREG; return SRNOPE; } /* * Rewrite operations on binary operators (like +, -, etc...). * Called as a result of table lookup. */ int setbin(NODE *p) { if (x2debug) printf("setbin(%p)\n", p); return 0; } /* setup for assignment operator */ int setasg(NODE *p, int cookie) { if (x2debug) printf("setasg(%p)\n", p); return(0); } /* setup for unary operator */ int setuni(NODE *p, int cookie) { return 0; } /* * Special handling of some instruction register allocation. */ struct rspecial * nspecial(struct optab *q) { switch (q->op) { case STASG: { static struct rspecial s[] = { { NEVER, D0 }, { NEVER, D1 }, { NEVER, A0 }, { NEVER, A1 }, /* { NRES, A0 }, */ { 0 } }; return s; } } comperr("nspecial entry %d", q - table); return 0; /* XXX gcc */ } /* * Set evaluation order of a binary node if it differs from default. */ int setorder(NODE *p) { return 0; } /* * set registers in calling conventions live. */ int * livecall(NODE *p) { static int r[] = { A0, -1 }; if (p->n_op == STCALL) return r; /* only if struct return */ return &r[1]; } /* * Signal whether the instruction is acceptable for this target. */ int acceptable(struct optab *op) { return 1; } pcc-20181216/arch/m68k/table.c010064400017500000000000000445651261370732200144420ustar raggewheel/* $Id: table.c,v 1.13 2015/10/27 14:48:50 ragge Exp $ */ /* * Copyright (c) 2014 Anders Magnusson (ragge@ludd.ltu.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass2.h" #define TLL TLONGLONG|TULONGLONG #define TAREG TINT|TSHORT|TCHAR|TUNSIGNED|TUSHORT|TUCHAR #define SABREG SAREG|SBREG #define TFP TFLOAT|TDOUBLE|TLDOUBLE # define ANYSIGNED TINT|TSHORT|TCHAR # define ANYUSIGNED TUNSIGNED|TUSHORT|TUCHAR # define ANYFIXED ANYSIGNED|ANYUSIGNED # define TUWORD TUNSIGNED # define TSWORD TINT # define TWORD TUWORD|TSWORD #define TANYINT TLL|ANYFIXED #define SHINT SAREG /* Any integer */ #define ININT INAREG #define SHFL SCREG /* shape for long double */ #define INFL INCREG /* shape for long double */ struct optab table[] = { /* First entry must be an empty entry */ { -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", }, /* begin with all these casts */ /* pointer to pointer (same reg class) */ { PCONV, INBREG, SBREG, TPOINT, SBREG, TANY, 0, RLEFT, "", }, /* (u)int -> pointer */ { PCONV, INBREG, SAREG, TWORD, SBREG, TANY, NBREG, RESC1, " move.l AL,A1\n", }, /* pointer to int/unsigned */ { SCONV, INAREG, SBREG, TPOINT, SAREG, TWORD, NAREG, RESC1, " move.l AL,A1\n", }, /* (u)char -> (u)char */ { SCONV, INAREG, SAREG, TCHAR|TUCHAR, SAREG, TCHAR|TUCHAR, 0, RLEFT, "", }, /* char -> short/ushort */ { SCONV, INAREG|INBREG, SABREG, TCHAR, SABREG, TSHORT|TUSHORT, 0, RLEFT, " ext.w AL\n", }, /* uchar -> short/ushort */ { SCONV, INAREG|INBREG, SABREG, TUCHAR, SABREG, TSHORT|TUSHORT, 0, RLEFT, " and.l #255,AL\n", }, /* char -> (u)int */ { SCONV, INAREG, SAREG, TCHAR, SAREG, TINT|TUNSIGNED, 0, RLEFT, " extb.l AL\n", }, /* uchar -> (u)int */ { SCONV, INAREG, SAREG, TUCHAR, SAREG, TINT|TUNSIGNED, 0, RLEFT, " and.l #255,AL\n", }, /* char -> (u)longlong */ { SCONV, INCREG, SAREG|SNAME|SOREG, TCHAR, SCREG, TLL, NCREG, RESC1, " move.b AL,U1\n extb.l U1\n" " smi A1\n extb.l A1\n", }, /* uchar -> (u)longlong */ { SCONV, INCREG, SAREG|SNAME|SOREG, TUCHAR, SCREG, TLL, NCREG, RESC1, " move.b AL,U1\n and.l #255,U1\n clr.l A1\n", }, /* char -> float/(l)double */ { SCONV, INDREG, SAREG, TCHAR, SDREG, TFP, NDREG, RESC1, " fmove.ZL AL,A1\n", }, /* (u)char -> float/(l)double */ { SCONV, INDREG, SAREG, TUCHAR, SDREG, TFP, NAREG|NDREG, RESC2, " clr.l A1\n move.b AL,A1\n fmove.w A1,A2\n", }, /* (u)short -> (u)char */ { SCONV, INAREG, SAREG, TSHORT|TUSHORT, SAREG, TCHAR|TUCHAR, 0, RLEFT, "", }, /* (u)short -> (u)short */ { SCONV, INAREG, SAREG, TSHORT|TUSHORT, SAREG, TSHORT|TUSHORT, 0, RLEFT, "", }, /* short -> (u)int */ { SCONV, INAREG|INBREG, SABREG, TSHORT, SABREG, TINT|TUNSIGNED, 0, RLEFT, " ext.l AL\n", }, /* ushort -> (u)int */ { SCONV, INAREG|INBREG, SABREG, TUSHORT, SABREG, TINT|TUNSIGNED, 0, RLEFT, " and.l #65535,AL\n", }, /* short -> (u)longlong */ { SCONV, INCREG, SAREG, TSHORT, SCREG, TLL, NCREG, RESC1, " move AL,U1\n ext.l U1\n" " smi A1\n extb.l A1\n", }, /* ushort -> (u)longlong */ { SCONV, INCREG, SAREG|SNAME|SOREG, TUSHORT, SCREG, TLL, NCREG, RESC1, " move.l AL,U1\n and.l #65535,U1\n clr.l A1\n", }, /* short -> float/(l)double */ { SCONV, INDREG, SAREG|SNAME|SOREG, TSHORT, SDREG, TFP, NDREG|NDSL, RESC1, " fmove.w AL,A1\n", }, /* ushort -> float/(l)double */ { SCONV, INDREG, SAREG|SNAME|SOREG, TUSHORT, SAREG|SDREG, TFP, NAREG|NDREG|NDSL, RESC2, " move.w AL,A1\n and.l #65535,A1\n" " fmove.l A1,A2\n", }, /* (u)int -> (u)char */ { SCONV, INAREG, SAREG, TWORD, SAREG, TCHAR|TUCHAR, 0, RLEFT, " and.l #255,AL\n", }, /* (u)int -> (u)short */ { SCONV, INAREG, SAREG, TWORD, SAREG, TSHORT|TUSHORT, 0, RLEFT, " and.l #65535,AL\n", }, /* (u)int -> (u)int - nothing */ { SCONV, INAREG, SAREG, TWORD, SAREG, TWORD, 0, RLEFT, "", }, /* int -> (u)longlong */ { SCONV, INCREG, SAREG|SOREG|SNAME, TINT, SCREG, TLL, NCREG, RESC1, " move.l AL,U1\n smi A1\n extb.l A1\n", }, /* (u)int -> (u)longlong */ { SCONV, INCREG, SAREG|SOREG|SNAME, TUNSIGNED, SCREG, TLL, NCREG, RESC1, " move.l AL,U1\n clr.l A1\n", }, /* int -> float/(l)double */ { SCONV, INDREG, SAREG|SNAME|SOREG, TINT, SDREG, TFP, NDREG|NDSL, RESC1, " fmove.l AL,A1\n", }, /* uint -> double */ { SCONV, INDREG, SAREG, TUNSIGNED, SDREG, TFLOAT|TDOUBLE, NDREG|NDSL, RESC1, " fmove.l AL,A1\n" " tst.l AL\n" " jge 1f\n" " fadd.d #0x41f0000000000000,A1\n" "1:\n", }, /* (u)longlong -> (u)char/(u)short/(u)int */ { SCONV, INAREG, SCREG|SOREG|SNAME, TLL, SAREG, TAREG, NAREG, RESC1, " movl UL,A1\n", }, /* (u)longlong to (u)longlong */ { SCONV, INCREG, SCREG, TLL, SCREG, TLL, 0, RLEFT, "", }, /* float/(l)double -> int/short/char (in reg) */ { SCONV, INAREG, SDREG, TFP, SAREG, TINT|TSHORT|TCHAR, NAREG, RESC1, " fmove.ZA AL,A1\n", }, /* float -> unsigned */ { SCONV, INAREG, SDREG, TFLOAT, SAREG, TUNSIGNED, NAREG|NDREG|NDSL, RESC1, "Z2 fcmp.s #0x4f000000,A2\n" " fjge 2f\n" " fintrz.x A2,A2\n" " fmove.l A2,A1\n" " jra 3f\n" "2: fsub.s #0x4f000000,A2\n" " fintrz.x A2,A2\n" " fmove.l A2,A1\n" " add.l #-2147483648,A1\n3:\n", }, /* float -> (l)double */ { SCONV, INDREG, SDREG, TFLOAT, SDREG, TDOUBLE|TLDOUBLE, 0, RLEFT, "", }, /* in fp regs -> do nothing */ /* double -> ldouble */ { SCONV, INDREG, SDREG, TDOUBLE, SDREG, TLDOUBLE, 0, RLEFT, "", }, /* in fp regs -> do nothing */ /* double -> uchar */ { SCONV, INAREG, SDREG, TDOUBLE, SAREG, TUCHAR, NAREG|NDREG|NDSL, RESC1, " fintrz.x AL,A2\n fmove.w A2,A1\n", }, /* double -> ushort */ { SCONV, INAREG, SDREG, TDOUBLE, SAREG, TUSHORT, NAREG|NDREG|NDSL, RESC1, " fintrz.x AL,A2\n fmove.l A2,A1\n", }, /* double -> unsigned */ { SCONV, INAREG, SDREG, TDOUBLE, SAREG, TUNSIGNED, NAREG|NDREG|NDSL, RESC1, "Z2 fcmp.d #0x41e0000000000000,A2\n" " fjge 2f\n" " fintrz.x A2,A2\n" " fmove.l A2,A1\n" " jra 3f\n" "2: fsub.d #0x41e0000000000000,A2\n" " fintrz.x A2,A2\n" " fmove.l A2,A1\n" " add.l #-2147483648,A1\n3:\n", }, /* (l)double -> float */ { SCONV, INDREG, SDREG, TDOUBLE|TLDOUBLE, SDREG, TFLOAT, NAREG, RLEFT, " fmove.s AL,A1\n fmove.s A1,AL\n", }, /* ldouble -> double */ { SCONV, INDREG, SDREG, TLDOUBLE, SDREG, TDOUBLE, NTEMP*2, RLEFT, " fmove.d AL,A1\n fmove.d A1,AL\n", }, /* assignment */ { ASSIGN, FOREFF, SCREG|SNAME|SOREG, TLL, SCREG|SNAME|SOREG, TLL, 0, 0, " move.l AR,AL\n" " move.l UR,UL\n", }, { ASSIGN, INCREG, SCREG|SNAME|SOREG, TLL, SCREG, TLL, 0, RDEST, " move.l AR,AL\n" " move.l UR,UL\n", }, { ASSIGN, FOREFF, SAREG|SNAME|SOREG, TAREG, SAREG|SNAME|SOREG, TAREG, 0, 0, " move.ZA AR,AL\n", }, { ASSIGN, FOREFF, SBREG|SNAME|SOREG, TPOINT, SBREG|SNAME|SOREG, TPOINT, 0, 0, " move.l AR,AL\n", }, { ASSIGN, FOREFF|INAREG, SAREG|SNAME|SOREG, TAREG, SAREG, TAREG, 0, RDEST, " move.ZA AR,AL\n", }, { ASSIGN, FOREFF|INBREG, SBREG|SNAME|SOREG, TPOINT, SBREG, TPOINT, 0, RDEST, " move.l AR,AL\n", }, { ASSIGN, FOREFF|INDREG, SNAME|SOREG, TFP, SDREG, TFP, 0, RDEST, " fmove.ZA AR,AL\n", }, { ASSIGN, FOREFF|INDREG, SDREG, TFP, SNAME|SOREG, TFP, 0, RDEST, " fmove.ZA AR,AL\n", }, { ASSIGN, FOREFF|INDREG, SDREG, TFP, SDREG, TFP, 0, RDEST, " fmove.x AR,AL\n", }, /* structure stuff */ { STASG, INBREG|FOREFF, SOREG|SNAME, TANY, SBREG, TPTRTO|TANY, NSPECIAL, RDEST, "ZQ", }, /* * Simple ops (add, sub, and, or, xor) */ /* Address registers may be added to (or subtracted from) */ { PLUS, FOREFF, SBREG|SNAME|SOREG|SCON, TWORD|TPOINT, SAREG, TWORD, 0, 0, " add.l AR,AL\n", }, { PLUS, FOREFF|INBREG, SBREG, TPOINT, SAREG|SNAME|SOREG|SCON, TWORD, 0, RLEFT|RESCC, " add.l AR,AL\n", }, { PLUS, FOREFF|INDREG, SDREG, TFP, SNAME|SOREG|SCON, TFP, 0, RLEFT|RESCC, " fadd.ZA AR,AL\n", }, { PLUS, FOREFF|INDREG, SDREG, TFP, SDREG, TFP, 0, RLEFT|RESCC, " fadd.x AR,AL\n", }, { PLUS, FOREFF|INCREG|RESCC, SCREG, TLL, SCREG, TLL, 0, RLEFT|RESCC, " add.l UR,UL\n addx.l AR,AL\n", }, { MINUS, FOREFF, SBREG|SNAME|SOREG|SCON, TWORD|TPOINT, SBREG, TWORD, 0, 0, " sub.l AR,AL\n", }, { MINUS, INAREG, SBREG, TPOINT, SBREG, TPOINT, NAREG, RESC1, " move.l AL,A1\n sub.l AR,A1\n", }, { MINUS, FOREFF|INBREG, SBREG, TWORD|TPOINT, SABREG|SNAME|SOREG|SCON, TWORD, 0, RLEFT|RESCC, " sub.l AR,AL\n", }, { MINUS, FOREFF|INDREG, SDREG, TFP, SNAME|SOREG|SCON, TFP, 0, RLEFT|RESCC, " fsub.ZA AR,AL\n", }, { MINUS, FOREFF|INDREG, SDREG, TFP, SDREG, TFP, 0, RLEFT|RESCC, " fsub.x AR,AL\n", }, { MINUS, FOREFF|INCREG|RESCC, SCREG, TLL, SCREG, TLL, 0, RLEFT|RESCC, " sub.l UR,UL\n subx.l AR,AL\n", }, /* two pointers give a scalar */ { MINUS, INAREG|FORCC, SBREG|SNAME|SOREG|SCON, TPOINT, SBREG|SNAME|SOREG|SCON, TPOINT, NAREG, RESC1|RESCC, " move.l AL,A1\n sub.l AR,A1\n", }, /* Hack to allow for opsimp later down */ /* Fortunately xor is not that common */ { ER, FOREFF|INAREG, SAREG, TAREG, SNAME|SOREG|SCON, TAREG, NAREG, RLEFT|RESCC, " move.ZA AR,A1\n eor.ZA A1,AL\n", }, { ER, FOREFF|INCREG|FORCC, SCREG|SNAME|SOREG|SCON, TLL, SCREG, TLL, 0, RLEFT|RESCC, " eor.l AR,AL\n eor.l UR,UL\n", }, { AND, FOREFF|INCREG|FORCC, SCREG, TLL, SCREG|SNAME|SOREG|SCON, TLL, 0, RLEFT|RESCC, " and.l AR,AL\n and.l UR,UL\n", }, { OR, FOREFF|INCREG|FORCC, SCREG, TLL, SCREG|SNAME|SOREG|SCON, TLL, 0, RLEFT|RESCC, " or.l AR,AL\n or.l UR,UL\n", }, { OPSIMP, FOREFF|INAREG, SAREG, TAREG, SAREG|SNAME|SOREG|SCON, TAREG, 0, RLEFT|RESCC, " Oz.ZA AR,AL\n", }, { OPSIMP, FOREFF, SAREG|SNAME|SOREG, TAREG, SAREG, TAREG, 0, RLEFT|RESCC, " Oz.ZA AR,AL\n", }, /* * Negate a word. */ { UMINUS, FOREFF|INCREG|FORCC, SCREG, TLL, SCREG, TLL, 0, RLEFT|RESCC, " neg.l UL\n negx.l AL\n", }, { UMINUS, FOREFF|INAREG|FORCC, SAREG, TAREG, SAREG, TAREG, 0, RLEFT|RESCC, " neg.ZA AL\n", }, { UMINUS, INDREG|FORCC, SDREG, TFP, SDREG, TFP, NDREG, RESC1|RESCC, " fmovecr #0xf,A1\n fsub.x AL,A1\n", }, { UMINUS, INDREG|FORCC, SNAME|SOREG, TFP, SDREG, TFP, NDREG, RESC1|RESCC, " fmovecr #0xf,A1\n fsub.ZA AL,A1\n", }, { COMPL, FOREFF|INAREG|FORCC, SAREG, TAREG, SAREG, TAREG, 0, RLEFT|RESCC, " not.ZA AL\n", }, { COMPL, FOREFF|INCREG, SCREG, TLL, SANY, TANY, 0, RLEFT, " not.l AL\n not.l UL\n", }, /* * Shift operators. */ { LS, INAREG|FOREFF, SAREG, TAREG, SAREG, TAREG, 0, RLEFT, " lsl.ZA AR,AL\n", }, { RS, INAREG|FOREFF, SAREG, TUNSIGNED|TUSHORT|TUCHAR, SAREG, TAREG, 0, RLEFT, " lsr.ZA AR,AL\n", }, { RS, INAREG|FOREFF, SAREG, TINT|TSHORT|TCHAR, SAREG, TAREG, 0, RLEFT, " asr.ZA AR,AL\n", }, /* * Leaf movements */ { OPLTYPE, INCREG, SANY, TANY, SCREG|SCON|SOREG|SNAME, TLL, NCREG|NCSL, RESC1, " move.l AL,A1\n move.l UL,U1\n", }, { OPLTYPE, INAREG, SANY, TANY, SAREG|SCON|SOREG|SNAME, TAREG, NAREG|NASL, RESC1, " move.ZA AL,A1\n", }, { OPLTYPE, INBREG, SANY, TANY, SBREG|SCON|SOREG|SNAME, TPOINT, NBREG|NBSL, RESC1, " move.l AL,A1\n", }, { OPLTYPE, INDREG, SANY, TANY, SNAME|SOREG, TFP, NDREG|NDSL, RESC1, " fmove.ZA AL,A1\n", }, { OPLTYPE, INDREG, SANY, TANY, SDREG, TFP, NDREG|NDSL, RESC1, " fmove.x AL,A1\n", }, /* * Indirection operators. */ { UMUL, INCREG, SANY, TPOINT, SOREG, TLL, NCREG, RESC1, " move.l AL,A1\n move.l UL,U1\n", }, { UMUL, INAREG, SANY, TPOINT|TWORD, SOREG, TPOINT|TWORD, NAREG|NASL, RESC1, " move.l AL,A1\n", }, { UMUL, INBREG, SANY, TPOINT|TWORD, SOREG, TPOINT|TWORD, NBREG|NBSL, RESC1, " move.l AL,A1\n", }, { UMUL, INDREG, SANY, TPOINT|TFP, SOREG, TFP, NDREG|NDSL, RESC1, " fmove.ZA AL,A1\n", }, { UMUL, INAREG, SANY, TPOINT|TWORD, SOREG, TSHORT|TUSHORT, NAREG|NASL, RESC1, " move.w AL,A1\n", }, { UMUL, INAREG, SANY, TPOINT|TWORD, SOREG, TCHAR|TUCHAR, NAREG|NASL, RESC1, " move.b AL,A1\n", }, /* * DIV/MOD/MUL */ { DIV, INAREG, SAREG|SNAME|SOREG, TINT, SAREG, TINT, 0, RLEFT, " divs.l AR,AL\n", }, { DIV, INAREG, SAREG|SNAME|SOREG, TUNSIGNED, SAREG, TUNSIGNED, 0, RLEFT, " divu.l AR,AL\n", }, { DIV, INDREG, SDREG, TDOUBLE|TLDOUBLE, SNAME|SOREG, TDOUBLE|TLDOUBLE, 0, RLEFT, " fdiv.ZA AR,AL\n", }, { DIV, INDREG, SDREG, TFP, SDREG, TFP, 0, RLEFT, " fdiv.x AR,AL\n", }, { DIV, INDREG, SDREG, TFLOAT, SNAME|SOREG, TFLOAT, 0, RLEFT, " fsgldiv.ZA AR,AL\n", }, { MOD, INAREG, SAREG, TINT, SAREG|SNAME|SOREG, TINT, NAREG*2, RESC1, "mov.l AL,A2\n divsl.l AR,A1:A2\n", }, { MOD, INAREG, SAREG, TUNSIGNED, SAREG|SNAME|SOREG, TUNSIGNED, NAREG*2, RESC1, "mov.l AL,A2\n divul.l AR,A1:A2\n", }, { MUL, INAREG, SAREG|SNAME|SOREG, TWORD, SAREG, TWORD, 0, RLEFT, " muls.l AR,AL\n", }, { MUL, INDREG, SDREG, TDOUBLE|TLDOUBLE, SNAME|SOREG, TDOUBLE|TLDOUBLE, 0, RLEFT, " fmul.ZA AR,AL\n", }, { MUL, INDREG, SDREG, TFP, SDREG, TFP, 0, RLEFT, " fmul.x AR,AL\n", }, { MUL, INDREG, SDREG, TFLOAT, SNAME|SOREG, TFLOAT, 0, RLEFT, " fsglmul.s AR,AL\n", }, /* * Function call nodes. * Too many of them. */ /* FOREFF both direct and indirect */ { UCALL, FOREFF, SCON, TANY, SANY, TANY, 0, 0, " ZC CL\n", }, { CALL, FOREFF, SCON, TANY, SANY, TANY, 0, 0, " ZC CL\nZB", }, { UCALL, FOREFF, SBREG, TANY, SANY, TANY, 0, 0, " jsr (AL)\n", }, { CALL, FOREFF, SBREG, TANY, SANY, TANY, 0, 0, " jsr (AL)\nZB", }, /* small scalar both direct and indirect */ { UCALL, INAREG, SCON, TANY, SAREG, TAREG, NAREG|NASL, RESC1, " ZC CL\n", }, { CALL, INAREG, SCON, TANY, SAREG, TAREG, NAREG|NASL, RESC1, " ZC CL\nZB", }, { UCALL, INAREG, SBREG, TANY, SAREG, TAREG, NAREG|NASL, RESC1, " jsr (AL)\n", }, { CALL, INAREG, SBREG, TANY, SAREG, TAREG, NAREG|NASL, RESC1, " jsr (AL)\nZB", }, /* long long both direct and indirect */ { UCALL, INCREG, SCON, TANY, SCREG, TLL, NCREG|NCSL, RESC1, " ZC CL\n", }, { CALL, INCREG, SCON, TANY, SCREG, TLL, NCREG|NCSL, RESC1, " ZC CL\nZB", }, { UCALL, INCREG, SBREG, TANY, SCREG, TLL, NCREG|NCSL, RESC1, " jsr (AL)\n", }, { CALL, INCREG, SBREG, TANY, SCREG, TLL, NCREG|NCSL, RESC1, " jsr (AL)\nZB", }, /* floats both direct and indirect */ { UCALL, INDREG, SCON, TANY, SDREG, TFP, NDREG|NDSL, RESC1, " ZC CL\n", }, { CALL, INDREG, SCON, TANY, SDREG, TFP, NDREG|NDSL, RESC1, " ZC CL\nZB", }, { UCALL, INDREG, SBREG, TANY, SDREG, TFP, NDREG|NDSL, RESC1, " jsr (AL)\n", }, { CALL, INDREG, SBREG, TANY, SDREG, TFP, NDREG|NDSL, RESC1, " jsr (AL)\nZB", }, /* pointers both direct and indirect */ { UCALL, INBREG, SCON, TANY, SBREG, TWORD|TPOINT, NBREG|NBSL, RESC1, " ZC CL\n", }, { CALL, INBREG, SCON, TANY, SBREG, TWORD|TPOINT, NBREG|NBSL, RESC1, " ZC CL\nZB", }, { UCALL, INBREG, SBREG, TANY, SBREG, TWORD|TPOINT, NBREG|NBSL, RESC1, " jsr (AL)\n", }, { CALL, INBREG, SBREG, TANY, SBREG, TWORD|TPOINT, NBREG|NBSL, RESC1, " jsr (AL)\nZB", }, /* struct return both direct and indirect */ { USTCALL, INBREG|FOREFF, SCON, TANY, SBREG, TWORD|TPOINT, NBREG|NBSL, RESC1, "ZP ZC CL\n", }, { STCALL, INBREG|FOREFF, SCON, TANY, SBREG, TWORD|TPOINT, NBREG|NBSL, RESC1, "ZP ZC CL\nZB", }, { USTCALL, INBREG|FOREFF, SBREG, TANY, SBREG, TWORD|TPOINT, NBREG|NBSL, RESC1, "ZP jsr (AL)\n", }, { STCALL, INBREG|FOREFF, SBREG, TANY, SBREG, TWORD|TPOINT, NBREG|NBSL, RESC1, "ZP jsr (AL)\nZB", }, /* * Arguments to functions. */ { FUNARG, FOREFF, SAREG|SOREG|SNAME|SCON, TINT|TUNSIGNED, SANY, TANY, 0, RNULL, " move.l AL,-(%sp)\n", }, { FUNARG, FOREFF, SCREG|SOREG|SNAME|SCON, TLL, SANY, TANY, 0, RNULL, " move.l UL,-(%sp)\n move.l AL,-(%sp)\n", }, { FUNARG, FOREFF, SCON, TPOINT, SANY, TANY, 0, RNULL, " pea CL\n", }, { FUNARG, FOREFF, SCON|SABREG|SNAME, TWORD|TPOINT, SANY, TWORD|TPOINT, 0, RNULL, " move.l AL,-(%sp)\n", }, { FUNARG, FOREFF, SOREG, TWORD|TPOINT, SANY, TWORD|TPOINT, 0, RNULL, " move.l AL,-(%sp)\n", }, { FUNARG, FOREFF, SDREG, TFP, SANY, TFP, 0, RNULL, " fmove.ZA AL,-(%sp)\n", }, { STARG, FOREFF, SBREG, TPTRTO|TSTRUCT, SANY, TSTRUCT, NAREG|NBREG, RNULL, "ZS", }, /* * Logical/branching operators */ /* Comparisions, take care of everything */ #if 0 { OPLOG, FORCC, SHLL|SOREG|SNAME, TLL, SHLL, TLL, 0, 0, "ZD", }, #endif { OPLOG, INCREG|FORCC, SCREG, TLL, SCREG, TLL, 0, RESCC|RLEFT, /* trash left nodes */ " sub.l UR,UL\n subx.l AR,AL\n", }, { OPLOG, FORCC, SAREG, TWORD, SCON|SAREG|SOREG|SNAME, TWORD, 0, RESCC, " cmp.l AR,AL\n", }, { OPLOG, FORCC, SBREG, TPOINT, SCON|SBREG|SOREG|SNAME, TPOINT, 0, RESCC, " cmp.l AR,AL\n", }, /* jumps below emitted in zzzcode */ { OPLOG, FORCC, SDREG, TFP, SCON|SOREG|SNAME, TFP, 0, 0, " fcmp.ZL AR,AL\n ZF", }, { OPLOG, FORCC, SDREG, TFP, SDREG, TFP, 0, 0, " fcmp.x AR,AL\n ZF", }, /* * Jumps. */ { GOTO, FOREFF, SCON, TANY, SANY, TANY, 0, RNOP, " jmp LL\n", }, #if defined(GCC_COMPAT) || defined(LANG_F77) { GOTO, FOREFF, SBREG, TANY, SANY, TANY, 0, RNOP, " jmp (AL)\n", }, #endif # define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,"" { UMUL, DF( UMUL ), }, { ASSIGN, DF(ASSIGN), }, { STASG, DF(STASG), }, { FLD, DF(FLD), }, { OPLEAF, DF(NAME), }, /* { INIT, DF(INIT), }, */ { OPUNARY, DF(UMINUS), }, { OPANY, DF(BITYPE), }, { FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" }, }; int tablesize = sizeof(table)/sizeof(table[0]); pcc-20181216/arch/mips004075500017500000000000000000001340533064000132735ustar raggewheelpcc-20181216/arch/mips/CVS004075500017500000000000000000001340533064000137265ustar raggewheelpcc-20181216/arch/mips/CVS/Root010064400017500000000000000000111340533064000146400ustar raggewheel/cvsroot pcc-20181216/arch/mips/CVS/Repository010064400017500000000000000000161340533064000161010ustar raggewheelpcc/arch/mips pcc-20181216/arch/mips/CVS/Entries010064400017500000000000000004371340533064000153420ustar raggewheel/TODO/1.2/Thu Dec 13 04:20:14 2007// /code.c/1.27/Wed Jan 6 16:11:24 2016// /local.c/1.39/Sun Dec 2 10:56:58 2018// /local2.c/1.32/Mon Sep 26 16:45:42 2016// /macdefs.h/1.25/Sun Dec 2 10:56:58 2018// /order.c/1.12/Sun Nov 30 21:00:24 2008// /table.c/1.18/Tue Jan 5 12:23:22 2016// D pcc-20181216/arch/mips/TODO010064400017500000000000000001231073013137600140360ustar raggewheel* Fix floating-point arguments in registers * Fix structure arguments in registers pcc-20181216/arch/mips/code.c010064400017500000000000000377261264323625400144550ustar raggewheel/* $Id: code.c,v 1.27 2016/01/06 16:11:24 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and * Simon Olsson (simols-1@student.ltu.se) 2005. */ #include #include "pass1.h" #ifndef LANG_CXX #undef NIL #define NIL NULL #define NODE P1ND #define nfree p1nfree #define ccopy p1tcopy #define tfree p1tfree #endif /* * Print out assembler segment name. */ void setseg(int seg, char *name) { switch (seg) { case PROG: name = ".text"; break; case DATA: case LDATA: name = ".data"; break; case STRNG: case RDATA: name = ".section .rodata"; break; case UDATA: break; case PICLDATA: case PICDATA: name = ".section .data.rel.rw,\"aw\",@progbits"; break; case PICRDATA: name = ".section .data.rel.ro,\"aw\",@progbits"; break; case TLSDATA: name = ".section .tdata,\"awT\",@progbits"; break; case TLSUDATA: name = ".section .tbss,\"awT\",@nobits"; break; case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break; case DTORS: name = ".section\t.dtors,\"aw\",@progbits"; break; case NMSEG: printf("\t.section %s,\"a%c\",@progbits\n", name, cftnsp ? 'x' : 'w'); return; } printf("\t%s\n", name); } /* * Define everything needed to print out some data (or text). * This means segment, alignment, visibility, etc. */ void defloc(struct symtab *sp) { char *n; if (ISFTN(sp->stype)) return; /* XXX until fixed */ n = getexname(sp); if (sp->sclass == EXTDEF) printf(" .globl %s\n", n); if (sp->slevel == 0) { #ifdef USE_GAS printf("\t.type %s,@%s\n", n, ISFTN(sp->stype) ? "function" : "object"); if (!ISFTN(sp->stype)) printf("\t.size %s," CONFMT "\n", n, tsize(sp->stype, sp->sdf, sp->sap)); #endif printf("%s:\n", n); } else printf(LABFMT ":\n", sp->soffset); } /* * cause the alignment to become a multiple of n */ void defalign(int n) { n = ispow2(n / SZCHAR); if (n == -1) cerror("defalign: n != 2^i"); printf("\t.p2align %d\n", n); } static int rvnr; /* * code for the end of a function * deals with struct return here */ void efcode(void) { NODE *p, *q; int tempnr; int ty; if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) return; ty = cftnsp->stype - FTN; q = block(REG, NIL, NIL, INCREF(ty), 0, cftnsp->sap); q->n_rval = V0; p = tempnode(0, INCREF(ty), 0, cftnsp->sap); tempnr = regno(p); p = buildtree(ASSIGN, p, q); ecomp(p); q = tempnode(tempnr, INCREF(ty), 0, cftnsp->sap); q = buildtree(UMUL, q, NIL); p = tempnode(rvnr, INCREF(ty), 0, cftnsp->sap); p = buildtree(UMUL, p, NIL); p = buildtree(ASSIGN, p, q); ecomp(p); q = tempnode(rvnr, INCREF(ty), 0, cftnsp->sap); p = block(REG, NIL, NIL, INCREF(ty), 0, cftnsp->sap); p->n_rval = V0; p = buildtree(ASSIGN, p, q); ecomp(p); } /* Put a symbol in a temporary * used by bfcode() and its helpers */ static void putintemp(struct symtab *sym) { NODE *p; p = tempnode(0, sym->stype, sym->sdf, sym->sap); p = buildtree(ASSIGN, p, nametree(sym)); sym->soffset = regno(p->n_left); sym->sflags |= STNODE; ecomp(p); } /* setup the hidden pointer to struct return parameter * used by bfcode() */ static void param_retptr(void) { NODE *p, *q; p = tempnode(0, PTR+STRTY, 0, cftnsp->sap); rvnr = regno(p); q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap); q->n_rval = A0; p = buildtree(ASSIGN, p, q); ecomp(p); } /* setup struct parameter * push the registers out to memory * used by bfcode() */ static void param_struct(struct symtab *sym, int *regp) { int reg = *regp; NODE *p, *q; int navail; int sz; int off; int num; int i; navail = nargregs - (reg - A0); sz = tsize(sym->stype, sym->sdf, sym->sap) / SZINT; off = ARGINIT/SZINT + (reg - A0); num = sz > navail ? navail : sz; for (i = 0; i < num; i++) { q = block(REG, NIL, NIL, INT, 0, 0); q->n_rval = reg++; p = block(REG, NIL, NIL, INT, 0, 0); p->n_rval = FP; p = block(PLUS, p, bcon(4*off++), INT, 0, 0); p = block(UMUL, p, NIL, INT, 0, 0); p = buildtree(ASSIGN, p, q); ecomp(p); } *regp = reg; } /* setup a 64-bit parameter (double/ldouble/longlong) * used by bfcode() */ static void param_64bit(struct symtab *sym, int *regp, int dotemps) { int reg = *regp; NODE *p, *q; int navail; /* alignment */ ++reg; reg &= ~1; navail = nargregs - (reg - A0); if (navail < 2) { /* would have appeared half in registers/half * on the stack, but alignment ensures it * appears on the stack */ if (dotemps) putintemp(sym); *regp = reg; return; } q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap); q->n_rval = A0A1 + (reg - A0); if (dotemps) { p = tempnode(0, sym->stype, sym->sdf, sym->sap); sym->soffset = regno(p); sym->sflags |= STNODE; } else { p = nametree(sym); } p = buildtree(ASSIGN, p, q); ecomp(p); *regp = reg + 2; } /* setup a 32-bit param on the stack * used by bfcode() */ static void param_32bit(struct symtab *sym, int *regp, int dotemps) { NODE *p, *q; q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap); q->n_rval = (*regp)++; if (dotemps) { p = tempnode(0, sym->stype, sym->sdf, sym->sap); sym->soffset = regno(p); sym->sflags |= STNODE; } else { p = nametree(sym); } p = buildtree(ASSIGN, p, q); ecomp(p); } /* * XXX This is a hack. We cannot have (l)doubles in more than one * register class. So we bounce them in and out of temps to * move them in and out of the right registers. */ static void param_double(struct symtab *sym, int *regp, int dotemps) { int reg = *regp; NODE *p, *q, *t; int navail; int tmpnr; /* alignment */ ++reg; reg &= ~1; navail = nargregs - (reg - A0); if (navail < 2) { /* would have appeared half in registers/half * on the stack, but alignment ensures it * appears on the stack */ if (dotemps) putintemp(sym); *regp = reg; return; } t = tempnode(0, LONGLONG, 0, 0); tmpnr = regno(t); q = block(REG, NIL, NIL, LONGLONG, 0, 0); q->n_rval = A0A1 + (reg - A0); p = buildtree(ASSIGN, t, q); ecomp(p); if (dotemps) { sym->soffset = tmpnr; sym->sflags |= STNODE; } else { q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap); p = nametree(sym); p = buildtree(ASSIGN, p, q); ecomp(p); } *regp = reg + 2; } /* * XXX This is a hack. We cannot have floats in more than one * register class. So we bounce them in and out of temps to * move them in and out of the right registers. */ static void param_float(struct symtab *sym, int *regp, int dotemps) { NODE *p, *q, *t; int tmpnr; t = tempnode(0, INT, 0, 0); tmpnr = regno(t); q = block(REG, NIL, NIL, INT, 0, 0); q->n_rval = (*regp)++; p = buildtree(ASSIGN, t, q); ecomp(p); if (dotemps) { sym->soffset = tmpnr; sym->sflags |= STNODE; } else { q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap); p = nametree(sym); p = buildtree(ASSIGN, p, q); ecomp(p); } } /* * code for the beginning of a function; a is an array of * indices in symtab for the arguments; n is the number */ void bfcode(struct symtab **sp, int cnt) { union arglist *usym; int lastreg = A0 + nargregs - 1; int saveallargs = 0; int i, reg; /* * Detect if this function has ellipses and save all * argument register onto stack. */ usym = cftnsp->sdf->dfun; while (usym && usym->type != TNULL) { if (usym->type == TELLIPSIS) { saveallargs = 1; break; } ++usym; } reg = A0; /* assign hidden return structure to temporary */ if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { param_retptr(); ++reg; } /* recalculate the arg offset and create TEMP moves */ for (i = 0; i < cnt; i++) { if ((reg > lastreg) && !xtemps) break; else if (reg > lastreg) putintemp(sp[i]); else if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY) param_struct(sp[i], ®); else if (DEUNSIGN(sp[i]->stype) == LONGLONG) param_64bit(sp[i], ®, xtemps && !saveallargs); else if (sp[i]->stype == DOUBLE || sp[i]->stype == LDOUBLE) param_double(sp[i], ®, xtemps && !saveallargs); else if (sp[i]->stype == FLOAT) param_float(sp[i], ®, xtemps && !saveallargs); else param_32bit(sp[i], ®, xtemps && !saveallargs); } /* if saveallargs, save the rest of the args onto the stack */ if (!saveallargs) return; while (reg <= lastreg) { NODE *p, *q; int off = ARGINIT/SZINT + (reg - A0); q = block(REG, NIL, NIL, INT, 0, 0); q->n_rval = reg++; p = block(REG, NIL, NIL, INT, 0, 0); p->n_rval = FP; p = block(PLUS, p, bcon(4*off), INT, 0, 0); p = block(UMUL, p, NIL, INT, 0, 0); p = buildtree(ASSIGN, p, q); ecomp(p); } } /* called just before final exit */ /* flag is 1 if errors, 0 if none */ void ejobcode(int flag) { } void bjobcode(void) { printf("\t.section .mdebug.abi32\n"); printf("\t.previous\n"); /* only if -fpic or -fPIC */ if (kflag > 0) printf("\t.abicalls\n"); } #ifdef notdef /* * Print character t at position i in one string, until t == -1. * Locctr & label is already defined. */ void bycode(int t, int i) { static int lastoctal = 0; /* put byte i+1 in a string */ if (t < 0) { if (i != 0) puts("\\000\""); } else { if (i == 0) printf("\t.ascii \""); if (t == 0) return; else if (t == '\\' || t == '"') { lastoctal = 0; putchar('\\'); putchar(t); } else if (t == 011) { printf("\\t"); } else if (t == 012) { printf("\\n"); } else if (t < 040 || t >= 0177) { lastoctal++; printf("\\%o",t); } else if (lastoctal && '0' <= t && t <= '9') { lastoctal = 0; printf("\"\n\t.ascii \"%c", t); } else { lastoctal = 0; putchar(t); } } } #endif /* fix up type of field p */ void fldty(struct symtab *p) { } /* * XXX - fix genswitch. */ int mygenswitch(int num, TWORD type, struct swents **p, int n) { return 0; } /* setup call stack with a structure */ /* called from moveargs() */ static NODE * movearg_struct(NODE *p, NODE *parent, int *regp) { int reg = *regp; NODE *l, *q, *t, *r; int tmpnr; int navail; int off; int num; int sz; int ty; int i; navail = nargregs - (reg - A0); sz = tsize(p->n_type, p->n_df, p->n_ap) / SZINT; num = sz > navail ? navail : sz; l = p->n_left; nfree(p); ty = l->n_type; t = tempnode(0, l->n_type, l->n_df, l->n_ap); tmpnr = regno(t); l = buildtree(ASSIGN, t, l); if (p != parent) { q = parent->n_left; } else q = NULL; /* copy structure into registers */ for (i = 0; i < num; i++) { t = tempnode(tmpnr, ty, 0, 0); t = block(SCONV, t, NIL, PTR+INT, 0, 0); t = block(PLUS, t, bcon(4*i), PTR+INT, 0, 0); t = buildtree(UMUL, t, NIL); r = block(REG, NIL, NIL, INT, 0, 0); r->n_rval = reg++; r = buildtree(ASSIGN, r, t); if (q == NULL) q = r; else q = block(CM, q, r, INT, 0, 0); } off = ARGINIT/SZINT + nargregs; for (i = num; i < sz; i++) { t = tempnode(tmpnr, ty, 0, 0); t = block(SCONV, t, NIL, PTR+INT, 0, 0); t = block(PLUS, t, bcon(4*i), PTR+INT, 0, 0); t = buildtree(UMUL, t, NIL); r = block(REG, NIL, NIL, INT, 0, 0); r->n_rval = FP; r = block(PLUS, r, bcon(4*off++), INT, 0, 0); r = block(UMUL, r, NIL, INT, 0, 0); r = buildtree(ASSIGN, r, t); if (q == NULL) q = r; else q = block(CM, q, r, INT, 0, 0); } if (parent->n_op == CM) { parent->n_left = q; q = l; } else { q = block(CM, q, l, INT, 0, 0); } *regp = reg; return q; } /* setup call stack with 64-bit argument */ /* called from moveargs() */ static NODE * movearg_64bit(NODE *p, int *regp) { int reg = *regp; NODE *q; int lastarg; /* alignment */ ++reg; reg &= ~1; lastarg = A0 + nargregs - 1; if (reg > lastarg) { *regp = reg; return block(FUNARG, p, NIL, p->n_type, p->n_df, p->n_ap); } q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap); q->n_rval = A0A1 + (reg - A0); q = buildtree(ASSIGN, q, p); *regp = reg + 2; return q; } /* setup call stack with 32-bit argument */ /* called from moveargs() */ static NODE * movearg_32bit(NODE *p, int *regp) { int reg = *regp; NODE *q; q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap); q->n_rval = reg++; q = buildtree(ASSIGN, q, p); *regp = reg; return q; } static NODE * moveargs(NODE *p, int *regp) { NODE *r, **rp; int lastreg; int reg; if (p->n_op == CM) { p->n_left = moveargs(p->n_left, regp); r = p->n_right; rp = &p->n_right; } else { r = p; rp = &p; } lastreg = A0 + nargregs - 1; reg = *regp; if (reg > lastreg && r->n_op != STARG) *rp = block(FUNARG, r, NIL, r->n_type, r->n_df, r->n_ap); else if (r->n_op == STARG) { *rp = movearg_struct(r, p, regp); } else if (DEUNSIGN(r->n_type) == LONGLONG) { *rp = movearg_64bit(r, regp); } else if (r->n_type == DOUBLE || r->n_type == LDOUBLE) { /* XXX bounce in and out of temporary to change to longlong */ NODE *t1 = tempnode(0, LONGLONG, 0, 0); int tmpnr = regno(t1); NODE *t2 = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap); t1 = movearg_64bit(t1, regp); r = block(ASSIGN, t2, r, r->n_type, r->n_df, r->n_ap); if (p->n_op == CM) { p->n_left = buildtree(CM, p->n_left, t1); p->n_right = r; } else { p = buildtree(CM, t1, r); } } else if (r->n_type == FLOAT) { /* XXX bounce in and out of temporary to change to int */ NODE *t1 = tempnode(0, INT, 0, 0); int tmpnr = regno(t1); NODE *t2 = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap); t1 = movearg_32bit(t1, regp); r = block(ASSIGN, t2, r, r->n_type, r->n_df, r->n_ap); if (p->n_op == CM) { p->n_left = buildtree(CM, p->n_left, t1); p->n_right = r; } else { p = buildtree(CM, t1, r); } } else { *rp = movearg_32bit(r, regp); } return p; } /* * Called with a function call with arguments as argument. * This is done early in buildtree() and only done once. */ NODE * funcode(NODE *p) { int regnum = A0; NODE *l, *r, *t, *q; int ty; l = p->n_left; r = p->n_right; /* * if returning a structure, make the first argument * a hidden pointer to return structure. */ ty = DECREF(l->n_type); if (ty == STRTY+FTN || ty == UNIONTY+FTN) { ty = DECREF(l->n_type) - FTN; q = tempnode(0, ty, l->n_df, l->n_ap); q = buildtree(ADDROF, q, NIL); if (r->n_op != CM) { p->n_right = block(CM, q, r, INCREF(ty), l->n_df, l->n_ap); } else { for (t = r; t->n_left->n_op == CM; t = t->n_left) ; t->n_left = block(CM, q, t->n_left, INCREF(ty), l->n_df, l->n_ap); } } p->n_right = moveargs(p->n_right, ®num); return p; } NODE * builtin_cfa(const struct bitable *bt, NODE *a) { uerror("missing builtin_cfa"); return bcon(0); } NODE * builtin_frame_address(const struct bitable *bt, NODE *a) { uerror("missing builtin_frame_address"); return bcon(0); } NODE * builtin_return_address(const struct bitable *bt, NODE *a) { uerror("missing builtin_return_address"); return bcon(0); } pcc-20181216/arch/mips/local.c010064400017500000000000000375571340073517200146320ustar raggewheel/* $Id: local.c,v 1.39 2018/12/02 10:56:58 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and * Simon Olsson (simols-1@student.ltu.se) 2005. */ #include "pass1.h" #ifndef LANG_CXX #define NODE P1ND #define ccopy p1tcopy #define tcopy p1tcopy #define tfree p1tfree #define nfree p1nfree #define fwalk p1fwalk #define talloc p1alloc #endif #define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz)) /* this is called to do local transformations on * an expression tree preparitory to its being * written out in intermediate code. */ NODE * clocal(NODE *p) { struct symtab *q; NODE *r, *l; int o; int m; TWORD ty; int tmpnr, isptrvoid = 0; #ifdef PCC_DEBUG if (xdebug) { printf("clocal in: %p\n", p); fwalk(p, eprint, 0); } #endif switch (o = p->n_op) { case UCALL: case CALL: case STCALL: case USTCALL: if (p->n_type == VOID) break; /* * if the function returns void*, ecode() invokes * delvoid() to convert it to uchar*. * We just let this happen on the ASSIGN to the temp, * and cast the pointer back to void* on access * from the temp. */ if (p->n_type == PTR+VOID) isptrvoid = 1; r = tempnode(0, p->n_type, p->n_df, p->n_ap); tmpnr = regno(r); r = block(ASSIGN, r, p, p->n_type, p->n_df, p->n_ap); p = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap); if (isptrvoid) { p = block(PCONV, p, NIL, PTR+VOID, p->n_df, 0); } p = buildtree(COMOP, r, p); break; case NAME: if ((q = p->n_sp) == NULL) return p; /* Nothing to care about */ switch (q->sclass) { case PARAM: case AUTO: /* fake up a structure reference */ r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); slval(r, 0); r->n_rval = FP; p = stref(block(STREF, r, p, 0, 0, 0)); break; case STATIC: if (q->slevel == 0) break; slval(p, 0); p->n_sp = q; break; case REGISTER: p->n_op = REG; slval(p, 0); p->n_rval = q->soffset; break; } break; case FUNARG: /* Args smaller than int are given as int */ if (p->n_type != CHAR && p->n_type != UCHAR && p->n_type != SHORT && p->n_type != USHORT) break; p->n_left = block(SCONV, p->n_left, NIL, INT, 0, 0); p->n_type = INT; p->n_ap = 0; p->n_rval = SZINT; break; case CBRANCH: l = p->n_left; /* * Remove unnecessary conversion ops. */ if (clogop(l->n_op) && l->n_left->n_op == SCONV) { if (coptype(l->n_op) != BITYPE) break; if (l->n_right->n_op == ICON) { r = l->n_left->n_left; if (r->n_type >= FLOAT && r->n_type <= LDOUBLE) break; /* Type must be correct */ ty = r->n_type; nfree(l->n_left); l->n_left = r; l->n_type = ty; l->n_right->n_type = ty; } #if 0 else if (l->n_right->n_op == SCONV && l->n_left->n_type == l->n_right->n_type) { r = l->n_left->n_left; nfree(l->n_left); l->n_left = r; r = l->n_right->n_left; nfree(l->n_right); l->n_right = r; } #endif } break; case PCONV: /* Remove redundant PCONV's. Be careful */ l = p->n_left; if (l->n_op == ICON) { slval(l, (unsigned)glval(l)); goto delp; } if (l->n_type < INT || DEUNSIGN(l->n_type) == LONGLONG) { /* float etc? */ p->n_left = block(SCONV, l, NIL, UNSIGNED, 0, 0); break; } /* if left is SCONV, cannot remove */ if (l->n_op == SCONV) break; /* avoid ADDROF TEMP */ if (l->n_op == ADDROF && l->n_left->n_op == TEMP) break; /* if conversion to another pointer type, just remove */ if (p->n_type > BTMASK && l->n_type > BTMASK) goto delp; break; delp: l->n_type = p->n_type; l->n_qual = p->n_qual; l->n_df = p->n_df; l->n_ap = p->n_ap; nfree(p); p = l; break; case SCONV: l = p->n_left; if (p->n_type == l->n_type) { nfree(p); p = l; break; } if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 && tsize(p->n_type, p->n_df, p->n_ap) == tsize(l->n_type, l->n_df, l->n_ap)) { if (p->n_type != FLOAT && p->n_type != DOUBLE && l->n_type != FLOAT && l->n_type != DOUBLE && l->n_type != LDOUBLE && p->n_type != LDOUBLE) { if (l->n_op == NAME || l->n_op == UMUL || l->n_op == TEMP) { l->n_type = p->n_type; nfree(p); p = l; break; } } } if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT && coptype(l->n_op) == BITYPE) { l->n_type = p->n_type; nfree(p); p = l; } if (DEUNSIGN(p->n_type) == SHORT && DEUNSIGN(l->n_type) == SHORT) { nfree(p); p = l; } /* convert float/double to int before to (u)char/(u)short */ if ((DEUNSIGN(p->n_type) == CHAR || DEUNSIGN(p->n_type) == SHORT) && (l->n_type == FLOAT || l->n_type == DOUBLE || l->n_type == LDOUBLE)) { p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap); p->n_left->n_type = INT; break; } /* convert (u)char/(u)short to int before float/double */ if ((p->n_type == FLOAT || p->n_type == DOUBLE || p->n_type == LDOUBLE) && (DEUNSIGN(l->n_type) == CHAR || DEUNSIGN(l->n_type) == SHORT)) { p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap); p->n_left->n_type = INT; break; } o = l->n_op; m = p->n_type; if (o == ICON) { /* * Can only end up here if o is an address, * and in that case the only compile-time conversion * possible is to int. */ if ((TMASK & l->n_type) == 0 && l->n_sp == NULL) cerror("SCONV ICON"); if (l->n_sp == 0) { p->n_type = UNSIGNED; concast(l, m); } else if (m != INT && m != UNSIGNED) break; l->n_type = m; l->n_ap = 0; nfree(p); return l; } else if (l->n_op == FCON) cerror("SCONV FCON"); break; case MOD: case DIV: if (o == DIV && p->n_type != CHAR && p->n_type != SHORT) break; if (o == MOD && p->n_type != CHAR && p->n_type != SHORT) break; /* make it an int division by inserting conversions */ p->n_left = block(SCONV, p->n_left, NIL, INT, 0, 0); p->n_right = block(SCONV, p->n_right, NIL, INT, 0, 0); p = block(SCONV, p, NIL, p->n_type, 0, 0); p->n_left->n_type = INT; break; case FORCE: /* put return value in return reg */ p->n_op = ASSIGN; p->n_right = p->n_left; p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0); p->n_left->n_rval = RETREG(p->n_type); break; } #ifdef PCC_DEBUG if (xdebug) { printf("clocal out: %p\n", p); fwalk(p, eprint, 0); } #endif return(p); } void myp2tree(NODE *p) { struct symtab *sp; if (p->n_op != FCON) return; /* Write float constants to memory */ sp = IALLOC(sizeof(struct symtab)); sp->sclass = STATIC; sp->sap = 0; sp->slevel = 1; /* fake numeric label */ sp->soffset = getlab(); sp->sflags = 0; sp->stype = p->n_type; sp->squal = (CON >> TSHIFT); defloc(sp); ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p); p->n_op = NAME; slval(p, 0); p->n_sp = sp; } /*ARGSUSED*/ int andable(NODE *p) { return(1); /* all names can have & taken on them */ } /* * is an automatic variable of type t OK for a register variable */ int cisreg(TWORD t) { if (t == INT || t == UNSIGNED || t == LONG || t == ULONG) return(1); return 0; /* XXX - fix reg assignment in pftn.c */ } /* * Allocate off bits on the stack. p is a tree that when evaluated * is the multiply count for off, t is a NAME node where to write * the allocated address. */ void spalloc(NODE *t, NODE *p, OFFSZ off) { NODE *sp; int nbytes = off / SZCHAR; p = buildtree(MUL, p, bcon(nbytes)); p = buildtree(PLUS, p, bcon(7)); p = buildtree(AND, p, bcon(~7)); /* subtract the size from sp */ sp = block(REG, NIL, NIL, p->n_type, 0, 0); slval(sp, 0); sp->n_rval = SP; ecomp(buildtree(MINUSEQ, sp, p)); /* save the address of sp */ sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap); sp->n_rval = SP; t->n_type = sp->n_type; ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */ } /* * print out a constant node * mat be associated with a label */ int ninval(CONSZ off, int fsz, NODE *p) { struct symtab *q; TWORD t; #ifndef USE_GAS int i, j; #endif t = p->n_type; if (t > BTMASK) p->n_type = t = INT; /* pointer */ if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT) uerror("element not constant"); switch (t) { case LONGLONG: case ULONGLONG: #ifdef USE_GAS printf("\t.dword %lld\n", (long long)glval(p)); #else i = glval(p) >> 32; j = glval(p) & 0xffffffff; p->n_type = INT; if (bigendian) { slval(p, j); ninval(off, 32, p); slval(p, i); ninval(off+32, 32, p); } else { slval(p, i); ninval(off, 32, p); slval(p, j); ninval(off+32, 32, p); } #endif break; case INT: case UNSIGNED: printf("\t.word " CONFMT, (CONSZ)glval(p)); if ((q = p->n_sp) != NULL) { if ((q->sclass == STATIC && q->slevel > 0)) { printf("+" LABFMT, q->soffset); } else printf("+%s", getexname(q)); } printf("\n"); break; case SHORT: case USHORT: astypnames[SHORT] = astypnames[USHORT] = "\t.half"; return 0; default: return 0; } return 1; } /* make a name look like an external name in the local machine */ char * exname(char *p) { if (p == NULL) return ""; return p; } /* * map types which are not defined on the local machine */ TWORD ctype(TWORD type) { switch (BTYPE(type)) { case LONG: MODTYPE(type,INT); break; case ULONG: MODTYPE(type,UNSIGNED); } return (type); } void calldec(NODE *p, NODE *q) { } void extdec(struct symtab *q) { } /* make a common declaration for id, if reasonable */ void defzero(struct symtab *sp) { int off; off = tsize(sp->stype, sp->sdf, sp->sap); off = (off+(SZCHAR-1))/SZCHAR; printf(" .%scomm ", sp->sclass == STATIC ? "l" : ""); if (sp->slevel == 0) printf("%s,0%o\n", getexname(sp), off); else printf(LABFMT ",0%o\n", sp->soffset, off); } #ifdef notdef /* make a common declaration for id, if reasonable */ void commdec(struct symtab *q) { int off; off = tsize(q->stype, q->sdf, q->ssue); off = (off+(SZCHAR-1))/SZCHAR; printf(" .comm %s,%d\n", exname(q->soname), off); } /* make a local common declaration for id, if reasonable */ void lcommdec(struct symtab *q) { int off; off = tsize(q->stype, q->sdf, q->ssue); off = (off+(SZCHAR-1))/SZCHAR; if (q->slevel == 0) printf("\t.lcomm %s,%d\n", exname(q->soname), off); else printf("\t.lcomm " LABFMT ",%d\n", q->soffset, off); } /* * print a (non-prog) label. */ void deflab1(int label) { printf(LABFMT ":\n", label); } /* ro-text, rw-data, ro-data, ro-strings */ static char *loctbl[] = { "text", "data", "rdata", "rdata" }; void setloc1(int locc) { if (locc == lastloc && locc != STRNG) return; if (locc == RDATA && lastloc == STRNG) return; if (locc != lastloc) { lastloc = locc; printf("\t.%s\n", loctbl[locc]); } if (locc == STRNG) printf("\t.align 2\n"); } #endif /* * va_start(ap, last) implementation. * * f is the NAME node for this builtin function. * a is the argument list containing: * CM * ap last * * It turns out that this is easy on MIPS. Just write the * argument registers to the stack in va_arg_start() and * use the traditional method of walking the stackframe. */ NODE * mips_builtin_stdarg_start(const struct bitable *bt, NODE *a) { NODE *p, *q; int sz = 1; /* check num args and type */ if (a == NULL || a->n_op != CM || a->n_left->n_op == CM || !ISPTR(a->n_left->n_type)) goto bad; /* must first deal with argument size; use int size */ p = a->n_right; if (p->n_type < INT) { /* round up to word */ sz = SZINT / tsize(p->n_type, p->n_df, p->n_ap); } p = buildtree(ADDROF, p, NIL); /* address of last arg */ p = optim(buildtree(PLUS, p, bcon(sz))); q = block(NAME, NIL, NIL, PTR+VOID, 0, 0); q = buildtree(CAST, q, p); p = q->n_right; nfree(q->n_left); nfree(q); p = buildtree(ASSIGN, a->n_left, p); nfree(a); return p; bad: uerror("bad argument to __builtin_stdarg_start"); return bcon(0); } NODE * mips_builtin_va_arg(const struct bitable *bt, NODE *a) { NODE *p, *q, *r; int sz, tmpnr; /* check num args and type */ if (a == NULL || a->n_op != CM || a->n_left->n_op == CM || !ISPTR(a->n_left->n_type) || a->n_right->n_op != TYPE) goto bad; r = a->n_right; /* get type size */ sz = tsize(r->n_type, r->n_df, r->n_ap) / SZCHAR; if (sz < SZINT/SZCHAR) { werror("%s%s promoted to int when passed through ...", r->n_type & 1 ? "unsigned " : "", DEUNSIGN(r->n_type) == SHORT ? "short" : "char"); sz = SZINT/SZCHAR; } /* alignment */ p = tcopy(a->n_left); if (sz > SZINT/SZCHAR && r->n_type != UNIONTY && r->n_type != STRTY) { p = buildtree(PLUS, p, bcon(7)); p = block(AND, p, bcon(-8), p->n_type, p->n_df, p->n_ap); } /* create a copy to a temp node */ q = tempnode(0, p->n_type, p->n_df, p->n_ap); tmpnr = regno(q); p = buildtree(ASSIGN, q, p); q = tempnode(tmpnr, p->n_type, p->n_df,p->n_ap); q = buildtree(PLUS, q, bcon(sz)); q = buildtree(ASSIGN, a->n_left, q); q = buildtree(COMOP, p, q); nfree(a->n_right); nfree(a); p = tempnode(tmpnr, INCREF(r->n_type), r->n_df, r->n_ap); p = buildtree(UMUL, p, NIL); p = buildtree(COMOP, q, p); return p; bad: uerror("bad argument to __builtin_va_arg"); return bcon(0); } NODE * mips_builtin_va_end(const struct bitable *bt, NODE *a) { tfree(a); return bcon(0); } NODE * mips_builtin_va_copy(const struct bitable *bt, NODE *a) { NODE *f; if (a == NULL || a->n_op != CM || a->n_left->n_op == CM) goto bad; f = buildtree(ASSIGN, a->n_left, a->n_right); nfree(a); return f; bad: uerror("bad argument to __buildtin_va_copy"); return bcon(0); } static int constructor; static int destructor; /* * Give target the opportunity of handling pragmas. */ int mypragma(char *str) { if (strcmp(str, "tls") == 0) { uerror("thread-local storage not supported for this target"); return 1; } if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) { constructor = 1; return 1; } if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) { destructor = 1; return 1; } return 0; } /* * Called when a identifier has been declared, to give target last word. */ void fixdef(struct symtab *sp) { if ((constructor || destructor) && (sp->sclass != PARAM)) { printf("\t.section .%ctors,\"aw\",@progbits\n", constructor ? 'c' : 'd'); printf("\t.p2align 2\n"); printf("\t.long %s\n", exname(sp->sname)); printf("\t.previous\n"); constructor = destructor = 0; } } void pass1_lastchance(struct interpass *ip) { } pcc-20181216/arch/mips/local2.c010064400017500000000000000761331277225026600147140ustar raggewheel/* $Id: local2.c,v 1.32 2016/09/26 16:45:42 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and * Simon Olsson (simols-1@student.ltu.se) 2005. */ #include #include #include #include #include "pass1.h" #include "pass2.h" #ifdef TARGET_BIG_ENDIAN int bigendian = 1; #else int bigendian = 0; #endif int nargregs = MIPS_O32_NARGREGS; static int argsiz(NODE *p); void deflab(int label) { printf(LABFMT ":\n", label); } static int regoff[32]; static TWORD ftype; /* * calculate stack size and offsets */ static int offcalc(struct interpass_prolog * ipp) { int i, j, addto; addto = p2maxautooff; for (i = p2env.p_regs[0], j = 0; i; i >>= 1, j++) { if (i & 1) { addto += SZINT / SZCHAR; regoff[j] = addto; } } /* round to 8-byte boundary */ addto += 7; addto &= ~7; return addto; } /* * Print out the prolog assembler. */ void prologue(struct interpass_prolog * ipp) { int addto; int i, j; ftype = ipp->ipp_type; printf("\t.align 2\n"); if (ipp->ipp_vis) printf("\t.globl %s\n", ipp->ipp_name); printf("\t.ent %s\n", ipp->ipp_name); printf("%s:\n", ipp->ipp_name); addto = offcalc(ipp); /* emit PIC only if -fpic or -fPIC set */ if (kflag > 0) { printf("\t.frame %s,%d,%s\n", rnames[FP], ARGINIT/SZCHAR, rnames[RA]); printf("\t.set noreorder\n"); printf("\t.cpload $25\t# pseudo-op to load GOT ptr into $25\n"); printf("\t.set reorder\n"); } printf("\t.frame %s,%d,%s\n", rnames[FP], ARGINIT/SZCHAR, rnames[RA]); printf("\t.set noreorder\n"); printf("\t.cpload $25\t# pseudo-op to load GOT ptr into $25\n"); printf("\t.set reorder\n"); printf("\tsubu %s,%s,%d\n", rnames[SP], rnames[SP], ARGINIT/SZCHAR); /* emit PIC only if -fpic or -fPIC set */ if (kflag > 0) printf("\t.cprestore 8\t# pseudo-op to store GOT ptr at 8(sp)\n"); printf("\tsw %s,4(%s)\n", rnames[RA], rnames[SP]); printf("\tsw %s,(%s)\n", rnames[FP], rnames[SP]); printf("\tmove %s,%s\n", rnames[FP], rnames[SP]); #ifdef notyet /* profiling */ if (pflag) { printf("\t.set noat\n"); printf("\tmove %s,%s\t# save current return address\n", rnames[AT], rnames[RA]); printf("\tsubu %s,%s,8\t# _mcount pops 2 words from stack\n", rnames[SP], rnames[SP]); printf("\tjal %s\n", exname("_mcount")); printf("\tnop\n"); printf("\t.set at\n"); } #endif if (addto) printf("\tsubu %s,%s,%d\n", rnames[SP], rnames[SP], addto); for (i = p2env.p_regs[0], j = 0; i; i >>= 1, j++) if (i & 1) printf("\tsw %s,-%d(%s) # save permanent\n", rnames[j], regoff[j], rnames[FP]); } void eoftn(struct interpass_prolog * ipp) { int i, j; (void) offcalc(ipp); if (ipp->ipp_ip.ip_lbl == 0) return; /* no code needs to be generated */ /* return from function code */ for (i = p2env.p_regs[0], j = 0; i; i >>= 1, j++) { if (i & 1) printf("\tlw %s,-%d(%s)\n\tnop\n", rnames[j], regoff[j], rnames[FP]); } printf("\taddiu %s,%s,%d\n", rnames[SP], rnames[FP], ARGINIT/SZCHAR); printf("\tlw %s,%d(%s)\n", rnames[RA], 4-ARGINIT/SZCHAR, rnames[SP]); printf("\tlw %s,%d(%s)\n", rnames[FP], 0-ARGINIT/SZCHAR, rnames[SP]); printf("\tjr %s\n", rnames[RA]); printf("\tnop\n"); #ifdef USE_GAS printf("\t.end %s\n", ipp->ipp_name); printf("\t.size %s,.-%s\n", ipp->ipp_name, ipp->ipp_name); #endif } /* * add/sub/... * * Param given: */ void hopcode(int f, int o) { char *str; switch (o) { case EQ: str = "beqz"; /* pseudo-op */ break; case NE: str = "bnez"; /* pseudo-op */ break; case ULE: case LE: str = "blez"; break; case ULT: case LT: str = "bltz"; break; case UGE: case GE: str = "bgez"; break; case UGT: case GT: str = "bgtz"; break; case PLUS: str = "add"; break; case MINUS: str = "sub"; break; case AND: str = "and"; break; case OR: str = "or"; break; case ER: str = "xor"; break; default: comperr("hopcode2: %d", o); str = 0; /* XXX gcc */ } printf("%s%c", str, f); } char * rnames[] = { #ifdef USE_GAS /* gnu assembler */ "$zero", "$at", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", "$24", "$25", "$kt0", "$kt1", "$gp", "$sp", "$fp", "$ra", "$2!!$3!!", "$4!!$5!!", "$5!!$6!!", "$6!!$7!!", "$7!!$8!!", "$8!!$9!!", "$9!!$10!", "$10!$11!", "$11!$12!", "$12!$13!", "$13!$14!", "$14!$15!", "$15!$24!", "$24!$25!", "$16!$17!", "$17!$18!", "$18!$19!", "$19!$20!", "$20!$21!", "$21!$22!", "$22!$23!", #else /* mips assembler */ "$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3", "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7", "$t8", "$t9", "$k0", "$k1", "$gp", "$sp", "$fp", "$ra", "$v0!$v1!", "$a0!$a1!", "$a1!$a2!", "$a2!$a3!", "$a3!$t0!", "$t0!$t1!", "$t1!$t2!", "$t2!$t3!", "$t3!$t4!", "$t4!$t5!", "$t5!$t6!", "$t6!$t7!", "$t7!$t8!", "$t8!$t9!", "$s0!$s1!", "$s1!$s2!", "$s2!$s3!", "$s3!$s4!", "$s4!$s5!", "$s5!$s6!", "$s6!$s7!", #endif "$f0!$f1!", "$f2!$f3!", "$f4!$f5!", "$f6!$f7!", "$f8!$f9!", "$f10$f11", "$f12$f13", "$f14$f15", "$f16$f17", "$f18$f19", "$f20$f21", "$f22$f23", "$f24$f25", "$f26$f27", "$f28$f29", "$f30$f31", }; char * rnames_n32[] = { /* mips assembler */ "$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3", "$a4", "$a5", "$a6", "$a7", "$t0", "$t1", "$t2", "$t3", "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7", "$t8", "$t9", "$k0", "$k1", "$gp", "$sp", "$fp", "$ra", "$v0!$v1!", "$a0!$a1!", "$a1!$a2!", "$a2!$a3!", "$a3!$a4!", "$a4!$a5!", "$a5!$a6!", "$a6!$a7!", "$a7!$t0!", "$t0!$t1!", "$t1!$t2!", "$t2!$t3!", "$t3!$t8!", "$t8!$t9!", "$s0!$s1!", "$s1!$s2!", "$s2!$s3!", "$s3!$s4!", "$s4!$s5!", "$s5!$s6!", "$s6!$s7!", "$f0!$f1!", "$f2!$f3!", "$f4!$f5!", "$f6!$f7!", "$f8!$f9!", "$f10$f11", "$f12$f13", "$f14$f15", "$f16$f17", "$f18$f19", "$f20$f21", "$f22$f23", "$f24$f25", "$f26$f27", "$f28$f29", "$f30$f31", }; int tlen(NODE *p) { switch (p->n_type) { case CHAR: case UCHAR: return (1); case SHORT: case USHORT: return (SZSHORT / SZCHAR); case DOUBLE: return (SZDOUBLE / SZCHAR); case INT: case UNSIGNED: case LONG: case ULONG: return (SZINT / SZCHAR); case LONGLONG: case ULONGLONG: return SZLONGLONG / SZCHAR; default: if (!ISPTR(p->n_type)) comperr("tlen type %d not pointer"); return SZPOINT(p->n_type) / SZCHAR; } } /* * Push a structure on stack as argument. */ static void starg(NODE *p) { int sz = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0); //assert(p->n_rval == A1); printf("\tsubu %s,%s,%d\n", rnames[SP], rnames[SP], sz); /* A0 = dest, A1 = src, A2 = len */ printf("\tmove %s,%s\n", rnames[A0], rnames[SP]); printf("\tli %s,%d\t# structure size\n", rnames[A2], sz); printf("\tsubu %s,%s,16\n", rnames[SP], rnames[SP]); printf("\tjal %s\t# structure copy\n", exname("memcpy")); printf("\tnop\n"); printf("\taddiu %s,%s,16\n", rnames[SP], rnames[SP]); } /* * Structure assignment. */ static void stasg(NODE *p) { assert(p->n_right->n_rval == A1); /* A0 = dest, A1 = src, A2 = len */ printf("\tli %s,%d\t# structure size\n", rnames[A2], attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)); if (p->n_left->n_op == OREG) { printf("\taddiu %s,%s," CONFMT "\t# dest address\n", rnames[A0], rnames[p->n_left->n_rval], getlval(p->n_left)); } else if (p->n_left->n_op == NAME) { printf("\tla %s,", rnames[A0]); adrput(stdout, p->n_left); printf("\n"); } printf("\tsubu %s,%s,16\n", rnames[SP], rnames[SP]); printf("\tjal %s\t# structure copy\n", exname("memcpy")); printf("\tnop\n"); printf("\taddiu %s,%s,16\n", rnames[SP], rnames[SP]); } static void shiftop(NODE *p) { NODE *r = p->n_right; TWORD ty = p->n_type; if (p->n_op == LS && r->n_op == ICON && getlval(r) < 32) { expand(p, INBREG, "\tsrl A1,AL,"); printf(CONFMT "\t# 64-bit left-shift\n", 32 - getlval(r)); expand(p, INBREG, "\tsll U1,UL,AR\n"); expand(p, INBREG, "\tor U1,U1,A1\n"); expand(p, INBREG, "\tsll A1,AL,AR\n"); } else if (p->n_op == LS && r->n_op == ICON && getlval(r) < 64) { expand(p, INBREG, "\tli A1,0\t# 64-bit left-shift\n"); expand(p, INBREG, "\tsll U1,AL,"); printf(CONFMT "\n", getlval(r) - 32); } else if (p->n_op == LS && r->n_op == ICON) { expand(p, INBREG, "\tli A1,0\t# 64-bit left-shift\n"); expand(p, INBREG, "\tli U1,0\n"); } else if (p->n_op == RS && r->n_op == ICON && getlval(r) < 32) { expand(p, INBREG, "\tsll U1,UL,"); printf(CONFMT "\t# 64-bit right-shift\n", 32 - getlval(r)); expand(p, INBREG, "\tsrl A1,AL,AR\n"); expand(p, INBREG, "\tor A1,A1,U1\n"); if (ty == LONGLONG) expand(p, INBREG, "\tsra U1,UL,AR\n"); else expand(p, INBREG, "\tsrl U1,UL,AR\n"); } else if (p->n_op == RS && r->n_op == ICON && getlval(r) < 64) { if (ty == LONGLONG) { expand(p, INBREG, "\tsra U1,UL,31\t# 64-bit right-shift\n"); expand(p, INBREG, "\tsra A1,UL,"); }else { expand(p, INBREG, "\tli U1,0\t# 64-bit right-shift\n"); expand(p, INBREG, "\tsrl A1,UL,"); } printf(CONFMT "\n", getlval(r) - 32); } else if (p->n_op == LS && r->n_op == ICON) { expand(p, INBREG, "\tli A1,0\t# 64-bit right-shift\n"); expand(p, INBREG, "\tli U1,0\n"); } else { comperr("shiftop"); } } /* * http://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Soft-float-library-routines */ static void fpemulop(NODE *p) { NODE *l = p->n_left; char *ch = NULL; if (p->n_op == PLUS && p->n_type == FLOAT) ch = "addsf3"; else if (p->n_op == PLUS && p->n_type == DOUBLE) ch = "adddf3"; else if (p->n_op == PLUS && p->n_type == LDOUBLE) ch = "addtf3"; else if (p->n_op == MINUS && p->n_type == FLOAT) ch = "subsf3"; else if (p->n_op == MINUS && p->n_type == DOUBLE) ch = "subdf3"; else if (p->n_op == MINUS && p->n_type == LDOUBLE) ch = "subtf3"; else if (p->n_op == MUL && p->n_type == FLOAT) ch = "mulsf3"; else if (p->n_op == MUL && p->n_type == DOUBLE) ch = "muldf3"; else if (p->n_op == MUL && p->n_type == LDOUBLE) ch = "multf3"; else if (p->n_op == DIV && p->n_type == FLOAT) ch = "divsf3"; else if (p->n_op == DIV && p->n_type == DOUBLE) ch = "divdf3"; else if (p->n_op == DIV && p->n_type == LDOUBLE) ch = "divtf3"; else if (p->n_op == UMINUS && p->n_type == FLOAT) ch = "negsf2"; else if (p->n_op == UMINUS && p->n_type == DOUBLE) ch = "negdf2"; else if (p->n_op == UMINUS && p->n_type == LDOUBLE) ch = "negtf2"; else if (p->n_op == EQ && l->n_type == FLOAT) ch = "eqsf2"; else if (p->n_op == EQ && l->n_type == DOUBLE) ch = "eqdf2"; else if (p->n_op == EQ && l->n_type == LDOUBLE) ch = "eqtf2"; else if (p->n_op == NE && l->n_type == FLOAT) ch = "nesf2"; else if (p->n_op == NE && l->n_type == DOUBLE) ch = "nedf2"; else if (p->n_op == NE && l->n_type == LDOUBLE) ch = "netf2"; else if (p->n_op == GE && l->n_type == FLOAT) ch = "gesf2"; else if (p->n_op == GE && l->n_type == DOUBLE) ch = "gedf2"; else if (p->n_op == GE && l->n_type == LDOUBLE) ch = "getf2"; else if (p->n_op == LE && l->n_type == FLOAT) ch = "lesf2"; else if (p->n_op == LE && l->n_type == DOUBLE) ch = "ledf2"; else if (p->n_op == LE && l->n_type == LDOUBLE) ch = "letf2"; else if (p->n_op == GT && l->n_type == FLOAT) ch = "gtsf2"; else if (p->n_op == GT && l->n_type == DOUBLE) ch = "gtdf2"; else if (p->n_op == GT && l->n_type == LDOUBLE) ch = "gttf2"; else if (p->n_op == LT && l->n_type == FLOAT) ch = "ltsf2"; else if (p->n_op == LT && l->n_type == DOUBLE) ch = "ltdf2"; else if (p->n_op == LT && l->n_type == LDOUBLE) ch = "lttf2"; else if (p->n_op == SCONV && p->n_type == FLOAT) { if (l->n_type == DOUBLE) ch = "truncdfsf2"; else if (l->n_type == LDOUBLE) ch = "trunctfsf2"; else if (l->n_type == ULONGLONG) ch = "floatdisf"; /**/ else if (l->n_type == LONGLONG) ch = "floatdisf"; else if (l->n_type == LONG) ch = "floatsisf"; else if (l->n_type == ULONG) ch = "floatunsisf"; else if (l->n_type == INT) ch = "floatsisf"; else if (l->n_type == UNSIGNED) ch = "floatunsisf"; } else if (p->n_op == SCONV && p->n_type == DOUBLE) { if (l->n_type == FLOAT) ch = "extendsfdf2"; else if (l->n_type == LDOUBLE) ch = "trunctfdf2"; else if (l->n_type == ULONGLONG) ch = "floatunsdidf"; else if (l->n_type == LONGLONG) ch = "floatdidf"; else if (l->n_type == LONG) ch = "floatsidf"; else if (l->n_type == ULONG) ch = "floatunsidf"; else if (l->n_type == INT) ch = "floatsidf"; else if (l->n_type == UNSIGNED) ch = "floatunsidf"; } else if (p->n_op == SCONV && p->n_type == LDOUBLE) { if (l->n_type == FLOAT) ch = "extendsftf2"; else if (l->n_type == DOUBLE) ch = "extenddfdf2"; else if (l->n_type == ULONGLONG) ch = "floatunsdidf"; else if (l->n_type == LONGLONG) ch = "floatdidf"; else if (l->n_type == LONG) ch = "floatsidf"; else if (l->n_type == ULONG) ch = "floatunssidf"; else if (l->n_type == INT) ch = "floatsidf"; else if (l->n_type == UNSIGNED) ch = "floatunsidf"; } else if (p->n_op == SCONV && p->n_type == ULONGLONG) { if (l->n_type == FLOAT) ch = "fixunssfdi"; else if (l->n_type == DOUBLE) ch = "fixunsdfdi"; else if (l->n_type == LDOUBLE) ch = "fixunsdfdi"; } else if (p->n_op == SCONV && p->n_type == LONGLONG) { if (l->n_type == FLOAT) ch = "fixsfdi"; else if (l->n_type == DOUBLE) ch = "fixdfdi"; else if (l->n_type == LDOUBLE) ch = "fixdfdi"; } else if (p->n_op == SCONV && p->n_type == LONG) { if (l->n_type == FLOAT) ch = "fixsfsi"; else if (l->n_type == DOUBLE) ch = "fixdfsi"; else if (l->n_type == LDOUBLE) ch = "fixdfsi"; } else if (p->n_op == SCONV && p->n_type == ULONG) { if (l->n_type == FLOAT) ch = "fixunssfsi"; else if (l->n_type == DOUBLE) ch = "fixunsdfsi"; else if (l->n_type == LDOUBLE) ch = "fixunsdfsi"; } else if (p->n_op == SCONV && p->n_type == INT) { if (l->n_type == FLOAT) ch = "fixsfsi"; else if (l->n_type == DOUBLE) ch = "fixdfsi"; else if (l->n_type == LDOUBLE) ch = "fixdfsi"; } else if (p->n_op == SCONV && p->n_type == UNSIGNED) { if (l->n_type == FLOAT) ch = "fixunssfsi"; else if (l->n_type == DOUBLE) ch = "fixunsdfsi"; else if (l->n_type == LDOUBLE) ch = "fixunsdfsi"; } if (ch == NULL) comperr("ZF: op=0x%x (%d)\n", p->n_op, p->n_op); if (p->n_op == SCONV) { if (l->n_type == FLOAT) { printf("\tmfc1 %s,", rnames[A0]); adrput(stdout, l); printf("\n\tnop\n"); } else if (l->n_type == DOUBLE || l->n_type == LDOUBLE) { printf("\tmfc1 %s,", rnames[A1]); upput(l, 0); printf("\n\tnop\n"); printf("\tmfc1 %s,", rnames[A0]); adrput(stdout, l); printf("\n\tnop\n"); } } else { comperr("ZF: incomplete softfloat - put args in registers"); } printf("\tjal __%s\t# softfloat operation\n", exname(ch)); printf("\tnop\n"); if (p->n_op >= EQ && p->n_op <= GT) printf("\tcmp %s,0\n", rnames[V0]); } /* * http://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html#Integer-library-routines */ static void emulop(NODE *p) { char *ch = NULL; if (p->n_op == LS && DEUNSIGN(p->n_type) == LONGLONG) ch = "ashldi3"; else if (p->n_op == LS && (DEUNSIGN(p->n_type) == LONG || DEUNSIGN(p->n_type) == INT)) ch = "ashlsi3"; else if (p->n_op == RS && p->n_type == ULONGLONG) ch = "lshrdi3"; else if (p->n_op == RS && (p->n_type == ULONG || p->n_type == INT)) ch = "lshrsi3"; else if (p->n_op == RS && p->n_type == LONGLONG) ch = "ashrdi3"; else if (p->n_op == RS && (p->n_type == LONG || p->n_type == INT)) ch = "ashrsi3"; else if (p->n_op == DIV && p->n_type == LONGLONG) ch = "divdi3"; else if (p->n_op == DIV && (p->n_type == LONG || p->n_type == INT)) ch = "divsi3"; else if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udivdi3"; else if (p->n_op == DIV && (p->n_type == ULONG || p->n_type == UNSIGNED)) ch = "udivsi3"; else if (p->n_op == MOD && p->n_type == LONGLONG) ch = "moddi3"; else if (p->n_op == MOD && (p->n_type == LONG || p->n_type == INT)) ch = "modsi3"; else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umoddi3"; else if (p->n_op == MOD && (p->n_type == ULONG || p->n_type == UNSIGNED)) ch = "umodsi3"; else if (p->n_op == MUL && p->n_type == LONGLONG) ch = "muldi3"; else if (p->n_op == MUL && (p->n_type == LONG || p->n_type == INT)) ch = "mulsi3"; else if (p->n_op == UMINUS && p->n_type == LONGLONG) ch = "negdi2"; else if (p->n_op == UMINUS && p->n_type == LONG) ch = "negsi2"; else ch = 0, comperr("ZE"); printf("\tsubu %s,%s,16\n", rnames[SP], rnames[SP]); printf("\tjal __%s\t# emulated operation\n", exname(ch)); printf("\tnop\n"); printf("\taddiu %s,%s,16\n", rnames[SP], rnames[SP]); } /* * Emit code to compare two longlong numbers. */ static void twollcomp(NODE *p) { int o = p->n_op; int s = getlab2(); int e = p->n_label; int cb1, cb2; if (o >= ULE) o -= (ULE-LE); switch (o) { case NE: cb1 = 0; cb2 = NE; break; case EQ: cb1 = NE; cb2 = 0; break; case LE: case LT: cb1 = GT; cb2 = LT; break; case GE: case GT: cb1 = LT; cb2 = GT; break; default: cb1 = cb2 = 0; /* XXX gcc */ } if (p->n_op >= ULE) cb1 += 4, cb2 += 4; expand(p, 0, "\tsub A1,UL,UR\t# compare 64-bit values (upper)\n"); if (cb1) { printf("\t"); hopcode(' ', cb1); expand(p, 0, "A1"); printf("," LABFMT "\n", s); printf("\tnop\n"); } if (cb2) { printf("\t"); hopcode(' ', cb2); expand(p, 0, "A1"); printf("," LABFMT "\n", e); printf("\tnop\n"); } expand(p, 0, "\tsub A1,AL,AR\t# (and lower)\n"); printf("\t"); hopcode(' ', o); expand(p, 0, "A1"); printf("," LABFMT "\n", e); printf("\tnop\n"); deflab(s); } static void fpcmpops(NODE *p) { NODE *l = p->n_left; switch (p->n_op) { case EQ: if (l->n_type == FLOAT) expand(p, 0, "\tc.eq.s AL,AR\n"); else expand(p, 0, "\tc.eq.d AL,AR\n"); expand(p, 0, "\tnop\n\tbc1t LC\n"); break; case NE: if (l->n_type == FLOAT) expand(p, 0, "\tc.eq.s AL,AR\n"); else expand(p, 0, "\tc.eq.d AL,AR\n"); expand(p, 0, "\tnop\n\tbc1f LC\n"); break; case LT: if (l->n_type == FLOAT) expand(p, 0, "\tc.lt.s AL,AR\n"); else expand(p, 0, "\tc.lt.d AL,AR\n"); expand(p, 0, "\tnop\n\tbc1t LC\n"); break; case GE: if (l->n_type == FLOAT) expand(p, 0, "\tc.lt.s AL,AR\n"); else expand(p, 0, "\tc.lt.d AL,AR\n"); expand(p, 0, "\tnop\n\tbc1f LC\n"); break; case LE: if (l->n_type == FLOAT) expand(p, 0, "\tc.le.s AL,AR\n"); else expand(p, 0, "\tc.le.d AL,AR\n"); expand(p, 0, "\tnop\n\tbc1t LC\n"); break; case GT: if (l->n_type == FLOAT) expand(p, 0, "\tc.le.s AL,AR\n"); else expand(p, 0, "\tc.le.d AL,AR\n"); expand(p, 0, "\tnop\n\tbc1f LC\n"); break; } printf("\tnop\n\tnop\n"); } void zzzcode(NODE * p, int c) { int sz; switch (c) { case 'C': /* remove arguments from stack after subroutine call */ sz = p->n_qual > 16 ? p->n_qual : 16; printf("\taddiu %s,%s,%d\n", rnames[SP], rnames[SP], sz); break; case 'D': /* long long comparison */ twollcomp(p); break; case 'E': /* emit emulated ops */ emulop(p); break; case 'F': /* emit emulate floating point ops */ fpemulop(p); break; case 'G': /* emit hardware floating-point compare op */ fpcmpops(p); break; case 'H': /* structure argument */ starg(p); break; case 'I': /* high part of init constant */ if (p->n_name[0] != '\0') comperr("named highword"); printf(CONFMT, (getlval(p) >> 32) & 0xffffffff); break; case 'O': /* 64-bit left and right shift operators */ shiftop(p); break; case 'Q': /* emit struct assign */ stasg(p); break; default: comperr("zzzcode %c", c); } } /* ARGSUSED */ int rewfld(NODE * p) { return (1); } int fldexpand(NODE *p, int cookie, char **cp) { CONSZ val; if (p->n_op == ASSIGN) p = p->n_left; switch (**cp) { case 'S': printf("%d", UPKFSZ(p->n_rval)); break; case 'H': printf("%d", UPKFOFF(p->n_rval)); break; case 'M': case 'N': val = (CONSZ)1 << UPKFSZ(p->n_rval); --val; val <<= UPKFOFF(p->n_rval); printf("0x%llx", (**cp == 'M' ? val : ~val) & 0xffffffff); break; default: comperr("fldexpand"); } return 1; } /* * Does the bitfield shape match? */ int flshape(NODE * p) { int o = p->n_op; if (o == OREG || o == REG || o == NAME) return SRDIR; /* Direct match */ if (o == UMUL && shumul(p->n_left, SOREG)) return SROREG; /* Convert into oreg */ return SRREG; /* put it into a register */ } /* INTEMP shapes must not contain any temporary registers */ /* XXX should this go away now? */ int shtemp(NODE * p) { return 0; #if 0 int r; if (p->n_op == STARG) p = p->n_left; switch (p->n_op) { case REG: return (!istreg(p->n_rval)); case OREG: r = p->n_rval; if (R2TEST(r)) { if (istreg(R2UPK1(r))) return (0); r = R2UPK2(r); } return (!istreg(r)); case UMUL: p = p->n_left; return (p->n_op != UMUL && shtemp(p)); } if (optype(p->n_op) != LTYPE) return (0); return (1); #endif } void adrcon(CONSZ val) { printf(CONFMT, val); } void conput(FILE *fp, NODE *p) { int val = getlval(p); switch (p->n_op) { case ICON: if (p->n_name[0] != '\0') { fprintf(fp, "%s", p->n_name); if (getlval(p)) fprintf(fp, "+%d", val); } else fprintf(fp, "%d", val); return; default: comperr("illegal conput"); } } /* ARGSUSED */ void insput(NODE * p) { comperr("insput"); } /* * Print lower or upper name of 64-bit register. */ static void print_reg64name(FILE *fp, int rval, int hi) { int off = 4 * (hi != 0); char *regname = rnames[rval]; fprintf(fp, "%c%c", regname[off], regname[off + 1]); if (regname[off + 2] != '!') fputc(regname[off + 2], fp); if (regname[off + 3] != '!') fputc(regname[off + 3], fp); } /* * Write out the upper address, like the upper register of a 2-register * reference, or the next memory location. */ void upput(NODE * p, int size) { size /= SZCHAR; switch (p->n_op) { case REG: if (GCLASS(p->n_rval) == CLASSB || GCLASS(p->n_rval) == CLASSC) print_reg64name(stdout, p->n_rval, 1); else printf("%s", rnames[p->n_rval]); break; case NAME: case OREG: setlval(p, getlval(p) + size); adrput(stdout, p); setlval(p, getlval(p) - size); break; case ICON: printf(CONFMT, getlval(p) >> 32); break; default: comperr("upput bad op %d size %d", p->n_op, size); } } void adrput(FILE * io, NODE * p) { /* output an address, with offsets, from p */ if (p->n_op == FLD) p = p->n_left; switch (p->n_op) { case NAME: if (p->n_name[0] != '\0') fputs(p->n_name, io); if (getlval(p) != 0) fprintf(io, "+" CONFMT, getlval(p)); return; case OREG: if (getlval(p)) fprintf(io, "%d", (int) getlval(p)); fprintf(io, "(%s)", rnames[p->n_rval]); return; case ICON: /* addressable value of the constant */ conput(io, p); return; case REG: if (GCLASS(p->n_rval) == CLASSB || GCLASS(p->n_rval) == CLASSC) print_reg64name(io, p->n_rval, 0); else fputs(rnames[p->n_rval], io); return; default: comperr("illegal address, op %d, node %p", p->n_op, p); return; } } /* printf conditional and unconditional branches */ void cbgen(int o, int lab) { } void myreader(struct interpass * ipole) { } #if 0 /* * Calculate the stack size for arguments */ static int stacksize; static void calcstacksize(NODE *p, void *arg) { int sz; printf("op=%d\n", p->n_op); if (p->n_op != CALL && p->n_op != STCALL) return; sz = argsiz(p->n_right); if (sz > stacksize) stacksize = sz; #ifdef PCC_DEBUG if (x2debug) printf("stacksize: %d\n", stacksize); #endif } #endif /* * If we're big endian, then all OREG loads of a type * larger than the destination, must have the * offset changed to point to the correct bytes in memory. */ static void offchg(NODE *p, void *arg) { NODE *l; if (p->n_op != SCONV) return; l = p->n_left; if (l->n_op != OREG) return; switch (l->n_type) { case SHORT: case USHORT: if (DEUNSIGN(p->n_type) == CHAR) setlval(l, getlval(l) + 1); break; case LONG: case ULONG: case INT: case UNSIGNED: if (DEUNSIGN(p->n_type) == CHAR) setlval(l, getlval(l + 3)); else if (DEUNSIGN(p->n_type) == SHORT) setlval(l, getlval(l + 2)); break; case LONGLONG: case ULONGLONG: if (DEUNSIGN(p->n_type) == CHAR) setlval(l, getlval(l + 7)); else if (DEUNSIGN(p->n_type) == SHORT) setlval(l, getlval(l + 6)); else if (DEUNSIGN(p->n_type) == INT || DEUNSIGN(p->n_type) == LONG) setlval(l, getlval(l + 4)); break; default: comperr("offchg: unknown type"); break; } } /* * Remove some PCONVs after OREGs are created. */ static void pconv2(NODE * p, void *arg) { NODE *q; if (p->n_op == PLUS) { if (p->n_type == (PTR | SHORT) || p->n_type == (PTR | USHORT)) { if (p->n_right->n_op != ICON) return; if (p->n_left->n_op != PCONV) return; if (p->n_left->n_left->n_op != OREG) return; q = p->n_left->n_left; nfree(p->n_left); p->n_left = q; /* * This will be converted to another OREG later. */ } } } void mycanon(NODE * p) { walkf(p, pconv2, 0); } void myoptim(struct interpass * ipole) { struct interpass *ip; #ifdef PCC_DEBUG if (x2debug) printf("myoptim:\n"); #endif #if 0 stacksize = 0; #endif DLIST_FOREACH(ip, ipole, qelem) { if (ip->type != IP_NODE) continue; if (bigendian) walkf(ip->ip_node, offchg, 0); #if 0 walkf(ip->ip_node, calcstacksize, 0); #endif } } /* * Move data between registers. While basic registers aren't a problem, * we have to handle the special case of overlapping composite registers. */ void rmove(int s, int d, TWORD t) { switch (t) { case LONGLONG: case ULONGLONG: if (s == d+1) { /* dh = sl, copy low word first */ printf("\tmove "); print_reg64name(stdout, d, 0); printf(","); print_reg64name(stdout, s, 0); printf("\t# 64-bit rmove\n"); printf("\tmove "); print_reg64name(stdout, d, 1); printf(","); print_reg64name(stdout, s, 1); printf("\n"); } else { /* copy high word first */ printf("\tmove "); print_reg64name(stdout, d, 1); printf(","); print_reg64name(stdout, s, 1); printf(" # 64-bit rmove\n"); printf("\tmove "); print_reg64name(stdout, d, 0); printf(","); print_reg64name(stdout, s, 0); printf("\n"); } break; case FLOAT: case DOUBLE: case LDOUBLE: if (t == FLOAT) printf("\tmov.s "); else printf("\tmov.d "); print_reg64name(stdout, d, 0); printf(","); print_reg64name(stdout, s, 0); printf("\t# float/double rmove\n"); break; default: printf("\tmove %s,%s\t# default rmove\n", rnames[d], rnames[s]); } } /* * For class c, find worst-case displacement of the number of * registers in the array r[] indexed by class. * * On MIPS, we have: * * 32 32-bit registers (8 reserved) * 26 64-bit pseudo registers (1 unavailable) * 16 floating-point register pairs */ int COLORMAP(int c, int *r) { int num = 0; switch (c) { case CLASSA: num += r[CLASSA]; num += 2*r[CLASSB]; return num < 24; case CLASSB: num += 2*r[CLASSB]; num += r[CLASSA]; return num < 25; case CLASSC: num += r[CLASSC]; return num < 6; } comperr("COLORMAP"); return 0; /* XXX gcc */ } /* * Return a class suitable for a specific type. */ int gclass(TWORD t) { if (t == LONGLONG || t == ULONGLONG) return CLASSB; if (t >= FLOAT && t <= LDOUBLE) return CLASSC; return CLASSA; } /* * Calculate argument sizes. */ void lastcall(NODE *p) { int sz; #ifdef PCC_DEBUG if (x2debug) printf("lastcall:\n"); #endif p->n_qual = 0; if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) return; sz = argsiz(p->n_right); if ((sz > 4*nargregs) && (sz & 7) != 0) { printf("\tsubu %s,%s,4\t# align stack\n", rnames[SP], rnames[SP]); sz += 4; assert((sz & 7) == 0); } p->n_qual = sz; /* XXX */ } static int argsiz(NODE *p) { TWORD t; int size = 0; int sz = 0; if (p->n_op == CM) { size = argsiz(p->n_left); p = p->n_right; } t = p->n_type; if (t < LONGLONG || t > BTMASK) sz = 4; else if (DEUNSIGN(t) == LONGLONG) sz = 8; else if (t == DOUBLE || t == LDOUBLE) sz = 8; else if (t == FLOAT) sz = 4; else if (t == STRTY || t == UNIONTY) sz = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0); if (p->n_type == STRTY || p->n_type == UNIONTY) { return (size + sz); } /* alignment */ if (sz == 8 && (size & 7) != 0) sz += 4; // printf("size=%d, sz=%d -> %d\n", size, sz, size + sz); return (size + sz); } /* * Special shapes. */ int special(NODE *p, int shape) { int o = p->n_op; if (o != ICON || p->n_name[0] != 0) return SRNOPE; switch(shape) { case SPCON: if ((getlval(p) & ~0xffff) == 0) return SRDIR; break; } return SRNOPE; } /* * Target-dependent command-line options. */ void mflags(char *str) { if (strcasecmp(str, "big-endian") == 0) { bigendian = 1; } else if (strcasecmp(str, "little-endian") == 0) { bigendian = 0; } else { fprintf(stderr, "unknown m option '%s'\n", str); exit(1); } #if 0 else if (strcasecmp(str, "ips2")) { } else if (strcasecmp(str, "ips2")) { } else if (strcasecmp(str, "ips3")) { } else if (strcasecmp(str, "ips4")) { } else if (strcasecmp(str, "hard-float")) { } else if (strcasecmp(str, "soft-float")) { } else if (strcasecmp(str, "abi=32")) { nargregs = MIPS_O32_NARGREGS; } else if (strcasecmp(str, "abi=n32")) { nargregs = MIPS_N32_NARGREGS; } else if (strcasecmp(str, "abi=64")) { nargregs = MIPS_N32_NARGREGS; } #endif } /* * Do something target-dependent for xasm arguments. * Supposed to find target-specific constraints and rewrite them. */ int myxasm(struct interpass *ip, NODE *p) { return 0; } pcc-20181216/arch/mips/macdefs.h010064400017500000000000000234401340073517200151310ustar raggewheel/* $Id: macdefs.h,v 1.25 2018/12/02 10:56:58 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and * Simon Olsson (simols-1@student.ltu.se) 2005. */ /* * Machine-dependent defines for both passes. */ #if defined(os_netbsd) || defined(os_litebsd) #define USE_GAS #endif /* * Convert (multi-)character constant to integer. * Assume: If only one value; store at left side (char size), otherwise * treat it as an integer. */ #define makecc(val,i) lastcon = (lastcon<<8)|((val<<24)>>24); #define ARGINIT (16*8) /* # bits above fp where arguments start */ #define AUTOINIT (0) /* # bits below fp where automatics start */ /* * Storage space requirements */ #define SZCHAR 8 #define SZBOOL 32 #define SZINT 32 #define SZFLOAT 32 #define SZDOUBLE 64 #define SZLDOUBLE 64 #define SZLONG 32 #define SZSHORT 16 #define SZLONGLONG 64 #define SZPOINT(t) 32 /* * Alignment constraints */ #define ALCHAR 8 #define ALBOOL 32 #define ALINT 32 #define ALFLOAT 32 #define ALDOUBLE 64 #define ALLDOUBLE 64 #define ALLONG 32 #define ALLONGLONG 64 #define ALSHORT 16 #define ALPOINT 32 #define ALSTRUCT 64 #define ALSTACK 32 /* * Min/max values. */ #define MIN_CHAR -128 #define MAX_CHAR 127 #define MAX_UCHAR 255 #define MIN_SHORT -32768 #define MAX_SHORT 32767 #define MAX_USHORT 65535 #define MIN_INT (-0x7fffffff-1) #define MAX_INT 0x7fffffff #define MAX_UNSIGNED 0xffffffffU #define MIN_LONG MIN_INT #define MAX_LONG 0x7fffffffL #define MAX_ULONG 0xffffffffUL #define MIN_LONGLONG (-0x7fffffffffffffffLL-1) #define MAX_LONGLONG 0x7fffffffffffffffLL #define MAX_ULONGLONG 0xffffffffffffffffULL #undef CHAR_UNSIGNED #define BOOL_TYPE INT /* * Use large-enough types. */ typedef long long CONSZ; typedef unsigned long long U_CONSZ; typedef long long OFFSZ; #define CONFMT "%lld" /* format for printing constants */ #ifdef USE_GAS #define LABFMT "$L%d" /* format for printing labels */ #define STABLBL "$LL%d" /* format for stab (debugging) labels */ #else #define LABFMT "L%d" /* format for printing labels */ #define STABLBL "LL%d" /* format for stab (debugging) labels */ #endif #define BACKAUTO /* stack grows negatively for automatics */ #define BACKTEMP /* stack grows negatively for temporaries */ #undef FIELDOPS /* no bit-field instructions */ #define TARGET_ENDIAN TARGET_LE #define MYALIGN /* Definitions mostly used in pass2 */ #define BYTEOFF(x) ((x)&03) #define szty(t) (((t) == DOUBLE || (t) == LDOUBLE || \ DEUNSIGN(t) == LONGLONG) ? 2 : 1) /* * Register names. These must match rnames[] and rstatus[] in local2.c. */ #define ZERO 0 #define AT 1 #define V0 2 #define V1 3 #define A0 4 #define A1 5 #define A2 6 #define A3 7 #define A4 8 #define A5 9 #define A6 10 #define A7 11 #if defined(MIPS_N32) || defined(MIPS_N64) #define T0 12 #define T1 13 #define T2 14 #define T3 15 #else #define T0 8 #define T1 9 #define T2 10 #define T3 11 #endif #define T4 12 #define T5 13 #define T6 14 #define T7 15 #define S0 16 #define S1 17 #define S2 18 #define S3 19 #define S4 20 #define S5 21 #define S6 22 #define S7 23 #define T8 24 #define T9 25 #define K0 26 #define K1 27 #define GP 28 #define SP 29 #define FP 30 #define RA 31 #define V0V1 32 #define A0A1 33 #define A1A2 34 #define A2A3 35 /* we just use o32 naming here, but it works ok for n32/n64 */ #define A3T0 36 #define T0T1 37 #define T1T2 38 #define T2T3 39 #define T3T4 40 #define T4T5 41 #define T5T6 42 #define T6T7 43 #define T7T8 44 #define T8T9 45 #define S0S1 46 #define S1S2 47 #define S2S3 48 #define S3S4 49 #define S4S5 50 #define S5S6 51 #define S6S7 52 #define F0 53 #define F2 54 #define F4 55 #define F6 56 #define F8 57 #define F10 58 #define F12 59 #define F14 60 #define F16 61 #define F18 62 #define F20 63 /* and the rest for later */ #define F22 64 #define F24 65 #define F26 66 #define F28 67 #define F30 68 #define MAXREGS 64 #define NUMCLASS 3 #define RETREG(x) (DEUNSIGN(x) == LONGLONG ? V0V1 : \ (x) == DOUBLE || (x) == LDOUBLE || (x) == FLOAT ? \ F0 : V0) #define FPREG FP /* frame pointer */ #define MIPS_N32_NARGREGS 8 #define MIPS_O32_NARGREGS 4 #define RSTATUS \ 0, 0, \ SAREG|TEMPREG, SAREG|TEMPREG, \ SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \ SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \ SAREG|TEMPREG, SAREG|TEMPREG, \ 0, 0, \ 0, 0, 0, 0, \ \ SBREG|TEMPREG, \ SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, \ SBREG|TEMPREG, \ SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, \ SBREG|TEMPREG, SBREG|TEMPREG, \ SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, \ SBREG, SBREG, SBREG, SBREG, \ SBREG, SBREG, SBREG, \ SCREG, SCREG, SCREG, SCREG, \ SCREG, SCREG, SCREG, SCREG, \ SCREG, SCREG, SCREG, \ #define ROVERLAP \ { -1 }, /* $zero */ \ { -1 }, /* $at */ \ { V0V1, -1 }, /* $v0 */ \ { V0V1, -1 }, /* $v1 */ \ { A0A1, -1 }, /* $a0 */ \ { A0A1, A1A2, -1 }, /* $a1 */ \ { A1A2, A2A3, -1 }, /* $a2 */ \ { A2A3, A3T0, -1 }, /* $a3 */ \ { A3T0, T0T1, -1 }, /* $t0 */ \ { T0T1, T1T2, -1 }, /* $t1 */ \ { T1T2, T2T3, -1 }, /* $t2 */ \ { T2T3, T3T4, -1 }, /* $t3 */ \ { T3T4, T4T5, -1 }, /* $t4 */ \ { T4T5, T5T6, -1 }, /* $t5 */ \ { T6T7, T7T8, -1 }, /* $t6 */ \ { T7T8, T8T9, -1 }, /* $t7 */ \ \ { S0S1, -1 }, /* $s0 */ \ { S0S1, S1S2, -1 }, /* $s1 */ \ { S1S2, S2S3, -1 }, /* $s2 */ \ { S2S3, S3S4, -1 }, /* $s3 */ \ { S3S4, S4S5, -1 }, /* $s4 */ \ { S4S5, S5S6, -1 }, /* $s5 */ \ { S5S6, S6S7, -1 }, /* $s6 */ \ { S6S7, -1 }, /* $s7 */ \ \ { T7T8, T8T9, -1 }, /* $t8 */ \ { T8T9, -1 }, /* $t9 */ \ \ { -1 }, /* $k0 */ \ { -1 }, /* $k1 */ \ { -1 }, /* $gp */ \ { -1 }, /* $sp */ \ { -1 }, /* $fp */ \ { -1 }, /* $ra */ \ \ { V0, V1, -1 }, /* $v0:$v1 */ \ \ { A0, A1, A1A2, -1 }, /* $a0:$a1 */ \ { A1, A2, A0A1, A2A3, -1 }, /* $a1:$a2 */ \ { A2, A3, A1A2, A3T0, -1 }, /* $a2:$a3 */ \ { A3, T0, A2A3, T0T1, -1 }, /* $a3:$t0 */ \ { T0, T1, A3T0, T1T2, -1 }, /* $t0:$t1 */ \ { T1, T2, T0T1, T2T3, -1 }, /* $t1:$t2 */ \ { T2, T3, T1T2, T3T4, -1 }, /* $t2:$t3 */ \ { T3, T4, T2T3, T4T5, -1 }, /* $t3:$t4 */ \ { T4, T5, T3T4, T5T6, -1 }, /* $t4:$t5 */ \ { T5, T6, T4T5, T6T7, -1 }, /* $t5:$t6 */ \ { T6, T7, T5T6, T7T8, -1 }, /* $t6:$t7 */ \ { T7, T8, T6T7, T8T9, -1 }, /* $t7:$t8 */ \ { T8, T9, T7T8, -1 }, /* $t8:$t9 */ \ \ { S0, S1, S1S2, -1 }, /* $s0:$s1 */ \ { S1, S2, S0S1, S2S3, -1 }, \ { S2, S3, S1S2, S3S4, -1 }, \ { S3, S4, S2S3, S4S5, -1 }, \ { S4, S5, S3S4, S5S6, -1 }, \ { S5, S6, S4S5, S6S7, -1 }, \ { S6, S7, S5S6, -1 }, \ \ { -1 }, { -1 }, { -1 }, { -1 }, \ { -1 }, { -1 }, { -1 }, { -1 }, \ { -1 }, { -1 }, { -1 }, \ #define GCLASS(x) (x < 32 ? CLASSA : (x < 52 ? CLASSB : CLASSC)) #define PCLASS(p) (1 << gclass((p)->n_type)) #define DECRA(x,y) (((x) >> (y*6)) & 63) /* decode encoded regs */ #define ENCRA(x,y) ((x) << (6+y*6)) /* encode regs in int */ #define ENCRD(x) (x) /* Encode dest reg in n_reg */ int COLORMAP(int c, int *r); extern int bigendian; extern int nargregs; #define SPCON (MAXSPECIAL+1) /* positive constant */ #define TARGET_STDARGS #define TARGET_BUILTINS \ { "__builtin_stdarg_start", mips_builtin_stdarg_start, \ 0, 2, 0, VOID }, \ { "__builtin_va_start", mips_builtin_stdarg_start, \ 0, 2, 0, VOID }, \ { "__builtin_va_arg", mips_builtin_va_arg, BTNORVAL|BTNOPROTO, \ 2, 0, 0 }, \ { "__builtin_va_end", mips_builtin_va_end, 0, 1, 0, VOID }, \ { "__builtin_va_copy", mips_builtin_va_copy, 0, 2, 0, VOID }, #ifdef LANG_CXX #define P1ND struct node #else #define P1ND struct p1node #endif struct node; struct bitable; P1ND *mips_builtin_stdarg_start(const struct bitable *, P1ND *a); P1ND *mips_builtin_va_arg(const struct bitable *, P1ND *a); P1ND *mips_builtin_va_end(const struct bitable *, P1ND *a); P1ND *mips_builtin_va_copy(const struct bitable *, P1ND *a); #undef P1ND /* floating point definitions */ #define USE_IEEEFP_32 #define FLT_PREFIX IEEEFP_32 #define USE_IEEEFP_64 #define DBL_PREFIX IEEEFP_64 #define LDBL_PREFIX IEEEFP_64 pcc-20181216/arch/mips/order.c010064400017500000000000000133771111457735000146470ustar raggewheel/* $Id: order.c,v 1.12 2008/11/30 21:00:24 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and * Simon Olsson (simols-1@student.ltu.se) 2005. */ #include "pass2.h" /* * is it legal to make an OREG or NAME entry which has an offset of off, * (from a register of r), if the resulting thing had type t */ int notoff(TWORD t, int r, CONSZ off, char *cp) { /* * although the hardware doesn't permit offsets greater * than +/- 32K, the assembler fixes it for us. */ return 0; /* YES */ } /* * Turn a UMUL-referenced node into OREG. */ void offstar(NODE * p, int shape) { if (x2debug) printf("offstar(%p)\n", p); if (p->n_op == PLUS || p->n_op == MINUS) { if (p->n_right->n_op == ICON) { if (isreg(p->n_left) == 0) (void)geninsn(p->n_left, INAREG); /* Converted in ormake() */ return; } } (void)geninsn(p, INAREG); } /* * Do the actual conversion of offstar-found OREGs into real OREGs. */ void myormake(NODE * q) { if (x2debug) printf("myormake(%p)\n", q); } /* * Shape matches for UMUL. Cooperates with offstar(). */ int shumul(NODE *p, int shape) { if (x2debug) printf("shumul(%p)\n", p); /* Always turn it into OREG */ if (shape & SOREG) return SROREG; return SRNOPE; } /* * Rewrite operations on binary operators (like +, -, etc...). * Called as a result of table lookup. */ int setbin(NODE * p) { if (x2debug) printf("setbin(%p)\n", p); return 0; } /* setup for assignment operator */ int setasg(NODE * p, int cookie) { if (x2debug) printf("setasg(%p)\n", p); return (0); } /* setup for unary operator */ int setuni(NODE * p, int cookie) { return 0; } /* * Special handling of some instruction register allocation. * - left is the register that left node wants. * - right is the register that right node wants. * - res is in which register the result will end up. * - mask is registers that will be clobbered. */ struct rspecial * nspecial(struct optab * q) { switch (q->op) { case SCONV: if (q->lshape == SBREG && q->rshape == SCREG) { static struct rspecial s[] = { { NLEFT, A0A1 }, { NRES, F0 }, { 0 } }; return s; } else if (q->lshape == SCREG && q->rshape == SBREG) { static struct rspecial s[] = { { NLEFT, F0 }, { NRES, A0A1 }, { 0 } }; return s; } else if (q->lshape == SAREG && q->rshape == SCREG) { static struct rspecial s[] = { { NLEFT, A0 }, { NRES, F0 }, { 0 } }; return s; } break; case MOD: case DIV: if (q->lshape == SBREG) { static struct rspecial s[] = { { NLEFT, A0A1 }, { NRIGHT, A2A3 }, { NRES, V0V1 }, { 0 }, }; return s; } else if (q->lshape == SAREG) { static struct rspecial s[] = { { NLEFT, A0 }, { NRIGHT, A1 }, { NRES, V0 }, { 0 }, }; return s; } case RS: case LS: if (q->lshape == SBREG) { static struct rspecial s[] = { { NLEFT, A0A1 }, { NRIGHT, A2 }, { NRES, V0V1 }, { 0 }, }; return s; } else if (q->lshape == SAREG) { static struct rspecial s[] = { { NLEFT, A0 }, { NRIGHT, A1 }, { NRES, V0 }, { 0 }, }; return s; } break; case STARG: { static struct rspecial s[] = { { NEVER, A0 }, { NLEFT, A1 }, { NEVER, A2 }, { 0 } }; return s; } case STASG: { static struct rspecial s[] = { { NEVER, A0 }, { NRIGHT, A1 }, { NEVER, A2 }, { 0 } }; return s; } } comperr("nspecial entry %d: %s", q - table, q->cstring); return 0; /* XXX gcc */ } /* * Set evaluation order of a binary node if it differs from default. */ int setorder(NODE * p) { return 0; /* nothing differs */ } /* * Set registers "live" at function calls (like arguments in registers). * This is for liveness analysis of registers. */ int * livecall(NODE *p) { static int r[1] = { -1 }; /* Terminate with -1 */ return &r[0]; } /* * Signal whether the instruction is acceptable for this target. */ int acceptable(struct optab *op) { return 1; } pcc-20181216/arch/mips/table.c010064400017500000000000000711011264273267200146170ustar raggewheel/* $Id: table.c,v 1.18 2016/01/05 12:23:22 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and * Simon Olsson (simols-1@student.ltu.se) 2005. * * It appears that the target machine was big endian. The original * code contained many endian aspects which are now handled in * machine-independent code. * * On MIPS, the assembler does an amazing amount of work for us. * We don't have to worry about PIC, nor about finding the address * of SNAMES. Whenever possible, we defer the work to the assembler. */ #include "pass2.h" #define TUWORD TUNSIGNED|TULONG #define TSWORD TINT|TLONG #define TWORD TUWORD|TSWORD struct optab table[] = { /* First entry must be an empty entry */ { -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", }, /* PCONVs are usually not necessary */ { PCONV, INAREG, SAREG, TWORD|TPOINT, SAREG, TWORD|TPOINT, 0, RLEFT, " # convert between word and pointer", }, /* * Conversions of integral types (register-register) * * For each deunsigned type, they look something like this: * * signed -> bigger signed - nothing to do * unsigned -> bigger - nothing to do * * signed -> bigger unsigned - clear the top bits (of source type) * signed -> smaller signed - sign-extend the bits (to dest type) * signed -> smaller unsigned - clear the top bits (of dest type) * unsigned -> smaller signed - sign-extend top bits (to dest type) * unsigned -> smaller unsigned - clear the top bits (of dest type) * */ /* convert between int and ptr */ { SCONV, INAREG, SAREG, TPOINT|TWORD, SAREG, TWORD|TPOINT, 0, RLEFT, "", }, /* convert between LL and uLL */ { SCONV, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TULONGLONG|TLONGLONG, 0, RLEFT, "", }, /* (u)char to (u)char/(u)short/(u)int */ { SCONV, INAREG, SAREG, TCHAR|TUCHAR, SAREG, TCHAR|TUCHAR|TWORD|TSHORT|TUSHORT, 0, RLEFT, "", }, /* (u)short to (u)int */ { SCONV, INAREG, SAREG, TSHORT|TUSHORT, SAREG, TWORD|TSHORT|TUSHORT, 0, RLEFT, "", }, /* (u)int to (u)int */ { SCONV, INAREG, SAREG, TWORD, SAREG, TWORD, 0, RLEFT, "", }, /* (u)int/(u)short to char */ { SCONV, INAREG, SAREG, TWORD|TSHORT|TUSHORT, SAREG, TCHAR, NAREG|NASL, RESC1, " sll A1,AL,24\n" " sra A1,A1,24\n", }, /* (u)int/(u)short to uchar */ { SCONV, INAREG, SAREG, TWORD|TSHORT|TUSHORT, SAREG, TUCHAR, NAREG|NASL, RESC1, " andi A1,AL,255\n", }, /* (u)int to short */ { SCONV, INAREG, SAREG, TWORD, SAREG, TSHORT, NAREG|NASL, RESC1, " sll A1,AL,16\n" " sra A1,A1,16\n", }, /* (u)int to ushort */ { SCONV, INAREG, SAREG, TWORD, SAREG, TUSHORT, NAREG|NASL, RESC1, " andi A1,AL,65535\n", }, /* longlong casts below */ { SCONV, INBREG, SAREG, TSWORD|TSHORT|TCHAR, SBREG, TLONGLONG, NBREG, RESC1, " move A1,AL # convert int/short/char to longlong\n" " sra U1,AL,31\n", }, { SCONV, INBREG, SAREG, TSWORD|TSHORT|TCHAR, SBREG, TULONGLONG, NBREG, RESC1, " move A1,AL # convert int/short/char to ulonglong\n" " move U1,$zero\n", }, { SCONV, INBREG, SAREG, TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR, SBREG, TLONGLONG|TULONGLONG, NBREG, RESC1, " move A1,AL # convert (u)int/(u)short/(u)char to ulonglong\n" " move U1,$zero\n", }, { SCONV, INAREG, SBREG, TLONGLONG|TULONGLONG, SAREG, TWORD, NAREG, RESC1, " move A1,AL # convert (u)longlong to int\n", }, { SCONV, INAREG, SBREG, TLONGLONG|TULONGLONG, SAREG, TSHORT, NAREG, RESC1, " sll A1,AL,16 # convert (u)longlong to short\n" " sra A1,A1,16\n", }, { SCONV, INAREG, SBREG, TLONGLONG|TULONGLONG, SAREG, TCHAR, NAREG, RESC1, " sll A1,AL,24 # convert (u)longlong to char\n" " sra A1,A1,24\n", }, { SCONV, INAREG, SBREG, TLONGLONG|TULONGLONG, SAREG, TUSHORT, NAREG, RESC1, " andi A1,AL,65535 # convert (u)longlong to ushort\n", }, { SCONV, INAREG, SBREG, TLONGLONG|TULONGLONG, SAREG, TUCHAR, NAREG, RESC1, " andi A1,AL,255 # convert (u)longlong to uchar\n", }, { SCONV, INCREG, SCREG, TFLOAT, SCREG, TDOUBLE|TLDOUBLE, NCREG, RESC1, " cvt.d.s A1,AL # convert float to (l)double\n", }, { SCONV, INCREG, SCREG, TDOUBLE|TLDOUBLE, SCREG, TFLOAT, NCREG, RESC1, " cvt.s.d A1,AL # convert (l)double to float\n", }, { SCONV, INCREG, SAREG, TWORD, SCREG, TFLOAT, NCREG, RESC1, " mtc1 AL,A1 # convert (u)int to float\n" " nop\n" " cvt.s.w A1,A1\n", }, { SCONV, INCREG, SOREG, TWORD, SCREG, TFLOAT, NCREG, RESC1, " l.s A1,AL # convert (u)int to float\n" " nop\n" " cvt.s.w A1,A1\n", }, { SCONV, INCREG, SAREG, TWORD, SCREG, TDOUBLE|TLDOUBLE, NCREG, RESC1, " mtc1 AL,A1 # convert (u)int to (l)double\n" " nop\n" " cvt.d.w A1,A1\n", }, { SCONV, INCREG, SOREG, TWORD, SCREG, TDOUBLE|TLDOUBLE, NCREG, RESC1, " l.d A1,AL # convert (u)int to (l)double\n" " nop\n" " cvt.d.w A1,A1\n", }, { SCONV, INAREG, SCREG, TFLOAT, SAREG, TWORD, NCREG|NAREG, RESC1, " cvt.w.s A2,AL # convert float to (u)int\n" " mfc1 A1,A2\n" " nop\n", }, { SCONV, FOREFF, SCREG, TFLOAT, SOREG, TWORD, NCREG, RDEST, " cvt.w.s A1,AL # convert float to (u)int\n" " s.s A1,AR\n" " nop\n", }, { SCONV, INAREG, SCREG, TDOUBLE|TLDOUBLE, SAREG, TWORD, NCREG|NAREG, RESC1, " cvt.w.d A2,AL # convert (l)double to (u)int\n" " mfc1 A1,A2\n" " nop\n", }, { SCONV, INCREG, SCREG, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, 0, RLEFT, " # convert between double and ldouble\n", }, { SCONV, INCREG, SBREG, TLONGLONG|TULONGLONG, SCREG, TFLOAT, NSPECIAL|NCREG, RESC1, "ZF", }, { SCONV, INCREG, SBREG, TLONGLONG|TULONGLONG, SCREG, TDOUBLE|TLDOUBLE, NSPECIAL|NCREG, RESC1, "ZF", }, { SCONV, INBREG, SCREG, TDOUBLE|TLDOUBLE, SBREG, TLONGLONG|TULONGLONG, NSPECIAL|NBREG, RESC1, "ZF", }, { SCONV, INBREG, SCREG, TFLOAT, SBREG, TLONGLONG|TULONGLONG, NSPECIAL|NBREG, RESC1, "ZF", }, /* * Multiplication and division */ { MUL, INAREG, SAREG, TUWORD|TUSHORT|TUCHAR, SAREG, TUWORD|TUSHORT|TUCHAR, NAREG|NASR|NASL, RESC1, " multu AL,AR # unsigned multiply\n" " nop\n" " nop\n" " mflo A1\n" }, /* this previous will match on unsigned/unsigned multiplication first */ { MUL, INAREG, SAREG, TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR, SAREG, TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR, NAREG|NASR|NASL, RESC1, " mult AL,AR # signed multiply\n" " nop\n" " nop\n" " mflo A1\n", }, { MUL, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, 2*NBREG, RESC1, " multu AL,AR\n" " mfhi U1\n" " mflo A1\n" " mult AL,UR\n" " mflo A2\n" " nop\n" " nop\n" " addu A2,U1,A2\n" " mult UL,AR\n" " mflo U2\n" " nop\n" " nop\n" " addu U1,A2,U2\n", }, { MUL, INCREG, SCREG, TFLOAT, SCREG, TFLOAT, NCREG, RESC1, " mul.s A1,AL,AR # floating-point multiply\n", }, { MUL, INCREG, SCREG, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, NCREG, RESC1, " mul.d A1,AL,AR # double-floating-point multiply\n", }, { DIV, INAREG, SAREG, TUWORD|TUSHORT|TUCHAR, SAREG, TUWORD|TUSHORT|TUCHAR, NAREG|NASR|NASL, RESC1, " divu AL,AR # unsigned division\n" " mflo A1\n" " nop\n" " nop\n", }, /* the previous rule will match unsigned/unsigned first */ { DIV, INAREG, SAREG, TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR, SAREG, TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR, NAREG|NASR|NASL, RESC1, " div AL,AR # signed division\n" " mflo A1\n" " nop\n" " nop\n", }, { DIV, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, NSPECIAL|NBREG, RESC1, "ZE", }, { DIV, INCREG, SCREG, TFLOAT, SCREG, TFLOAT, NCREG, RESC1, " div.s A1,AL,AR # floating-point division\n", }, { DIV, INCREG, SCREG, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, NCREG, RESC1, " div.d A1,AL,AR # double-floating-point division\n", }, { MOD, INAREG, SAREG, TUWORD|TUSHORT|TUCHAR, SAREG, TUWORD|TUSHORT|TUCHAR, NAREG, RESC1, " divu AL,AR # signed modulo\n" " mfhi A1\n" " nop\n" " nop\n", }, /* the previous rule will match unsigned%unsigned first */ { MOD, INAREG, SAREG, TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR, SAREG, TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR, NAREG, RESC1, " div AL,AR # signed modulo\n" " mfhi A1\n" " nop\n" " nop\n", }, { MOD, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, NSPECIAL|NBREG, RESC1, "ZE", }, /* * Templates for unsigned values needs to come before OPSIMP */ { PLUS, INBREG, SBREG, TULONGLONG|TLONGLONG, SBREG, TULONGLONG|TLONGLONG, 2*NBREG, RESC1, " addu A1,AL,AR # 64-bit addition\n" " sltu A2,A1,AR\n" " addu U1,UL,UR\n" " addu U1,U1,A2\n", }, { PLUS, INAREG, SAREG, TSWORD|TSHORT|TCHAR, SSCON, TANY, NAREG|NASL, RESC1, " addi A1,AL,AR\n", }, { PLUS, INAREG, SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, SSCON, TANY, NAREG|NASL, RESC1, " addiu A1,AL,AR\n", }, { PLUS, INAREG, SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, SAREG, TUWORD|TUSHORT|TUCHAR, NAREG|NASL, RESC1, " addu A1,AL,AR\n", }, { PLUS, INAREG, SAREG, TSWORD|TSHORT|TCHAR, SAREG, TSWORD|TSHORT|TCHAR, NAREG|NASL, RESC1, " add A1,AL,AR\n", }, { PLUS, INCREG, SCREG, TFLOAT, SCREG, TFLOAT, NCREG|NCSL, RESC1, " add.s A1,AL,AR\n", }, { PLUS, INCREG, SCREG, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, NCREG|NCSL, RESC1, " add.d A1,AL,AR\n", }, { MINUS, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, 2*NBREG, RESC1, " sltu A2,AL,AR # 64-bit subtraction\n" " subu A1,AL,AR\n" " subu U1,UL,UR\n" " subu U1,U1,A2\n", }, { MINUS, INAREG, SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, SSCON, TANY, NAREG|NASL, RESC1, " subu A1,AL,AR\n", }, { MINUS, INAREG, SAREG, TSWORD|TSHORT|TCHAR, SSCON, TANY, NAREG|NASL, RESC1, " sub A1,AL,AR\n", }, { MINUS, INAREG, SAREG, TSWORD|TSHORT|TCHAR, SAREG, TSWORD|TSHORT|TCHAR, NAREG|NASL, RESC1, " sub A1,AL,AR\n", }, { MINUS, INCREG, SCREG, TFLOAT, SCREG, TFLOAT, NCREG|NCSL, RESC1, " sub.s A1,AL,AR\n", }, { MINUS, INCREG, SCREG, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, NCREG|NCSL, RESC1, " sub.d A1,AL,AR\n", }, { UMINUS, INAREG, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SANY, TANY, NAREG|NASL, RESC1, " neg A1,AL\n", }, { UMINUS, INBREG, SBREG, TLONGLONG|TULONGLONG, SANY, TANY, NBREG|NAREG|NBSL, RESC2, " subu A1,$zero,AL\n" " subu U1,$zero,UL\n" " sltu A2,$zero,A1\n" " subu U1,U1,A2\n", }, { UMINUS, INCREG, SCREG, TFLOAT, SCREG, TFLOAT, NCREG|NCSL, RESC1, " neg.s A1,AL\n", }, { UMINUS, INCREG, SCREG, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, NCREG|NCSL, RESC1, " neg.d A1,AL\n", }, /* Simple 'op rd, rs, rt' or 'op rt, rs, imm' operations */ { OPSIMP, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, NBREG|NBSR|NBSL, RESC1, " O A1,AL,AR\n" " O U1,UL,UR\n", }, { OPSIMP, INAREG, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TUCHAR|TCHAR, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TUCHAR|TCHAR, NAREG|NASR|NASL, RESC1, " O A1,AL,AR\n", }, { OPSIMP, INAREG, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TUCHAR|TCHAR, SPCON, TANY, NAREG|NASL, RESC1, " Oi A1,AL,AR\n", }, /* * Shift instructions */ { RS, INAREG, SAREG, TSWORD|TSHORT|TCHAR, SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, " sra A1,AL,AR # shift right by constant\n", }, { RS, INAREG, SAREG, TUWORD|TUSHORT|TUCHAR, SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, " srl A1,AL,AR # shift right by constant\n", }, { LS, INAREG, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, " sll A1,AL,AR # shift left by constant\n", }, { RS, INAREG, SAREG, TSWORD|TSHORT|TCHAR, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, " srav A1,AL,AR # shift right by register\n", }, { RS, INAREG, SAREG, TUWORD|TUSHORT|TUCHAR, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, " srlv A1,AL,AR # shift right by register\n", }, { LS, INAREG, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, " sllv A1,AL,AR # shift left by register\n", }, { RS, INBREG, SBREG, TLONGLONG|TULONGLONG, SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NBREG, RESC1, "ZO", }, { LS, INBREG, SBREG, TLONGLONG|TULONGLONG, SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NBREG, RESC1, "ZO", }, { RS, INBREG, SBREG, TLONGLONG|TULONGLONG, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NSPECIAL|NBREG, RESC1, "ZE", }, { LS, INBREG, SBREG, TLONGLONG|TULONGLONG, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NSPECIAL|NBREG, RESC1, "ZE", }, /* * Rule for unary one's complement */ { COMPL, INAREG, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, SANY, TANY, NAREG|NASL, RESC1, " nor A1,$zero,AL # complement\n", }, { COMPL, INBREG, SBREG, TLONGLONG|TULONGLONG, SANY, TANY, NBREG|NBSL, RESC1, " nor A1,$zero,AL # complement\n" " nor U1,$zero,UL\n", }, /* * The next rules takes care of assignments. "=". */ { ASSIGN, FOREFF|INAREG, SOREG|SNAME, TWORD|TPOINT, SAREG, TWORD|TPOINT, 0, RDEST, " sw AR,AL # store (u)int/(u)long\n" " nop\n", }, { ASSIGN, FOREFF|INAREG, SOREG|SNAME, TSHORT|TUSHORT, SAREG, TSHORT|TUSHORT, 0, RDEST, " sh AR,AL # store (u)short\n" " nop\n", }, { ASSIGN, FOREFF|INAREG, SOREG|SNAME, TCHAR|TUCHAR, SAREG, TCHAR|TUCHAR, 0, RDEST, " sb AR,AL # store (u)char\n" " nop\n", }, { ASSIGN, FOREFF|INBREG, SOREG|SNAME, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, 0, RDEST, " sw UR,UL # store (u)longlong\n" " nop\n" " sw AR,AL\n" " nop\n", }, { ASSIGN, FOREFF|INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, 0, RDEST, " move UL,UR # register move\n" " move AL,AR\n", }, { ASSIGN, FOREFF|INAREG, SAREG, TANY, SAREG, TANY, 0, RDEST, " move AL,AR # register move\n", }, { ASSIGN, FOREFF|INCREG, SCREG, TFLOAT, SCREG, TFLOAT, 0, RDEST, " mov.s AL,AR # register move\n", }, { ASSIGN, FOREFF|INCREG, SCREG, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, 0, RDEST, " mov.d AL,AR # register move\n", }, { ASSIGN, FOREFF|INCREG, SNAME|SOREG, TFLOAT, SCREG, TFLOAT, 0, RDEST, " s.s AR,AL # store floating-point reg to oreg/sname\n" " nop\n", }, { ASSIGN, FOREFF|INCREG, SNAME|SOREG, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, 0, RDEST, " s.d AR,AL # store double floating-point reg to oreg/sname\n" " nop\n", }, { ASSIGN, FOREFF|INAREG, SFLD, TANY, SOREG|SNAME, TANY, 3*NAREG, RDEST, " lw A1,AR # bit-field assignment\n" " li A3,M\n" " lw A2,AL\n" " sll A1,A1,H\n" " and A1,A1,A3\n" " nor A3,$zero,A3\n" " and A2,A2,A3\n" " or A2,A2,A1\n" " sw A2,AL\n" "F lw AD,AR\n" "F nop\n" "F sll AD,AD,32-S\n" "F sra AD,AD,32-S\n", }, /* XXX we can optimise this away */ { ASSIGN, FOREFF|INAREG, SFLD, TANY, SCON, TANY, 3*NAREG, RDEST, " li A1,AR # bit-field assignment\n" " lw A2,AL\n" " li A3,M\n" " sll A1,A1,H\n" " and A1,A1,A3\n" " nor A3,$zero,A3\n" " and A2,A2,A3\n" " or A2,A2,A1\n" " sw A2,AL\n" "F li AD,AR\n" "F sll AD,AD,32-S\n" "F sra AD,AD,32-S\n", }, { ASSIGN, FOREFF|INAREG, SFLD, TANY, SAREG, TANY, 3*NAREG, RDEST, " move A1,AR # bit-field assignment\n" " lw A2,AL\n" " li A3,M\n" " sll A1,A1,H\n" " and A1,A1,A3\n" " nor A3,$zero,A3\n" " and A2,A2,A3\n" " or A2,A2,A1\n" " sw A2,AL\n" "F move AR,AD\n" "F sll AD,AD,32-S\n" "F sra AD,AD,32-S\n", }, { STASG, INAREG|FOREFF, SOREG|SNAME, TANY, SAREG, TPTRTO|TANY, NSPECIAL, RDEST, "ZQ", }, /* * Compare instructions */ { EQ, FORCC, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, 0, RESCC, " beq AL,AR,LC\n" " nop\n", }, { NE, FORCC, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, 0, RESCC, " bne AL,AR,LC\n" " nop\n", }, { OPLOG, FORCC, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SZERO, TANY, 0, RESCC, " O AL,LC\n" " nop\n", }, { OPLOG, FORCC, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESCC, " sub A1,AL,AR\n" " O A1,LC\n" " nop\n", }, { OPLOG, FORCC, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SSCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESCC, " sub A1,AL,AR\n" " O A1,LC\n" " nop\n", }, { OPLOG, FORCC, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, NAREG, RESCC, "ZD", }, { OPLOG, FORCC, SCREG, TFLOAT|TDOUBLE|TLDOUBLE, SCREG, TFLOAT|TDOUBLE|TLDOUBLE, 0, RESCC, "ZG", }, /* * Convert LTYPE to reg. */ { OPLTYPE, INAREG, SANY, TANY, SOREG|SNAME, TCHAR, NAREG, RESC1, " lb A1,AL # load char to reg\n" " nop\n", }, { OPLTYPE, INAREG, SANY, TANY, SOREG|SNAME, TUCHAR, NAREG, RESC1, " lbu A1,AL # load uchar to reg\n" " nop\n", }, { OPLTYPE, INAREG, SANY, TANY, SOREG|SNAME, TSHORT, NAREG, RESC1, " lh A1,AL # load short to reg\n" " nop\n", }, { OPLTYPE, INAREG, SANY, TANY, SOREG|SNAME, TUSHORT, NAREG, RESC1, " lhu A1,AL # load ushort to reg\n" " nop\n", }, { OPLTYPE, INAREG, SANY, TANY, SOREG|SNAME, TWORD|TPOINT, NAREG, RESC1, " lw A1,AL # load (u)int/(u)long to reg\n" " nop\n", }, { OPLTYPE, INBREG, SANY, TANY, SOREG|SNAME, TLONGLONG|TULONGLONG, NBREG, RESC1, " lw U1,UL # load (u)longlong to reg\n" " nop\n" " lw A1,AL\n" " nop\n", }, { OPLTYPE, INAREG, SANY, TANY, SCON, TPOINT, NAREG, RESC1, " la A1,AL # load constant address to reg\n", }, { OPLTYPE, INAREG, SANY, TANY, SZERO, TANY, NAREG, RESC1, " move A1,$zero # load 0 to reg\n", }, { OPLTYPE, INAREG, SANY, TANY, SCON, TANY, NAREG, RESC1, " li A1,AL # load constant to reg\n", }, { OPLTYPE, INBREG, SANY, TANY, SZERO, TANY, NBREG, RESC1, " move A1,$zero # load 0 to reg\n" " move U1,$zero\n", }, { OPLTYPE, INBREG, SANY, TANY, SCON, TANY, NBREG, RESC1, " li A1,AL # load constant to reg\n" " li U1,UL\n", }, { OPLTYPE, INAREG, SANY, TANY, SANY, TANY, NAREG, RESC1, " move A1,AL\n", }, { OPLTYPE, INCREG, SANY, TANY, SZERO, TFLOAT, NCREG, RESC1, " mtc1 $zero,A1 # load 0 to float reg\n" " nop\n", }, { OPLTYPE, INCREG, SANY, TANY, SZERO, TDOUBLE|TLDOUBLE, NCREG, RESC1, " mtc1 $zero,A1 # load 0 to (l)double reg\n" " mtc1 $zero,U1\n" " nop\n", }, { OPLTYPE, INCREG, SANY, TANY, SOREG|SNAME, TFLOAT, NCREG, RESC1, " l.s A1,AL # load into floating-point reg\n" " nop\n", }, { OPLTYPE, INCREG, SANY, TANY, OREG|SNAME, TDOUBLE|TLDOUBLE, NCREG, RESC1, " l.d A1,AL # load into double floating-point reg\n" " nop\n", }, /* * Jumps. */ { GOTO, FOREFF, SCON, TANY, SANY, TANY, 0, RNOP, " j LL # goto label\n" " nop\n" " nop\n", }, /* * Subroutine calls. */ { CALL, FOREFF, SCON, TANY, SANY, TANY, 0, 0, " subu $sp,$sp,16 # call (args, no result) to scon/sname\n" " jal CL\n" " nop\n" "ZC", }, { UCALL, FOREFF, SCON, TANY, SANY, TANY, 0, 0, " jal CL # call (no args, no result) to scon/sname\n" " nop\n", }, { CALL, INAREG, SCON, TANY, SAREG, TANY, NAREG, RESC1, /* should be 0 */ " subu $sp,$sp,16 # call (args, result in v0) to scon/sname\n" " jal CL\n" " nop\n" "ZC", }, { UCALL, INAREG, SCON, TANY, SAREG, TANY, NAREG, RESC1, /* should be 0 */ " jal CL # call (no args, result in v0) to scon/sname\n" " nop\n", }, { CALL, INBREG, SCON, TANY, SBREG, TANY, NBREG, RESC1, /* should be 0 */ " subu $sp,$sp,16 # call (args, result in v0:v1) to scon/sname\n" " jal CL\n" " nop\n" "ZC", }, { UCALL, INBREG, SCON, TANY, SBREG, TANY, NBREG, RESC1, /* should be 0 */ " jal CL # call (no args, result in v0:v1) to scon/sname\n" " nop\n", }, { CALL, INCREG, SCON, TANY, SCREG, TANY, NCREG, RESC1, /* should be 0 */ " subu $sp,$sp,16 # call (args, result in f0:f1) to scon/sname\n" " jal CL\n" " nop\n" "ZC", }, { UCALL, INCREG, SCON, TANY, SCREG, TANY, NCREG, RESC1, /* should be 0 */ " jal CL # call (no args, result in v0:v1) to scon/sname\n" " nop\n", }, { CALL, FOREFF, SAREG, TANY, SANY, TANY, 0, 0, " subu $sp,$sp,16 # call (args, no result) to reg\n" " move $25,AL\n" " jal $25\n" " nop\n" "ZC", }, { UCALL, FOREFF, SAREG, TANY, SANY, TANY, 0, 0, " move $25,AL\n" " jal $25 # call (no args, no result) to reg\n" " nop\n", }, { CALL, INAREG, SAREG, TANY, SAREG, TANY, NAREG, RESC1, /* should be 0 */ " subu $sp,$sp,16 # call (args, result) to reg\n" " move $25,AL\n" " jal $25\n" " nop\n" "ZC", }, { UCALL, INAREG, SAREG, TANY, SAREG, TANY, NAREG, RESC1, /* should be 0 */ " move $25,AL\n" " jal $25 # call (no args, result) to reg\n" " nop\n", }, { CALL, INBREG, SAREG, TANY, SBREG, TANY, NBREG, RESC1, /* should be 0 */ " subu $sp,$sp,16 # call (args, result) to reg\n" " move $25,AL\n" " jal $25\n" " nop\n" "ZC", }, { UCALL, INBREG, SAREG, TANY, SBREG, TANY, NBREG, RESC1, /* should be 0 */ " move $25,AL\n" " jal $25 # call (no args, result) to reg\n" " nop\n", }, { CALL, INCREG, SAREG, TANY, SCREG, TANY, NCREG, RESC1, /* should be 0 */ " subu $sp,$sp,16 # call (args, result) to reg\n" " move $25,AL\n" " jal $25\n" " nop\n" "ZC", }, { UCALL, INCREG, SCREG, TANY, SCREG, TANY, NCREG, RESC1, /* should be 0 */ " move $25,AL\n" " jal $25 # call (no args, result) to reg\n" " nop\n", }, /* struct return */ { USTCALL, FOREFF, SCON|SNAME, TANY, SANY, TANY, 0, 0, " jal CL\n" " nop\n", }, { USTCALL, FOREFF, SAREG, TANY, SANY, TANY, 0, 0, " move $25,AL\n" " jal $25\n" " nop\n", }, { USTCALL, INAREG, SCON|SNAME, TANY, SANY, TANY, NAREG|NASL, RESC1, " jal CL\n" " nop\n", }, { USTCALL, INAREG, SAREG, TANY, SANY, TANY, NAREG|NASL, RESC1, " move $25,AL\n" " jal $25\n" " nop\n", }, { STCALL, FOREFF, SCON|SNAME, TANY, SANY, TANY, 0, 0, " subu $sp,$sp,16\n" " jal CL\n" " nop\n" "ZC", }, { STCALL, FOREFF, SAREG, TANY, SANY, TANY, 0, 0, " subu $sp,$sp,16\n" " move $25,AL\n" " jal $25\n" " nop\n" "ZC", }, { STCALL, INAREG, SCON|SNAME, TANY, SANY, TANY, NAREG|NASL, RESC1, " subu $sp,$sp,16\n" " jal CL\n" " nop\n" "ZC", }, { STCALL, INAREG, SAREG, TANY, SANY, TANY, 0, 0, " subu $sp,$sp,16\n" " move $25,AL\n" " jal $25\n" " nop\n" "ZC", }, /* * Function arguments */ #if 0 /* intentionally write out the register for (u)short/(u)char */ { FUNARG, FOREFF, SAREG, TWORD|TPOINT|TUSHORT|TSHORT|TUCHAR|TCHAR, SANY, TWORD|TPOINT|TUSHORT|TSHORT|TUCHAR|TCHAR, 0, 0, " subu $sp,$sp,4 # save function arg to stack\n" " sw AL,($sp)\n" " #nop\n", }, { FUNARG, FOREFF, SBREG, TLONGLONG|TULONGLONG, SANY, TLONGLONG|TULONGLONG, 0, 0, " addi $sp,$sp,-8 # save function arg to stack (endian problem here?\n" " sw UL,4($sp)\n" " sw AL,($sp)\n" " #nop\n", }, { FUNARG, FOREFF, SCREG, TFLOAT, SANY, TFLOAT, 0, 0, " addi $sp,$sp,-4 # save function arg to stack\n" " s.s AL,($sp)\n" " #nop\n", }, { FUNARG, FOREFF, SCREG, TDOUBLE|TLDOUBLE, SANY, TDOUBLE|TLDOUBLE, 0, 0, " addi $sp,$sp,-8 # save function arg to stack\n" " s.d AL,($sp)\n" " #nop\n", }, #endif { STARG, FOREFF, SAREG, TANY, SANY, TSTRUCT, NSPECIAL, 0, "ZH", }, /* * Indirection operators. */ { UMUL, INAREG, SANY, TPOINT|TWORD, SOREG, TPOINT|TWORD, NAREG, RESC1, " lw A1,AL # word load\n" " nop\n", }, { UMUL, INAREG, SANY, TSHORT|TUSHORT, SOREG, TSHORT|TUSHORT, NAREG, RESC1, " lh A1,AL # (u)short load\n" " nop\n", }, { UMUL, INAREG, SANY, TCHAR|TUCHAR, SOREG, TCHAR|TUCHAR, NAREG, RESC1, " lb A1,AL # (u)char load\n" " nop\n", }, { UMUL, INBREG, SANY, TLONGLONG|TULONGLONG, SOREG, TLONGLONG|TULONGLONG, NBREG, RESC1, " lw A1,AL # (u)longlong load - endian problem here?\n" " nop\n" " lw U1,UL\n" " nop\n", }, { UMUL, INCREG, SANY, TFLOAT, SOREG, TFLOAT, NCREG, RESC1, " l.s A1,AL # float load\n" " nop\n", }, { UMUL, INCREG, SANY, TDOUBLE|TLDOUBLE, SOREG, TDOUBLE|TLDOUBLE, NCREG, RESC1, " l.d A1,AL # float load\n" " nop\n", }, #if 0 { UMUL, INCREG, SANY, TDOUBLE|TLDOUBLE, SAREG, TPOINT, NCREG, RESC1, " l.d A1,(AL)\n" " nop\n", }, { UMUL, INAREG, SANY, TPOINT|TWORD, SNAME, TPOINT|TWORD, NAREG, RESC1, " la A1,AL # sname word load\n" " lw A1,(A1)\n" " nop\n", }, { UMUL, INAREG, SANY, TSHORT|TUSHORT, SNAME, TSHORT|TUSHORT, NAREG, RESC1, " la A1,AL # sname (u)short load\n" " lh A1,(A1)\n" " nop\n", }, { UMUL, INAREG, SANY, TCHAR|TUCHAR, SNAME, TCHAR|TUCHAR, NAREG, RESC1, " la A1,AL # sname (u)char load\n" " lb A1,(A1)\n" " nop\n", }, { UMUL, INBREG, SANY, TLONGLONG|TULONGLONG, SNAME, TLONGLONG|TULONGLONG, NBREG|NAREG, RESC1, " la A2,AL # sname (u)long long load - endian problems here?\n" " lw A1,(A1)\n" " nop\n" " lw U1,4(A1)\n" " nop\n", }, #endif { UMUL, INAREG, SANY, TPOINT|TWORD, SAREG, TPOINT|TWORD, NAREG, RESC1, " lw A1,(AL) # word load\n" " nop\n", }, #if 0 { UMUL, INAREG, SANY, TSHORT|TUSHORT, SAREG, TPTRTO|TSHORT|TUSHORT, NAREG, RESC1, " lh A1,(AL) # (u)short load\n" " nop\n", }, { UMUL, INAREG, SANY, TCHAR|TUCHAR, SAREG, TPTRTO|TCHAR|TUCHAR, NAREG|NASL, RESC1, " lb A1,(AL) # (u)char load\n" " nop\n", }, { UMUL, INBREG, SANY, TLONGLONG|TULONGLONG, SAREG, TPTRTO|TLONGLONG|TULONGLONG, NBREG, RESC1, " lw A1,(AL) # (u)long long load - endianness problems?\n" " nop\n" " lw U1,4(AL)" " nop\n", }, #endif #define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,"" { FLD, DF(FLD), }, { FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" }, }; int tablesize = sizeof(table)/sizeof(table[0]); pcc-20181216/arch/mips64004075500017500000000000000000001340533064000134455ustar raggewheelpcc-20181216/arch/mips64/CVS004075500017500000000000000000001340533064000141005ustar raggewheelpcc-20181216/arch/mips64/CVS/Root010064400017500000000000000000111340533064000150120ustar raggewheel/cvsroot pcc-20181216/arch/mips64/CVS/Repository010064400017500000000000000000201340533064000162460ustar raggewheelpcc/arch/mips64 pcc-20181216/arch/mips64/CVS/Entries010064400017500000000000000004311340533064000155060ustar raggewheel/TODO/1.1/Wed Jul 6 07:49:48 2016// /code.c/1.1/Wed Jul 6 07:49:48 2016// /local.c/1.2/Sun Dec 2 20:25:55 2018// /local2.c/1.2/Mon Sep 26 16:45:42 2016// /macdefs.h/1.2/Sun Dec 2 20:25:55 2018// /order.c/1.1/Wed Jul 6 07:49:48 2016// /table.c/1.1/Wed Jul 6 07:49:48 2016// D pcc-20181216/arch/mips64/TODO010064400017500000000000000001231273713403400142130ustar raggewheel* Fix floating-point arguments in registers * Fix structure arguments in registers pcc-20181216/arch/mips64/code.c010064400017500000000000000401611273713403400146070ustar raggewheel/* $Id: code.c,v 1.1 2016/07/06 07:49:48 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and * Simon Olsson (simols-1@student.ltu.se) 2005. * * Extended to MIPS64 by Brian Callahan 2016. */ #include #include "pass1.h" #ifndef LANG_CXX #undef NIL #define NIL NULL #define NODE P1ND #define nfree p1nfree #define ccopy p1tcopy #define tfree p1tfree #endif /* * Print out assembler segment name. */ void setseg(int seg, char *name) { switch (seg) { case PROG: name = ".text"; break; case DATA: case LDATA: name = ".data"; break; case STRNG: case RDATA: name = ".section .rodata"; break; case UDATA: break; case PICLDATA: case PICDATA: name = ".section .data.rel.rw,\"aw\",@progbits"; break; case PICRDATA: name = ".section .data.rel.ro,\"aw\",@progbits"; break; case TLSDATA: name = ".section .tdata,\"awT\",@progbits"; break; case TLSUDATA: name = ".section .tbss,\"awT\",@nobits"; break; case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break; case DTORS: name = ".section\t.dtors,\"aw\",@progbits"; break; case NMSEG: printf("\t.section %s,\"a%c\",@progbits\n", name, cftnsp ? 'x' : 'w'); return; } printf("\t%s\n", name); } /* * Define everything needed to print out some data (or text). * This means segment, alignment, visibility, etc. */ void defloc(struct symtab *sp) { char *n; if (ISFTN(sp->stype)) return; /* XXX until fixed */ n = getexname(sp); if (sp->sclass == EXTDEF) printf(" .globl %s\n", n); if (sp->slevel == 0) { #ifdef USE_GAS printf("\t.type %s,@%s\n", n, ISFTN(sp->stype) ? "function" : "object"); if (!ISFTN(sp->stype)) printf("\t.size %s," CONFMT "\n", n, tsize(sp->stype, sp->sdf, sp->sap)); #endif printf("%s:\n", n); } else printf(LABFMT ":\n", sp->soffset); } /* * cause the alignment to become a multiple of n */ void defalign(int n) { n = ispow2(n / SZCHAR); if (n == -1) cerror("defalign: n != 2^i"); printf("\t.p2align %d\n", n); } static int rvnr; /* * code for the end of a function * deals with struct return here */ void efcode(void) { NODE *p, *q; int tempnr; int ty; if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) return; ty = cftnsp->stype - FTN; q = block(REG, NIL, NIL, INCREF(ty), 0, cftnsp->sap); q->n_rval = V0; p = tempnode(0, INCREF(ty), 0, cftnsp->sap); tempnr = regno(p); p = buildtree(ASSIGN, p, q); ecomp(p); q = tempnode(tempnr, INCREF(ty), 0, cftnsp->sap); q = buildtree(UMUL, q, NIL); p = tempnode(rvnr, INCREF(ty), 0, cftnsp->sap); p = buildtree(UMUL, p, NIL); p = buildtree(ASSIGN, p, q); ecomp(p); q = tempnode(rvnr, INCREF(ty), 0, cftnsp->sap); p = block(REG, NIL, NIL, INCREF(ty), 0, cftnsp->sap); p->n_rval = V0; p = buildtree(ASSIGN, p, q); ecomp(p); } /* Put a symbol in a temporary * used by bfcode() and its helpers */ static void putintemp(struct symtab *sym) { NODE *p; p = tempnode(0, sym->stype, sym->sdf, sym->sap); p = buildtree(ASSIGN, p, nametree(sym)); sym->soffset = regno(p->n_left); sym->sflags |= STNODE; ecomp(p); } /* setup the hidden pointer to struct return parameter * used by bfcode() */ static void param_retptr(void) { NODE *p, *q; p = tempnode(0, PTR+STRTY, 0, cftnsp->sap); rvnr = regno(p); q = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap); q->n_rval = A0; p = buildtree(ASSIGN, p, q); ecomp(p); } /* setup struct parameter * push the registers out to memory * used by bfcode() */ static void param_struct(struct symtab *sym, int *regp) { int reg = *regp; NODE *p, *q; int navail; int sz; int off; int num; int i; navail = nargregs - (reg - A0); sz = tsize(sym->stype, sym->sdf, sym->sap) / SZINT; off = (ARGINIT/SZINT * 2) + (reg - A0); num = sz > navail ? navail : sz; for (i = 0; i < num; i++) { q = block(REG, NIL, NIL, INT, 0, 0); q->n_rval = reg++; p = block(REG, NIL, NIL, INT, 0, 0); p->n_rval = FP; p = block(PLUS, p, bcon(8*off++), INT, 0, 0); p = block(UMUL, p, NIL, INT, 0, 0); p = buildtree(ASSIGN, p, q); ecomp(p); } *regp = reg; } /* setup a 64-bit parameter (double/ldouble/longlong) * used by bfcode() */ static void param_64bit(struct symtab *sym, int *regp, int dotemps) { int reg = *regp; NODE *p, *q; int navail; /* alignment */ ++reg; reg &= ~1; navail = nargregs - (reg - A0); if (navail < 2) { /* would have appeared half in registers/half * on the stack, but alignment ensures it * appears on the stack */ if (dotemps) putintemp(sym); *regp = reg; return; } q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap); q->n_rval = A0A1 + (reg - A0); if (dotemps) { p = tempnode(0, sym->stype, sym->sdf, sym->sap); sym->soffset = regno(p); sym->sflags |= STNODE; } else { p = nametree(sym); } p = buildtree(ASSIGN, p, q); ecomp(p); *regp = reg + 2; } /* setup a 32-bit param on the stack * used by bfcode() */ static void param_32bit(struct symtab *sym, int *regp, int dotemps) { NODE *p, *q; q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap); q->n_rval = (*regp)++; if (dotemps) { p = tempnode(0, sym->stype, sym->sdf, sym->sap); sym->soffset = regno(p); sym->sflags |= STNODE; } else { p = nametree(sym); } p = buildtree(ASSIGN, p, q); ecomp(p); } /* * XXX This is a hack. We cannot have (l)doubles in more than one * register class. So we bounce them in and out of temps to * move them in and out of the right registers. */ static void param_double(struct symtab *sym, int *regp, int dotemps) { int reg = *regp; NODE *p, *q, *t; int navail; int tmpnr; /* alignment */ ++reg; reg &= ~1; navail = nargregs - (reg - A0); if (navail < 2) { /* would have appeared half in registers/half * on the stack, but alignment ensures it * appears on the stack */ if (dotemps) putintemp(sym); *regp = reg; return; } t = tempnode(0, LONGLONG, 0, 0); tmpnr = regno(t); q = block(REG, NIL, NIL, LONGLONG, 0, 0); q->n_rval = A0A1 + (reg - A0); p = buildtree(ASSIGN, t, q); ecomp(p); if (dotemps) { sym->soffset = tmpnr; sym->sflags |= STNODE; } else { q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap); p = nametree(sym); p = buildtree(ASSIGN, p, q); ecomp(p); } *regp = reg + 2; } /* * XXX This is a hack. We cannot have floats in more than one * register class. So we bounce them in and out of temps to * move them in and out of the right registers. */ static void param_float(struct symtab *sym, int *regp, int dotemps) { NODE *p, *q, *t; int tmpnr; t = tempnode(0, INT, 0, 0); tmpnr = regno(t); q = block(REG, NIL, NIL, INT, 0, 0); q->n_rval = (*regp)++; p = buildtree(ASSIGN, t, q); ecomp(p); if (dotemps) { sym->soffset = tmpnr; sym->sflags |= STNODE; } else { q = tempnode(tmpnr, sym->stype, sym->sdf, sym->sap); p = nametree(sym); p = buildtree(ASSIGN, p, q); ecomp(p); } } /* * code for the beginning of a function; a is an array of * indices in symtab for the arguments; n is the number */ void bfcode(struct symtab **sp, int cnt) { union arglist *usym; int lastreg = A0 + nargregs - 1; int saveallargs = 0; int i, reg; /* * Detect if this function has ellipses and save all * argument register onto stack. */ usym = cftnsp->sdf->dfun; while (usym && usym->type != TNULL) { if (usym->type == TELLIPSIS) { saveallargs = 1; break; } ++usym; } reg = A0; /* assign hidden return structure to temporary */ if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { param_retptr(); ++reg; } /* recalculate the arg offset and create TEMP moves */ for (i = 0; i < cnt; i++) { if ((reg > lastreg) && !xtemps) break; else if (reg > lastreg) putintemp(sp[i]); else if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY) param_struct(sp[i], ®); else if ((DEUNSIGN(sp[i]->stype) == LONG) || (DEUNSIGN(sp[i]->stype) == LONGLONG)) param_64bit(sp[i], ®, xtemps && !saveallargs); else if (sp[i]->stype == DOUBLE || sp[i]->stype == LDOUBLE) param_double(sp[i], ®, xtemps && !saveallargs); else if (sp[i]->stype == FLOAT) param_float(sp[i], ®, xtemps && !saveallargs); else param_32bit(sp[i], ®, xtemps && !saveallargs); } /* if saveallargs, save the rest of the args onto the stack */ if (!saveallargs) return; while (reg <= lastreg) { NODE *p, *q; int off = ARGINIT/SZINT + (reg - A0); q = block(REG, NIL, NIL, INT, 0, 0); q->n_rval = reg++; p = block(REG, NIL, NIL, INT, 0, 0); p->n_rval = FP; p = block(PLUS, p, bcon(8*off), INT, 0, 0); p = block(UMUL, p, NIL, INT, 0, 0); p = buildtree(ASSIGN, p, q); ecomp(p); } } /* called just before final exit */ /* flag is 1 if errors, 0 if none */ void ejobcode(int flag) { } void bjobcode(void) { printf("\t.section .mdebug.abi64\n"); printf("\t.previous\n"); /* only if -fpic or -fPIC */ if (kflag > 0) printf("\t.abicalls\n"); } #ifdef notdef /* * Print character t at position i in one string, until t == -1. * Locctr & label is already defined. */ void bycode(int t, int i) { static int lastoctal = 0; /* put byte i+1 in a string */ if (t < 0) { if (i != 0) puts("\\000\""); } else { if (i == 0) printf("\t.ascii \""); if (t == 0) return; else if (t == '\\' || t == '"') { lastoctal = 0; putchar('\\'); putchar(t); } else if (t == 011) { printf("\\t"); } else if (t == 012) { printf("\\n"); } else if (t < 040 || t >= 0177) { lastoctal++; printf("\\%o",t); } else if (lastoctal && '0' <= t && t <= '9') { lastoctal = 0; printf("\"\n\t.ascii \"%c", t); } else { lastoctal = 0; putchar(t); } } } #endif /* fix up type of field p */ void fldty(struct symtab *p) { } /* * XXX - fix genswitch. */ int mygenswitch(int num, TWORD type, struct swents **p, int n) { return 0; } /* setup call stack with a structure */ /* called from moveargs() */ static NODE * movearg_struct(NODE *p, NODE *parent, int *regp) { int reg = *regp; NODE *l, *q, *t, *r; int tmpnr; int navail; int off; int num; int sz; int ty; int i; navail = nargregs - (reg - A0); sz = tsize(p->n_type, p->n_df, p->n_ap) / SZINT; num = sz > navail ? navail : sz; l = p->n_left; nfree(p); ty = l->n_type; t = tempnode(0, l->n_type, l->n_df, l->n_ap); tmpnr = regno(t); l = buildtree(ASSIGN, t, l); if (p != parent) { q = parent->n_left; } else q = NULL; /* copy structure into registers */ for (i = 0; i < num; i++) { t = tempnode(tmpnr, ty, 0, 0); t = block(SCONV, t, NIL, PTR+INT, 0, 0); t = block(PLUS, t, bcon(8*i), PTR+INT, 0, 0); t = buildtree(UMUL, t, NIL); r = block(REG, NIL, NIL, INT, 0, 0); r->n_rval = reg++; r = buildtree(ASSIGN, r, t); if (q == NULL) q = r; else q = block(CM, q, r, INT, 0, 0); } off = ARGINIT/SZINT + nargregs; for (i = num; i < sz; i++) { t = tempnode(tmpnr, ty, 0, 0); t = block(SCONV, t, NIL, PTR+INT, 0, 0); t = block(PLUS, t, bcon(8*i), PTR+INT, 0, 0); t = buildtree(UMUL, t, NIL); r = block(REG, NIL, NIL, INT, 0, 0); r->n_rval = FP; r = block(PLUS, r, bcon(8*off++), INT, 0, 0); r = block(UMUL, r, NIL, INT, 0, 0); r = buildtree(ASSIGN, r, t); if (q == NULL) q = r; else q = block(CM, q, r, INT, 0, 0); } if (parent->n_op == CM) { parent->n_left = q; q = l; } else { q = block(CM, q, l, INT, 0, 0); } *regp = reg; return q; } /* setup call stack with 64-bit argument */ /* called from moveargs() */ static NODE * movearg_64bit(NODE *p, int *regp) { int reg = *regp; NODE *q; int lastarg; /* alignment */ ++reg; reg &= ~1; lastarg = A0 + nargregs - 1; if (reg > lastarg) { *regp = reg; return block(FUNARG, p, NIL, p->n_type, p->n_df, p->n_ap); } q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap); q->n_rval = A0A1 + (reg - A0); q = buildtree(ASSIGN, q, p); *regp = reg + 2; return q; } /* setup call stack with 32-bit argument */ /* called from moveargs() */ static NODE * movearg_32bit(NODE *p, int *regp) { int reg = *regp; NODE *q; q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap); q->n_rval = reg++; q = buildtree(ASSIGN, q, p); *regp = reg; return q; } static NODE * moveargs(NODE *p, int *regp) { NODE *r, **rp; int lastreg; int reg; if (p->n_op == CM) { p->n_left = moveargs(p->n_left, regp); r = p->n_right; rp = &p->n_right; } else { r = p; rp = &p; } lastreg = A0 + nargregs - 1; reg = *regp; if (reg > lastreg && r->n_op != STARG) *rp = block(FUNARG, r, NIL, r->n_type, r->n_df, r->n_ap); else if (r->n_op == STARG) { *rp = movearg_struct(r, p, regp); } else if ((DEUNSIGN(r->n_type) == LONG) || (DEUNSIGN(r->n_type) == LONGLONG)) { *rp = movearg_64bit(r, regp); } else if (r->n_type == DOUBLE || r->n_type == LDOUBLE) { /* XXX bounce in and out of temporary to change to longlong */ NODE *t1 = tempnode(0, LONGLONG, 0, 0); int tmpnr = regno(t1); NODE *t2 = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap); t1 = movearg_64bit(t1, regp); r = block(ASSIGN, t2, r, r->n_type, r->n_df, r->n_ap); if (p->n_op == CM) { p->n_left = buildtree(CM, p->n_left, t1); p->n_right = r; } else { p = buildtree(CM, t1, r); } } else if (r->n_type == FLOAT) { /* XXX bounce in and out of temporary to change to int */ NODE *t1 = tempnode(0, INT, 0, 0); int tmpnr = regno(t1); NODE *t2 = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap); t1 = movearg_32bit(t1, regp); r = block(ASSIGN, t2, r, r->n_type, r->n_df, r->n_ap); if (p->n_op == CM) { p->n_left = buildtree(CM, p->n_left, t1); p->n_right = r; } else { p = buildtree(CM, t1, r); } } else { *rp = movearg_32bit(r, regp); } return p; } /* * Called with a function call with arguments as argument. * This is done early in buildtree() and only done once. */ NODE * funcode(NODE *p) { int regnum = A0; NODE *l, *r, *t, *q; int ty; l = p->n_left; r = p->n_right; /* * if returning a structure, make the first argument * a hidden pointer to return structure. */ ty = DECREF(l->n_type); if (ty == STRTY+FTN || ty == UNIONTY+FTN) { ty = DECREF(l->n_type) - FTN; q = tempnode(0, ty, l->n_df, l->n_ap); q = buildtree(ADDROF, q, NIL); if (r->n_op != CM) { p->n_right = block(CM, q, r, INCREF(ty), l->n_df, l->n_ap); } else { for (t = r; t->n_left->n_op == CM; t = t->n_left) ; t->n_left = block(CM, q, t->n_left, INCREF(ty), l->n_df, l->n_ap); } } p->n_right = moveargs(p->n_right, ®num); return p; } NODE * builtin_cfa(const struct bitable *bt, NODE *a) { uerror("missing builtin_cfa"); return bcon(0); } NODE * builtin_frame_address(const struct bitable *bt, NODE *a) { uerror("missing builtin_frame_address"); return bcon(0); } NODE * builtin_return_address(const struct bitable *bt, NODE *a) { uerror("missing builtin_return_address"); return bcon(0); } pcc-20181216/arch/mips64/local.c010064400017500000000000000367171340103772300147770ustar raggewheel/* $Id: local.c,v 1.2 2018/12/02 20:25:55 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and * Simon Olsson (simols-1@student.ltu.se) 2005. * * Extended to MIPS64 by Brian Callahan 2016. */ #include "pass1.h" #ifndef LANG_CXX #define NODE P1ND #define ccopy p1tcopy #define tcopy p1tcopy #define tfree p1tfree #define nfree p1nfree #define fwalk p1fwalk #define talloc p1alloc #endif #define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz)) /* this is called to do local transformations on * an expression tree preparitory to its being * written out in intermediate code. */ NODE * clocal(NODE *p) { struct symtab *q; NODE *r, *l; int o; int m; TWORD ty; int tmpnr, isptrvoid = 0; #ifdef PCC_DEBUG if (xdebug) { printf("clocal in: %p\n", p); fwalk(p, eprint, 0); } #endif switch (o = p->n_op) { case UCALL: case CALL: case STCALL: case USTCALL: if (p->n_type == VOID) break; /* * if the function returns void*, ecode() invokes * delvoid() to convert it to uchar*. * We just let this happen on the ASSIGN to the temp, * and cast the pointer back to void* on access * from the temp. */ if (p->n_type == PTR+VOID) isptrvoid = 1; r = tempnode(0, p->n_type, p->n_df, p->n_ap); tmpnr = regno(r); r = block(ASSIGN, r, p, p->n_type, p->n_df, p->n_ap); p = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap); if (isptrvoid) { p = block(PCONV, p, NIL, PTR+VOID, p->n_df, 0); } p = buildtree(COMOP, r, p); break; case NAME: if ((q = p->n_sp) == NULL) return p; /* Nothing to care about */ switch (q->sclass) { case PARAM: case AUTO: /* fake up a structure reference */ r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); slval(r, 0); r->n_rval = FP; p = stref(block(STREF, r, p, 0, 0, 0)); break; case STATIC: if (q->slevel == 0) break; slval(p, 0); p->n_sp = q; break; case REGISTER: p->n_op = REG; slval(p, 0); p->n_rval = q->soffset; break; } break; case FUNARG: /* Args smaller than int are given as int */ if (p->n_type != CHAR && p->n_type != UCHAR && p->n_type != SHORT && p->n_type != USHORT) break; p->n_left = block(SCONV, p->n_left, NIL, INT, 0, 0); p->n_type = INT; p->n_ap = 0; p->n_rval = SZINT; break; case CBRANCH: l = p->n_left; /* * Remove unnecessary conversion ops. */ if (clogop(l->n_op) && l->n_left->n_op == SCONV) { if (coptype(l->n_op) != BITYPE) break; if (l->n_right->n_op == ICON) { r = l->n_left->n_left; if (r->n_type >= FLOAT && r->n_type <= LDOUBLE) break; /* Type must be correct */ ty = r->n_type; nfree(l->n_left); l->n_left = r; l->n_type = ty; l->n_right->n_type = ty; } #if 0 else if (l->n_right->n_op == SCONV && l->n_left->n_type == l->n_right->n_type) { r = l->n_left->n_left; nfree(l->n_left); l->n_left = r; r = l->n_right->n_left; nfree(l->n_right); l->n_right = r; } #endif } break; case PCONV: /* Remove redundant PCONV's. Be careful */ l = p->n_left; if (l->n_op == ICON) { slval(l, (unsigned)glval(l)); goto delp; } if (l->n_type < INT || DEUNSIGN(l->n_type) == LONG || DEUNSIGN(l->n_type) == LONGLONG) { /* float etc? */ p->n_left = block(SCONV, l, NIL, UNSIGNED, 0, 0); break; } /* if left is SCONV, cannot remove */ if (l->n_op == SCONV) break; /* avoid ADDROF TEMP */ if (l->n_op == ADDROF && l->n_left->n_op == TEMP) break; /* if conversion to another pointer type, just remove */ if (p->n_type > BTMASK && l->n_type > BTMASK) goto delp; break; delp: l->n_type = p->n_type; l->n_qual = p->n_qual; l->n_df = p->n_df; l->n_ap = p->n_ap; nfree(p); p = l; break; case SCONV: l = p->n_left; if (p->n_type == l->n_type) { nfree(p); p = l; break; } if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 && tsize(p->n_type, p->n_df, p->n_ap) == tsize(l->n_type, l->n_df, l->n_ap)) { if (p->n_type != FLOAT && p->n_type != DOUBLE && l->n_type != FLOAT && l->n_type != DOUBLE && l->n_type != LDOUBLE && p->n_type != LDOUBLE) { if (l->n_op == NAME || l->n_op == UMUL || l->n_op == TEMP) { l->n_type = p->n_type; nfree(p); p = l; break; } } } if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT && coptype(l->n_op) == BITYPE) { l->n_type = p->n_type; nfree(p); p = l; } if (DEUNSIGN(p->n_type) == SHORT && DEUNSIGN(l->n_type) == SHORT) { nfree(p); p = l; } /* convert float/double to int before to (u)char/(u)short */ if ((DEUNSIGN(p->n_type) == CHAR || DEUNSIGN(p->n_type) == SHORT) && (l->n_type == FLOAT || l->n_type == DOUBLE || l->n_type == LDOUBLE)) { p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap); p->n_left->n_type = INT; break; } /* convert (u)char/(u)short to int before float/double */ if ((p->n_type == FLOAT || p->n_type == DOUBLE || p->n_type == LDOUBLE) && (DEUNSIGN(l->n_type) == CHAR || DEUNSIGN(l->n_type) == SHORT)) { p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap); p->n_left->n_type = INT; break; } break; case MOD: case DIV: if (o == DIV && p->n_type != CHAR && p->n_type != SHORT) break; if (o == MOD && p->n_type != CHAR && p->n_type != SHORT) break; /* make it an int division by inserting conversions */ p->n_left = block(SCONV, p->n_left, NIL, INT, 0, 0); p->n_right = block(SCONV, p->n_right, NIL, INT, 0, 0); p = block(SCONV, p, NIL, p->n_type, 0, 0); p->n_left->n_type = INT; break; case FORCE: /* put return value in return reg */ p->n_op = ASSIGN; p->n_right = p->n_left; p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0); p->n_left->n_rval = RETREG(p->n_type); break; } #ifdef PCC_DEBUG if (xdebug) { printf("clocal out: %p\n", p); fwalk(p, eprint, 0); } #endif return(p); } void myp2tree(NODE *p) { struct symtab *sp; if (p->n_op != FCON) return; /* Write float constants to memory */ sp = IALLOC(sizeof(struct symtab)); sp->sclass = STATIC; sp->sap = 0; sp->slevel = 1; /* fake numeric label */ sp->soffset = getlab(); sp->sflags = 0; sp->stype = p->n_type; sp->squal = (CON >> TSHIFT); defloc(sp); ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p); p->n_op = NAME; slval(p, 0); p->n_sp = sp; } /*ARGSUSED*/ int andable(NODE *p) { return(1); /* all names can have & taken on them */ } /* * is an automatic variable of type t OK for a register variable */ int cisreg(TWORD t) { if (t == INT || t == UNSIGNED) return(1); return 0; /* XXX - fix reg assignment in pftn.c */ } /* * Allocate off bits on the stack. p is a tree that when evaluated * is the multiply count for off, t is a NAME node where to write * the allocated address. */ void spalloc(NODE *t, NODE *p, OFFSZ off) { NODE *sp; int nbytes = off / SZCHAR; p = buildtree(MUL, p, bcon(nbytes)); p = buildtree(PLUS, p, bcon(7)); p = buildtree(AND, p, bcon(~7)); /* subtract the size from sp */ sp = block(REG, NIL, NIL, p->n_type, 0, 0); slval(sp, 0); sp->n_rval = SP; ecomp(buildtree(MINUSEQ, sp, p)); /* save the address of sp */ sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap); sp->n_rval = SP; t->n_type = sp->n_type; ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */ } /* * print out a constant node * mat be associated with a label */ int ninval(CONSZ off, int fsz, NODE *p) { struct symtab *q; TWORD t; #ifndef USE_GAS int i, j; #endif t = p->n_type; if (t > BTMASK) p->n_type = t = LONG; /* pointer */ if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != LONG) uerror("element not constant"); switch (t) { case LONGLONG: case ULONGLONG: #ifdef USE_GAS printf("\t.dword %lld\n", (long long)glval(p)); #else i = glval(p) >> 32; j = glval(p) & 0xffffffff; p->n_type = INT; if (bigendian) { slval(p, j); ninval(off, 32, p); slval(p, i); ninval(off+32, 32, p); } else { slval(p, i); ninval(off, 32, p); slval(p, j); ninval(off+32, 32, p); } #endif break; case INT: case UNSIGNED: printf("\t.word " CONFMT, (CONSZ)glval(p)); if ((q = p->n_sp) != NULL) { if ((q->sclass == STATIC && q->slevel > 0)) { printf("+" LABFMT, q->soffset); } else printf("+%s", getexname(q)); } printf("\n"); break; case SHORT: case USHORT: astypnames[SHORT] = astypnames[USHORT] = "\t.half"; return 0; default: return 0; } return 1; } /* make a name look like an external name in the local machine */ char * exname(char *p) { if (p == NULL) return ""; return p; } /* * map types which are not defined on the local machine */ TWORD ctype(TWORD type) { switch (BTYPE(type)) { case LONG: MODTYPE(type,LONGLONG); break; case ULONG: MODTYPE(type,ULONGLONG); } return (type); } void calldec(NODE *p, NODE *q) { } void extdec(struct symtab *q) { } /* make a common declaration for id, if reasonable */ void defzero(struct symtab *sp) { int off; off = tsize(sp->stype, sp->sdf, sp->sap); off = (off+(SZCHAR-1))/SZCHAR; printf(" .%scomm ", sp->sclass == STATIC ? "l" : ""); if (sp->slevel == 0) printf("%s,0%o\n", getexname(sp), off); else printf(LABFMT ",0%o\n", sp->soffset, off); } #ifdef notdef /* make a common declaration for id, if reasonable */ void commdec(struct symtab *q) { int off; off = tsize(q->stype, q->sdf, q->ssue); off = (off+(SZCHAR-1))/SZCHAR; printf(" .comm %s,%d\n", exname(q->soname), off); } /* make a local common declaration for id, if reasonable */ void lcommdec(struct symtab *q) { int off; off = tsize(q->stype, q->sdf, q->ssue); off = (off+(SZCHAR-1))/SZCHAR; if (q->slevel == 0) printf("\t.lcomm %s,%d\n", exname(q->soname), off); else printf("\t.lcomm " LABFMT ",%d\n", q->soffset, off); } /* * print a (non-prog) label. */ void deflab1(int label) { printf(LABFMT ":\n", label); } /* ro-text, rw-data, ro-data, ro-strings */ static char *loctbl[] = { "text", "data", "rdata", "rdata" }; void setloc1(int locc) { if (locc == lastloc && locc != STRNG) return; if (locc == RDATA && lastloc == STRNG) return; if (locc != lastloc) { lastloc = locc; printf("\t.%s\n", loctbl[locc]); } if (locc == STRNG) printf("\t.align 2\n"); } #endif /* * va_start(ap, last) implementation. * * f is the NAME node for this builtin function. * a is the argument list containing: * CM * ap last * * It turns out that this is easy on MIPS. Just write the * argument registers to the stack in va_arg_start() and * use the traditional method of walking the stackframe. */ NODE * mips64_builtin_stdarg_start(const struct bitable *bt, NODE *a) { NODE *p, *q; int sz = 1; /* check num args and type */ if (a == NULL || a->n_op != CM || a->n_left->n_op == CM || !ISPTR(a->n_left->n_type)) goto bad; /* must first deal with argument size; use int size */ p = a->n_right; if (p->n_type < INT) { /* round up to word */ sz = SZINT / tsize(p->n_type, p->n_df, p->n_ap); } p = buildtree(ADDROF, p, NIL); /* address of last arg */ p = optim(buildtree(PLUS, p, bcon(sz))); q = block(NAME, NIL, NIL, PTR+VOID, 0, 0); q = buildtree(CAST, q, p); p = q->n_right; nfree(q->n_left); nfree(q); p = buildtree(ASSIGN, a->n_left, p); nfree(a); return p; bad: uerror("bad argument to __builtin_stdarg_start"); return bcon(0); } NODE * mips64_builtin_va_arg(const struct bitable *bt, NODE *a) { NODE *p, *q, *r; int sz, tmpnr; /* check num args and type */ if (a == NULL || a->n_op != CM || a->n_left->n_op == CM || !ISPTR(a->n_left->n_type) || a->n_right->n_op != TYPE) goto bad; r = a->n_right; /* get type size */ sz = tsize(r->n_type, r->n_df, r->n_ap) / SZCHAR; if (sz < SZINT/SZCHAR) { werror("%s%s promoted to int when passed through ...", r->n_type & 1 ? "unsigned " : "", DEUNSIGN(r->n_type) == SHORT ? "short" : "char"); sz = SZINT/SZCHAR; } /* alignment */ p = tcopy(a->n_left); if (sz > SZINT/SZCHAR && r->n_type != UNIONTY && r->n_type != STRTY) { p = buildtree(PLUS, p, bcon(7)); p = block(AND, p, bcon(-8), p->n_type, p->n_df, p->n_ap); } /* create a copy to a temp node */ q = tempnode(0, p->n_type, p->n_df, p->n_ap); tmpnr = regno(q); p = buildtree(ASSIGN, q, p); q = tempnode(tmpnr, p->n_type, p->n_df,p->n_ap); q = buildtree(PLUS, q, bcon(sz)); q = buildtree(ASSIGN, a->n_left, q); q = buildtree(COMOP, p, q); nfree(a->n_right); nfree(a); p = tempnode(tmpnr, INCREF(r->n_type), r->n_df, r->n_ap); p = buildtree(UMUL, p, NIL); p = buildtree(COMOP, q, p); return p; bad: uerror("bad argument to __builtin_va_arg"); return bcon(0); } NODE * mips64_builtin_va_end(const struct bitable *bt, NODE *a) { tfree(a); return bcon(0); } NODE * mips64_builtin_va_copy(const struct bitable *bt, NODE *a) { NODE *f; if (a == NULL || a->n_op != CM || a->n_left->n_op == CM) goto bad; f = buildtree(ASSIGN, a->n_left, a->n_right); nfree(a); return f; bad: uerror("bad argument to __builtin_va_copy"); return bcon(0); } static int constructor; static int destructor; /* * Give target the opportunity of handling pragmas. */ int mypragma(char *str) { if (strcmp(str, "tls") == 0) { uerror("thread-local storage not supported for this target"); return 1; } if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) { constructor = 1; return 1; } if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) { destructor = 1; return 1; } return 0; } /* * Called when a identifier has been declared, to give target last word. */ void fixdef(struct symtab *sp) { if ((constructor || destructor) && (sp->sclass != PARAM)) { printf("\t.section .%ctors,\"aw\",@progbits\n", constructor ? 'c' : 'd'); printf("\t.p2align 2\n"); printf("\t.long %s\n", exname(sp->sname)); printf("\t.previous\n"); constructor = destructor = 0; } } void pass1_lastchance(struct interpass *ip) { } pcc-20181216/arch/mips64/local2.c010064400017500000000000000736351277225026600150720ustar raggewheel/* $Id: local2.c,v 1.2 2016/09/26 16:45:42 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and * Simon Olsson (simols-1@student.ltu.se) 2005. * * Extended to MIPS64 by Brian Callahan 2016. */ #include #include #include #include #include "pass1.h" #include "pass2.h" #ifdef TARGET_BIG_ENDIAN int bigendian = 1; #else int bigendian = 0; #endif int nargregs = MIPS_N64_NARGREGS; static int argsiz(NODE *p); void deflab(int label) { printf(LABFMT ":\n", label); } static int regoff[64]; static TWORD ftype; /* * calculate stack size and offsets */ static int offcalc(struct interpass_prolog * ipp) { int i, j, addto; addto = p2maxautooff; for (i = p2env.p_regs[0], j = 0; i; i >>= 1, j++) { if (i & 1) { addto += SZINT / SZCHAR * 2; regoff[j] = addto; } } /* round to 8-byte boundary */ addto += 7; addto &= ~7; return addto; } /* * Print out the prolog assembler. */ void prologue(struct interpass_prolog * ipp) { int addto; int i, j; ftype = ipp->ipp_type; printf("\t.align 2\n"); if (ipp->ipp_vis) printf("\t.globl %s\n", ipp->ipp_name); printf("\t.ent %s\n", ipp->ipp_name); printf("%s:\n", ipp->ipp_name); addto = offcalc(ipp); /* emit PIC only if -fpic or -fPIC set */ if (kflag > 0) { printf("\t.frame %s,%d,%s\n", rnames[FP], ARGINIT/SZCHAR, rnames[RA]); printf("\t.set noreorder\n"); printf("\t.cpload $25\t# pseudo-op to load GOT ptr into $25\n"); printf("\t.set reorder\n"); } printf("\tdsubu %s,%s,%d\n", rnames[SP], rnames[SP], ARGINIT/SZCHAR); /* emit PIC only if -fpic or -fPIC set */ if (kflag > 0) printf("\t.cprestore 8\t# pseudo-op to store GOT ptr at 8(sp)\n"); printf("\tsd %s,8(%s)\n", rnames[RA], rnames[SP]); printf("\tsd %s,(%s)\n", rnames[FP], rnames[SP]); printf("\tmove %s,%s\n", rnames[FP], rnames[SP]); #ifdef notyet /* profiling */ if (pflag) { printf("\t.set noat\n"); printf("\tmove %s,%s\t# save current return address\n", rnames[AT], rnames[RA]); printf("\tdsubu %s,%s,16\t# _mcount pops 2 dwords from stack\n", rnames[SP], rnames[SP]); printf("\tjal %s\n", exname("_mcount")); printf("\tnop\n"); printf("\t.set at\n"); } #endif if (addto) printf("\tdsubu %s,%s,%d\n", rnames[SP], rnames[SP], addto); for (i = p2env.p_regs[0], j = 0; i; i >>= 1, j++) if (i & 1) printf("\tsd %s,-%d(%s) # save permanent\n", rnames[j], regoff[j], rnames[FP]); } void eoftn(struct interpass_prolog * ipp) { int i, j; (void) offcalc(ipp); if (ipp->ipp_ip.ip_lbl == 0) return; /* no code needs to be generated */ /* return from function code */ for (i = p2env.p_regs[0], j = 0; i; i >>= 1, j++) { if (i & 1) printf("\tld %s,-%d(%s)\n\tnop\n", rnames[j], regoff[j], rnames[FP]); } printf("\tdaddiu %s,%s,%d\n", rnames[SP], rnames[FP], ARGINIT/SZCHAR); printf("\tld %s,%d(%s)\n", rnames[RA], 8-ARGINIT/SZCHAR, rnames[SP]); printf("\tld %s,%d(%s)\n", rnames[FP], 0-ARGINIT/SZCHAR, rnames[SP]); printf("\tjr %s\n", rnames[RA]); printf("\tnop\n"); #ifdef USE_GAS printf("\t.end %s\n", ipp->ipp_name); printf("\t.size %s,.-%s\n", ipp->ipp_name, ipp->ipp_name); #endif } /* * add/sub/... * * Param given: */ void hopcode(int f, int o) { char *str; switch (o) { case EQ: str = "beqz"; /* pseudo-op */ break; case NE: str = "bnez"; /* pseudo-op */ break; case ULE: case LE: str = "blez"; break; case ULT: case LT: str = "bltz"; break; case UGE: case GE: str = "bgez"; break; case UGT: case GT: str = "bgtz"; break; case PLUS: str = "add"; break; case MINUS: str = "sub"; break; case AND: str = "and"; break; case OR: str = "or"; break; case ER: str = "xor"; break; default: comperr("hopcode2: %d", o); str = 0; /* XXX gcc */ } printf("%s%c", str, f); } char * rnames[] = { #ifdef USE_GAS /* gnu assembler */ "$zero", "$at", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", "$24", "$25", "$kt0", "$kt1", "$gp", "$sp", "$fp", "$ra", "$2!!$3!!", "$4!!$5!!", "$5!!$6!!", "$6!!$7!!", "$7!!$8!!", "$8!!$9!!", "$9!!$10!", "$10!$11!", "$11!$12!", "$12!$13!", "$13!$14!", "$14!$15!", "$15!$24!", "$24!$25!", "$16!$17!", "$17!$18!", "$18!$19!", "$19!$20!", "$20!$21!", "$21!$22!", "$22!$23!", #else /* mips assembler */ "$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3", "$a4", "$a5", "$a6", "$a7", "$t4", "$t5", "$t6", "$t7", "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7", "$t8", "$t9", "$k0", "$k1", "$gp", "$sp", "$fp", "$ra", "$v0!$v1!", "$a0!$a1!", "$a1!$a2!", "$a2!$a3!", "$a3!$t0!", "$t0!$t1!", "$t1!$t2!", "$t2!$t3!", "$t3!$t4!", "$t4!$t5!", "$t5!$t6!", "$t6!$t7!", "$t7!$t8!", "$t8!$t9!", "$s0!$s1!", "$s1!$s2!", "$s2!$s3!", "$s3!$s4!", "$s4!$s5!", "$s5!$s6!", "$s6!$s7!", #endif "$f0!$f1!", "$f2!$f3!", "$f4!$f5!", "$f6!$f7!", "$f8!$f9!", "$f10$f11", "$f12$f13", "$f14$f15", "$f16$f17", "$f18$f19", "$f20$f21", "$f22$f23", "$f24$f25", "$f26$f27", "$f28$f29", "$f30$f31", }; int tlen(NODE *p) { switch (p->n_type) { case CHAR: case UCHAR: return (1); case SHORT: case USHORT: return (SZSHORT / SZCHAR); case DOUBLE: return (SZDOUBLE / SZCHAR); case INT: case UNSIGNED: return (SZINT / SZCHAR); case LONG: case ULONG: case LONGLONG: case ULONGLONG: return SZLONGLONG / SZCHAR; default: if (!ISPTR(p->n_type)) comperr("tlen type %d not pointer"); return SZPOINT(p->n_type) / SZCHAR; } } /* * Push a structure on stack as argument. */ static void starg(NODE *p) { int sz = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0); //assert(p->n_rval == A1); printf("\tdsubu %s,%s,%d\n", rnames[SP], rnames[SP], sz); /* A0 = dest, A1 = src, A2 = len */ printf("\tmove %s,%s\n", rnames[A0], rnames[SP]); printf("\tdli %s,%d\t# structure size\n", rnames[A2], sz); printf("\tdsubu %s,%s,32\n", rnames[SP], rnames[SP]); printf("\tjal %s\t# structure copy\n", exname("memcpy")); printf("\tnop\n"); printf("\tdaddiu %s,%s,32\n", rnames[SP], rnames[SP]); } /* * Structure assignment. */ static void stasg(NODE *p) { assert(p->n_right->n_rval == A1); /* A0 = dest, A1 = src, A2 = len */ printf("\tdli %s,%d\t# structure size\n", rnames[A2], attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)); if (p->n_left->n_op == OREG) { printf("\tdaddiu %s,%s," CONFMT "\t# dest address\n", rnames[A0], rnames[p->n_left->n_rval], getlval(p->n_left)); } else if (p->n_left->n_op == NAME) { printf("\tdla %s,", rnames[A0]); adrput(stdout, p->n_left); printf("\n"); } printf("\tdsubu %s,%s,32\n", rnames[SP], rnames[SP]); printf("\tjal %s\t# structure copy\n", exname("memcpy")); printf("\tnop\n"); printf("\tdaddiu %s,%s,32\n", rnames[SP], rnames[SP]); } static void shiftop(NODE *p) { NODE *r = p->n_right; TWORD ty = p->n_type; if (p->n_op == LS && r->n_op == ICON && getlval(r) < 32) { expand(p, INBREG, "\tdsrl A1,AL,"); printf(CONFMT "\t# 64-bit left-shift\n", 32 - getlval(r)); expand(p, INBREG, "\tdsll U1,UL,AR\n"); expand(p, INBREG, "\tor U1,U1,A1\n"); expand(p, INBREG, "\tdsll A1,AL,AR\n"); } else if (p->n_op == LS && r->n_op == ICON && getlval(r) < 64) { expand(p, INBREG, "\tdli A1,0\t# 64-bit left-shift\n"); expand(p, INBREG, "\tdsll U1,AL,"); printf(CONFMT "\n", getlval(r) - 32); } else if (p->n_op == LS && r->n_op == ICON) { expand(p, INBREG, "\tdli A1,0\t# 64-bit left-shift\n"); } else if (p->n_op == RS && r->n_op == ICON && getlval(r) < 32) { expand(p, INBREG, "\tdsll U1,UL,"); printf(CONFMT "\t# 64-bit right-shift\n", 32 - getlval(r)); expand(p, INBREG, "\tdsrl A1,AL,AR\n"); expand(p, INBREG, "\tor A1,A1,U1\n"); if (ty == LONG || ty == LONGLONG) expand(p, INBREG, "\tdsra U1,UL,AR\n"); else expand(p, INBREG, "\tdsrl U1,UL,AR\n"); } else if (p->n_op == RS && r->n_op == ICON && getlval(r) < 64) { if (ty == LONG || ty == LONGLONG) { expand(p, INBREG, "\tdsra U1,UL,31\t# 64-bit right-shift\n"); expand(p, INBREG, "\tdsra A1,UL,"); }else { expand(p, INBREG, "\tdli U1,0\t# 64-bit right-shift\n"); expand(p, INBREG, "\tdsrl A1,UL,"); } printf(CONFMT "\n", getlval(r) - 32); } else if (p->n_op == LS && r->n_op == ICON) { expand(p, INBREG, "\tdli A1,0\t# 64-bit right-shift\n"); } else { comperr("shiftop"); } } /* * http://gcc.gnu.org/onlinedocs/gccint/Soft-float-library-routines.html#Soft-float-library-routines */ static void fpemulop(NODE *p) { NODE *l = p->n_left; char *ch = NULL; if (p->n_op == PLUS && p->n_type == FLOAT) ch = "addsf3"; else if (p->n_op == PLUS && p->n_type == DOUBLE) ch = "adddf3"; else if (p->n_op == PLUS && p->n_type == LDOUBLE) ch = "addtf3"; else if (p->n_op == MINUS && p->n_type == FLOAT) ch = "subsf3"; else if (p->n_op == MINUS && p->n_type == DOUBLE) ch = "subdf3"; else if (p->n_op == MINUS && p->n_type == LDOUBLE) ch = "subtf3"; else if (p->n_op == MUL && p->n_type == FLOAT) ch = "mulsf3"; else if (p->n_op == MUL && p->n_type == DOUBLE) ch = "muldf3"; else if (p->n_op == MUL && p->n_type == LDOUBLE) ch = "multf3"; else if (p->n_op == DIV && p->n_type == FLOAT) ch = "divsf3"; else if (p->n_op == DIV && p->n_type == DOUBLE) ch = "divdf3"; else if (p->n_op == DIV && p->n_type == LDOUBLE) ch = "divtf3"; else if (p->n_op == UMINUS && p->n_type == FLOAT) ch = "negsf2"; else if (p->n_op == UMINUS && p->n_type == DOUBLE) ch = "negdf2"; else if (p->n_op == UMINUS && p->n_type == LDOUBLE) ch = "negtf2"; else if (p->n_op == EQ && l->n_type == FLOAT) ch = "eqsf2"; else if (p->n_op == EQ && l->n_type == DOUBLE) ch = "eqdf2"; else if (p->n_op == EQ && l->n_type == LDOUBLE) ch = "eqtf2"; else if (p->n_op == NE && l->n_type == FLOAT) ch = "nesf2"; else if (p->n_op == NE && l->n_type == DOUBLE) ch = "nedf2"; else if (p->n_op == NE && l->n_type == LDOUBLE) ch = "netf2"; else if (p->n_op == GE && l->n_type == FLOAT) ch = "gesf2"; else if (p->n_op == GE && l->n_type == DOUBLE) ch = "gedf2"; else if (p->n_op == GE && l->n_type == LDOUBLE) ch = "getf2"; else if (p->n_op == LE && l->n_type == FLOAT) ch = "lesf2"; else if (p->n_op == LE && l->n_type == DOUBLE) ch = "ledf2"; else if (p->n_op == LE && l->n_type == LDOUBLE) ch = "letf2"; else if (p->n_op == GT && l->n_type == FLOAT) ch = "gtsf2"; else if (p->n_op == GT && l->n_type == DOUBLE) ch = "gtdf2"; else if (p->n_op == GT && l->n_type == LDOUBLE) ch = "gttf2"; else if (p->n_op == LT && l->n_type == FLOAT) ch = "ltsf2"; else if (p->n_op == LT && l->n_type == DOUBLE) ch = "ltdf2"; else if (p->n_op == LT && l->n_type == LDOUBLE) ch = "lttf2"; else if (p->n_op == SCONV && p->n_type == FLOAT) { if (l->n_type == DOUBLE) ch = "truncdfsf2"; else if (l->n_type == LDOUBLE) ch = "trunctfsf2"; else if (l->n_type == ULONGLONG) ch = "floatdisf"; /**/ else if (l->n_type == LONGLONG) ch = "floatdisf"; else if (l->n_type == LONG) ch = "floatdisf"; else if (l->n_type == ULONG) ch = "floatdisf"; else if (l->n_type == INT) ch = "floatsisf"; else if (l->n_type == UNSIGNED) ch = "floatunsisf"; } else if (p->n_op == SCONV && p->n_type == DOUBLE) { if (l->n_type == FLOAT) ch = "extendsfdf2"; else if (l->n_type == LDOUBLE) ch = "trunctfdf2"; else if (l->n_type == ULONGLONG) ch = "floatunsdidf"; else if (l->n_type == LONGLONG) ch = "floatdidf"; else if (l->n_type == LONG) ch = "floatdidf"; else if (l->n_type == ULONG) ch = "floatunsdidf"; else if (l->n_type == INT) ch = "floatsidf"; else if (l->n_type == UNSIGNED) ch = "floatunsidf"; } else if (p->n_op == SCONV && p->n_type == LDOUBLE) { if (l->n_type == FLOAT) ch = "extendsftf2"; else if (l->n_type == DOUBLE) ch = "extenddfdf2"; else if (l->n_type == ULONGLONG) ch = "floatunsdidf"; else if (l->n_type == LONGLONG) ch = "floatdidf"; else if (l->n_type == LONG) ch = "floatdidf"; else if (l->n_type == ULONG) ch = "floatunsdidf"; else if (l->n_type == INT) ch = "floatsidf"; else if (l->n_type == UNSIGNED) ch = "floatunsidf"; } else if (p->n_op == SCONV && (p->n_type == ULONG || p->n_type == ULONGLONG)) { if (l->n_type == FLOAT) ch = "fixunssfdi"; else if (l->n_type == DOUBLE) ch = "fixunsdfdi"; else if (l->n_type == LDOUBLE) ch = "fixunsdfdi"; } else if (p->n_op == SCONV && (p->n_type == LONG || p->n_type == LONGLONG)) { if (l->n_type == FLOAT) ch = "fixsfdi"; else if (l->n_type == DOUBLE) ch = "fixdfdi"; else if (l->n_type == LDOUBLE) ch = "fixdfdi"; } else if (p->n_op == SCONV && p->n_type == INT) { if (l->n_type == FLOAT) ch = "fixsfsi"; else if (l->n_type == DOUBLE) ch = "fixdfsi"; else if (l->n_type == LDOUBLE) ch = "fixdfsi"; } else if (p->n_op == SCONV && p->n_type == UNSIGNED) { if (l->n_type == FLOAT) ch = "fixunssfsi"; else if (l->n_type == DOUBLE) ch = "fixunsdfsi"; else if (l->n_type == LDOUBLE) ch = "fixunsdfsi"; } if (ch == NULL) comperr("ZF: op=0x%x (%d)\n", p->n_op, p->n_op); if (p->n_op == SCONV) { if (l->n_type == FLOAT) { printf("\tdmfc1 %s,", rnames[A0]); adrput(stdout, l); printf("\n\tnop\n"); } else if (l->n_type == DOUBLE || l->n_type == LDOUBLE) { printf("\tdmfc1 %s,", rnames[A1]); upput(l, 0); printf("\n\tnop\n"); printf("\tdmfc1 %s,", rnames[A0]); adrput(stdout, l); printf("\n\tnop\n"); } } else { comperr("ZF: incomplete softfloat - put args in registers"); } printf("\tjal __%s\t# softfloat operation\n", exname(ch)); printf("\tnop\n"); if (p->n_op >= EQ && p->n_op <= GT) printf("\tcmp %s,0\n", rnames[V0]); } /* * http://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html#Integer-library-routines */ static void emulop(NODE *p) { char *ch = NULL; if (p->n_op == LS && (DEUNSIGN(p->n_type) == LONG || DEUNSIGN(p->n_type) == LONGLONG)) ch = "ashldi3"; else if (p->n_op == LS && DEUNSIGN(p->n_type) == INT) ch = "ashlsi3"; else if (p->n_op == RS && (p->n_type == ULONG || p->n_type == ULONGLONG)) ch = "lshrdi3"; else if (p->n_op == RS && p->n_type == INT) ch = "lshrsi3"; else if (p->n_op == RS && (p->n_type == LONG || p->n_type == LONGLONG)) ch = "ashrdi3"; else if (p->n_op == RS && p->n_type == INT) ch = "ashrsi3"; else if (p->n_op == DIV && (p->n_type == LONG || p->n_type == LONGLONG)) ch = "divdi3"; else if (p->n_op == DIV && p->n_type == INT) ch = "divsi3"; else if (p->n_op == DIV && (p->n_type == ULONG || p->n_type == ULONGLONG)) ch = "udivdi3"; else if (p->n_op == DIV && p->n_type == UNSIGNED) ch = "udivsi3"; else if (p->n_op == MOD && (p->n_type == LONG || p->n_type == LONGLONG)) ch = "moddi3"; else if (p->n_op == MOD && p->n_type == INT) ch = "modsi3"; else if (p->n_op == MOD && (p->n_type == ULONG || p->n_type == ULONGLONG)) ch = "umoddi3"; else if (p->n_op == MOD && p->n_type == UNSIGNED) ch = "umodsi3"; else if (p->n_op == MUL && (p->n_type == LONG || p->n_type == LONGLONG)) ch = "muldi3"; else if (p->n_op == MUL && p->n_type == INT) ch = "mulsi3"; else if (p->n_op == UMINUS && (p->n_type == LONG || p->n_type == LONGLONG)) ch = "negdi2"; else ch = 0, comperr("ZE"); printf("\tdsubu %s,%s,32\n", rnames[SP], rnames[SP]); printf("\tjal __%s\t# emulated operation\n", exname(ch)); printf("\tnop\n"); printf("\tdaddiu %s,%s,32\n", rnames[SP], rnames[SP]); } /* * Emit code to compare two longlong numbers. */ static void twollcomp(NODE *p) { int o = p->n_op; int s = getlab2(); int e = p->n_label; int cb1, cb2; if (o >= ULE) o -= (ULE-LE); switch (o) { case NE: cb1 = 0; cb2 = NE; break; case EQ: cb1 = NE; cb2 = 0; break; case LE: case LT: cb1 = GT; cb2 = LT; break; case GE: case GT: cb1 = LT; cb2 = GT; break; default: cb1 = cb2 = 0; /* XXX gcc */ } if (p->n_op >= ULE) cb1 += 8, cb2 += 8; expand(p, 0, "\tdsub A1,UL,UR\t# compare 64-bit values (upper)\n"); if (cb1) { printf("\t"); hopcode(' ', cb1); expand(p, 0, "A1"); printf("," LABFMT "\n", s); printf("\tnop\n"); } if (cb2) { printf("\t"); hopcode(' ', cb2); expand(p, 0, "A1"); printf("," LABFMT "\n", e); printf("\tnop\n"); } expand(p, 0, "\tdsub A1,AL,AR\t# (and lower)\n"); printf("\t"); hopcode(' ', o); expand(p, 0, "A1"); printf("," LABFMT "\n", e); printf("\tnop\n"); deflab(s); } static void fpcmpops(NODE *p) { NODE *l = p->n_left; switch (p->n_op) { case EQ: if (l->n_type == FLOAT) expand(p, 0, "\tc.eq.s AL,AR\n"); else expand(p, 0, "\tc.eq.d AL,AR\n"); expand(p, 0, "\tnop\n\tbc1t LC\n"); break; case NE: if (l->n_type == FLOAT) expand(p, 0, "\tc.eq.s AL,AR\n"); else expand(p, 0, "\tc.eq.d AL,AR\n"); expand(p, 0, "\tnop\n\tbc1f LC\n"); break; case LT: if (l->n_type == FLOAT) expand(p, 0, "\tc.lt.s AL,AR\n"); else expand(p, 0, "\tc.lt.d AL,AR\n"); expand(p, 0, "\tnop\n\tbc1t LC\n"); break; case GE: if (l->n_type == FLOAT) expand(p, 0, "\tc.lt.s AL,AR\n"); else expand(p, 0, "\tc.lt.d AL,AR\n"); expand(p, 0, "\tnop\n\tbc1f LC\n"); break; case LE: if (l->n_type == FLOAT) expand(p, 0, "\tc.le.s AL,AR\n"); else expand(p, 0, "\tc.le.d AL,AR\n"); expand(p, 0, "\tnop\n\tbc1t LC\n"); break; case GT: if (l->n_type == FLOAT) expand(p, 0, "\tc.le.s AL,AR\n"); else expand(p, 0, "\tc.le.d AL,AR\n"); expand(p, 0, "\tnop\n\tbc1f LC\n"); break; } printf("\tnop\n\tnop\n"); } void zzzcode(NODE * p, int c) { int sz; switch (c) { case 'C': /* remove arguments from stack after subroutine call */ sz = p->n_qual > 32 ? p->n_qual : 32; printf("\tdaddiu %s,%s,%d\n", rnames[SP], rnames[SP], sz); break; case 'D': /* long long comparison */ twollcomp(p); break; case 'E': /* emit emulated ops */ emulop(p); break; case 'F': /* emit emulate floating point ops */ fpemulop(p); break; case 'G': /* emit hardware floating-point compare op */ fpcmpops(p); break; case 'H': /* structure argument */ starg(p); break; case 'I': /* high part of init constant */ if (p->n_name[0] != '\0') comperr("named highword"); printf(CONFMT, (getlval(p) >> 32) & 0xffffffff); break; case 'O': /* 64-bit left and right shift operators */ shiftop(p); break; case 'Q': /* emit struct assign */ stasg(p); break; default: comperr("zzzcode %c", c); } } /* ARGSUSED */ int rewfld(NODE * p) { return (1); } int fldexpand(NODE *p, int cookie, char **cp) { CONSZ val; if (p->n_op == ASSIGN) p = p->n_left; switch (**cp) { case 'S': printf("%d", UPKFSZ(p->n_rval)); break; case 'H': printf("%d", UPKFOFF(p->n_rval)); break; case 'M': case 'N': val = (CONSZ)1 << UPKFSZ(p->n_rval); --val; val <<= UPKFOFF(p->n_rval); printf("0x%llx", (**cp == 'M' ? val : ~val) & 0xffffffff); break; default: comperr("fldexpand"); } return 1; } /* * Does the bitfield shape match? */ int flshape(NODE * p) { int o = p->n_op; if (o == OREG || o == REG || o == NAME) return SRDIR; /* Direct match */ if (o == UMUL && shumul(p->n_left, SOREG)) return SROREG; /* Convert into oreg */ return SRREG; /* put it into a register */ } /* INTEMP shapes must not contain any temporary registers */ /* XXX should this go away now? */ int shtemp(NODE * p) { return 0; #if 0 int r; if (p->n_op == STARG) p = p->n_left; switch (p->n_op) { case REG: return (!istreg(p->n_rval)); case OREG: r = p->n_rval; if (R2TEST(r)) { if (istreg(R2UPK1(r))) return (0); r = R2UPK2(r); } return (!istreg(r)); case UMUL: p = p->n_left; return (p->n_op != UMUL && shtemp(p)); } if (optype(p->n_op) != LTYPE) return (0); return (1); #endif } void adrcon(CONSZ val) { printf(CONFMT, val); } void conput(FILE *fp, NODE *p) { int val = getlval(p); switch (p->n_op) { case ICON: if (p->n_name[0] != '\0') { fprintf(fp, "%s", p->n_name); if (getlval(p)) fprintf(fp, "+%d", val); } else fprintf(fp, "%d", val); return; default: comperr("illegal conput"); } } /* ARGSUSED */ void insput(NODE * p) { comperr("insput"); } /* * Print lower or upper name of 64-bit register. */ static void print_reg64name(FILE *fp, int rval, int hi) { int off = 8 * (hi != 0); char *regname = rnames[rval]; fprintf(fp, "%c%c", regname[off], regname[off + 1]); if (regname[off + 2] != '!') fputc(regname[off + 2], fp); if (regname[off + 3] != '!') fputc(regname[off + 3], fp); } /* * Write out the upper address, like the upper register of a 2-register * reference, or the next memory location. */ void upput(NODE * p, int size) { size /= SZCHAR; switch (p->n_op) { case REG: if (GCLASS(p->n_rval) == CLASSB || GCLASS(p->n_rval) == CLASSC) print_reg64name(stdout, p->n_rval, 1); else printf("%s", rnames[p->n_rval]); break; case NAME: case OREG: setlval(p, getlval(p) + size); adrput(stdout, p); setlval(p, getlval(p) - size); break; case ICON: printf(CONFMT, getlval(p) >> 32); break; default: comperr("upput bad op %d size %d", p->n_op, size); } } void adrput(FILE * io, NODE * p) { /* output an address, with offsets, from p */ if (p->n_op == FLD) p = p->n_left; switch (p->n_op) { case NAME: if (p->n_name[0] != '\0') fputs(p->n_name, io); if (getlval(p) != 0) fprintf(io, "+" CONFMT, getlval(p)); return; case OREG: if (getlval(p)) fprintf(io, "%d", (int) getlval(p)); fprintf(io, "(%s)", rnames[p->n_rval]); return; case ICON: /* addressable value of the constant */ conput(io, p); return; case REG: if (GCLASS(p->n_rval) == CLASSB || GCLASS(p->n_rval) == CLASSC) print_reg64name(io, p->n_rval, 0); else fputs(rnames[p->n_rval], io); return; default: comperr("illegal address, op %d, node %p", p->n_op, p); return; } } /* printf conditional and unconditional branches */ void cbgen(int o, int lab) { } void myreader(struct interpass * ipole) { } #if 0 /* * Calculate the stack size for arguments */ static int stacksize; static void calcstacksize(NODE *p, void *arg) { int sz; printf("op=%d\n", p->n_op); if (p->n_op != CALL && p->n_op != STCALL) return; sz = argsiz(p->n_right); if (sz > stacksize) stacksize = sz; #ifdef PCC_DEBUG if (x2debug) printf("stacksize: %d\n", stacksize); #endif } #endif /* * If we're big endian, then all OREG loads of a type * larger than the destination, must have the * offset changed to point to the correct bytes in memory. */ static void offchg(NODE *p, void *arg) { NODE *l; if (p->n_op != SCONV) return; l = p->n_left; if (l->n_op != OREG) return; switch (l->n_type) { case SHORT: case USHORT: if (DEUNSIGN(p->n_type) == CHAR) setlval(l, getlval(l) + 1); break; case INT: case UNSIGNED: if (DEUNSIGN(p->n_type) == CHAR) setlval(l, getlval(l + 3)); else if (DEUNSIGN(p->n_type) == SHORT) setlval(l, getlval(l + 2)); break; case LONG: case ULONG: case LONGLONG: case ULONGLONG: if (DEUNSIGN(p->n_type) == CHAR) setlval(l, getlval(l + 7)); else if (DEUNSIGN(p->n_type) == SHORT) setlval(l, getlval(l + 6)); else if (DEUNSIGN(p->n_type) == INT) setlval(l, getlval(l + 4)); break; default: comperr("offchg: unknown type"); break; } } /* * Remove some PCONVs after OREGs are created. */ static void pconv2(NODE * p, void *arg) { NODE *q; if (p->n_op == PLUS) { if (p->n_type == (PTR | SHORT) || p->n_type == (PTR | USHORT)) { if (p->n_right->n_op != ICON) return; if (p->n_left->n_op != PCONV) return; if (p->n_left->n_left->n_op != OREG) return; q = p->n_left->n_left; nfree(p->n_left); p->n_left = q; /* * This will be converted to another OREG later. */ } } } void mycanon(NODE * p) { walkf(p, pconv2, 0); } void myoptim(struct interpass * ipole) { struct interpass *ip; #ifdef PCC_DEBUG if (x2debug) printf("myoptim:\n"); #endif #if 0 stacksize = 0; #endif DLIST_FOREACH(ip, ipole, qelem) { if (ip->type != IP_NODE) continue; if (bigendian) walkf(ip->ip_node, offchg, 0); #if 0 walkf(ip->ip_node, calcstacksize, 0); #endif } } /* * Move data between registers. While basic registers aren't a problem, * we have to handle the special case of overlapping composite registers. */ void rmove(int s, int d, TWORD t) { switch (t) { case LONG: case ULONG: case LONGLONG: case ULONGLONG: if (s == d+1) { /* dh = sl, copy low word first */ printf("\tmove "); print_reg64name(stdout, d, 0); printf(","); print_reg64name(stdout, s, 0); printf("\t# 64-bit rmove\n"); printf("\tmove "); print_reg64name(stdout, d, 1); printf(","); print_reg64name(stdout, s, 1); printf("\n"); } else { /* copy high word first */ printf("\tmove "); print_reg64name(stdout, d, 1); printf(","); print_reg64name(stdout, s, 1); printf(" # 64-bit rmove\n"); printf("\tmove "); print_reg64name(stdout, d, 0); printf(","); print_reg64name(stdout, s, 0); printf("\n"); } break; case FLOAT: case DOUBLE: case LDOUBLE: if (t == FLOAT) printf("\tmov.s "); else printf("\tmov.d "); print_reg64name(stdout, d, 0); printf(","); print_reg64name(stdout, s, 0); printf("\t# float/double rmove\n"); break; default: printf("\tmove %s,%s\t# default rmove\n", rnames[d], rnames[s]); } } /* * For class c, find worst-case displacement of the number of * registers in the array r[] indexed by class. * * On MIPS64, we have: * * 32 64-bit registers (8 reserved) * 26 64-bit pseudo registers (1 unavailable) * 32 floating-point registers */ int COLORMAP(int c, int *r) { int num = 0; switch (c) { case CLASSA: num += r[CLASSA]; num += 2*r[CLASSB]; return num < 24; case CLASSB: num += 2*r[CLASSB]; num += r[CLASSA]; return num < 25; case CLASSC: num += r[CLASSC]; return num < 6; } comperr("COLORMAP"); return 0; /* XXX gcc */ } /* * Return a class suitable for a specific type. */ int gclass(TWORD t) { if (t == LONG || t == ULONG || t == LONGLONG || t == ULONGLONG) return CLASSB; if (t >= FLOAT && t <= LDOUBLE) return CLASSC; return CLASSA; } /* * Calculate argument sizes. */ void lastcall(NODE *p) { int sz; #ifdef PCC_DEBUG if (x2debug) printf("lastcall:\n"); #endif p->n_qual = 0; if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) return; sz = argsiz(p->n_right); if ((sz > 8*nargregs) && (sz & 7) != 0) { printf("\tdsubu %s,%s,8\t# align stack\n", rnames[SP], rnames[SP]); sz += 8; assert((sz & 7) == 0); } p->n_qual = sz; /* XXX */ } static int argsiz(NODE *p) { TWORD t; int size = 0; int sz = 0; if (p->n_op == CM) { size = argsiz(p->n_left); p = p->n_right; } t = p->n_type; if (t < LONGLONG || t > BTMASK) sz = 4; else if (DEUNSIGN(t) == LONG || DEUNSIGN(t) == LONGLONG) sz = 8; else if (t == DOUBLE || t == LDOUBLE) sz = 8; else if (t == FLOAT) sz = 4; else if (t == STRTY || t == UNIONTY) sz = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0); if (p->n_type == STRTY || p->n_type == UNIONTY) { return (size + sz); } /* alignment */ if (sz == 8 && (size & 7) != 0) sz += 8; // printf("size=%d, sz=%d -> %d\n", size, sz, size + sz); return (size + sz); } /* * Special shapes. */ int special(NODE *p, int shape) { int o = p->n_op; if (o != ICON || p->n_name[0] != 0) return SRNOPE; switch(shape) { case SPCON: if ((getlval(p) & ~0xffff) == 0) return SRDIR; break; } return SRNOPE; } /* * Target-dependent command-line options. */ void mflags(char *str) { if (strcasecmp(str, "big-endian") == 0) { bigendian = 1; } else if (strcasecmp(str, "little-endian") == 0) { bigendian = 0; } else { fprintf(stderr, "unknown m option '%s'\n", str); exit(1); } #if 0 else if (strcasecmp(str, "ips2")) { } else if (strcasecmp(str, "ips2")) { } else if (strcasecmp(str, "ips3")) { } else if (strcasecmp(str, "ips4")) { } else if (strcasecmp(str, "hard-float")) { } else if (strcasecmp(str, "soft-float")) { } else if (strcasecmp(str, "abi=32")) { nargregs = MIPS_O32_NARGREGS; } else if (strcasecmp(str, "abi=n32")) { nargregs = MIPS_N32_NARGREGS; } else if (strcasecmp(str, "abi=64")) { nargregs = MIPS_N64_NARGREGS; } #endif } /* * Do something target-dependent for xasm arguments. * Supposed to find target-specific constraints and rewrite them. */ int myxasm(struct interpass *ip, NODE *p) { return 0; } pcc-20181216/arch/mips64/macdefs.h010064400017500000000000000234161340103772300153040ustar raggewheel/* $Id: macdefs.h,v 1.2 2018/12/02 20:25:55 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and * Simon Olsson (simols-1@student.ltu.se) 2005. * * Extended to MIPS64 by Brian Callahan 2016. */ /* * Machine-dependent defines for both passes. */ #if defined(os_netbsd) || defined(os_litebsd) || defined(os_openbsd) #define USE_GAS #endif /* * Convert (multi-)character constant to integer. * Assume: If only one value; store at left side (char size), otherwise * treat it as an integer. */ #define makecc(val,i) lastcon = (lastcon<<8)|((val<<24)>>24); #define ARGINIT (32*8) /* # bits above fp where arguments start */ #define AUTOINIT (0) /* # bits below fp where automatics start */ /* * Storage space requirements */ #define SZCHAR 8 #define SZBOOL 32 #define SZINT 32 #define SZFLOAT 32 #define SZDOUBLE 64 #define SZLDOUBLE 64 #define SZLONG 64 #define SZSHORT 16 #define SZLONGLONG 64 #define SZPOINT(t) 64 /* * Alignment constraints */ #define ALCHAR 8 #define ALBOOL 64 #define ALINT 64 #define ALFLOAT 32 #define ALDOUBLE 64 #define ALLDOUBLE 64 #define ALLONG 64 #define ALLONGLONG 64 #define ALSHORT 16 #define ALPOINT 64 #define ALSTRUCT 64 #define ALSTACK 64 /* * Min/max values. */ #define MIN_CHAR -128 #define MAX_CHAR 127 #define MAX_UCHAR 255 #define MIN_SHORT -32768 #define MAX_SHORT 32767 #define MAX_USHORT 65535 #define MIN_INT (-0x7fffffff-1) #define MAX_INT 0x7fffffff #define MAX_UNSIGNED 0xffffffffU #define MIN_LONG MIN_LONGLONG #define MAX_LONG MAX_LONGLONG #define MAX_ULONG MAX_ULONGLONG #define MIN_LONGLONG (-0x7fffffffffffffffLL-1) #define MAX_LONGLONG 0x7fffffffffffffffLL #define MAX_ULONGLONG 0xffffffffffffffffULL #undef CHAR_UNSIGNED #define BOOL_TYPE INT /* * Use large-enough types. */ typedef long long CONSZ; typedef unsigned long long U_CONSZ; typedef long long OFFSZ; #define CONFMT "%lld" /* format for printing constants */ #ifdef USE_GAS #define LABFMT "$L%d" /* format for printing labels */ #define STABLBL "$LL%d" /* format for stab (debugging) labels */ #else #define LABFMT "L%d" /* format for printing labels */ #define STABLBL "LL%d" /* format for stab (debugging) labels */ #endif #define BACKAUTO /* stack grows negatively for automatics */ #define BACKTEMP /* stack grows negatively for temporaries */ #undef FIELDOPS /* no bit-field instructions */ #define TARGET_ENDIAN TARGET_LE #define MYALIGN /* Definitions mostly used in pass2 */ #define BYTEOFF(x) ((x)&03) #define szty(t) (((t) == DOUBLE || (t) == LDOUBLE || \ DEUNSIGN(t) == LONG || DEUNSIGN(t) == LONGLONG) ? 2 : 1) /* * Register names. These must match rnames[] and rstatus[] in local2.c. */ #define ZERO 0 #define AT 1 #define V0 2 #define V1 3 #define A0 4 #define A1 5 #define A2 6 #define A3 7 #define A4 8 #define A5 9 #define A6 10 #define A7 11 #define T4 12 #define T5 13 #define T6 14 #define T7 15 #define S0 16 #define S1 17 #define S2 18 #define S3 19 #define S4 20 #define S5 21 #define S6 22 #define S7 23 #define T8 24 #define T9 25 #define K0 26 #define K1 27 #define GP 28 #define SP 29 #define FP 30 #define RA 31 #define V0V1 32 #define A0A1 33 #define A1A2 34 #define A2A3 35 /* we just use o32 naming here, but it works ok for n32/n64 */ #define A3T0 36 #define T0T1 37 #define T1T2 38 #define T2T3 39 #define T3T4 40 #define T4T5 41 #define T5T6 42 #define T6T7 43 #define T7T8 44 #define T8T9 45 #define S0S1 46 #define S1S2 47 #define S2S3 48 #define S3S4 49 #define S4S5 50 #define S5S6 51 #define S6S7 52 #define F0 53 #define F2 54 #define F4 55 #define F6 56 #define F8 57 #define F10 58 #define F12 59 #define F14 60 #define F16 61 #define F18 62 #define F20 63 /* and the rest for later */ #define F22 64 #define F24 65 #define F26 66 #define F28 67 #define F30 68 #define MAXREGS 64 #define NUMCLASS 3 #define RETREG(x) ((DEUNSIGN(x) == LONG || DEUNSIGN(x) == LONGLONG) ? V0V1 : \ (x) == DOUBLE || (x) == LDOUBLE || (x) == FLOAT ? \ F0 : V0) #define FPREG FP /* frame pointer */ #define MIPS_N64_NARGREGS 8 #define RSTATUS \ 0, 0, \ SAREG|TEMPREG, SAREG|TEMPREG, \ SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \ SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \ SAREG|TEMPREG, SAREG|TEMPREG, \ 0, 0, \ 0, 0, 0, 0, \ \ SBREG|TEMPREG, \ SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, \ SBREG|TEMPREG, \ SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, \ SBREG|TEMPREG, SBREG|TEMPREG, \ SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, \ SBREG, SBREG, SBREG, SBREG, \ SBREG, SBREG, SBREG, \ SCREG, SCREG, SCREG, SCREG, \ SCREG, SCREG, SCREG, SCREG, \ SCREG, SCREG, SCREG, \ #define ROVERLAP \ { -1 }, /* $zero */ \ { -1 }, /* $at */ \ { V0V1, -1 }, /* $v0 */ \ { V0V1, -1 }, /* $v1 */ \ { A0A1, -1 }, /* $a0 */ \ { A0A1, A1A2, -1 }, /* $a1 */ \ { A1A2, A2A3, -1 }, /* $a2 */ \ { A2A3, A3T0, -1 }, /* $a3 */ \ { A3T0, T0T1, -1 }, /* $a4 */ \ { T0T1, T1T2, -1 }, /* $a5 */ \ { T1T2, T2T3, -1 }, /* $a6 */ \ { T2T3, T3T4, -1 }, /* $a7 */ \ { T3T4, T4T5, -1 }, /* $t4 */ \ { T4T5, T5T6, -1 }, /* $t5 */ \ { T6T7, T7T8, -1 }, /* $t6 */ \ { T7T8, T8T9, -1 }, /* $t7 */ \ \ { S0S1, -1 }, /* $s0 */ \ { S0S1, S1S2, -1 }, /* $s1 */ \ { S1S2, S2S3, -1 }, /* $s2 */ \ { S2S3, S3S4, -1 }, /* $s3 */ \ { S3S4, S4S5, -1 }, /* $s4 */ \ { S4S5, S5S6, -1 }, /* $s5 */ \ { S5S6, S6S7, -1 }, /* $s6 */ \ { S6S7, -1 }, /* $s7 */ \ \ { T7T8, T8T9, -1 }, /* $t8 */ \ { T8T9, -1 }, /* $t9 */ \ \ { -1 }, /* $k0 */ \ { -1 }, /* $k1 */ \ { -1 }, /* $gp */ \ { -1 }, /* $sp */ \ { -1 }, /* $fp */ \ { -1 }, /* $ra */ \ \ { V0, V1, -1 }, /* $v0:$v1 */ \ \ { A0, A1, A1A2, -1 }, /* $a0:$a1 */ \ { A1, A2, A0A1, A2A3, -1 }, /* $a1:$a2 */ \ { A2, A3, A1A2, A3T0, -1 }, /* $a2:$a3 */ \ { A3, A4, A2A3, T0T1, -1 }, /* $a3:$t0 */ \ { A4, A5, A3T0, T1T2, -1 }, /* $t0:$t1 */ \ { A5, A6, T0T1, T2T3, -1 }, /* $t1:$t2 */ \ { A6, A7, T1T2, T3T4, -1 }, /* $t2:$t3 */ \ { A7, T4, T2T3, T4T5, -1 }, /* $t3:$t4 */ \ { T4, T5, T3T4, T5T6, -1 }, /* $t4:$t5 */ \ { T5, T6, T4T5, T6T7, -1 }, /* $t5:$t6 */ \ { T6, T7, T5T6, T7T8, -1 }, /* $t6:$t7 */ \ { T7, T8, T6T7, T8T9, -1 }, /* $t7:$t8 */ \ { T8, T9, T7T8, -1 }, /* $t8:$t9 */ \ \ { S0, S1, S1S2, -1 }, /* $s0:$s1 */ \ { S1, S2, S0S1, S2S3, -1 }, \ { S2, S3, S1S2, S3S4, -1 }, \ { S3, S4, S2S3, S4S5, -1 }, \ { S4, S5, S3S4, S5S6, -1 }, \ { S5, S6, S4S5, S6S7, -1 }, \ { S6, S7, S5S6, -1 }, \ \ { -1 }, { -1 }, { -1 }, { -1 }, \ { -1 }, { -1 }, { -1 }, { -1 }, \ { -1 }, { -1 }, { -1 }, \ #define GCLASS(x) (x < 32 ? CLASSA : (x < 52 ? CLASSB : CLASSC)) #define PCLASS(p) (1 << gclass((p)->n_type)) #define DECRA(x,y) (((x) >> (y*6)) & 63) /* decode encoded regs */ #define ENCRA(x,y) ((x) << (6+y*6)) /* encode regs in int */ #define ENCRD(x) (x) /* Encode dest reg in n_reg */ int COLORMAP(int c, int *r); extern int bigendian; extern int nargregs; #define SPCON (MAXSPECIAL+1) /* positive constant */ #define TARGET_STDARGS #define TARGET_BUILTINS \ { "__builtin_stdarg_start", mips64_builtin_stdarg_start, \ 0, 2, 0, VOID }, \ { "__builtin_va_start", mips64_builtin_stdarg_start, \ 0, 2, 0, VOID }, \ { "__builtin_va_arg", mips64_builtin_va_arg, BTNORVAL|BTNOPROTO, \ 2, 0, 0 }, \ { "__builtin_va_end", mips64_builtin_va_end, 0, 1, 0, VOID }, \ { "__builtin_va_copy", mips64_builtin_va_copy, 0, 2, 0, VOID }, #ifdef LANG_CXX #define P1ND struct node #else #define P1ND struct p1node #endif struct node; struct bitable; P1ND *mips64_builtin_stdarg_start(const struct bitable *, P1ND *a); P1ND *mips64_builtin_va_arg(const struct bitable *, P1ND *a); P1ND *mips64_builtin_va_end(const struct bitable *, P1ND *a); P1ND *mips64_builtin_va_copy(const struct bitable *, P1ND *a); #undef P1ND /* floating point definitions */ #define USE_IEEEFP_32 #define FLT_PREFIX IEEEFP_32 #define USE_IEEEFP_64 #define DBL_PREFIX IEEEFP_64 #define LDBL_PREFIX IEEEFP_64 pcc-20181216/arch/mips64/order.c010064400017500000000000000135021273713403400150070ustar raggewheel/* $Id: order.c,v 1.1 2016/07/06 07:49:48 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and * Simon Olsson (simols-1@student.ltu.se) 2005. * * Extended to MIPS64 by Brian Callahan 2016. */ #include "pass2.h" /* * is it legal to make an OREG or NAME entry which has an offset of off, * (from a register of r), if the resulting thing had type t */ int notoff(TWORD t, int r, CONSZ off, char *cp) { /* * although the hardware doesn't permit offsets greater * than +/- 32K, the assembler fixes it for us. */ return 0; /* YES */ } /* * Turn a UMUL-referenced node into OREG. */ void offstar(NODE * p, int shape) { if (x2debug) printf("offstar(%p)\n", p); if (p->n_op == PLUS || p->n_op == MINUS) { if (p->n_right->n_op == ICON) { if (isreg(p->n_left) == 0) (void)geninsn(p->n_left, INAREG); /* Converted in ormake() */ return; } } (void)geninsn(p, INAREG); } /* * Do the actual conversion of offstar-found OREGs into real OREGs. */ void myormake(NODE * q) { if (x2debug) printf("myormake(%p)\n", q); } /* * Shape matches for UMUL. Cooperates with offstar(). */ int shumul(NODE *p, int shape) { if (x2debug) printf("shumul(%p)\n", p); /* Always turn it into OREG */ if (shape & SOREG) return SROREG; return SRNOPE; } /* * Rewrite operations on binary operators (like +, -, etc...). * Called as a result of table lookup. */ int setbin(NODE * p) { if (x2debug) printf("setbin(%p)\n", p); return 0; } /* setup for assignment operator */ int setasg(NODE * p, int cookie) { if (x2debug) printf("setasg(%p)\n", p); return (0); } /* setup for unary operator */ int setuni(NODE * p, int cookie) { return 0; } /* * Special handling of some instruction register allocation. * - left is the register that left node wants. * - right is the register that right node wants. * - res is in which register the result will end up. * - mask is registers that will be clobbered. */ struct rspecial * nspecial(struct optab * q) { switch (q->op) { case SCONV: if (q->lshape == SBREG && q->rshape == SCREG) { static struct rspecial s[] = { { NLEFT, A0A1 }, { NRES, F0 }, { 0 } }; return s; } else if (q->lshape == SCREG && q->rshape == SBREG) { static struct rspecial s[] = { { NLEFT, F0 }, { NRES, A0A1 }, { 0 } }; return s; } else if (q->lshape == SAREG && q->rshape == SCREG) { static struct rspecial s[] = { { NLEFT, A0 }, { NRES, F0 }, { 0 } }; return s; } break; case MOD: case DIV: if (q->lshape == SBREG) { static struct rspecial s[] = { { NLEFT, A0A1 }, { NRIGHT, A2A3 }, { NRES, V0V1 }, { 0 }, }; return s; } else if (q->lshape == SAREG) { static struct rspecial s[] = { { NLEFT, A0 }, { NRIGHT, A1 }, { NRES, V0 }, { 0 }, }; return s; } case RS: case LS: if (q->lshape == SBREG) { static struct rspecial s[] = { { NLEFT, A0A1 }, { NRIGHT, A2 }, { NRES, V0V1 }, { 0 }, }; return s; } else if (q->lshape == SAREG) { static struct rspecial s[] = { { NLEFT, A0 }, { NRIGHT, A1 }, { NRES, V0 }, { 0 }, }; return s; } break; case STARG: { static struct rspecial s[] = { { NEVER, A0 }, { NLEFT, A1 }, { NEVER, A2 }, { 0 } }; return s; } case STASG: { static struct rspecial s[] = { { NEVER, A0 }, { NRIGHT, A1 }, { NEVER, A2 }, { 0 } }; return s; } } comperr("nspecial entry %d: %s", q - table, q->cstring); return 0; /* XXX gcc */ } /* * Set evaluation order of a binary node if it differs from default. */ int setorder(NODE * p) { return 0; /* nothing differs */ } /* * Set registers "live" at function calls (like arguments in registers). * This is for liveness analysis of registers. */ int * livecall(NODE *p) { static int r[1] = { -1 }; /* Terminate with -1 */ return &r[0]; } /* * Signal whether the instruction is acceptable for this target. */ int acceptable(struct optab *op) { return 1; } pcc-20181216/arch/mips64/table.c010064400017500000000000000706511273713403400147730ustar raggewheel/* $Id: table.c,v 1.1 2016/07/06 07:49:48 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * MIPS port by Jan Enoksson (janeno-1@student.ltu.se) and * Simon Olsson (simols-1@student.ltu.se) 2005. * * Extended to MIPS64 by Brian Callahan 2016. * * It appears that the target machine was big endian. The original * code contained many endian aspects which are now handled in * machine-independent code. * * On MIPS, the assembler does an amazing amount of work for us. * We don't have to worry about PIC, nor about finding the address * of SNAMES. Whenever possible, we defer the work to the assembler. */ #include "pass2.h" #define TUWORD TUNSIGNED|TULONG #define TSWORD TINT|TLONG #define TWORD TUWORD|TSWORD struct optab table[] = { /* First entry must be an empty entry */ { -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", }, /* PCONVs are usually not necessary */ { PCONV, INAREG, SAREG, TWORD|TPOINT, SAREG, TWORD|TPOINT, 0, RLEFT, " # convert between word and pointer", }, /* * Conversions of integral types (register-register) * * For each deunsigned type, they look something like this: * * signed -> bigger signed - nothing to do * unsigned -> bigger - nothing to do * * signed -> bigger unsigned - clear the top bits (of source type) * signed -> smaller signed - sign-extend the bits (to dest type) * signed -> smaller unsigned - clear the top bits (of dest type) * unsigned -> smaller signed - sign-extend top bits (to dest type) * unsigned -> smaller unsigned - clear the top bits (of dest type) * */ /* convert between int and ptr */ { SCONV, INAREG, SAREG, TPOINT|TWORD, SAREG, TWORD|TPOINT, 0, RLEFT, "", }, /* convert between LL and uLL */ { SCONV, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TULONGLONG|TLONGLONG, 0, RLEFT, "", }, /* (u)char to (u)char/(u)short/(u)int */ { SCONV, INAREG, SAREG, TCHAR|TUCHAR, SAREG, TCHAR|TUCHAR|TWORD|TSHORT|TUSHORT, 0, RLEFT, "", }, /* (u)short to (u)int */ { SCONV, INAREG, SAREG, TSHORT|TUSHORT, SAREG, TWORD|TSHORT|TUSHORT, 0, RLEFT, "", }, /* (u)int to (u)int */ { SCONV, INAREG, SAREG, TWORD, SAREG, TWORD, 0, RLEFT, "", }, /* (u)int/(u)short to char */ { SCONV, INAREG, SAREG, TWORD|TSHORT|TUSHORT, SAREG, TCHAR, NAREG|NASL, RESC1, " dsll A1,AL,24\n" " dsra A1,A1,24\n", }, /* (u)int/(u)short to uchar */ { SCONV, INAREG, SAREG, TWORD|TSHORT|TUSHORT, SAREG, TUCHAR, NAREG|NASL, RESC1, " andi A1,AL,255\n", }, /* (u)int to short */ { SCONV, INAREG, SAREG, TWORD, SAREG, TSHORT, NAREG|NASL, RESC1, " dsll A1,AL,16\n" " dsra A1,A1,16\n", }, /* (u)int to ushort */ { SCONV, INAREG, SAREG, TWORD, SAREG, TUSHORT, NAREG|NASL, RESC1, " andi A1,AL,65535\n", }, /* longlong casts below */ { SCONV, INBREG, SAREG, TSWORD|TSHORT|TCHAR, SBREG, TLONGLONG, NBREG, RESC1, " move A1,AL # convert int/short/char to longlong\n" " dsra U1,AL,31\n", }, { SCONV, INBREG, SAREG, TSWORD|TSHORT|TCHAR, SBREG, TULONGLONG, NBREG, RESC1, " move A1,AL # convert int/short/char to ulonglong\n", }, { SCONV, INBREG, SAREG, TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR, SBREG, TLONGLONG|TULONGLONG, NBREG, RESC1, " move A1,AL # convert (u)int/(u)short/(u)char to ulonglong\n", }, { SCONV, INAREG, SBREG, TLONGLONG|TULONGLONG, SAREG, TWORD, NAREG, RESC1, " move A1,AL # convert (u)longlong to int\n", }, { SCONV, INAREG, SBREG, TLONGLONG|TULONGLONG, SAREG, TSHORT, NAREG, RESC1, " dsll A1,AL,16 # convert (u)longlong to short\n" " dsra A1,A1,16\n", }, { SCONV, INAREG, SBREG, TLONGLONG|TULONGLONG, SAREG, TCHAR, NAREG, RESC1, " dsll A1,AL,24 # convert (u)longlong to char\n" " dsra A1,A1,24\n", }, { SCONV, INAREG, SBREG, TLONGLONG|TULONGLONG, SAREG, TUSHORT, NAREG, RESC1, " andi A1,AL,65535 # convert (u)longlong to ushort\n", }, { SCONV, INAREG, SBREG, TLONGLONG|TULONGLONG, SAREG, TUCHAR, NAREG, RESC1, " andi A1,AL,255 # convert (u)longlong to uchar\n", }, { SCONV, INCREG, SCREG, TFLOAT, SCREG, TDOUBLE|TLDOUBLE, NCREG, RESC1, " cvt.d.s A1,AL # convert float to (l)double\n", }, { SCONV, INCREG, SCREG, TDOUBLE|TLDOUBLE, SCREG, TFLOAT, NCREG, RESC1, " cvt.s.d A1,AL # convert (l)double to float\n", }, { SCONV, INCREG, SAREG, TWORD, SCREG, TFLOAT, NCREG, RESC1, " dmtc1 AL,A1 # convert (u)int to float\n" " nop\n" " cvt.s.w A1,A1\n", }, { SCONV, INCREG, SOREG, TWORD, SCREG, TFLOAT, NCREG, RESC1, " l.s A1,AL # convert (u)int to float\n" " nop\n" " cvt.s.w A1,A1\n", }, { SCONV, INCREG, SAREG, TWORD, SCREG, TDOUBLE|TLDOUBLE, NCREG, RESC1, " dmtc1 AL,A1 # convert (u)int to (l)double\n" " nop\n" " cvt.d.w A1,A1\n", }, { SCONV, INCREG, SOREG, TWORD, SCREG, TDOUBLE|TLDOUBLE, NCREG, RESC1, " l.d A1,AL # convert (u)int to (l)double\n" " nop\n" " cvt.d.w A1,A1\n", }, { SCONV, INAREG, SCREG, TFLOAT, SAREG, TWORD, NCREG|NAREG, RESC1, " cvt.w.s A2,AL # convert float to (u)int\n" " dmfc1 A1,A2\n" " nop\n", }, { SCONV, FOREFF, SCREG, TFLOAT, SOREG, TWORD, NCREG, RDEST, " cvt.w.s A1,AL # convert float to (u)int\n" " s.s A1,AR\n" " nop\n", }, { SCONV, INAREG, SCREG, TDOUBLE|TLDOUBLE, SAREG, TWORD, NCREG|NAREG, RESC1, " cvt.w.d A2,AL # convert (l)double to (u)int\n" " dmfc1 A1,A2\n" " nop\n", }, { SCONV, INCREG, SCREG, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, 0, RLEFT, " # convert between double and ldouble\n", }, { SCONV, INCREG, SBREG, TLONGLONG|TULONGLONG, SCREG, TFLOAT, NSPECIAL|NCREG, RESC1, "ZF", }, { SCONV, INCREG, SBREG, TLONGLONG|TULONGLONG, SCREG, TDOUBLE|TLDOUBLE, NSPECIAL|NCREG, RESC1, "ZF", }, { SCONV, INBREG, SCREG, TDOUBLE|TLDOUBLE, SBREG, TLONGLONG|TULONGLONG, NSPECIAL|NBREG, RESC1, "ZF", }, { SCONV, INBREG, SCREG, TFLOAT, SBREG, TLONGLONG|TULONGLONG, NSPECIAL|NBREG, RESC1, "ZF", }, /* * Multiplication and division */ { MUL, INAREG, SAREG, TUWORD|TUSHORT|TUCHAR, SAREG, TUWORD|TUSHORT|TUCHAR, NAREG|NASR|NASL, RESC1, " dmultu AL,AR # unsigned multiply\n" " nop\n" " nop\n" " mflo A1\n" }, /* this previous will match on unsigned/unsigned multiplication first */ { MUL, INAREG, SAREG, TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR, SAREG, TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR, NAREG|NASR|NASL, RESC1, " dmult AL,AR # signed multiply\n" " nop\n" " nop\n" " mflo A1\n", }, { MUL, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, 2*NBREG, RESC1, " dmultu AL,AR\n" " mfhi U1\n" " mflo A1\n" " mult AL,UR\n" " mflo A2\n" " nop\n" " nop\n" " daddu A2,U1,A2\n" " dmult UL,AR\n" " mflo U2\n" " nop\n" " nop\n" " daddu U1,A2,U2\n", }, { MUL, INCREG, SCREG, TFLOAT, SCREG, TFLOAT, NCREG, RESC1, " mul.s A1,AL,AR # floating-point multiply\n", }, { MUL, INCREG, SCREG, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, NCREG, RESC1, " mul.d A1,AL,AR # double-floating-point multiply\n", }, { DIV, INAREG, SAREG, TUWORD|TUSHORT|TUCHAR, SAREG, TUWORD|TUSHORT|TUCHAR, NAREG|NASR|NASL, RESC1, " ddivu AL,AR # unsigned division\n" " mflo A1\n" " nop\n" " nop\n", }, /* the previous rule will match unsigned/unsigned first */ { DIV, INAREG, SAREG, TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR, SAREG, TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR, NAREG|NASR|NASL, RESC1, " ddiv AL,AR # signed division\n" " mflo A1\n" " nop\n" " nop\n", }, { DIV, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, NSPECIAL|NBREG, RESC1, "ZE", }, { DIV, INCREG, SCREG, TFLOAT, SCREG, TFLOAT, NCREG, RESC1, " div.s A1,AL,AR # floating-point division\n", }, { DIV, INCREG, SCREG, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, NCREG, RESC1, " div.d A1,AL,AR # double-floating-point division\n", }, { MOD, INAREG, SAREG, TUWORD|TUSHORT|TUCHAR, SAREG, TUWORD|TUSHORT|TUCHAR, NAREG, RESC1, " ddivu AL,AR # signed modulo\n" " mfhi A1\n" " nop\n" " nop\n", }, /* the previous rule will match unsigned%unsigned first */ { MOD, INAREG, SAREG, TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR, SAREG, TWORD|TUSHORT|TSHORT|TUCHAR|TCHAR, NAREG, RESC1, " ddiv AL,AR # signed modulo\n" " mfhi A1\n" " nop\n" " nop\n", }, { MOD, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, NSPECIAL|NBREG, RESC1, "ZE", }, /* * Templates for unsigned values needs to come before OPSIMP */ { PLUS, INBREG, SBREG, TULONGLONG|TLONGLONG, SBREG, TULONGLONG|TLONGLONG, 2*NBREG, RESC1, " daddu A1,AL,AR # 64-bit addition\n" " sltu A2,A1,AR\n" " daddu U1,UL,UR\n" " daddu U1,U1,A2\n", }, { PLUS, INAREG, SAREG, TSWORD|TSHORT|TCHAR, SSCON, TANY, NAREG|NASL, RESC1, " addi A1,AL,AR\n", }, { PLUS, INAREG, SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, SSCON, TANY, NAREG|NASL, RESC1, " daddiu A1,AL,AR\n", }, { PLUS, INAREG, SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, SAREG, TUWORD|TUSHORT|TUCHAR, NAREG|NASL, RESC1, " daddu A1,AL,AR\n", }, { PLUS, INAREG, SAREG, TSWORD|TSHORT|TCHAR, SAREG, TSWORD|TSHORT|TCHAR, NAREG|NASL, RESC1, " dadd A1,AL,AR\n", }, { PLUS, INCREG, SCREG, TFLOAT, SCREG, TFLOAT, NCREG|NCSL, RESC1, " add.s A1,AL,AR\n", }, { PLUS, INCREG, SCREG, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, NCREG|NCSL, RESC1, " add.d A1,AL,AR\n", }, { MINUS, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, 2*NBREG, RESC1, " sltu A2,AL,AR # 64-bit subtraction\n" " dsubu A1,AL,AR\n" " dsubu U1,UL,UR\n" " dsubu U1,U1,A2\n", }, { MINUS, INAREG, SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, SSCON, TANY, NAREG|NASL, RESC1, " dsubu A1,AL,AR\n", }, { MINUS, INAREG, SAREG, TSWORD|TSHORT|TCHAR, SSCON, TANY, NAREG|NASL, RESC1, " dsub A1,AL,AR\n", }, { MINUS, INAREG, SAREG, TSWORD|TSHORT|TCHAR, SAREG, TSWORD|TSHORT|TCHAR, NAREG|NASL, RESC1, " dsub A1,AL,AR\n", }, { MINUS, INCREG, SCREG, TFLOAT, SCREG, TFLOAT, NCREG|NCSL, RESC1, " sub.s A1,AL,AR\n", }, { MINUS, INCREG, SCREG, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, NCREG|NCSL, RESC1, " sub.d A1,AL,AR\n", }, { UMINUS, INAREG, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SANY, TANY, NAREG|NASL, RESC1, " neg A1,AL\n", }, { UMINUS, INBREG, SBREG, TLONGLONG|TULONGLONG, SANY, TANY, NBREG|NAREG|NBSL, RESC2, " dsubu A1,$zero,AL\n" " dsubu U1,$zero,UL\n" " sltu A2,$zero,A1\n" " dsubu U1,U1,A2\n", }, { UMINUS, INCREG, SCREG, TFLOAT, SCREG, TFLOAT, NCREG|NCSL, RESC1, " neg.s A1,AL\n", }, { UMINUS, INCREG, SCREG, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, NCREG|NCSL, RESC1, " neg.d A1,AL\n", }, /* Simple 'op rd, rs, rt' or 'op rt, rs, imm' operations */ { OPSIMP, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, NBREG|NBSR|NBSL, RESC1, " O A1,AL,AR\n" " O U1,UL,UR\n", }, { OPSIMP, INAREG, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TUCHAR|TCHAR, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TUCHAR|TCHAR, NAREG|NASR|NASL, RESC1, " O A1,AL,AR\n", }, { OPSIMP, INAREG, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TUCHAR|TCHAR, SPCON, TANY, NAREG|NASL, RESC1, " Oi A1,AL,AR\n", }, /* * Shift instructions */ { RS, INAREG, SAREG, TSWORD|TSHORT|TCHAR, SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, " dsra A1,AL,AR # shift right by constant\n", }, { RS, INAREG, SAREG, TUWORD|TUSHORT|TUCHAR, SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, " dsrl A1,AL,AR # shift right by constant\n", }, { LS, INAREG, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, " dsll A1,AL,AR # shift left by constant\n", }, { RS, INAREG, SAREG, TSWORD|TSHORT|TCHAR, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, " dsrav A1,AL,AR # shift right by register\n", }, { RS, INAREG, SAREG, TUWORD|TUSHORT|TUCHAR, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, " dsrlv A1,AL,AR # shift right by register\n", }, { LS, INAREG, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, " dsllv A1,AL,AR # shift left by register\n", }, { RS, INBREG, SBREG, TLONGLONG|TULONGLONG, SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NBREG, RESC1, "ZO", }, { LS, INBREG, SBREG, TLONGLONG|TULONGLONG, SCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NBREG, RESC1, "ZO", }, { RS, INBREG, SBREG, TLONGLONG|TULONGLONG, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NSPECIAL|NBREG, RESC1, "ZE", }, { LS, INBREG, SBREG, TLONGLONG|TULONGLONG, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NSPECIAL|NBREG, RESC1, "ZE", }, /* * Rule for unary one's complement */ { COMPL, INAREG, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, SANY, TANY, NAREG|NASL, RESC1, " nor A1,$zero,AL # complement\n", }, { COMPL, INBREG, SBREG, TLONGLONG|TULONGLONG, SANY, TANY, NBREG|NBSL, RESC1, " nor A1,$zero,AL # complement\n" " nor U1,$zero,UL\n", }, /* * The next rules takes care of assignments. "=". */ { ASSIGN, FOREFF|INAREG, SOREG|SNAME, TWORD|TPOINT, SAREG, TWORD|TPOINT, 0, RDEST, " sd AR,AL # store (u)int/(u)long\n" " nop\n", }, { ASSIGN, FOREFF|INAREG, SOREG|SNAME, TSHORT|TUSHORT, SAREG, TSHORT|TUSHORT, 0, RDEST, " sh AR,AL # store (u)short\n" " nop\n", }, { ASSIGN, FOREFF|INAREG, SOREG|SNAME, TCHAR|TUCHAR, SAREG, TCHAR|TUCHAR, 0, RDEST, " sb AR,AL # store (u)char\n" " nop\n", }, { ASSIGN, FOREFF|INBREG, SOREG|SNAME, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, 0, RDEST, " sd AR,AL # store (u)longlong\n" " nop\n", }, { ASSIGN, FOREFF|INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, 0, RDEST, " move AL,AR # register move\n", }, { ASSIGN, FOREFF|INAREG, SAREG, TANY, SAREG, TANY, 0, RDEST, " move AL,AR # register move\n", }, { ASSIGN, FOREFF|INCREG, SCREG, TFLOAT, SCREG, TFLOAT, 0, RDEST, " mov.s AL,AR # register move\n", }, { ASSIGN, FOREFF|INCREG, SCREG, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, 0, RDEST, " mov.d AL,AR # register move\n", }, { ASSIGN, FOREFF|INCREG, SNAME|SOREG, TFLOAT, SCREG, TFLOAT, 0, RDEST, " s.s AR,AL # store floating-point reg to oreg/sname\n" " nop\n", }, { ASSIGN, FOREFF|INCREG, SNAME|SOREG, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, 0, RDEST, " s.d AR,AL # store double floating-point reg to oreg/sname\n" " nop\n", }, { ASSIGN, FOREFF|INAREG, SFLD, TANY, SOREG|SNAME, TANY, 3*NAREG, RDEST, " ld A1,AR # bit-field assignment\n" " dli A3,M\n" " ld A2,AL\n" " dsll A1,A1,H\n" " and A1,A1,A3\n" " nor A3,$zero,A3\n" " and A2,A2,A3\n" " or A2,A2,A1\n" " sd A2,AL\n" "F ld AD,AR\n" "F nop\n" "F dsll AD,AD,32-S\n" "F dsra AD,AD,32-S\n", }, /* XXX we can optimise this away */ { ASSIGN, FOREFF|INAREG, SFLD, TANY, SCON, TANY, 3*NAREG, RDEST, " dli A1,AR # bit-field assignment\n" " ld A2,AL\n" " dli A3,M\n" " dsll A1,A1,H\n" " and A1,A1,A3\n" " nor A3,$zero,A3\n" " and A2,A2,A3\n" " or A2,A2,A1\n" " sd A2,AL\n" "F dli AD,AR\n" "F dsll AD,AD,32-S\n" "F dsra AD,AD,32-S\n", }, { ASSIGN, FOREFF|INAREG, SFLD, TANY, SAREG, TANY, 3*NAREG, RDEST, " move A1,AR # bit-field assignment\n" " ld A2,AL\n" " dli A3,M\n" " dsll A1,A1,H\n" " and A1,A1,A3\n" " nor A3,$zero,A3\n" " and A2,A2,A3\n" " or A2,A2,A1\n" " sd A2,AL\n" "F move AR,AD\n" "F dsll AD,AD,32-S\n" "F dsra AD,AD,32-S\n", }, { STASG, INAREG|FOREFF, SOREG|SNAME, TANY, SAREG, TPTRTO|TANY, NSPECIAL, RDEST, "ZQ", }, /* * Compare instructions */ { EQ, FORCC, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, 0, RESCC, " beq AL,AR,LC\n" " nop\n", }, { NE, FORCC, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, 0, RESCC, " bne AL,AR,LC\n" " nop\n", }, { OPLOG, FORCC, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SZERO, TANY, 0, RESCC, " O AL,LC\n" " nop\n", }, { OPLOG, FORCC, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESCC, " dsub A1,AL,AR\n" " O A1,LC\n" " nop\n", }, { OPLOG, FORCC, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SSCON, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESCC, " dsub A1,AL,AR\n" " O A1,LC\n" " nop\n", }, { OPLOG, FORCC, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, NAREG, RESCC, "ZD", }, { OPLOG, FORCC, SCREG, TFLOAT|TDOUBLE|TLDOUBLE, SCREG, TFLOAT|TDOUBLE|TLDOUBLE, 0, RESCC, "ZG", }, /* * Convert LTYPE to reg. */ { OPLTYPE, INAREG, SANY, TANY, SOREG|SNAME, TCHAR, NAREG, RESC1, " lb A1,AL # load char to reg\n" " nop\n", }, { OPLTYPE, INAREG, SANY, TANY, SOREG|SNAME, TUCHAR, NAREG, RESC1, " lbu A1,AL # load uchar to reg\n" " nop\n", }, { OPLTYPE, INAREG, SANY, TANY, SOREG|SNAME, TSHORT, NAREG, RESC1, " lh A1,AL # load short to reg\n" " nop\n", }, { OPLTYPE, INAREG, SANY, TANY, SOREG|SNAME, TUSHORT, NAREG, RESC1, " lhu A1,AL # load ushort to reg\n" " nop\n", }, { OPLTYPE, INAREG, SANY, TANY, SOREG|SNAME, TWORD|TPOINT, NAREG, RESC1, " ld A1,AL # load (u)int/(u)long to reg\n" " nop\n", }, { OPLTYPE, INBREG, SANY, TANY, SOREG|SNAME, TLONGLONG|TULONGLONG, NBREG, RESC1, " ld A1,AL # load (u)longlong to reg\n" " nop\n", }, { OPLTYPE, INAREG, SANY, TANY, SCON, TPOINT, NAREG, RESC1, " dla A1,AL # load constant address to reg\n", }, { OPLTYPE, INAREG, SANY, TANY, SZERO, TANY, NAREG, RESC1, " move A1,$zero # load 0 to reg\n", }, { OPLTYPE, INAREG, SANY, TANY, SCON, TANY, NAREG, RESC1, " dli A1,AL # load constant to reg\n", }, { OPLTYPE, INBREG, SANY, TANY, SZERO, TANY, NBREG, RESC1, " move A1,$zero # load 0 to reg\n", }, { OPLTYPE, INBREG, SANY, TANY, SCON, TANY, NBREG, RESC1, " dli A1,AL # load constant to reg\n", }, { OPLTYPE, INAREG, SANY, TANY, SANY, TANY, NAREG, RESC1, " move A1,AL\n", }, { OPLTYPE, INCREG, SANY, TANY, SZERO, TFLOAT, NCREG, RESC1, " dmtc1 $zero,A1 # load 0 to float reg\n" " nop\n", }, { OPLTYPE, INCREG, SANY, TANY, SZERO, TDOUBLE|TLDOUBLE, NCREG, RESC1, " dmtc1 $zero,A1 # load 0 to (l)double reg\n" " dmtc1 $zero,U1\n" " nop\n", }, { OPLTYPE, INCREG, SANY, TANY, SOREG|SNAME, TFLOAT, NCREG, RESC1, " l.s A1,AL # load into floating-point reg\n" " nop\n", }, { OPLTYPE, INCREG, SANY, TANY, OREG|SNAME, TDOUBLE|TLDOUBLE, NCREG, RESC1, " l.d A1,AL # load into double floating-point reg\n" " nop\n", }, /* * Jumps. */ { GOTO, FOREFF, SCON, TANY, SANY, TANY, 0, RNOP, " j LL # goto label\n" " nop\n" " nop\n", }, /* * Subroutine calls. */ { CALL, FOREFF, SCON, TANY, SANY, TANY, 0, 0, " dsubu $sp,$sp,32 # call (args, no result) to scon/sname\n" " jal CL\n" " nop\n" "ZC", }, { UCALL, FOREFF, SCON, TANY, SANY, TANY, 0, 0, " jal CL # call (no args, no result) to scon/sname\n" " nop\n", }, { CALL, INAREG, SCON, TANY, SAREG, TANY, NAREG, RESC1, /* should be 0 */ " dsubu $sp,$sp,32 # call (args, result in v0) to scon/sname\n" " jal CL\n" " nop\n" "ZC", }, { UCALL, INAREG, SCON, TANY, SAREG, TANY, NAREG, RESC1, /* should be 0 */ " jal CL # call (no args, result in v0) to scon/sname\n" " nop\n", }, { CALL, INBREG, SCON, TANY, SBREG, TANY, NBREG, RESC1, /* should be 0 */ " dsubu $sp,$sp,32 # call (args, result in v0:v1) to scon/sname\n" " jal CL\n" " nop\n" "ZC", }, { UCALL, INBREG, SCON, TANY, SBREG, TANY, NBREG, RESC1, /* should be 0 */ " jal CL # call (no args, result in v0:v1) to scon/sname\n" " nop\n", }, { CALL, INCREG, SCON, TANY, SCREG, TANY, NCREG, RESC1, /* should be 0 */ " dsubu $sp,$sp,32 # call (args, result in f0:f1) to scon/sname\n" " jal CL\n" " nop\n" "ZC", }, { UCALL, INCREG, SCON, TANY, SCREG, TANY, NCREG, RESC1, /* should be 0 */ " jal CL # call (no args, result in v0:v1) to scon/sname\n" " nop\n", }, { CALL, FOREFF, SAREG, TANY, SANY, TANY, 0, 0, " dsubu $sp,$sp,32 # call (args, no result) to reg\n" " move $25,AL\n" " jal $25\n" " nop\n" "ZC", }, { UCALL, FOREFF, SAREG, TANY, SANY, TANY, 0, 0, " move $25,AL\n" " jal $25 # call (no args, no result) to reg\n" " nop\n", }, { CALL, INAREG, SAREG, TANY, SAREG, TANY, NAREG, RESC1, /* should be 0 */ " dsubu $sp,$sp,32 # call (args, result) to reg\n" " move $25,AL\n" " jal $25\n" " nop\n" "ZC", }, { UCALL, INAREG, SAREG, TANY, SAREG, TANY, NAREG, RESC1, /* should be 0 */ " move $25,AL\n" " jal $25 # call (no args, result) to reg\n" " nop\n", }, { CALL, INBREG, SAREG, TANY, SBREG, TANY, NBREG, RESC1, /* should be 0 */ " dsubu $sp,$sp,32 # call (args, result) to reg\n" " move $25,AL\n" " jal $25\n" " nop\n" "ZC", }, { UCALL, INBREG, SAREG, TANY, SBREG, TANY, NBREG, RESC1, /* should be 0 */ " move $25,AL\n" " jal $25 # call (no args, result) to reg\n" " nop\n", }, { CALL, INCREG, SAREG, TANY, SCREG, TANY, NCREG, RESC1, /* should be 0 */ " dsubu $sp,$sp,32 # call (args, result) to reg\n" " move $25,AL\n" " jal $25\n" " nop\n" "ZC", }, { UCALL, INCREG, SCREG, TANY, SCREG, TANY, NCREG, RESC1, /* should be 0 */ " move $25,AL\n" " jal $25 # call (no args, result) to reg\n" " nop\n", }, /* struct return */ { USTCALL, FOREFF, SCON|SNAME, TANY, SANY, TANY, 0, 0, " jal CL\n" " nop\n", }, { USTCALL, FOREFF, SAREG, TANY, SANY, TANY, 0, 0, " move $25,AL\n" " jal $25\n" " nop\n", }, { USTCALL, INAREG, SCON|SNAME, TANY, SANY, TANY, NAREG|NASL, RESC1, " jal CL\n" " nop\n", }, { USTCALL, INAREG, SAREG, TANY, SANY, TANY, NAREG|NASL, RESC1, " move $25,AL\n" " jal $25\n" " nop\n", }, { STCALL, FOREFF, SCON|SNAME, TANY, SANY, TANY, 0, 0, " dsubu $sp,$sp,32\n" " jal CL\n" " nop\n" "ZC", }, { STCALL, FOREFF, SAREG, TANY, SANY, TANY, 0, 0, " dsubu $sp,$sp,32\n" " move $25,AL\n" " jal $25\n" " nop\n" "ZC", }, { STCALL, INAREG, SCON|SNAME, TANY, SANY, TANY, NAREG|NASL, RESC1, " dsubu $sp,$sp,32\n" " jal CL\n" " nop\n" "ZC", }, { STCALL, INAREG, SAREG, TANY, SANY, TANY, 0, 0, " dsubu $sp,$sp,32\n" " move $25,AL\n" " jal $25\n" " nop\n" "ZC", }, /* * Function arguments */ /* intentionally write out the register for (u)short/(u)char */ { FUNARG, FOREFF, SAREG, TWORD|TPOINT|TUSHORT|TSHORT|TUCHAR|TCHAR, SANY, TWORD|TPOINT|TUSHORT|TSHORT|TUCHAR|TCHAR, 0, 0, " dsubu $sp,$sp,8 # save function arg to stack\n" " sd AL,($sp)\n" " #nop\n", }, { FUNARG, FOREFF, SBREG, TLONGLONG|TULONGLONG, SANY, TLONGLONG|TULONGLONG, 0, 0, " daddi $sp,$sp,-8 # save function arg to stack\n" " sd AL,($sp)\n" " #nop\n", }, { FUNARG, FOREFF, SCREG, TFLOAT, SANY, TFLOAT, 0, 0, " daddi $sp,$sp,-8 # save function arg to stack\n" " s.s AL,($sp)\n" " #nop\n", }, { FUNARG, FOREFF, SCREG, TDOUBLE|TLDOUBLE, SANY, TDOUBLE|TLDOUBLE, 0, 0, " daddi $sp,$sp,-26 # save function arg to stack\n" " s.d AL,($sp)\n" " #nop\n", }, { STARG, FOREFF, SAREG, TANY, SANY, TSTRUCT, NSPECIAL, 0, "ZH", }, /* * Indirection operators. */ { UMUL, INAREG, SANY, TPOINT|TWORD, SOREG, TPOINT|TWORD, NAREG, RESC1, " ld A1,AL # word load\n" " nop\n", }, { UMUL, INAREG, SANY, TSHORT|TUSHORT, SOREG, TSHORT|TUSHORT, NAREG, RESC1, " lh A1,AL # (u)short load\n" " nop\n", }, { UMUL, INAREG, SANY, TCHAR|TUCHAR, SOREG, TCHAR|TUCHAR, NAREG, RESC1, " lb A1,AL # (u)char load\n" " nop\n", }, { UMUL, INBREG, SANY, TLONGLONG|TULONGLONG, SOREG, TLONGLONG|TULONGLONG, NBREG, RESC1, " ld A1,AL # (u)longlong load - endian problem here?\n" " nop\n", }, { UMUL, INCREG, SANY, TFLOAT, SOREG, TFLOAT, NCREG, RESC1, " l.s A1,AL # float load\n" " nop\n", }, { UMUL, INCREG, SANY, TDOUBLE|TLDOUBLE, SOREG, TDOUBLE|TLDOUBLE, NCREG, RESC1, " l.d A1,AL # float load\n" " nop\n", }, #if 0 { UMUL, INCREG, SANY, TDOUBLE|TLDOUBLE, SAREG, TPOINT, NCREG, RESC1, " l.d A1,(AL)\n" " nop\n", }, { UMUL, INAREG, SANY, TPOINT|TWORD, SNAME, TPOINT|TWORD, NAREG, RESC1, " dla A1,AL # sname word load\n" " ld A1,(A1)\n" " nop\n", }, { UMUL, INAREG, SANY, TSHORT|TUSHORT, SNAME, TSHORT|TUSHORT, NAREG, RESC1, " dla A1,AL # sname (u)short load\n" " lh A1,(A1)\n" " nop\n", }, { UMUL, INAREG, SANY, TCHAR|TUCHAR, SNAME, TCHAR|TUCHAR, NAREG, RESC1, " dla A1,AL # sname (u)char load\n" " lb A1,(A1)\n" " nop\n", }, { UMUL, INBREG, SANY, TLONGLONG|TULONGLONG, SNAME, TLONGLONG|TULONGLONG, NBREG|NAREG, RESC1, " dla A2,AL # sname (u)long long load - endian problems here?\n" " ld A1,(A1)\n" " nop\n", }, #endif { UMUL, INAREG, SANY, TPOINT|TWORD, SAREG, TPOINT|TWORD, NAREG, RESC1, " ld A1,(AL) # word load\n" " nop\n", }, #if 0 { UMUL, INAREG, SANY, TSHORT|TUSHORT, SAREG, TPTRTO|TSHORT|TUSHORT, NAREG, RESC1, " lh A1,(AL) # (u)short load\n" " nop\n", }, { UMUL, INAREG, SANY, TCHAR|TUCHAR, SAREG, TPTRTO|TCHAR|TUCHAR, NAREG|NASL, RESC1, " lb A1,(AL) # (u)char load\n" " nop\n", }, { UMUL, INBREG, SANY, TLONGLONG|TULONGLONG, SAREG, TPTRTO|TLONGLONG|TULONGLONG, NBREG, RESC1, " ld A1,(AL) # (u)long long load - endianness problems?\n" " nop\n", }, #endif #define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,"" { FLD, DF(FLD), }, { FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" }, }; int tablesize = sizeof(table)/sizeof(table[0]); pcc-20181216/arch/nova004075500017500000000000000000001340533064000132665ustar raggewheelpcc-20181216/arch/nova/CVS004075500017500000000000000000001340533064000137215ustar raggewheelpcc-20181216/arch/nova/CVS/Root010064400017500000000000000000111340533064000146330ustar raggewheel/cvsroot pcc-20181216/arch/nova/CVS/Repository010064400017500000000000000000161340533064000160740ustar raggewheelpcc/arch/nova pcc-20181216/arch/nova/CVS/Entries010064400017500000000000000004371340533064000153350ustar raggewheel/README/1.5/Mon Jun 27 11:47:06 2016// /code.c/1.13/Mon Jun 27 11:47:06 2016// /local.c/1.19/Mon Jun 27 11:47:06 2016// /local2.c/1.16/Mon Jun 27 11:47:06 2016// /macdefs.h/1.12/Mon Jun 27 11:47:06 2016// /order.c/1.7/Mon Jun 27 11:47:06 2016// /table.c/1.4/Mon Jun 27 11:47:06 2016// D pcc-20181216/arch/nova/README010064400017500000000000000143321273421107200142260ustar raggewheelCalling conventions, stack frame and zero page: The variables that normally are placed on the stack or in registers in C are instead allocated in the zero page and saved on a (fictive) stack when calling functions. Some locations have predefined functions though. Arrays allocated as automatics are stored on the stack with a pointer in zero page to its destination. #ifdef 2bsd 0-7 Unused (by us) 10 Stack pointer 11 Frame pointer 12-14 Unused 15 Prolog private word 16 Prolog address, written in crt0 17 Epilog address, written in crt0 20-27 (Auto-increment), scratch 30-37 (Auto-decrement), scratch 40-47 Used by HW stack and MMPU 50-77 Permanent, save before use. 100-377 Addresses for subroutines, written by the linker #elif rdos 0-17 Unused (by us) 20-27 (Auto-increment), scratch 30-37 (Auto-decrement), scratch 40-47 Used by HW stack and MMPU 50-377 Addresses for subroutines, written by the linker #endif The normal registers (AC0-AC3) are all considered scratch registers. Register classes are assigned as: AC0-AC3: AREGs. AC2-AC3: BREGs. ...and eventually register pairs/floats as EREGs, double in FREGs. In byte code the left half of a word is the first byte (big-endian). This is bit 0-7 in Nova syntax. The stack is growing towards lower adresses (as opposed to the HW stack). Stack pointer points to the last used stack entry, which means: PUSH: store value, dec sp POP: inc sp, fetch val Note that internally is the first 24 words stored in loc 50-77! So an offset is subtracted in adrput(). Functions which modifies stack (like calls to alloca) will have a frame pointer to which everything relates. Functions that do not only have stack pointer. Space for all possible arguments are allocated on stack by the compiler, so no pushing and popping. Stack layout (with frame pointer): ! arg1 ! 2 ! arg0 ! 1 fp -> ! ret pc! 0 <- stack pointer when enter new function ! old fp! -1 sp -> ! saved ! -2 Stack references to zero page are converted to NAMEs, using word addresses. References to the stack itself are using byte offsets. Arguments are transferred on the stack. To avoid unneccessary double instructions they are copied to the zp use area initially. XXX? Need tests here. Return values in ac0 and ac1. A reference to a struct member in assembler, a = b->c; b is in ZP 50 (or on stack) + is zeropage-addressing * is fp-adressing, assume fp in ac3 # offset 0 + lda 0,@50 # load value from indirect ZP 50 into ac0 or * lda 2,,3 # load value from (ac3) into ac2 * lda 0,,2 # load value from (ac2) into ac0 # offset 12 + lda 2,50 # load value from ZP 50 into ac2 + lda 0,12,2 # load value from (ac2+12) into ac0 or * lda 2,,3 # load value from (ac3) into ac2 * lda 0,12,2 # load value from 12(ac2) into ac0 # offset 517 + lda %2,50 # load value from ZP 50 into ac2 + lda %0,.L42-.,%1 # load offset from .L42 PC-indexed + addz %0,%2,skp # add offset to ac2 and skip +.L42: .word 517 # offset value + lda %0,,%2 # load value from (ac2) into ac0 or The prolog/epilog; they are implemented as subroutines. Both can be omitted if the function do not need it. .word 012 # total words that needs to be saved func: mov 3,0 # avoid trashing return address jsr @prolog # go to prolog ... jmp @epilog # jump to epilog #ifdef prolog lda 0,sp sta 3,@sp lda 1,fp sta 1,@sp sta 0,fp lda 1,[Css] sub 1,0 sta 0,sp #endif ... lda 2,fp lda 3,-1,2 lda 0,-2,2 sta 0,fp sta 2,sp jmp 0,3 # # decrement from stack, and save permanent registers. # push retreg # push fp # mov sp,fp # sub $w,sp # # prolog: return in ac3, fun in ac0. prolog: lda 1,sp sta 0,@sp lda 0,fp sta 0,@sp sta 1,fp lda 0,-3,3 sub 0,1 sta 1,sp jmp 0,3 epilog: lda 3,fp sta 3,sp lda 3,@fp lda 2,@fp sta 2,fp jmp 0,3 prolog: lda 2,sp # sp points to the first argument sta 2,30 # store at auto-dec location sta 0,@30 # store fun return address lda 0,fp # fetch old fp sta 0,@30 # store saved fp sta 2,fp # save frame pointer lda 0,-3,3 # stack size to subtract neg 0,0,snr # Any words? jmp 1f # no, get away lda 1,$51 # fetch zp offset sub 0,1 # get highest word sta 1,31 # at auto-dec location 2: lda 1,@31 # fetch word to copy sta 1,@30 # on stack inc 0,0,szr # count words jmp 1b # more to go 1: lda 0,30 # finished, get stackptr sta 0,sp # jmp 0,3 # get back! # epilog, need save frame pointer in ac3 epilog: lda 0,-3,3 # get words to save neg 0,0,snr # any words to save? jmp 1f # No, get out lda 1,$51 # get zp offset sub 0,1 # Highest word sta 1,31 # auto-dec loc lda 2,fp # get fp adczl 1,1 # -2 add 1,2 # 2 now offset sta 2,30 # auto-dec loc 2: lda 1,@30 sta 1,@31 inc 0,0,szr jmp 2b 1: lda 2,fp # fetch current fp lda 3,-1,2 # return pc lda 0,-2,2 # fetch old fp sta 0,fp # restore fp sta 2,sp # stack pointer restored jmp 0,3 # Done! #if 0 Assembler syntax and functions. The assembler syntax mimics the DG assembler but uses AT&T syntax. Load and store to addresses is written "lda 0,foo" to load from address foo. If foo is not in zero page then the assembler will put the lda in the text area close to the instruction and do an indirect pc-relative load. Arithmetic instruction: subsl# %0,%1,snr skip code may be omitted subsl# %0,%1 Load/store/jmp/jsr/isz/dsz: lda %1,@disp,2 or mov *disp(%2),%1 index may be omitted if 0 (ZP) disp can only be +-127 words. It's allowed to write "mov $32,%0" which will be converted to an indirect load by the assembler. Example of AT&T arguments: 01234 - Zero-page L11 - Relative. Will be converted to indirect + addr if distance too long (%2) - indexed 012(%2) - indexed with offset * in front of any of these will generate indirection #endif lbyte: movr 2,2 # get byte ID into C bit lda 0,,2 # word into ac0 mov 2,2,snc # skip if right byte movs 0,0 # swap bytes jmp 0,3 # get back sbyte: sta 3,@sp movr 2,2 # get byte ID into C bit lda 1,,2 # get word lda 3,[377] # get mask and 3,0,snc # clear left input + skip if right byte movs 1,1 # swap bytes and 3,1 # clear old bits add 0,1,snc # swap back if necessary movs 1,1 # swap sta 1,2 lda 3,sp isz sp jmp @0,3 pcc-20181216/arch/nova/code.c010064400017500000000000000143421273421107200144250ustar raggewheel/* $Id: code.c,v 1.13 2016/06/27 11:47:06 ragge Exp $ */ /* * Copyright (c) 2006 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass1.h" #ifdef LANG_CXX #define P1ND NODE #define p1alloc talloc #define p1nfree nfree #define p1fwalk fwalk #define p1tcopy ccopy #endif /* * cause the alignment to become a multiple of n * never called for text segment. */ void defalign(int n) { /* alignment are always correct */ } /* * Print out assembler segment name. */ void setseg(int seg, char *name) { #ifndef os_none switch (seg) { case PROG: name = ".text"; break; case DATA: case LDATA: name = ".data"; break; case STRNG: case RDATA: name = ".rodata"; break; case UDATA: break; default: cerror((char *)__func__); } #else name = ".NREL"; #endif printf("\t%s\n", name); } /* * Define everything needed to print out some data (or text). * This means segment, alignment, visibility, etc. */ void defloc(struct symtab *sp) { char *name; name = getexname(sp); if (ISFTN(sp->stype)) return; if (sp->sclass == EXTDEF) printf("\t.globl %s\n", name); if (sp->slevel == 0) printf("%s:\n", name); else printf(LABFMT ":\n", sp->soffset); } /* make a common declaration for id, if reasonable */ void defzero(struct symtab *sp) { int off, al; char *name; name = getexname(sp); off = tsize(sp->stype, sp->sdf, sp->sap); SETOFF(off,SZCHAR); off /= SZCHAR; al = talign(sp->stype, sp->sap)/SZCHAR; if (sp->sclass == STATIC) { if (sp->slevel == 0) { printf("\t.local %s\n", name); } else printf("\t.local " LABFMT "\n", sp->soffset); } if (sp->slevel == 0) { printf("\t.comm %s,0%o,%d\n", name, off, al); } else printf("\t.comm " LABFMT ",0%o,%d\n", sp->soffset, off, al); } //static int ac3temp; /* * code for the end of a function * deals with struct return here */ void efcode(void) { P1ND *p, *q; // int sz; #if 0 /* restore ac3 */ p = block(REG, 0, 0, INT, 0, 0); regno(p) = 3; q = tempnode(ac3temp, INT, 0, 0); ecomp(buildtree(ASSIGN, p, q)); #endif if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) return; cerror("efcode"); /* address of return struct is in eax */ /* create a call to memcpy() */ /* will get the result in eax */ p = block(REG, NULL, NULL, CHAR+PTR, 0, 0); // p->n_rval = EAX; q = block(OREG, NULL, NULL, CHAR+PTR, 0, 0); // q->n_rval = EBP; slval(q, 8); /* return buffer offset */ p = block(CM, q, p, INT, 0, 0); // sz = (tsize(STRTY, cftnsp->sdf, cftnsp->ssue)+SZCHAR-1)/SZCHAR; // p = block(CM, p, bcon(sz), INT, 0, 0); p->n_right->n_name = ""; p = block(CALL, bcon(0), p, CHAR+PTR, 0, 0); p->n_left->n_name = "memcpy"; p = clocal(p); send_passt(IP_NODE, p); } /* * code for the beginning of a function; a is an array of * indices in symtab for the arguments; n is the number */ void bfcode(struct symtab **a, int n) { // P1ND *p, *q; int i; for (i = 0; i < n; i++) { if (a[i]->stype == CHAR) a[i]->stype = INT; if (a[i]->stype == UCHAR) a[i]->stype = UNSIGNED; } if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) return; cerror("bfcode"); /* Function returns struct, adjust arg offset */ for (i = 0; i < n; i++) a[i]->soffset += SZPOINT(INT); } /* called just before final exit */ /* flag is 1 if errors, 0 if none */ void ejobcode(int flag) { #ifdef os_none printf("\t.END\n"); #endif } void bjobcode(void) { #ifdef os_none printf("\t.TITL foo\n"); printf("\t.TXTM 1\n"); /* big endian */ printf("\t.NREL\n"); /* relocatable */ printf("\t.EXTU\n"); /* undefined syms are external */ #endif } /* fix up type of field p */ void fldty(struct symtab *p) { } /* * XXX - fix genswitch. */ int mygenswitch(int num, TWORD type, struct swents **p, int n) { return 0; } static int xoff; static void fnummer(P1ND *p) { if (p->n_op != FUNARG) return; p->n_rval = xoff; xoff += tsize(p->n_type, p->n_df, p->n_ap)/SZSHORT; } /* * Called with a function call with arguments as argument. * This is done early in buildtree() and only done once. */ P1ND * funcode(P1ND *p) { P1ND *r, *l; /* Fix function call arguments. On nova, just add funarg */ for (r = p->n_right; r->n_op == CM; r = r->n_left) { if (r->n_right->n_op != STARG) { r->n_right = block(FUNARG, r->n_right, NULL, r->n_right->n_type, r->n_right->n_df, r->n_right->n_ap); } } if (r->n_op != STARG) { l = p1alloc(); *l = *r; r->n_op = FUNARG; r->n_left = l; r->n_type = l->n_type; } xoff = 1; p1listf(p->n_right, fnummer); return p; } /* * Return return as given by a. */ P1ND * builtin_return_address(const struct bitable *bt, P1ND *a) { cerror((char *)__func__); return 0; } /* * Return frame as given by a. */ P1ND * builtin_frame_address(const struct bitable *bt, P1ND *a) { cerror((char *)__func__); return 0; } /* * Return "canonical frame address". */ P1ND * builtin_cfa(const struct bitable *bt, P1ND *a) { cerror((char *)__func__); return 0; } pcc-20181216/arch/nova/local.c010064400017500000000000000232641273421107200146100ustar raggewheel/* $Id: local.c,v 1.19 2016/06/27 11:47:06 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass1.h" # include "unicode.h" #ifdef LANG_CXX #define P1ND NODE #define p1alloc talloc #define p1nfree nfree #define p1fwalk fwalk #define p1tcopy ccopy #endif /* this file contains code which is dependent on the target machine */ P1ND * clocal(P1ND *p) { struct symtab *q; P1ND *r, *l; TWORD t; int o; #ifdef PCC_DEBUG if (xdebug) { printf("clocal\n"); p1fwalk(p, eprint, 0); } #endif switch( o = p->n_op ){ case NAME: /* handle variables */ if ((q = p->n_sp) == NULL) return p; /* Nothing to care about */ switch (q->sclass) { case PARAM: case AUTO: /* fake up a structure reference */ r = block(REG, NULL, NULL, PTR+STRTY, 0, 0); slval(r, 0); r->n_rval = FPREG; p = stref(block(STREF, r, p, 0, 0, 0)); break; default: break; } break; case PMCONV: case PVCONV: if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0); r = (buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right)); p1nfree(p); p = r; break; case PCONV: t = p->n_type; if (t == INCREF(CHAR) || t == INCREF(UCHAR) || t == INCREF(BOOL) || t == INCREF(VOID)) break; l = p->n_left; t = l->n_type; if (t == INCREF(CHAR) || t == INCREF(UCHAR) || t == INCREF(BOOL) || t == INCREF(VOID)) break; if (p->n_type <= UCHAR || l->n_type <= UCHAR) break; /* must do runtime ptr conv */ /* if conversion to another pointer type, just remove */ if (p->n_type > BTMASK && l->n_type > BTMASK) goto delp; if (l->n_op == ICON && l->n_sp == NULL) goto delp; break; delp: l->n_type = p->n_type; l->n_qual = p->n_qual; l->n_df = p->n_df; l->n_ap = p->n_ap; p = p1nfree(p); break; case FORCE: /* put return value in return reg */ p->n_op = ASSIGN; p->n_right = p->n_left; p->n_left = block(REG, NULL, NULL, p->n_type, 0, 0); p->n_left->n_rval = RETREG(p->n_type); break; } #ifdef PCC_DEBUG if (xdebug) { printf("clocal end\n"); p1fwalk(p, eprint, 0); } #endif return(p); } void myp2tree(P1ND *p) { struct symtab *sp; P1ND *l, *r; int o = p->n_op; switch (o) { case NAME: /* reading from a name must be done with a subroutine */ if (p->n_type != CHAR && p->n_type != UCHAR) break; l = buildtree(ADDROF, p1tcopy(p), NULL); r = block(NAME, NULL, NULL, INT, 0, 0); r->n_sp = lookup(addname("__nova_rbyte"), SNORMAL); if (r->n_sp->sclass == SNULL) { r->n_sp->sclass = EXTERN; r->n_sp->stype = INCREF(p->n_type)+(FTN-PTR); } r->n_type = r->n_sp->stype; r = clocal(r); r = optim(buildtree(CALL, r, l)); *p = *r; p1nfree(r); break; case FCON: sp = tmpalloc(sizeof(struct symtab)); sp->sclass = STATIC; sp->sap = 0; sp->slevel = 1; /* fake numeric label */ sp->soffset = getlab(); sp->sflags = 0; sp->stype = p->n_type; sp->squal = (CON >> TSHIFT); defloc(sp); ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p); p->n_op = NAME; slval(p, 0); p->n_sp = sp; } } /*ARGSUSED*/ int andable(P1ND *p) { return(1); /* all names can have & taken on them */ } /* * Return 1 if a variable of type type is OK to put in register. */ int cisreg(TWORD t) { return 1; /* try to put anything in a register */ } /* * return a node, for structure references, which is suitable for * being added to a pointer of type t, in order to be off bits offset * into a structure * t, d, and s are the type, dimension offset, and sizeoffset * For nova, return the type-specific index number which calculation * is based on its size. For example, char a[3] would return 3. * Be careful about only handling first-level pointers, the following * indirections must be fullword. */ P1ND * offcon(OFFSZ off, TWORD t, union dimfun *d, struct attr *ap) { register P1ND *p; if (xdebug) printf("offcon: OFFSZ %ld type %x dim %p siz %ld\n", off, t, d, tsize(t, d, ap)); p = bcon(off/SZINT); if (t == INCREF(CHAR) || t == INCREF(UCHAR) || t == INCREF(VOID)) slval(p, off/SZCHAR); /* pointer to char */ return(p); } /* * Allocate off bits on the stack. p is a tree that when evaluated * is the multiply count for off, t is a NAME node where to write * the allocated address. */ void spalloc(P1ND *t, P1ND *p, OFFSZ off) { P1ND *sp; cerror("spalloc"); if ((off % SZINT) == 0) p = buildtree(MUL, p, bcon(off/SZINT)); else if ((off % SZSHORT) == 0) { p = buildtree(MUL, p, bcon(off/SZSHORT)); p = buildtree(PLUS, p, bcon(1)); p = buildtree(RS, p, bcon(1)); } else if ((off % SZCHAR) == 0) { p = buildtree(MUL, p, bcon(off/SZCHAR)); p = buildtree(PLUS, p, bcon(3)); p = buildtree(RS, p, bcon(2)); } else cerror("roundsp"); /* save the address of sp */ sp = block(REG, NULL, NULL, PTR+INT, t->n_df, t->n_ap); slval(sp, 0); sp->n_rval = STKREG; t->n_type = sp->n_type; ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */ /* add the size to sp */ sp = block(REG, NULL, NULL, p->n_type, 0, 0); slval(sp, 0); sp->n_rval = STKREG; ecomp(buildtree(PLUSEQ, sp, p)); } #ifdef os_none /* * Print out a string of characters. * Assume that the assembler understands C-style escape * sequences. */ void instring(struct symtab *sp) { unsigned short sh[2]; char *s; TWORD t; P1ND *p; locctr(STRNG, sp); defloc(sp); t = BTYPE(sp->stype); s = sp->sname; if (t == ctype(USHORT)) { /* convert to UTF-16 */ p = xbcon(0, NULL, t); while (*s) { cp2u16(u82cp(&s), sh); if ((glval(p) = sh[0])) inval(0, SZSHORT, p); if ((glval(p) = sh[1])) inval(0, SZSHORT, p); } slval(p, 0); inval(0, SZSHORT, p); p1nfree(p); } else if (t == ctype(SZINT < 32 ? ULONG : UNSIGNED) || t == ctype(SZINT < 32 ? LONG : INT)) { /* convert to UTF-32 */ p = xbcon(0, NULL, t); while (*s) { slval(p, u82cp(&s)); inval(0, SZINT < 32 ? SZLONG : SZINT, p); } slval(p, 0); inval(0, SZINT < 32 ? SZLONG : SZINT, p); p1nfree(p); } else if (t == CHAR || t == UCHAR) { int chno = 0; printf(PRTPREF "\t.TXT \""); for (; *s; s++) { if (*s == '\\') { printf("<%o>", esccon(&s)); } else printf("%c", *s); if (chno++ >= 60) { printf("\r\n" PRTPREF); chno = 0; } } printf("\"\n"); } else cerror("instring %ld", t); } #endif /* * print out a constant node * mat be associated with a label */ int ninval(CONSZ off, int fsz, P1ND *p) { switch (p->n_type) { case FLOAT: case DOUBLE: case LDOUBLE: cerror("ninval"); } return 1; } /* make a name look like an external name in the local machine */ char * exname(char *p) { if (p == NULL) return ""; return p; } /* * map types which are not defined on the local machine */ TWORD ctype(TWORD type) { switch (BTYPE(type)) { case LONGLONG: MODTYPE(type,LONG); break; case ULONGLONG: MODTYPE(type,ULONG); break; case SHORT: MODTYPE(type,INT); break; case USHORT: MODTYPE(type,UNSIGNED); break; } return (type); } #if 0 /* curid is a variable which is defined but * is not initialized (and not a function ); * This routine returns the storage class for an uninitialized declaration */ int noinit() { return(EXTERN); } #endif void calldec(P1ND *p, P1ND *q) { } void extdec(struct symtab *q) { } #if 0 /* make a common declaration for id, if reasonable */ void commdec(struct symtab *q) { int off; off = tsize(q->stype, q->sdf, q->ssue); off = (off+(SZCHAR-1))/SZCHAR; printf(" .comm %s,0%o\n", exname(q->soname), off); } /* make a local common declaration for id, if reasonable */ void lcommdec(struct symtab *q) { int off; off = tsize(q->stype, q->sdf, q->ssue); off = (off+(SZCHAR-1))/SZCHAR; if (q->slevel == 0) printf(" .lcomm %s,0%o\n", exname(q->soname), off); else printf(" .lcomm " LABFMT ",0%o\n", q->soffset, off); } /* * print a (non-prog) label. */ void deflab1(int label) { printf(LABFMT ":\n", label); } #endif /* * Give target the opportunity of handling pragmas. */ int mypragma(char *str) { return 0; } /* * Called when a identifier has been declared, to give target last word. * On Nova we put symbols over the size of an int above 24 bytes in * offset and leave zeropage for small vars. */ void fixdef(struct symtab *sp) { #if 0 if (sp->sclass != AUTO) return; /* not our business */ if (ISPTR(sp->stype) || sp->stype < LONG) return; if (sp->soffset >= (MAXZP * SZINT)) return; /* already above */ /* have to move */ /* XXX remember old autooff for reorg of smaller vars */ if (autooff < MAXZP * SZINT) autooff = MAXZP * SZINT; oalloc(sp, &autooff); #endif } void pass1_lastchance(struct interpass *ip) { } pcc-20181216/arch/nova/local2.c010064400017500000000000000275541273421107200147000ustar raggewheel/* $Id: local2.c,v 1.16 2016/06/27 11:47:06 ragge Exp $ */ /* * Copyright (c) 2006 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass2.h" # include # include #include void acon(NODE *p); int argsize(NODE *p); static int totstk, maxargsz; struct conlbl { struct conlbl *next; int lbl; CONSZ l; char *n; int isch; }; struct conlbl *pole; void deflab(int label) { printf(LABFMT ":\n", label); } void prologue(struct interpass_prolog *ipp) { totstk = p2maxautooff/(SZINT/SZCHAR) + maxargsz; maxargsz = 0; #ifdef os_none if (ipp->ipp_vis) printf(" .ENT %s\n", ipp->ipp_name); printf(" .ZREL\n"); printf("%s: .%s\n", ipp->ipp_name, ipp->ipp_name); printf(" .NREL\n"); printf(" 0%o\n", totstk); printf(".%s:\n", ipp->ipp_name); #else if (ipp->ipp_vis) printf(" .globl %s\n", ipp->ipp_name); if (totstk) printf(" .word 0%o\n", totstk); printf("%s:\n", ipp->ipp_name); #endif printf(" sta 3,@csp\n"); /* put ret pc on stack */ printf(" jsr @prolog\n"); /* jump to prolog */ } void eoftn(struct interpass_prolog *ipp) { struct conlbl *w; char *ch; if (ipp->ipp_ip.ip_lbl == 0) return; /* no code needs to be generated */ printf(" jmp @epilog\n"); if (pole == NULL) return; while (pole != NULL) { w = pole, pole = w->next; printf("." LABFMT ":\t", w->lbl); ch = w->isch ? "*2" : ""; if (w->n[0]) printf("%s%s%s", w->n, ch, w->l ? "+" : ""); if (w->l || w->n[0] == 0) printf(CONFMT "%s", w->l, ch); printf("\n"); free(w); } } /* * add/sub/... * * Param given: */ void hopcode(int f, int o) { char *str = 0; switch (o) { case PLUS: str = "add"; break; case MINUS: str = "sub"; break; case AND: str = "and"; break; case OR: cerror("hopcode OR"); break; case ER: cerror("hopcode xor"); str = "xor"; break; default: comperr("hopcode2: %d", o); str = 0; /* XXX gcc */ } printf("%s%c", str, f); } #if 0 /* * Return type size in bytes. Used by R2REGS, arg 2 to offset(). */ int tlen(p) NODE *p; { switch(p->n_type) { case CHAR: case UCHAR: return(1); case SHORT: case USHORT: return(SZSHORT/SZCHAR); case DOUBLE: return(SZDOUBLE/SZCHAR); case INT: case UNSIGNED: case LONG: case ULONG: return(SZINT/SZCHAR); case LONGLONG: case ULONGLONG: return SZLONGLONG/SZCHAR; default: if (!ISPTR(p->n_type)) comperr("tlen type %d not pointer"); return SZPOINT(p->n_type)/SZCHAR; } } #endif int fldexpand(NODE *p, int cookie, char **cp) { return 0; } #if 0 /* * Assign to a bitfield. * Clumsy at least, but what to do? */ static void bfasg(NODE *p) { NODE *fn = p->n_left; int shift = UPKFOFF(fn->n_rval); int fsz = UPKFSZ(fn->n_rval); int andval, tch = 0; /* get instruction size */ switch (p->n_type) { case CHAR: case UCHAR: tch = 'b'; break; case SHORT: case USHORT: tch = 'w'; break; case INT: case UNSIGNED: tch = 'l'; break; default: comperr("bfasg"); } /* put src into a temporary reg */ printf(" mov%c ", tch); adrput(stdout, getlr(p, 'R')); printf(","); adrput(stdout, getlr(p, '1')); printf("\n"); /* AND away the bits from dest */ andval = ~(((1 << fsz) - 1) << shift); printf(" and%c $%d,", tch, andval); adrput(stdout, fn->n_left); printf("\n"); /* AND away unwanted bits from src */ andval = ((1 << fsz) - 1); printf(" and%c $%d,", tch, andval); adrput(stdout, getlr(p, '1')); printf("\n"); /* SHIFT left src number of bits */ if (shift) { printf(" sal%c $%d,", tch, shift); adrput(stdout, getlr(p, '1')); printf("\n"); } /* OR in src to dest */ printf(" or%c ", tch); adrput(stdout, getlr(p, '1')); printf(","); adrput(stdout, fn->n_left); printf("\n"); } #endif #if 0 /* * Push a structure on stack as argument. * the scratch registers are already free here */ static void starg(NODE *p) { int sz = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0); printf(" subl $%d,%%esp\n", sz); printf(" pushl $%d\n", sz); expand(p, 0, " pushl AL\n"); expand(p, 0, " leal 8(%esp),A1\n"); expand(p, 0, " pushl A1\n"); printf(" call memcpy\n"); printf(" addl $12,%%esp\n"); } #endif static void addacon(int lbl, CONSZ lval, char *name, int isch) { struct conlbl *w = xmalloc(sizeof(struct conlbl)); w->next = pole, pole = w; w->lbl = lbl; w->l = lval; w->n = name; w->isch = isch; } void zzzcode(NODE *p, int c) { struct conlbl *w; char *ch; int pr; switch (c) { case 'A': if (pole == NULL) break; w = pole, pole = w->next; printf(",skp\n." LABFMT ":\t", w->lbl); ch = w->isch ? "*2" : ""; if (w->n[0]) printf("%s%s%s", w->n, ch, w->l ? "+" : ""); if (w->l || w->n[0] == 0) printf(CONFMT "%s", w->l, ch); free(w); break; case 'B': /* push arg relative sp */ printf("%d,", p->n_rval); expand(p, 0, "A1"); break; default: comperr("zzzcode %c", c); } } /*ARGSUSED*/ int rewfld(NODE *p) { return(1); } int canaddr(NODE *); int canaddr(NODE *p) { int o = p->n_op; if (o==NAME || o==REG || o==ICON || o==OREG || (o==UMUL && shumul(p->n_left, SOREG))) return(1); return(0); } /* * Does the bitfield shape match? */ int flshape(NODE *p) { int o = p->n_op; cerror("flshape"); if (o == OREG || o == REG || o == NAME) return SRDIR; /* Direct match */ if (o == UMUL && shumul(p->n_left, SOREG)) return SROREG; /* Convert into oreg */ return SRREG; /* put it into a register */ } /* INTEMP shapes must not contain any temporary registers */ /* XXX should this go away now? */ int shtemp(NODE *p) { return 0; #if 0 int r; if (p->n_op == STARG ) p = p->n_left; switch (p->n_op) { case REG: return (!istreg(p->n_rval)); case OREG: r = p->n_rval; if (R2TEST(r)) { if (istreg(R2UPK1(r))) return(0); r = R2UPK2(r); } return (!istreg(r)); case UMUL: p = p->n_left; return (p->n_op != UMUL && shtemp(p)); } if (optype(p->n_op) != LTYPE) return(0); return(1); #endif } void adrcon(CONSZ val) { printf("[" CONFMT "]", val); } /* * Conput prints out a constant. */ void conput(FILE *fp, NODE *p) { int val = getlval(p); switch (p->n_op) { case ICON: if (p->n_name[0] != '\0') { fprintf(fp, "%s", p->n_name); if (val) fprintf(fp, "+0%o", val); } else fprintf(fp, "0%o", val); return; default: comperr("illegal conput, p %p", p); } } /*ARGSUSED*/ void insput(NODE *p) { comperr("insput"); } /* * Write out the upper address, like the upper register of a 2-register * reference, or the next memory location. */ void upput(NODE *p, int size) { comperr("upput"); #if 0 size /= SZCHAR; switch (p->n_op) { case REG: printf("%%%s", &rnames[p->n_rval][3]); break; case NAME: case OREG: setlval(p, getlval(p) + size); adrput(stdout, p); setlval(p, getlval(p) - size); break; case ICON: printf("$" CONFMT, getlval(p) >> 32); break; default: comperr("upput bad op %d size %d", p->n_op, size); } #endif } void adrput(FILE *io, NODE *p) { int i; /* output an address, with offsets, from p */ static int looping = 7; if (looping == 0) { looping = 1; printf("adrput %p\n", p); fwalk(p, e2print, 0); looping = 0; } if (p->n_op == FLD) p = p->n_left; switch (p->n_op) { case ICON: #if 1 /* addressable value of the constant */ printf("." LABFMT, i = getlab2()); addacon(i, getlval(p), p->n_name, p->n_type == INCREF(CHAR) || p->n_type == INCREF(UCHAR)); #else fputc('[', io); if (p->n_type == INCREF(CHAR) || p->n_type == INCREF(UCHAR)) printf(".byteptr "); conput(io, p); fputc(']', io); #endif break; case NAME: if (p->n_name[0] != '\0') { fputs(p->n_name, io); if (getlval(p) != 0) fprintf(io, "+" CONFMT, getlval(p)); } else fprintf(io, CONFMT, getlval(p)); break; case OREG: if (p->n_name[0]) comperr("name in OREG"); i = (int)getlval(p); if (i < 0) { putchar('-'); i = -i; } printf("0%o,%s", i, rnames[regno(p)]); break; case REG: fprintf(io, "%s", rnames[p->n_rval]); break; default: comperr("illegal address, op %d, node %p", p->n_op, p); break; } } /* printf conditional and unconditional branches */ void cbgen(int o, int lab) { comperr("cbgen"); } void myreader(struct interpass *ipole) { if (x2debug) printip(ipole); } void mycanon(NODE *p) { int size = 0; p->n_qual = 0; if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) return; for (p = p->n_right; p->n_op == CM; p = p->n_left) { if (p->n_right->n_op != ASSIGN) size += szty(p->n_right->n_type); } if (p->n_op != ASSIGN) size += szty(p->n_type); if (maxargsz < size) maxargsz = size; } void myoptim(struct interpass *ip) { } void rmove(int s, int d, TWORD t) { printf(" mov %s,%s\n", rnames[s], rnames[d]); if (t > UNSIGNED && !ISPTR(t)) comperr("rmove"); } /* * For class c, find worst-case displacement of the number of * registers in the array r[] indexed by class. * Return true if we always can find a color. */ int COLORMAP(int c, int *r) { int num = 0; switch (c) { case CLASSA: num = (r[CLASSA]+r[CLASSB]) < AREGCNT; break; case CLASSB: num = (r[CLASSB]+r[CLASSA]) < BREGCNT; break; case CLASSC: num = r[CLASSC] < CREGCNT; break; case CLASSD: num = r[CLASSD] < DREGCNT; break; case CLASSE: num = r[CLASSE] < EREGCNT; break; } return num; } char *rnames[] = { "0", "1", "2", "3", "2", "3", "cfp", "csp" }; /* * Return a class suitable for a specific type. */ int gclass(TWORD t) { return ISPTR(t) ? CLASSB : CLASSA; } /* * Calculate argument sizes. */ void lastcall(NODE *p) { NODE *op = p; int size = 0; p->n_qual = 0; if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) return; for (p = p->n_right; p->n_op == CM; p = p->n_left) { if (p->n_right->n_op != ASSIGN) size += szty(p->n_right->n_type); } if (p->n_op != ASSIGN) size += szty(p->n_type); op->n_qual = size; /* XXX */ if (maxargsz < size) maxargsz = size; } /* * Special shapes. */ int special(NODE *p, int shape) { switch (shape) { case SLDFPSP: return regno(p) == FPREG || regno(p) == STKREG; } return SRNOPE; } /* * Target-dependent command-line options. */ void mflags(char *str) { } /* * Do something target-dependent for xasm arguments. * Supposed to find target-specific constraints and rewrite them. */ int myxasm(struct interpass *ip, NODE *p) { return 0; } #ifdef MYSTOREMOD void storemod(NODE *q, int off, int reg) { NODE *l, *r, *p; if (off < MAXZP*2) { q->n_op = NAME; q->n_name = ""; setlval(q, -off/2 + ZPOFF); } else { l = mklnode(REG, 0, reg, INCREF(q->n_type)); r = mklnode(ICON, off, 0, INT); p = mkbinode(PLUS, l, r, INCREF(q->n_type)); q->n_op = UMUL; q->n_left = p; } q->n_rval = q->n_su = 0; } #endif pcc-20181216/arch/nova/macdefs.h010064400017500000000000000125411273421107200151210ustar raggewheel/* $Id: macdefs.h,v 1.12 2016/06/27 11:47:06 ragge Exp $ */ /* * Copyright (c) 2006 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Machine-dependent defines for Data General Nova. */ /* * Convert (multi-)character constant to integer. */ #define makecc(val,i) lastcon = (lastcon<<8)|(val); /* * Storage space requirements */ #define SZCHAR 8 #define SZBOOL 8 #define SZINT 16 #define SZFLOAT 32 #define SZDOUBLE 64 #define SZLDOUBLE 64 #define SZLONG 32 #define SZSHORT 16 #define SZLONGLONG 64 #define SZPOINT(t) 16 /* Actually 15 */ /* * Alignment constraints */ #define ALCHAR 8 #define ALBOOL 8 #define ALINT 16 #define ALFLOAT 16 #define ALDOUBLE 16 #define ALLDOUBLE 16 #define ALLONG 16 #define ALLONGLONG 16 #define ALSHORT 16 #define ALPOINT 16 #define ALSTRUCT 16 #define ALSTACK 16 /* * Min/max values. */ #define MIN_CHAR -128 #define MAX_CHAR 127 #define MAX_UCHAR 255 #define MIN_SHORT -32768 #define MAX_SHORT 32767 #define MAX_USHORT 65535 #define MIN_INT MIN_SHORT #define MAX_INT MAX_SHORT #define MAX_UNSIGNED MAX_USHORT #define MIN_LONG 0x80000000L #define MAX_LONG 0x7fffffffL #define MAX_ULONG 0xffffffffUL #define MIN_LONGLONG 0x8000000000000000LL #define MAX_LONGLONG 0x7fffffffffffffffLL #define MAX_ULONGLONG 0xffffffffffffffffULL /* Default char is unsigned */ #define CHAR_UNSIGNED #define WORD_ADDRESSED #define BOOL_TYPE UCHAR #define MYALIGN /* provide private alignment function */ /* * Use large-enough types. */ typedef long CONSZ; typedef unsigned long U_CONSZ; typedef long OFFSZ; #define CONFMT "0%lo" /* format for printing constants */ #define LABFMT "L%d" /* format for printing labels */ #define STABLBL "LL%d" /* format for stab (debugging) labels */ #define BACKAUTO /* stack grows negatively for automatics */ #define BACKTEMP /* stack grows negatively for temporaries */ #define ARGINIT 16 /* first arg at 0 offset */ #define AUTOINIT 32 /* first var below 32-bit offset */ #undef FIELDOPS /* no bit-field instructions */ #define TARGET_ENDIAN TARGET_BE /* Definitions mostly used in pass2 */ #define BYTEOFF(x) ((x)&01) #define wdal(k) (BYTEOFF(k)==0) #define szty(t) ((t) == DOUBLE || (t) == LDOUBLE || \ (t) == LONGLONG || (t) == ULONGLONG ? 4 : \ ((t) == LONG || (t) == ULONG || (t) == FLOAT) ? 2 : 1) /* * The Nova has two register classes. Note that the space used in * zero page is considered stack. * Register 6 and 7 are FP and SP (in zero page). * * The classes used on Nova are: * A - AC0-AC3 (as non-index registers) : reg 0-3 * B - AC2-AC3 (as index registers) : reg 4-5 * FP/SP as 6/7. */ #define AC0 0 #define AC1 1 #define AC2 2 #define AC3 3 #define MAXREGS 8 /* 0-29 */ #define RSTATUS \ SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ SBREG|TEMPREG, SBREG|TEMPREG, 0, 0 #define ROVERLAP \ { -1 }, { -1 }, { 4, -1 }, { 5, -1 }, { 2, -1 }, { 3, -1 }, \ { -1 }, { -1 } /* Return a register class based on the type of the node */ /* Used in tshape, avoid matching fp/sp as reg */ #define PCLASS(p) (p->n_op == REG && regno(p) > 5 ? 0 : \ ISPTR(p->n_type) ? SBREG : SAREG) #define NUMCLASS 2 /* highest number of reg classes used */ int COLORMAP(int c, int *r); #define GCLASS(x) (x < 4 ? CLASSA : CLASSB) #define DECRA(x,y) (((x) >> (y*6)) & 63) /* decode encoded regs */ #define ENCRD(x) (x) /* Encode dest reg in n_reg */ #define ENCRA1(x) ((x) << 6) /* A1 */ #define ENCRA2(x) ((x) << 12) /* A2 */ #define ENCRA(x,y) ((x) << (6+y*6)) /* encode regs in int */ #define RETREG(x) (0) /* ? Sanity */ #define FPREG 6 /* frame pointer */ #define STKREG 7 /* stack pointer */ #define MAXZP 030 /* number of locations used as stack */ #define ZPOFF 050 /* offset of zero page regs */ #ifdef os_none #define MYINSTRING #endif #undef MYSTOREMOD #define MYLONGTEMP(p,w) { \ if (w->r_class == 0) { \ w->r_color = freetemp(szty(p->n_type)); \ w->r_class = FPREG; \ } \ if (w->r_color < MAXZP*2) { /* color in bytes */ \ p->n_op = NAME; \ setlval(p, w->r_color/2 + ZPOFF); \ p->n_name = ""; \ break; \ } \ } /* * special shapes for sp/fp. */ #define SLDFPSP (MAXSPECIAL+1) /* load fp or sp */ pcc-20181216/arch/nova/order.c010064400017500000000000000101021273421107200146140ustar raggewheel/* $Id: order.c,v 1.7 2016/06/27 11:47:06 ragge Exp $ */ /* * Copyright (c) 2006 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass2.h" #include int canaddr(NODE *); /* is it legal to make an OREG or NAME entry which has an * offset of off, (from a register of r), if the * resulting thing had type t */ int notoff(TWORD t, int r, CONSZ off, char *cp) { if (r != 4 && r != 5) return 1; /* can only index ac2 and ac3 */ #if 0 if (t == CHAR || t == UCHAR) { if (off < -256 || off > 254) return 1; } else #endif if (off < -128 || off > 127) return 1; return(0); /* YES */ } /* * Turn a UMUL-referenced node into OREG. * Be careful about register classes, this is a place where classes change. */ void offstar(NODE *p, int shape) { NODE *r; if (x2debug) printf("offstar(%p)\n", p); if (regno(p) == 4 || regno(p) == 5) return; /* Is already OREG */ r = p->n_right; if ((p->n_op == PLUS || p->n_op == MINUS) && r->n_op == ICON) { if (!isreg(p->n_left) || (regno(p->n_left) != 4 && regno(p->n_left) != 5)) (void)geninsn(p->n_left, INBREG); return; } (void)geninsn(p, INBREG); } /* * Do the actual conversion of offstar-found OREGs into real OREGs. */ void myormake(NODE *q) { if (x2debug) printf("myormake(%p)\n", q); } /* * Shape matches for UMUL. Cooperates with offstar(). */ int shumul(NODE *p, int shape) { if (x2debug) printf("shumul(%p)\n", p); /* Turns currently anything into OREG on x86 */ if (shape & SOREG) return SROREG; return SRNOPE; } /* * Rewrite operations on binary operators (like +, -, etc...). * Called as a result of table lookup. */ int setbin(NODE *p) { if (x2debug) printf("setbin(%p)\n", p); return 0; } /* setup for assignment operator */ int setasg(NODE *p, int cookie) { if (x2debug) printf("setasg(%p)\n", p); return(0); } /* setup for unary operator */ int setuni(NODE *p, int cookie) { return 0; } /* * Special handling of some instruction register allocation. */ struct rspecial * nspecial(struct optab *q) { switch (q->op) { case UMUL: { static struct rspecial s[] = { { NLEFT, 4 }, { NRES, AC0 }, { NEVER, AC3 }, { NEVER, AC0 }, }; return s; } } comperr("nspecial entry %d", q - table); return 0; /* XXX gcc */ } /* * Set evaluation order of a binary node if it differs from default. */ int setorder(NODE *p) { return 0; } /* * Set registers "live" at function calls (like arguments in registers). * This is for liveness analysis of registers. */ int * livecall(NODE *p) { static int r[1] = { -1 }; /* Terminate with -1 */ return &r[0]; } /* * Signal whether the instruction is acceptable for this target. */ int acceptable(struct optab *op) { return 1; } pcc-20181216/arch/nova/table.c010064400017500000000000000127041273421107200146020ustar raggewheel/* $Id: table.c,v 1.4 2016/06/27 11:47:06 ragge Exp $ */ /* * Copyright (c) 2006 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass2.h" # define ANYSIGNED TINT|TLONG|TSHORT|TCHAR # define ANYUSIGNED TUNSIGNED|TULONG|TUSHORT|TUCHAR # define ANYFIXED ANYSIGNED|ANYUSIGNED # define ANYREG (INAREG|INBREG|INCREG) # define TUWORD TUNSIGNED|TULONG # define TSWORD TINT|TLONG # define TWORD TUWORD|TSWORD struct optab table[] = { /* First entry must be an empty entry */ { -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", }, /* * Conversions. */ /* uchar to (u)int */ { SCONV, INAREG, SAREG, TUCHAR, SAREG, TINT|TUNSIGNED, 0, RLEFT, "", }, /* * All ASSIGN entries. */ /* reg->reg */ { ASSIGN, FOREFF|INAREG|INBREG, SAREG|SBREG, TWORD|TPOINT, SAREG|SBREG, TWORD|TPOINT, 0, RDEST, " mov AR,AL\n", }, /* reg->mem */ { ASSIGN, FOREFF|INAREG|INBREG, SNAME|SOREG, TWORD|TPOINT, SAREG|SBREG, TWORD|TPOINT, 0, RDEST, " sta AR,AL\n", }, /* mem->reg */ { ASSIGN, FOREFF|INAREG|INBREG, SAREG|SBREG, TWORD|TPOINT, SNAME|SOREG, TWORD|TPOINT, 0, RDEST, " lda AL,AR\n", }, /* * LEAF type movements. */ /* 0 -> reg */ { OPLTYPE, INAREG|INBREG, SANY, TANY, SZERO, TWORD, NAREG, RESC1, " subo A1,A1\n", }, /* 1 -> reg */ { OPLTYPE, INAREG|INBREG, SANY, TANY, SONE, TWORD, NAREG|NBREG, RESC1, " subzl A1,A1\n", }, /* constant -> reg */ { OPLTYPE, INAREG|INBREG, SANY, TANY, SCON, TWORD|TPOINT, NAREG|NBREG, RESC1, " lda A1,AR\n", }, /* mem -> reg */ { OPLTYPE, INAREG, SANY, TANY, SNAME|SOREG, TWORD, NAREG, RESC1, " lda A1,AR\n", }, /* reg -> A-reg */ { OPLTYPE, INAREG, SANY, TANY, SAREG|SBREG, TWORD, NAREG, RESC1, " mov AR,A1\n", }, /* reg -> B-reg */ { OPLTYPE, INBREG, SANY, TANY, SAREG|SBREG, TWORD|TPOINT, NBREG, RESC1, " mov AR,A1\n", }, { OPLTYPE, INBREG, SANY, TANY, SNAME|SOREG, TPOINT, NBREG, RESC1, " lda A1,AR\n", }, { OPLTYPE, INBREG, SANY, TANY, SLDFPSP, TANY, NBREG, RESC1, " lda A1,AR\n", }, /* * Simple ops. */ { PLUS, INBREG|INAREG, SAREG|SBREG, TWORD|TPOINT, SONE, TANY, 0, RLEFT, " inc AL,AL\n", }, { OPSIMP, INBREG|INAREG|FOREFF, SAREG|SBREG, TWORD|TPOINT, SAREG|SBREG, TWORD|TPOINT, 0, RLEFT, " O AR,AL\n", }, /* * Indirections */ #ifdef nova4 { UMUL, INAREG, SANY, TPTRTO|TCHAR|TUCHAR, SOREG|SAREG|SBREG|SNAME, TCHAR|TUCHAR, NAREG|NASL, RESC1, " ldb A1,AL\n", }, #endif { UMUL, INAREG, SANY, TPTRTO|TUCHAR, SOREG, TUCHAR, NSPECIAL|NAREG, RESC1, " jsr @lbyt\n", }, { UMUL, INAREG, SANY, TPTRTO|TCHAR, SOREG, TCHAR, NSPECIAL|NAREG, RESC1, " jsr @lsbyt\n", }, { UMUL, INAREG, SANY, TPOINT|TWORD, SOREG, TPOINT|TWORD, NAREG|NASL, RESC1, " lda A1,AL\n", }, { UMUL, INBREG, SANY, TPOINT|TWORD, SOREG, TPOINT|TWORD, NBREG|NBSL, RESC1, " lda A1,AL\n", }, /* * logops */ { EQ, FOREFF, SAREG|SBREG, TANY, SZERO, TANY, 0, RNOP, " mov# AL,AL,snr\n jmp LC\n", }, { EQ, FOREFF, SAREG|SBREG, TANY, SAREG|SBREG, TANY, 0, RNOP, " sub# AL,AR,snr\n jmp LC\n", }, { NE, FOREFF, SAREG|SBREG, TANY, SZERO, TANY, 0, RNOP, " mov# AL,AL,szr\n jmp LC\n", }, { NE, FOREFF, SAREG|SBREG, TANY, SAREG|SBREG, TANY, 0, RNOP, " sub# AL,AR,szr\n jmp LC\n", }, /* * Subroutine calls. */ { CALL, FOREFF, SCON, TANY, SANY, TANY, 0, 0, " jsr @CL\n", }, { UCALL, FOREFF, SCON, TANY, SANY, TANY, 0, 0, " jsr @CL\n", }, { CALL, INAREG|FOREFF, SCON, TANY, SANY, TANY, NAREG|NASL, RESC1, " jsr @CL\n", }, { UCALL, INAREG|FOREFF, SCON, TANY, SANY, TANY, NAREG|NASL, RESC1, " jsr @CL\n", }, { GOTO, FOREFF, SCON, TANY, SANY, TANY, 0, RNOP, " jmp @LL\n", }, { FUNARG, FOREFF, SAREG|SBREG, TCHAR|TUCHAR|TWORD|TPOINT, SANY, TCHAR|TUCHAR|TWORD|TPOINT, NBREG, RNULL, " lda A1,csp\n sta AL,ZB\n", }, # define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,"" { UMUL, DF( UMUL ), }, { ASSIGN, DF(ASSIGN), }, { STASG, DF(STASG), }, { FLD, DF(FLD), }, { OPLEAF, DF(NAME), }, { OPUNARY, DF(UMINUS), }, { OPANY, DF(BITYPE), }, { FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" }, }; int tablesize = sizeof(table)/sizeof(table[0]); pcc-20181216/arch/pdp10004075500017500000000000000000001340533064000132475ustar raggewheelpcc-20181216/arch/pdp10/CVS004075500017500000000000000000001340533064000137025ustar raggewheelpcc-20181216/arch/pdp10/CVS/Root010064400017500000000000000000111340533064000146140ustar raggewheel/cvsroot pcc-20181216/arch/pdp10/CVS/Repository010064400017500000000000000000171340533064000160560ustar raggewheelpcc/arch/pdp10 pcc-20181216/arch/pdp10/CVS/Entries010064400017500000000000000004421340533064000153120ustar raggewheel/README/1.1/Mon Nov 12 19:00:04 2007// /code.c/1.43/Sat Feb 18 15:43:48 2017// /local.c/1.79/Sat Feb 18 15:43:48 2017// /local2.c/1.108/Sat Feb 18 15:43:48 2017// /macdefs.h/1.36/Sat Mar 5 15:53:04 2016// /order.c/1.64/Sat Feb 18 15:43:48 2017// /table.c/1.98/Sat Feb 18 15:43:48 2017// D pcc-20181216/arch/pdp10/README010064400017500000000000000013271071612126400142100ustar raggewheel PDP10 C calling convention -------------------------- Register 1-7 are argument registers. Types of sizes up to 36 bits are given in one register, two otherwise. CHAR and SHORT are given as INTs. If the argument that would end up in register 7 requires two registers, it is saved on the stack instead and no more registers would end up on the stack. struct return: a hidden argument containing the address of the struct is stored as the first argument _on_the_stack_, never in register. struct argument: always saved on stack, and terminates the list of arguments that are kept in registers. In case of debugging all arguments are saved on stack in the function. All variadic arguments are always saved on the stack. pcc-20181216/arch/pdp10/code.c010064400017500000000000000114571305206566400144220ustar raggewheel/* $Id: code.c,v 1.43 2017/02/18 15:43:48 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass1.h" #ifdef LANG_CXX #define p1listf listf #define p1tfree tfree #else #define NODE P1ND #define talloc p1alloc #endif /* * Define everything needed to print out some data (or text). * This means segment, alignment, visibility, etc. */ void defloc(struct symtab *sp) { char *nextsect = NULL; /* notyet */ static char *loctbl[] = { "text", "data", "section .rodata" }; static int lastloc = -1; TWORD t; int s; if (sp == NULL) { lastloc = -1; return; } t = sp->stype; s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? RDATA : DATA; if (nextsect) { printf(" .section %s\n", nextsect); nextsect = NULL; s = -1; } else if (s != lastloc) printf(" .%s\n", loctbl[s]); lastloc = s; if (sp->sclass == EXTDEF) printf(" .globl %s\n", getexname(sp)); if (sp->slevel == 0) printf("%s:\n", getexname(sp)); else printf(LABFMT ":\n", sp->soffset); } /* * code for the end of a function */ void efcode(void) { } /* * code for the beginning of a function; a is an array of * indices in stab for the arguments; n is the number */ void bfcode(struct symtab **sp, int cnt) { NODE *p, *q; int i, n; if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { uerror("no struct return yet"); } /* recalculate the arg offset and create TEMP moves */ for (n = 1, i = 0; i < cnt; i++) { if (n < 8) { p = tempnode(0, sp[i]->stype, sp[i]->sdf, sp[i]->sap); q = block(REG, NIL, NIL, sp[i]->stype, sp[i]->sdf, sp[i]->sap); q->n_rval = n; p = buildtree(ASSIGN, p, q); sp[i]->soffset = regno(p->n_left); sp[i]->sflags |= STNODE; ecomp(p); } else { sp[i]->soffset += SZINT * n; if (xtemps) { /* put stack args in temps if optimizing */ p = tempnode(0, sp[i]->stype, sp[i]->sdf, sp[i]->sap); p = buildtree(ASSIGN, p, nametree(sp[i])); sp[i]->soffset = regno(p->n_left); sp[i]->sflags |= STNODE; ecomp(p); } } n += szty(sp[i]->stype); } } void bjobcode(void) { } /* called just before final exit */ /* flag is 1 if errors, 0 if none */ void ejobcode(int flag) { } /* * Make a register node, helper for funcode. */ static NODE * mkreg(NODE *p, int n) { NODE *r; r = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap); if (szty(p->n_type) == 2) n += 16; r->n_rval = n; return r; } static int regnum; /* * Move args to registers and emit expressions bottom-up. */ static void fixargs(NODE *p) { NODE *r; if (p->n_op == CM) { fixargs(p->n_left); r = p->n_right; if (r->n_op == STARG) regnum = 9; /* end of register list */ else if (regnum + szty(r->n_type) > 8) p->n_right = block(FUNARG, r, NIL, r->n_type, r->n_df, r->n_ap); else p->n_right = buildtree(ASSIGN, mkreg(r, regnum), r); } else { if (p->n_op == STARG) { regnum = 9; /* end of register list */ } else { r = talloc(); *r = *p; r = buildtree(ASSIGN, mkreg(r, regnum), r); *p = *r; p1nfree(r); } r = p; } regnum += szty(r->n_type); } /* * Called with a function call with arguments as argument. * This is done early in buildtree() and only done once. */ NODE * funcode(NODE *p) { regnum = 1; fixargs(p->n_right); return p; } /* fix up type of field p */ void fldty(struct symtab *p) { } /* * XXX - fix genswitch. */ int mygenswitch(int num, TWORD type, struct swents **p, int n) { return 0; } pcc-20181216/arch/pdp10/local.c010064400017500000000000000440431305206566400145770ustar raggewheel/* $Id: local.c,v 1.79 2017/02/18 15:43:48 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass1.h" #undef NIL #define NIL NULL #ifdef LANG_CXX #define P1ND NODE #define p1nfree nfree #define p1fwalk fwalk #define p1tcopy tcopy #else #define NODE P1ND #define nfree p1nfree #define fwalk p1fwalk #define tcopy p1tcopy #endif #define n_sue n_ap /* this file contains code which is dependent on the target machine */ static int pointp(TWORD t); static struct symtab *newfun(char *name, TWORD type); #define PTRNORMAL 1 #define PTRCHAR 2 #define PTRSHORT 3 static int xptype(TWORD t); NODE * clocal(NODE *p) { /* this is called to do local transformations on an expression tree preparitory to its being written out in intermediate code. */ /* the major essential job is rewriting the automatic variables and arguments in terms of REG and OREG nodes */ /* conversion ops which are not necessary are also clobbered here */ /* in addition, any special features (such as rewriting exclusive or) are easily handled here as well */ register struct symtab *q; register NODE *r, *l, *oop; register int o; register int m, ml; int siz; #ifdef PCC_DEBUG if (xdebug) { printf("clocal: %p\n", p); fwalk(p, eprint, 0); } #endif switch( o = p->n_op ){ case NAME: if ((q = p->n_sp) == NULL) return p; /* Nothing to care about */ switch (q->sclass) { case PARAM: /* First 7 parameters are in registers */ /* XXX last may be double */ if (q->soffset/SZINT < 7) { p->n_op = REG; p->n_rval = q->soffset/SZINT; break; } else q->soffset -= 7*SZINT; case AUTO: /* fake up a structure reference */ if (q->stype == CHAR || q->stype == UCHAR || q->stype == SHORT || q->stype == USHORT) r = block(REG, NIL, NIL, PTR+q->stype, 0, 0); else r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); slval(r, 0); r->n_rval = FPREG; p = stref(block(STREF, r, p, 0, 0, 0)); break; case STATIC: if (q->slevel == 0) break; slval(p, 0); break; case REGISTER: p->n_op = REG; slval(p, 0); p->n_rval = q->soffset; break; } break; case CALL: /* avoid recursive calls */ r = tempnode(0, p->n_type, p->n_df, p->n_sue); l = tempnode(regno(r), p->n_type, p->n_df, p->n_sue); ecomp(buildtree(ASSIGN, r, p)); p = l; break; case PCONV: l = p->n_left; /* * Handle frame pointer directly without conversion, * for efficiency. */ if (l->n_op == REG && l->n_rval == 0) { rmpc: l->n_type = p->n_type; l->n_df = p->n_df; l->n_sue = p->n_sue; nfree(p); return l; } /* Convert ICON with name to new type */ if (l->n_op == ICON && l->n_sp != NULL && l->n_type == INCREF(STRTY) && (p->n_type == INCREF(CHAR) || p->n_type == INCREF(UCHAR) || p->n_type == INCREF(SHORT) || p->n_type == INCREF(USHORT))) { int j = (BTYPE(p->n_type) == CHAR || BTYPE(p->n_type) == UCHAR ? 4 : 2); slval(l, glval(l) * j); goto rmpc; } /* Convert only address constants, never convert other */ if (l->n_op == ICON) { if (l->n_sp == NULL) goto rmpc; if (p->n_type == INCREF(CHAR) || p->n_type == INCREF(UCHAR) || p->n_type == INCREF(VOID)) slval(l, (glval(l) & 07777777777) | 0700000000000LL); else if (p->n_type == INCREF(SHORT) || p->n_type == INCREF(USHORT)) slval(l, (glval(l) & 07777777777) | 0750000000000LL); else slval(l, (glval(l) & 07777777777)); goto rmpc; } /* Remove more conversions of identical pointers */ /* Be careful! optim() may do bad things */ if (ISPTR(DECREF(p->n_type))) { if (ISPTR(DECREF(l->n_type))) { if ((coptype(l->n_op) == UTYPE || coptype(l->n_op) == BITYPE) && (l->n_left->n_op == REG)) l->n_left->n_type = p->n_type; goto rmpc; } } /* Change PCONV from int to double pointer to right shift */ if (ISPTR(p->n_type) && ISPTR(DECREF(p->n_type)) && (l->n_type == INT || l->n_type == UNSIGNED)) { p->n_op = RS; p->n_right = bcon(2); break; } /* Check for cast integral -> pointer */ if (BTYPE(l->n_type) == l->n_type) break; /* Remove conversions to identical pointers */ switch (xptype(p->n_type)) { case PTRNORMAL: if (xptype(l->n_type) == PTRNORMAL) goto rmpc; break; case PTRSHORT: if (xptype(l->n_type) == PTRSHORT) goto rmpc; break; case PTRCHAR: if (xptype(l->n_type) == PTRCHAR) goto rmpc; break; } break; case SCONV: l = p->n_left; if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 && tsize(p->n_type, p->n_df, p->n_ap) == tsize(l->n_type, l->n_df, l->n_ap)) { if (p->n_type != FLOAT && p->n_type != DOUBLE && l->n_type != FLOAT && l->n_type != DOUBLE) { nfree(p); return l; } } /* cast to (void) XXX should be removed in MI code */ if (p->n_type == VOID) { nfree(p); return l; } m = p->n_type; ml = l->n_type; if (m == ml) { nfree(p); return l; } o = l->n_op; if (ml == FLOAT || ml == DOUBLE) { if (o != FCON) break; ml = ISUNSIGNED(m) ? UNSIGNED : INT; /* LONG? */ r = xbcon(ml == INT ? (int)p->n_left->n_dcon : (unsigned)p->n_left->n_dcon, NULL, ml); nfree(p->n_left); p->n_left = r; o = ICON; if (m == ml) { r = p->n_left; nfree(p); return r; } } if (o == ICON) { CONSZ val = glval(l); switch (m) { case CHAR: slval(l, val & 0777); if (val & 0400) slval(l, glval(l) | ~((CONSZ)0777)); break; case UCHAR: slval(l, val & 0777); break; case USHORT: slval(l, val & 0777777); break; case SHORT: slval(l, val & 0777777); if (val & 0400000) slval(l, glval(l) | ~((CONSZ)0777777)); break; case UNSIGNED: slval(l, val & 0777777777777LL); break; case INT: slval(l, val & 0777777777777LL); if (val & 0400000000000LL) slval(l, glval(l) | ~(0777777777777LL)); break; case LONGLONG: /* XXX */ case ULONGLONG: slval(l, val); break; case VOID: break; case DOUBLE: case FLOAT: l->n_op = FCON; l->n_dcon = 0; break; default: cerror("unknown type %d", m); } l->n_type = m; l->n_sue = 0; nfree(p); return l; } break; case PMCONV: case PVCONV: /* if( p->n_right->n_op != ICON ) cerror( "bad conversion", 0); */ nfree(p); return(buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right)); case RS: case RSEQ: /* convert >> to << with negative shift count */ /* Beware! constant shifts will be converted back in optim() */ if (p->n_right->n_op != UMINUS) { p->n_right = buildtree(UMINUS, p->n_right, NIL); } else { r = p->n_right; p->n_right = p->n_right->n_left; nfree(r); } if (p->n_op == RS) p->n_op = LS; else p->n_op = LSEQ; break; case UMUL: /* Convert structure assignment to memcpy() */ if (p->n_left->n_op == PLUS && p->n_left->n_left->n_op == PCONV && p->n_left->n_right->n_op == ICON && (p->n_type == CHAR || p->n_type == UCHAR || p->n_type == SHORT || p->n_type == USHORT)) { /* Can remove the left SCONV */ l = p->n_left->n_left; p->n_left->n_left = l->n_left; nfree(l); break; } if (p->n_left->n_op != STASG) break; oop = p; p = p->n_left; siz = tsize(p->n_type, p->n_df, p->n_ap)/SZCHAR; l = p->n_left; r = p->n_right; if (l->n_type == STRTY || l->n_type == UNIONTY) { if (l->n_op == UMUL) { p->n_left = l->n_left; nfree(l); l = p->n_left; } else { l = block(ADDROF, l, NIL, INCREF(l->n_type), 0, 0); } } if ((l->n_type != (STRTY+PTR) && l->n_type != (UNIONTY+PTR)) || (r->n_type != (STRTY+PTR) && r->n_type != (UNIONTY+PTR))) cerror("bad stasg, l = %o, r = %o", l->n_type, r->n_type); q = newfun("__structcpy", p->n_type); /* structure pointer block */ l = block(CM, l, r, INT, 0, 0); /* Size block */ r = block(CM, l, bcon(siz), INT, 0, 0); l = xbcon(0, q, q->stype); p->n_left = l; p->n_right = r; p->n_op = CALL; oop->n_left = p; return oop; case FORCE: p->n_op = ASSIGN; p->n_right = p->n_left; p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0); p->n_left->n_rval = RETREG(p->n_type); break; } return(p); } void myp2tree(NODE *p) { NODE *r; switch (p->n_op) { case ULT: /* exor sign bit to avoid unsigned comparitions */ case ULE: case UGT: case UGE: if (ISLONGLONG(p->n_left->n_type)) { /* XXX */ r = xbcon(0x8000000000000000ULL, NULL, LONGLONG); } else r = xbcon(0400000000000LL, NULL, INT); p->n_left = buildtree(ER, p->n_left, r); if (ISUNSIGNED(p->n_left->n_type)) p->n_left->n_type = DEUNSIGN(p->n_left->n_type); if (ISLONGLONG(p->n_right->n_type)) { /* XXX */ r = xbcon(0x8000000000000000ULL, NULL, LONGLONG); } else r = xbcon(0400000000000LL, NULL, INT); p->n_right = buildtree(ER, p->n_right, r); if (ISUNSIGNED(p->n_right->n_type)) p->n_right->n_type = DEUNSIGN(p->n_right->n_type); p->n_op -= (ULT-LT); break; case FCON: cerror("fix float constants"); } } struct symtab * newfun(char *name, TWORD type) { struct symtab *sp; sp = lookup(name, 0); if (sp->stype == VOID) { sp->stype = INCREF(type | FTN); sp->sclass = EXTERN; sp->soffset = 0; } #ifdef notdef else if (!ISFTN(DECREF(sp->stype))) uerror("reserved name '%s' used illegally", name); #endif return sp; } /*ARGSUSED*/ int andable(NODE *p) { return(1); /* all names can have & taken on them */ } /* * is an automatic variable of type t OK for a register variable * Everything is trusted to be in register here. */ int cisreg(TWORD t) { return(1); } int xptype(TWORD t) { int tt = BTYPE(t); int e, rv; if (!ISPTR(t)) cerror("not a pointer"); e = t & ~BTMASK; rv = e; while (e) { rv = e; if (DECREF(e) == 0) break; e = DECREF(e); } if (ISFTN(rv)) return PTRNORMAL; switch (tt) { case INT: case LONG: case LONGLONG: case FLOAT: case DOUBLE: case STRTY: case UNIONTY: case UNSIGNED: case ULONG: case ULONGLONG: return PTRNORMAL; case VOID: case CHAR: case UCHAR: if (DECREF(t) == tt || ISARY(rv)) return PTRCHAR; return PTRNORMAL; case SHORT: case USHORT: if (DECREF(t) == tt || ISARY(rv)) return PTRSHORT; return PTRNORMAL; default: break; } cerror("unknown type"); return PTRNORMAL; /* XXX */ } /* * Help routine to the one below; return true if it's not a word pointer. */ static int pointp(TWORD t) { int rv = 0; if (ISPTR(t) && ((t & TMASK1) == 0)) return 1; t &= ~BTMASK; while (t) { rv = ISARY(t); t = DECREF(t); } return rv; } /* * return a node, for structure references, which is suitable for * being added to a pointer of type t, in order to be off bits offset * into a structure * t, d, and s are the type, dimension offset, and sizeoffset * For pdp10, return the type-specific index number which calculation * is based on its size. For example, short a[3] would return 3. * Be careful about only handling first-level pointers, the following * indirections must be fullword. */ NODE * offcon(OFFSZ off, TWORD t, union dimfun *d, struct attr *ap) { register NODE *p; if (xdebug) printf("offcon: OFFSZ %lld type %x dim %p siz %d\n", off, t, d, 0); p = bcon(0); slval(p, off/SZINT); /* Default */ if (ISPTR(DECREF(t))) return p; /* Pointer/pointer reference */ switch (BTMASK & t) { case INT: case UNSIGNED: case LONG: case ULONG: case STRTY: case UNIONTY: case LONGLONG: case ULONGLONG: case FLOAT: case DOUBLE: break; case SHORT: case USHORT: if (pointp(t)) slval(p, off/SZSHORT); break; case VOID: /* void pointers */ case CHAR: case UCHAR: if (pointp(t)) slval(p, off/SZCHAR); break; default: cerror("offcon, off %llo size %d type %x", off, 0, t); } if (xdebug) printf("offcon return 0%llo\n", glval(p)); return(p); } /* * Allocate off bits on the stack. p is a tree that when evaluated * is the multiply count for off, t is a NAME node where to write * the allocated address. * Be aware that a pointer conversion may be needed when saving * to node t! */ void spalloc(NODE *t, NODE *p, OFFSZ off) { NODE *sp; if ((off % SZINT) == 0) p = buildtree(MUL, p, bcon(off/SZINT)); else if ((off % SZSHORT) == 0) { p = buildtree(MUL, p, bcon(off/SZSHORT)); p = buildtree(PLUS, p, bcon(1)); p = buildtree(RS, p, bcon(1)); } else if ((off % SZCHAR) == 0) { p = buildtree(MUL, p, bcon(off/SZCHAR)); p = buildtree(PLUS, p, bcon(3)); p = buildtree(RS, p, bcon(2)); } else cerror("roundsp"); /* save the address of sp */ sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_sue); slval(sp, 0); sp->n_rval = STKREG; /* Cast sp to destination type (may be redundant) */ sp = buildtree(CAST, block(NAME, NIL, NIL, t->n_type, t->n_df, t->n_ap), sp); nfree(sp->n_left); nfree(sp); sp = sp->n_right; ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */ /* add the size to sp */ sp = block(REG, NIL, NIL, p->n_type, 0, 0); slval(sp, 0); sp->n_rval = STKREG; ecomp(buildtree(PLUSEQ, sp, p)); } #if 0 static int inwd; /* current bit offsed in word */ static CONSZ word; /* word being built from fields */ /* * Generate initialization code for assigning a constant c * to a field of width sz * we assume that the proper alignment has been obtained * inoff is updated to have the proper final value * we also assume sz < SZINT */ void incode(NODE *p, int sz) { char *s; inoff += sz; if ((sz + inwd) > SZINT) cerror("incode: field > int"); word |= ((p->n_lval & ((1 << sz) - 1)) << (36 - inwd - sz)); inwd += sz; if (inoff % SZINT == 0) { s = isinlining ? permalloc(30) : tmpalloc(30); sprintf(s, "\t.long 0%llo\n", word); send_passt(IP_ASM, s); word = inwd = 0; } tfree(p); } /* output code to initialize space of size sz to the value d */ /* the proper alignment has been obtained */ /* inoff is updated to have the proper final value */ /* on the target machine, write it out in octal! */ void fincode(NODE *p, int sz) { double d = p->n_dcon; if(!nerrors) printf(" %s 0%c%.20e\n", sz == SZDOUBLE ? ".double" : ".float", sz == SZDOUBLE ? 'd' : 'f', d); inoff += sz; } void cinit(NODE *p, int sz) { NODE *l; /* * as a favor (?) to people who want to write * int i = 9600/134.5; * we will, under the proper circumstances, do * a coercion here. */ switch (p->n_type) { case INT: case UNSIGNED: l = p->n_left; if (l->n_op != SCONV || l->n_left->n_op != FCON) break; nfree(l); l = l->n_left; l->n_lval = (long)(l->n_dcon); l->n_sp = NULL; l->n_op = ICON; l->n_type = INT; p->n_left = l; break; } /* arrange for the initialization of p into a space of size sz */ /* the proper alignment has been opbtained */ /* inoff is updated to have the proper final value */ ecode( p ); inoff += sz; } /* * define n bits of zeros in a vfd */ void vfdzero(int n) { char *s; inoff += n; inwd += n; if (inoff%ALINT ==0) { s = isinlining ? permalloc(30) : tmpalloc(30); sprintf(s, "\t.long 0%llo\n", word); send_passt(IP_ASM, s); word = inwd = 0; } } #endif /* make a name look like an external name in the local machine */ char * exname(char *p) { if (p == NULL) return ""; return p; } /* * map types which are not defined on the local machine */ TWORD ctype(TWORD type) { switch (BTYPE(type)) { case LONG: MODTYPE(type,INT); break; case ULONG: MODTYPE(type,UNSIGNED); break; case LDOUBLE: MODTYPE(type,DOUBLE); break; } return (type); } #if 0 /* curid is a variable which is defined but * is not initialized (and not a function ); * This routine returns the stroage class for an uninitialized declaration */ int noinit() { return(EXTERN); } #endif void calldec(NODE *p, NODE *q) { } void extdec(struct symtab *q) { } /* make a common declaration for id, if reasonable */ void defzero(struct symtab *sp) { int off; off = tsize(sp->stype, sp->sdf, sp->sap); off = (off+(SZINT-1))/SZINT; printf(" .%scomm ", sp->sclass == STATIC ? "l" : ""); if (sp->slevel == 0) printf("%s,0%o\n", getexname(sp), off); else printf(LABFMT ",0%o\n", sp->soffset, off); } /* * set fsz bits in sequence to zero. */ void zbits(OFFSZ off, int fsz) { cerror("zbits"); } /* * Initialize a bitfield. */ void infld(CONSZ off, int fsz, CONSZ val) { // if (idebug) // printf("infld off %lld, fsz %d, val %lld inbits %d\n", // off, fsz, val, inbits); cerror("infld"); } /* * print out a constant node, may be associated with a label. * Do not free the node after use. * off is bit offset from the beginning of the aggregate * fsz is the number of bits this is referring to */ int ninval(CONSZ off, int fsz, NODE *p) { cerror("ninval"); return 0; } /* * Give target the opportunity of handling pragmas. */ int mypragma(char *str) { return 0; } /* * Called when a identifier has been declared, to give target last word. */ void fixdef(struct symtab *sp) { } void pass1_lastchance(struct interpass *ip) { } pcc-20181216/arch/pdp10/local2.c010064400017500000000000000663761305206566400146760ustar raggewheel/* $Id: local2.c,v 1.108 2017/02/18 15:43:48 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass2.h" # include void acon(FILE *, NODE *p); int argsize(NODE *p); void genargs(NODE *p); static int offlab; int offarg; static int addto; static int regoff[16]; void deflab(int label) { printf(LABFMT ":\n", label); } void prologue(struct interpass_prolog *ipp) { int i, j; if (ipp->ipp_vis) printf(" .globl %s\n", ipp->ipp_name); printf("%s:\n", ipp->ipp_name); addto = p2maxautooff; if (addto >= AUTOINIT/SZCHAR) addto -= AUTOINIT/SZCHAR; addto /= SZINT/SZCHAR; /* use words here */ printf(" push %s,%s\n",rnames[STKREG], rnames[FPREG]); printf(" move %s,%s\n", rnames[FPREG],rnames[STKREG]); for (i = p2env.p_regs[0], j = 0; i ; i >>= 1, j++) { if (i & 1) regoff[j] = addto++; } if (addto) printf(" addi %s,0%o\n", rnames[STKREG], addto); for (i = p2env.p_regs[0], j = 0; i ; i >>= 1, j++) { if (i & 1) printf(" movem %s,%d(%s)\n", rnames[j], regoff[j], rnames[STKREG]); } } void eoftn(struct interpass_prolog *ipp) { int i, j; if (ipp->ipp_ip.ip_lbl == 0) return; /* no code needs to be generated */ for (i = p2env.p_regs[0], j = 0; i ; i >>= 1, j++) { if (i & 1) printf(" move %s,%d(%s)\n", rnames[j], regoff[j], rnames[STKREG]); } printf(" move %s,%s\n", rnames[STKREG], rnames[FPREG]); printf(" pop %s,%s\n", rnames[STKREG], rnames[FPREG]); printf(" popj %s,\n", rnames[STKREG]); } #if 0 void prologue(int regs, int autos) { int i, addto; offlab = getlab2(); if (regs < 0 || autos < 0) { /* * non-optimized code, jump to epilogue for code generation. */ ftlab1 = getlab2(); ftlab2 = getlab2(); printf(" jrst L%d\n", ftlab1); printf("L%d:\n", ftlab2); } else { /* * We here know what register to save and how much to * add to the stack. */ autos = autos + (SZINT-1); addto = (autos - AUTOINIT)/SZINT + (MAXRVAR-regs); if (addto || gflag) { printf(" push %s,%s\n",rnames[017], rnames[016]); printf(" move %s,%s\n", rnames[016],rnames[017]); for (i = regs; i < MAXRVAR; i++) { int db = ((i+1) < MAXRVAR); printf(" %smovem %s,0%o(%s)\n", db ? "d" : "", rnames[i+1], i+1-regs, rnames[016]); if (db) i++; } if (addto) printf(" addi %s,0%o\n", rnames[017], addto); } else offarg = 1; } } /* * End of block. */ void eoftn(int regs, int autos, int retlab) { register OFFSZ spoff; /* offset from stack pointer */ int i; spoff = autos + (SZINT-1); if (spoff >= AUTOINIT) spoff -= AUTOINIT; spoff /= SZINT; /* return from function code */ printf("L%d:\n", retlab); if (gflag || isoptim == 0 || autos != AUTOINIT || regs != MAXRVAR) { for (i = regs; i < MAXRVAR; i++) { int db = ((i+1) < MAXRVAR); printf(" %smove %s,0%o(%s)\n", db ? "d" : "", rnames[i+1], i+1-regs, rnames[016]); if (db) i++; } printf(" move %s,%s\n", rnames[017], rnames[016]); printf(" pop %s,%s\n", rnames[017], rnames[016]); } printf(" popj %s,\n", rnames[017]); /* Prolog code */ if (isoptim == 0) { printf("L%d:\n", ftlab1); printf(" push %s,%s\n", rnames[017], rnames[016]); printf(" move %s,%s\n", rnames[016], rnames[017]); for (i = regs; i < MAXRVAR; i++) { int db = ((i+1) < MAXRVAR); printf(" %smovem %s,0%o(%s)\n", db ? "d" : "", rnames[i+1], i+1-regs, rnames[016]); spoff++; if (db) i++, spoff++; } if (spoff) printf(" addi %s,0%llo\n", rnames[017], spoff); printf(" jrst L%d\n", ftlab2); } printf(" .set " LABFMT ",0%o\n", offlab, MAXRVAR-regs); offarg = isoptim = 0; } #endif /* * add/sub/... * * Param given: * R - Register * M - Memory * C - Constant */ void hopcode(int f, int o) { cerror("hopcode: f %d %d", f, o); } char * rnames[] = { /* keyed to register number tokens */ "%0", "%1", "%2", "%3", "%4", "%5", "%6", "%7", "%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17", "%0", "%1", "%2", "%3", "%4", "%5", "%6", "%7", "%10", "%11", "%12", "%13", "%14", "%15", }; int tlen(p) NODE *p; { switch(p->n_type) { case CHAR: case UCHAR: return(1); case SHORT: case USHORT: return(SZSHORT/SZCHAR); case DOUBLE: return(SZDOUBLE/SZCHAR); case INT: case UNSIGNED: case LONG: case ULONG: return(SZINT/SZCHAR); case LONGLONG: case ULONGLONG: return SZLONGLONG/SZCHAR; default: if (!ISPTR(p->n_type)) cerror("tlen type %d not pointer"); return SZPOINT(0)/SZCHAR; } } static char * binskip[] = { "e", /* jumpe */ "n", /* jumpn */ "le", /* jumple */ "l", /* jumpl */ "ge", /* jumpge */ "g", /* jumpg */ }; /* * Extract the higher 36 bits from a longlong. */ static CONSZ gethval(CONSZ lval) { CONSZ hval = (lval >> 35) & 03777777777LL; if ((hval & 03000000000LL) == 03000000000LL) { hval |= 0777000000000LL; } else if ((hval & 03000000000LL) == 02000000000LL) { hval &= 01777777777LL; hval |= 0400000000000LL; } return hval; } /* * Do a binary comparision, and jump accordingly. */ static void twocomp(NODE *p) { int o = p->n_op; extern int negrel[]; int isscon = 0, iscon = p->n_right->n_op == ICON; if (o < EQ || o > GT) cerror("bad binary conditional branch: %s", opst[o]); if (iscon && p->n_right->n_name[0] != 0) { printf(" cam%s ", binskip[negrel[o-EQ]-EQ]); adrput(stdout, getlr(p, 'L')); putchar(','); printf("[ .long "); adrput(stdout, getlr(p, 'R')); putchar(']'); printf("\n jrst L%d\n", p->n_label); return; } if (iscon) isscon = getlval(p->n_right) >= 0 && getlval(p->n_right) < 01000000; printf(" ca%c%s ", iscon && isscon ? 'i' : 'm', binskip[negrel[o-EQ]-EQ]); adrput(stdout, getlr(p, 'L')); putchar(','); if (iscon && (isscon == 0)) { printf("[ .long "); adrput(stdout, getlr(p, 'R')); putchar(']'); } else adrput(stdout, getlr(p, 'R')); printf("\n jrst L%d\n", p->n_label); } /* * Compare byte/word pointers. * XXX - do not work for highest bit set in address */ static void ptrcomp(NODE *p) { printf(" rot "); adrput(stdout, getlr(p, 'L')); printf(",6\n"); printf(" rot "); adrput(stdout, getlr(p, 'R')); printf(",6\n"); twocomp(p); } /* * Do a binary comparision of two long long, and jump accordingly. * XXX - can optimize for constants. */ static void twollcomp(NODE *p) { int o = p->n_op; int iscon = p->n_right->n_op == ICON; int m = 0; /* XXX gcc */ if (o < EQ || o > GT) cerror("bad long long conditional branch: %s", opst[o]); /* Special strategy for equal/not equal */ if (o == EQ || o == NE) { if (o == EQ) m = getlab2(); printf(" came "); upput(getlr(p, 'L'), SZLONG); putchar(','); if (iscon) printf("[ .long "); upput(getlr(p, 'R'), SZLONG); if (iscon) putchar(']'); printf("\n jrst L%d\n", o == EQ ? m : p->n_label); printf(" cam%c ", o == EQ ? 'n' : 'e'); adrput(stdout, getlr(p, 'L')); putchar(','); if (iscon) printf("[ .long "); adrput(stdout, getlr(p, 'R')); if (iscon) putchar(']'); printf("\n jrst L%d\n", p->n_label); if (o == EQ) printf("L%d:\n", m); return; } /* First test highword */ printf(" cam%ce ", o == GT || o == GE ? 'l' : 'g'); adrput(stdout, getlr(p, 'L')); putchar(','); if (iscon) printf("[ .long "); adrput(stdout, getlr(p, 'R')); if (iscon) putchar(']'); printf("\n jrst L%d\n", p->n_label); /* Test equality */ printf(" came "); adrput(stdout, getlr(p, 'L')); putchar(','); if (iscon) printf("[ .long "); adrput(stdout, getlr(p, 'R')); if (iscon) putchar(']'); printf("\n jrst L%d\n", m = getlab2()); /* Test lowword. Only works with pdp10 format for longlongs */ printf(" cam%c%c ", o == GT || o == GE ? 'l' : 'g', o == LT || o == GT ? 'e' : ' '); upput(getlr(p, 'L'), SZLONG); putchar(','); if (iscon) printf("[ .long "); upput(getlr(p, 'R'), SZLONG); if (iscon) putchar(']'); printf("\n jrst L%d\n", p->n_label); printf("L%d:\n", m); } /* * Print the correct instruction for constants. */ static void constput(NODE *p) { CONSZ val = getlval(p->n_right); int reg = p->n_left->n_rval; /* Only numeric constant */ if (p->n_right->n_name[0] == '\0') { if (val == 0) { printf("movei %s,0", rnames[reg]); } else if ((val & 0777777000000LL) == 0) { printf("movei %s,0%llo", rnames[reg], val); } else if ((val & 0777777) == 0) { printf("hrlzi %s,0%llo", rnames[reg], val >> 18); } else { printf("move %s,[ .long 0%llo]", rnames[reg], szty(p->n_right->n_type) > 1 ? val : val & 0777777777777LL); } /* Can have more tests here, hrloi etc */ return; } else { printf("xmovei %s,%s", rnames[reg], p->n_right->n_name); if (val) printf("+" CONFMT, val); } } /* * Return true if the constant can be bundled in an instruction (immediate). */ static int oneinstr(NODE *p) { if (p->n_name[0] != '\0') return 0; if ((getlval(p) & 0777777000000ULL) != 0) return 0; return 1; } /* * Emit a halfword or byte instruction, from OREG to REG. * Sign extension must also be done here. */ static void emitshort(NODE *p) { CONSZ off = getlval(p); TWORD type = p->n_type; int reg = p->n_rval; int issigned = !ISUNSIGNED(type); int ischar = type == CHAR || type == UCHAR; int reg1 = getlr(p, '1')->n_rval; if (off < 0) { /* argument, use move instead */ printf(" move "); } else if (off == 0 && p->n_name[0] == 0) { printf(" ldb %s,%s\n", rnames[reg1], rnames[reg]); /* XXX must sign extend here even if not necessary */ switch (type) { case CHAR: printf(" lsh %s,033\n", rnames[reg1]); printf(" ash %s,-033\n", rnames[reg1]); break; case SHORT: printf(" hrre %s,%s\n", rnames[reg1], rnames[reg1]); break; } return; } else if (ischar) { if (off >= 0700000000000LL && p->n_name[0] != '\0') { cerror("emitsh"); /* reg contains index integer */ // if (!istreg(reg)) // cerror("emitshort !istreg"); printf(" adjbp %s,[ .long 0%llo+%s ]\n", rnames[reg], off, p->n_name); printf(" ldb "); adrput(stdout, getlr(p, '1')); printf(",%s\n", rnames[reg]); goto signe; } printf(" ldb "); adrput(stdout, getlr(p, '1')); if (off) printf(",[ .long 0%02o11%02o%06o ]\n", (int)(27-(9*(off&3))), reg, (int)off/4); else printf(",%s\n", rnames[reg]); signe: if (issigned) { printf(" lsh "); adrput(stdout, getlr(p, '1')); printf(",033\n ash "); adrput(stdout, getlr(p, '1')); printf(",-033\n"); } return; } else { printf(" h%cr%c ", off & 1 ? 'r' : 'l', issigned ? 'e' : 'z'); } setlval(p, getlval(p) / (ischar ? 4 : 2)); adrput(stdout, getlr(p, '1')); putchar(','); adrput(stdout, getlr(p, 'L')); putchar('\n'); } /* * Store a short from a register. Destination is a OREG. */ static void storeshort(NODE *p) { NODE *l = p->n_left; CONSZ off = getlval(l); int reg = l->n_rval; int ischar = BTYPE(p->n_type) == CHAR || BTYPE(p->n_type) == UCHAR; if (l->n_op == NAME) { if (ischar) { printf(" dpb "); adrput(stdout, getlr(p, 'R')); printf(",[ .long 0%02o%010o+%s ]\n", 070+((int)off&3), (int)(off/4), l->n_name); return; } printf(" hr%cm ", off & 1 ? 'r' : 'l'); setlval(l, getlval(l) / 2); adrput(stdout, getlr(p, 'R')); putchar(','); adrput(stdout, getlr(p, 'L')); putchar('\n'); return; } if (off || reg == FPREG) { /* Can emit halfword instructions */ if (off < 0) { /* argument, use move instead */ printf(" movem "); } else if (ischar) { printf(" dpb "); adrput(stdout, getlr(p, '1')); printf(",[ .long 0%02o11%02o%06o ]\n", (int)(27-(9*(off&3))), reg, (int)off/4); return; } else { printf(" hr%cm ", off & 1 ? 'r' : 'l'); } setlval(l, getlval(l) / 2); adrput(stdout, getlr(p, 'R')); putchar(','); adrput(stdout, getlr(p, 'L')); } else { printf(" dpb "); adrput(stdout, getlr(p, 'R')); putchar(','); l = getlr(p, 'L'); l->n_op = REG; adrput(stdout, l); l->n_op = OREG; } putchar('\n'); } /* * Multiply a register with a constant. */ static void imuli(NODE *p) { NODE *r = p->n_right; if (getlval(r) >= 0 && getlval(r) <= 0777777) { printf(" imuli "); adrput(stdout, getlr(p, 'L')); printf(",0%llo\n", getlval(r)); } else { printf(" imul "); adrput(stdout, getlr(p, 'L')); printf(",[ .long 0%llo ]\n", getlval(r) & 0777777777777LL); } } /* * Divide a register with a constant. */ static void idivi(NODE *p) { NODE *r = p->n_right; if (getlval(r) >= 0 && getlval(r) <= 0777777) { printf(" idivi "); adrput(stdout, getlr(p, '1')); printf(",0%llo\n", getlval(r)); } else { printf(" idiv "); adrput(stdout, getlr(p, '1')); printf(",[ .long 0%llo ]\n", getlval(r) & 0777777777777LL); } } /* * move a constant into a register. */ static void xmovei(NODE *p) { /* * Trick: If this is an unnamed constant, just move it directly, * otherwise use xmovei to get section number. */ if (p->n_name[0] == '\0' || getlval(p) > 0777777) { printf(" "); zzzcode(p, 'D'); putchar(' '); adrput(stdout, getlr(p, '1')); putchar(','); zzzcode(p, 'E'); } else { printf(" xmovei "); adrput(stdout, getlr(p, '1')); printf(",%s", p->n_name); if (getlval(p) != 0) printf("+0%llo", getlval(p)); } putchar('\n'); } static void printcon(NODE *p) { CONSZ cz; p = p->n_left; if (getlval(p) >= 0700000000000LL) { /* converted to pointer in clocal() */ conput(stdout, p); return; } if (getlval(p) == 0 && p->n_name[0] == '\0') { putchar('0'); return; } if (BTYPE(p->n_type) == CHAR || BTYPE(p->n_type) == UCHAR) cz = (getlval(p)/4) | ((getlval(p) & 3) << 30); else cz = (getlval(p)/2) | (((getlval(p) & 1) + 5) << 30); cz |= 0700000000000LL; printf("0%llo", cz); if (p->n_name[0] != '\0') printf("+%s", p->n_name); } static void putcond(NODE *p) { char *c = 0; /* XXX gcc */ switch (p->n_op) { case EQ: c = "e"; break; case NE: c = "n"; break; case LE: c = "le"; break; case LT: c = "l"; break; case GT: c = "g"; break; case GE: c = "ge"; break; default: cerror("putcond"); } printf("%s", c); } void zzzcode(NODE *p, int c) { NODE *l; CONSZ hval; switch (c) { case 'A': /* ildb right arg */ adrput(stdout, p->n_left->n_left); break; case 'B': /* remove from stack after subroutine call */ if (p->n_qual) printf(" subi %%17,0%o\n", p->n_qual); break; case 'C': constput(p); break; case 'D': /* Find out which type of const load insn to use */ if (p->n_op != ICON) cerror("zzzcode not ICON"); if (p->n_name[0] == '\0') { if ((getlval(p) <= 0777777) && (getlval(p) > 0)) printf("movei"); else if ((getlval(p) & 0777777) == 0) printf("hrlzi"); else printf("move"); } else printf("move"); break; case 'E': /* Print correct constant expression */ if (p->n_name[0] == '\0') { if ((getlval(p) <= 0777777) && (getlval(p) > 0)){ printf("0%llo", getlval(p)); } else if ((getlval(p) & 0777777) == 0) { printf("0%llo", getlval(p) >> 18); } else { if (getlval(p) < 0) printf("[ .long -0%llo]", -getlval(p)); else printf("[ .long 0%llo]", getlval(p)); } } else { if (getlval(p) == 0) printf("[ .long %s]", p->n_name); else printf("[ .long %s+0%llo]", p->n_name, getlval(p)); } break; case 'G': /* structure argument */ printf(" addl %%17,0%o\n", attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)/(SZINT/SZCHAR)); printf(" foo...\n"); break; case 'P': p = getlr(p, 'R'); /* FALLTHROUGH */ case 'O': /* * Print long long expression. */ hval = gethval(getlval(p)); printf("[ .long 0%llo,0%llo", hval, (getlval(p) & 0377777777777LL) | (hval & 0400000000000LL)); if (p->n_name[0] != '\0') printf("+%s", p->n_name); printf(" ]"); break; case 'F': /* Print an "opsimp" instruction based on its const type */ hopcode(oneinstr(p->n_right) ? 'C' : 'R', p->n_op); break; case 'H': /* Print a small constant */ p = p->n_right; printf("0%llo", getlval(p) & 0777777); break; case 'Q': /* two-param long long comparisions */ twollcomp(p); break; case 'R': /* two-param conditionals */ twocomp(p); break; case 'U': emitshort(p); break; case 'V': storeshort(p); break; case 'Z': ptrcomp(p); break; case 'a': imuli(p); break; case 'b': idivi(p); break; case 'c': xmovei(p); break; case 'd': printcon(p); break; case 'e': putcond(p); break; case 'g': if (p->n_right->n_op != OREG || getlval(p->n_right) != 0) comperr("bad Zg oreg"); printf("%s", rnames[p->n_right->n_rval]); break; #if 0 case '1': /* double upput */ p = getlr(p, '1'); p->n_rval += 2; adrput(stdout, p); p->n_rval -= 2; break; #endif case 'i': /* Write instruction for short load from name */ l = getlr(p, 'L'); printf(" h%cr%c %s,%s+" CONFMT "\n", getlval(l) & 1 ? 'r' : 'l', ISUNSIGNED(p->n_type) ? 'z' : 'e', rnames[getlr(p, '1')->n_rval], l->n_name, getlval(l) >> 1); break; default: cerror("zzzcode %c", c); } } #if 0 /* set up temporary registers */ void setregs(void) { fregs = 7; /* 7 free regs on PDP10 (1-7) */ } #endif /*ARGSUSED*/ int rewfld(NODE *p) { return(1); } int fldexpand(NODE *p, int cookie, char **cp) { return 0; } int flshape(NODE *p) { register int o = p->n_op; return (o == REG || o == NAME || o == ICON || (o == OREG && (!R2TEST(p->n_rval) || tlen(p) == 1))); } /* INTEMP shapes must not contain any temporary registers */ int shtemp(NODE *p) { return(0); } int shumul(NODE *p, int order) { register int o; if (x2debug) { printf("shumul(%p)\n", p); // eprint(p, 0, &val, &val); } o = p->n_op; #if 0 if (o == NAME || (o == OREG && !R2TEST(p->n_rval)) || o == ICON) return(STARNM); #endif #if 0 if ((o == INCR) && (p->n_left->n_op == REG && p->n_right->n_op == ICON) && p->n_right->n_name[0] == '\0') { switch (p->n_type) { case CHAR|PTR: case UCHAR|PTR: o = 1; break; case SHORT|PTR: case USHORT|PTR: o = 2; break; case INT|PTR: case UNSIGNED|PTR: case LONG|PTR: case ULONG|PTR: case FLOAT|PTR: o = 4; break; case DOUBLE|PTR: case LONGLONG|PTR: case ULONGLONG|PTR: o = 8; break; default: if (ISPTR(p->n_type) && ISPTR(DECREF(p->n_type))) { o = 4; break; } else return(0); } return( 0); } #endif return( SRNOPE ); } void adrcon(CONSZ val) { cerror("adrcon: val %llo\n", val); } void conput(FILE *fp, NODE *p) { switch (p->n_op) { case ICON: if (getlval(p) != 0) { acon(fp, p); if (p->n_name[0] != '\0') fputc('+', fp); } if (p->n_name[0] != '\0') fprintf(fp, "%s", p->n_name); if (p->n_name[0] == '\0' && getlval(p) == 0) fputc('0', fp); return; case REG: fprintf(fp, "%s", rnames[p->n_rval]); return; default: cerror("illegal conput"); } } /*ARGSUSED*/ void insput(NODE *p) { cerror("insput"); } /* * Write out the upper address, like the upper register of a 2-register * reference, or the next memory location. */ void upput(NODE *p, int size) { size /= SZLONG; switch (p->n_op) { case REG: printf("%s", rnames[p->n_rval + size]); break; case NAME: case OREG: setlval(p, getlval(p) + size); adrput(stdout, p); setlval(p, getlval(p) - size); break; case ICON: printf(CONFMT, getlval(p) >> (36 * size)); break; default: cerror("upput bad op %d size %d", p->n_op, size); } } void adrput(FILE *fp, NODE *p) { int r; /* output an address, with offsets, from p */ if (p->n_op == FLD) p = p->n_left; switch (p->n_op) { case NAME: if (p->n_name[0] != '\0') fputs(p->n_name, fp); if (getlval(p) != 0) fprintf(fp, "+" CONFMT, getlval(p) & 0777777777777LL); return; case OREG: r = p->n_rval; #if 0 if (R2TEST(r)) { /* double indexing */ register int flags; flags = R2UPK3(r); if (flags & 1) putc('*', fp); if (flags & 4) putc('-', fp); if (p->n_lval != 0 || p->n_name[0] != '\0') acon(p); if (R2UPK1(r) != 100) printf("(%s)", rnames[R2UPK1(r)]); if (flags & 2) putchar('+'); printf("[%s]", rnames[R2UPK2(r)]); return; } #endif if (R2TEST(r)) cerror("adrput: unwanted double indexing: r %o", r); if (getlval(p) != FPREG && getlval(p) < 0 && p->n_name[0]) { fprintf(fp, "%s", p->n_name); acon(fp, p); fprintf(fp, "(%s)", rnames[p->n_rval]); return; } if (getlval(p) < 0 && p->n_rval == FPREG && offarg) { setlval(p, getlval(p) - (offarg-2)); acon(fp, p); setlval(p, getlval(p) + (offarg-2)); } else if (getlval(p) != 0) acon(fp, p); if (p->n_name[0] != '\0') fprintf(fp, "%s%s", getlval(p) ? "+" : "", p->n_name); if (getlval(p) > 0 && p->n_rval == FPREG && offlab) fprintf(fp, "+" LABFMT, offlab); if (getlval(p) < 0 && p->n_rval == FPREG && offarg) fprintf(fp, "(017)"); else fprintf(fp, "(%s)", rnames[p->n_rval]); return; case ICON: /* addressable value of the constant */ if (getlval(p) > 0) { acon(fp, p); if (p->n_name[0] != '\0') putc('+', fp); } if (p->n_name[0] != '\0') fprintf(fp, "%s", p->n_name); if (getlval(p) < 0) acon(fp, p); if (p->n_name[0] == '\0' && getlval(p) == 0) putc('0', fp); return; case REG: fputs(rnames[p->n_rval], fp); return; default: cerror("illegal address, op %d", p->n_op); return; } } /* * print out a constant */ void acon(FILE *fp, NODE *p) { if (getlval(p) < 0 && getlval(p) > -0777777777777LL) fprintf(fp, "-" CONFMT, -getlval(p)); else fprintf(fp, CONFMT, getlval(p)); } /* printf conditional and unconditional branches */ void cbgen(int o,int lab) { } /* * Do some local optimizations that must be done after optim is called. */ static void optim2(NODE *p, void *arg) { int op = p->n_op; int m, ml; NODE *l; /* Remove redundant PCONV's */ if (op == PCONV) { l = p->n_left; m = BTYPE(p->n_type); ml = BTYPE(l->n_type); if ((m == INT || m == LONG || m == LONGLONG || m == FLOAT || m == DOUBLE || m == STRTY || m == UNIONTY || m == UNSIGNED || m == ULONG || m == ULONGLONG) && (ml == INT || ml == LONG || ml == LONGLONG || ml == FLOAT || ml == DOUBLE || ml == STRTY || ml == UNIONTY || ml == UNSIGNED || ml == ULONG || ml == ULONGLONG) && ISPTR(l->n_type)) { *p = *l; nfree(l); op = p->n_op; } else if (ISPTR(DECREF(p->n_type)) && (l->n_type == INCREF(STRTY))) { *p = *l; nfree(l); op = p->n_op; } else if (ISPTR(DECREF(l->n_type)) && (p->n_type == INCREF(INT) || p->n_type == INCREF(STRTY) || p->n_type == INCREF(UNSIGNED))) { *p = *l; nfree(l); op = p->n_op; } } /* Add constands, similar to the one in optim() */ if (op == PLUS && p->n_right->n_op == ICON) { l = p->n_left; if (l->n_op == PLUS && l->n_right->n_op == ICON && (p->n_right->n_name[0] == '\0' || l->n_right->n_name[0] == '\0')) { setlval(l, getlval(l) + getlval(p->n_right)); if (l->n_right->n_name[0] == '\0') l->n_right->n_name = p->n_right->n_name; nfree(p->n_right); *p = *l; nfree(l); } } /* Convert "PTR undef" (void *) to "PTR uchar" */ /* XXX - should be done in MI code */ if (BTYPE(p->n_type) == VOID) p->n_type = (p->n_type & ~BTMASK) | UCHAR; if (op == ICON) { if ((p->n_type == (PTR|CHAR) || p->n_type == (PTR|UCHAR)) && getlval(p) == 0 && p->n_name[0] != '\0') setlval(p, 0700000000000LL); if ((p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) && getlval(p) == 0 && p->n_name[0] != '\0') setlval(p, 0750000000000LL); } if (op == MINUS) { if ((p->n_left->n_type == (PTR|CHAR) || p->n_left->n_type == (PTR|UCHAR)) && (p->n_right->n_type == (PTR|CHAR) || p->n_right->n_type == (PTR|UCHAR))) { l = talloc(); l->n_op = SCONV; l->n_type = INT; l->n_left = p->n_right; p->n_right = l; l = talloc(); l->n_op = SCONV; l->n_type = INT; l->n_left = p->n_left; p->n_left = l; } } } void myreader(struct interpass *ipole) { struct interpass *ip; DLIST_FOREACH(ip, ipole, qelem) { if (ip->type != IP_NODE) continue; walkf(ip->ip_node, optim2, 0); } if (x2debug) { printf("myreader final tree:\n"); printip(ipole); } } /* * Remove some PCONVs after OREGs are created. */ static void pconv2(NODE *p, void *arg) { NODE *q; if (p->n_op == PLUS) { if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) { if (p->n_right->n_op != ICON) return; if (p->n_left->n_op != PCONV) return; if (p->n_left->n_left->n_op != OREG) return; q = p->n_left->n_left; nfree(p->n_left); p->n_left = q; /* * This will be converted to another OREG later. */ } } } void mycanon(NODE *p) { walkf(p, pconv2, 0); } /* * Remove last goto. */ void myoptim(struct interpass *ip) { } /* * Return a class suitable for a specific type. */ int gclass(TWORD t) { return (szty(t) == 2 ? CLASSB : CLASSA); } static int argsiz(NODE *p) { TWORD t = p->n_type; if (t == STRTY || t == UNIONTY) return attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)/(SZINT/SZCHAR); return szty(t); } /* * Calculate argument sizes. */ void lastcall(NODE *p) { NODE *op = p; int size = 0; p->n_qual = 0; if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) return; for (p = p->n_right; p->n_op == CM; p = p->n_left) if (p->n_right->n_op != ASSIGN) size += argsiz(p->n_right); if (p->n_op != ASSIGN) size += argsiz(p); op->n_qual = size; /* XXX */ } void rmove(int s, int d, TWORD t) { printf(" %smove %s,%s\n", (s > 017 ? "d" : ""), rnames[d], rnames[s]); } /* * For class c, find worst-case displacement of the number of * registers in the array r[] indexed by class. */ int COLORMAP(int c, int *r) { int num; switch (c) { case CLASSA: /* there are 13 classa, so min 6 classb are needed to block */ num = r[CLASSB] * 2; num += r[CLASSA]; return num < 13; case CLASSB: /* 7 classa may block all classb */ num = r[CLASSB] + r[CLASSA]; return num < 7; } comperr("COLORMAP"); return 0; /* XXX gcc */ } /* * Target-dependent command-line options. */ void mflags(char *str) { } /* * Do something target-dependent for xasm arguments. * Supposed to find target-specific constraints and rewrite them. */ int myxasm(struct interpass *ip, NODE *p) { return 0; } pcc-20181216/arch/pdp10/macdefs.h010064400017500000000000000160351266660034000151100ustar raggewheel/* $Id: macdefs.h,v 1.36 2016/03/05 15:53:04 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Machine-dependent defines for both passes. */ /* * Convert (multi-)character constant to integer. * Assume: If only one value; store at left side (char size), otherwise * treat it as an integer. */ #define makecc(val,i) { \ if (i == 0) { lastcon = val; \ } else if (i == 1) { lastcon = (lastcon << 9) | val; lastcon <<= 18; \ } else { lastcon |= (val << (27 - (i * 9))); } } #define ARGINIT 36 /* # bits below fp where arguments start */ #define AUTOINIT 36 /* # bits above fp where automatics start */ /* * Storage space requirements */ #define SZCHAR 9 #define SZBOOL 36 #define SZINT 36 #define SZFLOAT 36 #define SZDOUBLE 72 #define SZLDOUBLE 72 #define SZLONG 36 #define SZSHORT 18 #define SZPOINT(x) 36 #define SZLONGLONG 72 /* * Alignment constraints */ #define ALCHAR 9 #define ALBOOL 36 #define ALINT 36 #define ALFLOAT 36 #define ALDOUBLE 36 #define ALLDOUBLE 36 #define ALLONG 36 #define ALLONGLONG 36 #define ALSHORT 18 #define ALPOINT 36 #define ALSTRUCT 36 #define ALSTACK 36 /* * Max values. */ #define MIN_CHAR -256 #define MAX_CHAR 255 #define MAX_UCHAR 511 #define MIN_SHORT -131072 #define MAX_SHORT 131071 #define MAX_USHORT 262143 #define MIN_INT (-0377777777777LL-1) #define MAX_INT 0377777777777LL #define MAX_UNSIGNED 0777777777777ULL #define MIN_LONG (-0377777777777LL-1) #define MAX_LONG 0377777777777LL #define MAX_ULONG 0777777777777ULL #define MIN_LONGLONG (000777777777777777777777LL-1) /* XXX cross */ #define MAX_LONGLONG 000777777777777777777777LL /* XXX cross */ #define MAX_ULONGLONG 001777777777777777777777ULL /* XXX cross */ /* Default char is unsigned */ #define TARGET_STDARGS #define CHAR_UNSIGNED #define BOOL_TYPE INT #define WORD_ADDRESSED /* * Use large-enough types. */ typedef long long CONSZ; typedef unsigned long long U_CONSZ; typedef long long OFFSZ; #define CONFMT "0%llo" /* format for printing constants */ #define LABFMT ".L%d" /* format for printing labels */ #define STABLBL ".LL%d" /* format for stab (debugging) labels */ #undef BACKAUTO /* stack grows negatively for automatics */ #undef BACKTEMP /* stack grows negatively for temporaries */ #undef FIELDOPS /* no bit-field instructions */ #define TARGET_ENDIAN TARGET_BE /* Definitions mostly used in pass2 */ #define BYTEOFF(x) ((x)&03) #define wdal(k) (BYTEOFF(k)==0) #define STOARG(p) #define STOFARG(p) #define STOSTARG(p) #define genfcall(a,b) gencall(a,b) #define szty(t) (((t) == DOUBLE || (t) == FLOAT || \ (t) == LONGLONG || (t) == ULONGLONG) ? 2 : 1) #define shltype(o, p) \ ((o) == REG || (o) == NAME || (o) == ICON || \ (o) == OREG || ((o) == UMUL && shumul((p)->n_left, SOREG))) #undef SPECIAL_INTEGERS /* * Special shapes used in code generation. */ #define SUSHCON (SPECIAL|6) /* unsigned short constant */ #define SNSHCON (SPECIAL|7) /* negative short constant */ #define SILDB (SPECIAL|8) /* use ildb here */ /* * Register allocator definitions. * * The pdp10 has 16 general-purpose registers, but the two * highest are used as sp and fp. Register 0 has special * constraints in its possible use as index register. * All regs can be used as pairs, named by the lowest number. * In here we call the registers Rn and the pairs XRn, in assembler * just its number prefixed with %. * * R1/XR1 are return registers. * * R0 is currently not used. */ #define MAXREGS 29 /* 16 + 13 regs */ #define NUMCLASS 2 #define R0 00 #define R1 01 #define R2 02 #define R3 03 #define R4 04 #define R5 05 #define R6 06 #define R7 07 #define R10 010 #define R11 011 #define R12 012 #define R13 013 #define R14 014 #define R15 015 #define R16 016 #define R17 017 #define FPREG R16 /* frame pointer */ #define STKREG R17 /* stack pointer */ #define XR0 020 #define XR1 021 #define XR2 022 #define XR3 023 #define XR4 024 #define XR5 025 #define XR6 026 #define XR7 027 #define XR10 030 #define XR11 031 #define XR12 032 #define XR13 033 #define XR14 034 #define RSTATUS \ 0, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \ SAREG|PERMREG, SAREG|PERMREG, 0, 0, \ SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \ SBREG, SBREG, SBREG, SBREG, SBREG, #define ROVERLAP \ { XR0, -1 }, \ { XR0, XR1, -1 }, \ { XR1, XR2, -1 }, \ { XR2, XR3, -1 }, \ { XR3, XR4, -1 }, \ { XR4, XR5, -1 }, \ { XR5, XR6, -1 }, \ { XR6, XR7, -1 }, \ { XR7, XR10, -1 }, \ { XR10, XR11, -1 }, \ { XR11, XR12, -1 }, \ { XR12, XR13, -1 }, \ { XR13, XR14, -1 }, \ { XR14, -1 }, \ { -1 }, \ { -1 }, \ { R0, R1, XR1, -1 }, \ { R1, R2, XR0, XR2, -1 }, \ { R2, R3, XR1, XR3, -1 }, \ { R3, R4, XR2, XR4, -1 }, \ { R4, R5, XR3, XR5, -1 }, \ { R5, R6, XR4, XR6, -1 }, \ { R6, R7, XR5, XR7, -1 }, \ { R7, R10, XR6, XR10, -1 }, \ { R10, R11, XR7, XR11, -1 }, \ { R11, R12, XR10, XR12, -1 }, \ { R12, R13, XR11, XR13, -1 }, \ { R13, R14, XR12, XR14, -1 }, \ { R14, R15, XR13, -1 }, /* Return a register class based on the type of the node */ #define PCLASS(p) (szty(p->n_type) == 2 ? SBREG : SAREG) #define RETREG(x) (szty(x) == 2 ? XR1 : R1) #define DECRA(x,y) (((x) >> (y*6)) & 63) /* decode encoded regs */ #define ENCRD(x) (x) /* Encode dest reg in n_reg */ #define ENCRA1(x) ((x) << 6) /* A1 */ #define ENCRA2(x) ((x) << 12) /* A2 */ #define ENCRA(x,y) ((x) << (6+y*6)) /* encode regs in int */ #define GCLASS(x) (x < 16 ? CLASSA : CLASSB) int COLORMAP(int c, int *r); pcc-20181216/arch/pdp10/order.c010064400017500000000000000107011305206566400146120ustar raggewheel/* $Id: order.c,v 1.64 2017/02/18 15:43:48 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass2.h" int canaddr(NODE *); /* is it legal to make an OREG or NAME entry which has an * offset of off, (from a register of r), if the * resulting thing had type t */ int notoff(TWORD t, int r, CONSZ off, char *cp) { return(0); /* YES */ } int radebug = 0; void offstar(NODE *p, int shape) { NODE *q; if (x2debug) printf("offstar(%p)\n", p); if( p->n_op == PLUS || p->n_op == MINUS ){ if( p->n_right->n_op == ICON ){ q = p->n_left; if (q->n_op != REG) geninsn(q, INAREG); p->n_su = -1; } } geninsn(p, INAREG); } /* * findops() failed, see if we can rewrite it to match. */ int setbin(NODE *p) { TWORD ty; NODE *r, *s; ty = p->n_type; switch (p->n_op) { case MINUS: switch (ty) { case PTR+CHAR: case PTR+UCHAR: case PTR+SHORT: case PTR+USHORT: /* * Must negate the right side and change op to PLUS. */ r = p->n_right; if (r->n_op == ICON) { setlval(r, -getlval(r)); } else { s = talloc(); s->n_type = r->n_type; s->n_op = UMINUS; s->n_left = r; p->n_right = s; } p->n_op = PLUS; return 1; } } return 0; } /* setup for assignment operator */ int setasg(NODE *p, int cookie) { return(0); } /* setup for unary operator */ int setuni(NODE *p, int cookie) { return 0; } int special(NODE *p, int shape) { switch (shape) { case SUSHCON: if (p->n_op == ICON && p->n_name[0] == '\0' && (getlval(p) > 0 && getlval(p) <= 0777777)) return 1; break; case SNSHCON: if (p->n_op == ICON && p->n_name[0] == '\0' && (getlval(p) < 0 && getlval(p) > -01000000)) return 1; break; case SILDB: if (p->n_op == ASSIGN && p->n_left->n_op == REG && p->n_right->n_op == PLUS && p->n_right->n_left->n_op == REG && p->n_right->n_right->n_op == ICON && getlval(p->n_right->n_right) == 1 && p->n_right->n_left->n_rval == p->n_left->n_rval) return 1; break; } return 0; } /* * Set evaluation order of a binary node if it differs from default. */ int setorder(NODE *p) { return 0; /* nothing differs on x86 */ } /* * Special handling of some instruction register allocation. */ struct rspecial * nspecial(struct optab *q) { return 0; /* XXX gcc */ } /* * Do the actual conversion of offstar-found OREGs into real OREGs. */ void myormake(NODE *p) { if (x2debug) printf("myormake(%p)\n", p); } /* * set registers in calling conventions live. */ int * livecall(NODE *p) { static int r[8], *s = r; *s = -1; if (p->n_op == UCALL || p->n_op == UFORTCALL || p->n_op == USTCALL || p->n_op == FORTCALL) return s; for (p = p->n_right; p->n_op == CM; p = p->n_left) { if (p->n_right->n_op == ASSIGN && p->n_right->n_left->n_op == REG) *s++ = p->n_right->n_left->n_rval; } if (p->n_op == ASSIGN && p->n_left->n_op == REG) *s++ = p->n_left->n_rval; *s = -1; return r; } /* * Signal whether the instruction is acceptable for this target. */ int acceptable(struct optab *op) { return 1; } pcc-20181216/arch/pdp10/table.c010064400017500000000000000607311305206566400145760ustar raggewheel/* $Id: table.c,v 1.98 2017/02/18 15:43:48 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass2.h" # define TLL TLONGLONG|TULONGLONG # define ANYSIGNED TINT|TLONG|TSHORT|TCHAR # define ANYUSIGNED TUNSIGNED|TULONG|TUSHORT|TUCHAR # define ANYFIXED ANYSIGNED|ANYUSIGNED # define TUWORD TUNSIGNED|TULONG # define TSWORD TINT|TLONG # define TWORD TUWORD|TSWORD struct optab table[] = { { -1, FORREW,SANY,TANY,SANY,TANY,REWRITE,-1,"", }, /* * A bunch of pointer conversions. * First pointer to integer. */ /* Convert char pointer to int */ { SCONV, INAREG, SAREG|SAREG, TPTRTO|TCHAR|TUCHAR, SANY, TWORD, NAREG, RLEFT, " lsh AL,2\n" " move A1,AL\n" " lsh A1,-040\n" " trz A1,074\n" " ior AL,A1\n" " tlz AL,0740000\n", }, /* Convert short pointer to int */ { SCONV, INAREG, SAREG|SAREG, TPTRTO|TSHORT|TUSHORT, SANY, TWORD, NAREG, RLEFT, " lsh AL,2\n" " move A1,AL\n" " lsh A1,-041\n" " trz A1,2\n" " ior AL,A1\n" " tlz AL,0740000\n", }, /* Convert int/unsigned/long/ulong/struct/union/func ptr to int */ { SCONV, INAREG, SAREG|SAREG, TPTRTO|TWORD|TSTRUCT|TPOINT, SANY, TWORD, 0, RLEFT, " lsh AL,2\n", }, /* * Convert int/long to pointers. */ /* Convert int to char pointer */ { PCONV, INAREG, SAREG, TWORD, SANY, TPTRTO|TCHAR|TUCHAR, NAREG, RLEFT, " move A1,AL\n" " lsh A1,036\n" " tlo A1,0700000\n" " tlz A1,0040000\n" " lsh AL,-2\n" " ior AL,A1\n", }, /* Convert int/long to short pointer */ { PCONV, INAREG, SAREG, TWORD, SANY, TPTRTO|TSHORT|TUSHORT, NAREG, RLEFT, " move A1,AL\n" " lsh AL,-2\n" " tlo AL,0750000\n" " lsh A1,035\n" " tlz A1,0760000\n" " add AL,A1\n", }, /* Convert int/long to int/struct/multiple ptr */ { PCONV, INAREG, SAREG, TWORD, SANY, TPOINT|TWORD|TSTRUCT, 0, RLEFT, " lsh AL,-2\n", }, /* * Pointer to pointer conversions. */ /* Convert char ptr to short ptr */ { PCONV, INAREG, SAREG, TPTRTO|TCHAR|TUCHAR, SANY, TPTRTO|TSHORT|TUSHORT, 0, RLEFT, " tlo AL,050000\n" " tlne AL,020000\n" " tlz AL,010000\n", }, /* Convert char/short pointer to int/struct/multiple ptr */ { PCONV, INAREG, SAREG, TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT, SANY, TPOINT|TWORD|TSTRUCT, 0, RLEFT, " tlz AL,0770000\n", }, /* Convert short pointer to char ptr */ { PCONV, INAREG, SAREG, TPTRTO|TSHORT|TUSHORT, SANY, TPTRTO|TCHAR|TUCHAR, 0, RLEFT, " tlz AL,050000\n", }, /* Convert int/struct/foo pointer to char ptr */ { PCONV, INAREG, SAREG, TPOINT|TWORD|TSTRUCT, SANY, TPTRTO|TCHAR|TUCHAR, 0, RLEFT, " tlo AL,0700000\n", }, /* Convert int/struct/foo pointer to short ptr */ { PCONV, INAREG, SAREG, TPTRTO|TWORD|TSTRUCT, SANY, TPTRTO|TSHORT|TUSHORT, 0, RLEFT, " tlo AL,0750000\n", }, /* * A bunch conversions of integral<->integral types */ /* convert short/char to int. This is done when register is loaded */ { SCONV, INAREG, SAREG, TSHORT|TUSHORT|TCHAR|TUCHAR|TWORD, SANY, TWORD, 0, RLEFT, "", }, /* convert int to short/char. This is done when register is loaded */ { SCONV, INAREG, SAREG, TWORD, SANY, TSHORT|TUSHORT|TCHAR|TUCHAR|TWORD, 0, RLEFT, "", }, /* convert int/long to unsigned long long */ { SCONV, INAREG, SAREG|SAREG|SNAME|SOREG, TWORD, SANY, TULONGLONG, NAREG|NASL, RESC1, " move U1,AL\n" " setz A1,\n" " tlze U1,0400000\n" " tro A1,01\n" , }, /* convert int/long to long long */ { SCONV, INAREG, SAREG|SAREG|SNAME|SOREG, TWORD, SANY, TLONGLONG, NAREG|NASL, RESC1, " move U1,AL\n" " move A1,U1\n" " ash A1,-043\n", }, /* convert uchar/ushort to (unsigned) long long */ { SCONV, INAREG, SAREG|SAREG|SNAME|SOREG, TUCHAR|TUSHORT, SANY, TLL, NAREG|NASL, RESC1, " move U1,AL\n" " setz A1,\n", }, /* convert long long to int/long */ { SCONV, INAREG, SAREG|SAREG|SNAME|SOREG, TLL, SANY, TWORD, NAREG|NASL, RESC1, " move A1,UL\n", }, /* convert long long to unsigned char - XXX - signed char */ { SCONV, INAREG, SAREG|SAREG|SNAME|SOREG, TLL, SANY, TCHAR|TUCHAR, NAREG|NASL, RESC1, " move A1,UL\n" " andi A1,0777\n", }, /* convert long long to short - XXX - signed short */ { SCONV, INAREG, SAREG|SAREG|SNAME|SOREG, TLL, SANY, TSHORT|TUSHORT, NAREG|NASL, RESC1, " move A1,UL\n" " hrrz A1,A1\n", }, /* floating point conversions */ { SCONV, INAREG, SAREG|SAREG|SNAME|SOREG, TDOUBLE|TFLOAT, SANY, TWORD, NAREG|NASL, RESC1, " fix A1,AL\n", }, { SCONV, INAREG, SAREG|SAREG|SNAME|SOREG, TWORD, SANY, TFLOAT, NAREG|NASL, RESC1, " fltr A1,AL\n", }, { SCONV, INAREG, SAREG|SAREG|SNAME|SOREG, TWORD, SANY, TDOUBLE, NAREG|NASL, RESC1, " fltr A1,AL\n setz U1,\n", }, { SCONV, INAREG, SAREG|SAREG|SNAME|SOREG, TDOUBLE, SANY, TFLOAT, NAREG|NASL, RESC1, " move A1,AL\n", }, { SCONV, INAREG, SAREG|SAREG|SNAME|SOREG, TFLOAT, SANY, TDOUBLE, NAREG|NASL, RESC1, " move A1,AL\n setz U1,\n", }, /* * Subroutine calls. */ { UCALL, FOREFF, SCON, TANY, SANY, TANY, 0, 0, /* should be 0 */ " pushj 017,AL\nZB", }, { CALL, FOREFF, SCON, TANY, SANY, TANY, 0, 0, /* should be 0 */ " pushj 017,AL\nZB", }, { UCALL, INAREG, SCON, TANY, SANY, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT|TFLOAT|TPOINT, NAREG, RESC1, /* should be 0 */ " pushj 017,AL\nZB", }, { CALL, INAREG, SCON, TANY, SANY, TANY, NAREG|NASL, RESC1, /* should be 0 */ " pushj 017,AL\nZB", }, { UCALL, INAREG, SAREG|SAREG, TANY, SANY, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT|TFLOAT|TDOUBLE|TLL|TPOINT, NAREG|NASL, RESC1, /* should be 0 */ " pushj 017,(AL)\nZB", }, { UCALL, INAREG, SNAME|SOREG, TANY, SANY, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT|TFLOAT|TDOUBLE|TLL|TPOINT, NAREG, RESC1, /* should be 0 */ " pushj 017,@AL\nZB", }, #ifdef notyet /* * INCR can be slightly optimized. */ { INCR, INAREG, SAREG|SAREG|SNAME|SOREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TPTRTO, SONE, TANY, NAREG, RESC1, " move A1,AL\n" " ibp AL\n", }, /* Fix check of return value */ { INCR, FOREFF, SAREG|SAREG|SNAME|SOREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TPTRTO, SONE, TANY, 0, 0, " ibp AL\n", }, #endif /* * PLUS operators. */ /* Add a value to a char/short pointer */ { PLUS, INAREG|INAREG|FOREFF, SAREG|SAREG|SNAME|SOREG, TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT, SAREG|SAREG, TWORD, 0, RRIGHT, " adjbp AR,AL\n", }, /* No more search for char/short pointer addition */ { PLUS, INAREG|INAREG|FOREFF, SANY, TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT, SANY, TANY, REWRITE, 0, "DIEDIEDIE!\n", }, /* Add char/short/int to register */ { PLUS, FOREFF|INAREG|INAREG, SAREG|SAREG, TWORD, SAREG|SAREG|SNAME|SOREG, TWORD, 0, RLEFT, " add AL,AR\n", }, /* Add char/short/int to memory */ { PLUS, FOREFF|INAREG|INAREG, SAREG|SAREG|SNAME|SOREG, TWORD, SAREG|SAREG, TWORD, 0, RLEFT, " addm AR,AL\n", }, /* Add a small constant to a register */ { PLUS, FOREFF|INAREG|INAREG, SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD|TPOINT, SUSHCON, TWORD, 0, RLEFT, " addi AL,AR\n", }, /* Add a larger constant to a register */ { PLUS, FOREFF|INAREG|INAREG, SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD|TPOINT, SCON, TWORD, 0, RLEFT, " add AL,[ .long AR ]\n", }, /* Add long long to register */ { PLUS, INAREG|INAREG|FOREFF, SAREG|SAREG, TLL, SAREG|SAREG|SNAME|SOREG, TLL, 0, RLEFT, " dadd AL,AR\n", }, /* Add int (or int pointer) to register */ { PLUS, FOREFF|INAREG|INAREG, SAREG|SAREG, TWORD|TPOINT, SAREG|SAREG|SNAME|SOREG, TWORD, 0, RLEFT, " add AL,AR # foo \n", }, /* char/short are allowed to be added if they are in registers */ { PLUS, INAREG|INAREG|FOREFF, SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, 0, RLEFT, " add AL,AR\n", }, /* get address of an memory position into a register */ { PLUS, INAREG|INAREG, SAREG|SAREG, TWORD|TPTRTO, SCON, TANY, NAREG, RESC1, " xmovei A1,AR(AL)\n", }, /* Safety belt for plus */ { PLUS, FORREW|FOREFF|INAREG|INAREG, SANY, TANY, SANY, TANY, REWRITE, 0, "DIEDIEDIE", }, /* * MINUS operators. */ /* Rewrite subtracts from char/short pointers (to negative adds) */ { MINUS, FORREW|FOREFF|INAREG|INAREG, SANY, TCHAR|TUCHAR|TSHORT|TUSHORT|TPTRTO, SANY, TANY, REWRITE, 0, "DIEDIEDIE", }, /* Subtract char/short/int word in memory from reg */ { MINUS, FOREFF|INAREG|INAREG, SAREG|SAREG, TWORD|TPOINT, SAREG|SAREG|SNAME|SOREG, TWORD|TPOINT, 0, RLEFT, " sub AL,AR\n", }, /* Subtract a small constant from reg */ { MINUS, FOREFF|INAREG|INAREG, SAREG|SAREG, TWORD|TPOINT, SUSHCON, TWORD|TPOINT, 0, RLEFT, " subi AL,AR\n", }, /* Subtract a large constant from reg */ { MINUS, FOREFF|INAREG|INAREG, SAREG|SAREG, TWORD|TPOINT, SCON, TWORD|TPOINT, 0, RLEFT, " sub AL,[ .long AR ]\n", }, /* Subtract char/short/int word in memory from reg, save in memory */ { MINUS, FOREFF|INAREG|INAREG, SAREG|SAREG, TWORD, SAREG|SAREG|SNAME|SOREG, TWORD, 0, RRIGHT, " subm AL,AR\n", }, /* Subtract long long from register */ { MINUS, INAREG|INAREG|FOREFF, SAREG|SAREG, TLL, SAREG|SAREG|SNAME|SOREG, TLL, 0, RLEFT, " dsub AL,AR\n", }, /* char/short are allowed to be subtracted if they are in registers */ { MINUS, INAREG|INAREG|FOREFF, SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, 0, RLEFT, " sub AL,AR\n", }, /* Safety belt for plus */ { MINUS, FORREW|FOREFF|INAREG|INAREG, SANY, TANY, SANY, TANY, REWRITE, 0, "DIEDIEDIE", }, /* * AND/OR/ER operators. * Simpler that the ops above in that they only work on integral types. */ /* And char/short/int with integer memory */ { AND, FOREFF|INAREG|INAREG, SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, SAREG|SAREG|SNAME|SOREG, TWORD, 0, RLEFT, " and AL,AR\n", }, /* And char/short/int with register */ { AND, FOREFF|INAREG|INAREG, SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, 0, RLEFT, " and AL,AR\n", }, /* And char/short/int with small constant */ { AND, FOREFF|INAREG|INAREG, SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, SUSHCON, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, 0, RLEFT, " andi AL,AR\n", }, /* And char/short/int with large constant */ { AND, FOREFF|INAREG|INAREG, SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, SCON, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, 0, RLEFT, " and AL,[ .long AR ]\n", }, /* long long AND */ { AND, INAREG|FOREFF, SAREG|SAREG, TLL, SAREG|SAREG|SNAME|SOREG, TLL, 0, RLEFT, " and AL,AR\n" " and UL,UR\n", }, /* Safety belt for AND */ { AND, FORREW|FOREFF|INAREG|INAREG, SANY, TANY, SANY, TANY, REWRITE, 0, "DIEDIEDIE", }, /* OR char/short/int with integer memory */ { OR, FOREFF|INAREG|INAREG, SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, SAREG|SAREG|SNAME|SOREG, TWORD, 0, RLEFT, " ior AL,AR\n", }, /* OR char/short/int with register */ { OR, FOREFF|INAREG|INAREG, SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, 0, RLEFT, " ior AL,AR\n", }, /* OR char/short/int with small constant */ { OR, FOREFF|INAREG|INAREG, SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, SUSHCON, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, 0, RLEFT, " iori AL,AR\n", }, /* OR char/short/int with large constant */ { OR, FOREFF|INAREG|INAREG, SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, SCON, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, 0, RLEFT, " ior AL,[ .long AR ]\n", }, /* long long OR */ { OR, INAREG|FOREFF, SAREG|SAREG, TLL, SAREG|SAREG|SNAME|SOREG, TLL, 0, RLEFT, " ior AL,AR\n" " ior UL,UR\n", }, /* Safety belt for OR */ { OR, FORREW|FOREFF|INAREG|INAREG, SANY, TANY, SANY, TANY, REWRITE, 0, "DIEDIEDIE", }, /* ER char/short/int with integer memory */ { ER, FOREFF|INAREG|INAREG, SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, SAREG|SAREG|SNAME|SOREG, TWORD, 0, RLEFT, " xor AL,AR\n", }, /* ER char/short/int with register */ { ER, FOREFF|INAREG|INAREG, SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, 0, RLEFT, " xor AL,AR\n", }, /* ER char/short/int with small constant */ { ER, FOREFF|INAREG|INAREG, SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, SUSHCON, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, 0, RLEFT, " xori AL,AR\n", }, /* ER char/short/int with large constant */ { ER, FOREFF|INAREG|INAREG, SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, SCON, TCHAR|TUCHAR|TSHORT|TUSHORT|TWORD, 0, RLEFT, " xor AL,[ .long AR ]\n", }, /* long long ER */ { ER, INAREG|FOREFF, SAREG|SAREG, TLL, SAREG|SAREG|SNAME|SOREG, TLL, 0, RLEFT, " xor AL,AR\n" " xor UL,UR\n", }, /* Safety belt for ER */ { ER, FORREW|FOREFF|INAREG|INAREG, SANY, TANY, SANY, TANY, REWRITE, 0, "DIEDIEDIE", }, /* * The next rules handle all shift operators. */ { LS, INAREG|INAREG|FOREFF, SAREG|SAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, SAREG|SAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, 0, RLEFT, " lsh AL,(AR)\n", }, { LS, INAREG|INAREG|FOREFF, SAREG|SAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, SNAME|SOREG, TWORD, 0, RLEFT, " lsh AL,@AR\n", }, { LS, INAREG|INAREG|FOREFF, SAREG|SAREG, TLL, SCON, TANY, 0, RLEFT, " ashc AL,ZH\n", }, { LS, INAREG|INAREG|FOREFF, SAREG|SAREG, TLL, SAREG|SAREG /* |SNAME|SOREG */, TANY, 0, RLEFT, " ashc AL,(AR)\n", }, { RS, INAREG|INAREG|FOREFF, SAREG|SAREG, TSWORD, SCON, TWORD, 0, RLEFT, " ash AL,-ZH\n", }, { RS, INAREG|INAREG|FOREFF, SAREG|SAREG, TUWORD, SCON, TWORD, 0, RLEFT, " lsh AL,-ZH\n", }, /* Safety belt for LS/RS */ { LS, FORREW|FOREFF|INAREG|INAREG, SANY, TANY, SANY, TANY, REWRITE, 0, "DIEDIEDIE", }, { RS, FORREW|FOREFF|INAREG|INAREG, SANY, TANY, SANY, TANY, REWRITE, 0, "DIEDIEDIE", }, /* * The next rules takes care of assignments. "=". */ /* Match zeroed registers first */ { ASSIGN, INAREG|FOREFF, SAREG, TUCHAR|TUSHORT|TCHAR|TSHORT|TWORD|TPOINT, SZERO, TANY, 0, RDEST, " setz AL,\n", }, { ASSIGN, FOREFF, SAREG|SNAME|SOREG, TWORD|TPOINT, SZERO, TANY, 0, 0, " setzm AL\n", }, { ASSIGN, INAREG|FOREFF, SAREG|SAREG, TUCHAR|TUSHORT|TCHAR|TSHORT|TWORD|TPOINT, SMONE, TANY, 0, RDEST, " setom AL\n", }, { ASSIGN, FOREFF, SAREG|SNAME|SOREG, TWORD|TPOINT, SMONE, TANY, 0, 0, " setom AL\n", }, { ASSIGN, INAREG|INAREG|FOREFF, SAREG|SAREG, TWORD|TPOINT, SCON, TWORD|TPOINT, 0, RDEST, " ZC\n", }, { ASSIGN, INAREG|INAREG|FOREFF, SAREG|SNAME|SOREG, TWORD|TPOINT|TFLOAT, SAREG|SAREG, TUCHAR|TUSHORT|TWORD|TPOINT|TFLOAT, 0, RDEST, " movem AR,AL\n", }, { ASSIGN, INAREG|INAREG|FOREFF, SAREG|SNAME|SOREG, TWORD|TPOINT|TFLOAT, SAREG|SAREG, TSHORT, 0, RDEST, " hrrem AR,AL\n", }, { ASSIGN, INAREG|INAREG|FOREFF, SAREG|SAREG, TUCHAR|TUSHORT|TCHAR|TSHORT|TWORD|TPOINT, SAREG|SAREG|SNAME|SOREG, TWORD|TPOINT, 0, RDEST, " move AL,AR\n", }, { ASSIGN, INAREG|INAREG|FOREFF, SAREG|SAREG, TUCHAR|TUSHORT|TCHAR|TSHORT, SAREG|SAREG, TUCHAR|TUSHORT|TCHAR|TSHORT, 0, RDEST, " move AL,AR\n", }, { ASSIGN, INBREG|FOREFF, SBREG|SNAME|SOREG, TLL|TDOUBLE, SBREG, TLL|TDOUBLE, 0, RDEST, " dmovem AR,AL\n", }, { ASSIGN, INAREG|INAREG|FOREFF, SOREG|SNAME, TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG|SAREG, TANY, 0, RDEST, "ZV", }, { ASSIGN, INAREG|INAREG|FOREFF, SAREG|SAREG, TUSHORT|TUCHAR, SOREG, TANY, 0, RDEST, " ldb AL,Zg\n", }, { ASSIGN, INAREG|INAREG|FOREFF, SAREG|SAREG, TSHORT|TUSHORT|TCHAR|TUCHAR, SSCON, TANY, 0, RDEST, " movei AL,AR\n", }, { ASSIGN, INAREG|INAREG|FOREFF, SAREG|SAREG, TSHORT|TUSHORT|TCHAR|TUCHAR, SCON, TANY, 0, RDEST, " move AL,[ .long AR]\n", }, /* * DIV/MOD/MUL * These can be done way more efficient. */ /* long long div. XXX - work only with unsigned */ { DIV, INBREG, SBREG|SNAME|SOREG, TLL, SBREG|SNAME|SOREG, TLL, (2*NBREG)|NBSL, RESC1, " dmove A2,AL ; dmove A1,[ .long 0,0 ]\n" " ddiv A1,AR\n", }, /* long long div. with constant. XXX - work only with unsigned */ { DIV, INBREG, SBREG|SNAME|SOREG, TLL, SCON, TLL, (2*NBREG)|NBSL, RESC1, " dmove A2,AL ; dmove A1,[ .long 0,0 ]\n" " ddiv A1,ZP\n", }, /* Simple divide. XXX - fix so next reg can be free */ { DIV, INAREG|INAREG|FOREFF, SAREG|SAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, SAREG|SAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, 0, RRIGHT, " idivm AL,AR\n", }, /* Safety belt for DIV */ { DIV, FORREW|FOREFF|INAREG|INAREG, SANY, TANY, SANY, TANY, REWRITE, 0, "DIEDIEDIE", }, /* long long MOD */ { MOD, INBREG, SBREG|SNAME|SOREG, TLL, SBREG|SNAME|SOREG, TLL, 2*NBREG|NBSL, RESC2, " dmove A2,AL ; dmove A1,[ .long 0,0 ]\n" " ddiv A1,AR\n", }, /* integer MOD */ { MOD, INAREG, SAREG|SNAME|SOREG, TWORD, SAREG|SNAME|SOREG, TWORD, 2*NAREG|NASL, RESC2, " move A2,AL\n" " setz A1,\n" " idiv A1,AR\n", }, /* integer MOD for char/short */ { MOD, INAREG, SAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, SAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, 2*NAREG|NASL, RESC2, " move A2,AL\n" " setz A1,\n" " idiv A1,AR\n", }, /* Safety belt for MOD */ { MOD, FOREFF, SANY, TANY, SANY, TANY, REWRITE, 0, "DIEDIEDIE", }, /* long long MUL */ { MUL, INBREG, SBREG|SNAME|SOREG, TLL, SBREG|SNAME|SOREG, TLL, 2*NBREG|NBSL, RESC2, " dmove A1,AL\n" " dmul A1,AR\n", }, /* integer multiply to memory*/ { MUL, INAREG|INAREG|FOREFF, SAREG|SAREG|SNAME|SOREG, TWORD, SAREG|SAREG, TWORD, 0, RLEFT, " imulm AR,AL\n", }, /* integer multiply */ { MUL, INAREG|INAREG|FOREFF, SAREG|SAREG, TWORD, SAREG|SAREG|SNAME|SOREG, TWORD, 0, RLEFT, " imul AL,AR\n", }, /* integer multiply for char/short */ { MUL, INAREG|INAREG|FOREFF, SAREG|SAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, SAREG|SAREG, TWORD|TCHAR|TUCHAR|TSHORT|TUSHORT, 0, RLEFT, " imul AL,AR\n", }, /* integer multiply with small constant */ { MUL, INAREG|INAREG|FOREFF, SAREG|SAREG, TWORD, SUSHCON, TWORD, 0, RLEFT, " imuli AL,AR\n", }, /* integer multiply with large constant */ { MUL, INAREG|INAREG|FOREFF, SAREG|SAREG, TWORD, SCON, TWORD, 0, RLEFT, " imul AL,[ .long AR ]\n", }, /* Safety belt for MUL */ { MUL, FORREW|FOREFF|INAREG|INAREG, SANY, TANY, SANY, TANY, REWRITE, 0, "DIEDIEDIE", }, /* read an indirect long long value into register */ { UMUL, INAREG, SAREG|SAREG, TPTRTO|TLL|TWORD, SANY, TLL, NAREG|NASL, RESC1, " dmove A1,(AL)\n", }, /* read an indirect integer value into register */ { UMUL, INAREG, SAREG|SAREG, TWORD|TPOINT, SANY, TWORD|TPOINT, NAREG|NASL, RESC1, " move A1,(AL)\n", }, /* read an indirect value into register */ { UMUL, INAREG, SOREG, TWORD|TPOINT, SANY, TWORD|TPOINT, NAREG, RESC1, " move A1,@AL\n", }, /* read an indirect value into register */ { UMUL, INAREG, SAREG|SAREG|SOREG, TCHAR|TUCHAR|TSHORT|TUSHORT|TPTRTO, SANY, TCHAR|TUCHAR|TSHORT|TUSHORT, NAREG|NASL, RESC1, " ldb A1,AL\n", }, #ifdef notyet /* Match tree shape for ildb */ { UMUL, INAREG, SANY, TANY, SILDB, TUCHAR|TCHAR|TPTRTO, NAREG, RESC1, " ildb A1,ZA\n", }, #endif /* Match char/short pointers first, requires special handling */ { OPLOG, FORCC, SAREG|SAREG, TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT, SAREG|SAREG, TPTRTO|TCHAR|TUCHAR|TSHORT|TUSHORT, 0, RESCC, "ZZ", }, /* Can check anything by just comparing if EQ/NE */ { OPLOG, FORCC, SAREG|SAREG, TWORD|TPOINT|TCHAR|TUCHAR|TSHORT|TUSHORT, SZERO, TANY, 0, RESCC, " jumpZe AL,LC # bu\n", }, { EQ, FORCC, SAREG|SAREG, TWORD|TPOINT|TCHAR|TUCHAR|TSHORT|TUSHORT, SAREG|SAREG|SOREG|SNAME|SCON, TWORD|TPOINT, 0, RESCC, "ZR", }, { NE, FORCC, SAREG|SAREG, TWORD|TPOINT|TCHAR|TUCHAR|TSHORT|TUSHORT, SAREG|SAREG|SOREG|SNAME|SCON, TWORD|TPOINT, 0, RESCC, "ZR", }, { OPLOG, FORCC, SAREG|SAREG, TWORD, SAREG|SAREG|SOREG|SNAME|SCON, TSWORD, 0, RESCC, "ZR", }, { OPLOG, FORCC, SAREG|SAREG, TCHAR|TUCHAR, SCON, TANY, 0, RESCC, "ZR", }, { OPLOG, FORCC, SAREG|SAREG, TWORD|TPOINT|TFLOAT, SAREG|SAREG|SOREG|SNAME|SCON, TWORD|TPOINT|TFLOAT, 0, RESCC, "ZR", }, { OPLOG, FORCC, SAREG|SAREG, TWORD|TPOINT|TCHAR|TUCHAR|TSHORT|TUSHORT, SAREG|SAREG, TWORD|TPOINT|TCHAR|TUCHAR|TSHORT|TUSHORT, 0, RESCC, "ZR", }, { OPLOG, FORCC, SAREG|SAREG, TLL|TDOUBLE, /* XXX - does double work here? */ SAREG|SAREG|SOREG|SNAME, TLL|TDOUBLE, 0, RESCC, "ZQ", }, /* * Jumps. */ { GOTO, FOREFF, SCON, TANY, SANY, TANY, 0, RNOP, " jrst LL\n", }, /* * Convert LTYPE to reg. */ { OPLTYPE, INBREG, SANY, TANY, SMONE, TLL, NBREG, RESC1, " seto A1,\n seto U1,\n", }, { OPLTYPE, INAREG, SANY, TANY, SMONE, TANY, NAREG, RESC1, " seto A1,\n", }, { OPLTYPE, INBREG, SANY, TANY, SZERO, TLL, NBREG, RESC1, " setz A1,\n setz U1,\n", }, { OPLTYPE, INAREG, SANY, TANY, SZERO, TANY, NAREG, RESC1, " setz A1,\n", }, { OPLTYPE, INBREG, SANY, TANY, SUSHCON, TLL, NBREG, RESC1, " setz A1,\n movei U1,AR\n", }, { OPLTYPE, INAREG, SANY, TANY, SUSHCON, ANYFIXED, NAREG, RESC1, " movei A1,AR\n", }, { OPLTYPE, INAREG, SANY, ANYFIXED, SNSHCON, ANYFIXED, NAREG, RESC1, " hrroi A1,AR\n", }, { OPLTYPE, INAREG, SANY, ANYFIXED, SCON, ANYFIXED, NAREG|NASR, RESC1, " ZD A1,ZE # suspekt\n", }, { OPLTYPE, INAREG, SANY, TWORD|TPOINT|TFLOAT, SAREG|SAREG|SOREG|SNAME, TWORD|TPOINT|TFLOAT, NAREG|NASR, RESC1, " move A1,AR\n", }, { OPLTYPE, INBREG, SANY, TLL, SCON, TLL, NBREG, RESC1, " dmove A1,ZO\n", }, { OPLTYPE, INBREG, SANY, TLL|TDOUBLE, SANY, TLL|TDOUBLE, NBREG|NBSR, RESC1, " dmove A1,AR\n", }, { OPLTYPE, INAREG, SOREG, TSHORT|TUSHORT|TCHAR|TUCHAR, SOREG, TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASR, RESC1, "ZU", }, { OPLTYPE, INAREG, SNAME, TUCHAR, SNAME, TUCHAR, NAREG|NASR, RESC1, " ldb A1,[ .long AL ]\n" }, { OPLTYPE, INAREG, SNAME, TCHAR, SNAME, TCHAR, NAREG|NASR, RESC1, " ldb A1,[ .long AL ]\n" " ash A1,033\n" " ash A1,-033\n", }, { OPLTYPE, INAREG, SANY, TANY, SNAME, TSHORT|TUSHORT, NAREG|NASR, RESC1, "Zi", }, { OPLTYPE, INAREG, SANY, TWORD|TPOINT, SCON, TWORD|TPOINT, NAREG|NASR, RESC1, "Zc", }, { OPLTYPE, INAREG, SAREG|SAREG, TUSHORT|TUCHAR, SAREG|SAREG, TUSHORT|TUCHAR|TWORD, NAREG, RESC1, " move A1,AL\n", }, /* * Negate a word. */ { UMINUS, INAREG, SAREG|SAREG|SNAME|SOREG, TWORD, SANY, TWORD, NAREG|NASL, RESC1, " movn A1,AL\n", }, { UMINUS, INAREG, SAREG|SAREG, TWORD, SANY, TCHAR|TUCHAR|TSHORT|TUSHORT, 0, RLEFT, " movn AL,AL\n", }, { UMINUS, INAREG, SAREG|SNAME|SOREG, TLL, SANY, TLL, NAREG|NASR, RESC1, " dmovn A1,AL\n", }, { COMPL, INAREG, SAREG|SAREG|SNAME|SOREG, TLL, SANY, TANY, NAREG|NASL, RESC1, " setcm A1,AL\n" " setcm U1,UL\n", }, { COMPL, INAREG, SAREG|SAREG|SNAME|SOREG, TWORD, SANY, TANY, NAREG|NASL, RESC1, " setcm A1,AL\n", }, { COMPL, INAREG, SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT, SANY, TCHAR|TUCHAR|TSHORT|TUSHORT, NAREG|NASL, RESC1, " setcm A1,AL\n", }, /* * Arguments to functions. */ { FUNARG, FOREFF, SAREG|SNAME|SOREG, TWORD|TPOINT|TFLOAT, SANY, TANY, 0, RNULL, " push 017,AL\n", }, { FUNARG, FOREFF, SAREG|SAREG, TCHAR|TUCHAR|TSHORT|TUSHORT, SANY, TANY, 0, RNULL, " push 017,AL\n", }, { FUNARG, FOREFF, SCON, TCHAR|TUCHAR|TSHORT|TUSHORT|TPOINT|TWORD, SANY, TANY, 0, RNULL, " push 017,[ .long AL]\n", }, { FUNARG, FOREFF, SBREG, TLL|TDOUBLE, SANY, TANY, 0, RNULL, " push 017,AL\n push 017,UL\n", }, { STARG, FOREFF, SAREG|SOREG|SNAME|SCON, TANY, SANY, TSTRUCT, 0, 0, "ZG", }, # define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,"" { UMUL, DF( UMUL ), }, { ASSIGN, DF(ASSIGN), }, { OPLEAF, DF(NAME), }, { OPUNARY, DF(UMINUS), }, { FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" }, }; int tablesize = sizeof(table)/sizeof(table[0]); pcc-20181216/arch/pdp11004075500017500000000000000000001340533064000132505ustar raggewheelpcc-20181216/arch/pdp11/CVS004075500017500000000000000000001340533064000137035ustar raggewheelpcc-20181216/arch/pdp11/CVS/Root010064400017500000000000000000111340533064000146150ustar raggewheel/cvsroot pcc-20181216/arch/pdp11/CVS/Repository010064400017500000000000000000171340533064000160570ustar raggewheelpcc/arch/pdp11 pcc-20181216/arch/pdp11/CVS/Entries010064400017500000000000000003671340533064000153210ustar raggewheel/code.c/1.9/Tue Jan 17 13:12:13 2017// /local.c/1.16/Tue Jan 17 13:12:13 2017// /local2.c/1.11/Tue Jan 17 13:12:13 2017// /macdefs.h/1.12/Tue Jan 17 13:12:13 2017// /order.c/1.4/Tue Jan 17 13:12:13 2017// /table.c/1.5/Sun Oct 19 15:25:25 2008// D pcc-20181216/arch/pdp11/code.c010064400017500000000000000135151303741405500144130ustar raggewheel/* $Id: code.c,v 1.9 2017/01/17 13:12:13 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass1.h" #ifndef LANG_CXX #define NODE P1ND #undef NIL #define NIL NULL #define talloc p1alloc #endif /* * Print out assembler segment name. */ void setseg(int seg, char *name) { switch (seg) { case PROG: name = ".text"; break; case DATA: case LDATA: name = ".data"; break; case UDATA: break; case STRNG: case RDATA: name = ".rodata"; break; default: cerror("setseg"); } printf("\t%s\n", name); } void defalign(int al) { if (al > ALCHAR) printf(".even\n"); } /* * Define everything needed to print out some data (or text). * This means segment, alignment, visibility, etc. */ void defloc(struct symtab *sp) { static char *loctbl[] = { "text", "data", "data" }; TWORD t; char *n; int s; t = sp->stype; s = ISFTN(t) ? PROG : ISCON(cqual(t, sp->squal)) ? RDATA : DATA; if (s != lastloc) printf(" .%s\n", loctbl[s]); lastloc = s; n = getexname(sp); if (sp->sclass == EXTDEF) printf(" .globl %s\n", n); if (sp->slevel == 0) { printf("%s:\n", n); } else { printf(LABFMT ":\n", sp->soffset); } } /* * code for the end of a function * deals with struct return here */ void efcode(void) { NODE *p, *q; if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) return; /* Create struct assignment */ q = block(OREG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap); q->n_rval = R5; slval(q, 8); /* return buffer offset */ q = buildtree(UMUL, q, NIL); p = block(REG, NIL, NIL, PTR+STRTY, 0, cftnsp->sap); p = buildtree(UMUL, p, NIL); p = buildtree(ASSIGN, q, p); ecomp(p); } /* * code for the beginning of a function; a is an array of * indices in symtab for the arguments; n is the number */ void bfcode(struct symtab **sp, int cnt) { struct symtab *sp2; NODE *n; int i; if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { /* Function returns struct, adjust arg offset */ for (i = 0; i < cnt; i++) sp[i]->soffset += SZPOINT(INT); } if (xtemps == 0) return; /* put arguments in temporaries */ for (i = 0; i < cnt; i++) { if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY || cisreg(sp[i]->stype) == 0) continue; sp2 = sp[i]; n = tempnode(0, sp[i]->stype, sp[i]->sdf, sp[i]->sap); n = buildtree(ASSIGN, n, nametree(sp2)); sp[i]->soffset = regno(n->n_left); sp[i]->sflags |= STNODE; ecomp(n); } } /* called just before final exit */ /* flag is 1 if errors, 0 if none */ void ejobcode(int flag) { } void bjobcode(void) { } /* * Called with a function call with arguments as argument. * This is done early in buildtree() and only done once. * Returns p. */ NODE * funcode(NODE *p) { NODE *r, *l; /* Fix function call arguments. On x86, just add funarg */ for (r = p->n_right; r->n_op == CM; r = r->n_left) { if (r->n_right->n_op != STARG) r->n_right = block(FUNARG, r->n_right, NIL, r->n_right->n_type, r->n_right->n_df, r->n_right->n_ap); } if (r->n_op != STARG) { l = talloc(); *l = *r; r->n_op = FUNARG; r->n_left = l; r->n_type = l->n_type; } return p; } /* fix up type of field p */ void fldty(struct symtab *p) { } /* * XXX - fix genswitch. */ int mygenswitch(int num, TWORD type, struct swents **p, int n) { return 0; } /* * Return "canonical frame address". */ NODE * builtin_cfa(const struct bitable *bt, NODE *a) { uerror(__func__); return bcon(0); } NODE * builtin_return_address(const struct bitable *bt, NODE *a) { uerror(__func__); return bcon(0); } NODE * builtin_frame_address(const struct bitable *bt, NODE *a) { uerror(__func__); return bcon(0); } NODE * builtin_huge_val(const struct bitable *bt, NODE *a) { uerror(__func__); return bcon(0); } NODE * builtin_huge_valf(const struct bitable *bt, NODE *a) { uerror(__func__); return bcon(0); } NODE * builtin_huge_vall(const struct bitable *bt, NODE *a) { uerror(__func__); return bcon(0); } NODE * builtin_inf(const struct bitable *bt, NODE *a) { uerror(__func__); return bcon(0); } NODE * builtin_inff(const struct bitable *bt, NODE *a) { uerror(__func__); return bcon(0); } NODE * builtin_infl(const struct bitable *bt, NODE *a) { uerror(__func__); return bcon(0); } NODE * builtin_nan(const struct bitable *bt, NODE *a) { uerror(__func__); return bcon(0); } NODE * builtin_nanf(const struct bitable *bt, NODE *a) { uerror(__func__); return bcon(0); } NODE * builtin_nanl(const struct bitable *bt, NODE *a) { uerror(__func__); return bcon(0); } pcc-20181216/arch/pdp11/local.c010064400017500000000000000173221303741405500145730ustar raggewheel/* $Id: local.c,v 1.16 2017/01/17 13:12:13 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "pass1.h" #ifndef LANG_CXX #define NODE P1ND #undef NIL #define NIL NULL #define fwalk p1fwalk #define nfree p1nfree #endif /* this file contains code which is dependent on the target machine */ /* clocal() is called to do local transformations on * an expression tree preparitory to its being * written out in intermediate code. * * the major essential job is rewriting the * automatic variables and arguments in terms of * REG and OREG nodes * conversion ops which are not necessary are also clobbered here * in addition, any special features (such as rewriting * exclusive or) are easily handled here as well */ NODE * clocal(NODE *p) { register struct symtab *q; register NODE *r, *l; register int o; #ifdef PCC_DEBUG if (xdebug) { printf("clocal: %p\n", p); fwalk(p, eprint, 0); } #endif switch( o = p->n_op ){ case NAME: if ((q = p->n_sp) == NULL) return p; /* Nothing to care about */ switch (q->sclass) { case PARAM: case AUTO: /* fake up a structure reference */ r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); slval(r, 0); r->n_rval = FPREG; p = stref(block(STREF, r, p, 0, 0, 0)); break; case STATIC: if (q->slevel == 0) break; slval(p, 0); break; case REGISTER: p->n_op = REG; slval(p, 0); p->n_rval = q->soffset; break; case EXTERN: case EXTDEF: break; } break; case CBRANCH: l = p->n_left; if (coptype(l->n_op) != BITYPE) break; if (l->n_left->n_op != SCONV || l->n_right->n_op != ICON) break; if ((r = l->n_left->n_left)->n_type > INT) break; /* compare with constant without casting */ nfree(l->n_left); l->n_left = r; l->n_right->n_type = l->n_left->n_type; break; case STASG: /* struct assignment, modify left */ l = p->n_left; if (l->n_type == STRTY) p->n_left = buildtree(ADDROF, l, NIL); break; case FORCE: /* put return value in return reg */ p->n_op = ASSIGN; p->n_right = p->n_left; p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0); p->n_left->n_rval = p->n_left->n_type == BOOL ? RETREG(CHAR) : RETREG(p->n_type); break; } #ifdef PCC_DEBUG if (xdebug) { printf("clocal end: %p\n", p); fwalk(p, eprint, 0); } #endif return(p); } void myp2tree(NODE *p) { struct symtab *sp; if (p->n_op != FCON) return; sp = tmpalloc(sizeof(struct symtab)); sp->sclass = STATIC; sp->sap = 0; sp->slevel = 1; /* fake numeric label */ sp->soffset = getlab(); sp->sflags = 0; sp->stype = p->n_type; sp->squal = (CON >> TSHIFT); locctr(DATA, sp); defloc(sp); ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p); p->n_op = NAME; slval(p, 0); p->n_sp = sp; } /*ARGSUSED*/ int andable(NODE *p) { return(1); /* all names can have & taken on them */ } /* * Return 1 if a variable of type type is OK to put in register. */ int cisreg(TWORD t) { if (t == FLOAT || t == DOUBLE || t == LDOUBLE || t == LONGLONG || t == ULONGLONG) return 0; /* not yet */ return 1; } /* * Allocate off bits on the stack. p is a tree that when evaluated * is the multiply count for off, t is a storeable node where to write * the allocated address. */ void spalloc(NODE *t, NODE *p, OFFSZ off) { NODE *sp; p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */ /* sub the size from sp */ sp = block(REG, NIL, NIL, p->n_type, 0, 0); slval(sp, 0); sp->n_rval = STKREG; ecomp(buildtree(MINUSEQ, sp, p)); /* save the address of sp */ sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap); slval(sp, 0); sp->n_rval = STKREG; t->n_type = sp->n_type; ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */ } /* * Print out a string of characters. * Assume that the assembler understands C-style escape * sequences. */ void instring(struct symtab *sp) { char *s; int val, cnt; defloc(sp); for (cnt = 0, s = sp->sname; *s != 0; ) { if (cnt++ == 0) printf(".byte "); if (*s++ == '\\') val = esccon(&s); else val = s[-1]; printf("%o", val & 0377); if (cnt > 15) { cnt = 0; printf("\n"); } else printf(","); } printf("%s0\n", cnt ? "" : ".byte "); } /* * print out a constant node, may be associated with a label. * Do not free the node after use. * off is bit offset from the beginning of the aggregate * fsz is the number of bits this is referring to */ int ninval(CONSZ off, int fsz, NODE *p) { union { float f; double d; short s[4]; int i[2]; } u; TWORD t; int i; t = p->n_type; switch (t) { case LONGLONG: case ULONGLONG: i = (glval(p) >> 32); slval(p, glval(p) & 0xffffffff); p->n_type = INT; ninval(off, 32, p); slval(p, i); ninval(off+32, 32, p); break; case LONG: case ULONG: printf("%o ; %o\n", (int)((glval(p) >> 16) & 0177777), (int)(glval(p) & 0177777)); break; case FLOAT: u.f = (float)((FLT *)p->n_dcon)->fp; printf("%o ; %o\n", u.s[0], u.s[1]); break; case LDOUBLE: case DOUBLE: u.d = (double)((FLT *)p->n_dcon)->fp; printf("%o ; %o ; %o ; %o\n", u.s[0], u.s[1], u.s[2], u.s[3]); break; default: return 0; } return 1; } /* make a name look like an external name in the local machine */ char * exname(char *p) { #define NCHNAM 256 static char text[NCHNAM+1]; int i; if (p == NULL) return ""; text[0] = '_'; for (i=1; *p && istype, sp->sdf, sp->sap); off = (off+(SZCHAR-1))/SZCHAR; n = getexname(sp); if (sp->sclass == STATIC) { printf(".bss\n"); if (sp->slevel == 0) printf("%s:", n); else printf(LABFMT ":", sp->soffset); printf(" .=.+%o\n", off); lastloc = -1; return; } printf(".comm "); if (sp->slevel == 0) printf("%s,0%o\n", n, off); else printf(LABFMT ",0%o\n", sp->soffset, off); } /* * Give target the opportunity of handling pragmas. */ int mypragma(char *str) { return 0; } /* * Called when a identifier has been declared. */ void fixdef(struct symtab *sp) { } void pass1_lastchance(struct interpass *ip) { } pcc-20181216/arch/pdp11/local2.c010064400017500000000000000377771303741405500146750ustar raggewheel/* $Id: local2.c,v 1.11 2017/01/17 13:12:13 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass2.h" # include # include static int spcoff; static int argsiz(NODE *p); void deflab(int label) { printf(LABFMT ":\n", label); } void prologue(struct interpass_prolog *ipp) { int addto; #ifdef LANG_F77 if (ipp->ipp_vis) printf(" .globl %s\n", ipp->ipp_name); printf("%s:\n", ipp->ipp_name); #endif printf("jsr r5,csv\n"); addto = p2maxautooff; if (addto >= AUTOINIT/SZCHAR) addto -= AUTOINIT/SZCHAR; if (addto & 1) addto++; if (addto == 2) printf("tst -(sp)\n"); else if (addto == 4) printf("cmp -(sp),-(sp)\n"); else if (addto > 4) printf("sub $%o,sp\n", addto); spcoff = 0; } void eoftn(struct interpass_prolog *ipp) { if (spcoff) comperr("spcoff == %d", spcoff); if (ipp->ipp_ip.ip_lbl == 0) return; /* no code needs to be generated */ printf("jmp cret\n"); } /* * add/sub/... * * Param given: */ void hopcode(int f, int o) { char *str; switch (o) { case PLUS: str = "add"; break; case MINUS: str = "sub"; break; case AND: str = "and"; break; case OR: str = "or"; break; case ER: str = "xor"; break; default: comperr("hopcode2: %d", o); str = 0; /* XXX gcc */ } printf("%s%c", str, f); } /* * Return type size in bytes. Used by R2REGS, arg 2 to offset(). */ int tlen(p) NODE *p; { switch(p->n_type) { case CHAR: case UCHAR: return(1); case SHORT: case USHORT: return(SZSHORT/SZCHAR); case DOUBLE: return(SZDOUBLE/SZCHAR); case INT: case UNSIGNED: case LONG: case ULONG: return(SZINT/SZCHAR); case LONGLONG: case ULONGLONG: return SZLONGLONG/SZCHAR; default: if (!ISPTR(p->n_type)) comperr("tlen type %d not pointer"); return SZPOINT(p->n_type)/SZCHAR; } } /* * Emit code to compare two long numbers. */ static void twolcomp(NODE *p) { int o = p->n_op; int s = getlab2(); int e = p->n_label; int cb1, cb2; if (o >= ULE) o -= (ULE-LE); switch (o) { case NE: cb1 = 0; cb2 = NE; break; case EQ: cb1 = NE; cb2 = 0; break; case LE: case LT: cb1 = GT; cb2 = LT; break; case GE: case GT: cb1 = LT; cb2 = GT; break; default: cb1 = cb2 = 0; /* XXX gcc */ } if (p->n_op >= ULE) cb1 += 2, cb2 += 2; expand(p, 0, "cmp AR,AL\n"); if (cb1) cbgen(cb1, s); if (cb2) cbgen(cb2, e); expand(p, 0, "cmp UR,UL\n"); cbgen(p->n_op, e); deflab(s); } /* * Generate compare code for long instructions when right node is 0. */ static void lcomp(NODE *p) { switch (p->n_op) { case EQ: expand(p, FORCC, "tst AL\n"); printf("jne 1f\n"); expand(p, FORCC, "tst UL\n"); cbgen(EQ, p->n_label); printf("1:\n"); break; case NE: expand(p, FORCC, "tst AL\n"); cbgen(NE, p->n_label); expand(p, FORCC, "tst UL\n"); cbgen(NE, p->n_label); break; case GE: expand(p, FORCC, "tst AL\n"); cbgen(GE, p->n_label); break; default: comperr("lcomp %p", p); } } void zzzcode(NODE *p, int c) { switch (c) { case 'A': /* print out - if not first arg */ if (spcoff || (p->n_type == FLOAT || p->n_type == DOUBLE)) printf("-"); spcoff += argsiz(p); break; case 'B': /* arg is pointer to block */ expand(p->n_left, FOREFF, "mov AL,ZA(sp)\n"); expand(p->n_left, FOREFF, "sub CR,(sp)\n"); break; case 'C': /* subtract stack after call */ spcoff -= p->n_qual; if (spcoff == 0 /* && !(p->n_flags & NLOCAL1) XXX FIXME */) p->n_qual -= 2; if (p->n_qual == 2) printf("tst (sp)+\n"); else if (p->n_qual == 4) printf("cmp (sp)+,(sp)+\n"); else if (p->n_qual > 2) printf("add $%o,sp\n", (int)p->n_qual); break; case 'D': /* long comparisions */ lcomp(p); break; case 'E': /* long move */ rmove(p->n_right->n_reg, p->n_left->n_reg, p->n_type); break; case 'F': /* long comparision */ twolcomp(p); break; case 'G': /* printout a subnode for post-inc */ adrput(stdout, p->n_left->n_left); break; case 'H': /* arg with post-inc */ expand(p->n_left->n_left, FOREFF, "mov AL,ZA(sp)\n"); expand(p->n_left->n_left, FOREFF, "inc AL\n"); break; case 'Q': /* struct assignment, no rv */ printf("mov $%o,", attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)/2); expand(p, INAREG, "A1\n"); printf("1:\n"); expand(p, INAREG, "mov (AR)+,(AL)+\n"); expand(p, INAREG, "dec A1\n"); printf("jne 1b\n"); break; case 'R': /* struct assignment with rv */ printf("mov $%o,", attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)/2); expand(p, INAREG, "A1\n"); expand(p, INAREG, "mov AR,A2\n"); printf("1:\n"); expand(p, INAREG, "mov (A2)+,(AL)+\n"); expand(p, INAREG, "dec A1\n"); printf("jne 1b\n"); break; case '1': /* lower part of double regs */ p = getlr(p, '1'); printf("r%c", rnames[p->n_rval][1]); break; default: comperr("zzzcode %c", c); } } /*ARGSUSED*/ int rewfld(NODE *p) { return(1); } int canaddr(NODE *); int canaddr(NODE *p) { int o = p->n_op; if (o==NAME || o==REG || o==ICON || o==OREG || (o==UMUL && shumul(p->n_left, STARNM|SOREG))) return(1); return(0); } /* * Does the bitfield shape match? */ int flshape(NODE *p) { int o = p->n_op; if (o == OREG || o == REG || o == NAME) return SRDIR; /* Direct match */ if (o == UMUL && shumul(p->n_left, SOREG)) return SROREG; /* Convert into oreg */ return SRREG; /* put it into a register */ } /* INTEMP shapes must not contain any temporary registers */ /* XXX should this go away now? */ int shtemp(NODE *p) { return 0; #if 0 int r; if (p->n_op == STARG ) p = p->n_left; switch (p->n_op) { case REG: return (!istreg(p->n_rval)); case OREG: r = p->n_rval; if (R2TEST(r)) { if (istreg(R2UPK1(r))) return(0); r = R2UPK2(r); } return (!istreg(r)); case UMUL: p = p->n_left; return (p->n_op != UMUL && shtemp(p)); } if (optype(p->n_op) != LTYPE) return(0); return(1); #endif } static void negcon(FILE *fp, int con) { if (con < 0) fprintf(fp, "-"), con = -con; fprintf(fp, "%o", con & 0177777); } void adrcon(CONSZ val) { printf("$" CONFMT, val); } void conput(FILE *fp, NODE *p) { int val = getlval(p); switch (p->n_op) { case ICON: printf("$"); if (p->n_name[0] != '\0') { fprintf(fp, "%s", p->n_name); if (val) fprintf(fp, "+%o", val & 0177777); } else if (p->n_type == LONG || p->n_type == ULONG) negcon(fp, val >> 16); else negcon(fp, val); return; default: comperr("illegal conput, p %p", p); } } /*ARGSUSED*/ void insput(NODE *p) { comperr("insput"); } /* * Write out the upper address, like the upper register of a 2-register * reference, or the next memory location. */ void upput(NODE *p, int size) { size /= SZINT; switch (p->n_op) { case NAME: case OREG: setlval(p, getlval(p) + size); adrput(stdout, p); setlval(p, getlval(p) - size); break; case REG: printf("r%c", rnames[p->n_rval][2]); break; case ICON: /* On PDP11 upper value is low 16 bits */ printf("$"); negcon(stdout, getlval(p) & 0177777); break; default: comperr("upput bad op %d size %d", p->n_op, size); } } /* * output an address, with offsets, from p */ void adrput(FILE *io, NODE *p) { int r; if (p->n_op == FLD) p = p->n_left; switch (p->n_op) { case NAME: if (p->n_name[0] != '\0') { fputs(p->n_name, io); if (getlval(p) != 0) fprintf(io, "+%o", (int)(getlval(p) & 0177777)); } else negcon(io, getlval(p)); return; case OREG: r = p->n_rval; if (p->n_name[0]) printf("%s%s", p->n_name, getlval(p) ? "+" : ""); if (R2TEST(r) && R2UPK3(r) == 0) printf("*"); if (getlval(p)) negcon(io, getlval(p)); if (R2TEST(r)) { fprintf(io, "(%s)", rnames[R2UPK1(r)]); if (R2UPK3(r) == 1) fprintf(io, "+"); } else fprintf(io, "(%s)", rnames[p->n_rval]); return; case ICON: /* addressable value of the constant */ conput(io, p); return; case REG: switch (p->n_type) { case LONG: case ULONG: fprintf(io, "r%c", rnames[p->n_rval][1]); break; default: fprintf(io, "%s", rnames[p->n_rval]); } return; case UMUL: if (tshape(p, STARNM)) { printf("*"); adrput(io, p->n_left); break; } /* FALLTHROUGH */ default: comperr("illegal address, op %d, node %p", p->n_op, p); return; } } static char * ccbranches[] = { "jeq", /* jumpe */ "jne", /* jumpn */ "jle", /* jumple */ "jlt", /* jumpl */ "jge", /* jumpge */ "jgt", /* jumpg */ "jlos", /* jumple (jlequ) */ "jlo", /* jumpl (jlssu) */ "jhis", /* jumpge (jgequ) */ "jhi", /* jumpg (jgtru) */ }; /* printf conditional and unconditional branches */ void cbgen(int o, int lab) { if (o < EQ || o > UGT) comperr("bad conditional branch: %s", opst[o]); printf("%s " LABFMT "\n", ccbranches[o-EQ], lab); } #define IS1CON(p) ((p)->n_op == ICON && getlval(p) == 1) /* * Move postfix operators to the next statement, unless they are * within a function call or a branch. */ static void cvtree(NODE *p, struct interpass *ip2) { struct interpass *ip; NODE *q; if (callop(p->n_op) || p->n_op == CBRANCH) return; if ((p->n_op == PLUS || p->n_op == MINUS) && IS1CON(p->n_right) && (q = p->n_left)->n_op == ASSIGN && treecmp(q->n_left, q->n_right->n_left) && IS1CON(q->n_right->n_right)) { if ((p->n_op == PLUS && q->n_right->n_op == MINUS) || (p->n_op == MINUS && q->n_right->n_op == PLUS)) { nfree(p->n_right); *p = *q->n_left; if (optype(p->n_op) != LTYPE) p->n_left = tcopy(p->n_left); ip = ipnode(q); DLIST_INSERT_AFTER(ip2, ip, qelem); return; } } if (optype(p->n_op) == BITYPE) cvtree(p->n_right, ip2); if (optype(p->n_op) != LTYPE) cvtree(p->n_left, ip2); } /* * Convert AND to BIC. */ static void fixops(NODE *p, void *arg) { static int fltwritten; if (!fltwritten && (p->n_type == FLOAT || p->n_type == DOUBLE)) { printf(".globl fltused\n"); fltwritten = 1; } switch (p->n_op) { case AND: if (p->n_right->n_op == ICON) { CONSZ val = getlval(p->n_right); val = ((~val) & 0177777); setlval(p->n_right, val); } else if (p->n_right->n_op == COMPL) { NODE *q = p->n_right->n_left; nfree(p->n_right); p->n_right = q; } else p->n_right = mkunode(COMPL, p->n_right, 0, p->n_type); break; case RS: p->n_right = mkunode(UMINUS, p->n_right, 0, p->n_right->n_type); p->n_op = LS; break; case EQ: case NE: /* Hack not to clear bits if FORCC */ if (p->n_left->n_op == AND) fixops(p->n_left, 0); /* Convert an extra time */ break; } } void myreader(struct interpass *ipole) { struct interpass *ip; #ifdef PCC_DEBUG if (x2debug) { printf("myreader before\n"); printip(ipole); } #endif DLIST_FOREACH(ip, ipole, qelem) { if (ip->type != IP_NODE) continue; walkf(ip->ip_node, fixops, 0); canon(ip->ip_node); /* call it early */ } #ifdef PCC_DEBUG if (x2debug) { printf("myreader middle\n"); printip(ipole); } #endif DLIST_FOREACH(ip, ipole, qelem) { if (ip->type == IP_NODE) cvtree(ip->ip_node, ip); } #ifdef PCC_DEBUG if (x2debug) { printf("myreader after\n"); printip(ipole); } #endif } /* * Remove SCONVs where the left node is an OREG with a smaller type. */ static void delsconv(NODE *p, void *arg) { #if 0 NODE *l; if (p->n_op != SCONV || (l = p->n_left)->n_op != OREG) return; if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == LONG) { p->n_op = OREG; p->n_lval = l->n_lval; /* high word */ p->n_rval = l->n_rval; nfree(l); } #endif /* Could do this for char etc. also */ } void mycanon(NODE *p) { walkf(p, delsconv, 0); } void myoptim(struct interpass *ip) { } void rmove(int s, int d, TWORD t) { if (t < LONG || t > BTMASK) { printf("mov%s %s,%s\n", t < SHORT ? "b" : "", rnames[s],rnames[d]); /* XXX char should be full reg? */ } else if (t == LONG || t == ULONG) { /* avoid trashing double regs */ if (d > s) printf("mov r%c,r%c\nmov r%c,r%c\n", rnames[s][2],rnames[d][2], rnames[s][1],rnames[d][1]); else printf("mov r%c,r%c\nmov r%c,r%c\n", rnames[s][1],rnames[d][1], rnames[s][2],rnames[d][2]); } else if (t == FLOAT || t == DOUBLE) { printf("movf %s,%s\n", rnames[s],rnames[d]); } else comperr("bad float rmove: %d %d %x", s, d, t); } /* * For class c, find worst-case displacement of the number of * registers in the array r[] indexed by class. */ int COLORMAP(int c, int *r) { switch (c) { case CLASSA: return (r[CLASSB] * 2 + r[CLASSA]) < 5; case CLASSB: if (r[CLASSB] > 1) return 0; if (r[CLASSB] == 1 && r[CLASSA] > 0) return 0; if (r[CLASSA] > 2) return 0; return 1; case CLASSC: return r[CLASSC] < 8; } return 0; } char *rnames[] = { "r0", "r1", "r2", "r3", "r4", "r5", "sp", "pc", "r01", "r12", "r23", "r34", "XXX", "XXX", "XXX", "XXX", "fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "XXX", "XXX", }; /* * Return a class suitable for a specific type. */ int gclass(TWORD t) { if (t < LONG || t > BTMASK) return CLASSA; if (t == LONG || t == ULONG) return CLASSB; if (t == FLOAT || t == DOUBLE || t == LDOUBLE) return CLASSC; comperr("gclass"); return CLASSD; } static int argsiz(NODE *p) { TWORD t = p->n_type; if (t == LONG || t == ULONG || t == FLOAT) return 4; if (t == DOUBLE) return 8; if (t == STRTY || t == UNIONTY) return attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0); return 2; } /* * Argument specialties. */ void lastcall(NODE *p) { NODE *op = p; int size = 0; /* * Calculate arg sizes. * Mark first arg not to have - before it. */ p->n_qual = 0; if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) return; for (p = p->n_right; p->n_op == CM; p = p->n_left) { p->n_right->n_qual = 0; size += argsiz(p->n_right); } p->n_qual = 0; size += argsiz(p); p = op->n_right; if (p->n_op == CM) p = p->n_right; #if 0 /* XXX fixme */ if (p->n_type == FLOAT || p->n_type == DOUBLE || p->n_type == STRTY || p->n_type == UNIONTY) op->n_flags |= NLOCAL1; /* Does not use stack slot */ else op->n_flags &= ~NLOCAL1; #endif op->n_qual = size; /* XXX */ } static int is1con(NODE *p) { if (p->n_op == ICON && getlval(p) == 1) return 1; return 0; } /* * Special shapes. */ int special(NODE *p, int shape) { CONSZ s; switch (shape) { case SANDSCON: s = ~getlval(p); if (s < 65536 || s > -65537) return SRDIR; break; case SINCB: /* Check if subject for post-inc */ if (p->n_op == ASSIGN && p->n_right->n_op == PLUS && treecmp(p->n_left, p->n_right->n_left) && is1con(p->n_right->n_right)) return SRDIR; break; case SARGSUB: if (p->n_op == MINUS && p->n_right->n_op == ICON && p->n_left->n_op == REG) return SRDIR; break; case SARGINC: if (p->n_op == MINUS && is1con(p->n_right)) return special(p->n_left, SINCB); break; } return SRNOPE; } /* * Target-dependent command-line options. */ void mflags(char *str) { } /* * Do something target-dependent for xasm arguments. */ int myxasm(struct interpass *ip, NODE *p) { return 0; } int fldexpand(NODE *p, int cookie, char **cp) { return 0; } pcc-20181216/arch/pdp11/macdefs.h010064400017500000000000000150741303741405500151120ustar raggewheel/* $Id: macdefs.h,v 1.12 2017/01/17 13:12:13 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Machine-dependent defines for both passes. */ /* * Convert (multi-)character constant to integer. */ #define makecc(val,i) lastcon = i ? (val<<8)|lastcon : val #define ARGINIT 32 /* # bits above r5 where arguments start */ #define AUTOINIT 64 /* # bits below r5 where automatics start */ /* * Storage space requirements */ #define SZCHAR 8 #define SZBOOL 8 #define SZINT 16 #define SZFLOAT 32 #define SZDOUBLE 64 #define SZLDOUBLE 64 #define SZLONG 32 #define SZSHORT 16 #define SZLONGLONG 64 #define SZPOINT(t) 16 /* * Alignment constraints */ #define ALCHAR 8 #define ALBOOL 8 #define ALINT 16 #define ALFLOAT 16 #define ALDOUBLE 16 #define ALLDOUBLE 16 #define ALLONG 16 #define ALLONGLONG 16 #define ALSHORT 16 #define ALPOINT 16 #define ALSTRUCT 16 #define ALSTACK 16 /* * Min/max values. */ #define MIN_CHAR -128 #define MAX_CHAR 127 #define MAX_UCHAR 255 #define MIN_SHORT -32768 #define MAX_SHORT 32767 #define MAX_USHORT 65535 #define MIN_INT (-0x7fff-1) #define MAX_INT 0x7fff #define MAX_UNSIGNED 0xffff #define MIN_LONG (-0x7fffffff-1) #define MAX_LONG 0x7fffffff #define MAX_ULONG 0xffffffff #define MIN_LONGLONG 0x8000000000000000LL #define MAX_LONGLONG 0x7fffffffffffffffLL #define MAX_ULONGLONG 0xffffffffffffffffULL /* Default char is signed */ #undef CHAR_UNSIGNED #define BOOL_TYPE CHAR /* what used to store _Bool */ /* * Use large-enough types. */ typedef long long CONSZ; typedef unsigned long long U_CONSZ; typedef long long OFFSZ; #define CONFMT "%lld" /* format for printing constants */ #define LABFMT "L%d" /* format for printing labels */ #ifdef LANG_F77 #define BLANKCOMMON "_BLNK_" #define MSKIREG (M(TYSHORT)|M(TYLONG)) #define TYIREG TYLONG #define FSZLENG FSZLONG #define AUTOREG EBP #define ARGREG EBP #define ARGOFFSET 8 #endif #define BACKAUTO /* stack grows negatively for automatics */ #define BACKTEMP /* stack grows negatively for temporaries */ #undef FIELDOPS /* no bit-field instructions */ #define TARGET_ENDIAN TARGET_LE /* XXX TARGET_PDP */ #define MYINSTRING #define MYALIGN #define TARGET_ISMATH /* need private versions of these */ /* Definitions mostly used in pass2 */ #define BYTEOFF(x) ((x)&01) #define wdal(k) (BYTEOFF(k)==0) #define STOARG(p) #define STOFARG(p) #define STOSTARG(p) #define FINDMOPS /* pdp11 has instructions that modifies memory */ #define szty(t) ((t) == DOUBLE || (t) == LONGLONG || (t) == ULONGLONG ? 4 : \ (t) == FLOAT || (t) == LONG || (t) == ULONG ? 2 : 1) /* * The pdp11 has 3 register classes, 16-bit, 32-bit and floats. * Class membership and overlaps are defined in the macros RSTATUS * and ROVERLAP below. * * The classes used on pdp11 are: * A - 16-bit * B - 32-bit (concatenated 16-bit) * C - floating point */ #define R0 000 /* Scratch and return register */ #define R1 001 /* Scratch and secondary return register */ #define R2 002 /* Scratch register */ #define R3 003 /* Scratch register */ #define R4 004 /* Scratch register */ #define R5 005 /* Frame pointer */ #define SP 006 /* Stack pointer */ #define PC 007 /* Program counter */ #define R01 010 #define R12 011 #define R23 012 #define R34 013 #define FR0 020 #define FR1 021 #define FR2 022 #define FR3 023 #define FR4 024 #define FR5 025 #define FR6 026 #define FR7 027 #define MAXREGS 030 /* 24 registers */ #define RSTATUS \ SAREG|TEMPREG, SAREG|TEMPREG, SAREG, SAREG, SAREG, 0, 0, 0, \ SBREG, SBREG, SBREG, SBREG, 0, 0, 0, 0, \ SCREG, SCREG, SCREG, SCREG, 0, 0, 0, 0 #define ROVERLAP \ /* 8 basic registers */\ { R01, -1 }, \ { R01, R12, -1 }, \ { R12, R23, -1 }, \ { R23, R34, -1 }, \ { R34, -1 }, \ { -1 }, \ { -1 }, \ { -1 }, \ \ /* 4 long registers */\ { R0, R1, R12, -1 }, \ { R1, R2, R01, R23, -1 }, \ { R2, R3, R12, R34, -1 }, \ { R3, R4, R23, -1 }, \ { -1 }, \ { -1 }, \ { -1 }, \ { -1 }, \ \ /* The fp registers do not overlap with anything */\ { -1 },\ { -1 },\ { -1 },\ { -1 },\ { -1 },\ { -1 },\ { -1 },\ { -1 }, /* Return a register class based on the type of the node */ #define PCLASS(p) (p->n_type < LONG || p->n_type > BTMASK ? SAREG : \ (p->n_type == LONG || p->n_type == ULONG ? SBREG : SCREG)) #define NUMCLASS 3 /* highest number of reg classes used */ int COLORMAP(int c, int *r); #define GCLASS(x) (x < 8 ? CLASSA : x < 16 ? CLASSB : CLASSC) #define DECRA(x,y) (((x) >> (y*5)) & 31) /* decode encoded regs */ #define ENCRD(x) (x) /* Encode dest reg in n_reg */ #define ENCRA1(x) ((x) << 5) /* A1 */ #define ENCRA2(x) ((x) << 10) /* A2 */ #define ENCRA(x,y) ((x) << (5+y*5)) /* encode regs in int */ #define RETREG(x) ((x) == LONG || (x) == ULONG ? R01 : \ (x) == FLOAT || (x) == DOUBLE ? FR0 : R0) //#define R2REGS 1 /* permit double indexing */ /* XXX - to die */ #define FPREG R5 /* frame pointer */ #define STKREG SP /* stack pointer */ /* A bunch of specials to make life easier for pdp11 */ #define SANDSCON (MAXSPECIAL+1) #define SINCB (MAXSPECIAL+2) /* post-increment */ #define SINCW (MAXSPECIAL+3) /* post-increment */ #define SARGSUB (MAXSPECIAL+4) /* arg pointer to array */ #define SARGINC (MAXSPECIAL+5) /* post-increment arg */ pcc-20181216/arch/pdp11/order.c010064400017500000000000000132321303741405500146100ustar raggewheel/* $Id: order.c,v 1.4 2017/01/17 13:12:13 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass2.h" #include int canaddr(NODE *); /* is it legal to make an OREG or NAME entry which has an * offset of off, (from a register of r), if the * resulting thing had type t */ int notoff(TWORD t, int r, CONSZ off, char *cp) { return(0); /* YES */ } static int inctree(NODE *p) { if (p->n_op == MINUS && p->n_left->n_op == ASSIGN && p->n_left->n_right->n_op == PLUS && treecmp(p->n_left->n_left, p->n_left->n_right->n_left) && p->n_right->n_op == ICON && getlval(p->n_right) == 1 && p->n_left->n_right->n_right->n_op == ICON && getlval(p->n_left->n_right->n_right) == 1) { /* post-increment by 1; (r0)+ */ if (isreg(p->n_left->n_left)) /* Ignore if index not in reg */ return 1; } return 0; } /* * Turn a UMUL-referenced node into OREG. * Be careful about register classes, this is a place where classes change. */ void offstar(NODE *p, int shape) { if (x2debug) printf("offstar(%p)\n", p); if (isreg(p)) return; /* Is already OREG */ if (p->n_op == UMUL) p = p->n_left; /* double indexed umul */ if (inctree(p)) /* Do post-inc conversion */ return; if( p->n_op == PLUS || p->n_op == MINUS ){ if (p->n_right->n_op == ICON) { if (isreg(p->n_left) == 0) (void)geninsn(p->n_left, INAREG); /* Converted in ormake() */ return; } } (void)geninsn(p, INAREG); } /* * Do the actual conversion of offstar-found OREGs into real OREGs. */ void myormake(NODE *p) { NODE *q = p->n_left; if (x2debug) { printf("myormake(%p)\n", p); fwalk(p, e2print, 0); } if (inctree(q)) { if (q->n_left->n_left->n_op == TEMP) return; p->n_op = OREG; setlval(p, 0); /* Add support for index offset */ p->n_rval = R2PACK(regno(q->n_left->n_left), 0, 1); tfree(q); return; } if (q->n_op != OREG) return; p->n_op = OREG; setlval(p, getlval(q)); p->n_rval = R2PACK(q->n_rval, 0, 0); nfree(q); } /* * Shape matches for UMUL. Cooperates with offstar(). */ int shumul(NODE *p, int shape) { if (x2debug) printf("shumul(%p)\n", p); if (p->n_op == NAME && (shape & STARNM)) return SRDIR; if (shape & SOREG) return SROREG; /* Calls offstar */ return SRNOPE; } /* * Rewrite operations on binary operators (like +, -, etc...). * Called as a result of table lookup. */ int setbin(NODE *p) { if (x2debug) printf("setbin(%p)\n", p); return 0; } /* setup for assignment operator */ int setasg(NODE *p, int cookie) { if (x2debug) printf("setasg(%p)\n", p); return(0); } /* setup for unary operator */ int setuni(NODE *p, int cookie) { return(0); } /* * Special handling of some instruction register allocation. */ struct rspecial * nspecial(struct optab *q) { switch (q->op) { case MUL: if (q->visit == INAREG) { static struct rspecial s[] = { { NLEFT, R1 }, { 0 } }; return s; } else if (q->visit == INBREG) { static struct rspecial s[] = { { NRES, R01 }, { 0 } }; return s; } break; case DIV: if (q->visit == INAREG && q->ltype == TUNSIGNED) { static struct rspecial s[] = { { NLEFT, R0 }, { NRIGHT, R1 }, { NRES, R0 }, { 0 } }; return s; } else if (q->visit == INAREG) { static struct rspecial s[] = { { NRES, R0 }, { 0 } }; return s; } else if (q->visit == INBREG) { static struct rspecial s[] = { { NRES, R01 }, { 0 } }; return s; } break; case MOD: if (q->visit == INAREG && q->ltype == TUNSIGNED) { static struct rspecial s[] = { { NLEFT, R0 }, { NRIGHT, R1 }, { NRES, R0 }, { 0 } }; return s; } else if (q->visit == INBREG) { static struct rspecial s[] = { { NRES, R01 }, { 0 } }; return s; } break; case SCONV: if (q->lshape == SAREG) { static struct rspecial s[] = { { NLEFT, R1 }, { NRES, R01 }, { 0 } }; return s; } break; } comperr("nspecial entry %d", q - table); return 0; /* XXX gcc */ } /* * Set evaluation order of a binary node if it differs from default. */ int setorder(NODE *p) { return 0; /* nothing differs on x86 */ } /* * set registers in calling conventions live. */ int * livecall(NODE *p) { static int r[] = { -1 }; return r; } /* * Signal whether the instruction is acceptable for this target. */ int acceptable(struct optab *op) { return 1; } pcc-20181216/arch/pdp11/table.c010064400017500000000000000421111107665054500145710ustar raggewheel/* $Id: table.c,v 1.5 2008/10/19 15:25:25 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass2.h" # define TLL TLONGLONG|TULONGLONG # define ANYSIGNED TINT|TLONG|TSHORT|TCHAR # define ANYUSIGNED TUNSIGNED|TULONG|TUSHORT|TUCHAR # define ANYFIXED ANYSIGNED|ANYUSIGNED # define TUWORD TUNSIGNED # define TSWORD TINT # define TWORD TUWORD|TSWORD # define ANYSH SCON|SAREG|SOREG|SNAME # define ARONS SAREG|SOREG|SNAME|STARNM struct optab table[] = { /* First entry must be an empty entry */ { -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", }, /* PCONVs are usually not necessary */ { PCONV, INAREG, SAREG, TWORD|TPOINT, SAREG, TWORD|TPOINT, 0, RLEFT, "", }, /* convert char to int or unsigned */ { SCONV, INAREG, SAREG, TCHAR, SAREG, TINT|TUNSIGNED, NAREG|NASL, RESC1, "", }, /* chars are stored as ints in registers */ { SCONV, INAREG, SOREG|SCON|SNAME, TCHAR, SAREG, TINT, NAREG|NASL, RESC1, "movb AL,A1\n", }, /* convert uchar to int or unsigned */ { SCONV, INAREG, SAREG|SOREG|SCON|SNAME, TUCHAR, SAREG, TINT|TUNSIGNED, NAREG, RESC1, "clr A1\nbisb AL,A1\n", }, /* convert (u)int to (u)char. Nothing to do. */ { SCONV, INAREG, SAREG, TWORD, SANY, TCHAR|TUCHAR, 0, RLEFT, "", }, /* convert (u)int to (u)int */ { SCONV, INAREG, SAREG, TWORD, SANY, TWORD, 0, RLEFT, "", }, /* convert pointer to (u)int */ { SCONV, INAREG, SAREG, TPOINT, SANY, TWORD, 0, RLEFT, "", }, /* convert int to long from memory */ { SCONV, INBREG, SNAME|SOREG, TINT, SANY, TLONG, NBREG, RESC1, "mov AL,U1\nsxt A1\n", }, /* int -> (u)long. XXX - only in r0 and r1 */ { SCONV, INBREG, SAREG, TINT, SANY, TLONG|TULONG, NSPECIAL|NBREG|NBSL, RESC1, "tst AL\nsxt r0\n", }, /* unsigned -> (u)long. XXX - only in r0 and r1 */ { SCONV, INBREG, SAREG, TUNSIGNED, SANY, TLONG|TULONG, NSPECIAL|NBREG|NBSL, RESC1, "clr r0\n", }, /* uint -> double */ { SCONV, INCREG, SAREG|SNAME|SOREG|SCON, TUNSIGNED, SANY, TFLOAT|TDOUBLE, NCREG|NCSL, RESC1, "mov AL,-(sp)\nclr -(sp)\n" "setl\nmovif (sp)+,A1\nseti\n", }, /* long -> int */ { SCONV, INAREG, SBREG|SOREG|SNAME, TLONG|TULONG, SAREG, TWORD, NAREG|NASL, RESC1, "mov UL,A1\n", }, /* (u)long -> (u)long, nothing */ { SCONV, INBREG, SBREG, TLONG|TULONG, SANY, TLONG|TULONG, NBREG|NBSL, RESC1, "", }, /* long -> double */ { SCONV, INCREG, SBREG|SNAME|SOREG|SCON, TLONG, SANY, TFLOAT|TDOUBLE, NCREG|NCSL, RESC1, "mov UL,-(sp)\nmov AL,-(sp)\n" "setl\nmovif (sp)+,A1\nseti\n", }, /* * Subroutine calls. */ { CALL, INBREG, SCON, TANY, SBREG, TLONG|TULONG, NBREG|NBSL, RESC1, "jsr pc,*CL\nZC", }, { UCALL, INBREG, SCON, TANY, SBREG, TLONG|TULONG, NBREG|NBSL, RESC1, "jsr pc,*CL\n", }, { CALL, FOREFF, SCON|SNAME|SOREG, TANY, SANY, TANY, 0, 0, "jsr pc,*AL\nZC", }, { UCALL, FOREFF, SCON|SNAME|SOREG, TANY, SANY, TANY, 0, 0, "jsr pc,*AL\n", }, { CALL, INAREG, SCON|SOREG|SNAME, TANY, SAREG, TWORD|TPOINT|TCHAR|TUCHAR, NAREG|NASL, RESC1, "jsr pc,*AL\nZC", }, { UCALL, INAREG, SCON|SOREG|SNAME, TANY, SAREG, TWORD|TPOINT|TCHAR|TUCHAR, NAREG|NASL, RESC1, "jsr pc,*AL\n", }, { CALL, FOREFF, SAREG, TANY, SANY, TANY, 0, 0, "jsr pc,(AL)\nZC", }, { UCALL, FOREFF, SAREG, TANY, SANY, TANY, 0, 0, "jsr pc,(AL)\n", }, { CALL, INAREG, SAREG, TANY, SANY, TANY, NAREG|NASL, RESC1, /* should be 0 */ "jsr pc,(AL)\nZC", }, { UCALL, INAREG, SAREG, TANY, SANY, TANY, NAREG|NASL, RESC1, /* should be 0 */ "jsr pc,(AL)\n", }, /* * The next rules handle all binop-style operators. */ /* Add one to anything left but use only for side effects */ { PLUS, FOREFF|INAREG|FORCC, SAREG|SNAME|SOREG, TWORD|TPOINT, SONE, TANY, 0, RLEFT|RESCC, "inc AL\n", }, /* add one for char to reg, special handling */ { PLUS, FOREFF|INAREG|FORCC, SAREG, TCHAR|TUCHAR, SONE, TANY, 0, RLEFT|RESCC, "inc AL\n", }, /* add one for char to memory */ { PLUS, FOREFF|FORCC, SNAME|SOREG|STARNM, TCHAR|TUCHAR, SONE, TANY, 0, RLEFT|RESCC, "incb AL\n", }, { PLUS, INBREG|FOREFF, SBREG, TLONG, SBREG|SNAME|SOREG|SCON, TLONG, 0, RLEFT, "add AR,AL\nadd UR,UL\nadc AL\n", }, /* Add to reg left and reclaim reg */ { PLUS, INAREG|FOREFF|FORCC, SAREG|SNAME|SOREG, TWORD|TPOINT, SAREG|SNAME|SOREG|SCON, TWORD|TPOINT, 0, RLEFT|RESCC, "add AR,AL\n", }, /* Add to anything left but use only for side effects */ { PLUS, FOREFF|FORCC, SNAME|SOREG, TWORD|TPOINT, SAREG|SNAME|SOREG|SCON, TWORD|TPOINT, 0, RLEFT|RESCC, "add AR,AL\n", }, { PLUS, INAREG|FOREFF|FORCC, SAREG, TCHAR|TUCHAR, SAREG|SNAME|SOREG|SCON, TCHAR|TUCHAR, 0, RLEFT|RESCC, "add AR,AL\n", }, /* Post-increment read, byte */ { MINUS, INAREG, SINCB, TCHAR|TUCHAR, SONE, TANY, NAREG, RESC1, "movb ZG,A1\nincb ZG\n", }, /* Post-increment read, int */ { MINUS, INAREG, SINCB, TWORD|TPOINT, SONE, TANY, NAREG, RESC1, "mov ZG,A1\ninc ZG\n", }, { MINUS, INBREG|FOREFF, SBREG, TLONG|TULONG, SBREG|SNAME|SOREG|SCON, TLONG|TULONG, 0, RLEFT, "sub AR,AL\nsub UR,UL\nsbc AL\n", }, /* Sub one from anything left */ { MINUS, FOREFF|INAREG|FORCC, SAREG|SNAME|SOREG, TWORD|TPOINT, SONE, TANY, 0, RLEFT|RESCC, "dec AL\n", }, { MINUS, INAREG|FOREFF, SAREG, TWORD|TPOINT, SAREG|SNAME|SOREG|SCON, TWORD|TPOINT, 0, RLEFT, "sub AR,AL\n", }, /* Sub from anything left but use only for side effects */ { MINUS, FOREFF|INAREG|FORCC, SAREG|SNAME|SOREG, TWORD|TPOINT, SAREG|SNAME|SOREG|SCON, TWORD|TPOINT, 0, RLEFT|RESCC, "sub AR,AL\n", }, /* Sub one left but use only for side effects */ { MINUS, FOREFF|FORCC, SAREG|SNAME|SOREG, TCHAR|TUCHAR, SONE, TANY, 0, RLEFT|RESCC, "decb AL\n", }, /* Sub from anything left but use only for side effects */ { MINUS, FOREFF|FORCC, SAREG|SNAME|SOREG, TCHAR|TUCHAR, SAREG|SNAME|SOREG|SCON, TCHAR|TUCHAR|TWORD|TPOINT, 0, RLEFT|RESCC, "subb AR,AL\n", }, /* * The next rules handle all shift operators. */ { LS, INBREG|FOREFF, SBREG, TLONG|TULONG, SANY, TANY, 0, RLEFT, "ashc AR,AL\n", }, { LS, INAREG|FOREFF, SAREG, TWORD, SONE, TANY, 0, RLEFT, "asl AL\n", }, { LS, INAREG|FOREFF, SAREG, TWORD, ANYSH, TWORD, 0, RLEFT, "ash AR,AL\n", }, /* * The next rules takes care of assignments. "=". */ /* First optimizations, in lack of weight it uses first found */ /* Start with class A registers */ /* Clear word at address */ { ASSIGN, FOREFF|FORCC, ARONS, TWORD|TPOINT, SZERO, TANY, 0, RESCC, "clr AL\n", }, /* Clear word at reg */ { ASSIGN, FOREFF|INAREG, SAREG, TWORD|TPOINT, SZERO, TANY, 0, RDEST, "clr AL\n", }, /* Clear byte at address. No reg here. */ { ASSIGN, FOREFF, SNAME|SOREG|STARNM, TCHAR|TUCHAR, SZERO, TANY, 0, RDEST, "clrb AL\n", }, /* Clear byte in reg. must clear the whole register. */ { ASSIGN, FOREFF|INAREG, SAREG, TCHAR|TUCHAR, SZERO, TANY, 0, RDEST, "clr AL\n", }, /* The next is class B regs */ /* Clear long at address or in reg */ { ASSIGN, FOREFF|INBREG, SNAME|SOREG|SBREG, TLONG|TULONG, SZERO, TANY, 0, RDEST, "clr AL\nclr UL\n", }, /* Save 2 bytes if high-order bits are zero */ { ASSIGN, FOREFF|INBREG, SBREG, TLONG|TULONG, SSCON, TLONG, 0, RDEST, "mov UR,UL\nsxt AL\n", }, /* Must have multiple rules for long otherwise regs may be trashed */ { ASSIGN, FOREFF|INBREG, SBREG, TLONG|TULONG, SCON|SNAME|SOREG, TLONG|TULONG, 0, RDEST, "mov AR,AL\nmov UR,UL\n", }, { ASSIGN, FOREFF|INBREG, SNAME|SOREG, TLONG|TULONG, SBREG, TLONG|TULONG, 0, RDEST, "mov AR,AL\nmov UR,UL\n", }, { ASSIGN, FOREFF, SNAME|SOREG, TLONG|TULONG, SCON|SNAME|SOREG, TLONG|TULONG, 0, 0, "mov AR,AL\nmov UR,UL\n", }, { ASSIGN, INBREG|FOREFF, SBREG, TLONG|TULONG, SBREG, TLONG|TULONG, 0, RDEST, "ZE\n", }, { ASSIGN, FOREFF|INAREG|FORCC, SAREG, TWORD|TPOINT, SAREG|SNAME|SOREG|SCON, TWORD|TPOINT, 0, RDEST|RESCC, "mov AR,AL\n", }, { ASSIGN, FOREFF|INAREG|FORCC, ARONS, TWORD|TPOINT, SAREG, TWORD|TPOINT, 0, RDEST|RESCC, "mov AR,AL\n", }, { ASSIGN, FOREFF|FORCC, SNAME|SOREG, TWORD|TPOINT, SNAME|SOREG|SCON, TWORD|TPOINT, 0, RESCC, "mov AR,AL\n", }, { ASSIGN, FOREFF|INAREG|FORCC, SAREG, TCHAR|TUCHAR, ARONS|SCON, TCHAR|TUCHAR, 0, RDEST|RESCC, "movb AR,AL\n", }, { ASSIGN, FOREFF|INAREG|FORCC, ARONS, TCHAR|TUCHAR, SAREG, TCHAR|TUCHAR, 0, RDEST|RESCC, "movb AR,AL\n", }, { ASSIGN, FOREFF|FORCC, SNAME|SOREG|STARNM, TCHAR|TUCHAR, SNAME|SOREG|SCON|STARNM, TCHAR|TUCHAR, 0, RDEST|RESCC, "movb AR,AL\n", }, { ASSIGN, FOREFF|INCREG, SCREG, TDOUBLE, SNAME|SOREG|SCON, TDOUBLE, 0, RDEST, "movf AR,AL\n", }, { ASSIGN, FOREFF|INCREG, SCREG, TFLOAT, SNAME|SOREG|SCON, TFLOAT, 0, RDEST, "movof AR,AL\n", }, { ASSIGN, FOREFF|INCREG, SNAME|SOREG|SCREG, TDOUBLE, SCREG, TDOUBLE, 0, RDEST, "movf AR,AL\n", }, { ASSIGN, FOREFF|INCREG, SNAME|SOREG|SCREG, TFLOAT, SCREG, TFLOAT, 0, RDEST, "movfo AR,AL\n", }, /* * DIV/MOD/MUL */ /* XXX - mul may use any odd register, only r1 for now */ { MUL, INAREG, SAREG, TWORD|TPOINT, SAREG|SNAME|SOREG|SCON, TWORD|TPOINT, NSPECIAL, RLEFT, "mul AR,AL\n", }, { MUL, INBREG, SBREG|SNAME|SCON|SOREG, TLONG|TULONG, SBREG|SNAME|SCON|SOREG, TLONG|TULONG, NSPECIAL|NBREG|NBSL|NBSR, RESC1, "mov UR,-(sp)\nmov AR,-(sp)\n" "mov UL,-(sp)\nmov AL,-(sp)\n" "jsr pc,lmul\nadd $10,sp\n", }, { MUL, INCREG, SCREG, TFLOAT|TDOUBLE, SCREG|SNAME|SOREG, TFLOAT|TDOUBLE, 0, RLEFT, "mulf AR,AL\n", }, /* need extra move to be sure N flag is correct for sxt */ { DIV, INAREG, ANYSH, TINT|TPOINT, ANYSH, TINT|TPOINT, NSPECIAL, RDEST, "mov AL,r1\nsxt r0\ndiv AR,r0\n", }, /* udiv uses args in registers */ { DIV, INAREG, SAREG, TUNSIGNED, SAREG, TUNSIGNED, NSPECIAL|NAREG|NASL|NASR, RESC1, "jsr pc,udiv\n", }, { DIV, INBREG, SBREG|SNAME|SCON|SOREG, TLONG|TULONG, SBREG|SNAME|SCON|SOREG, TLONG|TULONG, NSPECIAL|NBREG|NBSL|NBSR, RESC1, "mov UR,-(sp)\nmov AR,-(sp)\n" "mov UL,-(sp)\nmov AL,-(sp)\n" "jsr pc,ldiv\nadd $10,sp\n", }, { DIV, INCREG, SCREG, TFLOAT|TDOUBLE, SCREG|SNAME|SOREG, TFLOAT|TDOUBLE, 0, RLEFT, "divf AR,AL\n", }, /* XXX merge the two below to one */ { MOD, INBREG, SBREG|SNAME|SCON|SOREG, TLONG, SBREG|SNAME|SCON|SOREG, TLONG, NSPECIAL|NBREG|NBSL|NBSR, RESC1, "mov UR,-(sp)\nmov AR,-(sp)\n" "mov UL,-(sp)\nmov AL,-(sp)\n" "jsr pc,lrem\nadd $10,sp\n", }, { MOD, INBREG, SBREG|SNAME|SCON|SOREG, TULONG, SBREG|SNAME|SCON|SOREG, TULONG, NSPECIAL|NBREG|NBSL|NBSR, RESC1, "mov UR,-(sp)\nmov AR,-(sp)\n" "mov UL,-(sp)\nmov AL,-(sp)\n" "jsr pc,ulrem\nadd $10,sp\n", }, /* urem uses args in registers */ { MOD, INAREG, SAREG, TUNSIGNED, SAREG, TUNSIGNED, NSPECIAL|NAREG|NASL|NASR, RESC1, "jsr pc,urem\n", }, /* * Indirection operators. */ { UMUL, INBREG, SANY, TPOINT|TWORD, SOREG, TLONG|TULONG, NBREG, RESC1, /* |NBSL - may overwrite index reg */ "mov AR,A1\nmov UR,U1\n", }, { UMUL, INAREG, SANY, TPOINT|TWORD, SOREG, TPOINT|TWORD, NAREG|NASL, RESC1, "mov AR,A1\n", }, { UMUL, INAREG, SANY, TANY, SOREG, TCHAR|TUCHAR, NAREG|NASL, RESC1, "movb AR,A1\n", }, /* * Logical/branching operators */ { OPLOG, FORCC, SAREG|SOREG|SNAME|SCON, TWORD|TPOINT, SZERO, TANY, 0, RESCC, "tst AL\n", }, { OPLOG, FORCC, SAREG|SOREG|SNAME|SCON, TCHAR|TUCHAR, SZERO, TANY, 0, RESCC, "tstb AL\n", }, { OPLOG, FORCC, SAREG|SOREG|SNAME|SCON, TWORD|TPOINT, SAREG|SOREG|SNAME|SCON, TWORD|TPOINT, 0, RESCC, "cmp AL,AR\n", }, { OPLOG, FORCC, SAREG|SOREG|SNAME|SCON, TCHAR|TUCHAR, SAREG|SOREG|SNAME|SCON, TCHAR|TUCHAR, 0, RESCC, "cmpb AL,AR\n", }, { OPLOG, FORCC, SBREG|SOREG|SNAME|SCON, TLONG|TULONG, SZERO, TANY, 0, RNULL, "ZD", }, { OPLOG, FORCC, SBREG|SOREG|SNAME, TLONG|TULONG, SBREG|SOREG|SNAME, TLONG|TULONG, 0, RNULL, "ZF", }, /* AND/OR/ER/NOT */ /* Optimize if high order bits are zero */ { AND, FOREFF|INBREG|FORCC, SOREG|SNAME|SBREG, TLONG|TULONG, SANDSCON, TLONG|TULONG, 0, RLEFT|RESCC, "clr AL\nbic UR,UL\n", }, { AND, INBREG|FORCC, SBREG, TLONG|TULONG, SCON|SBREG|SOREG|SNAME, TLONG|TULONG, 0, RLEFT|RESCC, "bic AR,AL\nbic UR,UL\n", }, /* set status bits */ { AND, FORCC, ARONS|SCON, TWORD|TPOINT, ARONS|SCON, TWORD|TPOINT, 0, RESCC, "bit AR,AL\n", }, /* AND with int */ { AND, INAREG|FORCC|FOREFF, SAREG|SNAME|SOREG, TWORD, SCON|SAREG|SOREG|SNAME, TWORD, 0, RLEFT|RESCC, "bic AR,AL\n", }, /* AND with char */ { AND, INAREG|FORCC, SAREG|SOREG|SNAME, TCHAR|TUCHAR, ARONS|SCON, TCHAR|TUCHAR, 0, RLEFT|RESCC, "bicb AR,AL\n", }, { OR, INBREG|FORCC, SBREG, TLONG|TULONG, SCON|SBREG|SOREG|SNAME, TLONG|TULONG, 0, RLEFT|RESCC, "bis AR,AL\nbis UR,UL\n", }, /* OR with int */ { OR, FOREFF|INAREG|FORCC, ARONS, TWORD, ARONS|SCON, TWORD, 0, RLEFT|RESCC, "bis AR,AL\n", }, /* OR with char */ { OR, INAREG|FORCC, SAREG|SOREG|SNAME, TCHAR|TUCHAR, ARONS|SCON, TCHAR|TUCHAR, 0, RLEFT|RESCC, "bisb AR,AL\n", }, /* XOR with int (extended insn) */ { ER, INAREG|FORCC, ARONS, TWORD, SAREG, TWORD, 0, RLEFT|RESCC, "xor AR,AL\n", }, /* XOR with char (extended insn) */ { ER, INAREG|FORCC, SAREG, TCHAR|TUCHAR, SAREG, TCHAR|TUCHAR, 0, RLEFT|RESCC, "xor AR,AL\n", }, /* * Jumps. */ { GOTO, FOREFF, SCON, TANY, SANY, TANY, 0, RNOP, "jbr LL\n", }, /* * Convert LTYPE to reg. */ /* Two bytes less if high half of constant is zero */ { OPLTYPE, INBREG, SANY, TANY, SSCON, TLONG|TULONG, NBREG, RESC1, "mov UL,U1\nsxt A1\n", }, /* XXX - avoid OREG index register to be overwritten */ { OPLTYPE, INBREG, SANY, TANY, SCON|SBREG|SNAME|SOREG, TLONG|TULONG, NBREG, RESC1, "mov AL,A1\nmov UL,U1\n", }, { OPLTYPE, INAREG, SANY, TANY, SAREG|SCON|SOREG|SNAME, TWORD|TPOINT, NAREG|NASR, RESC1, "mov AL,A1\n", }, { OPLTYPE, INAREG, SANY, TANY, SAREG|SCON|SOREG|SNAME, TCHAR, NAREG, RESC1, "movb AR,A1\n", }, { OPLTYPE, INAREG, SANY, TANY, SAREG|SCON|SOREG|SNAME, TUCHAR, NAREG, RESC1, "clr A1\nbisb AL,A1\n", }, { OPLTYPE, INCREG, SANY, TANY, SCREG|SCON|SOREG|SNAME, TDOUBLE, NCREG, RESC1, "movf AL,A1\n", }, { OPLTYPE, INCREG, SANY, TANY, SCREG|SCON|SOREG|SNAME, TFLOAT, NCREG, RESC1, "movof AL,A1\n", }, /* * Negate a word. */ { UMINUS, INAREG|FOREFF, SAREG, TWORD|TPOINT|TCHAR|TUCHAR, SANY, TANY, 0, RLEFT, "neg AL\n", }, { UMINUS, INBREG|FOREFF, SBREG|SOREG|SNAME, TLONG, SANY, TANY, 0, RLEFT, "neg AL\nneg UL\nsbc AL\n", }, { COMPL, INBREG, SBREG, TLONG|TULONG, SANY, TANY, 0, RLEFT, "com AL\ncom UL\n", }, { COMPL, INAREG, SAREG, TWORD, SANY, TANY, 0, RLEFT, "com AL\n", }, /* * Arguments to functions. */ { FUNARG, FOREFF, SCON|SBREG|SNAME|SOREG, TLONG|TULONG, SANY, TLONG|TULONG, 0, RNULL, "mov UL,ZA(sp)\nmov AL,-(sp)\n", }, { FUNARG, FOREFF, SZERO, TANY, SANY, TANY, 0, RNULL, "clr ZA(sp)\n", }, { FUNARG, FOREFF, SARGSUB, TWORD|TPOINT, SANY, TWORD|TPOINT, 0, RNULL, "ZB", }, { FUNARG, FOREFF, SARGINC, TWORD|TPOINT, SANY, TWORD|TPOINT, 0, RNULL, "ZH", }, { FUNARG, FOREFF, SCON|SAREG|SNAME|SOREG, TWORD|TPOINT, SANY, TWORD|TPOINT, 0, RNULL, "mov AL,ZA(sp)\n", }, { FUNARG, FOREFF, SCON, TCHAR|TUCHAR, SANY, TANY, 0, RNULL, "mov AL,ZA(sp)\n", }, { FUNARG, FOREFF, SNAME|SOREG, TCHAR, SANY, TCHAR, NAREG, RNULL, "movb AL,A1\nmov A1,ZA(sp)\n", }, { FUNARG, FOREFF, SNAME|SOREG, TUCHAR, SANY, TUCHAR, NAREG, RNULL, "clr ZA(sp)\nbisb AL,(sp)\n", }, { FUNARG, FOREFF, SAREG, TUCHAR|TCHAR, SANY, TUCHAR|TCHAR, 0, RNULL, "mov AL,ZA(sp)\n", }, { FUNARG, FOREFF, SCREG, TFLOAT|TDOUBLE, SANY, TANY, 0, RNULL, "movf AL,ZA(sp)\n", }, # define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,"" { UMUL, DF( UMUL ), }, { ASSIGN, DF(ASSIGN), }, { STASG, DF(STASG), }, { FLD, DF(FLD), }, { OPLEAF, DF(NAME), }, /* { INIT, DF(INIT), }, */ { OPUNARY, DF(UMINUS), }, { OPANY, DF(BITYPE), }, { FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" }, }; int tablesize = sizeof(table)/sizeof(table[0]); pcc-20181216/arch/pdp7004075500017500000000000000000001340533064000131755ustar raggewheelpcc-20181216/arch/pdp7/CVS004075500017500000000000000000001340533064000136305ustar raggewheelpcc-20181216/arch/pdp7/CVS/Root010064400017500000000000000000111340533064000145420ustar raggewheel/cvsroot pcc-20181216/arch/pdp7/CVS/Repository010064400017500000000000000000161340533064000160030ustar raggewheelpcc/arch/pdp7 pcc-20181216/arch/pdp7/CVS/Entries010064400017500000000000000003651340533064000152440ustar raggewheel/code.c/1.7/Thu Feb 16 18:55:31 2017// /local.c/1.8/Thu Feb 16 18:55:31 2017// /local2.c/1.9/Thu Feb 16 18:55:31 2017// /macdefs.h/1.8/Thu Feb 16 18:55:31 2017// /order.c/1.6/Thu Feb 16 18:55:31 2017// /table.c/1.12/Thu Feb 16 18:55:31 2017// D pcc-20181216/arch/pdp7/code.c010064400017500000000000000125701305137264300143420ustar raggewheel/* $Id: code.c,v 1.7 2017/02/16 18:55:31 ragge Exp $ */ /* * Copyright (c) 2017 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass1.h" #ifdef LANG_CXX #define p1listf listf #define p1tfree tfree #define P1ND NODE #else #define NODE P1ND #define talloc p1alloc #endif /* * Print out assembler segment name. */ void setseg(int seg, char *name) { #if 0 switch (seg) { case PROG: name = ".text"; break; case DATA: case LDATA: name = ".data"; break; case UDATA: break; case PICLDATA: name = ".section .data.rel.local,\"aw\",@progbits";break; case PICDATA: name = ".section .data.rel.rw,\"aw\",@progbits"; break; case PICRDATA: name = ".section .data.rel.ro,\"aw\",@progbits"; break; case STRNG: case RDATA: name = ".data"; break; case TLSDATA: name = ".section .tdata,\"awT\",@progbits"; break; case TLSUDATA: name = ".section .tbss,\"awT\",@nobits"; break; case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break; case DTORS: name = ".section\t.dtors,\"aw\",@progbits"; break; case NMSEG: printf(PRTPREF "\t.section %s,\"a%c\",@progbits\n", name, cftnsp ? 'x' : 'w'); return; } printf(PRTPREF "\t%s\n", name); #endif } /* nothing on pdp7 */ void defalign(int al) { } /* * Define everything needed to print out some data (or text). * This means segment, alignment, visibility, etc. */ void defloc(struct symtab *sp) { extern void dellab(int); char *name; name = getexname(sp); if (sp->slevel == 0) { if (sp->sclass == STATIC) printf(PRTPREF "\t.local %s\n", name); printf(PRTPREF "%s:\t", name); } else { dellab(sp->soffset); printf(PRTPREF LABFMT ":\t", sp->soffset); } } /* * code for the end of a function * deals with struct return here */ void efcode(void) { if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) return; } /* * code for the beginning of a function; a is an array of * indices in symtab for the arguments; n is the number * pdp7 has its arguments after the function call, must * put them aside directly. */ void bfcode(struct symtab **sp, int cnt) { P1ND *p, *p2; char *c; int i, l; /* handcraft isz */ l = strlen(cftnsp->sname)+10; c = tmpalloc(l); snprintf(c, l, " isz %s\n", exname(cftnsp->sname)); /* Convert param symtab entries to NAMEs */ for (i = 0; i < cnt; i++) { sp[i]->sclass = STATIC; sp[i]->soffset = getlab(); p2 = cast(buildtree(ADDROF, nametree(cftnsp), 0), INCREF(INCREF(sp[i]->stype)), 0); p = buildtree(ASSIGN, nametree(sp[i]), buildtree(UMUL, buildtree(UMUL, p2, 0), 0)); ecomp(p); send_passt(IP_ASM, c); printf(LABFMT ": 0\n", sp[i]->soffset); } } /* called just before final exit */ /* flag is 1 if errors, 0 if none */ void ejobcode(int flag) { extern void printlab(void); printlab(); } void bjobcode(void) { astypnames[INT] = astypnames[UNSIGNED] = ""; } /* * Called with a function call with arguments as argument. * This is done early in buildtree() and only done once. * Returns p. */ NODE * funcode(NODE *p) { extern int gotnr; NODE *r, *l; TWORD t = DECREF(DECREF(p->n_left->n_type)); int stcall; stcall = ISSOU(t); /* * We may have to prepend: * - Hidden arg0 for struct return (in reg or on stack). * - ebx in case of PIC code. */ /* Fix function call arguments. On x86, just add funarg */ for (r = p->n_right; r->n_op == CM; r = r->n_left) { if (r->n_right->n_op != STARG) r->n_right = block(FUNARG, r->n_right, NIL, r->n_right->n_type, r->n_right->n_df, r->n_right->n_ap); } if (r->n_op != STARG) { l = talloc(); *l = *r; r->n_op = FUNARG; r->n_left = l; r->n_type = l->n_type; } return p; } /* fix up type of field p */ void fldty(struct symtab *p) { } /* * XXX - fix genswitch. */ int mygenswitch(int num, TWORD type, struct swents **p, int n) { return 0; } NODE * builtin_return_address(const struct bitable *bt, NODE *a) { uerror("missing builtin_return_address"); return bcon(0); } NODE * builtin_frame_address(const struct bitable *bt, NODE *a) { uerror("missing __builtin_frame_address"); return bcon(0); } /* * Return "canonical frame address". */ NODE * builtin_cfa(const struct bitable *bt, NODE *a) { uerror("missing builtin_cfa"); return bcon(0); } pcc-20181216/arch/pdp7/local.c010064400017500000000000000177571305137264300145360ustar raggewheel/* $Id: local.c,v 1.8 2017/02/16 18:55:31 ragge Exp $ */ /* * Copyright (c) 2017 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "pass1.h" #undef NIL #define NIL NULL #ifdef LANG_CXX #define P1ND NODE #define p1nfree nfree #define p1fwalk fwalk #define p1tcopy tcopy #endif /* this file contains code which is dependent on the target machine */ /* clocal() is called to do local transformations on * an expression tree preparitory to its being * written out in intermediate code. * * the major essential job is rewriting the * automatic variables and arguments in terms of * REG and OREG nodes * conversion ops which are not necessary are also clobbered here * in addition, any special features (such as rewriting * exclusive or) are easily handled here as well */ P1ND * clocal(P1ND *p) { P1ND *r; register struct symtab *q; register int o; #ifdef PCC_DEBUG if (xdebug) { printf("clocal: %p\n", p); p1fwalk(p, eprint, 0); } #endif switch( o = p->n_op ){ case NAME: if ((q = p->n_sp) == NULL) return p; /* Nothing to care about */ switch (q->sclass) { case AUTO: /* fake up a structure reference */ r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); slval(r, 0); r->n_rval = FPREG; p = stref(block(STREF, r, p, 0, 0, 0)); break; case PARAM: cerror("PARAM"); break; case USTATIC: break; case STATIC: break; case REGISTER: p->n_op = REG; slval(p, 0); p->n_rval = q->soffset; break; case EXTERN: case EXTDEF: break; } break; case PCONV: if (coptype(p->n_left->n_op) == LTYPE) { p->n_left->n_type = p->n_type; p = p1nfree(p); } break; case SCONV: break; case PMCONV: case PVCONV: r = buildtree(o==PMCONV?MUL:DIV, p->n_left, p->n_right); p1nfree(p); p = r; break; case FORCE: /* put return value in return reg */ p->n_op = ASSIGN; p->n_right = p->n_left; p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0); p->n_left->n_rval = p->n_left->n_type == BOOL ? RETREG(CHAR) : RETREG(p->n_type); break; } #ifdef PCC_DEBUG if (xdebug) { printf("clocal end: %p\n", p); p1fwalk(p, eprint, 0); } #endif return(p); } P1ND * offcon(OFFSZ o, TWORD t, union dimfun *d, struct attr *ap) { P1ND *p; if (t == (PTR|CHAR) || t == (PTR|UCHAR)) p = xbcon((o/SZCHAR), NULL, INTPTR); else p = xbcon((o/SZINT), NULL, INTPTR); return p; } void myp2tree(P1ND *p) { } /*ARGSUSED*/ int andable(P1ND *p) { return(1); /* all names can have & taken on them */ } /* * Return 1 if a variable of type type is OK to put in register. */ int cisreg(TWORD t) { return 1; } /* * Allocate off bits on the stack. p is a tree that when evaluated * is the multiply count for off, t is a storeable node where to write * the allocated address. */ void spalloc(P1ND *t, P1ND *p, OFFSZ off) { P1ND *sp; p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */ /* sub the size from sp */ sp = block(REG, NIL, NIL, p->n_type, 0, 0); slval(sp, 0); sp->n_rval = STKREG; ecomp(buildtree(MINUSEQ, sp, p)); /* save the address of sp */ sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap); slval(sp, 0); sp->n_rval = STKREG; t->n_type = sp->n_type; ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */ } static int chalv, curbits; /* * print out a constant node, may be associated with a label. * Do not free the node after use. * off is bit offset from the beginning of the aggregate * fsz is the number of bits this is referring to */ int ninval(CONSZ off, int fsz, P1ND *p) { struct symtab *sp = p->n_sp; long l = glval(p); if (p->n_type != CHAR && p->n_type != UCHAR && chalv) printf(" 0%o\n", curbits), chalv = 0; switch (p->n_type) { case CHAR: case UCHAR: if ((msettings & M_CHAR18) == 0) { if (chalv) { printf(" 0%o\n", curbits | ((int)l & 0777)); chalv = 0; } else curbits = (l & 0777) << 9, chalv = 1; break; } /* FALLTHROUGH */ case INT: case UNSIGNED: printf("0%o", (int)l); if (sp != NULL) { if ((sp->sclass == STATIC && sp->slevel > 0)) { printf("+" LABFMT, (int)sp->soffset); } else printf("+%s", getexname(sp)); } printf("\n"); break; case PTR+CHAR: case PTR+UCHAR: if (ISCHAR9) printf(".byteptr "); if (l) printf("0%o%s", (int)l, sp ? "+" : ""); if (sp != NULL) { if ((sp->sclass == STATIC && sp->slevel > 0)) { printf(LABFMT, (int)sp->soffset); } else printf("%s", getexname(sp)); } printf("\n"); break; default: return 0; } return 1; } void myendinit() { if (chalv) printf(" 0%o\n", curbits), chalv = 0; } void instring(struct symtab *sp) { char *s = sp->sname; unsigned short word; defloc(sp); printf("\n"); for (; ; ) { word = (*s == '\\' ? esccon(&s) : (unsigned)*s++) << 9; if (word == 0 || *s == 0) break; word |= (*s == '\\' ? esccon(&s) : (unsigned)*s++); printf(" 0%o\n", word); } printf(" 0%o\n", word); } /* make a name look like an external name in the local machine */ char * exname(char *p) { static char b[100] = "_"; strcpy(b+1, p); return b; } /* * map types which are not defined on the local machine */ TWORD ctype(TWORD type) { switch (BTYPE(type)) { case SHORT: MODTYPE(type,INT); break; case USHORT: MODTYPE(type,UNSIGNED); } return (type); } void calldec(P1ND *p, P1ND *q) { } void extdec(struct symtab *q) { } /* make a common declaration for id, if reasonable */ void defzero(struct symtab *sp) { int off; char *name; name = getexname(sp); off = (int)tsize(sp->stype, sp->sdf, sp->sap); SETOFF(off,SZINT); off /= SZINT; if (ISCHAR18 && ISARY(sp->stype) && (BTYPE(sp->stype) == CHAR || BTYPE(sp->stype) == UCHAR)) off <<= 1; if (sp->slevel == 0) { if (sp->slevel == 0) printf(PRTPREF "\t.local %s\n", name); printf("%s:\n", name); } else printf(LABFMT ":", sp->soffset); printf(" .=.+0%o\n", off); } /* * Give target the opportunity of handling pragmas. */ int mypragma(char *str) { return 0; } struct lab { struct lab *next; int lab; } *lpole; void dellab(int lab); void printlab(void); void addlab(int lab); void addlab(int lab) { struct lab *l; for (l = lpole; l; l = l->next) { if (l->lab == lab) return; } l = permalloc(sizeof(struct lab)); l->lab = lab; l->next = lpole; lpole = l; } void dellab(int lab) { struct lab *l; for (l = lpole; l; l = l->next) { if (l->lab == lab) { l->lab = 0; return; } } } void printlab() { struct lab *l; for (l = lpole; l; l = l->next) { if (l->lab != 0) printf(LABFMT ": 0\n", l->lab); } } /* * Called when a identifier has been declared. */ void fixdef(struct symtab *sp) { if (sp->sflags & STNODE) return; #if 0 if (sp->sclass == AUTO) { sp->sclass = STATIC; sp->soffset = getlab(); addlab(sp->soffset); } #endif } void pass1_lastchance(struct interpass *ip) { } #ifdef PASS1 void mflags(char *s) { } #endif pcc-20181216/arch/pdp7/local2.c010064400017500000000000000260341305137264300146040ustar raggewheel/* $Id: local2.c,v 1.9 2017/02/16 18:55:31 ragge Exp $ */ /* * Copyright (c) 2017 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass2.h" # include # include int msettings; #if defined(PECOFFABI) || defined(MACHOABI) || defined(AOUTABI) #define EXPREFIX "_" #else #define EXPREFIX "" #endif static struct consts { struct consts *next; int lblnum; CONSZ val; char *str; int printed; } *copole; struct ttemp { struct ttemp *next; int tno; } *tpole; static int curargs, prearg, minum, indirs; void deflab(int label) { printf(LABFMT ":\n", label); } void prologue(struct interpass_prolog *ipp) { printf("0\n"); /* return address */ } void eoftn(struct interpass_prolog *ipp) { struct consts *co; if (ipp->ipp_ip.ip_lbl) printf(" jmp %s i\n", ipp->ipp_name); for (co = copole; co; co = co->next) { if (co->printed) continue; printf("LC%d: ", co->lblnum); if (co->str && co->str[0] != '\0') { printf("%s", co->str); if (co->val) printf("+0%llo", co->val); } else printf("0%llo", co->val); printf("\n"); co->printed = 1; } for (; tpole; tpole = tpole->next) printf("LT%d: 0\n", tpole->tno); if (indirs) printf("Lindir: 0\n"); } static int addicon(int v, char *s) { struct consts *co; for (co = copole; co; co = co->next) { if (co->val == v && co->str == s) return co->lblnum; } co = permalloc(sizeof(struct consts)); memset(co, 0, sizeof(struct consts)); co->val = v & 0777777; co->str = s; co->lblnum = minum++; co->next = copole; copole = co; return co->lblnum; } /* * add/sub/... * * Param given: */ void hopcode(int f, int o) { char *str; switch (o) { case PLUS: str = "add"; break; case MINUS: str = "sub"; break; case AND: str = "and"; break; case OR: str = "or"; break; case ER: str = "xor"; break; default: comperr("hopcode2: %d", o); str = 0; /* XXX gcc */ } printf("%s%c", str, f); } /* * Return type size in bytes. Used by R2REGS, arg 2 to offset(). */ int tlen(NODE *p) { switch(p->n_type) { case CHAR: case UCHAR: return(1); case SHORT: case USHORT: return(SZSHORT/SZCHAR); case DOUBLE: return(SZDOUBLE/SZCHAR); case INT: case UNSIGNED: case LONG: case ULONG: return(SZINT/SZCHAR); case LONGLONG: case ULONGLONG: return SZLONGLONG/SZCHAR; default: if (!ISPTR(p->n_type)) comperr("tlen type %d not pointer"); return SZPOINT(p->n_type)/SZCHAR; } } int fldexpand(NODE *p, int cookie, char **cp) { comperr("fldexpand"); return 0; } void zzzcode(NODE *p, int c) { NODE *q; int i; switch (c) { case 'A': /* print out label arg address */ printf("LA%d%d", prearg, curargs - p->n_rval); break; case 'B': /* put aside constant value for later use */ printf("LC%d", addicon(getlval(p), p->n_name)); break; case 'C': /* print out space for label args */ for (i = 0; i < (int)p->n_qual; i++) printf("LA%d%d: 0\n", prearg, i+1); break; case 'D': /* print out NOP if not pointer */ if (!ISPTR(p->n_type)) printf(" nop\n"); break; case 'E': /* print a negative number used for comparison */ printf("LC%d", addicon(-getlval(getlr(p, 'R')) & 0777777, 0)); break; case 'F': /* mask chars with 0777 */ printf("LC%d", addicon(0777, 0)); break; case 'G': /* store byte to a name (with offset) */ q = getlr(p, 'L'); i = addicon(0, q->n_name); printf(" dac .+5\n"); printf(" lac LC%d\n", i); printf(" rcl\n"); printf(" tad LC%d\n", addicon(getlval(q), 0)); printf(" jms sbyt; ..\n"); break; case 'H': /* memory position to save indirect refs */ indirs=1; printf("Lindir"); break; case 'I': /* Gen code to add constant to memory pos */ expand(p, FOREFF, " dac A1\n"); expand(p, FOREFF, " lac A1 i\n"); printf(" tad LC%d\n", addicon(getlval(getlr(p, 'R')) & 0777777, 0)); expand(p, FOREFF, " dac A1 i\n"); break; case 'J': /* add const */ printf("LC%d", addicon(getlval(getlr(p, 'R')) & 0777777, 0)); break; case 'K': if (regno(p->n_right) != AC) expand(p, FOREFF, " lac AR\n"); break; case 'L': /* put aside left constant value for later use */ printf("LC%d", addicon(getlval(p->n_left), p->n_left->n_name)); break; default: comperr("zzzcode %c", c); } } int canaddr(NODE *); int canaddr(NODE *p) { int o = p->n_op; if (o==NAME || o==REG || o==ICON || o==OREG || (o==UMUL && shumul(p->n_left, SOREG))) return(1); return(0); } /* * Does the bitfield shape match? */ int flshape(NODE *p) { comperr("flshape"); return 0; } /* INTEMP shapes must not contain any temporary registers */ /* XXX should this go away now? */ int shtemp(NODE *p) { return 0; } void adrcon(CONSZ val) { printf("$" CONFMT, val); } void conput(FILE *fp, NODE *p) { int val = (int)getlval(p); switch (p->n_op) { case ICON: if (p->n_name[0] != '\0') { fprintf(fp, "%s", p->n_name); if (val) fprintf(fp, "+%d", val); } else fprintf(fp, "%d", val); return; default: comperr("illegal conput, p %p", p); } } /*ARGSUSED*/ void insput(NODE *p) { comperr("insput"); } /* * Write out the upper address, like the upper register of a 2-register * reference, or the next memory location. */ void upput(NODE *p, int size) { size /= SZCHAR; switch (p->n_op) { case REG: printf("%%%s", &rnames[p->n_rval][3]); break; case NAME: case OREG: setlval(p, getlval(p) + size); adrput(stdout, p); setlval(p, getlval(p) - size); break; case ICON: printf("$" CONFMT, getlval(p) >> 32); break; default: comperr("upput bad op %d size %d", p->n_op, size); } } void adrput(FILE *io, NODE *p) { int r; /* output an address, with offsets, from p */ switch (p->n_op) { case NAME: if (p->n_name[0] != '\0') { fputs(p->n_name, io); if (getlval(p) != 0) { OFFSZ l = getlval(p); if (ISCHAR9 && (p->n_type == CHAR || p->n_type == UCHAR)) l >>= 1; fprintf(io, "+" CONFMT, l); } } else fprintf(io, CONFMT, getlval(p)); return; case OREG: r = p->n_rval; if (p->n_name[0]) printf("%s%s", p->n_name, getlval(p) ? "+" : ""); if (getlval(p)) fprintf(io, "%d", (int)getlval(p)); if (R2TEST(r)) { fprintf(io, "(%s,%s,4)", rnames[R2UPK1(r)], rnames[R2UPK2(r)]); } else fprintf(io, "(%s)", rnames[p->n_rval]); return; case ICON: #ifdef PCC_DEBUG /* Sanitycheck for PIC, to catch adressable constants */ if (kflag && p->n_name[0] && 0) { static int foo; if (foo++ == 0) { printf("\nfailing...\n"); fwalk(p, e2print, 0); comperr("pass2 conput"); } } #endif /* addressable value of the constant */ fputc('$', io); conput(io, p); return; case REG: switch (p->n_type) { case LONGLONG: case ULONGLONG: fprintf(io, "%%%c%c%c", rnames[p->n_rval][0], rnames[p->n_rval][1], rnames[p->n_rval][2]); break; case SHORT: case USHORT: fprintf(io, "%%%s", &rnames[p->n_rval][2]); break; default: fprintf(io, "%s", rnames[p->n_rval]); } return; case UMUL: if (p->n_left->n_op == NAME) { adrput(io, p->n_left); break; } if (p->n_left->n_op != REG || regno(p->n_left) == 0) comperr("adrput"); fprintf(io, "%s i", rnames[regno(p->n_left)]); break; default: comperr("illegal address, op %d, node %p", p->n_op, p); return; } } static char * ccbranches[] = { "sna", /* jumpe */ "sza", /* jumpn */ "ERROR", /* jumple */ "spa", /* jumpl */ "sma", /* jumpge */ "sma sza", /* jumpg */ "jbe", /* jumple (jlequ) */ "jb", /* jumpl (jlssu) */ "jae", /* jumpge (jgequ) */ "ja", /* jumpg (jgtru) */ }; /* printf conditional and unconditional branches */ void cbgen(int o, int lab) { if (o < EQ || o > UGT) comperr("bad conditional branch: %s", opst[o]); printf(" %s\n", ccbranches[o-EQ]); printf(" jmp " LABFMT "\n", lab); } #if 0 static void exttemp(NODE *p, void *arg) { struct ttemp *w; if (p->n_op != TEMP) return; for (w = tpole; w; w = w->next) { if (w->tno == regno(p)) break; } if (w == NULL) { w = tmpcalloc(sizeof(struct ttemp)); w->tno = regno(p); w->next = tpole; tpole = w; } p->n_op = NAME; p->n_name = tmpcalloc(10); sprintf(p->n_name, "LT%d", w->tno); } #endif void myreader(struct interpass *ipole) { #if 0 struct interpass *ip; DLIST_FOREACH(ip, ipole, qelem) { if (ip->type != IP_NODE) continue; walkf(ip->ip_node, exttemp, 0); } #endif if (x2debug) printip(ipole); } void mycanon(NODE *p) { NODE *q; /* Avoid test for result > 0 */ if (p->n_op == CBRANCH && p->n_left->n_op == LE) { /* Swap */ p = p->n_left; q = p->n_left; p->n_left = p->n_right; p->n_right = q; p->n_op = GT; } } void myoptim(struct interpass *ip) { } void rmove(int s, int d, TWORD t) { comperr("bad rmove: %d %d", s, d); } /* * For class c, find worst-case displacement of the number of * registers in the array r[] indexed by class. */ int COLORMAP(int c, int *r) { if (c == CLASSA) return r[CLASSA] == 0; return r[CLASSB] < 7; } char *rnames[] = { "AC", "POS1", "POS1", "POS1", "POS1", "POS1", "POS1", "POS1", "FP", "SP", }; /* * Return a class suitable for a specific type. */ int gclass(TWORD t) { return CLASSA; } /* * Calculate argument sizes. * Will count # of args before emitting them. */ void lastcall(NODE *p) { NODE *op = p; int size = 0; if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) return; p->n_qual = 0; for (p = p->n_right; p->n_op == CM; p = p->n_left) p->n_right->n_rval = size++; p->n_rval = size++; op->n_qual = size; curargs = size; prearg++; } /* * Special shapes. */ int special(NODE *p, int shape) { switch (shape) { case SLDFPSP: return regno(p) == FP || regno(p) == SP; } return SRNOPE; } /* * Target-dependent command-line options. */ void mflags(char *str) { if (strcmp(str, "char18") == 0) msettings |= M_CHAR18; else uerror("bad mflag"); } /* * Do something target-dependent for xasm arguments. */ int myxasm(struct interpass *ip, NODE *p) { return 0; } pcc-20181216/arch/pdp7/macdefs.h010064400017500000000000000124311305137264300150330ustar raggewheel/* $Id: macdefs.h,v 1.8 2017/02/16 18:55:31 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Machine-dependent defines for both passes. */ /* * Convert (multi-)character constant to integer. */ #define makecc(val,i) lastcon = val; #define ARGINIT 18 /* # bits above fp where arguments start */ #define AUTOINIT 0 /* # bits below fp where automatics start */ /* * Storage space requirements */ #define SZCHAR 9 #define SZBOOL 9 #define SZSHORT 18 #define SZINT 18 #define SZFLOAT 18 #define SZDOUBLE 36 #define SZLDOUBLE 36 #define SZLONG 36 #define SZLONGLONG 36 /* XXX */ #define SZPOINT(t) 18 /* XXX */ /* * Alignment constraints */ #define ALCHAR 9 #define ALBOOL 9 #define ALSHORT 18 #define ALINT 18 #define ALFLOAT 18 #define ALDOUBLE 18 #define ALLDOUBLE 18 #define ALLONG 18 #define ALLONGLONG 18 #define ALPOINT 18 #undef ALSTRUCT /* Not defined if ELF ABI */ #define ALSTACK 18 #define ALMAX 18 /* not yet supported type */ /* * Min/max values. */ #define MIN_CHAR -256 #define MAX_CHAR 255 #define MAX_UCHAR 511 #define MIN_SHORT -131072 #define MAX_SHORT 131071 #define MAX_USHORT 262144 #define MIN_INT MIN_SHORT #define MAX_INT MAX_SHORT #define MAX_UNSIGNED MAX_USHORT #define MIN_LONG MIN_INT #define MAX_LONG MAX_INT #define MAX_ULONG MAX_UNSIGNED #define MIN_LONGLONG MIN_LONG #define MAX_LONGLONG MAX_LONG #define MAX_ULONGLONG MAX_ULONG /* Default char is signed */ #define CHAR_UNSIGNED #define BOOL_TYPE UCHAR /* what used to store _Bool */ #undef UNALIGNED_ACCESS /* * Use large-enough types. */ typedef long long CONSZ; typedef unsigned long long U_CONSZ; typedef long long OFFSZ; #define CONFMT "%llo" /* format for printing constants */ #define LABFMT "L%d" /* format for printing labels */ #define BACKAUTO /* stack grows negatively for automatics */ #define BACKTEMP /* stack grows negatively for temporaries */ #undef FIELDOPS /* no bit-field instructions */ #define TARGET_ENDIAN TARGET_LE #define FINDMOPS /* to find isz */ #define CC_DIV_0 /* division by zero is safe in the compiler */ #define BYTEOFF(x) ((x)&01) #define MYALIGN #define MYINSTRING #define MYDOTFILE #define printdotfile(ftitle) /* just ignore */ void myendinit(void); #define MYENDINIT myendinit(); #define WORD_ADDRESSED #define szty(t) (((t) == DOUBLE || (t) == FLOAT || \ (t) == LONGLONG || (t) == ULONGLONG) ? 2 : (t) == LDOUBLE ? 3 : 1) /* * pdp7 has only one register. * We emulate 7 memory positions to make the compiler happier. */ #define AC 000 /* Scratch and return register */ #define POS1 001 #define POS2 002 #define POS3 003 #define POS4 004 #define POS5 005 #define POS6 006 #define POS7 007 #define FP 010 #define SP 011 #define MAXREGS 012 #define RSTATUS SAREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, \ SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, SBREG|TEMPREG, \ 0, 0 #define ROVERLAP { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \ { -1 }, { -1 }, { -1 }, /* Return a register class based on the type of the node */ #define PCLASS(p) (p->n_op == REG && regno(p) > 7 ? 0 : \ (p->n_op == REG && regno(p)) ? SBREG : SAREG) #define NUMCLASS 2 /* highest number of reg classes used */ int COLORMAP(int c, int *r); #define GCLASS(x) ((x) == 0 ? CLASSA : CLASSB) #define DECRA(x,y) (((x) >> (y*6)) & 63) /* decode encoded regs */ #define ENCRD(x) (x) /* Encode dest reg in n_reg */ #define ENCRA1(x) ((x) << 6) /* A1 */ #define ENCRA2(x) ((x) << 12) /* A2 */ #define ENCRA(x,y) ((x) << (6+y*6)) /* encode regs in int */ #define RETREG(x) AC /* XXX - to die */ #define FPREG FP /* frame pointer */ #define STKREG SP /* stack pointer */ #define SLDFPSP (MAXSPECIAL+1) /* load fp or sp */ extern int msettings; #define M_CHAR18 001 /* Use chars that are word size */ #define ISCHAR18 (msettings & M_CHAR18) #define ISCHAR9 ((msettings & M_CHAR18) == 0) /* For acceptable() */ #define USECHAR9 0200 #define USECHAR18 0400 pcc-20181216/arch/pdp7/order.c010064400017500000000000000100001305137264300145250ustar raggewheel/* $Id: order.c,v 1.6 2017/02/16 18:55:31 ragge Exp $ */ /* * Copyright (c) 2017 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass2.h" #include int canaddr(NODE *); /* is it legal to make an OREG or NAME entry which has an * offset of off, (from a register of r), if the * resulting thing had type t */ int notoff(TWORD t, int r, CONSZ off, char *cp) { return(1); /* NO */ } /* * Turn a UMUL-referenced node into OREG. * Be careful about register classes, this is a place where classes change. */ void offstar(NODE *p, int shape) { if (x2debug) printf("offstar(%p)\n", p); if (isreg(p) == 0) (void)geninsn(p, INBREG); } /* * Do the actual conversion of offstar-found OREGs into real OREGs. */ void myormake(NODE *q) { if (x2debug) printf("myormake(%p)\n", q); #if 0 p = q->n_left; if (p->n_op == PLUS && (r = p->n_right)->n_op == LS && r->n_right->n_op == ICON && getlval(r->n_right) == 2 && p->n_left->n_op == REG && r->n_left->n_op == REG) { q->n_op = OREG; setlval(q, 0); q->n_rval = R2PACK(p->n_left->n_rval, r->n_left->n_rval, 0); tfree(p); } #endif } /* * Shape matches for UMUL. Cooperates with offstar(). */ int shumul(NODE *p, int shape) { if (x2debug) { printf("shumul(%p)\n", p); fwalk(p, e2print, 0); } if (shape & SOREG) return SROREG; if ((shape & STARNM) && (p->n_op == NAME)) return SRDIR; if (shape & STARREG) return SROREG; return SRNOPE; } /* * Rewrite operations on binary operators (like +, -, etc...). * Called as a result of table lookup. */ int setbin(NODE *p) { if (x2debug) printf("setbin(%p)\n", p); return 0; } /* setup for assignment operator */ int setasg(NODE *p, int cookie) { if (x2debug) printf("setasg(%p)\n", p); return(0); } /* setup for unary operator */ int setuni(NODE *p, int cookie) { return 0; } /* * Special handling of some instruction register allocation. */ struct rspecial * nspecial(struct optab *q) { switch (q->op) { case ASSIGN: if (q->lshape == STARREG && q->rshape == SNAME) { static struct rspecial s[] = { { NEVER, AC }, { NRES, AC }, { 0 } }; return s; } break; default: comperr("nspecial entry %d", q - table); } return 0; } /* * Set evaluation order of a binary node if it differs from default. */ int setorder(NODE *p) { return 0; /* nothing differs on x86 */ } /* * set registers in calling conventions live. */ int * livecall(NODE *p) { static int r[] = { -1 }; return r; } /* * Signal whether the instruction is acceptable for this target. */ int acceptable(struct optab *op) { if (msettings & M_CHAR18) { if (op->visit & USECHAR18) return 1; else if (op->visit & USECHAR9) return 0; } else { if (op->visit & USECHAR18) return 0; else if (op->visit & USECHAR9) return 1; } return 1; } pcc-20181216/arch/pdp7/table.c010064400017500000000000000432121305137264300145140ustar raggewheel/* $Id: table.c,v 1.12 2017/02/16 18:55:31 ragge Exp $ */ /* * Copyright (c) 2017 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass2.h" # define TLL TLONGLONG|TULONGLONG # define ANYSIGNED TINT|TLONG|TSHORT|TCHAR # define ANYUSIGNED TUNSIGNED|TULONG|TUSHORT|TUCHAR # define ANYFIXED ANYSIGNED|ANYUSIGNED # define TUWORD TUNSIGNED # define TSWORD TINT # define TWORD TUWORD|TSWORD #define SHINT SAREG /* short and int */ #define ININT INAREG #define SHCH SBREG /* shape for char */ #define INCH INBREG #define SHLL SCREG /* shape for long long */ #define INLL INCREG #define SHFL SDREG /* shape for float/double */ #define INFL INDREG /* shape for float/double */ struct optab table[] = { /* First entry must be an empty entry */ { -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", }, /* PCONVs are usually not necessary */ { PCONV, INAREG, SAREG, TWORD|TPOINT, SAREG, TWORD|TPOINT, 0, RLEFT, "", }, /* * A bunch conversions of integral<->integral types * There are lots of them, first in table conversions to itself * and then conversions from each type to the others. */ /* itself to itself, including pointers */ /* convert pointers to int. */ { SCONV, ININT, SHINT, TPOINT|TWORD, SANY, TWORD, 0, RLEFT, "", }, /* convert pointers to pointers. */ { SCONV, ININT, SHINT, TPOINT, SANY, TPOINT, 0, RLEFT, "", }, /* char to something */ /* convert signed char to int (or pointer). */ { SCONV, INAREG, SAREG, TCHAR, SAREG, TWORD|TPOINT, 0, RLEFT, " sign extend AL\n", }, /* convert unsigned char to (u)int. */ { SCONV, INAREG, SAREG, TUCHAR, SAREG, TWORD, 0, RLEFT, "", }, /* short to something */ /* convert (u)short to (u)short. */ { SCONV, INAREG, SAREG, TSHORT|TUSHORT, SAREG, TSHORT|TUSHORT, 0, RLEFT, "", }, /* convert short (in memory) to char */ { SCONV, INCH, SNAME|SOREG, TSHORT|TUSHORT, SHCH, TCHAR|TUCHAR, NBREG|NBSL, RESC1, " movb AL,A1\n", }, /* convert short (in reg) to char. */ { SCONV, INCH, SAREG|SNAME|SOREG, TSHORT|TUSHORT, SHCH, TCHAR|TUCHAR, NSPECIAL|NBREG|NBSL, RESC1, "ZM", }, /* convert short to (u)int. */ { SCONV, ININT, SAREG|SOREG|SNAME, TSHORT, SAREG, TWORD, NASL|NAREG, RESC1, " movswl AL,A1\n", }, /* convert unsigned short to (u)int. */ { SCONV, ININT, SAREG|SOREG|SNAME, TUSHORT, SAREG, TWORD, NASL|NAREG, RESC1, " movzwl AL,A1\n", }, /* convert short to (u)long long */ { SCONV, INLL, SAREG|SOREG|SNAME, TSHORT, SHLL, TLL, NSPECIAL|NCREG|NCSL, RESC1, " movswl AL,%eax\n cltd\n", }, /* convert unsigned short to (u)long long */ { SCONV, INLL, SAREG|SOREG|SNAME, TUSHORT, SHLL, TLL, NCREG|NCSL, RESC1, " movzwl AL,A1\n xorl U1,U1\n", }, /* int to something */ /* convert int to char. This is done when register is loaded */ { SCONV, INCH, SAREG, TWORD|TPOINT, SANY, TCHAR|TUCHAR, NSPECIAL|NBREG|NBSL, RESC1, "ZM", }, /* convert int to uchar. */ { SCONV, INAREG, SAREG, TWORD|TPOINT, SANY, TCHAR|TUCHAR, NAREG|NASL, RESC1, " and ZF\n", }, /* convert int to short. Nothing to do */ { SCONV, INAREG, SAREG, TWORD|TPOINT, SANY, TSHORT|TUSHORT, 0, RLEFT, "", }, /* convert signed int to (u)long long */ { SCONV, INLL, SHINT, TSWORD, SHLL, TLL, NSPECIAL|NCREG|NCSL, RESC1, " cltd\n", }, /* convert unsigned int to (u)long long */ { SCONV, INLL, SHINT|SOREG|SNAME, TUWORD|TPOINT, SHLL, TLL, NCSL|NCREG, RESC1, " movl AL,A1\n xorl U1,U1\n", }, /* long long to something */ /* convert (u)long long to (u)char (mem->reg) */ { SCONV, INCH, SOREG|SNAME, TLL, SANY, TCHAR|TUCHAR, NBREG|NBSL, RESC1, " movb AL,A1\n", }, /* convert (u)long long to (u)char (reg->reg, hopefully nothing) */ { SCONV, INCH, SHLL, TLL, SANY, TCHAR|TUCHAR, NBREG|NBSL|NTEMP, RESC1, "ZS", }, /* convert (u)long long to (u)short (mem->reg) */ { SCONV, INAREG, SOREG|SNAME, TLL, SAREG, TSHORT|TUSHORT, NAREG|NASL, RESC1, " movw AL,A1\n", }, /* convert (u)long long to (u)short (reg->reg, hopefully nothing) */ { SCONV, INAREG, SHLL|SOREG|SNAME, TLL, SAREG, TSHORT|TUSHORT, NAREG|NASL|NTEMP, RESC1, "ZS", }, /* convert long long to int (mem->reg) */ { SCONV, INAREG, SOREG|SNAME, TLL, SAREG, TWORD|TPOINT, NAREG|NASL, RESC1, " movl AL,A1\n", }, /* slut sconv */ /* * Subroutine calls. */ { UCALL, FOREFF, SCON, TANY, SANY, TANY, 0, 0, " jms CL\nZC", }, { CALL, FOREFF, SCON, TANY, SANY, TANY, 0, 0, " jms CL\nZC", }, { UCALL, FOREFF, SCON, TANY, SAREG, TWORD|TPOINT, 0, 0, " jms CL\nZC", }, { CALL, INAREG, SCON, TANY, SAREG, TSHORT|TUSHORT|TWORD|TPOINT, NAREG|NASL|NASR, RESC1, /* should be 0 */ " jms CL\nZC", }, { UCALL, INAREG, SCON, TANY, SAREG, TSHORT|TUSHORT|TWORD|TPOINT, NAREG|NASL|NASR, RESC1, /* should be 0 */ " jms CL\nZC", }, { CALL, FOREFF, SAREG, TANY, SANY, TANY, 0, 0, " dac 20\n cal i\nZC", }, { UCALL, FOREFF, SAREG, TANY, SANY, TANY, 0, 0, " dac 20\n cal i\nZC", }, { CALL, INAREG, SAREG, TANY, SANY, TANY, NAREG|NASL|NASR, RESC1, /* should be 0 */ " dac 20\n cal i\nZC", }, { UCALL, INAREG, SAREG, TANY, SANY, TANY, NAREG|NASL|NASR, RESC1, /* should be 0 */ " dac 20\n cal i\nZC", }, { STCALL, FOREFF, SCON, TANY, SANY, TANY, NAREG|NASL|NASR, 0, " jms CL\nZC", }, { STCALL, INAREG, SCON, TANY, SANY, TANY, NAREG|NASL|NASR, RESC1, /* should be 0 */ " jms CL\nZC", }, { STCALL, INAREG, SNAME|SAREG, TANY, SANY, TANY, NAREG|NASL|NASR, RESC1, /* should be 0 */ " dac 20\n cal i\nZC", }, /* * The next rules handle all binop-style operators. */ { PLUS, INBREG|USECHAR18, SCON, TCHAR|TUCHAR|TWORD|TPOINT, SAREG, TCHAR|TUCHAR|TWORD|TPOINT, NBREG, RESC1, " tad ZL\n dac A1\n", }, { PLUS, INAREG, SAREG, TWORD|TPOINT, SNAME|SBREG, TWORD|TPOINT, 0, RLEFT, " tad AR\n", }, { PLUS, INBREG, SAREG, TPOINT, SCON, TANY, NBREG, RESC1, " tad ZJ\n dac A1\n", }, #if 0 { PLUS, INAREG|FOREFF, SNAME|SBREG, TWORD|TPOINT, SONE, TANY, 0, RLEFT, " isz AL\nZD", }, #endif /* add constant to memory position referenced by AL */ { PLUS, INAREG|FOREFF, STARREG, TWORD|TPOINT, SCON, TANY, NBREG, RLEFT, "ZI", }, /* Add name to AC */ { PLUS, INAREG|FOREFF, SAREG, TWORD|TPOINT, SNAME, TWORD|TPOINT, 0, RLEFT, " tad AR\n", }, /* Add constant to AC */ { PLUS, INAREG|FOREFF, SAREG, TWORD|TPOINT, SCON, TWORD|TPOINT, 0, RLEFT, " tad ZJ\n", }, { MINUS, INBREG|FOREFF, SLDFPSP, TANY, SAREG, TANY, NBREG, RESC1, " tad AL\n dad A1\n", }, { MINUS, INAREG|FOREFF, SAREG, TWORD|TPOINT, SNAME, TWORD|TPOINT, 0, RLEFT, " cma\n tad AR\n cma\n", }, { MINUS, INAREG|FOREFF, SAREG, TWORD|TPOINT, SCON, TWORD|TPOINT, 0, RLEFT, " tad ZE\n", }, /* Tricky here. Left reg is pointer, must store and use indirect address. */ { MINUS, INAREG|FOREFF, STARREG, TWORD|TPOINT, SCON, TANY, NBREG, RLEFT, " dac A1\n" " lac A1 i\n" " tad ZE\n" " dac A1 i\n", }, /* * The next rules handle all shift operators. */ { LS, INAREG|FOREFF, SAREG, TWORD, SHCH, TCHAR|TUCHAR, 0, RLEFT, " sall AR,AL\n", }, /* r/m <<= const */ { LS, INAREG|FOREFF, SAREG, TWORD, SCON, TANY, 0, RLEFT, " clq lls CR\n", }, /* r/m <<= r */ { LS, INAREG|FOREFF, SAREG|SNAME|SOREG, TSHORT|TUSHORT, SHCH, TCHAR|TUCHAR, NSPECIAL, RLEFT, " shlw AR,AL\n", }, /* r/m <<= const */ { LS, INAREG|FOREFF, SAREG|SNAME|SOREG, TSHORT|TUSHORT, SCON, TANY, 0, RLEFT, " shlw AR,AL\n", }, { LS, INCH|FOREFF, SHCH|SNAME|SOREG, TCHAR|TUCHAR, SHCH, TCHAR|TUCHAR, NSPECIAL, RLEFT, " salb AR,AL\n", }, { LS, INCH|FOREFF, SHCH|SNAME|SOREG, TCHAR|TUCHAR, SCON, TANY, 0, RLEFT, " salb AR,AL\n", }, /* (u)longlong right shift is emulated */ { RS, INCREG, SCREG, TLL, SHCH, TCHAR|TUCHAR, NSPECIAL, RLEFT, "ZO", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TSWORD, SHCH, TCHAR|TUCHAR, NSPECIAL, RLEFT, " sarl AR,AL\n", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TSWORD, SCON, TANY, 0, RLEFT, " sarl AR,AL\n", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TUWORD, SHCH, TCHAR|TUCHAR, NSPECIAL, RLEFT, " shrl AR,AL\n", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TUWORD, SCON, TANY, 0, RLEFT, " shrl AR,AL\n", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TSHORT, SHCH, TCHAR|TUCHAR, NSPECIAL, RLEFT, " sarw AR,AL\n", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TSHORT, SCON, TANY, 0, RLEFT, " sarw AR,AL\n", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TUSHORT, SHCH, TCHAR|TUCHAR, NSPECIAL, RLEFT, " shrw AR,AL\n", }, { RS, INAREG|FOREFF, SAREG|SNAME|SOREG, TUSHORT, SCON, TANY, 0, RLEFT, " shrw AR,AL\n", }, { RS, INCH|FOREFF, SHCH|SNAME|SOREG, TCHAR, SHCH, TCHAR|TUCHAR, NSPECIAL, RLEFT, " sarb AR,AL\n", }, { RS, INCH|FOREFF, SHCH|SNAME|SOREG, TCHAR, SCON, TANY, 0, RLEFT, " sarb AR,AL\n", }, { RS, INCH|FOREFF, SHCH|SNAME|SOREG, TUCHAR, SHCH, TCHAR|TUCHAR, NSPECIAL, RLEFT, " shrb AR,AL\n", }, { RS, INCH|FOREFF, SHCH|SNAME|SOREG, TUCHAR, SCON, TANY, 0, RLEFT, " shrb AR,AL\n", }, /* * The next rules takes care of assignments. "=". */ { ASSIGN, FOREFF, SNAME, TWORD|TPOINT, SZERO, TANY, 0, 0, " dzm AL\n", }, { ASSIGN, FOREFF|USECHAR9, SNAME, TCHAR|TUCHAR, SAREG, TANY, 0, 0, "ZG", }, { ASSIGN, FOREFF|USECHAR18, SNAME, TCHAR|TUCHAR, SZERO, TANY, 0, 0, " dzm AL\n", }, { ASSIGN, FOREFF|USECHAR18, SNAME, TCHAR|TUCHAR, SAREG, TANY, 0, 0, " dac AL\n", }, { ASSIGN, FOREFF|USECHAR18, STARNM, TCHAR|TUCHAR, SAREG, TANY, 0, 0, " dac AL i\n", }, { ASSIGN, FOREFF|USECHAR9, STARREG, TCHAR|TUCHAR, SCON, TANY, 0, 0, " jms sbyt\n CR\n", }, { ASSIGN, FOREFF|USECHAR18, STARREG, TCHAR|TUCHAR, SAREG, TANY, 0, 0, " sac AL i\n", }, { ASSIGN, FOREFF|INAREG, STARREG, TWORD|TPOINT, SAREG, TWORD|TPOINT, 0, RDEST, " dac AL\n", }, { ASSIGN, FOREFF|INAREG, STARREG, TWORD|TPOINT, SNAME|SBREG, TWORD|TPOINT, NAREG|NASL|NASR, RDEST, " lac AR\n dac AL\n", }, { ASSIGN, FOREFF|INAREG, SAREG, TWORD|TPOINT, SNAME, TWORD|TPOINT, 0, RDEST, " lac AR\n", }, { ASSIGN, FOREFF|INAREG, SNAME, TWORD|TPOINT, SAREG, TWORD|TPOINT, 0, RDEST, " dac AL\n", }, { ASSIGN, FOREFF|INAREG, SAREG, TWORD|TPOINT, SBREG, TWORD|TPOINT, 0, RDEST, "ZK", }, { ASSIGN, FOREFF|INAREG, SBREG, TWORD|TPOINT, SNAME, TWORD|TPOINT, NAREG, RDEST, " lac AR\n dac AL\n", }, { STASG, INAREG|FOREFF, SOREG|SNAME, TANY, SAREG, TPTRTO|TANY, NSPECIAL|NAREG, RDEST, "F movl %esi,A1\nZQF movl A1,%esi\n", }, /* * DIV/MOD/MUL */ /* long long div is emulated */ { DIV, INCREG, SCREG|SNAME|SOREG|SCON, TLL, SCREG|SNAME|SOREG|SCON, TLL, NSPECIAL|NCREG|NCSL|NCSR, RESC1, "ZO", }, { DIV, INAREG, SAREG, TSWORD, SCON, TWORD, 0, RLEFT, " cll; idiv; CR; lacq\n", }, { DIV, INAREG, SAREG, TWORD, SNAME, TWORD, 0, RLEFT, // XXX, how to rewrite to do the // operands in reverse order? // I tried RRIGHT and lac AL, no good " lmq\n" " lac AR\n" " dac .+4\n" " lacq\n" " cll; idiv; ..; lacq\n", }, { MOD, INAREG, SAREG, TSWORD, SCON, TWORD, 0, RLEFT, " cll; idiv; CR\n", }, { MOD, INAREG, SAREG, TSWORD, SAREG|SNAME|SOREG, TSWORD, NAREG|NSPECIAL, RESC1, " cltd\n idivl AR\n", }, { MOD, INAREG, SAREG, TWORD|TPOINT, SAREG|SNAME|SOREG, TUWORD|TPOINT, NAREG|NSPECIAL, RESC1, " xorl %edx,%edx\n divl AR\n", }, { MOD, INAREG, SAREG, TUSHORT, SAREG|SNAME|SOREG, TUSHORT, NAREG|NSPECIAL, RESC1, " xorl %edx,%edx\n divw AR\n", }, { MOD, INCH, SHCH, TUCHAR, SHCH|SNAME|SOREG, TUCHAR, NBREG|NSPECIAL, RESC1, " xorb %ah,%ah\n divb AR\n", }, { MUL, INAREG, SAREG, TWORD, SNAME, TWORD, 0, RLEFT, " dac .+4\n" " lac AR\n" " cll; mul; ..; lacq\n", }, /* * Indirection operators. */ { UMUL, INBREG|USECHAR18, SANY, TANY, STARREG, TPOINT, NAREG|NBREG, RESC2, " lac AL i\n dac A2\n", }, { UMUL, INAREG, SANY, TANY, SNAME, TPTRTO|TCHAR|TUCHAR|TINT|TUNSIGNED, NAREG|NASL, RESC1, " lac AL i\n", }, { UMUL, INAREG|USECHAR18, SANY, TANY, STARNM, TCHAR|TUCHAR, NAREG|NASL, RESC1, " lac AL i\n", }, /* fetch byte based on byte pointer */ { UMUL, INAREG|USECHAR18, SANY, TANY, STARREG, TUCHAR, NAREG, RESC1, " lac AR\n", }, { UMUL, INAREG|USECHAR9, SANY, TANY, STARREG, TUCHAR, 0, RLEFT, " jms lbyt\n", }, { UMUL, INAREG|USECHAR9, SANY, TANY, SNAME, TUCHAR, NAREG|NASL, RESC1, " lac AL\n jms lbyt\n", }, { UMUL, INAREG, SANY, TANY, STARNM, TINT|TUNSIGNED|TPOINT, NAREG|NASL, RESC1, " lac AL i\n", }, { UMUL, INAREG, SANY, TANY, STARREG, TINT|TUNSIGNED|TPOINT, NAREG|NASL|NBREG, RESC1, " dac A2\n lac A2 i\n", }, /* * Logical/branching operators */ /* Comparisions, take care of everything */ { EQ, FORCC, SAREG, TWORD|TPOINT, SZERO, TWORD|TPOINT, 0, 0, " sna\n jmp LC\n", }, { NE, FORCC, SAREG, TWORD|TPOINT, SZERO, TWORD|TPOINT, 0, 0, " sza\n jmp LC\n", }, { OPLOG, FORCC, SAREG, TWORD|TPOINT, SNAME, TWORD|TPOINT, 0, RESCC, " cma ; tad AR ; cma\n", }, { OPLOG, FORCC, SAREG, TWORD|TPOINT, SCON, TWORD|TPOINT, 0, RESCC, " tad ZE\n", }, { OPLOG, FORCC, SAREG, TWORD|TPOINT, SZERO, TWORD|TPOINT, 0, RESCC, "", }, { OPLOG, FORCC, SANY, TANY, SANY, TANY, REWRITE, 0, "diediedie!", }, /* AND/OR/ER/NOT */ { AND, INAREG|FOREFF, SAREG|SOREG|SNAME, TWORD, SCON|SAREG, TWORD, 0, RLEFT, " andl AR,AL\n", }, { AND, INCREG|FOREFF, SCREG, TLL, SCREG|SOREG|SNAME, TLL, 0, RLEFT, " andl AR,AL\n andl UR,UL\n", }, { AND, INAREG|FOREFF, SAREG, TWORD, SAREG|SOREG|SNAME, TWORD, 0, RLEFT, " andl AR,AL\n", }, { AND, INAREG|FOREFF, SAREG|SOREG|SNAME, TSHORT|TUSHORT, SCON|SAREG, TSHORT|TUSHORT, 0, RLEFT, " andw AR,AL\n", }, { AND, INAREG|FOREFF, SAREG, TSHORT|TUSHORT, SAREG|SOREG|SNAME, TSHORT|TUSHORT, 0, RLEFT, " andw AR,AL\n", }, { AND, INBREG|FOREFF, SBREG|SOREG|SNAME, TCHAR|TUCHAR, SCON|SBREG, TCHAR|TUCHAR, 0, RLEFT, " andb AR,AL\n", }, { AND, INBREG|FOREFF, SBREG, TCHAR|TUCHAR, SBREG|SOREG|SNAME, TCHAR|TUCHAR, 0, RLEFT, " andb AR,AL\n", }, /* AND/OR/ER/NOT */ /* * Jumps. */ { GOTO, FOREFF, SCON, TANY, SANY, TANY, 0, RNOP, " jmp LL\n", }, #if defined(GCC_COMPAT) || defined(LANG_F77) { GOTO, FOREFF, SAREG, TANY, SANY, TANY, 0, RNOP, " jmp *AL\n", }, #endif /* * Convert LTYPE to reg. */ /* XXX as will store references to byte pointers as word pointers. */ { OPLTYPE, INAREG|USECHAR9, SANY, TANY, SCON, TPTRTO|TCHAR|TUCHAR, NAREG, RESC1, " lac ZB\n rcl\n", }, { OPLTYPE, INAREG, SANY, TANY, SCON, TCHAR|TUCHAR|TWORD|TPOINT, NAREG, RESC1, " lac ZB\n", }, { OPLTYPE, INAREG, SANY, TANY, SNAME, TWORD|TPOINT, NAREG, RESC1, " lac AL\n", }, { OPLTYPE, INAREG|USECHAR9, SANY, TANY, SNAME|SWADD, TUCHAR, NAREG, RESC1, " lac AL\n clq lrs 011\n", }, { OPLTYPE, INAREG|USECHAR18, SANY, TANY, SNAME|SWADD, TUCHAR, NAREG, RESC1, " lac AL\n", }, { OPLTYPE, INAREG|USECHAR18, SANY, TANY, SNAME, TPTRTO|TCHAR|TUCHAR, NAREG, RESC1, " lac AL\n", }, { OPLTYPE, INAREG, SANY, TANY, SNAME, TUCHAR, NAREG, RESC1, " lac AL\n and ZF\n", }, { OPLTYPE, INAREG, SANY, TANY, SLDFPSP, TWORD|TPOINT, NAREG, RESC1, " lac AL\n", }, /* * Negate a word. */ { UMINUS, INCREG|FOREFF, SCREG, TLL, SCREG, TLL, 0, RLEFT, " negl AL\n adcl $0,UL\n negl UL\n", }, { UMINUS, INAREG|FOREFF, SAREG, TWORD|TPOINT, SAREG, TWORD|TPOINT, 0, RLEFT, " negl AL\n", }, { UMINUS, INAREG|FOREFF, SAREG, TSHORT|TUSHORT, SAREG, TSHORT|TUSHORT, 0, RLEFT, " negw AL\n", }, { UMINUS, INBREG|FOREFF, SBREG, TCHAR|TUCHAR, SBREG, TCHAR|TUCHAR, 0, RLEFT, " negb AL\n", }, { UMINUS, INFL|FOREFF, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, SHFL, TLDOUBLE|TDOUBLE|TFLOAT, 0, RLEFT, " fchs\n", }, { COMPL, INCREG, SCREG, TLL, SANY, TANY, 0, RLEFT, " notl AL\n notl UL\n", }, { COMPL, INAREG, SAREG, TWORD, SANY, TANY, 0, RLEFT, " notl AL\n", }, { COMPL, INAREG, SAREG, TSHORT|TUSHORT, SANY, TANY, 0, RLEFT, " notw AL\n", }, { COMPL, INBREG, SBREG, TCHAR|TUCHAR, SANY, TANY, 0, RLEFT, " notb AL\n", }, /* * Arguments to functions. */ { FUNARG, FOREFF, SAREG, TWORD|TPOINT, SANY, TWORD|TPOINT, 0, RNULL, " dac ZA\n", }, { FUNARG, FOREFF, SAREG, TUCHAR, SANY, TANY, 0, RNULL, " dac ZA\n", }, { STARG, FOREFF, SAREG, TPTRTO|TSTRUCT, SANY, TSTRUCT, NSPECIAL, 0, "ZF", }, # define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,"" { UMUL, DF( UMUL ), }, { ASSIGN, DF(ASSIGN), }, { STASG, DF(STASG), }, { FLD, DF(FLD), }, { OPLEAF, DF(NAME), }, /* { INIT, DF(INIT), }, */ { OPUNARY, DF(UMINUS), }, { OPANY, DF(BITYPE), }, { FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" }, }; int tablesize = sizeof(table)/sizeof(table[0]); pcc-20181216/arch/powerpc004075500017500000000000000000001340533064000140025ustar raggewheelpcc-20181216/arch/powerpc/CVS004075500017500000000000000000001340533064000144355ustar raggewheelpcc-20181216/arch/powerpc/CVS/Root010064400017500000000000000000111340533064000153470ustar raggewheel/cvsroot pcc-20181216/arch/powerpc/CVS/Repository010064400017500000000000000000211340533064000166040ustar raggewheelpcc/arch/powerpc pcc-20181216/arch/powerpc/CVS/Entries010064400017500000000000000004401340533064000160430ustar raggewheel/README/1.2/Thu Nov 22 16:47:02 2007// /code.c/1.32/Sun Jul 10 09:49:52 2016// /local.c/1.36/Sun Dec 2 11:11:39 2018// /local2.c/1.30/Mon Sep 26 16:45:42 2016// /macdefs.h/1.20/Sun Dec 2 11:11:39 2018// /order.c/1.9/Sun Jul 10 09:49:52 2016// /table.c/1.18/Fri Nov 26 17:06:31 2010// D pcc-20181216/arch/powerpc/README010064400017500000000000000050451072133120600147370ustar raggewheelmacdefs.h ; machine-dependent definitions code.c ; machine-dependent code for prologs, switches (pass 1) local.c ; machine-dependent code for prologs, switches (pass 1) local2.c ; misc routines and tables of register names (pass 2) order.c ; machine-dependent code-generation strategy (pass 2) table.c ; code templates (pass 2) On OS X, binaries are not ELF and all binaries are compiled PIC. To use pcc on OS X while linking against the system libraries, use the -k option. Current issues: - no floating point (need mickey's patches to support >64 registers) - mod/div on longlong not supported - the stack frame is always 200 bytes - need to calculate size and patch OREGs to temporaries and arguments [see discussion below] - function arguments are always saved to the stack [need to change MI code] - permanent registers >R13 are not saved [need to change MI code] - structure arguments don't work - return of structure doesn't work - function pointers don't work for PIC - constant structure assignment doesn't work properly for PIC - no built-in vararg support [shouldn't be too hard to add] The way most modern CPUs create the stack is to allocate the frame to contain room for the temporaries, to save the permanent registers and to store the arguments to functions invoked from within the function. To achieve this, all the information must be known when the prologue is generated. Currently we only know the size of the temporaries - we don't know the size of the argument space for each function that gets invoked from this function. Even if we did know this information, we create ops to save the register arguments (R3-R10), early in pass1 and don't know the position of the stack pointer, and the size of the argument space required to "step over". One solution is to have two pointers to the stack. One for the top of the stack and the other pointing just below the temporaries but above the argument space. Then our function arguments and the permanent registers can be saved fixed-relative to this register. If we don't know the size of argument space, we cannot "dynamically" alter the stack (like we do with mips), since the powerpc ABI specifies that the "lowest" address in the stack frame is the saved stack pointer (pointing to the previous stack frame). While this is a nice feature for tracking back through the stack frames (which mips has always had problems with), it makes it next-to-impossible to increase the strack frame dynamically. I guess the best approach is to determine the size of the argument stack and have a second frame pointer. pcc-20181216/arch/powerpc/code.c010064400017500000000000001077431274041510000151440ustar raggewheel/* $Id: code.c,v 1.32 2016/07/10 09:49:52 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include "pass1.h" #include "pass2.h" #ifdef LANG_CXX #define p1listf listf #define p1tfree tfree #define p1nfree nfree #define p1tcopy tcopy #else #define NODE P1ND #define talloc p1alloc #endif static void genswitch_bintree(int num, TWORD ty, struct swents **p, int n); #if 0 static void genswitch_table(int num, struct swents **p, int n); static void genswitch_mrst(int num, struct swents **p, int n); #endif static int rvnr; /* * Print out assembler segment name. */ void setseg(int seg, char *name) { switch (seg) { case PROG: name = ".text"; break; case DATA: case LDATA: name = ".data"; break; case UDATA: break; #ifdef MACHOABI case PICLDATA: case PICDATA: name = ".section .data.rel.rw,\"aw\""; break; case PICRDATA: name = ".section .data.rel.ro,\"aw\""; break; case STRNG: name = ".cstring"; break; case RDATA: name = ".const_data"; break; #else case PICLDATA: name = ".section .data.rel.local,\"aw\",@progbits";break; case PICDATA: name = ".section .data.rel.rw,\"aw\",@progbits"; break; case PICRDATA: name = ".section .data.rel.ro,\"aw\",@progbits"; break; case STRNG: #ifdef AOUTABI case RDATA: name = ".data"; break; #else case RDATA: name = ".section .rodata"; break; #endif #endif case TLSDATA: name = ".section .tdata,\"awT\",@progbits"; break; case TLSUDATA: name = ".section .tbss,\"awT\",@nobits"; break; case CTORS: name = ".section\t.ctors,\"aw\",@progbits"; break; case DTORS: name = ".section\t.dtors,\"aw\",@progbits"; break; case NMSEG: printf("\t.section %s,\"a%c\",@progbits\n", name, cftnsp ? 'x' : 'w'); return; } printf("\t%s\n", name); } void defalign(int al) { if (ispow2(al/ALCHAR)) printf("\t.p2align %d\n", ispow2(al/ALCHAR)); } /* * Define everything needed to print out some data (or text). * This means segment, alignment, visibility, etc. */ void defloc(struct symtab *sp) { char *name; name = getexname(sp); if (sp->sclass == EXTDEF) printf(" .globl %s\n", name); if (sp->slevel == 0) printf("%s:\n", name); else printf(LABFMT ":\n", sp->soffset); } /* Put a symbol in a temporary * used by bfcode() and its helpers */ static void putintemp(struct symtab *sym) { NODE *p; p = tempnode(0, sym->stype, sym->sdf, sym->sap); p = buildtree(ASSIGN, p, nametree(sym)); sym->soffset = regno(p->n_left); sym->sflags |= STNODE; ecomp(p); } /* setup a 64-bit parameter (double/ldouble/longlong) * used by bfcode() */ static void param_64bit(struct symtab *sym, int *argofsp, int dotemps) { int argofs = *argofsp; NODE *p, *q; int navail; #if ALLONGLONG == 64 /* alignment */ ++argofs; argofs &= ~1; #endif navail = NARGREGS - argofs; if (navail < 2) { /* half in and half out of the registers */ q = block(REG, NIL, NIL, INT, 0, 0); regno(q) = R3 + argofs; p = block(REG, NIL, NIL, INT, 0, 0); regno(p) = FPREG; p = block(PLUS, p, bcon(sym->soffset/SZCHAR), PTR+INT, 0, 0); p = block(UMUL, p, NIL, INT, 0, 0); } else { q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap); regno(q) = R3R4 + argofs; if (dotemps) { p = tempnode(0, sym->stype, sym->sdf, sym->sap); sym->soffset = regno(p); sym->sflags |= STNODE; } else { p = nametree(sym); } } p = buildtree(ASSIGN, p, q); ecomp(p); *argofsp = argofs + 2; } /* setup a 32-bit param on the stack * used by bfcode() */ static void param_32bit(struct symtab *sym, int *argofsp, int dotemps) { NODE *p, *q; q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap); regno(q) = R3 + (*argofsp)++; if (dotemps) { p = tempnode(0, sym->stype, sym->sdf, sym->sap); sym->soffset = regno(p); sym->sflags |= STNODE; } else { p = nametree(sym); } p = buildtree(ASSIGN, p, q); ecomp(p); } /* setup a double param on the stack * used by bfcode() */ static void param_double(struct symtab *sym, int *argofsp, int dotemps) { NODE *p, *q, *t; int tmpnr; /* * we have to dump the double from the general register * into a temp, since the register allocator doesn't like * floats to be in CLASSA. This may not work for -xtemps. */ if (xtemps) { q = block(REG, NIL, NIL, ULONGLONG, 0, 0); regno(q) = R3R4 + *argofsp; p = block(REG, NIL, NIL, PTR+ULONGLONG, 0, 0); regno(p) = SPREG; p = block(PLUS, p, bcon(-8), INT, 0, 0); p = block(UMUL, p, NIL, ULONGLONG, 0, 0); p = buildtree(ASSIGN, p, q); ecomp(p); t = tempnode(0, sym->stype, sym->sdf, sym->sap); tmpnr = regno(t); p = block(REG, NIL, NIL, INCREF(sym->stype), sym->sdf, sym->sap); regno(p) = SPREG; p = block(PLUS, p, bcon(-8), INT, 0, 0); p = block(UMUL, p, NIL, sym->stype, sym->sdf, sym->sap); p = buildtree(ASSIGN, t, p); ecomp(p); } else { /* bounce straight into temp */ p = block(REG, NIL, NIL, ULONGLONG, 0, 0); regno(p) = R3R4 + *argofsp; t = tempnode(0, ULONGLONG, 0, 0); tmpnr = regno(t); p = buildtree(ASSIGN, t, p); ecomp(p); } (*argofsp) += 2; sym->soffset = tmpnr; sym->sflags |= STNODE; } /* setup a float param on the stack * used by bfcode() */ static void param_float(struct symtab *sym, int *argofsp, int dotemps) { NODE *p, *q, *t; int tmpnr; /* * we have to dump the float from the general register * into a temp, since the register allocator doesn't like * floats to be in CLASSA. This may not work for -xtemps. */ if (xtemps) { /* bounce onto TOS */ q = block(REG, NIL, NIL, INT, 0, 0); regno(q) = R3 + (*argofsp); p = block(REG, NIL, NIL, INT, 0, 0); regno(p) = SPREG; p = block(PLUS, p, bcon(-4), INT, 0, 0); p = block(UMUL, p, NIL, INT, 0, 0); p = buildtree(ASSIGN, p, q); ecomp(p); t = tempnode(0, sym->stype, sym->sdf, sym->sap); tmpnr = regno(t); p = block(REG, NIL, NIL, INCREF(sym->stype), sym->sdf, sym->sap); regno(p) = SPREG; p = block(PLUS, p, bcon(-4), INT, 0, 0); p = block(UMUL, p, NIL, sym->stype, sym->sdf, sym->sap); p = buildtree(ASSIGN, t, p); ecomp(p); } else { /* bounce straight into temp */ p = block(REG, NIL, NIL, INT, 0, 0); regno(p) = R3 + (*argofsp); t = tempnode(0, INT, 0, 0); tmpnr = regno(t); p = buildtree(ASSIGN, t, p); ecomp(p); } (*argofsp)++; sym->soffset = tmpnr; sym->sflags |= STNODE; } /* setup the hidden pointer to struct return parameter * used by bfcode() */ static void param_retstruct(void) { NODE *p, *q; p = tempnode(0, INCREF(cftnsp->stype), 0, cftnsp->sap); rvnr = regno(p); q = block(REG, NIL, NIL, INCREF(cftnsp->stype), cftnsp->sdf, cftnsp->sap); regno(q) = R3; p = buildtree(ASSIGN, p, q); ecomp(p); } /* setup struct parameter * push the registers out to memory * used by bfcode() */ static void param_struct(struct symtab *sym, int *argofsp) { int argofs = *argofsp; NODE *p, *q; int navail; int sz; int off; int num; int i; navail = NARGREGS - argofs; sz = tsize(sym->stype, sym->sdf, sym->sap) / SZINT; off = ARGINIT/SZINT + argofs; num = sz > navail ? navail : sz; for (i = 0; i < num; i++) { q = block(REG, NIL, NIL, INT, 0, 0); regno(q) = R3 + argofs++; p = block(REG, NIL, NIL, INT, 0, 0); regno(p) = SPREG; p = block(PLUS, p, bcon(4*off++), INT, 0, 0); p = block(UMUL, p, NIL, INT, 0, 0); p = buildtree(ASSIGN, p, q); ecomp(p); } *argofsp = argofs; } /* * code for the beginning of a function * sp is an array of indices in symtab for the arguments * cnt is the number of arguments */ void bfcode(struct symtab **sp, int cnt) { #ifdef USE_GOTNR extern int gotnr; #endif struct symtab *sp2; union arglist *usym; int saveallargs = 0; int i, argofs = 0; /* * Detect if this function has ellipses and save all * argument registers onto stack. */ usym = cftnsp->sdf->dfun; while (usym && usym->type != TNULL) { if (usym->type == TELLIPSIS) { saveallargs = 1; break; } ++usym; } if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { param_retstruct(); ++argofs; } #ifdef USE_GOTNR if (kflag) { /* put GOT register into temporary */ NODE *q, *p; q = block(REG, NIL, NIL, INT, 0, 0); regno(q) = GOTREG; p = tempnode(0, INT, 0, 0); gotnr = regno(p); ecomp(buildtree(ASSIGN, p, q)); } #endif /* recalculate the arg offset and create TEMP moves */ for (i = 0; i < cnt; i++) { if (sp[i] == NULL) continue; if ((argofs >= NARGREGS) && !xtemps) break; if (argofs >= NARGREGS) { putintemp(sp[i]); } else if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY) { param_struct(sp[i], &argofs); } else if (DEUNSIGN(sp[i]->stype) == LONGLONG) { param_64bit(sp[i], &argofs, xtemps && !saveallargs); } else if (sp[i]->stype == DOUBLE || sp[i]->stype == LDOUBLE) { if (features(FEATURE_HARDFLOAT)) param_double(sp[i], &argofs, xtemps && !saveallargs); else param_64bit(sp[i], &argofs, xtemps && !saveallargs); } else if (sp[i]->stype == FLOAT) { if (features(FEATURE_HARDFLOAT)) param_float(sp[i], &argofs, xtemps && !saveallargs); else param_32bit(sp[i], &argofs, xtemps && !saveallargs); } else { param_32bit(sp[i], &argofs, xtemps && !saveallargs); } } /* if saveallargs, save the rest of the args onto the stack */ while (saveallargs && argofs < NARGREGS) { NODE *p, *q; /* int off = (ARGINIT+FIXEDSTACKSIZE*SZCHAR)/SZINT + argofs; */ int off = ARGINIT/SZINT + argofs; q = block(REG, NIL, NIL, INT, 0, 0); regno(q) = R3 + argofs++; p = block(REG, NIL, NIL, INT, 0, 0); regno(p) = FPREG; p = block(PLUS, p, bcon(4*off), INT, 0, 0); p = block(UMUL, p, NIL, INT, 0, 0); p = buildtree(ASSIGN, p, q); ecomp(p); } /* profiling */ if (pflag) { NODE *p; #if defined(ELFABI) sp2 = lookup("_mcount", 0); sp2->stype = EXTERN; p = nametree(sp2); p->n_sp->sclass = EXTERN; p = clocal(p); p = buildtree(ADDROF, p, NIL); p = block(UCALL, p, NIL, INT, 0, 0); ecomp(funcode(p)); #elif defined(MACHOABI) NODE *q; int tmpnr; q = block(REG, NIL, NIL, INT, 0, 0); regno(q) = R0; p = tempnode(0, INT, 0, 0); tmpnr = regno(p); p = buildtree(ASSIGN, p, q); ecomp(p); q = tempnode(tmpnr, INT, 0, 0); sp2 = lookup("mcount", 0); sp2->stype = EXTERN; p = nametree(sp2); p->n_sp->sclass = EXTERN; p = clocal(p); p = buildtree(ADDROF, p, NIL); p = block(CALL, p, q, INT, 0, 0); ecomp(funcode(p)); #endif } } /* * code for the end of a function * deals with struct return here */ void efcode(void) { NODE *p, *q; int tempnr; int ty; #ifdef USE_GOTNR extern int gotnr; gotnr = 0; #endif if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) return; ty = cftnsp->stype - FTN; q = block(REG, NIL, NIL, INCREF(ty), 0, cftnsp->sap); regno(q) = R3; p = tempnode(0, INCREF(ty), 0, cftnsp->sap); tempnr = regno(p); p = buildtree(ASSIGN, p, q); ecomp(p); q = tempnode(tempnr, INCREF(ty), 0, cftnsp->sap); q = buildtree(UMUL, q, NIL); p = tempnode(rvnr, INCREF(ty), 0, cftnsp->sap); p = buildtree(UMUL, p, NIL); p = buildtree(ASSIGN, p, q); ecomp(p); q = tempnode(rvnr, INCREF(ty), 0, cftnsp->sap); p = block(REG, NIL, NIL, INCREF(ty), 0, cftnsp->sap); regno(p) = R3; p = buildtree(ASSIGN, p, q); ecomp(p); } struct stub stublist; struct stub nlplist; /* called just before final exit */ /* flag is 1 if errors, 0 if none */ void ejobcode(int flag) { #if defined(MACHOABI) /* * iterate over the stublist and output the PIC stubs ` */ if (kflag) { struct stub *p; DLIST_FOREACH(p, &stublist, link) { printf("\t.section __TEXT, __picsymbolstub1,symbol_stubs,pure_instructions,32\n"); printf("\t.align 5\n"); printf("L%s$stub:\n", p->name); if (strcmp(p->name, "mcount") == 0) printf("\t.indirect_symbol %s\n", p->name); else printf("\t.indirect_symbol %s\n", p->name); printf("\tmflr r0\n"); printf("\tbcl 20,31,L%s$spb\n", p->name); printf("L%s$spb:\n", p->name); printf("\tmflr r11\n"); printf("\taddis r11,r11,ha16(L%s$lazy_ptr-L%s$spb)\n", p->name, p->name); printf("\tmtlr r0\n"); printf("\tlwzu r12,lo16(L%s$lazy_ptr-L%s$spb)(r11)\n", p->name, p->name); printf("\tmtctr r12\n"); printf("\tbctr\n"); printf("\t.lazy_symbol_pointer\n"); printf("L%s$lazy_ptr:\n", p->name); if (strcmp(p->name, "mcount") == 0) printf("\t.indirect_symbol %s\n", p->name); else printf("\t.indirect_symbol %s\n", p->name); printf("\t.long dyld_stub_binding_helper\n"); printf("\t.subsections_via_symbols\n"); } printf("\t.non_lazy_symbol_pointer\n"); DLIST_FOREACH(p, &nlplist, link) { printf("L%s$non_lazy_ptr:\n", p->name); if (strcmp(p->name, "mcount") == 0) printf("\t.indirect_symbol %s\n", p->name); else printf("\t.indirect_symbol %s\n", p->name); printf("\t.long 0\n"); } } #endif #ifndef os_darwin printf("\t.ident \"PCC: %s\"\n", VERSSTR); #endif } void bjobcode(void) { DLIST_INIT(&stublist, link); DLIST_INIT(&nlplist, link); } #ifdef notdef /* * Print character t at position i in one string, until t == -1. * Locctr & label is already defined. */ void bycode(int t, int i) { static int lastoctal = 0; /* put byte i+1 in a string */ if (t < 0) { if (i != 0) puts("\""); } else { if (i == 0) printf("\t.ascii \""); if (t == '\\' || t == '"') { lastoctal = 0; putchar('\\'); putchar(t); } else if (t < 040 || t >= 0177) { lastoctal++; printf("\\%o",t); } else if (lastoctal && '0' <= t && t <= '9') { lastoctal = 0; printf("\"\n\t.ascii \"%c", t); } else { lastoctal = 0; putchar(t); } } } #endif /* fix up type of field p */ void fldty(struct symtab *p) { } /* * XXX - fix genswitch. */ int mygenswitch(int num, TWORD type, struct swents **p, int n) { if (num < 0) { genswitch_bintree(num, type, p, n); return 1; } return 0; #if 0 if (0) genswitch_table(num, p, n); if (0) genswitch_bintree(num, p, n); genswitch_mrst(num, p, n); #endif } static void bintree_rec(TWORD ty, int num, struct swents **p, int n, int s, int e); static void genswitch_bintree(int num, TWORD ty, struct swents **p, int n) { int lab = getlab(); if (p[0]->slab == 0) p[0]->slab = lab; bintree_rec(ty, num, p, n, 1, n); plabel(lab); } static void bintree_rec(TWORD ty, int num, struct swents **p, int n, int s, int e) { NODE *r; int rlabel; int h; if (s == e) { r = tempnode(num, ty, 0, 0); r = buildtree(NE, r, bcon(p[s]->sval)); cbranch(buildtree(NOT, r, NIL), bcon(p[s]->slab)); branch(p[0]->slab); return; } rlabel = getlab(); h = s + (e - s) / 2; r = tempnode(num, ty, 0, 0); r = buildtree(GT, r, bcon(p[h]->sval)); cbranch(r, bcon(rlabel)); bintree_rec(ty, num, p, n, s, h); plabel(rlabel); bintree_rec(ty, num, p, n, h+1, e); } #if 0 static void genswitch_table(int num, struct swents **p, int n) { NODE *r, *t; int tval; int minval, maxval, range; int deflabel, tbllabel; int i, j; minval = p[1]->sval; maxval = p[n]->sval; range = maxval - minval + 1; if (n < 10 || range > 3 * n) { /* too small or too sparse for jump table */ genswitch_simple(num, p, n); return; } r = tempnode(num, UNSIGNED, 0, 0); r = buildtree(MINUS, r, bcon(minval)); t = tempnode(0, UNSIGNED, 0, 0); tval = regno(t); r = buildtree(ASSIGN, t, r); ecomp(r); deflabel = p[0]->slab; if (deflabel == 0) deflabel = getlab(); t = tempnode(tval, UNSIGNED, 0, 0); cbranch(buildtree(GT, t, bcon(maxval-minval)), bcon(deflabel)); tbllabel = getlab(); struct symtab *strtbl = lookup("__switch_table", SLBLNAME|STEMP); strtbl->soffset = tbllabel; strtbl->sclass = ILABEL; strtbl->stype = INCREF(UCHAR); t = block(NAME, NIL, NIL, UNSIGNED, 0, 0); t->n_sp = strtbl; t = buildtree(ADDROF, t, NIL); r = tempnode(tval, UNSIGNED, 0, 0); r = buildtree(PLUS, t, r); t = tempnode(0, INCREF(UNSIGNED), 0, 0); r = buildtree(ASSIGN, t, r); ecomp(r); r = tempnode(regno(t), INCREF(UNSIGNED), 0, 0); r = buildtree(UMUL, r, NIL); t = block(NAME, NIL, NIL, UCHAR, 0, 0); t->n_sp = strtbl; t = buildtree(ADDROF, t, NIL); r = buildtree(PLUS, t, r); r = block(GOTO, r, NIL, 0, 0, 0); ecomp(r); plabel(tbllabel); for (i = minval, j=1; i <= maxval; i++) { char *entry = tmpalloc(20); int lab = deflabel; //printf("; minval=%d, maxval=%d, i=%d, j=%d p[j]=%lld\n", minval, maxval, i, j, p[j]->sval); if (p[j]->sval == i) { lab = p[j]->slab; j++; } snprintf(entry, 20, "\t.long " LABFMT "-" LABFMT "\n", lab, tbllabel); send_passt(IP_ASM, entry); } if (p[0]->slab <= 0) plabel(deflabel); } #define DPRINTF(x) if (xdebug) printf x //#define DPRINTF(x) do { } while(0) #define MIN_TABLE_SIZE 8 /* * Multi-way Radix Search Tree (MRST) */ static void mrst_rec(int num, struct swents **p, int n, int *state, int lab); static unsigned long mrst_find_window(struct swents **p, int n, int *state, int lab, int *len, int *lowbit); void mrst_put_entry_and_recurse(int num, struct swents **p, int n, int *state, int tbllabel, int lab, unsigned long j, unsigned long tblsize, unsigned long Wmax, int lowbit); static void genswitch_mrst(int num, struct swents **p, int n) { int *state; int i; int putlabel = 0; if (n < 10) { /* too small for MRST */ genswitch_simple(num, p, n); return; } state = tmpalloc((n+1)*sizeof(int)); for (i = 0; i <= n; i++) state[i] = 0; if (p[0]->slab == 0) { p[0]->slab = getlab(); putlabel = 1; } mrst_rec(num, p, n, state, 0); if (putlabel) plabel(p[0]->slab); } /* * Look through the cases and generate a table or * list of simple comparisons. If generating a table, * invoke mrst_put_entry_and_recurse() to put * an entry in the table and recurse. */ static void mrst_rec(int num, struct swents **p, int n, int *state, int lab) { int len, lowbit; unsigned long Wmax; unsigned int tblsize; NODE *t; NODE *r; int tval; int i; DPRINTF(("mrst_rec: num=%d, n=%d, lab=%d\n", num, n, lab)); /* find best window to cover set*/ Wmax = mrst_find_window(p, n, state, lab, &len, &lowbit); tblsize = (1 << len); assert(len > 0 && tblsize > 0); DPRINTF(("mrst_rec: Wmax=%lu, lowbit=%d, tblsize=%u\n", Wmax, lowbit, tblsize)); if (lab) plabel(lab); if (tblsize <= MIN_TABLE_SIZE) { DPRINTF(("msrt_rec: break the recursion\n")); for (i = 1; i <= n; i++) { if (state[i] == lab) { t = tempnode(num, UNSIGNED, 0, 0); cbranch(buildtree(EQ, t, bcon(p[i]->sval)), bcon(p[i]->slab)); } } branch(p[0]->slab); return; } DPRINTF(("generating table with %d elements\n", tblsize)); // AND with Wmax t = tempnode(num, UNSIGNED, 0, 0); r = buildtree(AND, t, bcon(Wmax)); // RS lowbits r = buildtree(RS, r, bcon(lowbit)); t = tempnode(0, UNSIGNED, 0, 0); tval = regno(t); r = buildtree(ASSIGN, t, r); ecomp(r); int tbllabel = getlab(); struct symtab *strtbl = lookup("__switch_table", SLBLNAME|STEMP); strtbl->sclass = STATIC; strtbl->sap = 0; strtbl->slevel = 1; strtbl->soffset = tbllabel; strtbl->stype = INCREF(UCHAR); strtbl->squal = (CON >> TSHIFT); t = block(NAME, NIL, NIL, UNSIGNED, 0, 0); t->n_sp = strtbl; t = buildtree(ADDROF, t, NIL); r = tempnode(tval, UNSIGNED, 0, 0); r = buildtree(PLUS, t, r); t = tempnode(0, INCREF(UNSIGNED), 0, 0); r = buildtree(ASSIGN, t, r); ecomp(r); r = tempnode(regno(t), INCREF(UNSIGNED), 0, 0); r = buildtree(UMUL, r, NIL); t = block(NAME, NIL, NIL, UCHAR, 0, 0); t->n_sp = strtbl; t = buildtree(ADDROF, t, NIL); r = buildtree(PLUS, t, r); r = block(GOTO, r, NIL, 0, 0, 0); ecomp(r); plabel(tbllabel); mrst_put_entry_and_recurse(num, p, n, state, tbllabel, lab, 0, tblsize, Wmax, lowbit); } /* * Put an entry into the table and recurse to the next entry * in the table. On the way back through the recursion, invoke * mrst_rec() to check to see if we should generate another * table. */ void mrst_put_entry_and_recurse(int num, struct swents **p, int n, int *state, int tbllabel, int labval, unsigned long j, unsigned long tblsize, unsigned long Wmax, int lowbit) { int i; int found = 0; int lab = getlab(); /* * Look for labels which map to this table entry. * Mark each one in "state" that they fall inside this table. */ for (i = 1; i <= n; i++) { unsigned int val = (p[i]->sval & Wmax) >> lowbit; if (val == j && state[i] == labval) { found = 1; state[i] = lab; } } /* couldn't find any labels? goto the default label */ if (!found) lab = p[0]->slab; /* generate the table entry */ char *entry = tmpalloc(20); snprintf(entry, 20, "\t.long " LABFMT "-" LABFMT "\n", lab, tbllabel); send_passt(IP_ASM, entry); DPRINTF(("mrst_put_entry: table=%d, pos=%lu/%lu, label=%d\n", tbllabel, j, tblsize, lab)); /* go to the next table entry */ if (j+1 < tblsize) { mrst_put_entry_and_recurse(num, p, n, state, tbllabel, labval, j+1, tblsize, Wmax, lowbit); } /* if we are going to the default label, bail now */ if (!found) return; #ifdef PCC_DEBUG if (xdebug) { printf("state: "); for (i = 1; i <= n; i++) printf("%d ", state[i]); printf("\n"); } #endif /* build another table */ mrst_rec(num, p, n, state, lab); } /* * counts the number of entries in a table of size (1 << L) which would * be used given the cases and the mask (W, lowbit). */ static unsigned int mrst_cardinality(struct swents **p, int n, int *state, int step, unsigned long W, int L, int lowbit) { unsigned int count = 0; int i; if (W == 0) return 0; int *vals = (int *)calloc(1 << L, sizeof(int)); assert(vals); DPRINTF(("mrst_cardinality: ")); for (i = 1; i <= n; i++) { int idx; if (state[i] != step) continue; idx = (p[i]->sval & W) >> lowbit; DPRINTF(("%llu->%d, ", p[i]->sval, idx)); if (!vals[idx]) { count++; } vals[idx] = 1; } DPRINTF((": found %d entries\n", count)); free(vals); return count; } /* * Find the maximum window (table size) which would best cover * the set of labels. Algorithm explained in: * * Ulfar Erlingsson, Mukkai Krishnamoorthy and T.V. Raman. * Efficient Multiway Radix Search Trees. * Information Processing Letters 60:3 115-120 (November 1996) */ static unsigned long mrst_find_window(struct swents **p, int n, int *state, int lab, int *len, int *lowbit) { unsigned int tblsize; unsigned long W = 0; unsigned long Wmax = 0; unsigned long Wleft = (1 << (SZLONG-1)); unsigned int C = 0; unsigned int Cmax = 0; int L = 0; int Lmax = 0; int lowmax = 0; int no_b = SZLONG-1; unsigned long b = (1 << (SZLONG-1)); DPRINTF(("mrst_find_window: n=%d, lab=%d\n", n, lab)); for (; b > 0; b >>= 1, no_b--) { // select the next bit W |= b; L += 1; tblsize = 1 << L; assert(tblsize > 0); DPRINTF(("no_b=%d, b=0x%lx, Wleft=0x%lx, W=0x%lx, Wmax=0x%lx, L=%d, Lmax=%d, Cmax=%u, lowmax=%d, tblsize=%u\n", no_b, b, Wleft, W, Wmax, L, Lmax, Cmax, lowmax, tblsize)); C = mrst_cardinality(p, n, state, lab, W, L, no_b); DPRINTF((" -> cardinality is %d\n", C)); if (2*C >= tblsize) { DPRINTF(("(found good match, keep adding to table)\n")); Wmax = W; Lmax = L; lowmax = no_b; Cmax = C; } else { DPRINTF(("(too sparse)\n")); assert((W & Wleft) != 0); /* flip the MSB and see if we get a better match */ W ^= Wleft; Wleft >>= 1; L -= 1; DPRINTF((" --> trying W=0x%lx and L=%d and Cmax=%u\n", W, L, Cmax)); C = mrst_cardinality(p, n, state, lab, W, L, no_b); DPRINTF((" --> C=%u\n", C)); if (C > Cmax) { Wmax = W; Lmax = L; lowmax = no_b; Cmax = C; DPRINTF((" --> better!\n")); } else { DPRINTF((" --> no better\n")); } } } #ifdef PCC_DEBUG if (xdebug) { int i; int hibit = lowmax + Lmax; printf("msrt_find_window: Wmax=0x%lx, lowbit=%d, result=", Wmax, lowmax); for (i = 31; i >= 0; i--) { int mask = (1 << i); if (i == hibit) printf("["); if (Wmax & mask) printf("1"); else printf("0"); if (i == lowmax) printf("]"); } printf("\n"); } #endif assert(Lmax > 0); *len = Lmax; *lowbit = lowmax; DPRINTF(("msrt_find_window: returning Wmax=%lu, len=%d, lowbit=%d [tblsize=%u, entries=%u]\n", Wmax, Lmax, lowmax, tblsize, C)); return Wmax; } #endif /* * Straighten a chain of CM ops so that the CM nodes * only appear on the left node. * * CM CM * CM CM CM b * x y a b CM a * x y * * CM CM * CM CM CM c * CM z CM c CM b * x y a b CM a * CM z * x y */ static NODE * straighten(NODE *p) { NODE *r = p->n_right; if (p->n_op != CM || r->n_op != CM) return p; p->n_right = r->n_left; r->n_left = straighten(p); return r; } static NODE * reverse1(NODE *p, NODE *a) { NODE *l = p->n_left; NODE *r = p->n_right; a->n_right = r; p->n_left = a; if (l->n_op == CM) { return reverse1(l, p); } else { p->n_right = l; return p; } } /* * Reverse a chain of CM ops */ static NODE * reverse(NODE *p) { NODE *l = p->n_left; NODE *r = p->n_right; p->n_left = r; if (l->n_op == CM) return reverse1(l, p); p->n_right = l; return p; } /* push arg onto the stack */ /* called by moveargs() */ static NODE * pusharg(NODE *p, int *regp) { NODE *q; int sz; int off; /* convert to register size, if smaller */ sz = tsize(p->n_type, p->n_df, p->n_ap); if (sz < SZINT) p = block(SCONV, p, NIL, INT, 0, 0); q = block(REG, NIL, NIL, INCREF(p->n_type), p->n_df, p->n_ap); regno(q) = SPREG; off = ARGINIT/SZCHAR + 4 * (*regp - R3); q = block(PLUS, q, bcon(off), INT, 0, 0); q = block(UMUL, q, NIL, p->n_type, p->n_df, p->n_ap); (*regp) += szty(p->n_type); return buildtree(ASSIGN, q, p); } /* setup call stack with 32-bit argument */ /* called from moveargs() */ static NODE * movearg_32bit(NODE *p, int *regp) { int reg = *regp; NODE *q; q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap); regno(q) = reg++; q = buildtree(ASSIGN, q, p); *regp = reg; return q; } /* setup call stack with 64-bit argument */ /* called from moveargs() */ static NODE * movearg_64bit(NODE *p, int *regp) { int reg = *regp; NODE *q, *r; #if ALLONGLONG == 64 /* alignment */ ++reg; reg &= ~1; #endif if (reg > R10) { *regp = reg; q = pusharg(p, regp); } else if (reg == R10) { /* half in and half out of the registers */ r = p1tcopy(p); if (!features(FEATURE_BIGENDIAN)) { q = block(SCONV, p, NIL, INT, 0, 0); q = movearg_32bit(q, regp); /* little-endian */ r = buildtree(RS, r, bcon(32)); r = block(SCONV, r, NIL, INT, 0, 0); r = pusharg(r, regp); /* little-endian */ } else { q = buildtree(RS, p, bcon(32)); q = block(SCONV, q, NIL, INT, 0, 0); q = movearg_32bit(q, regp); /* big-endian */ r = block(SCONV, r, NIL, INT, 0, 0); r = pusharg(r, regp); /* big-endian */ } q = straighten(block(CM, q, r, p->n_type, p->n_df, p->n_ap)); } else { q = block(REG, NIL, NIL, p->n_type, p->n_df, p->n_ap); regno(q) = R3R4 + (reg - R3); q = buildtree(ASSIGN, q, p); *regp = reg + 2; } return q; } /* setup call stack with float argument */ /* called from moveargs() */ static NODE * movearg_float(NODE *p, int *fregp, int *regp) { #if defined(MACHOABI) NODE *q, *r; TWORD ty = INCREF(p->n_type); int tmpnr; #endif p = movearg_32bit(p, fregp); /* * On OS/X, floats are passed in the floating-point registers * and in the general registers for compatibily with libraries * compiled to handle soft-float. */ #if defined(MACHOABI) if (xtemps) { /* bounce into TOS */ r = block(REG, NIL, NIL, ty, p->n_df, p->n_ap); regno(r) = SPREG; r = block(PLUS, r, bcon(-4), INT, 0, 0); r = block(UMUL, r, NIL, p->n_type, p->n_df, p->n_ap); r = buildtree(ASSIGN, r, p); ecomp(r); /* bounce into temp */ r = block(REG, NIL, NIL, PTR+INT, 0, 0); regno(r) = SPREG; r = block(PLUS, r, bcon(-4), INT, 0, 0); r = block(UMUL, r, NIL, INT, 0, 0); q = tempnode(0, INT, 0, 0); tmpnr = regno(q); r = buildtree(ASSIGN, q, r); ecomp(r); } else { /* copy directly into temp */ q = tempnode(0, p->n_type, p->n_df, p->n_ap); tmpnr = regno(q); r = buildtree(ASSIGN, q, p); ecomp(r); } /* copy from temp to register parameter */ r = tempnode(tmpnr, INT, 0, 0); q = block(REG, NIL, NIL, INT, 0, 0); regno(q) = (*regp)++; p = buildtree(ASSIGN, q, r); #endif return p; } /* setup call stack with float/double argument */ /* called from moveargs() */ static NODE * movearg_double(NODE *p, int *fregp, int *regp) { #if defined(MACHOABI) NODE *q, *r; TWORD ty = INCREF(p->n_type); int tmpnr; #endif /* this does the move to a single register for us */ p = movearg_32bit(p, fregp); /* * On OS/X, doubles are passed in the floating-point registers * and in the general registers for compatibily with libraries * compiled to handle soft-float. */ #if defined(MACHOABI) if (xtemps) { /* bounce on TOS */ r = block(REG, NIL, NIL, ty, p->n_df, p->n_ap); regno(r) = SPREG; r = block(PLUS, r, bcon(-8), ty, p->n_df, p->n_ap); r = block(UMUL, r, NIL, p->n_type, p->n_df, p->n_ap); r = buildtree(ASSIGN, r, p); ecomp(r); /* bounce into temp */ r = block(REG, NIL, NIL, PTR+LONGLONG, 0, 0); regno(r) = SPREG; r = block(PLUS, r, bcon(-8), PTR+LONGLONG, 0, 0); r = block(UMUL, r, NIL, LONGLONG, 0, 0); q = tempnode(0, LONGLONG, 0, 0); tmpnr = regno(q); r = buildtree(ASSIGN, q, r); ecomp(r); } else { /* copy directly into temp */ q = tempnode(0, p->n_type, p->n_df, p->n_ap); tmpnr = regno(q); r = buildtree(ASSIGN, q, p); ecomp(r); } /* copy from temp to register parameter */ r = tempnode(tmpnr, LONGLONG, 0, 0); q = block(REG, NIL, NIL, LONGLONG, 0, 0); regno(q) = R3R4 - R3 + (*regp); p = buildtree(ASSIGN, q, r); (*regp) += 2; #endif return p; } /* setup call stack with a structure */ /* called from moveargs() */ static NODE * movearg_struct(NODE *p, int *regp) { int reg = *regp; NODE *l, *q, *t, *r; int tmpnr; int navail; int num; int sz; int ty; int i; assert(p->n_op == STARG); navail = NARGREGS - (reg - R3); navail = navail < 0 ? 0 : navail; sz = tsize(p->n_type, p->n_df, p->n_ap) / SZINT; num = sz > navail ? navail : sz; /* remove STARG node */ l = p->n_left; p1nfree(p); ty = l->n_type; /* * put it into a TEMP, rather than tcopy(), since the tree * in p may have side-affects */ t = tempnode(0, ty, l->n_df, l->n_ap); tmpnr = regno(t); q = buildtree(ASSIGN, t, l); /* copy structure into registers */ for (i = 0; i < num; i++) { t = tempnode(tmpnr, ty, 0, 0); t = block(SCONV, t, NIL, PTR+INT, 0, 0); t = block(PLUS, t, bcon(4*i), PTR+INT, 0, 0); t = buildtree(UMUL, t, NIL); r = block(REG, NIL, NIL, INT, 0, 0); regno(r) = reg++; r = buildtree(ASSIGN, r, t); q = block(CM, q, r, INT, 0, 0); } /* put the rest of the structure on the stack */ for (i = num; i < sz; i++) { t = tempnode(tmpnr, ty, 0, 0); t = block(SCONV, t, NIL, PTR+INT, 0, 0); t = block(PLUS, t, bcon(4*i), PTR+INT, 0, 0); t = buildtree(UMUL, t, NIL); r = pusharg(t, ®); q = block(CM, q, r, INT, 0, 0); } q = reverse(q); *regp = reg; return q; } static NODE * moveargs(NODE *p, int *regp, int *fregp) { NODE *r, **rp; int reg, freg; if (p->n_op == CM) { p->n_left = moveargs(p->n_left, regp, fregp); r = p->n_right; rp = &p->n_right; } else { r = p; rp = &p; } reg = *regp; freg = *fregp; #define ISFLOAT(p) (p->n_type == FLOAT || \ p->n_type == DOUBLE || \ p->n_type == LDOUBLE) if (reg > R10 && r->n_op != STARG) { *rp = pusharg(r, regp); } else if (r->n_op == STARG) { *rp = movearg_struct(r, regp); } else if (DEUNSIGN(r->n_type) == LONGLONG) { *rp = movearg_64bit(r, regp); } else if (r->n_type == DOUBLE || r->n_type == LDOUBLE) { if (features(FEATURE_HARDFLOAT)) *rp = movearg_double(r, fregp, regp); else *rp = movearg_64bit(r, regp); } else if (r->n_type == FLOAT) { if (features(FEATURE_HARDFLOAT)) *rp = movearg_float(r, fregp, regp); else *rp = movearg_32bit(r, regp); } else { *rp = movearg_32bit(r, regp); } return straighten(p); } /* * Fixup arguments to pass pointer-to-struct as first argument. * * called from funcode(). */ static NODE * retstruct(NODE *p) { struct symtab s; NODE *l, *r, *t, *q; TWORD ty; l = p->n_left; r = p->n_right; ty = DECREF(l->n_type) - FTN; s.sclass = AUTO; s.stype = ty; s.sdf = l->n_df; s.sap = l->n_ap; oalloc(&s, &autooff); q = block(REG, NIL, NIL, INCREF(ty), l->n_df, l->n_ap); regno(q) = FPREG; q = block(MINUS, q, bcon(autooff/SZCHAR), INCREF(ty), l->n_df, l->n_ap); /* insert hidden assignment at beginning of list */ if (r->n_op != CM) { p->n_right = block(CM, q, r, INCREF(ty), l->n_df, l->n_ap); } else { for (t = r; t->n_left->n_op == CM; t = t->n_left) ; t->n_left = block(CM, q, t->n_left, INCREF(ty), l->n_df, l->n_ap); } return p; } /* * Called with a function call with arguments as argument. * This is done early in buildtree() and only done once. */ NODE * funcode(NODE *p) { int regnum = R3; int fregnum = F1; if (DECREF(p->n_left->n_type) == STRTY+FTN || DECREF(p->n_left->n_type) == UNIONTY+FTN) p = retstruct(p); p->n_right = moveargs(p->n_right, ®num, &fregnum); if (p->n_right == NULL) p->n_op += (UCALL - CALL); return p; } pcc-20181216/arch/powerpc/local.c010064400017500000000000000646261340073675300153440ustar raggewheel/* $Id: local.c,v 1.36 2018/12/02 11:11:39 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "pass1.h" #undef NIL #define NIL NULL #ifdef LANG_CXX #define P1ND NODE #define p1nfree nfree #define p1tfree tfree #define p1fwalk fwalk #define p1walkf walkf #define p1tcopy tcopy #else #define NODE P1ND #define nfree p1nfree #endif #define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz)) extern int kflag; static void simmod(NODE *p); /* this file contains code which is dependent on the target machine */ #if defined(MACHOABI) /* * Keep track of PIC stubs. */ void addstub(struct stub *list, char *name) { struct stub *s; DLIST_FOREACH(s, list, link) { if (strcmp(s->name, name) == 0) return; } s = permalloc(sizeof(struct stub)); s->name = newstring(name, strlen(name)); DLIST_INSERT_BEFORE(list, s, link); } #endif /* * Make a symtab entry for PIC use. */ static struct symtab * picsymtab(char *p, char *s, char *s2) { struct symtab *sp = IALLOC(sizeof(struct symtab)); size_t len = strlen(p) + strlen(s) + strlen(s2) + 1; sp->sname = IALLOC(len); strlcpy(sp->sname, p, len); strlcat(sp->sname, s, len); strlcat(sp->sname, s2, len); sp->sclass = EXTERN; sp->sflags = sp->slevel = 0; return sp; } int gotnr; /* tempnum for GOT register */ /* * Create a reference for an extern variable. */ static NODE * picext(NODE *p) { NODE *q; struct symtab *sp; char *name; name = getexname(p->n_sp); if (strncmp(name, "__builtin", 9) == 0) return p; #if defined(ELFABI) sp = picsymtab("", name, "@got(31)"); q = xbcon(0, sp, PTR+VOID); q = block(UMUL, q, 0, PTR+VOID, 0, 0); #elif defined(MACHOABI) char buf2[64]; NODE *r; char *fname; fname = cftnsp->soname ? cftnsp->soname : cftnsp->sname; if (p->n_sp->sclass == EXTDEF) { snprintf(buf2, 64, "-L%s$pb", fname); sp = picsymtab("", name, buf2); } else { snprintf(buf2, 64, "$non_lazy_ptr-L%s$pb", fname); sp = picsymtab("L", name, buf2); addstub(&nlplist, name); } #if USE_GOTNR q = tempnode(gotnr, PTR+VOID, 0, 0); #else q = block(REG, NIL, NIL, PTR+VOID, 0, 0); regno(q) = GOTREG; #endif r = xbcon(0, sp, INT); q = buildtree(PLUS, q, r); if (p->n_sp->sclass != EXTDEF) q = block(UMUL, q, 0, PTR+VOID, 0, 0); #endif q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); q->n_sp = p->n_sp; /* for init */ p1nfree(p); return q; } /* * Create a reference for a static variable */ static NODE * picstatic(NODE *p) { NODE *q; struct symtab *sp; #if defined(ELFABI) char *n; if (p->n_sp->slevel > 0) { char buf[64]; snprintf(buf, 64, LABFMT, (int)p->n_sp->soffset); sp = picsymtab("", buf, "@got(31)"); } else { n = getexname(p->n_sp); sp = picsymtab("", n, "@got(31)"); } sp->sclass = STATIC; sp->stype = p->n_sp->stype; q = xbcon(0, sp, PTR+VOID); q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); q->n_sp = p->n_sp; p1nfree(p); #elif defined(MACHOABI) char buf2[64]; NODE *r; snprintf(buf2, 64, "-L%s$pb", cftnsp->soname ? cftnsp->soname : cftnsp->sname); if (p->n_sp->slevel > 0) { char buf1[64]; snprintf(buf1, 64, LABFMT, (int)p->n_sp->soffset); sp = picsymtab("", buf1, buf2); } else { char *name = p->n_sp->soname ? p->n_sp->soname : exname(p->n_sp->sname); sp = picsymtab("", name, buf2); } sp->sclass = STATIC; sp->stype = p->n_sp->stype; #if USE_GOTNR q = tempnode(gotnr, PTR+VOID, 0, 0); #else q = block(REG, NIL, NIL, PTR+VOID, 0, 0); regno(q) = GOTREG; #endif r = xbcon(0, sp, INT); q = buildtree(PLUS, q, r); q = block(UMUL, q, 0, p->n_type, p->n_df, p->n_ap); q->n_sp = p->n_sp; nfree(p); #endif return q; } static NODE * convert_ulltof(NODE *p) { NODE *q, *r, *l, *t; int ty; int tmpnr; ty = p->n_type; l = p->n_left; nfree(p); q = tempnode(0, ULONGLONG, 0, 0); tmpnr = regno(q); t = buildtree(ASSIGN, q, l); ecomp(t); #if 0 q = tempnode(tmpnr, ULONGLONG, 0, 0); q = block(SCONV, q, NIL, LONGLONG, 0, 0); #endif q = tempnode(tmpnr, LONGLONG, 0, 0); r = block(SCONV, q, NIL, ty, 0, 0); q = tempnode(tmpnr, ULONGLONG, 0, 0); q = block(RS, q, bcon(1), ULONGLONG, 0, 0); q = block(SCONV, q, NIL, LONGLONG, 0, 0); q = block(SCONV, q, NIL, ty, 0, 0); t = block(FCON, NIL, NIL, ty, 0, 0); #ifndef LANG_CXX t->n_dcon = fltallo(); FLOAT_INT2FP(p->n_dcon, 2, INT); #else cerror("convert_ulltof"); #endif l = block(MUL, q, t, ty, 0, 0); r = buildtree(COLON, l, r); q = tempnode(tmpnr, ULONGLONG, 0, 0); q = block(SCONV, q, NIL, LONGLONG, 0, 0); l = block(LE, q, xbcon(0, NULL, LONGLONG), INT, 0, 0); return clocal(buildtree(QUEST, l, r)); } /* clocal() is called to do local transformations on * an expression tree preparitory to its being * written out in intermediate code. * * the major essential job is rewriting the * automatic variables and arguments in terms of * REG and OREG nodes * conversion ops which are not necessary are also clobbered here * in addition, any special features (such as rewriting * exclusive or) are easily handled here as well */ NODE * clocal(NODE *p) { struct symtab *q; NODE *r, *l; int o; int m; TWORD t; int isptrvoid = 0; int tmpnr; #ifdef PCC_DEBUG if (xdebug) { printf("clocal: %p\n", p); p1fwalk(p, eprint, 0); } #endif switch (o = p->n_op) { case ADDROF: #ifdef PCC_DEBUG if (xdebug) { printf("clocal(): ADDROF\n"); printf("type: 0x%x\n", p->n_type); } #endif /* XXX cannot takes addresses of PARAMs */ if (kflag == 0 || blevel == 0) break; /* char arrays may end up here */ l = p->n_left; if (l->n_op != NAME || (l->n_type != ARY+CHAR && l->n_type != ARY+WCHAR_TYPE)) break; l = p; p = picstatic(p->n_left); nfree(l); if (p->n_op != UMUL) cerror("ADDROF error"); l = p; p = p->n_left; nfree(l); break; case NAME: if ((q = p->n_sp) == NULL) return p; /* Nothing to care about */ switch (q->sclass) { case PARAM: case AUTO: /* fake up a structure reference */ r = block(REG, NIL, NIL, PTR+STRTY, 0, 0); slval(r, 0); r->n_rval = FPREG; p = stref(block(STREF, r, p, 0, 0, 0)); break; case USTATIC: if (kflag == 0) break; /* FALLTHROUGH */ case STATIC: if (kflag == 0) { if (q->slevel == 0) break; slval(p, 0); } else if (blevel > 0) { p = picstatic(p); } break; case REGISTER: p->n_op = REG; slval(p, 0); p->n_rval = q->soffset; break; case EXTERN: case EXTDEF: if (kflag == 0) break; if (blevel > 0) p = picext(p); break; } break; case UCALL: case CALL: case USTCALL: case STCALL: if (p->n_type == VOID) break; /* * if the function returns void*, ecode() invokes * delvoid() to convert it to uchar*. * We just let this happen on the ASSIGN to the temp, * and cast the pointer back to void* on access * from the temp. */ if (p->n_type == PTR+VOID) isptrvoid = 1; r = tempnode(0, p->n_type, p->n_df, p->n_ap); tmpnr = regno(r); r = buildtree(ASSIGN, r, p); p = tempnode(tmpnr, r->n_type, r->n_df, r->n_ap); if (isptrvoid) { p = block(PCONV, p, NIL, PTR+VOID, p->n_df, 0); } #if 1 p = buildtree(COMOP, r, p); #else /* XXX this doesn't work if the call is already in a COMOP */ r = clocal(r); ecomp(r); #endif break; case CBRANCH: l = p->n_left; /* * Remove unnecessary conversion ops. */ if (clogop(l->n_op) && l->n_left->n_op == SCONV) { if (coptype(l->n_op) != BITYPE) break; if (l->n_right->n_op == ICON) { r = l->n_left->n_left; if (r->n_type >= FLOAT && r->n_type <= LDOUBLE) break; /* Type must be correct */ t = r->n_type; nfree(l->n_left); l->n_left = r; l->n_type = t; l->n_right->n_type = t; } } break; case PCONV: /* Remove redundant PCONV's. Be careful */ l = p->n_left; if (l->n_op == ICON) { slval(l, (unsigned)glval(l)); goto delp; } if (l->n_type < INT || DEUNSIGN(l->n_type) == LONGLONG) { /* float etc? */ p->n_left = block(SCONV, l, NIL, UNSIGNED, 0, 0); break; } /* if left is SCONV, cannot remove */ if (l->n_op == SCONV) break; /* avoid ADDROF TEMP */ if (l->n_op == ADDROF && l->n_left->n_op == TEMP) break; /* if conversion to another pointer type, just remove */ if (p->n_type > BTMASK && l->n_type > BTMASK) goto delp; break; delp: l->n_type = p->n_type; l->n_qual = p->n_qual; l->n_df = p->n_df; l->n_ap = p->n_ap; nfree(p); p = l; break; case SCONV: l = p->n_left; if (p->n_type == l->n_type) { nfree(p); return l; } if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 && tsize(p->n_type, p->n_df, p->n_ap) == tsize(l->n_type, l->n_df, l->n_ap)) { if (p->n_type != FLOAT && p->n_type != DOUBLE && l->n_type != FLOAT && l->n_type != DOUBLE && l->n_type != LDOUBLE && p->n_type != LDOUBLE) { if (l->n_op == NAME || l->n_op == UMUL || l->n_op == TEMP) { l->n_type = p->n_type; nfree(p); return l; } } } if (DEUNSIGN(p->n_type) == INT && DEUNSIGN(l->n_type) == INT && coptype(l->n_op) == BITYPE) { l->n_type = p->n_type; nfree(p); return l; } /* * if converting ULONGLONG to FLOAT/(L)DOUBLE, * replace ___floatunsdidf() with ___floatdidf() */ if (l->n_type == ULONGLONG && p->n_type >= FLOAT && p->n_type <= LDOUBLE) { return convert_ulltof(p); } o = l->n_op; m = p->n_type; if (DEUNSIGN(p->n_type) == SHORT && DEUNSIGN(l->n_type) == SHORT) { nfree(p); p = l; } if ((DEUNSIGN(p->n_type) == CHAR || DEUNSIGN(p->n_type) == SHORT) && (l->n_type == FLOAT || l->n_type == DOUBLE || l->n_type == LDOUBLE)) { p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap); p->n_left->n_type = INT; return p; } if ((DEUNSIGN(l->n_type) == CHAR || DEUNSIGN(l->n_type) == SHORT) && (p->n_type == FLOAT || p->n_type == DOUBLE || p->n_type == LDOUBLE)) { p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap); p->n_left->n_type = INT; return p; } break; case MOD: simmod(p); break; case DIV: if (o == DIV && p->n_type != CHAR && p->n_type != SHORT) break; /* make it an int division by inserting conversions */ p->n_left = block(SCONV, p->n_left, NIL, INT, 0, 0); p->n_right = block(SCONV, p->n_right, NIL, INT, 0, 0); p = block(SCONV, p, NIL, p->n_type, 0, 0); p->n_left->n_type = INT; break; case STNAME: if ((q = p->n_sp) == NULL) return p; if (q->sclass != STNAME) return p; t = p->n_type; p = block(ADDROF, p, NIL, INCREF(t), p->n_df, p->n_ap); p = block(UMUL, p, NIL, t, p->n_df, p->n_ap); break; case FORCE: /* put return value in return reg */ p->n_op = ASSIGN; p->n_right = p->n_left; p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0); p->n_left->n_rval = p->n_left->n_type == BOOL ? RETREG(BOOL_TYPE) : RETREG(p->n_type); break; case LS: case RS: if (p->n_right->n_op == ICON) break; /* do not do anything */ if (DEUNSIGN(p->n_right->n_type) == INT) break; p->n_right = block(SCONV, p->n_right, NIL, INT, 0, 0); break; } #ifdef PCC_DEBUG if (xdebug) { printf("clocal end: %p\n", p); p1fwalk(p, eprint, 0); } #endif return(p); } /* * Change CALL references to either direct (static) or PLT. */ static void fixnames(NODE *p, void *arg) { struct symtab *sp; struct attr *ap, *ap2; NODE *q; char *c; int isu; if ((cdope(p->n_op) & CALLFLG) == 0) return; isu = 0; q = p->n_left; ap = q->n_ap; if (q->n_op == UMUL) q = q->n_left, isu = 1; #if defined(ELFABI) if (q->n_op == ICON) { sp = q->n_sp; #elif defined(MACHOABI) #ifdef USE_GOTNR if (q->n_op == PLUS && q->n_left->n_op == TEMP && #else if (q->n_op == PLUS && q->n_left->n_op == REG && #endif q->n_right->n_op == ICON) { sp = q->n_right->n_sp; #endif if (sp == NULL) return; /* nothing to do */ if (sp->sclass == STATIC && !ISFTN(sp->stype)) return; /* function pointer */ if (sp->sclass != STATIC && sp->sclass != EXTERN && sp->sclass != EXTDEF) cerror("fixnames"); c = NULL; #if defined(ELFABI) if ((ap2 = attr_find(sp->sap, ATTR_SONAME)) == NULL || (c = strstr(ap2->sarg(0), "@got(31)")) == NULL) cerror("fixnames2"); if (isu) { memcpy(c, "@plt", sizeof("@plt")); } else *c = 0; #elif defined(MACHOABI) if (sp->soname == NULL || ((c = strstr(sp->soname, "$non_lazy_ptr")) == NULL && (c = strstr(sp->soname, "-L")) == NULL)) cerror("fixnames2"); if (isu) { addstub(&stublist, sp->soname+1); memcpy(c, "$stub", sizeof("$stub")); } else *c = 0; nfree(q->n_left); q = q->n_right; if (isu) nfree(p->n_left->n_left); nfree(p->n_left); p->n_left = q; q->n_ap = ap; #endif } } void myp2tree(NODE *p) { int o = p->n_op; struct symtab *sp; if (kflag) p1walkf(p, fixnames, 0); if (o != FCON) return; /* Write float constants to memory */ /* Should be voluntary per architecture */ sp = IALLOC(sizeof(struct symtab)); sp->sclass = STATIC; sp->sap = 0; sp->slevel = 1; /* fake numeric label */ sp->soffset = getlab(); sp->sflags = 0; sp->stype = p->n_type; sp->squal = (CON >> TSHIFT); defloc(sp); ninval(0, tsize(sp->stype, sp->sdf, sp->sap), p); p->n_op = NAME; slval(p, 0); p->n_sp = sp; } /*ARGSUSED*/ int andable(NODE *p) { return(1); /* all names can have & taken on them */ } /* * Return 1 if a variable of type type is OK to put in register. */ int cisreg(TWORD t) { return 1; } /* * Allocate bits on the stack. * 'off' is the number of bits to allocate * 'p' is a tree that when evaluated is the multiply count for 'off' * 't' is a storeable node where to write the allocated address */ void spalloc(NODE *t, NODE *p, OFFSZ off) { NODE *q, *r; int nbytes = off / SZCHAR; int stacksize = 24+40; /* this should be p2stacksize */ /* * After we subtract the requisite bytes * off the stack, we need to step back over * the 40 bytes for the arguments registers * *and* any other parameters which will get * saved to the stack. Unfortunately, we * don't have that information in pass1 and * the parameters will stomp on the allocated * space for alloca(). * * No fix yet. */ werror("parameters may stomp on alloca()"); /* compute size */ p = buildtree(MUL, p, bcon(nbytes)); p = buildtree(PLUS, p, bcon(ALSTACK/SZCHAR)); /* load the top-of-stack */ q = block(REG, NIL, NIL, PTR+INT, 0, 0); regno(q) = SPREG; q = block(UMUL, q, NIL, INT, 0, 0); /* save old top-of-stack value to new top-of-stack position */ r = block(REG, NIL, NIL, PTR+INT, 0, 0); regno(r) = SPREG; r = block(MINUSEQ, r, p, INT, 0, 0); r = block(UMUL, r, NIL, INT, 0, 0); ecomp(buildtree(ASSIGN, r, q)); r = block(REG, NIL, NIL, PTR+INT, 0, 0); regno(r) = SPREG; /* skip over the arguments space and align to 16 bytes */ r = block(PLUS, r, bcon(stacksize + 15), INT, 0, 0); r = block(RS, r, bcon(4), INT, 0, 0); r = block(LS, r, bcon(4), INT, 0, 0); t->n_type = p->n_type; ecomp(buildtree(ASSIGN, t, r)); } /* * Print out a string of characters. * Unfortunately, this code assumes that the assembler understands * C-style escape sequences. (which it doesn't!) * Location is already set. */ void instring(struct symtab *sp) { char *s, *str = sp->sname; #if defined(ELFABI) defloc(sp); #elif defined(MACHOABI) extern int lastloc; if (lastloc != STRNG) printf(" .cstring\n"); lastloc = STRNG; printf("\t.p2align 2\n"); printf(LABFMT ":\n", sp->soffset); #endif /* be kind to assemblers and avoid long strings */ printf("\t.ascii \""); for (s = str; *s != 0; ) { if (*s++ == '\\') { (void)esccon(&s); } if (s - str > 64) { fwrite(str, 1, s - str, stdout); printf("\"\n\t.ascii \""); str = s; } } fwrite(str, 1, s - str, stdout); printf("\\0\"\n"); } /* * print out a constant node, may be associated with a label. * Do not free the node after use. * off is bit offset from the beginning of the aggregate * fsz is the number of bits this is referring to */ int ninval(CONSZ off, int fsz, NODE *p) { struct symtab *q; TWORD t; int i; t = p->n_type; if (t > BTMASK) p->n_type = t = INT; /* pointer */ #if 0 /* not needed anymore */ if (kflag && (p->n_op == PLUS || p->n_op == UMUL)) { char *c; if (p->n_op == UMUL) p = p->n_left; p = p->n_right; q = p->n_sp; #if defined(ELFABI) if (q->soname && (c = strstr(q->soname, "@got(31)")) != NULL) *c = 0; /* ignore GOT ref here */ #elif defined(MACHOABI) if ((c = strstr(q->soname, "$non_lazy_ptr")) != NULL) { q->soname++; /* skip "L" */ *c = 0; /* ignore GOT ref here */ } else if ((c = strstr(q->soname, "-L")) != NULL) *c = 0; /* ignore GOT ref here */ #endif } #endif if (p->n_op == ICON && p->n_sp != NULL && DEUNSIGN(t) != INT) uerror("element not constant"); switch (t) { case LONGLONG: case ULONGLONG: #if 0 /* little-endian */ i = (glval(p) >> 32); slval(p, glval(p) & 0xffffffff); p->n_type = INT; ninval(off, 32, p); slval(p, i); ninval(off+32, 32, p); #endif /* big-endian */ i = (glval(p) & 0xffffffff); slval(p, glval(p) >> 32); p->n_type = INT; ninval(off, 32, p); slval(p, i); ninval(off+32, 32, p); break; case INT: case UNSIGNED: printf("\t.long %d", (int)glval(p)); if ((q = p->n_sp) != NULL) { if ((q->sclass == STATIC && q->slevel > 0)) { printf("+" LABFMT, q->soffset); } else { char *name = getexname(q); printf("+%s", name); } } printf("\n"); break; default: return 0; } return 1; } /* make a name look like an external name in the local machine */ char * exname(char *p) { #if defined(ELFABI) return (p == NULL ? "" : p); #elif defined(MACHOABI) #define NCHNAM 256 static char text[NCHNAM+1]; int i; if (p == NULL) return ""; text[0] = '_'; for (i=1; *p && istype, sp->sdf, sp->sap); off = (off+(SZCHAR-1))/SZCHAR; printf("\t.%scomm ", sp->sclass == STATIC ? "l" : ""); n = getexname(sp); if (sp->slevel == 0) printf("%s,%d\n", n, off); else printf(LABFMT ",%d\n", sp->soffset, off); } #ifdef notdef /* make a common declaration for id, if reasonable */ void commdec(struct symtab *q) { int off; off = tsize(q->stype, q->sdf, q->ssue); off = (off+(SZCHAR-1))/SZCHAR; printf("\t.comm %s,0%o\n", getexname(q), off); } /* make a local common declaration for id, if reasonable */ void lcommdec(struct symtab *q) { int off; off = tsize(q->stype, q->sdf, q->ssue); off = (off+(SZCHAR-1))/SZCHAR; if (q->slevel == 0) printf("\t.lcomm %s,%d\n", getexname(q), off); else printf("\t.lcomm " LABFMT ",%d\n", q->soffset, off); } /* * print a (non-prog) label. */ void deflab1(int label) { printf(LABFMT ":\n", label); } #if defined(ELFABI) static char *loctbl[] = { "text", "data", "section .rodata,", "section .rodata" }; #elif defined(MACHOABI) static char *loctbl[] = { "text", "data", "section .rodata,", "cstring" }; #endif void setloc1(int locc) { #ifdef PCC_DEBUG if (xdebug) printf("setloc1: locc=%d, lastloc=%d\n", locc, lastloc); #endif if (locc == lastloc) return; lastloc = locc; printf(" .%s\n", loctbl[locc]); } #endif /* simulate and optimise the MOD opcode */ static void simmod(NODE *p) { NODE *r = p->n_right; assert(p->n_op == MOD); if (!ISUNSIGNED(p->n_type)) return; #define ISPOW2(n) ((n) && (((n)&((n)-1)) == 0)) /* if the right is a constant power of two, then replace with AND */ if (r->n_op == ICON && ISPOW2(glval(r))) { p->n_op = AND; slval(r, glval(r) - 1); return; } #undef ISPOW2 /* other optimizations can go here */ } static int constructor; static int destructor; /* * Give target the opportunity of handling pragmas. */ int mypragma(char *str) { if (strcmp(str, "tls") == 0) { uerror("thread-local storage not supported for this target"); return 1; } if (strcmp(str, "constructor") == 0 || strcmp(str, "init") == 0) { constructor = 1; return 1; } if (strcmp(str, "destructor") == 0 || strcmp(str, "fini") == 0) { destructor = 1; return 1; } return 0; } /* * Called when a identifier has been declared, to give target last word. */ void fixdef(struct symtab *sp) { /* may have sanity checks here */ if ((constructor || destructor) && (sp->sclass != PARAM)) { #ifdef MACHOABI if (kflag) { if (constructor) printf("\t.mod_init_func\n"); else printf("\t.mod_term_func\n"); } else { if (constructor) printf("\t.constructor\n"); else printf("\t.destructor\n"); } printf("\t.p2align 2\n"); printf("\t.long %s\n", exname(sp->sname)); printf("\t.text\n"); constructor = destructor = 0; #endif } } /* * There is very little different here to the standard builtins. * It basically handles promotion of types smaller than INT. */ NODE * powerpc_builtin_stdarg_start(const struct bitable *bi, NODE *a) { NODE *p, *q; int sz = 1; /* must first deal with argument size; use int size */ p = a->n_right; if (p->n_type < INT) { /* round up to word */ sz = SZINT / tsize(p->n_type, p->n_df, p->n_ap); } p = buildtree(ADDROF, p, NIL); /* address of last arg */ p = optim(buildtree(PLUS, p, bcon(sz))); q = block(NAME, NIL, NIL, PTR+VOID, 0, 0); q = buildtree(CAST, q, p); p = q->n_right; nfree(q->n_left); nfree(q); p = buildtree(ASSIGN, a->n_left, p); nfree(a); return p; } NODE * powerpc_builtin_va_arg(const struct bitable *bi, NODE *a) { NODE *p, *q, *r; int sz, tmpnr; r = a->n_right; /* get type size */ sz = tsize(r->n_type, r->n_df, r->n_ap) / SZCHAR; if (sz < SZINT/SZCHAR) { werror("%s%s promoted to int when passed through ...", ISUNSIGNED(r->n_type) ? "unsigned " : "", DEUNSIGN(r->n_type) == SHORT ? "short" : "char"); sz = SZINT/SZCHAR; r->n_type = INT; r->n_ap = 0; } p = p1tcopy(a->n_left); #if defined(ELFABI) /* alignment */ if (SZINT/SZCHAR && r->n_type != UNIONTY && r->n_type != STRTY) { p = buildtree(PLUS, p, bcon(ALSTACK/8 - 1)); p = block(AND, p, bcon(-ALSTACK/8), p->n_type, p->n_df, p->n_ap); } #endif /* create a copy to a temp node */ q = tempnode(0, p->n_type, p->n_df, p->n_ap); tmpnr = regno(q); p = buildtree(ASSIGN, q, p); q = tempnode(tmpnr, p->n_type, p->n_df, p->n_ap); q = buildtree(PLUS, q, bcon(sz)); q = buildtree(ASSIGN, a->n_left, q); q = buildtree(COMOP, p, q); nfree(a->n_right); nfree(a); p = tempnode(tmpnr, INCREF(r->n_type), r->n_df, r->n_ap); p = buildtree(UMUL, p, NIL); p = buildtree(COMOP, q, p); return p; } NODE * powerpc_builtin_va_end(const struct bitable *bi, NODE *a) { p1tfree(a); return bcon(0); } NODE * powerpc_builtin_va_copy(const struct bitable *bi, NODE *a) { P1ND *f = buildtree(ASSIGN, a->n_left, a->n_right); p1nfree(a); return f; } NODE * builtin_return_address(const struct bitable *bt, NODE *a) { P1ND *f; int nframes; int i = 0; nframes = glval(a); p1tfree(a); f = block(REG, NIL, NIL, PTR+VOID, 0, 0); regno(f) = SPREG; do { f = block(UMUL, f, NIL, PTR+VOID, 0, 0); } while (i++ < nframes); f = block(PLUS, f, bcon(8), INCREF(PTR+VOID), 0, 0); f = buildtree(UMUL, f, NIL); return f; } NODE * builtin_frame_address(const struct bitable *bt, NODE *a) { P1ND *f; int nframes; int i = 0; nframes = glval(a); p1tfree(a); if (nframes == 0) { f = block(REG, NIL, NIL, PTR+VOID, 0, 0); regno(f) = FPREG; } else { f = block(REG, NIL, NIL, PTR+VOID, 0, 0); regno(f) = SPREG; do { f = block(UMUL, f, NIL, PTR+VOID, 0, 0); } while (i++ < nframes); f = block(PLUS, f, bcon(24), INCREF(PTR+VOID), 0, 0); f = buildtree(UMUL, f, NIL); } return f; } /* * Return "canonical frame address". */ NODE * builtin_cfa(const struct bitable *bt, NODE *a) { cerror("builtin_cfa"); return bcon(0); } void pass1_lastchance(struct interpass *ip) { } pcc-20181216/arch/powerpc/local2.c010064400017500000000000001060061277225026600154140ustar raggewheel/* $Id: local2.c,v 1.30 2016/09/26 16:45:42 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "pass1.h" /* for cftnsp */ #include "pass2.h" #include #include #include #if defined(MACHOABI) #define EXPREFIX "_" #else #define EXPREFIX "" #endif #define LOWREG 0 #define HIREG 1 char *rnames[] = { REGPREFIX "r0", REGPREFIX "r1", REGPREFIX "r2", REGPREFIX "r3", REGPREFIX "r4", REGPREFIX "r5", REGPREFIX "r6", REGPREFIX "r7", REGPREFIX "r8", REGPREFIX "r9", REGPREFIX "r10", REGPREFIX "r11", REGPREFIX "r12", REGPREFIX "r13", REGPREFIX "r14", REGPREFIX "r15", REGPREFIX "r16", REGPREFIX "r17", REGPREFIX "r18", REGPREFIX "r19", REGPREFIX "r20", REGPREFIX "r21", REGPREFIX "r22", REGPREFIX "r23", REGPREFIX "r24", REGPREFIX "r25", REGPREFIX "r26", REGPREFIX "r27", REGPREFIX "r28", REGPREFIX "r29", REGPREFIX "r30", REGPREFIX "r31", "r4\0r3\0", "r5\0r4\0", "r6\0r5\0", "r7\0r6\0", "r8\0r7\0", "r9\0r8\0", "r10r9\0", "r15r14", "r17r16", "r19r18", "r21r20", "r23r22", "r25r24", "r27r26", "r29r28", "r31r30", REGPREFIX "f0", REGPREFIX "f1", REGPREFIX "f2", REGPREFIX "f3", REGPREFIX "f4", REGPREFIX "f5", REGPREFIX "f6", REGPREFIX "f7", REGPREFIX "f8", REGPREFIX "f9", REGPREFIX "f10", REGPREFIX "f11", REGPREFIX "f12", REGPREFIX "f13", REGPREFIX "f14", REGPREFIX "f15", REGPREFIX "f16", REGPREFIX "f17", REGPREFIX "f18", REGPREFIX "f19", REGPREFIX "f20", REGPREFIX "f21", REGPREFIX "f22", REGPREFIX "f23", REGPREFIX "f24", REGPREFIX "f25", REGPREFIX "f26", REGPREFIX "f27", REGPREFIX "f28", REGPREFIX "f29", REGPREFIX "f30", REGPREFIX "f31", }; static int argsize(NODE *p); static int p2calls; static int p2temps; /* TEMPs which aren't autos yet */ static int p2framesize; static int p2maxstacksize; void deflab(int label) { printf(LABFMT ":\n", label); } static TWORD ftype; /* * Print out the prolog assembler. */ void prologue(struct interpass_prolog *ipp) { int addto; #ifdef PCC_DEBUG if (x2debug) printf("prologue: type=%d, lineno=%d, name=%s, vis=%d, ipptype=%d, autos=%d, tmpnum=%d, lblnum=%d\n", ipp->ipp_ip.type, ipp->ipp_ip.lineno, ipp->ipp_name, ipp->ipp_vis, ipp->ipp_type, ipp->ipp_autos, ipp->ip_tmpnum, ipp->ip_lblnum); #endif ftype = ipp->ipp_type; addto = p2framesize; if (p2calls != 0 || kflag) { /* get return address (not required for leaf function) */ printf("\tmflr %s\n", rnames[R0]); printf("\tstw %s,8(%s)\n", rnames[R0], rnames[R1]); } /* save registers R30 and R31 */ printf("\tstmw %s,-8(%s)\n", rnames[R30], rnames[R1]); #ifdef FPREG printf("\tmr %s,%s\n", rnames[FPREG], rnames[R1]); #endif /* create the new stack frame */ if (addto > 32767) { printf("\tlis %s,%d\n", rnames[R0], (-addto) >> 16); printf("\tori %s,%s,%d\n", rnames[R0], rnames[R0], (-addto) & 0xffff); printf("\tstwux %s,%s,%s\n", rnames[R1], rnames[R1], rnames[R0]); } else { printf("\tstwu %s,-%d(%s)\n", rnames[R1], addto, rnames[R1]); } if (kflag) { #if defined(ELFABI) printf("\tbl _GLOBAL_OFFSET_TABLE_@local-4\n"); printf("\tmflr %s\n", rnames[GOTREG]); #elif defined(MACHOABI) printf("\tbcl 20,31,L%s$pb\n", ipp->ipp_name + 1); printf("L%s$pb:\n", ipp->ipp_name + 1); printf("\tmflr %s\n", rnames[GOTREG]); #endif } } void eoftn(struct interpass_prolog *ipp) { #ifdef PCC_DEBUG if (x2debug) printf("eoftn:\n"); #endif if (ipp->ipp_ip.ip_lbl == 0) return; /* no code needs to be generated */ /* struct return needs special treatment */ if (ftype == STRTY || ftype == UNIONTY) cerror("eoftn"); /* unwind stack frame */ printf("\tlwz %s,0(%s)\n", rnames[R1], rnames[R1]); if (p2calls != 0 || kflag) { printf("\tlwz %s,8(%s)\n", rnames[R0], rnames[R1]); printf("\tmtlr %s\n", rnames[R0]); } printf("\tlmw %s,-8(%s)\n", rnames[R30], rnames[R1]); printf("\tblr\n"); } /* * add/sub/... * * Param given: */ void hopcode(int f, int o) { char *str; switch (o) { case PLUS: str = "addw"; break; case MINUS: str = "subw"; break; case AND: str = "and"; break; case OR: str = "or"; break; case ER: str = "xor"; break; default: comperr("hopcode2: %d", o); str = 0; /* XXX gcc */ } printf("%s%c", str, f); } /* * Return type size in bytes. Used by R2REGS, arg 2 to offset(). */ int tlen(NODE *p) { switch(p->n_type) { case CHAR: case UCHAR: return(1); case SHORT: case USHORT: return(SZSHORT/SZCHAR); case DOUBLE: return(SZDOUBLE/SZCHAR); case INT: case UNSIGNED: case LONG: case ULONG: return(SZINT/SZCHAR); case LONGLONG: case ULONGLONG: return SZLONGLONG/SZCHAR; default: if (!ISPTR(p->n_type)) comperr("tlen type %d not pointer"); return SZPOINT(p->n_type)/SZCHAR; } } /* * Emit code to compare two longlong numbers. */ static void twollcomp(NODE *p) { int o = p->n_op; int s = getlab2(); int e = p->n_label; int cb1, cb2; if (o >= ULE) o -= (ULE-LE); switch (o) { case NE: cb1 = 0; cb2 = NE; break; case EQ: cb1 = NE; cb2 = 0; break; case LE: case LT: cb1 = GT; cb2 = LT; break; case GE: case GT: cb1 = LT; cb2 = GT; break; default: cb1 = cb2 = 0; /* XXX gcc */ } if (p->n_op >= ULE) cb1 += 4, cb2 += 4; if (p->n_op >= ULE) expand(p, 0, "\tcmplw UL,UR" COM "compare 64-bit values (upper)\n"); else expand(p, 0, "\tcmpw UL,UR" COM "compare 64-bit values (upper)\n"); if (cb1) cbgen(cb1, s); if (cb2) cbgen(cb2, e); if (p->n_op >= ULE) expand(p, 0, "\tcmplw AL,AR" COM "(and lower)\n"); else expand(p, 0, "\tcmpw AL,AR" COM "(and lower)\n"); cbgen(p->n_op, e); deflab(s); } static void shiftop(NODE *p) { NODE *r = p->n_right; TWORD ty = p->n_type; if (p->n_op == LS && r->n_op == ICON && getlval(r) < 32) { expand(p, INBREG, "\tsrwi A1,AL,32-AR" COM "64-bit left-shift\n"); expand(p, INBREG, "\tslwi U1,UL,AR\n"); expand(p, INBREG, "\tor U1,U1,A1\n"); expand(p, INBREG, "\tslwi A1,AL,AR\n"); } else if (p->n_op == LS && r->n_op == ICON && getlval(r) < 64) { expand(p, INBREG, "\tli A1,0" COM "64-bit left-shift\n"); if (getlval(r) == 32) expand(p, INBREG, "\tmr U1,AL\n"); else expand(p, INBREG, "\tslwi U1,AL,AR-32\n"); } else if (p->n_op == LS && r->n_op == ICON) { expand(p, INBREG, "\tli A1,0" COM "64-bit left-shift\n"); expand(p, INBREG, "\tli U1,0\n"); } else if (p->n_op == RS && r->n_op == ICON && getlval(r) < 32) { expand(p, INBREG, "\tslwi U1,UL,32-AR" COM "64-bit right-shift\n"); expand(p, INBREG, "\tsrwi A1,AL,AR\n"); expand(p, INBREG, "\tor A1,A1,U1\n"); if (ty == LONGLONG) expand(p, INBREG, "\tsrawi U1,UL,AR\n"); else expand(p, INBREG, "\tsrwi U1,UL,AR\n"); } else if (p->n_op == RS && r->n_op == ICON && getlval(r) < 64) { if (ty == LONGLONG) expand(p, INBREG, "\tli U1,-1" COM "64-bit right-shift\n"); else expand(p, INBREG, "\tli U1,0" COM "64-bit right-shift\n"); if (getlval(r) == 32) expand(p, INBREG, "\tmr A1,UL\n"); else if (ty == LONGLONG) expand(p, INBREG, "\tsrawi A1,UL,AR-32\n"); else expand(p, INBREG, "\tsrwi A1,UL,AR-32\n"); } else if (p->n_op == RS && r->n_op == ICON) { expand(p, INBREG, "\tli A1,0" COM "64-bit right-shift\n"); expand(p, INBREG, "\tli U1,0\n"); } } /* * Structure assignment. */ static void stasg(NODE *p) { NODE *l = p->n_left; int val = getlval(l); /* R3 = dest, R4 = src, R5 = len */ printf("\tli %s,%d\n", rnames[R5], attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)); if (l->n_op == OREG) { printf("\taddi %s,%s,%d\n", rnames[R3], rnames[regno(l)], val); } else if (l->n_op == NAME) { #if defined(ELFABI) printf("\tli %s,", rnames[R3]); adrput(stdout, l); printf("@ha\n"); printf("\taddi %s,%s,", rnames[R3], rnames[R3]); adrput(stdout, l); printf("@l\n"); #elif defined(MACHOABI) printf("\tli %s,ha16(", rnames[R3]); adrput(stdout, l); printf(")\n"); printf("\taddi %s,%s,lo16(", rnames[R3], rnames[R3]); adrput(stdout, l); printf(")\n"); #endif } if (kflag) { #if defined(ELFABI) printf("\tbl %s@got(30)\n", EXPREFIX "memcpy"); #elif defined(MACHOABI) printf("\tbl L%s$stub\n", EXPREFIX "memcpy"); addstub(&stublist, EXPREFIX "memcpy"); #endif } else { printf("\tbl %s\n", EXPREFIX "memcpy"); } } static void fpemul(NODE *p) { NODE *l = p->n_left; char *ch = NULL; if (p->n_op == PLUS && p->n_type == FLOAT) ch = "addsf3"; else if (p->n_op == PLUS && p->n_type == DOUBLE) ch = "adddf3"; else if (p->n_op == PLUS && p->n_type == LDOUBLE) ch = "addtf3"; else if (p->n_op == MINUS && p->n_type == FLOAT) ch = "subsf3"; else if (p->n_op == MINUS && p->n_type == DOUBLE) ch = "subdf3"; else if (p->n_op == MINUS && p->n_type == LDOUBLE) ch = "subtf3"; else if (p->n_op == MUL && p->n_type == FLOAT) ch = "mulsf3"; else if (p->n_op == MUL && p->n_type == DOUBLE) ch = "muldf3"; else if (p->n_op == MUL && p->n_type == LDOUBLE) ch = "multf3"; else if (p->n_op == DIV && p->n_type == FLOAT) ch = "divsf3"; else if (p->n_op == DIV && p->n_type == DOUBLE) ch = "divdf3"; else if (p->n_op == DIV && p->n_type == LDOUBLE) ch = "divtf3"; else if (p->n_op == UMINUS && p->n_type == FLOAT) ch = "negsf2"; else if (p->n_op == UMINUS && p->n_type == DOUBLE) ch = "negdf2"; else if (p->n_op == UMINUS && p->n_type == LDOUBLE) ch = "negtf2"; else if (p->n_op == EQ && l->n_type == FLOAT) ch = "eqsf2"; else if (p->n_op == EQ && l->n_type == DOUBLE) ch = "eqdf2"; else if (p->n_op == EQ && l->n_type == LDOUBLE) ch = "eqtf2"; else if (p->n_op == NE && l->n_type == FLOAT) ch = "nesf2"; else if (p->n_op == NE && l->n_type == DOUBLE) ch = "nedf2"; else if (p->n_op == NE && l->n_type == LDOUBLE) ch = "netf2"; else if (p->n_op == GE && l->n_type == FLOAT) ch = "gesf2"; else if (p->n_op == GE && l->n_type == DOUBLE) ch = "gedf2"; else if (p->n_op == GE && l->n_type == LDOUBLE) ch = "getf2"; else if (p->n_op == LE && l->n_type == FLOAT) ch = "lesf2"; else if (p->n_op == LE && l->n_type == DOUBLE) ch = "ledf2"; else if (p->n_op == LE && l->n_type == LDOUBLE) ch = "letf2"; else if (p->n_op == GT && l->n_type == FLOAT) ch = "gtsf2"; else if (p->n_op == GT && l->n_type == DOUBLE) ch = "gtdf2"; else if (p->n_op == GT && l->n_type == LDOUBLE) ch = "gttf2"; else if (p->n_op == LT && l->n_type == FLOAT) ch = "ltsf2"; else if (p->n_op == LT && l->n_type == DOUBLE) ch = "ltdf2"; else if (p->n_op == LT && l->n_type == LDOUBLE) ch = "lttf2"; else if (p->n_op == SCONV && p->n_type == FLOAT) { if (l->n_type == DOUBLE) ch = "truncdfsf2"; else if (l->n_type == LDOUBLE) ch = "truncdfsf2"; else if (l->n_type == ULONGLONG) ch = "floatunsdisf"; else if (l->n_type == LONGLONG) ch = "floatdisf"; else if (l->n_type == LONG) ch = "floatsisf"; else if (l->n_type == ULONG) ch = "floatunsisf"; else if (l->n_type == INT) ch = "floatsisf"; else if (l->n_type == UNSIGNED) ch = "floatunsisf"; } else if (p->n_op == SCONV && p->n_type == DOUBLE) { if (l->n_type == FLOAT) ch = "extendsfdf2"; else if (l->n_type == LDOUBLE) ch = "truncdfdf2"; else if (l->n_type == ULONGLONG) ch = "floatunsdidf"; else if (l->n_type == LONGLONG) ch = "floatdidf"; else if (l->n_type == LONG) ch = "floatsidf"; else if (l->n_type == ULONG) ch = "floatunssidf"; else if (l->n_type == INT) ch = "floatsidf"; else if (l->n_type == UNSIGNED) ch = "floatunssidf"; } else if (p->n_op == SCONV && p->n_type == LDOUBLE) { if (l->n_type == FLOAT) ch = "extendsfdf2"; else if (l->n_type == DOUBLE) ch = "extenddfdf2"; else if (l->n_type == ULONGLONG) ch = "floatunsdidf"; else if (l->n_type == LONGLONG) ch = "floatdidf"; else if (l->n_type == LONG) ch = "floatsidf"; else if (l->n_type == ULONG) ch = "floatunssidf"; else if (l->n_type == INT) ch = "floatsidf"; else if (l->n_type == UNSIGNED) ch = "floatunsidf"; } else if (p->n_op == SCONV && p->n_type == ULONGLONG) { if (l->n_type == FLOAT) ch = "fixunssfdi"; else if (l->n_type == DOUBLE) ch = "fixunsdfdi"; else if (l->n_type == LDOUBLE) ch = "fixunsdfdi"; } else if (p->n_op == SCONV && p->n_type == LONGLONG) { if (l->n_type == FLOAT) ch = "fixsfdi"; else if (l->n_type == DOUBLE) ch = "fixdfdi"; else if (l->n_type == LDOUBLE) ch = "fixdfdi"; } else if (p->n_op == SCONV && p->n_type == LONG) { if (l->n_type == FLOAT) ch = "fixsfdi"; else if (l->n_type == DOUBLE) ch = "fixdfdi"; else if (l->n_type == LDOUBLE) ch = "fixdfdi"; } else if (p->n_op == SCONV && p->n_type == ULONG) { if (l->n_type == FLOAT) ch = "fixunssfdi"; else if (l->n_type == DOUBLE) ch = "fixunsdfdi"; else if (l->n_type == LDOUBLE) ch = "fixunsdfdi"; } else if (p->n_op == SCONV && p->n_type == INT) { if (l->n_type == FLOAT) ch = "fixsfsi"; else if (l->n_type == DOUBLE) ch = "fixdfsi"; else if (l->n_type == LDOUBLE) ch = "fixdfsi"; } else if (p->n_op == SCONV && p->n_type == UNSIGNED) { if (l->n_type == FLOAT) ch = "fixunssfsi"; else if (l->n_type == DOUBLE) ch = "fixunsdfsi"; else if (l->n_type == LDOUBLE) ch = "fixunsdfsi"; } if (ch == NULL) comperr("ZF: op=0x%x (%d)\n", p->n_op, p->n_op); if (kflag) { #if defined(ELFABI) printf("\tbl __%s%s@got(30)" COM "soft-float\n", EXPREFIX, ch); #elif defined(MACHOABI) char buf[32]; printf("\tbl L__%s%s$stub" COM "soft-float\n", EXPREFIX, ch); snprintf(buf, 32, "__%s%s", EXPREFIX, ch); addstub(&stublist, buf); #endif } else { printf("\tbl __%s%s" COM "soft-float\n", EXPREFIX, ch); } if (p->n_op >= EQ && p->n_op <= GT) printf("\tcmpwi %s,0\n", rnames[R3]); } /* * http://gcc.gnu.org/onlinedocs/gccint/Integer-library-routines.html#Integer-library-routines */ static void emul(NODE *p) { char *ch = NULL; if (p->n_op == LS && DEUNSIGN(p->n_type) == LONGLONG) ch = "ashldi3"; else if (p->n_op == LS && (DEUNSIGN(p->n_type) == LONG || DEUNSIGN(p->n_type) == INT)) ch = "ashlsi3"; else if (p->n_op == RS && p->n_type == ULONGLONG) ch = "lshrdi3"; else if (p->n_op == RS && (p->n_type == ULONG || p->n_type == INT)) ch = "lshrsi3"; else if (p->n_op == RS && p->n_type == LONGLONG) ch = "ashrdi3"; else if (p->n_op == RS && (p->n_type == LONG || p->n_type == INT)) ch = "ashrsi3"; else if (p->n_op == DIV && p->n_type == LONGLONG) ch = "divdi3"; else if (p->n_op == DIV && (p->n_type == LONG || p->n_type == INT)) ch = "divsi3"; else if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udivdi3"; else if (p->n_op == DIV && (p->n_type == ULONG || p->n_type == UNSIGNED)) ch = "udivsi3"; else if (p->n_op == MOD && p->n_type == LONGLONG) ch = "moddi3"; else if (p->n_op == MOD && (p->n_type == LONG || p->n_type == INT)) ch = "modsi3"; else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umoddi3"; else if (p->n_op == MOD && (p->n_type == ULONG || p->n_type == UNSIGNED)) ch = "umodsi3"; else if (p->n_op == MUL && p->n_type == LONGLONG) ch = "muldi3"; else if (p->n_op == MUL && (p->n_type == LONG || p->n_type == INT)) ch = "mulsi3"; else if (p->n_op == UMINUS && p->n_type == LONGLONG) ch = "negdi2"; else if (p->n_op == UMINUS && p->n_type == LONG) ch = "negsi2"; else ch = 0, comperr("ZE"); if (kflag) { #if defined(ELFABI) printf("\tbl __%s%s@got(30)" COM "emulated op\n", EXPREFIX, ch); #elif defined(MACHOABI) char buf[32]; printf("\tbl L__%s%s$stub" COM "emulated op\n", EXPREFIX, ch); snprintf(buf, 32, "__%s%s", EXPREFIX, ch); addstub(&stublist, buf); #endif } else { printf("\tbl __%s%s" COM "emulated operation\n", EXPREFIX, ch); } } /* * Floating-point conversions (int -> float/double & float/double -> int) */ static void ftoi(NODE *p) { NODE *l = p->n_left; printf(COM "start conversion float/(l)double to int\n"); if (l->n_op != OREG) { expand(p, 0, "\tstw AL,-4"); printf("(%s)\n", rnames[SPREG]); if (l->n_type == FLOAT) expand(p, 0, "\tlfs A2,"); else expand(p, 0, "\tlfd A2,\n"); printf("-4(%s)\n", rnames[SPREG]); } else { if (l->n_type == FLOAT) expand(p, 0, "\tlfs A2,AL\n"); else expand(p, 0, "\tlfd A2,AL\n"); } expand(p, 0, "\tfctiwz A2,A2\n"); expand(p, 0, "\tstfd A2,"); printf("-8(%s)\n", rnames[SPREG]); expand(p, 0, "\tlwz A1,"); printf("-4(%s)\n", rnames[SPREG]); printf(COM "end conversion\n"); } static void ftou(NODE *p) { static int lab = 0; NODE *l = p->n_left; int lab1 = getlab2(); int lab2 = getlab2(); printf(COM "start conversion of float/(l)double to unsigned\n"); if (lab == 0) { lab = getlab2(); expand(p, 0, "\t.data\n"); printf(LABFMT ":\t.long 0x41e00000\n\t.long 0\n", lab); expand(p, 0, "\t.text\n"); } if (l->n_op != OREG) { expand(p, 0, "\tstw AL,"); printf("-4(%s)\n", rnames[SPREG]); if (l->n_type == FLOAT) expand(p, 0, "\tlfs A3,"); else expand(p, 0, "\tlfd A3,"); printf("-4(%s)\n", rnames[SPREG]); } else { if (l->n_type == FLOAT) expand(p, 0, "\tlfs A3,AL\n"); else expand(p, 0, "\tlfd A3,AL\n"); } #if 0 if (kflag) { expand(p, 0, "\taddis A1,"); printf("%s,ha16(", rnames[R31]); printf(LABFMT, lab); printf("-L%s$pb)\n", cftnsp->soname ? cftnsp->soname : exname(cftnsp->sname)); expand(p, 0, "\tlfd A2,lo16("); printf(LABFMT, lab); printf("-L%s$pb)\n", cftnsp->soname ? cftnsp->soname : exname(cftnsp->sname)); expand(p, 0, "(A1)\n"); } else { expand(p, 0, "\tlfd A2,"); printf(LABFMT "\n", lab); } #endif #if defined(ELFABI) expand(p, 0, "\taddis A1,"); printf("%s," LABFMT "@ha\n", rnames[R31], lab); expand(p, 0, "\tlfd A2,"); printf(LABFMT "@l", lab); expand(p, 0, "(A1)\n"); #elif defined(MACHOABI) expand(p, 0, "\taddis A1,"); printf("%s,ha16(", rnames[R31]); printf(LABFMT, lab); if (kflag) printf("-L%s$pb", cftnsp->soname ? cftnsp->soname : exname(cftnsp->sname)); printf(")\n"); expand(p, 0, "\tlfd A2,lo16("); printf(LABFMT, lab); if (kflag) printf("-L%s$pb", cftnsp->soname ? cftnsp->soname : exname(cftnsp->sname)); expand(p, 0, ")(A1)\n"); #endif expand(p, 0, "\tfcmpu cr7,A3,A2\n"); printf("\tcror 30,29,30\n"); printf("\tbeq cr7,"LABFMT "\n", lab1); expand(p, 0, "\tfctiwz A2,A3\n"); expand(p, 0, "\tstfd A2,"); printf("-8(%s)\n", rnames[SPREG]); expand(p, 0, "\tlwz A1,"); printf("-4(%s)\n", rnames[SPREG]); printf("\tba " LABFMT "\n", lab2); deflab(lab1); expand(p, 0, "\tfsub A2,A3,A2\n"); expand(p, 0, "\tfctiwz A2,A2\n"); expand(p, 0, "\tstfd A2,"); printf("-8(%s)\n", rnames[SPREG]); expand(p, 0, "\tlwz A1,"); printf("-4(%s)\n", rnames[SPREG]); expand(p, 0, "\txoris A1,A1,0x8000\n"); deflab(lab2); printf(COM "end conversion\n"); } static void itof(NODE *p) { static int labu = 0; static int labi = 0; int lab; NODE *l = p->n_left; printf(COM "start conversion (u)int to float/(l)double\n"); if (labi == 0 && l->n_type == INT) { labi = getlab2(); expand(p, 0, "\t.data\n"); printf(LABFMT ":\t.long 0x43300000\n\t.long 0x80000000\n", labi); expand(p, 0, "\t.text\n"); } else if (labu == 0 && l->n_type == UNSIGNED) { labu = getlab2(); expand(p, 0, "\t.data\n"); printf(LABFMT ":\t.long 0x43300000\n\t.long 0x00000000\n", labu); expand(p, 0, "\t.text\n"); } if (l->n_type == INT) { expand(p, 0, "\txoris A1,AL,0x8000\n"); lab = labi; } else { lab = labu; } expand(p, 0, "\tstw A1,"); printf("-4(%s)\n", rnames[SPREG]); expand(p, 0, "\tlis A1,0x4330\n"); expand(p, 0, "\tstw A1,"); printf("-8(%s)\n", rnames[SPREG]); expand(p, 0, "\tlfd A3,"); printf("-8(%s)\n", rnames[SPREG]); #if 0 if (kflag) { expand(p, 0, "\taddis A1,"); printf("%s,ha16(", rnames[R31]); printf(LABFMT, lab); printf("-L%s$pb)\n", cftnsp->soname ? cftnsp->soname : exname(cftnsp->sname)); expand(p, 0, "\tlfd A2,lo16("); printf(LABFMT, lab); printf("-L%s$pb)\n", cftnsp->soname ? cftnsp->soname : exname(cftnsp->sname)); expand(p, 0, "(A1)\n"); } else { expand(p, 0, "\tlfd A2,"); printf(LABFMT "\n", lab); } #endif #if defined(ELFABI) expand(p, 0, "\taddis A1,"); printf("%s," LABFMT "@ha\n", rnames[R31], lab); expand(p, 0, "\tlfd A2,"); printf(LABFMT "@l", lab); expand(p, 0, "(A1)\n"); #elif defined(MACHOABI) expand(p, 0, "\taddis A1,"); printf("%s,ha16(", rnames[R31]); printf(LABFMT, lab); if (kflag) printf("-L%s$pb", cftnsp->soname ? cftnsp->soname : exname(cftnsp->sname)); printf(")\n"); expand(p, 0, "\tlfd A2,lo16("); printf(LABFMT, lab); if (kflag) printf("-L%s$pb", cftnsp->soname ? cftnsp->soname : exname(cftnsp->sname)); expand(p, 0, ")(A1)\n"); #endif expand(p, 0, "\tfsub A3,A3,A2\n"); if (p->n_type == FLOAT) expand(p, 0, "\tfrsp A3,A3\n"); printf(COM "end conversion\n"); } static void fpconv(NODE *p) { NODE *l = p->n_left; #ifdef PCC_DEBUG if (p->n_op != SCONV) cerror("fpconv 1"); #endif if (DEUNSIGN(l->n_type) == INT) itof(p); else if (p->n_type == INT) ftoi(p); else if (p->n_type == UNSIGNED) ftou(p); else cerror("unhandled floating-point conversion"); } void zzzcode(NODE *p, int c) { switch (c) { case 'C': /* floating-point conversions */ fpconv(p); break; case 'D': /* long long comparision */ twollcomp(p); break; case 'E': /* print out emulated ops */ emul(p); break; case 'F': /* print out emulate floating-point ops */ fpemul(p); break; case 'O': /* 64-bit left and right shift operators */ shiftop(p); break; case 'Q': /* emit struct assign */ stasg(p); break; default: comperr("zzzcode %c", c); } } /*ARGSUSED*/ int rewfld(NODE *p) { return(1); } int canaddr(NODE *); int canaddr(NODE *p) { int o = p->n_op; if (o == NAME || o == REG || o == ICON || o == OREG || (o == UMUL && shumul(p->n_left, SOREG))) return(1); return 0; } int fldexpand(NODE *p, int cookie, char **cp) { CONSZ val; int shft; if (p->n_op == ASSIGN) p = p->n_left; if (features(FEATURE_BIGENDIAN)) shft = SZINT - UPKFSZ(p->n_rval) - UPKFOFF(p->n_rval); else shft = UPKFOFF(p->n_rval); switch (**cp) { case 'S': printf("%d", UPKFSZ(p->n_rval)); break; case 'H': printf("%d", shft); break; case 'M': case 'N': val = (CONSZ)1 << UPKFSZ(p->n_rval); --val; val <<= shft; printf(CONFMT, (**cp == 'M' ? val : ~val) & 0xffffffff); break; default: comperr("fldexpand"); } return 1; } /* * Does the bitfield shape match? */ int flshape(NODE *p) { int o = p->n_op; if (o == OREG || o == REG || o == NAME) return SRDIR; /* Direct match */ if (o == UMUL && shumul(p->n_left, SOREG)) return SROREG; /* Convert into oreg */ return SRREG; /* put it into a register */ } /* INTEMP shapes must not contain any temporary registers */ /* XXX should this go away now? */ int shtemp(NODE *p) { printf("; shtemp\n"); return 0; #if 0 int r; if (p->n_op == STARG ) p = p->n_left; switch (p->n_op) { case REG: return (!istreg(regno(p))); case OREG: r = regno(p); if (R2TEST(r)) { if (istreg(R2UPK1(r))) return(0); r = R2UPK2(r); } return (!istreg(r)); case UMUL: p = p->n_left; return (p->n_op != UMUL && shtemp(p)); } if (optype(p->n_op) != LTYPE) return(0); return(1); #endif } void adrcon(CONSZ val) { printf( CONFMT, val); } void conput(FILE *fp, NODE *p) { int val = getlval(p); switch (p->n_op) { case ICON: if (p->n_name[0] != '\0') { fprintf(fp, "%s", p->n_name); if (val) fprintf(fp, "+%d", val); } else { if (GCLASS(p->n_type) == CLASSB) fprintf(fp, CONFMT, getlval(p) >> 32); else fprintf(fp, "%d", val); } return; default: comperr("illegal conput, p %p", p); } } /*ARGSUSED*/ void insput(NODE *p) { comperr("insput"); } /* * Print lower or upper name of 64-bit register. */ static void reg64name(int reg, int hi) { int idx; int off = 0; idx = (reg > R14R15 ? (2*(reg - R14R15) + R14) : (reg - R3R4 + R3)); if ((hi == HIREG && !features(FEATURE_BIGENDIAN)) || (hi == LOWREG && features(FEATURE_BIGENDIAN))) off = 1; printf("%s" , rnames[idx + off]); } /* * Write out the upper address, like the upper register of a 2-register * reference, or the next memory location. */ void upput(NODE *p, int size) { size /= SZCHAR; switch (p->n_op) { case REG: reg64name(regno(p), HIREG); break; case NAME: case OREG: if (features(FEATURE_BIGENDIAN)) printf("%d", (int)getlval(p)); else printf("%d", (int)(getlval(p) + 4)); printf("(%s)", rnames[regno(p)]); break; case ICON: printf(CONFMT, getlval(p) >> 32); break; default: comperr("upput bad op %d size %d", p->n_op, size); } } void adrput(FILE *io, NODE *p) { /* output an address, with offsets, from p */ if (p->n_op == FLD) p = p->n_left; switch (p->n_op) { case NAME: if (p->n_name[0] != '\0') { fputs(p->n_name, io); if (getlval(p) != 0) fprintf(io, "+" CONFMT, getlval(p)); } else fprintf(io, CONFMT, getlval(p)); return; case OREG: if (DEUNSIGN(p->n_type) == LONGLONG && features(FEATURE_BIGENDIAN)) fprintf(io, "%d", (int)getlval(p) + 4); else fprintf(io, "%d", (int)getlval(p)); fprintf(io, "(%s)", rnames[regno(p)]); return; case ICON: /* addressable value of the constant */ conput(io, p); return; case REG: if (GCLASS(regno(p)) == CLASSB) reg64name(regno(p), LOWREG); else fprintf(io, "%s", rnames[regno(p)]); #if 0 switch (p->n_type) { case DOUBLE: case LDOUBLE: if (features(FEATURE_HARDFLOAT)) { fprintf(io, "%s", rnames[regno(p)]); break; } /* FALL-THROUGH */ case LONGLONG: case ULONGLONG: reg64name(regno(p), LOWREG); break; default: fprintf(io, "%s", rnames[regno(p)]); } #endif return; default: comperr("illegal address, op %d, node %p", p->n_op, p); return; } } /* * these mnemonics match the order of the preprocessor decls * EQ, NE, LE, LT, GE, GT, ULE, ULT, UGE, UGT */ static char * ccbranches[] = { "beq", /* branch if equal */ "bne", /* branch if not-equal */ "ble", /* branch if less-than-or-equal */ "blt", /* branch if less-than */ "bge", /* branch if greater-than-or-equal */ "bgt", /* branch if greater-than */ /* what should these be ? */ "ble", /* branch if less-than-or-equal */ "blt", /* branch if less-than */ "bge", /* branch if greater-than-or-equal */ "bgt", /* branch if greater-than */ }; /* printf conditional and unconditional branches */ void cbgen(int o, int lab) { if (o < EQ || o > UGT) comperr("bad conditional branch: %s", opst[o]); printf("\t%s " LABFMT "\n", ccbranches[o-EQ], lab); } static int argsize(NODE *p) { TWORD t = p->n_type; if (t < LONGLONG || t == FLOAT || t > BTMASK) return 4; if (t == LONGLONG || t == ULONGLONG) return 8; if (t == DOUBLE || t == LDOUBLE) return 8; if (t == STRTY || t == UNIONTY) return attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0); comperr("argsize"); return 0; } static int calc_args_size(NODE *p) { int n = 0; if (p->n_op == CM) { n += calc_args_size(p->n_left); n += calc_args_size(p->n_right); return n; } n += argsize(p); return n; } static void fixcalls(NODE *p, void *arg) { int n = 0; switch (p->n_op) { case STCALL: case CALL: n = calc_args_size(p->n_right); if (n > p2maxstacksize) p2maxstacksize = n; /* FALLTHROUGH */ case USTCALL: case UCALL: ++p2calls; break; case TEMP: p2temps += argsize(p); break; } } /* * Must store floats in memory if there are two function calls involved. */ static int storefloat(struct interpass *ip, NODE *p) { int l, r; switch (optype(p->n_op)) { case BITYPE: l = storefloat(ip, p->n_left); r = storefloat(ip, p->n_right); if (p->n_op == CM) return 0; /* arguments, don't care */ if (callop(p->n_op)) return 1; /* found one */ #define ISF(p) ((p)->n_type == FLOAT || (p)->n_type == DOUBLE || \ (p)->n_type == LDOUBLE) if (ISF(p->n_left) && ISF(p->n_right) && l && r) { /* must store one. store left */ struct interpass *nip; TWORD t = p->n_left->n_type; NODE *ll; int off; off = (freetemp(szty(t))); ll = mklnode(OREG, off, SPREG, t); nip = ipnode(mkbinode(ASSIGN, ll, p->n_left, t)); p->n_left = mklnode(OREG, off, SPREG, t); DLIST_INSERT_BEFORE(ip, nip, qelem); } return l|r; case UTYPE: l = storefloat(ip, p->n_left); if (callop(p->n_op)) l = 1; return l; default: return 0; } } void myreader(struct interpass *ipole) { struct interpass *ip; p2calls = 0; p2temps = 0; p2maxstacksize = 0; DLIST_FOREACH(ip, ipole, qelem) { if (ip->type != IP_NODE) continue; walkf(ip->ip_node, fixcalls, 0); storefloat(ip, ip->ip_node); } if (p2maxstacksize < NARGREGS*SZINT/SZCHAR) p2maxstacksize = NARGREGS*SZINT/SZCHAR; p2framesize = ARGINIT/SZCHAR; /* stack ptr / return addr */ p2framesize += 8; /* for R31 and R30 */ p2framesize += p2maxautooff; /* autos */ p2framesize += p2temps; /* TEMPs that aren't autos */ if (p2calls != 0) p2framesize += p2maxstacksize; /* arguments to functions */ p2framesize += (ALSTACK/SZCHAR - 1); /* round to 16-byte boundary */ p2framesize &= ~(ALSTACK/SZCHAR - 1); #if 0 printf("!!! MYREADER\n"); printf("!!! p2maxautooff = %d\n", p2maxautooff); printf("!!! p2autooff = %d\n", p2autooff); printf("!!! p2temps = %d\n", p2temps); printf("!!! p2calls = %d\n", p2calls); printf("!!! p2maxstacksize = %d\n", p2maxstacksize); #endif if (x2debug) printip(ipole); } /* * Remove some PCONVs after OREGs are created. */ static void pconv2(NODE *p, void *arg) { NODE *q; if (p->n_op == PLUS) { if (p->n_type == (PTR|SHORT) || p->n_type == (PTR|USHORT)) { if (p->n_right->n_op != ICON) return; if (p->n_left->n_op != PCONV) return; if (p->n_left->n_left->n_op != OREG) return; q = p->n_left->n_left; nfree(p->n_left); p->n_left = q; /* * This will be converted to another OREG later. */ } } } void mycanon(NODE *p) { walkf(p, pconv2, 0); } void myoptim(struct interpass *ip) { #ifdef PCC_DEBUG if (x2debug) { printf("myoptim\n"); } #endif } /* * Move data between registers. While basic registers aren't a problem, * we have to handle the special case of overlapping composite registers. * It might just be easier to modify the register allocator so that * moves between overlapping registers isn't possible. */ void rmove(int s, int d, TWORD t) { switch (t) { case LDOUBLE: case DOUBLE: if (features(FEATURE_HARDFLOAT)) { printf("\tfmr %s,%s" COM "rmove\n", rnames[d], rnames[s]); break; } /* FALL-THROUGH */ case LONGLONG: case ULONGLONG: if (s == d+1) { /* dh = sl, copy low word first */ printf("\tmr "); reg64name(d, LOWREG); printf(","); reg64name(s, LOWREG); printf("\n"); printf("\tmr "); reg64name(d, HIREG); printf(","); reg64name(s, HIREG); printf("\n"); } else { /* copy high word first */ printf("\tmr "); reg64name(d, HIREG); printf(","); reg64name(s, HIREG); printf("\n"); printf("\tmr "); reg64name(d, LOWREG); printf(","); reg64name(s, LOWREG); printf("\n"); } break; case FLOAT: if (features(FEATURE_HARDFLOAT)) { printf("\tfmr %s,%s" COM "rmove\n", rnames[d], rnames[s]); break; } /* FALL-THROUGH */ default: printf("\tmr %s,%s" COM "rmove\n", rnames[d], rnames[s]); } } /* * For class c, find worst-case displacement of the number of * registers in the array r[] indexed by class. * * On PowerPC, we have: * * 32 32-bit registers (2 reserved) * 16 64-bit pseudo registers * 32 floating-point registers */ int COLORMAP(int c, int *r) { int num = 0; switch (c) { case CLASSA: num += r[CLASSA]; num += 2*r[CLASSB]; return num < 30; case CLASSB: num += 2*r[CLASSB]; num += r[CLASSA]; return num < 16; case CLASSC: return num < 32; case CLASSD: return r[CLASSD] < DREGCNT; } return 0; /* XXX gcc */ } /* * Return a class suitable for a specific type. */ int gclass(TWORD t) { if (t == LONGLONG || t == ULONGLONG) return CLASSB; if (t == FLOAT || t == DOUBLE || t == LDOUBLE) { if (features(FEATURE_HARDFLOAT)) return CLASSC; if (t == FLOAT) return CLASSA; else return CLASSB; } return CLASSA; } int retreg(int t) { int c = gclass(t); if (c == CLASSB) return R3R4; else if (c == CLASSC) return F1; return R3; } /* * Calculate argument sizes. */ void lastcall(NODE *p) { NODE *op = p; int size = 0; #ifdef PCC_DEBUG if (x2debug) printf("lastcall:\n"); #endif p->n_qual = 0; if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) return; for (p = p->n_right; p->n_op == CM; p = p->n_left) size += argsize(p->n_right); size += argsize(p); op->n_qual = size; /* XXX */ } /* * Special shapes. */ int special(NODE *p, int shape) { int o = p->n_op; switch (shape) { case SFUNCALL: if (o == STCALL || o == USTCALL) return SRREG; break; case SPCON: if (o == ICON && p->n_name[0] == 0 && (getlval(p) & ~0x7fff) == 0) return SRDIR; break; } return SRNOPE; } static int fset = FEATURE_BIGENDIAN | FEATURE_HARDFLOAT; /* * Target-dependent command-line options. */ void mflags(char *str) { if (strcasecmp(str, "big-endian") == 0) { fset |= FEATURE_BIGENDIAN; } else if (strcasecmp(str, "little-endian") == 0) { fset &= ~FEATURE_BIGENDIAN; } else if (strcasecmp(str, "soft-float") == 0) { fset &= ~FEATURE_HARDFLOAT; } else if (strcasecmp(str, "hard-float") == 0) { fset |= FEATURE_HARDFLOAT; } else { fprintf(stderr, "unknown m option '%s'\n", str); exit(1); } } int features(int mask) { return ((fset & mask) == mask); } /* * Do something target-dependent for xasm arguments. * Supposed to find target-specific constraints and rewrite them. */ int myxasm(struct interpass *ip, NODE *p) { return 0; } pcc-20181216/arch/powerpc/macdefs.h010064400017500000000000000267041340073675300156540ustar raggewheel/* $Id: macdefs.h,v 1.20 2018/12/02 11:11:39 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Machine-dependent defines for both passes. */ /* * Convert (multi-)character constant to integer. */ #define makecc(val,i) lastcon = (lastcon<<8)|((val<<24)>>24); /* * Storage space requirements */ #define SZCHAR 8 #define SZBOOL 32 #define SZINT 32 #define SZFLOAT 32 #define SZDOUBLE 64 #ifdef ELFABI #define SZLDOUBLE 96 #else #define SZLDOUBLE 128 #endif #define SZLONG 32 #define SZSHORT 16 #define SZLONGLONG 64 #define SZPOINT(t) 32 /* * Alignment constraints */ #define ALCHAR 8 #define ALBOOL 32 #define ALINT 32 #define ALFLOAT 32 #define ALDOUBLE 32 #ifdef ELFABI #define ALLDOUBLE 32 #else #define ALLDOUBLE 128 #endif #define ALLONG 32 #ifdef ELFABI #define ALLONGLONG 64 #else #define ALLONGLONG 32 #endif #define ALSHORT 16 #define ALPOINT 32 #define ALSTRUCT 32 #define ALSTACK (16*SZCHAR) /* * Min/max values. */ #define MIN_CHAR -128 #define MAX_CHAR 127 #define MAX_UCHAR 255 #define MIN_SHORT -32768 #define MAX_SHORT 32767 #define MAX_USHORT 65535 #define MIN_INT -1 #define MAX_INT 0x7fffffff #define MAX_UNSIGNED 0xffffffff #define MIN_LONG MIN_INT #define MAX_LONG MAX_INT #define MAX_ULONG MAX_UNSIGNED #define MIN_LONGLONG 0x8000000000000000LL #define MAX_LONGLONG 0x7fffffffffffffffLL #define MAX_ULONGLONG 0xffffffffffffffffULL #define CHAR_UNSIGNED #define BOOL_TYPE INT /* what used to store _Bool */ /* * Use large-enough types. */ typedef long long CONSZ; typedef unsigned long long U_CONSZ; typedef long long OFFSZ; #define CONFMT "%lld" /* format for printing constants */ #if defined(ELFABI) #define LABFMT ".L%d" /* format for printing labels */ #define REGPREFIX "%" /* format for printing registers */ #elif defined(MACHOABI) #define LABFMT "L%d" /* format for printing labels */ #define REGPREFIX #else #error undefined ABI #endif #define STABLBL "LL%d" /* format for stab (debugging) labels */ #ifdef MACHOABI #define STAB_LINE_ABSOLUTE /* S_LINE fields use absolute addresses */ #endif #undef FIELDOPS /* no bit-field instructions */ #define TARGET_ENDIAN TARGET_BE #define MYINSTRING #define MYALIGN /* Definitions mostly used in pass2 */ #define BYTEOFF(x) ((x)&03) #define szty(t) (((t) == DOUBLE || (t) == LDOUBLE || \ DEUNSIGN(t) == LONGLONG) ? 2 : 1) /* * The PPC register definition are taken from apple docs. * * The classes used are: * A - general registers * B - 64-bit register pairs * C - floating-point registers */ #define R0 0 /* scratch register */ #define R1 1 /* stack base pointer */ #define R2 2 #define R3 3 /* return register / argument 0 */ #define R4 4 /* return register (for longlong) / argument 1 */ #define R5 5 /* scratch register / argument 2 */ #define R6 6 /* scratch register / argument 3 */ #define R7 7 /* scratch register / argument 4 */ #define R8 8 /* scratch register / argument 5 */ #define R9 9 /* scratch register / argument 6 */ #define R10 10 /* scratch register / argument 7 */ #define R11 11 /* scratch register */ #define R12 12 /* scratch register */ #define R13 13 #define R14 14 #define R15 15 #define R16 16 #define R17 17 #define R18 18 #define R19 19 #define R20 20 #define R21 21 #define R22 22 #define R23 23 #define R24 24 #define R25 25 #define R26 26 #define R27 27 #define R28 28 #define R29 29 #define R30 30 #define R31 31 #define R3R4 32 #define R4R5 33 #define R5R6 34 #define R6R7 35 #define R7R8 36 #define R8R9 37 #define R9R10 38 #define R14R15 39 #define R16R17 40 #define R18R19 41 #define R20R21 42 #define R22R23 43 #define R24R25 44 #define R26R27 45 #define R28R29 46 #define R30R31 47 #define F0 48 /* scratch register */ #define F1 49 /* return value 0 / argument 0 */ #define F2 50 /* return value 1 / argument 1 */ #define F3 51 /* return value 2 / argument 2 */ #define F4 52 /* return value 3 / argument 3 */ #define F5 53 /* argument 4 */ #define F6 54 /* argument 5 */ #define F7 55 /* argument 6 */ #define F8 56 /* argument 7 */ #define F9 57 /* argument 8 */ #define F10 58 /* argument 9 */ #define F11 59 /* argument 10 */ #define F12 60 /* argument 11 */ #define F13 61 /* argument 12 */ #define F14 62 #define F15 63 #define F16 64 #define F17 65 #define F18 66 #define F19 67 #define F20 68 #define F21 69 #define F22 70 #define F23 71 #define F24 72 #define F25 73 #define F26 74 #define F27 75 #define F28 76 #define F29 77 #define F30 78 #define F31 79 #define NUMCLASS 3 #define MAXREGS 64 /* XXX cannot have more than 64 */ #define RSTATUS \ 0, /* R0 */ \ 0, /* R1 */ \ SAREG|TEMPREG, /* R2 */ \ SAREG|TEMPREG, /* R3 */ \ SAREG|TEMPREG, /* R4 */ \ SAREG|TEMPREG, /* R5 */ \ SAREG|TEMPREG, /* R6 */ \ SAREG|TEMPREG, /* R7 */ \ SAREG|TEMPREG, /* R8 */ \ SAREG|TEMPREG, /* R9 */ \ SAREG|TEMPREG, /* R10 */ \ SAREG|TEMPREG, /* R11 */ \ SAREG|TEMPREG, /* R12 */ \ SAREG, /* R13 */ \ SAREG, /* R14 */ \ SAREG, /* R15 */ \ SAREG, /* R16 */ \ SAREG, /* R17 */ \ SAREG, /* R18 */ \ SAREG, /* R19 */ \ SAREG, /* R20 */ \ SAREG, /* R21 */ \ SAREG, /* R22 */ \ SAREG, /* R23 */ \ SAREG, /* R24 */ \ SAREG, /* R25 */ \ SAREG, /* R26 */ \ SAREG, /* R27 */ \ SAREG, /* R28 */ \ SAREG, /* R29 */ \ SAREG, /* R30 */ \ SAREG, /* R31 */ \ \ SBREG|TEMPREG, /* R3R4 */ \ SBREG|TEMPREG, /* R4R5 */ \ SBREG|TEMPREG, /* R5R6 */ \ SBREG|TEMPREG, /* R6R7 */ \ SBREG|TEMPREG, /* R7R8 */ \ SBREG|TEMPREG, /* R8R9 */ \ SBREG|TEMPREG, /* R9R10 */ \ \ SBREG, /* R14R15 */ \ SBREG, /* R16R17 */ \ SBREG, /* R18R19 */ \ SBREG, /* R20R21 */ \ SBREG, /* R22R23 */ \ SBREG, /* R24R25 */ \ SBREG, /* R26R2k */ \ SBREG, /* R28R29 */ \ SBREG, /* R30R31 */ \ \ SCREG|TEMPREG, /* F0 */ \ SCREG|TEMPREG, /* F1 */ \ SCREG|TEMPREG, /* F2 */ \ SCREG|TEMPREG, /* F3 */ \ SCREG|TEMPREG, /* F4 */ \ SCREG|TEMPREG, /* F5 */ \ SCREG|TEMPREG, /* F6 */ \ SCREG|TEMPREG, /* F7 */ \ SCREG|TEMPREG, /* F8 */ \ SCREG|TEMPREG, /* F9 */ \ SCREG|TEMPREG, /* F10 */ \ SCREG|TEMPREG, /* F11 */ \ SCREG|TEMPREG, /* F12 */ \ SCREG|TEMPREG, /* F13 */ \ SCREG, /* F14 */ \ SCREG, /* F15 */ \ #define ROVERLAP \ { -1 }, { -1 }, { -1 }, \ { R3R4, -1 }, { R3R4, R4R5, -1 }, \ { R4R5, R5R6, -1 }, { R5R6, R6R7, -1 }, \ { R6R7, R7R8, -1 }, { R7R8, R8R9, -1 }, \ { R8R9, R9R10, -1 }, { R9R10, -1 }, \ { -1 }, { -1 }, { -1 }, \ { R14R15, -1 }, { R14R15, -1 }, \ { R16R17, -1 }, { R16R17, -1 }, \ { R18R19, -1 }, { R18R19, -1 }, \ { R20R21, -1 }, { R20R21, -1 }, \ { R22R23, -1 }, { R22R23, -1 }, \ { R24R25, -1 }, { R24R25, -1 }, \ { R26R27, -1 }, { R26R27, -1 }, \ { R28R29, -1 }, { R28R29, -1 }, \ { R30R31, -1 }, { R30R31, -1 }, \ \ { R3, R4, R4R5, -1 }, { R4, R5, R3R4, R5R6, -1 }, \ { R5, R6, R4R5, R6R7, -1 }, { R6, R7, R5R6, R7R8, -1 }, \ { R7, R8, R6R7, R8R9, -1 }, { R8, R9, R7R8, R8R9, -1 }, \ { R9, R10, R8R9, -1 }, \ { R14, R15, -1 }, { R16, R17, -1 }, \ { R18, R19, -1 }, { R20, R21, -1 }, \ { R22, R23, -1 }, { R24, R25, -1 }, \ { R26, R27, -1 }, { R28, R29, -1 }, \ { R30, R31, -1 }, \ \ { -1 }, { -1 }, { -1 }, { -1 }, \ { -1 }, { -1 }, { -1 }, { -1 }, \ { -1 }, { -1 }, { -1 }, { -1 }, \ { -1 }, { -1 }, { -1 }, { -1 }, \ /* * According to the ABI documents, there isn't really a frame pointer; * all references to data on the stack (autos and parameters) are * indexed relative to the stack pointer. However, pcc isn't really * capable of running in this manner, and expects a frame pointer. */ #define SPREG R1 /* stack pointer */ #define FPREG R30 /* frame pointer */ #define GOTREG R31 /* global offset table (PIC) */ #ifdef FPREG #define ARGINIT (24*8) /* # bits above fp where arguments start */ #define AUTOINIT (8*8) /* # bits above fp where automatics start */ #define BACKAUTO /* stack grows negatively for automatics */ #define BACKTEMP /* stack grows negatively for temporaries */ #else #define ARGINIT (24*8) /* # bits above fp where arguments start */ #define AUTOINIT (56*8) /* # bits above fp where automatics start */ #endif /* Return a register class based on the type of the node */ #define PCLASS(p) (1 << gclass((p)->n_type)) #define GCLASS(x) ((x) < 32 ? CLASSA : ((x) < 48 ? CLASSB : CLASSC)) #define DECRA(x,y) (((x) >> (y*6)) & 63) /* decode encoded regs */ #define ENCRA(x,y) ((x) << (6+y*6)) /* encode regs in int */ #define ENCRD(x) (x) /* Encode dest reg in n_reg */ #define RETREG(x) retreg(x) int COLORMAP(int c, int *r); int retreg(int ty); #define SHSTR (MAXSPECIAL+1) /* short struct */ #define SFUNCALL (MAXSPECIAL+2) /* struct assign after function call */ #define SPCON (MAXSPECIAL+3) /* positive constant */ int features(int f); #define FEATURE_BIGENDIAN 0x00010000 #define FEATURE_PIC 0x00020000 #define FEATURE_HARDFLOAT 0x00040000 struct stub { struct { struct stub *q_forw, *q_back; } link; char *name; }; extern struct stub stublist; extern struct stub nlplist; void addstub(struct stub *list, char *name); #define TARGET_STDARGS #define TARGET_BUILTINS \ { "__builtin_stdarg_start", powerpc_builtin_stdarg_start, \ 0, 2, 0, VOID }, \ { "__builtin_va_arg", powerpc_builtin_va_arg, \ BTNORVAL|BTNOPROTO, 2, 0, 0 }, \ { "__builtin_va_end", powerpc_builtin_va_end, 0, 1, 0, VOID }, \ { "__builtin_va_copy", powerpc_builtin_va_copy, 0, 2, 0, VOID }, #ifdef LANG_CXX #define P1ND struct node #else #define P1ND struct p1node #endif struct node; struct bitable; P1ND *powerpc_builtin_stdarg_start(const struct bitable *, P1ND *a); P1ND *powerpc_builtin_va_arg(const struct bitable *f, P1ND *a); P1ND *powerpc_builtin_va_end(const struct bitable *f, P1ND *a); P1ND *powerpc_builtin_va_copy(const struct bitable *f, P1ND *a); P1ND *powerpc_builtin_frame_address(const struct bitable *f, P1ND *a); P1ND *powerpc_builtin_return_address(const struct bitable *f, P1ND *a); #undef P1ND #define NARGREGS 8 #ifdef ELFABI #define COM " # " #else #define COM " ; " #endif /* floating point definitions */ #define USE_IEEEFP_32 #define FLT_PREFIX IEEEFP_32 #define USE_IEEEFP_64 #define DBL_PREFIX IEEEFP_64 #define LDBL_PREFIX IEEEFP_64 pcc-20181216/arch/powerpc/order.c010064400017500000000000000212021274041510000153260ustar raggewheel/* $Id: order.c,v 1.9 2016/07/10 09:49:52 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include # include "pass2.h" #include int canaddr(NODE *); /* * Check size of offset in OREG. Called by oregok() to see if an * OREG can be generated. * * returns 0 if it can, 1 otherwise. */ int notoff(TWORD t, int r, CONSZ off, char *cp) { #if 0 if (off >= 32767 || off <= -32768) printf("; notoff %lld TOO BIG!\n", off); #endif if (cp && cp[0]) return 1; return (off >= 32768 || off <= -32769); } /* * Generate instructions for an OREG. * Called by swmatch(). */ void offstar(NODE *p, int shape) { NODE *r; if (x2debug) printf("offstar(%p)\n", p); if (isreg(p)) return; /* Is already OREG */ r = p->n_right; if( p->n_op == PLUS || p->n_op == MINUS ){ if( r->n_op == ICON ){ if (isreg(p->n_left) == 0) (void)geninsn(p->n_left, INAREG); /* Converted in ormake() */ return; } } (void)geninsn(p, INAREG); } /* * Unable to convert to OREG (notoff() returned failure). Output * suitable instructions to replace OREG. */ void myormake(NODE *q) { NODE *p; if (x2debug) printf("myormake(%p)\n", q); p = q->n_left; /* * This handles failed OREGs conversions, due to the offset * being too large for an OREG. */ if ((p->n_op == PLUS || p->n_op == MINUS) && p->n_right->n_op == ICON) { if (isreg(p->n_left) == 0) (void)geninsn(p->n_left, INAREG); if (isreg(p->n_right) == 0) (void)geninsn(p->n_right, INAREG); (void)geninsn(p, INAREG); } else if (p->n_op == REG) { q->n_op = OREG; setlval(q, getlval(p)); q->n_rval = p->n_rval; tfree(p); } } /* * Shape matches for UMUL. Cooperates with offstar(). */ int shumul(NODE *p, int shape) { if (x2debug) printf("shumul(%p)\n", p); /* Turns currently anything into OREG on x86 */ if (shape & SOREG) return SROREG; return SRNOPE; } /* * Rewrite operations on binary operators (like +, -, etc...). * Called as a result of table lookup. */ int setbin(NODE *p) { if (x2debug) printf("setbin(%p)\n", p); return 0; } /* setup for assignment operator */ int setasg(NODE *p, int cookie) { if (x2debug) printf("setasg(%p)\n", p); return(0); } /* setup for unary operator */ int setuni(NODE *p, int cookie) { return 0; } /* * Special handling of some instruction register allocation. */ struct rspecial * nspecial(struct optab *q) { if (x2debug) printf("nspecial: op=%d, visit=0x%x: %s", q->op, q->visit, q->cstring); switch (q->op) { /* soft-float stuff */ case RS: case LS: if (q->lshape == SBREG) { static struct rspecial s[] = { { NLEFT, R3R4 }, { NRIGHT, R5 }, { NRES, R3R4 }, { 0 }, }; return s; } else if (q->lshape == SAREG) { static struct rspecial s[] = { { NLEFT, R3 }, { NRIGHT, R4 }, { NRES, R3 }, { 0 }, }; return s; } cerror("nspecial LS/RS"); break; case UMINUS: case SCONV: if (q->lshape == SBREG && q->rshape == SAREG) { static struct rspecial s[] = { { NLEFT, R3R4 }, { NRES, R3 }, { 0 } }; return s; } else if (q->lshape == SAREG && q->rshape == SBREG) { static struct rspecial s[] = { { NLEFT, R3 }, { NRES, R3R4 }, { 0 } }; return s; } else if (q->lshape == SAREG && q->rshape == SAREG) { static struct rspecial s[] = { { NLEFT, R3 }, { NRES, R3 }, { 0 } }; return s; } else if (q->lshape == SBREG && q->rshape == SBREG) { static struct rspecial s[] = { { NLEFT, R3R4 }, { NRES, R3R4 }, { 0 } }; return s; } else if (q->lshape == SCREG && q->rshape == SBREG) { static struct rspecial s[] = { { NLEFT, F1 }, { NEVER, F0 }, /* stomped on */ { NRES, R3R4 }, { 0 } }; return s; } else if (q->lshape == SBREG && q->rshape == SCREG) { static struct rspecial s[] = { { NLEFT, R3R4 }, { NEVER, F0 }, /* stomped on */ { NRES, F1 }, { 0 } }; return s; } else { static struct rspecial s[] = { { NOLEFT, R0 }, { 0 } }; return s; } break; case OPLOG: if (q->lshape == SBREG) { static struct rspecial s[] = { { NLEFT, R3R4 }, { NRIGHT, R5R6 }, { NRES, R3 }, { 0 } }; return s; } else if (q->lshape == SAREG) { static struct rspecial s[] = { { NLEFT, R3 }, { NRIGHT, R4 }, { NRES, R3 }, { 0 } }; return s; } cerror("nspecial oplog"); break; case PLUS: case MINUS: case MUL: case DIV: case MOD: if (q->lshape == SBREG && (q->ltype & (TDOUBLE|TLDOUBLE|TLONGLONG|TULONGLONG))) { static struct rspecial s[] = { { NLEFT, R3R4 }, { NRIGHT, R5R6 }, { NRES, R3R4 }, { 0 } }; return s; } else if (q->lshape == SAREG && q->ltype & TFLOAT) { static struct rspecial s[] = { { NLEFT, R3 }, { NRIGHT, R4 }, { NRES, R3 }, { 0 } }; return s; } else if (q->lshape == SAREG) { static struct rspecial s[] = { { NOLEFT, R0 }, { 0 } }; return s; } cerror("nspecial mul"); break; case STASG: { static struct rspecial s[] = { { NEVER, R3 }, { NRIGHT, R4 }, { NEVER, R5 }, { 0 } }; return s; } break; case OPLTYPE: { if (q->visit & SAREG) { static struct rspecial s[] = { { NEVER, R0 }, { 0 } }; return s; } } break; case ASSIGN: if (q->lshape & SNAME) { static struct rspecial s[] = { { NEVER, R0 }, { 0 } }; return s; } else if (q->rshape & SNAME) { static struct rspecial s[] = { { NOLEFT, R0 }, { 0 } }; return s; } else if (q->lshape & SOREG) { static struct rspecial s[] = { { NOLEFT, R0 }, { 0 } }; return s; } else if (q->rshape & SOREG) { static struct rspecial s[] = { { NORIGHT, R0 }, { 0 } }; return s; } /* fallthough */ case UMUL: case AND: case OR: case ER: { static struct rspecial s[] = { { NOLEFT, R0 }, { 0 } }; return s; } default: break; } comperr("nspecial entry %d: %s", q - table, q->cstring); return 0; /* XXX gcc */ } /* * Set evaluation order of a binary node if it differs from default. */ int setorder(NODE *p) { return 0; /* nothing differs on x86 */ } /* * Set registers "live" at function calls (like arguments in registers). * This is for liveness analysis of registers. */ int * livecall(NODE *p) { static int r[] = { R10, R9, R8, R7, R6, R5, R4, R3, R30, R31, -1 }; int num = 1; if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) return &r[8-0]; for (p = p->n_right; p->n_op == CM; p = p->n_left) num += szty(p->n_right->n_type); num += szty(p->n_right->n_type); num = (num > 8 ? 8 : num); return &r[8 - num]; } /* * Signal whether the instruction is acceptable for this target. */ int acceptable(struct optab *op) { if ((op->visit & FEATURE_PIC) != 0) return (kflag != 0); return features(op->visit & 0xffff0000); } pcc-20181216/arch/powerpc/table.c010064400017500000000000001151161147376442700153370ustar raggewheel/* $Id: table.c,v 1.18 2010/11/26 17:06:31 ragge Exp $ */ /*- * Copyright (c) 2007 Gregory McGarry * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * A template has five logical sections: * * 1) subtree (operator); goal to achieve (cookie) * 2) left node descendent of operator (node class; type) * 3) right node descendent of operator (node class; type) * 4) resource requirements (number of scratch registers); * subtree rewriting rule * 5) emitted instructions */ #include "pass2.h" #define TUWORD TUNSIGNED|TULONG #define TSWORD TINT|TLONG #define TWORD TUWORD|TSWORD #if defined(ELFABI) #define HA16(x) # x "@ha" #define LO16(x) # x "@l" #elif defined(MACHOABI) #define HA16(x) "ha16(" # x ")" #define LO16(x) "lo16(" # x ")" #else #error undefined ABI #endif struct optab table[] = { /* First entry must be an empty entry */ { -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", }, /* PCONVs are not necessary */ { PCONV, INAREG, SAREG, TWORD|TPOINT, SAREG, TWORD|TPOINT, 0, RLEFT, COM "pointer conversion\n", }, /* * Conversions of integral types */ { SCONV, INAREG, SAREG, TCHAR|TUCHAR, SAREG, TCHAR|TUCHAR, 0, RLEFT, COM "convert between (u)char and (u)char\n", }, { SCONV, INAREG, SAREG, TSHORT|TUSHORT, SAREG, TSHORT|TUSHORT, 0, RLEFT, COM "convert between (u)short and (u)short\n", }, { SCONV, INAREG, SAREG, TPOINT|TWORD, SAREG, TWORD, 0, RLEFT, COM "convert a pointer/word to an int\n", }, { SCONV, INAREG, SAREG, TPOINT, SAREG, TPOINT, 0, RLEFT, COM "convert pointers\n", }, { SCONV, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, 0, RLEFT, COM "convert (u)longlong to (u)longlong\n", }, { SCONV, INAREG, SAREG, TCHAR, SAREG, TSHORT|TSWORD, NASL|NAREG, RESC1, " extsb A1,AL" COM "convert char to short/int\n", }, { SCONV, INAREG, SAREG, TUCHAR, SAREG, TSHORT|TSWORD, 0, RLEFT, COM "convert uchar to short/int\n", }, { SCONV, INAREG, SAREG, TUCHAR, SAREG, TUSHORT|TUWORD, 0, RLEFT, COM "convert uchar to ushort/unsigned\n", }, /* XXX is this necessary? */ { SCONV, INAREG, SAREG, TCHAR, SAREG, TUSHORT|TUWORD, NSPECIAL|NAREG|NASL, RESC1, " extsb A1,AL" COM "convert char to ushort/unsigned\n", }, { SCONV, INBREG | FEATURE_BIGENDIAN, SAREG, TUCHAR|TUSHORT|TUNSIGNED, SBREG, TLONGLONG|TULONGLONG, NBREG, RESC1, " mr U1,AL" COM "convert uchar/ushort/uint to (u)longlong\n" " li A1,0\n", }, { SCONV, INBREG, SAREG, TUCHAR|TUSHORT|TUNSIGNED, SBREG, TLONGLONG|TULONGLONG, NBREG, RESC1, " mr A1,AL" COM "convert uchar/ushort/uint to (u)longlong\n" " li U1,0\n", }, { SCONV, INBREG | FEATURE_BIGENDIAN, SAREG, TCHAR|TSHORT|TSWORD, SBREG, TULONGLONG|TLONGLONG, NBREG, RESC1, " mr U1,AL" COM "convert char/short/int to ulonglong\n" " srawi A1,AL,31\n", }, { SCONV, INBREG, SAREG, TCHAR|TSHORT|TSWORD, SBREG, TULONGLONG|TLONGLONG, NBREG, RESC1, " mr A1,AL" COM "convert char/short/int to ulonglong\n" " srawi U1,AL,31\n", }, { SCONV, INAREG, SAREG, TSHORT|TUSHORT, SAREG, TCHAR|TUCHAR, NSPECIAL|NAREG|NASL, RESC1, " andi. A1,AL,255" COM "convert (u)short to (u)char\n", }, /* XXX is this really necessary? */ { SCONV, INAREG, SAREG, TSHORT, SAREG, TWORD, NAREG|NASL, RESC1, " extsh A1,AL" COM "convert short to int\n", }, { SCONV, INAREG, SAREG, TUSHORT, SAREG, TWORD, NSPECIAL|NAREG|NASL, RESC1, COM "convert ushort to word\n", }, { SCONV, INAREG, SAREG, TWORD, SAREG, TCHAR|TUCHAR, NAREG|NASL|NSPECIAL, RESC1, " andi. A1,AL,255" COM "convert (u)int to (u)char\n", }, { SCONV, INAREG, SAREG, TWORD, SAREG, TSHORT|TUSHORT, NAREG|NASL|NSPECIAL, RESC1, " andi. A1,AL,65535" COM "convert (u)int to (u)short\n", }, { SCONV, INAREG, SBREG, TLONGLONG|TULONGLONG, SAREG, TCHAR|TUCHAR, NAREG|NSPECIAL, RESC1, " andi. A1,AL,255" COM "(u)longlong to (u)char\n", }, { SCONV, INAREG, SBREG, TLONGLONG|TULONGLONG, SAREG, TSHORT|TUSHORT, NAREG|NSPECIAL, RESC1, " andi. A1,AL,65535" COM "(u)longlong to (u)short\n", }, { SCONV, INAREG, SBREG, TLONGLONG|TULONGLONG, SAREG, TWORD, NAREG, RESC1, " mr A1,AL" COM "convert (u)longlong to (u)int/long\n", }, /* conversions on load from memory */ { SCONV, INAREG, SOREG, TCHAR, SAREG, TWORD, NASL|NAREG|NSPECIAL, RESC1, " lbz A1,AL" COM "convert char to int/long\n" " extsb A1,A1\n", }, { SCONV, INAREG, SOREG, TUCHAR, SAREG, TWORD, NASL|NAREG|NSPECIAL, RESC1, " lbz A1,AL" COM "convert uchar to int/long\n", }, { SCONV, INAREG, SOREG, TSHORT, SAREG, TWORD, NASL|NAREG|NSPECIAL, RESC1, " lha A1,AL" COM "convert short to int/long\n", }, { SCONV, INAREG, SOREG, TUSHORT, SAREG, TWORD, NASL|NAREG|NSPECIAL, RESC1, " lhz A1,AL" COM "convert ushort to int/long\n", }, { SCONV, INAREG, SOREG, TLONGLONG|TULONGLONG, SAREG, TCHAR|TUCHAR, NAREG|NSPECIAL, RESC1, " lwz A1,AL" COM "(u)longlong to (u)char\n" " andi. A1,A1,255\n", }, { SCONV, INAREG, SOREG, TLONGLONG|TULONGLONG, SAREG, TSHORT|TUSHORT, NAREG|NSPECIAL, RESC1, " lwz A1,AL" COM "(u)longlong to (u)short\n" " andi. A1,A1,65535\n", }, { SCONV, INAREG, SOREG, TLONGLONG|TULONGLONG, SAREG, TWORD, NAREG|NSPECIAL, RESC1, " lwz A1,AL" COM "(u)longlong to (u)int\n", }, /* * floating-point conversions * * There doesn't appear to be an instruction to move values between * the floating-point registers and the general-purpose registers. * So values are bounced into memory... */ { SCONV, INCREG | FEATURE_HARDFLOAT, SCREG, TFLOAT, SCREG, TDOUBLE|TLDOUBLE, 0, RLEFT, COM "convert float to (l)double\n", }, /* soft-float */ { SCONV, INBREG, SAREG, TFLOAT, SBREG, TDOUBLE|TLDOUBLE, NSPECIAL|NBREG, RESC1, "ZF", }, { SCONV, INCREG | FEATURE_HARDFLOAT, SCREG, TDOUBLE|TLDOUBLE, SCREG, TFLOAT, NCREG, RESC1, " frsp A1,AL" COM "convert (l)double to float\n", }, /* soft-float */ { SCONV, INAREG, SBREG, TDOUBLE|TLDOUBLE, SAREG, TFLOAT, NSPECIAL|NAREG, RESC1, "ZF", }, { SCONV, INCREG | FEATURE_HARDFLOAT, SCREG, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, 0, RLEFT, COM "convert (l)double to (l)double\n", }, /* soft-float */ { SCONV, INBREG, SBREG, TDOUBLE|TLDOUBLE, SBREG, TDOUBLE|TLDOUBLE, 0, RLEFT, COM "convert (l)double to (l)double (soft-float)\n", }, { SCONV, INCREG | FEATURE_HARDFLOAT, SAREG, TWORD, SCREG, TFLOAT|TDOUBLE|TLDOUBLE, 2*NCREG|NAREG, RESC3, "ZC", }, /* soft-float */ { SCONV, INAREG, SAREG, TWORD, SAREG, TFLOAT, NSPECIAL|NAREG, RESC1, "ZF", }, /* soft-float */ { SCONV, INBREG, SAREG, TWORD, SBREG, TDOUBLE|TLDOUBLE, NSPECIAL|NBREG, RESC1, "ZF", }, { SCONV, INAREG | FEATURE_HARDFLOAT, SOREG, TFLOAT|TDOUBLE|TLDOUBLE, SAREG, TWORD, 2*NCREG|NAREG, RESC1, "ZC", }, /* soft-float */ { SCONV, INAREG, SAREG, TFLOAT, SAREG, TWORD, NSPECIAL|NAREG, RESC1, "ZF", }, /* soft-float */ { SCONV, INAREG, SBREG, TDOUBLE|TLDOUBLE, SAREG, TWORD, NSPECIAL|NAREG, RESC1, "ZF", }, { SCONV, INCREG | FEATURE_HARDFLOAT, SBREG, TLONGLONG|TULONGLONG, SCREG, TFLOAT|TDOUBLE|TLDOUBLE, NSPECIAL|NCREG, RESC1, "ZF", }, /* soft-float */ { SCONV, INAREG, SBREG, TLONGLONG|TULONGLONG, SAREG, TFLOAT, NSPECIAL|NAREG, RESC1, "ZF", }, /* soft-float */ { SCONV, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TDOUBLE|TLDOUBLE, NSPECIAL|NBREG, RESC1, "ZF", }, { SCONV, INBREG | FEATURE_HARDFLOAT, SCREG, TFLOAT|TDOUBLE|TLDOUBLE, SBREG, TLONGLONG|TULONGLONG, NSPECIAL|NBREG, RESC1, "ZF", }, /* soft-float */ { SCONV, INBREG, SAREG, TFLOAT, SBREG, TLONGLONG|TULONGLONG, NSPECIAL|NBREG, RESC1, "ZF", }, /* soft-float */ { SCONV, INBREG, SBREG, TDOUBLE|TLDOUBLE, SBREG, TLONGLONG|TULONGLONG, NSPECIAL|NBREG, RESC1, "ZF", }, /* * Subroutine calls. */ { CALL, FOREFF, SCON, TANY, SANY, TANY, 0, 0, " bl CL" COM "call (args, no result) to scon\n", }, { UCALL, FOREFF, SCON, TANY, SANY, TANY, 0, 0, " bl CL" COM "call (no args, no result) to scon\n", }, { CALL, INAREG, SCON, TANY, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, /* should be 0 */ " bl CL" COM "call (args, result) to scon\n", }, { UCALL, INAREG, SCON, TANY, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, /* should be 0 */ " bl CL" COM "call (no args, result) to scon\n", }, { CALL, INBREG, SCON, TANY, SBREG, TLONGLONG|TULONGLONG, NBREG|NBSL, RESC1, /* should be 0 */ " bl CL" COM "call (args, result) to scon\n", }, { UCALL, INBREG, SCON, TANY, SBREG, TLONGLONG|TULONGLONG, NBREG|NBSL, RESC1, /* should be 0 */ " bl CL" COM "call (no args, result) to scon\n", }, { CALL, INCREG | FEATURE_HARDFLOAT, SCON, TANY, SCREG, TFLOAT|TDOUBLE|TLDOUBLE, NCREG|NCSL, RESC1, /* should be 0 */ " bl CL" COM "call (args, result) to scon\n", }, { UCALL, INCREG | FEATURE_HARDFLOAT, SCON, TANY, SCREG, TFLOAT|TDOUBLE|TLDOUBLE, NCREG|NCSL, RESC1, /* should be 0 */ " bl CL" COM "call (no args, result) to scon\n", }, { CALL, INAREG, SCON, TANY, SAREG, TFLOAT, NAREG|NASL, RESC1, /* should be 0 */ " bl CL" COM "call (args, result) to scon\n", }, { UCALL, INAREG, SCON, TANY, SAREG, TFLOAT, NAREG|NASL, RESC1, /* should be 0 */ " bl CL" COM "call (no args, result) to scon\n", }, { CALL, INBREG, SCON, TANY, SBREG, TDOUBLE|TLDOUBLE, NBREG|NBSL, RESC1, /* should be 0 */ " bl CL" COM "call (args, result) to scon\n", }, { UCALL, INBREG, SCON, TANY, SBREG, TDOUBLE|TLDOUBLE, NBREG|NBSL, RESC1, /* should be 0 */ " bl CL" COM "call (no args, result) to scon\n", }, { CALL, FOREFF, SAREG, TANY, SANY, TANY, 0, 0, " mtctr AL" COM "call (args, no result) to reg\n" " bctrl\n", }, { UCALL, FOREFF, SAREG, TANY, SANY, TANY, 0, 0, " mtctr AL" COM "call (no args, no result) to reg\n" " bctrl\n", }, { CALL, INAREG, SAREG, TANY, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG, RESC1, " mtctr AL" COM "call (args, result) to reg\n" " bctrl\n", }, { UCALL, INAREG, SAREG, TANY, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG, RESC1, " mtctr AL" COM "call (no args, result) to reg\n" " bctrl\n", }, /* struct return */ { USTCALL, FOREFF, SCON, TANY, SANY, TANY, 0, 0, " bl CL\n", }, { USTCALL, INAREG, SCON, TANY, SANY, TANY, NAREG|NASL, RESC1, /* should be 0 */ " bl CL\n", }, { USTCALL, INAREG, SAREG, TANY, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG, RESC1, " mtctr AL" " bctrl\n", }, { STCALL, FOREFF, SCON, TANY, SANY, TANY, 0, 0, " bl CL\n", }, { STCALL, INAREG, SCON, TANY, SANY, TANY, NAREG|NASL, RESC1, /* should be 0 */ " bl CL\n", }, { STCALL, INAREG, SAREG, TANY, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, " mtctr AL" " bctrl\n", }, /* * The next rules handle all binop-style operators. */ /* XXX AL cannot be R0 */ { PLUS, INAREG, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SSCON, TANY, NAREG|NASL|NSPECIAL, RESC1, " addi A1,AL,AR" COM "addition of constant\n", }, /* XXX AL cannot be R0 */ { PLUS, INAREG|FORCC, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SSCON, TANY, NAREG|NASL|NSPECIAL, RESC1|RESCC, " addic. A1,AL,AR" COM "addition of constant\n", }, { PLUS, INBREG, SBREG, TLONGLONG|TULONGLONG, SSCON, TANY, NBREG|NBSL, RESC1, " addic A1,AL,AR" COM "64-bit addition of constant\n" " addze U1,UL\n", }, { PLUS, INAREG, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL|NSPECIAL, RESC1, " add A1,AL,AR\n", }, { PLUS, INAREG|FORCC, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL|NSPECIAL, RESC1|RESCC, " add. A1,AL,AR\n", }, { PLUS, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, NBREG|NBSL, RESC1, " addc A1,AL,AR" COM "64-bit add\n" " adde U1,UL,UR\n", }, { PLUS, INCREG | FEATURE_HARDFLOAT, SCREG, TFLOAT, SCREG, TFLOAT, NCREG, RESC1, " fadds A1,AL,AR" COM "float add\n", }, { PLUS, INAREG, SAREG, TFLOAT, SAREG, TFLOAT, NSPECIAL|NAREG, RESC1, "ZF", }, { PLUS, INCREG | FEATURE_HARDFLOAT, SCREG, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, NCREG|NCSL, RESC1, " fadd A1,AL,AR" COM "(l)double add\n", }, /* soft-float */ { PLUS, INBREG, SBREG, TDOUBLE|TLDOUBLE, SBREG, TDOUBLE|TLDOUBLE, NSPECIAL|NBREG|NBSL, RESC1, "ZF", }, { MINUS, INAREG, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SSCON, TANY, NAREG|NASL|NSPECIAL, RESC1, " addi A1,AL,-AR\n", }, { MINUS, INAREG|FORCC, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SSCON, TANY, NAREG|NASL|NSPECIAL, RESC1|RESCC, " addic. A1,AL,-AR\n", }, { MINUS, INBREG, SBREG, TLONGLONG|TULONGLONG, SSCON, TANY, NBREG|NBSL, RESC1, " addic A1,AL,-AR\n" " addme U1,UL\n", }, { MINUS, INAREG, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL|NSPECIAL, RESC1, " subf A1,AR,AL\n", }, { MINUS, INAREG|FORCC, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL|NSPECIAL, RESC1|RESCC, " subf. A1,AR,AL\n", }, { MINUS, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, NBREG|NBSL, RESC1, " subfc A1,AR,AL" COM "64-bit subtraction\n" " subfe U1,UR,UL\n", }, { MINUS, INCREG | FEATURE_HARDFLOAT, SCREG, TFLOAT, SCREG, TFLOAT, NCREG, RESC1, " fsubs A1,AL,AR\n", }, { MINUS, INAREG, SAREG, TFLOAT, SAREG, TFLOAT, NSPECIAL|NAREG, RESC1, "ZF", }, { MINUS, INCREG | FEATURE_HARDFLOAT, SCREG, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, NCREG|NCSL, RESC1, " fsub A1,AL,AR" COM "(l)double sub\n", }, /* soft-float */ { MINUS, INBREG, SBREG, TDOUBLE|TLDOUBLE, SBREG, TDOUBLE|TLDOUBLE, NSPECIAL|NBREG|NBSL, RESC1, "ZF", }, /* * The next rules handle all shift operators. */ { LS, INAREG, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, " slw A1,AL,AR" COM "left shift\n", }, { LS, INAREG|FORCC, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, " slw. A1,AL,AR" COM "left shift\n", }, { LS, INAREG, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, SCON, TANY, NAREG|NASL, RESC1, " slwi A1,AL,AR" COM "left shift by constant\n", }, { LS, INAREG|FORCC, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, SCON, TANY, NAREG|NASL, RESC1, " slwi. A1,AL,AR" COM "left shift by constant\n", }, { LS, INBREG, SBREG, TLONGLONG|TULONGLONG, SCON, TANY, NBREG, RESC1, "ZO", }, { LS, INBREG, SBREG, TLONGLONG|TULONGLONG, SAREG, TANY, NSPECIAL|NBREG, RESC1, "ZE", }, { RS, INAREG, SAREG, TUWORD|TUSHORT|TUCHAR, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, " srw A1,AL,AR" COM "right shift\n", }, { RS, INAREG, SAREG, TSWORD|TSHORT|TCHAR, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, " sraw A1,AL,AR" COM "arithmetic right shift\n", }, { RS, INAREG|FORCC, SAREG, TUWORD|TUSHORT|TUCHAR, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, " srw. A1,AL,AR" COM "right shift\n", }, { RS, INAREG|FORCC, SAREG, TSWORD|TSHORT|TCHAR, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, " sraw. A1,AL,AR" COM "arithmetic right shift\n", }, { RS, INAREG, SAREG, TUWORD|TUSHORT|TUCHAR, SCON, TANY, NAREG|NASL, RESC1, " srwi A1,AL,AR" COM "right shift by constant\n", }, { RS, INAREG, SAREG, TSWORD|TSHORT|TCHAR, SCON, TANY, NAREG|NASL, RESC1, " srawi A1,AL,AR" COM "arithmetic right shift by constant\n", }, { RS, INAREG|FORCC, SAREG, TUWORD|TUSHORT|TUCHAR, SCON, TANY, NAREG|NASL, RESC1, " srwi. A1,AL,AR" COM "right shift by constant\n", }, { RS, INAREG|FORCC, SAREG, TSWORD|TSHORT|TCHAR, SCON, TANY, NAREG|NASL, RESC1, " srawi. A1,AL,AR" COM "right shift by constant\n", }, { RS, INBREG, SBREG, TLONGLONG|TULONGLONG, SCON, TANY, NBREG, RESC1, "ZO" }, { RS, INBREG, SBREG, TLONGLONG|TULONGLONG, SAREG, TANY, NSPECIAL|NBREG, RESC1, "ZE", }, /* * The next rules takes care of assignments. "=". */ { ASSIGN, FOREFF|INAREG, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SSCON, TANY, 0, RDEST, " li AL,AR\n", }, { ASSIGN, FOREFF|INBREG, SBREG, TLONGLONG|TULONGLONG, SSCON, TANY, 0, RDEST, " li AL,AR\n" " li UL,UR\n", }, { ASSIGN, FOREFF|INAREG, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SCON, TANY, 0, RDEST, " lis AL," HA16(AR) "\n" " addi AL,AL," LO16(AR) "\n", }, { ASSIGN, FOREFF|INBREG, SBREG, TLONGLONG|TULONGLONG, SCON, TANY, 0, RDEST, " lis AL," HA16(AR) "\n" " addi AL,AL," LO16(AR) "\n" " lis UL," HA16(UR) "\n" " addi UL,UL," LO16(UR) "\n", }, { ASSIGN, FOREFF|INAREG, SAREG, TWORD|TPOINT, SOREG, TWORD|TPOINT, NSPECIAL, RDEST, " lwz AL,AR" COM "assign oreg to reg\n", }, { ASSIGN, FOREFF|INAREG, SAREG, TWORD|TPOINT, SNAME, TWORD|TPOINT, NSPECIAL, RDEST, " lis AL," HA16(AR) COM "assign sname to reg\n" " lwz AL," LO16(AR) "(AL)\n", }, { ASSIGN, FOREFF|INBREG, SBREG, TLONGLONG|TULONGLONG, SOREG, TLONGLONG|TULONGLONG, NSPECIAL, RDEST, " lwz AL,AR" COM "assign llong to reg\n" " lwz UL,UR\n" }, { ASSIGN, FOREFF|INAREG, SBREG, TLONGLONG|TULONGLONG, SNAME, TLONGLONG|TULONGLONG, NSPECIAL, RDEST, " lis AL," HA16(AR) COM "assign 64-bit sname to reg\n" " lwz AL," LO16(AR) "(AL)\n" " lis UL," HA16(UR) "\n" " lwz UL," LO16(UR) "(UL)\n", }, { ASSIGN, FOREFF|INBREG, SBREG, TLONGLONG|TULONGLONG, SOREG, TSWORD, NSPECIAL, RDEST, " lwz AL,AR" COM "load int/pointer into llong\n" " srawi UL,AR,31\n" }, { ASSIGN, FOREFF|INBREG, SBREG, TLONGLONG|TULONGLONG, SOREG, TUNSIGNED|TPOINT, NSPECIAL, RDEST, " lwz AL,AR" COM "load uint/pointer into (u)llong\n" " li UL,0\n" }, { ASSIGN, FOREFF|INAREG, SAREG, TUCHAR, SOREG, TUCHAR, NSPECIAL, RDEST, " lbz AL,AR\n", }, { ASSIGN, FOREFF|INAREG, SAREG, TUCHAR, SNAME, TUCHAR, NSPECIAL, RDEST, " lis AL," HA16(AR) COM "assign uchar sname to reg\n" " lbz AL," LO16(AR) "(AL)\n", }, { ASSIGN, FOREFF|INAREG, SAREG, TCHAR, SOREG, TCHAR, NSPECIAL, RDEST, " lbz AL,AR\n" " extsb AL,AL\n", }, { ASSIGN, FOREFF|INAREG, SAREG, TCHAR, SNAME, TCHAR, NSPECIAL, RDEST, " lis AL," HA16(AR) COM "assign char sname to reg\n" " lbz AL," LO16(AR) "(AL)\n" " extsb AL,AL\n", }, { ASSIGN, FOREFF|INAREG, SAREG, TWORD|TPOINT, SOREG, TSHORT, NSPECIAL, RDEST, " lha AL,AR\n", }, { ASSIGN, FOREFF|INAREG, SAREG, TWORD|TPOINT, SOREG, TUSHORT, NSPECIAL, RDEST, " lhz AL,AR\n", }, { ASSIGN, FOREFF|INAREG, SAREG, TWORD, SNAME, TSHORT, NSPECIAL, RDEST, " lis AL," HA16(AR) "\n" " lha AL," LO16(AR) "(AL)\n", }, { ASSIGN, FOREFF|INAREG, SAREG, TWORD, SNAME, TUSHORT, NSPECIAL, RDEST, " lis AL," HA16(AR) "\n" " lhz AL," LO16(AR) "(AL)\n", }, { ASSIGN, FOREFF|INAREG, SOREG, TWORD|TPOINT, SAREG, TWORD|TPOINT, NSPECIAL, RDEST, " stw AR,AL\n", }, { ASSIGN, FOREFF|INAREG, SNAME, TWORD|TPOINT, SAREG, TWORD|TPOINT, NAREG|NSPECIAL, RDEST, " lis A1," HA16(AL) COM "assign reg to sname\n" " stw AR," LO16(AL) "(A1)\n", }, { ASSIGN, FOREFF|INBREG, SOREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, NSPECIAL, RDEST, " stw AR,AL" COM "store 64-bit value\n" " stw UR,UL\n", }, { ASSIGN, FOREFF|INBREG, SNAME, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, NBREG|NSPECIAL, RDEST, " lis A1," HA16(AL) COM "assign reg to 64-bit sname\n" " stw AR," LO16(AL) "(A1)\n" " lis U1," HA16(UL) "\n" " stw UR," LO16(UL) "(U1)\n", }, { ASSIGN, FOREFF|INAREG, SOREG, TCHAR|TUCHAR, SAREG, TCHAR|TUCHAR, NSPECIAL, RDEST, " stb AR,AL\n", }, { ASSIGN, FOREFF|INAREG, SNAME, TCHAR|TUCHAR, SAREG, TCHAR|TUCHAR, NAREG|NSPECIAL, RDEST, " lis A1," HA16(AL) "\n" " stb AR," LO16(AL) "(A1)\n", }, { ASSIGN, FOREFF|INAREG, SOREG, TSHORT|TUSHORT, SAREG, TSHORT|TUSHORT, NSPECIAL, RDEST, " sth AR,AL\n", }, { ASSIGN, FOREFF|INAREG, SNAME, TSHORT|TUSHORT, SAREG, TSHORT|TUSHORT, NAREG|NSPECIAL, RDEST, " lis A1," HA16(AL) "\n" " sth AR," LO16(AL) "(A1)\n", }, { ASSIGN, FOREFF|INAREG, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, 0, RDEST, " mr AL,AR" COM "assign AR to AL\n", }, { ASSIGN, FOREFF|INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, 0, RDEST, " mr AL,AR" COM "assign UR:AR to UL:AL\n" " mr UL,UR\n", }, { ASSIGN, FOREFF|INAREG, SFLD, TANY, SAREG, TANY, 3*NAREG, RDEST, " lis A3," HA16(M) COM "bit-field assignment\n" " addi A3,A3," LO16(M) "\n" " lwz A2,AL\n" " slwi A1,AR,H\n" " and A1,A1,A3\n" " not A3,A3\n" " and A2,A2,A3\n" " or A2,A2,A1\n" " stw A2,AL\n" "F mr AD,AR\n" "F slwi AD,AD,32-S\n" "F srwi AD,AD,32-S\n", }, { STASG, INAREG|FOREFF, SOREG|SNAME, TANY, SAREG, TPTRTO|TANY, NSPECIAL, RDEST, "ZQ", }, { ASSIGN, FOREFF|INCREG | FEATURE_HARDFLOAT, SOREG, TFLOAT, SCREG, TFLOAT, 0, RDEST, " stfs AR,AL" COM "store float\n", }, /* soft-float */ { ASSIGN, FOREFF|INAREG, SOREG, TFLOAT, SAREG, TFLOAT, 0, RDEST, " stw AR,AL" COM "store float (soft-float)\n", }, { ASSIGN, FOREFF|INCREG | FEATURE_HARDFLOAT, SNAME, TFLOAT, SCREG, TFLOAT, NAREG, RDEST, " lis A1," HA16(AL) "\n" " stfs AR," LO16(AL) "(A1)\n", }, /* soft-float */ { ASSIGN, FOREFF|INAREG, SNAME, TFLOAT, SAREG, TFLOAT, NAREG, RDEST, " lis A1," HA16(AL) "\n" " stw AR," LO16(AL) "(A1)\n", }, { ASSIGN, FOREFF|INCREG | FEATURE_HARDFLOAT, SCREG, TFLOAT, SOREG, TFLOAT, 0, RDEST, " lfs AL,AR" COM "load float\n", }, /* soft-float */ { ASSIGN, FOREFF|INAREG, SAREG, TFLOAT, SOREG, TFLOAT, 0, RDEST, " lwz AL,AR" COM "load float (soft-float)\n", }, { ASSIGN, FOREFF|INCREG | FEATURE_HARDFLOAT, SCREG, TFLOAT, SNAME, TFLOAT, NAREG, RDEST, " lis A1," HA16(AR) "\n" " lfs AL," LO16(AR) "(A1)\n", }, /* soft-float */ { ASSIGN, FOREFF|INAREG, SAREG, TFLOAT, SNAME, TFLOAT, NAREG, RDEST, " lis A1," HA16(AR) "\n" " lwz AL," LO16(AR) "(A1)\n", }, { ASSIGN, FOREFF|INCREG | FEATURE_HARDFLOAT, SCREG, TFLOAT, SCREG, TFLOAT, 0, RDEST, " fmr AL,AR" COM "assign AR to AL\n", }, /* soft-float */ { ASSIGN, FOREFF|INAREG, SAREG, TFLOAT, SAREG, TFLOAT, 0, RDEST, " mr AL,AR" COM "assign AR to AL\n", }, { ASSIGN, FOREFF|INCREG | FEATURE_HARDFLOAT, SOREG, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, 0, RDEST, " stfd AR,AL" COM "store (l)double\n", }, /* soft-float */ { ASSIGN, FOREFF|INBREG, SOREG, TDOUBLE|TLDOUBLE, SBREG, TDOUBLE|TLDOUBLE, 0, RDEST, " stw AR,AL" COM "store (l)double (soft-float)\n" " stw UR,UL\n", }, { ASSIGN, FOREFF|INCREG | FEATURE_HARDFLOAT, SNAME, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, NAREG, RDEST, " lis A1," HA16(AL) "\n" " stfd AR," LO16(AL) "(A1)\n", }, /* soft-float */ { ASSIGN, FOREFF|INBREG, SNAME, TDOUBLE|TLDOUBLE, SBREG, TDOUBLE|TLDOUBLE, NAREG, RDEST, " lis A1," HA16(AL) "\n" " stw AR," LO16(AL) "(A1)\n" " lis A1," HA16(UL) "\n" " stw UR," LO16(UL) "(A1)\n", }, { ASSIGN, FOREFF|INCREG | FEATURE_HARDFLOAT, SCREG, TDOUBLE|TLDOUBLE, SOREG, TDOUBLE|TLDOUBLE, 0, RDEST, " lfd AL,AR" COM "load (l)double\n", }, /* soft-float */ { ASSIGN, FOREFF|INBREG, SBREG, TDOUBLE|TLDOUBLE, SOREG, TDOUBLE|TLDOUBLE, 0, RDEST, " lwz AL,AR" COM "load (l)double (soft-float)\n" " lwz UL,UR\n", }, { ASSIGN, FOREFF|INCREG | FEATURE_HARDFLOAT, SCREG, TDOUBLE|TLDOUBLE, SNAME, TDOUBLE|TLDOUBLE, NAREG, RDEST, " lis A1," HA16(AR) "\n" " lfd AL," LO16(AR) "(A1)\n", }, /* soft-float */ { ASSIGN, FOREFF|INBREG, SBREG, TDOUBLE|TLDOUBLE, SNAME, TDOUBLE|TLDOUBLE, NAREG, RDEST, " lis A1," HA16(AR) "\n" " lwz AL," LO16(AR) "(A1)\n" " lis A1," HA16(UR) "\n" " lwz UL," LO16(UR) "(A1)\n", }, { ASSIGN, FOREFF|INCREG | FEATURE_HARDFLOAT, SCREG, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, 0, RDEST, " fmr AL,AR" COM "assign AR to AL\n", }, /* soft-float */ { ASSIGN, FOREFF|INBREG, SBREG, TDOUBLE|TLDOUBLE, SBREG, TDOUBLE|TLDOUBLE, 0, RDEST, " mr AL,AR" COM "assign AR to AL\n" " mr UL,UR\n", }, /* * DIV/MOD/MUL */ { DIV, INAREG, SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, NAREG|NASL, RESC1, " divwu A1,AL,AR\n", }, { DIV, INAREG|FORCC, SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, NAREG|NASL, RESC1|RESCC, " divwu. A1,AL,AR\n", }, { DIV, INAREG, SAREG, TWORD|TSHORT|TCHAR, SAREG, TWORD|TSHORT|TCHAR, NAREG|NASL, RESC1, " divw A1,AL,AR\n", }, { DIV, INAREG|FORCC, SAREG, TWORD|TSHORT|TCHAR, SAREG, TWORD|TSHORT|TCHAR, NAREG|NASL, RESC1|RESCC, " divw. A1,AL,AR\n", }, { DIV, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, NSPECIAL|NBREG, RESC1, "ZE", }, { DIV, INCREG | FEATURE_HARDFLOAT, SCREG, TFLOAT, SCREG, TFLOAT, NCREG|NCSR, RESC1, " fdivs A1,AL,AR" COM "float divide\n", }, /* soft-float */ { DIV, INAREG, SAREG, TFLOAT, SAREG, TFLOAT, NSPECIAL|NAREG, RESC1, "ZF", }, { DIV, INCREG | FEATURE_HARDFLOAT, SCREG, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, NCREG|NCSR, RESC1, " fdiv A1,AL,AR" COM "(l)double divide\n", }, /* soft-float */ { DIV, INBREG, SBREG, TDOUBLE|TLDOUBLE, SBREG, TDOUBLE|TLDOUBLE, NSPECIAL|NBREG, RESC1, "ZF", }, { MOD, INAREG, SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, NAREG, RESC1, " divwu A1,AL,AR" COM "unsigned modulo\n" " mullw A1,A1,AR\n" " subf A1,A1,AL\n", }, { MOD, INAREG, SAREG, TWORD|TSHORT|TCHAR, SAREG, TWORD|TSHORT|TCHAR, NAREG, RESC1, " divw A1,AL,AR" COM "signed modulo\n" " mullw A1,A1,AR\n" " subf A1,A1,AL\n", }, { MOD, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, NSPECIAL|NBREG, RESC1, "ZE", }, { MUL, INAREG, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SSCON, TANY, NAREG|NASL, RESC1, " mulli A1,AL,AR\n", }, { MUL, INAREG|FORCC, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SSCON, TANY, NAREG|NASL, RESC1|RESCC, " mulli. A1,AL,AR\n", }, { MUL, INAREG, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, " mullw A1,AL,AR\n", }, { MUL, INAREG|FORCC, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1|RESCC, " mullw. A1,AL,AR\n", }, { MUL, INBREG, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, NBREG, RESC1, " mullw A1,AL,AR\n" " mulhw U1,AL,AR\n", }, { MUL, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, NBREG, RESC1, " mullw A1,AL,AR\n" " mulhw U1,AL,AR\n", }, { MUL, INCREG | FEATURE_HARDFLOAT, SCREG, TFLOAT, SCREG, TFLOAT, NCREG|NCSR, RESC1, " fmuls A1,AL,AR" COM "float multiply\n", }, /* soft-float */ { MUL, INAREG, SAREG, TFLOAT, SAREG, TFLOAT, NSPECIAL|NAREG, RESC1, "ZF", }, { MUL, INCREG | FEATURE_HARDFLOAT, SCREG, TDOUBLE|TLDOUBLE, SCREG, TDOUBLE|TLDOUBLE, NCREG|NCSR, RESC1, " fmul A1,AL,AR" COM "(l)double multiply\n", }, /* soft-float */ { MUL, INBREG, SBREG, TDOUBLE|TLDOUBLE, SBREG, TDOUBLE|TLDOUBLE, NSPECIAL|NBREG, RESC1, "ZF", }, /* * Indirection operators. */ { UMUL, INAREG, SANY, TANY, SOREG|SNAME, TWORD|TPOINT, NAREG|NSPECIAL, RESC1, " lwz A1,AL" COM "word load\n", }, { UMUL, INAREG, SANY, TANY, SOREG|SNAME, TCHAR, NAREG|NSPECIAL, RESC1, " lbz A1,AL" COM "char load\n" " extsb A1,A1\n", }, { UMUL, INAREG, SANY, TANY, SOREG|SNAME, TUCHAR, NAREG|NSPECIAL, RESC1, " lbz A1,AL" COM "uchar load\n", }, { UMUL, INAREG, SANY, TANY, SOREG|SNAME, TSHORT, NAREG|NSPECIAL, RESC1, " lha A1,AL" COM "short load\n", }, { UMUL, INAREG, SANY, TANY, SOREG|SNAME, TUSHORT, NAREG|NSPECIAL, RESC1, " lhz A1,AL" COM "ushort load\n", }, { UMUL, INBREG, SANY, TANY, SOREG|SNAME, TLONGLONG|TULONGLONG, NBREG, RESC1, " lwz A1,AL" COM "64-bit load\n" " lwz U1,UL\n", }, { UMUL, INCREG | FEATURE_HARDFLOAT, SANY, TANY, SOREG|SNAME, TFLOAT, NCREG, RESC1, " lfs A1,AL" COM "float load\n", }, { UMUL, INAREG, SANY, TANY, SOREG|SNAME, TFLOAT, NAREG, RESC1, " lwz A1,AL" COM "float load (soft-float)\n", }, { UMUL, INCREG | FEATURE_HARDFLOAT, SANY, TANY, SOREG|SNAME, TDOUBLE|TLDOUBLE, NCREG, RESC1, " lfd A1,AL" COM "(l)double load\n", }, { UMUL, INBREG, SANY, TANY, SOREG|SNAME, TDOUBLE|TLDOUBLE, NSPECIAL|NBREG, RESC1, " lwz A1,AL" COM "(l)double load (soft-float)\n" " lwz U1,UL\n", }, #if 0 { UMUL, INAREG, SANY, TANY, SAREG, TWORD|TPOINT, NAREG, RESC1, " lwz A1,(AL)" COM "word load\n", }, #endif /* * Logical/branching operators */ /* compare with constant */ { OPLOG, FORCC, SAREG, TSWORD|TSHORT|TCHAR, SSCON, TANY, 0, RESCC, " cmpwi AL,AR\n", }, /* compare with constant */ { OPLOG, FORCC, SAREG, TUWORD|TPOINT|TUSHORT|TUCHAR, SSCON, TANY, 0, RESCC, " cmplwi AL,AR\n", }, /* compare with register */ { OPLOG, FORCC, SAREG, TSWORD|TSHORT|TCHAR, SAREG, TSWORD|TSHORT|TCHAR, 0, RESCC, " cmpw AL,AR\n", }, /* compare with register */ { OPLOG, FORCC, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, 0, RESCC, " cmplw AL,AR\n", }, /* compare with register */ { OPLOG, FORCC, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, 0, RESCC, "ZD", }, /* compare with register */ { OPLOG, FORCC | FEATURE_HARDFLOAT, SCREG, TFLOAT|TDOUBLE|TLDOUBLE, SCREG, TFLOAT|TDOUBLE|TLDOUBLE, 0, RESCC, " fcmpu 0,AL,AR\n", }, /* soft-float */ { OPLOG, FORCC, SAREG, TFLOAT, SAREG, TFLOAT, NSPECIAL, RESCC, "ZF\n", }, /* soft-float */ { OPLOG, FORCC, SBREG, TDOUBLE|TLDOUBLE, SBREG, TDOUBLE|TLDOUBLE, NSPECIAL, RESCC, "ZF", }, { OPLOG, FORCC, SANY, TANY, SANY, TANY, REWRITE, 0, "diediedie!", }, /* AND/OR/ER */ { AND, INAREG, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL|NSPECIAL, RESC1|RESCC, " and A1,AL,AR\n", }, { AND, INAREG|FORCC, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL|NSPECIAL, RESC1, " and. A1,AL,AR\n", }, /* AR must be positive */ { AND, INAREG|FORCC, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SPCON, TANY, NAREG|NASL|NSPECIAL, RESC1|RESCC, " andi. A1,AL,AR\n", }, { AND, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, NBREG|NBSL, RESC1, " and A1,AL,AR" COM "64-bit and\n" " and U1,UL,UR\n" }, { AND, INBREG|FORCC, SBREG, TLONGLONG|TULONGLONG, SPCON, TANY, NBREG|NBSL, RESC1|RESCC, " andi. A1,AL,AR" COM "64-bit and with constant\n" " li U1,0\n" }, { OR, INAREG, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL|NSPECIAL, RESC1, " or A1,AL,AR\n", }, { OR, INAREG|FORCC, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL|NSPECIAL, RESC1|RESCC, " or. A1,AL,AR\n", }, { OR, INAREG, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SPCON, TANY, NAREG|NASL, RESC1, " ori A1,AL,AR\n", }, { OR, INAREG|FORCC, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SPCON, TANY, NAREG|NASL, RESC1|RESCC, " ori. A1,AL,AR\n", }, { OR, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, NBREG|NBSL, RESC1, " or A1,AL,AR" COM "64-bit or\n" " or U1,UL,UR\n" }, { OR, INBREG, SBREG, TLONGLONG|TULONGLONG, SPCON, TANY, NBREG|NBSL, RESC1, " ori A1,AL,AR" COM "64-bit or with constant\n" }, { OR, INBREG|FORCC, SBREG, TLONGLONG|TULONGLONG, SPCON, TANY, NBREG|NBSL, RESC1|RESCC, " ori. A1,AL,AR" COM "64-bit or with constant\n" }, { ER, INAREG, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL|NSPECIAL, RESC1, " xor A1,AL,AR\n", }, { ER, INAREG|FORCC, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL|NSPECIAL, RESC1|RESCC, " xor. A1,AL,AR\n", }, { ER, INAREG, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SPCON, TANY, NAREG|NASL|NSPECIAL, RESC1, " xori A1,AL,AR\n", }, { ER, INBREG, SBREG, TLONGLONG|TULONGLONG, SBREG, TLONGLONG|TULONGLONG, NBREG|NBSL, RESC1, " xor A1,AL,AR" COM "64-bit xor\n" " xor U1,UL,UR\n" }, { ER, INBREG, SBREG, TLONGLONG|TULONGLONG, SPCON, TANY, NBREG|NBSL, RESC1, " xori A1,AL,AR" COM "64-bit xor with constant\n" }, /* * Jumps. */ { GOTO, FOREFF, SCON, TANY, SANY, TANY, 0, RNOP, " b LL\n", }, { GOTO, FOREFF, SAREG, TANY, SANY, TANY, 0, RNOP, " mtctr AL\n" " bctr\n", }, /* * Convert LTYPE to reg. */ #if defined(ELFABI) { OPLTYPE, INAREG | FEATURE_PIC, SANY, TANY, SNAME, TANY, NAREG, RESC1, " lwz A1,AL" COM "elfabi pic load\n", }, #endif { OPLTYPE, INBREG, SANY, TANY, SOREG, TLONGLONG|TULONGLONG, NBREG, RESC1, " lwz A1,AL" COM "load llong from memory\n" " lwz U1,UL\n", }, { OPLTYPE, INBREG, SANY, TANY, SNAME, TLONGLONG|TULONGLONG, NBREG, RESC1, " lis A1," HA16(AL) COM "load llong from sname\n" " lwz A1," LO16(AL) "(A1)\n" " lis U1," HA16(UL) "\n" " lwz U1," LO16(UL) "(U1)\n", }, { OPLTYPE, INAREG, SANY, TANY, SOREG, TWORD|TPOINT, NAREG, RESC1, " lwz A1,AL" COM "load word from memory\n", }, { OPLTYPE, INAREG, SANY, TANY, SNAME, TWORD|TPOINT, NAREG|NSPECIAL, RESC1, " lis A1," HA16(AL) COM "load word from sname\n" " lwz A1," LO16(AL) "(A1)\n", }, { OPLTYPE, INAREG, SANY, TANY, SOREG, TCHAR, NAREG, RESC1, " lbz A1,AL" COM "load char from memory\n" " extsb A1,A1\n", }, { OPLTYPE, INAREG, SANY, TANY, SNAME, TCHAR, NAREG|NSPECIAL, RESC1, " lis A1," HA16(AL) COM "load char from sname\n" " lbz A1," LO16(AL) "(A1)\n" " extsb A1,A1\n", }, { OPLTYPE, INAREG, SANY, TANY, SOREG, TUCHAR, NAREG, RESC1, " lbz A1,AL" COM "load uchar from memory\n", }, { OPLTYPE, INAREG, SANY, TANY, SNAME, TUCHAR, NAREG|NSPECIAL, RESC1, " lis A1," HA16(AL) COM "load uchar from sname\n" " lbz A1," LO16(AL) "(A1)\n", }, /* load short from memory */ { OPLTYPE, INAREG, SANY, TANY, SOREG, TSHORT, NAREG, RESC1, " lha A1,AL" COM "load short from memory\n", }, { OPLTYPE, INAREG, SANY, TANY, SOREG, TUSHORT, NAREG, RESC1, " lhz A1,AL" COM "load ushort from memory\n", }, { OPLTYPE, INAREG, SANY, TANY, SNAME, TSHORT, NAREG|NSPECIAL, RESC1, " lis A1," HA16(AL) COM "load short from sname\n" " lha A1," LO16(AL) "(A1)\n", }, { OPLTYPE, INAREG, SANY, TANY, SNAME, TUSHORT, NAREG|NSPECIAL, RESC1, " lis A1," HA16(AL) COM "load ushort from sname\n" " lhz A1," LO16(AL) "(A1)\n", }, { OPLTYPE, INAREG, SANY, TANY, SSCON, TANY, NAREG, RESC1, " li A1,AL" COM "load 16-bit constant\n", }, { OPLTYPE, INBREG, SANY, TANY, SSCON, TANY, NBREG, RESC1, " li A1,AL" COM "load 16-bit constant\n" " li U1,UL\n", }, { OPLTYPE, INAREG, SANY, TANY, SCON, TANY, NAREG|NASL, RESC1, " lis A1," HA16(AL) COM "load constant into register\n" " addi A1,A1," LO16(AL) "\n", }, { OPLTYPE, INBREG, SANY, TANY, SCON, TANY, NBREG, RESC1, " lis A1," HA16(AL) COM "load constant into register\n" " addi A1,A1," LO16(AL) "\n" " lis U1," HA16(UL) "\n" " addi U1,U1," LO16(UL) "\n", }, { OPLTYPE, INAREG, SANY, TANY, SAREG, TANY, NAREG, RESC1, " mr A1,AL" COM "load AL into A1\n" }, { OPLTYPE, INBREG, SANY, TANY, SBREG, TANY, NBREG, RESC1, " mr A1,AL" COM "load UL:AL into U1:A1\n" " mr U1,UL\n", }, { OPLTYPE, INCREG, SANY, TANY, SCREG, TFLOAT|TDOUBLE|TLDOUBLE, NCREG, RESC1, " fmr A1,AL" COM "load AL into A1\n", }, { OPLTYPE, INCREG | FEATURE_HARDFLOAT, SANY, TANY, SOREG, TFLOAT, NCREG, RESC1, " lfs A1,AL" COM "load float\n", }, /* soft-float */ { OPLTYPE, INAREG, SANY, TANY, SOREG, TFLOAT, NAREG, RESC1, " lwz A1,AL" COM "load float (soft-float)\n", }, { OPLTYPE, INCREG | FEATURE_HARDFLOAT, SANY, TANY, SNAME, TFLOAT, NCREG|NAREG, RESC2, " lis A1," HA16(AL) COM "load sname\n" " lfs A2," LO16(AL) "(A1)\n", }, /* soft-float */ { OPLTYPE, INAREG, SANY, TANY, SNAME, TFLOAT, NAREG, RESC1, " lis A1," HA16(AL) COM "load sname (soft-float)\n" " lwz A1," LO16(AL) "(A1)\n", }, { OPLTYPE, INCREG | FEATURE_HARDFLOAT, SANY, TANY, SOREG, TDOUBLE|TLDOUBLE, NCREG, RESC1, " lfd A1,AL" COM "load (l)double\n", }, /* soft-float */ { OPLTYPE, INBREG, SANY, TANY, SOREG, TDOUBLE|TLDOUBLE, NBREG, RESC1, " lwz A1,AL" COM "load (l)double (soft-float)\n" " lwz U1,UL\n", }, { OPLTYPE, INCREG | FEATURE_HARDFLOAT, SANY, TANY, SNAME, TDOUBLE|TLDOUBLE, NCREG|NAREG, RESC2, " lis A1," HA16(AL) COM "load sname\n" " lfd A2," LO16(AL) "(A1)\n", }, { OPLTYPE, INBREG, SANY, TANY, SNAME, TDOUBLE|TLDOUBLE, NBREG, RESC1, " lis A1," HA16(AL) COM "load sname (soft-float)\n" " lwz A1," LO16(AL) "(A1)\n" " lis U1," HA16(UL) "\n" " lwz U1," LO16(UL) "(U1)\n", }, /* * Negate a word. */ { UMINUS, INAREG, SAREG, TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR, SANY, TANY, NAREG|NASL, RESC1, " neg A1,AL\n", }, { UMINUS, INBREG, SBREG, TLONGLONG|TULONGLONG, SANY, TANY, NBREG|NBSL, RESC1, " subfic A1,AL,0\n" " subfze U1,UL\n", }, { UMINUS, INCREG | FEATURE_HARDFLOAT, SCREG, TFLOAT|TDOUBLE|TLDOUBLE, SANY, TANY, NCREG|NCSL, RESC1, " fneg A1,AL\n", }, { UMINUS, INAREG, SAREG, TFLOAT, SANY, TANY, NAREG|NASL, RESC1, " xoris A1,AL,0x8000" COM "(soft-float)\n", }, { UMINUS, INBREG, SBREG, TDOUBLE|TLDOUBLE, SANY, TANY, NBREG|NBSL, RESC1, " xoris U1,UL,0x8000" COM "(soft-float)\n" " mr A1,AL\n", }, { COMPL, INAREG, SAREG, TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR, SANY, TANY, NAREG|NASL, RESC1, " not A1,AL\n", }, { COMPL, INBREG, SBREG, TLONGLONG|TULONGLONG, SANY, TANY, NBREG|NBSL, RESC1, " not A1,AL\n" " not U1,UL\n", }, /* * Arguments to functions. */ #if 0 { STARG, FOREFF, SAREG|SOREG|SNAME|SCON, TANY, SANY, TSTRUCT, NSPECIAL|NAREG, 0, "ZF", }, #endif # define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,"" { UMUL, DF( UMUL ), }, { ASSIGN, DF(ASSIGN), }, { STASG, DF(STASG), }, { FLD, DF(FLD), }, { OPLEAF, DF(NAME), }, /* { INIT, DF(INIT), }, */ { OPUNARY, DF(UMINUS), }, { OPANY, DF(BITYPE), }, { FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" }, }; int tablesize = sizeof(table)/sizeof(table[0]); pcc-20181216/arch/sparc64004075500017500000000000000000001340533064000136055ustar raggewheelpcc-20181216/arch/sparc64/CVS004075500017500000000000000000001340533064000142405ustar raggewheelpcc-20181216/arch/sparc64/CVS/Root010064400017500000000000000000111340533064000151520ustar raggewheel/cvsroot pcc-20181216/arch/sparc64/CVS/Repository010064400017500000000000000000211340533064000164070ustar raggewheelpcc/arch/sparc64 pcc-20181216/arch/sparc64/CVS/Entries010064400017500000000000000003711340533064000156510ustar raggewheel/code.c/1.23/Fri Jul 24 07:57:01 2015// /local.c/1.34/Thu Jun 23 13:41:25 2011// /local2.c/1.28/Mon Sep 26 16:45:42 2016// /macdefs.h/1.18/Sat Mar 5 15:53:04 2016// /order.c/1.7/Sun Jun 5 08:54:42 2011// /table.c/1.29/Sun Jun 5 08:54:42 2011// D pcc-20181216/arch/sparc64/code.c010064400017500000000000000142071255436771500147640ustar raggewheel/* $Id: code.c,v 1.23 2015/07/24 07:57:01 ragge Exp $ */ /* * Copyright (c) 2008 David Crawshaw * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "pass1.h" /* * Print out assembler segment name. */ void setseg(int seg, char *name) { switch (seg) { case PROG: name = ".text"; break; case DATA: case LDATA: name = ".data"; break; case STRNG: case RDATA: name = ".section .rodata"; break; case UDATA: break; case PICLDATA: case PICDATA: case PICRDATA: case TLSDATA: case TLSUDATA: case CTORS: case DTORS: uerror("FIXME: unknown section"); case NMSEG: printf("\t.section %s,\"a%c\",@progbits\n", name, cftnsp ? 'x' : 'w'); return; } printf("\t%s\n", name); } void defloc(struct symtab *sp) { TWORD t; char *name; t = sp->stype; if ((name = sp->soname) == NULL) name = exname(sp->sname); if (!ISFTN(t)) { printf("\t.type %s,#object\n", name); printf("\t.size %s," CONFMT "\n", name, tsize(sp->stype, sp->sdf, sp->sap) / SZCHAR); } if (sp->sclass == EXTDEF) printf("\t.global %s\n", name); if (sp->slevel == 0) { printf("%s:\n", name); } else printf(LABFMT ":\n", sp->soffset); } void efcode(void) { /* XXX */ } void bfcode(struct symtab **sp, int cnt) { int i, off; NODE *p, *q; struct symtab *sym; /* Process the first six arguments. */ for (i=0; i < cnt && i < 6; i++) { sym = sp[i]; q = block(REG, NIL, NIL, sym->stype, sym->sdf, sym->sap); q->n_rval = RETREG_PRE(sym->stype) + i; p = tempnode(0, sym->stype, sym->sdf, sym->sap); sym->soffset = regno(p); sym->sflags |= STNODE; p = buildtree(ASSIGN, p, q); ecomp(p); } /* Process the remaining arguments. */ for (off = V9RESERVE; i < cnt; i++) { sym = sp[i]; p = tempnode(0, sym->stype, sym->sdf, sym->sap); off = ALIGN(off, (tlen(p) - 1)); sym->soffset = off * SZCHAR; off += tlen(p); p = buildtree(ASSIGN, p, nametree(sym)); sym->soffset = regno(p->n_left); sym->sflags |= STNODE; ecomp(p); } } void ejobcode(int flag) { } void bjobcode(void) { astypnames[USHORT] = astypnames[SHORT] = "\t.half"; astypnames[INT] = astypnames[UNSIGNED] = "\t.long"; astypnames[LONG] = astypnames[ULONG] = astypnames[LONGLONG] = astypnames[ULONGLONG] = "\t.xword"; } /* * The first six 64-bit arguments are saved in the registers O0 to O5, * which become I0 to I5 after the "save" instruction moves the register * window. Arguments 7 and up must be saved on the stack to %sp+BIAS+176. * * For a pretty picture, see Figure 3-16 in the SPARC Compliance Def 2.4. */ static NODE * moveargs(NODE *p, int *regp, int *stacksize) { NODE *r, *q; if (p->n_op == CM) { p->n_left = moveargs(p->n_left, regp, stacksize); r = p->n_right; } else { r = p; } /* XXX more than six FP args can and should be passed in registers. */ if (*regp > 5 && r->n_op != STARG) { /* We are storing the stack offset in n_rval. */ r = block(FUNARG, r, NIL, r->n_type, r->n_df, r->n_ap); /* Make sure we are appropriately aligned. */ *stacksize = ALIGN(*stacksize, (tlen(r) - 1)); r->n_rval = *stacksize; *stacksize += tlen(r); } else if (r->n_op == STARG) cerror("op STARG in moveargs"); else { q = block(REG, NIL, NIL, r->n_type, r->n_df, r->n_ap); /* * The first six non-FP arguments go in the registers O0 - O5. * Float arguments are stored in %fp1, %fp3, ..., %fp29, %fp31. * Double arguments are stored in %fp0, %fp2, ..., %fp28, %fp30. * A non-fp argument still increments register, eg. * test(int a, int b, float b) * takes %o0, %o1, %fp5. */ if (q->n_type == FLOAT) q->n_rval = F0 + (*regp++ * 2) + 1; else if (q->n_type == DOUBLE) q->n_rval = D0 + *regp++; else if (q->n_type == LDOUBLE) cerror("long double support incomplete"); else q->n_rval = O0 + (*regp)++; r = buildtree(ASSIGN, q, r); } if (p->n_op == CM) { p->n_right = r; return p; } return r; } NODE * funcode(NODE *p) { NODE *r, *l; int reg = 0, stacksize = 0; r = l = 0; p->n_right = moveargs(p->n_right, ®, &stacksize); /* * This is a particularly gross and inefficient way to handle * argument overflows. First, we calculate how much stack space * we need in moveargs(). Then we assign it by moving %sp, make * the function call, and then move %sp back. * * What we should be doing is getting the maximum of all the needed * stacksize values to the prologue and doing it all in the "save" * instruction. */ if (stacksize != 0) { stacksize = V9STEP(stacksize); /* 16-bit alignment. */ r = block(REG, NIL, NIL, INT, 0, 0); r->n_lval = 0; r->n_rval = SP; r = block(MINUS, r, bcon(stacksize), INT, 0, 0); l = block(REG, NIL, NIL, INT, 0, 0); l->n_lval = 0; l->n_rval = SP; r = buildtree(ASSIGN, l, r); p = buildtree(COMOP, r, p); r = block(REG, NIL, NIL, INT, 0, 0); r->n_lval = 0; r->n_rval = SP; r = block(PLUS, r, bcon(stacksize), INT, 0, 0); l = block(REG, NIL, NIL, INT, 0, 0); l->n_lval = 0; l->n_rval = SP; r = buildtree(ASSIGN, l, r); p = buildtree(COMOP, p, r); } return p; } void fldty(struct symtab *p) { } int mygenswitch(int num, TWORD type, struct swents **p, int n) { return 0; } /* * Return "canonical frame address". */ NODE * builtin_cfa(const struct bitable *bt, NODE *a) { uerror("missing %s", __func__); return bcon(0); } NODE * builtin_frame_address(const struct bitable *bt, NODE *a) { uerror("missing %s", __func__); return bcon(0); } NODE * builtin_return_address(const struct bitable *bt, NODE *a) { uerror("missing %s", __func__); return bcon(0); } pcc-20181216/arch/sparc64/local.c010064400017500000000000000126751160064120500151270ustar raggewheel/* $Id: local.c,v 1.34 2011/06/23 13:41:25 ragge Exp $ */ /* * Copyright (c) 2008 David Crawshaw * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "pass1.h" NODE * clocal(NODE *p) { struct symtab *sp; int op; NODE *r, *l; op = p->n_op; sp = p->n_sp; l = p->n_left; r = p->n_right; #ifdef PCC_DEBUG if (xdebug) { printf("clocal in: %p, %s\n", p, copst(op)); fwalk(p, eprint, 0); } #endif switch (op) { case NAME: if (sp->sclass == PARAM || sp->sclass == AUTO) { /* * Use a fake structure reference to * write out frame pointer offsets. */ l = block(REG, NIL, NIL, PTR+STRTY, 0, 0); l->n_lval = 0; l->n_rval = FP; r = p; p = stref(block(STREF, l, r, 0, 0, 0)); } break; case PCONV: /* Remove what PCONVs we can. */ if (l->n_op == SCONV) break; if (l->n_op == ICON || (ISPTR(p->n_type) && ISPTR(l->n_type))) { l->n_type = p->n_type; l->n_qual = p->n_qual; l->n_df = p->n_df; l->n_ap = p->n_ap; nfree(p); p = l; } break; case SCONV: /* Remove redundant conversions. */ if ((p->n_type & TMASK) == 0 && (l->n_type & TMASK) == 0 && tsize(p->n_type, p->n_df, p->n_ap) == tsize(l->n_type, l->n_df, l->n_ap) && p->n_type != FLOAT && p->n_type != DOUBLE && l->n_type != FLOAT && l->n_type != DOUBLE && l->n_type != DOUBLE && p->n_type != LDOUBLE) { if (l->n_op == NAME || l->n_op == UMUL || l->n_op == TEMP) { l->n_type = p->n_type; nfree(p); p = l; break; } } /* Convert floating point to int before to char or short. */ if ((l->n_type == FLOAT || l->n_type == DOUBLE || l->n_type == LDOUBLE) && (DEUNSIGN(p->n_type) == CHAR || DEUNSIGN(p->n_type) == SHORT)) { p = block(SCONV, p, NIL, p->n_type, p->n_df, p->n_ap); p->n_left->n_type = INT; break; } /* Transform constants now. */ if (l->n_op != ICON) break; if (ISPTR(p->n_type)) { l->n_type = p->n_type; nfree(p); p = l; break; } switch (p->n_type) { case BOOL: l->n_lval = (l->n_lval != 0); break; case CHAR: l->n_lval = (char)l->n_lval; break; case UCHAR: l->n_lval = l->n_lval & 0377; break; case SHORT: l->n_lval = (short)l->n_lval; break; case USHORT: l->n_lval = l->n_lval & 0177777; break; case UNSIGNED: l->n_lval = l->n_lval & 0xffffffff; break; case INT: l->n_lval = (int)l->n_lval; break; case ULONG: case ULONGLONG: l->n_lval = l->n_lval; break; case LONG: case LONGLONG: l->n_lval = (long long)l->n_lval; break; case FLOAT: case DOUBLE: case LDOUBLE: l->n_op = FCON; l->n_dcon = l->n_lval; break; case VOID: break; default: cerror("sconv type unknown %d", p->n_type); } l->n_type = p->n_type; nfree(p); p = l; break; case FORCE: /* Put attached value into the return register. */ p->n_op = ASSIGN; p->n_right = p->n_left; p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0); p->n_left->n_rval = RETREG_PRE(p->n_type); break; } #ifdef PCC_DEBUG if (xdebug) { printf("clocal out: %p, %s\n", p, copst(op)); fwalk(p, eprint, 0); } #endif return p; } void myp2tree(NODE *p) { struct symtab *sp; if (p->n_op != FCON) return; sp = tmpalloc(sizeof(struct symtab)); sp->sclass = STATIC; sp->slevel = 1; sp->soffset = getlab(); sp->sflags = 0; sp->stype = p->n_type; sp->squal = (CON >> TSHIFT); defloc(sp); ninval(0, tsize(p->n_type, p->n_df, p->n_ap), p); p->n_op = NAME; p->n_lval = 0; p->n_sp = sp; } int andable(NODE *p) { return 1; } int cisreg(TWORD t) { /* SPARCv9 registers are all 64-bits wide. */ return 1; } void spalloc(NODE *t, NODE *p, OFFSZ off) { cerror("spalloc"); } int ninval(CONSZ off, int fsz, NODE *p) { union { float f; double d; int i; long long l; } u; switch (p->n_type) { case FLOAT: u.f = (float)p->n_dcon; printf("\t.long %d\n", u.i); break; case DOUBLE: u.d = (double)p->n_dcon; printf("\t.xword %lld\n", u.l); break; default: return 0; } return 1; } char * exname(char *p) { return p ? p : ""; } TWORD ctype(TWORD type) { switch (BTYPE(type)) { case LONGLONG: MODTYPE(type,LONG); break; case ULONGLONG: MODTYPE(type,ULONG); } return type; } void calldec(NODE *p, NODE *q) { } void extdec(struct symtab *q) { } void defzero(struct symtab *sp) { int off; char *name; if ((name = sp->soname) == NULL) name = exname(sp->sname); off = tsize(sp->stype, sp->sdf, sp->sap); SETOFF(off,SZCHAR); off /= SZCHAR; if (sp->sclass == STATIC) printf("\t.local %s\n", name); if (sp->slevel == 0) printf("\t.comm %s,%d\n", name, off); else printf("\t.comm " LABFMT ",%d\n", sp->soffset, off); } int mypragma(char *str) { return 0; } void fixdef(struct symtab *sp) { } void pass1_lastchance(struct interpass *ip) { } pcc-20181216/arch/sparc64/local2.c010064400017500000000000000207431277225026600152220ustar raggewheel/* $Id: local2.c,v 1.28 2016/09/26 16:45:42 ragge Exp $ */ /* * Copyright (c) 2008 David Crawshaw * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "pass1.h" #include "pass2.h" char * rnames[] = { /* "\%g0", always zero, removed due to 31-element class limit */ "\%g1", "\%g2", "\%g3", "\%g4", "\%g5", "\%g6", "\%g7", "\%o0", "\%o1", "\%o2", "\%o3", "\%o4", "\%o5", "\%o6", "\%o7", "\%l0", "\%l1", "\%l2", "\%l3", "\%l4", "\%l5", "\%l6", "\%l7", "\%i0", "\%i1", "\%i2", "\%i3", "\%i4", "\%i5", "\%i6", "\%i7", "\%f0", "\%f1", "\%f2", "\%f3", "\%f4", "\%f5", "\%f6", "\%f7", "\%f8", "\%f9", "\%f10", "\%f11", "\%f12", "\%f13", "\%f14", "\%f15", "\%f16", "\%f17", "\%f18", "\%f19", "\%f20", "\%f21", "\%f22", "\%f23", "\%f24", "\%f25", "\%f26", "\%f27", "\%f28", "\%f29", "\%f30", /*, "\%f31" XXX removed due to 31-element class limit */ "\%f0", "\%f2", "\%f4", "\%f6", "\%f8", "\%f10", "\%f12", "\%f14", "\%f16", "\%f18", "\%f20", "\%f22", "\%f24", "\%f26", "\%f28", "\%f30", "\%sp", "\%fp", }; void deflab(int label) { printf(LABFMT ":\n", label); } void prologue(struct interpass_prolog *ipp) { int i, stack; stack = V9RESERVE + V9STEP(p2maxautooff); for (i = p2env.p_regs[0]; i; i >>= 1) if (i & 1) stack += 16; /* TODO printf("\t.proc %d\n"); */ if (SIMM13(stack)) printf("\tsave %%sp,-%d,%%sp\n", stack); else { printf("\tsetx -%d,%%g4,%%g1\n", stack); printf("\tsave %%sp,%%g1,%%sp\n"); } } void eoftn(struct interpass_prolog *ipp) { printf("\tret\n"); printf("\trestore\n"); printf("\t.type %s,#function\n", ipp->ipp_name); printf("\t.size %s,(.-%s)\n", ipp->ipp_name, ipp->ipp_name); } void hopcode(int f, int o) { char *str; switch (o) { case EQ: str = "brz"; break; case NE: str = "brnz"; break; case ULE: case LE: str = "brlez"; break; case ULT: case LT: str = "brlz"; break; case UGE: case GE: str = "brgez"; break; case UGT: case GT: str = "brgz"; break; case PLUS: str = "add"; break; case MINUS: str = "sub"; break; case AND: str = "and"; break; case OR: str = "or"; break; case ER: str = "xor"; break; default: comperr("unknown hopcode: %d (with %c)", o, f); return; } printf("%s%c", str, f); } int tlen(NODE *p) { switch (p->n_type) { case CHAR: case UCHAR: return 1; case SHORT: case USHORT: return (SZSHORT / SZCHAR); case FLOAT: return (SZFLOAT / SZCHAR); case DOUBLE: return (SZDOUBLE / SZCHAR); case INT: case UNSIGNED: return (SZINT / SZCHAR); case LONG: case ULONG: case LONGLONG: case ULONGLONG: return SZLONGLONG / SZCHAR; default: if (!ISPTR(p->n_type)) comperr("tlen type unknown: %d"); return SZPOINT(p->n_type) / SZCHAR; } } void zzzcode(NODE * p, int c) { char *str; NODE *l, *r; int sz; l = p->n_left; r = p->n_right; switch (c) { case 'A': /* Add const. */ if (ISPTR(l->n_type) && l->n_rval == FP) r->n_lval += V9BIAS; if (SIMM13(r->n_lval)) expand(p, 0, "\tadd AL,AR,A1\t\t! add const\n"); else expand(p, 0, "\tsetx AR,A3,A2\t\t! add const\n" "\tadd AL,A2,A1\n"); break; case 'B': /* Subtract const. */ if (ISPTR(l->n_type) && l->n_rval == FP) r->n_lval -= V9BIAS; if (SIMM13(r->n_lval)) expand(p, 0, "\tsub AL,AR,A1\t\t! subtract const\n"); else expand(p, 0, "\tsetx AR,A3,A2\t\t! subtract const\n" "\tsub AL,A2,A1\n"); break; case 'C': /* Load constant to register. */ if (ISPTR(p->n_type)) expand(p, 0, "\tsethi %h44(AL),A1\t\t! load label\n" "\tor A1,%m44(AL),A1\n" "\tsllx A1,12,A1\n" "\tor A1,%l44(AL),A1\n"); else if (SIMM13(p->n_lval)) expand(p, 0, "\tor %g0,AL,A1\t\t\t! load const\n"); else expand(p, 0, "\tsetx AL,A2,A1\t\t! load const\n"); break; case 'F': /* Floating-point comparison, cf. hopcode(). */ switch (p->n_op) { case EQ: str = "fbe"; break; case NE: str = "fbne"; break; case ULE: case LE: str = "fbule"; break; case ULT: case LT: str = "fbul"; break; case UGE: case GE: str = "fbuge"; break; case UGT: case GT: str = "fbug"; break; /* XXX case PLUS: str = "add"; break; case MINUS: str = "sub"; break; case AND: str = "and"; break; case OR: str = "or"; break; case ER: str = "xor"; break;*/ default: comperr("unknown float code: %d", p->n_op); return; } printf(str); break; case 'Q': /* Structure assignment. */ /* TODO Check if p->n_stsize is small and use a few ldx's to move the struct instead of memcpy. The equiv. could be done on all the architectures. */ sz = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0); if (l->n_rval != O0) printf("\tmov %s,%s\n", rnames[l->n_rval], rnames[O0]); if (SIMM13(sz)) printf("\tor %%g0,%d,%%o2\n", sz); else printf("\tsetx %d,%%g1,%%o2\n", sz); printf("\tcall memcpy\t\t\t! struct assign (dest, src, len)\n"); printf("\tnop\n"); break; default: cerror("unknown zzzcode call: %c", c); } } int rewfld(NODE * p) { return (1); } int fldexpand(NODE *p, int cookie, char **cp) { printf("XXX fldexpand called\n"); /* XXX */ return 1; } int flshape(NODE * p) { return SRREG; } int shtemp(NODE * p) { return 0; } void adrcon(CONSZ val) { } void conput(FILE * fp, NODE * p) { if (p->n_op != ICON) { comperr("conput got bad op: %s", copst(p->n_op)); return; } if (p->n_name[0] != '\0') { fprintf(fp, "%s", p->n_name); if (p->n_lval > 0) fprintf(fp, "+"); if (p->n_lval) fprintf(fp, CONFMT, p->n_lval); } else fprintf(fp, CONFMT, p->n_lval); } void insput(NODE * p) { comperr("insput"); } void upput(NODE *p, int size) { comperr("upput"); } void adrput(FILE * io, NODE * p) { int64_t off; if (p->n_op == FLD) { printf("adrput a FLD\n"); p = p->n_left; } if (p->n_op == UMUL && p->n_right == 0) p = p->n_left; off = p->n_lval; switch (p->n_op) { case NAME: if (p->n_name[0] != '\0') fputs(p->n_name, io); if (off > 0) fprintf(io, "+"); if (off != 0) fprintf(io, CONFMT, (long long int)off); return; case OREG: fprintf(io, "%s", rnames[p->n_rval]); if (p->n_rval == FP) off += V9BIAS; if (p->n_rval == SP) off += V9BIAS + V9RESERVE; if (off > 0) fprintf(io, "+"); if (off) fprintf(io, CONFMT, (CONSZ)off); return; case ICON: /* addressable value of the constant */ conput(io, p); return; case REG: fputs(rnames[p->n_rval], io); return; case FUNARG: /* We do something odd and store the stack offset in n_rval. */ fprintf(io, "%d", V9BIAS + V9RESERVE + p->n_rval); return; default: comperr("bad address, %s, node %p", copst(p->n_op), p); return; } } void cbgen(int o, int lab) { } void myreader(struct interpass * ipole) { } void mycanon(NODE * p) { } void myoptim(struct interpass * ipole) { } void rmove(int s, int d, TWORD t) { printf("\t"); if (t == FLOAT) printf("fmovs"); else if (t == DOUBLE) printf("fmovd"); else printf("mov"); printf(" %s,%s\t\t\t! rmove()\n", rnames[s], rnames[d]); } int gclass(TWORD t) { if (t == FLOAT) return CLASSB; if (t == DOUBLE) return CLASSC; return CLASSA; } void lastcall(NODE *p) { } int special(NODE *p, int shape) { return SRNOPE; } void mflags(char *str) { } int COLORMAP(int c, int *r) { int num=0; switch (c) { case CLASSA: num += r[CLASSA]; return num < 32; case CLASSB: num += r[CLASSB]; num += 2*r[CLASSC]; return num < 32;; case CLASSC: num += r[CLASSC]; num += 2*r[CLASSB]; return num < 17; case CLASSD: return 0; default: comperr("COLORMAP: unknown class: %d", c); return 0; } } /* * Do something target-dependent for xasm arguments. * Supposed to find target-specific constraints and rewrite them. */ int myxasm(struct interpass *ip, NODE *p) { return 0; } pcc-20181216/arch/sparc64/macdefs.h010064400017500000000000000160501266660034000154430ustar raggewheel/* $Id: macdefs.h,v 1.18 2016/03/05 15:53:04 ragge Exp $ */ /* * Copyright (c) 2008 David Crawshaw * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Many arithmetic instructions take 'reg_or_imm' in SPARCv9, where imm * means we can use a signed 13-bit constant (simm13). This gives us a * shortcut for small constants, instead of loading them into a register. * Special handling is required because 13 bits lies between SSCON and SCON. */ #define SIMM13(val) (val < 4096 && val > -4097) /* * The SPARCv9 ABI specifies a stack bias of 2047 bits. This means that the * end of our call space is %fp+V9BIAS, working back towards %sp+V9BIAS+176. */ #define V9BIAS 2047 /* * The ABI requires that every frame reserve 176 bits for saving registers * in the case of a spill. The stack size must be 16-bit aligned. */ #define V9RESERVE 176 #define V9STEP(x) ALIGN(x, 0xf) #define ALIGN(x, y) ((x & y) ? (x + y) & ~y : x) #define makecc(val,i) lastcon = (lastcon<<8)|((val<<24)>>24); #define ARGINIT (7*8) /* XXX */ #define AUTOINIT (0) /* Type sizes */ #define SZCHAR 8 #define SZBOOL 32 #define SZINT 32 #define SZFLOAT 32 #define SZDOUBLE 64 #define SZLDOUBLE 64 #define SZLONG 64 #define SZSHORT 16 #define SZLONGLONG 64 #define SZPOINT(t) 64 /* Type alignments */ #define ALCHAR 8 #define ALBOOL 32 #define ALINT 32 #define ALFLOAT 32 #define ALDOUBLE 64 #define ALLDOUBLE 64 #define ALLONG 64 #define ALLONGLONG 64 #define ALSHORT 16 #define ALPOINT 64 #define ALSTRUCT 32 #define ALSTACK 64 /* Min/max values. */ #define MIN_CHAR -128 #define MAX_CHAR 127 #define MAX_UCHAR 255 #define MIN_SHORT -32768 #define MAX_SHORT 32767 #define MAX_USHORT 65535 #define MIN_INT -1 #define MAX_INT 0x7fffffff #define MAX_UNSIGNED 0xffffffff #define MIN_LONGLONG 0x8000000000000000LL #define MAX_LONGLONG 0x7fffffffffffffffLL #define MAX_ULONGLONG 0xffffffffffffffffULL #define MIN_LONG MIN_LONGLONG #define MAX_LONG MAX_LONGLONG #define MAX_ULONG MAX_ULONGLONG #define BOOL_TYPE INT typedef long long CONSZ; typedef unsigned long long U_CONSZ; typedef long long OFFSZ; #define CONFMT "%lld" #define LABFMT "L%d" #define STABLBL "LL%d" #define BACKAUTO /* Stack grows negatively for automatics. */ #define BACKTEMP /* Stack grows negatively for temporaries. */ #undef FIELDOPS #define TARGET_ENDIAN TARGET_BE #define BYTEOFF(x) ((x)&03) #define szty(t) ((ISPTR(t) || (t) == DOUBLE || \ (t) == LONG || (t) == ULONG || \ (t) == LONGLONG || (t) == ULONGLONG) ? 2 : 1) /* Register names. */ #define MAXREGS (31 + 31 + 16 + 2) #define NUMCLASS 4 //define G0 -1 #define G1 0 #define G2 1 #define G3 2 #define G4 3 #define G5 4 #define G6 5 #define G7 6 #define O0 7 #define O1 8 #define O2 9 #define O3 10 #define O4 11 #define O5 12 #define O6 13 #define O7 14 #define L0 15 #define L1 16 #define L2 17 #define L3 18 #define L4 19 #define L5 20 #define L6 21 #define L7 22 #define I0 23 #define I1 24 #define I2 25 #define I3 26 #define I4 27 #define I5 28 #define I6 29 #define I7 30 #define F0 31 #define F1 32 #define F2 33 #define F3 34 #define F4 35 #define F5 36 #define F6 37 #define F7 38 #define F8 39 #define F9 40 #define F10 41 #define F11 42 #define F12 43 #define F13 44 #define F14 45 #define F15 46 #define F16 47 #define F17 48 #define F18 49 #define F19 50 #define F20 51 #define F21 52 #define F22 53 #define F23 54 #define F24 55 #define F25 56 #define F26 57 #define F27 58 #define F28 59 #define F29 60 #define F30 61 //define F31 XXX #define D0 62 #define D1 63 #define D2 64 #define D3 65 #define D4 66 #define D5 67 #define D6 68 #define D7 69 #define D8 70 #define D9 71 #define D10 72 #define D11 73 #define D12 74 #define D13 75 #define D14 76 #define D15 77 #define SP 78 #define FP 79 #define FPREG FP #define RETREG(x) ((x)==DOUBLE ? D0 : (x)==FLOAT ? F1 : O0) #define RETREG_PRE(x) ((x)==DOUBLE ? D0 : (x)==FLOAT ? F1 : I0) #define RSTATUS \ /* global */ \ SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \ SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \ /* out */ \ SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ /* local */ \ SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ /* in */ \ SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ /* 32-bit floating point */ \ SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \ SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \ SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \ SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, /*, SBREG */ \ /* 64-bit floating point */ \ SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \ SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, SCREG, \ /* sp */ SDREG, \ /* fp */ SDREG #define ROVERLAP \ { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \ { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \ { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \ { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, { -1 }, \ /* 32-bit floating point */ \ { D0, -1 }, { D0, -1 }, { D1, -1 }, { D1, -1 }, \ { D2, -1 }, { D2, -1 }, { D3, -1 }, { D3, -1 }, \ { D4, -1 }, { D4, -1 }, { D5, -1 }, { D5, -1 }, \ { D6, -1 }, { D6, -1 }, { D7, -1 }, { D7, -1 }, \ { D8, -1 }, { D8, -1 }, { D9, -1 }, { D9, -1 }, \ { D10, -1 }, { D10, -1 }, { D11, -1 }, { D11, -1 }, \ { D12, -1 }, { D12, -1 }, { D13, -1 }, { D13, -1 }, \ { D14, -1 }, { D14, -1 }, { D15, -1 }, /* { D15, -1 }, */ \ /* 64-bit floating point */ \ { F0, F1, -1 }, { F2, F3, -1 }, { F4, F5, -1 }, \ { F6, F7, -1 }, { F8, F9, -1 }, { F10, F11, -1 }, \ { F12, F13, -1 }, { F14, F15, -1 }, { F16, F17, -1 }, \ { F18, F19, -1 }, { F20, F21, -1 }, { F22, F23, -1 }, \ { F24, F25, -1 }, { F26, F27, -1 }, { F28, F29, -1 }, \ { F30, /* F31, */ -1 }, \ { -1 }, \ { -1 } #define GCLASS(x) (x <= I7 ? CLASSA : \ (x <= F30 ? CLASSB : \ (x <= D15 ? CLASSC : \ (x == SP || x == FP ? CLASSD : 0)))) #define PCLASS(p) (1 << gclass((p)->n_type)) #define DECRA(x,y) (((x) >> (y*7)) & 127) #define ENCRA(x,y) ((x) << (7+y*7)) #define ENCRD(x) (x) int COLORMAP(int c, int *r); pcc-20181216/arch/sparc64/order.c010064400017500000000000000042251157264212200151470ustar raggewheel/* $Id: order.c,v 1.7 2011/06/05 08:54:42 plunky Exp $ */ /* * Copyright (c) 2008 David Crawshaw * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "pass2.h" /* is it legal to make an OREG or NAME entry which has an * offset of off, (from a register of r), if the * resulting thing had type t */ int notoff(TWORD t, int r, CONSZ off, char *cp) { return !SIMM13(off); } /* * Turn a UMUL-referenced node into OREG. */ void offstar(NODE *p, int shape) { if (x2debug) printf("offstar(%p)\n", p); if (p->n_op == PLUS || p->n_op == MINUS) { if (p->n_right->n_op == ICON && SIMM13(p->n_right->n_lval)) { if (isreg(p->n_left) == 0) (void)geninsn(p->n_left, INAREG); /* Converted in ormake() */ return; } } (void)geninsn(p, INAREG); } void myormake(NODE *q) { } int shumul(NODE *p, int shape) { if (shape & SOREG) return SROREG; return SRNOPE; } int setbin(NODE *p) { return 0; } int setasg(NODE *p, int cookie) { return 0; } int setuni(NODE *p, int cookie) { return 0; } struct rspecial * nspecial(struct optab *q) { switch (q->op) { case STASG: { static struct rspecial s[] = { { NEVER, O0 }, { NRIGHT, O1 }, { NEVER, O2 }, { 0 } }; return s; } } comperr("unknown nspecial %d: %s", q - table, q->cstring); return 0; /* XXX */ } int setorder(NODE *p) { return 0; } int * livecall(NODE *p) { static int ret[] = { O0, O1, O2, O3, O4, O5, O6, O7, -1 }; return ret; } int acceptable(struct optab *op) { return 1; } pcc-20181216/arch/sparc64/table.c010064400017500000000000000457541157264212200151370ustar raggewheel/* $Id: table.c,v 1.29 2011/06/05 08:54:42 plunky Exp $ */ /* * Copyright (c) 2008 David Crawshaw * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "pass2.h" #define TS64 TLONG|TLONGLONG #define TU64 TULONG|TULONGLONG|TPOINT #define T64 TS64|TU64 struct optab table[] = { { -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", }, /* empty */ { PCONV, INAREG, SAREG, T64|TINT, SAREG, T64, 0, RLEFT, " ! convert between word and pointer\n", }, /* Conversions. */ { SCONV, INAREG, SAREG, T64|TUNSIGNED, SAREG, TINT, NAREG|NASL, RESC1, " sra AL,0,A1 \t\t! (u)int64/32 -> (u)int32\n", }, { SCONV, INAREG, SAREG, T64|TINT|TUNSIGNED, SAREG, TSHORT, NAREG|NASL, RESC1, " sll AL,16,A1 \t\t! (u)int64/32 -> int16\n" " sra AL,16,A1\n" " sra AL, 0,A1\n", }, { SCONV, INAREG, SAREG, T64|TINT|TUNSIGNED, SAREG, TUSHORT, NAREG|NASL, RESC1, " sll AL,16,A1 \t\t! (u)int64/32 -> uint16\n" " srl AL,16,A1\n", }, { SCONV, INAREG, SAREG, T64|TINT|TUNSIGNED|TSHORT|TUSHORT, SAREG, TCHAR, NAREG|NASL, RESC1, " sll AL,24,A1 \t\t! (u)int64/32/16 -> int8\n" " sra AL,24,A1\n" " sra AL, 0,A1\n", }, { SCONV, INAREG, SAREG, T64|TINT|TUNSIGNED|TSHORT|TUSHORT, SAREG, TUCHAR, NAREG|NASL, RESC1, " and AL,0xff,A1 \t\t! (u)int64/32/16 -> uint8\n", }, { SCONV, INAREG, SAREG, T64|TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR, /* TCHAR|TUCHAR added to handle char -> long (among others) */ SAREG, T64, 0, RLEFT, " \t\t! (u)int64...8 -> (u)int64\n", }, { SCONV, INAREG, SAREG, TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG, TINT, 0, RLEFT, " \t\t! (u)int16/8 -> int32\n", }, { SCONV, INAREG, SAREG, T64|TINT|TSHORT|TCHAR, SAREG, TUNSIGNED, 0, RLEFT, " srl AL, 0,A1 \t\t! int32/16/8 -> uint32\n", }, { SCONV, INAREG, SAREG, TUSHORT|TUCHAR, SAREG, TUNSIGNED, 0, RLEFT, " \t\t! uint16/8 -> uint32\n", }, { SCONV, INBREG, SBREG, TINT|TUNSIGNED, SBREG, TFLOAT, NBREG|NASL, RESC1, " fitos AL,A1 \t\t! (u)int32 -> float\n", }, { SCONV, INBREG, SBREG, T64, SBREG, TFLOAT, NBREG|NASL, RESC1, " fxtos AL,A1 \t\t! (u)int64 -> float\n", }, { SCONV, INCREG, SCREG, TINT|TUNSIGNED, SCREG, TDOUBLE, NCREG|NASL, RESC1, " fitod AL,A1 \t\t! (u)int32 -> double\n", }, { SCONV, INCREG, SCREG, T64, SCREG, TDOUBLE, NCREG|NASL, RESC1, " fxtod AL,A1 \t\t! (u)int64 -> double\n", }, /* Floating-point conversions must be stored and loaded. */ { SCONV, INAREG, SOREG, TFLOAT, SAREG, TINT, NAREG|(2*NBREG), RESC1, " ld [AL],A2 \t\t! float -> int32\n" " nop\n" " fmovs A2,A3\n" " fstoi A2,A2\n" " st A2,[AL]\n" " nop\n" " ld [AL],A1\n" " nop\n" " st A3,[AL]\n" " nop\n", }, { SCONV, INAREG, SOREG, TDOUBLE, SAREG, TINT, NAREG|(2*NCREG), RESC1, " ld [AL],A2 \t\t! double -> int32\n" " nop\n" " fmovd A2,A3\n" " fdtoi A2,A2\n" " std A2,[AL]\n" " nop\n" " ldd [AL],A1\n" " nop\n" " std A3,[AL]\n" " nop\n", }, { SCONV, INBREG, SOREG, T64|TUNSIGNED, SBREG, TFLOAT, NBREG, RESC1, " ld [AL],A1 \t\t! int64 -> float\n" " fxtos A1,A1\n", }, { SCONV, INBREG, SOREG, TINT|TSHORT|TCHAR, SBREG, TFLOAT, NBREG, RESC1, " ld [AL],A1 \t\t! int32/16/8 -> float\n" " fitos A1,A1\n", }, // XXX need 'lds', 'ldh', etc { SCONV, INCREG, SOREG, T64|TUNSIGNED, SCREG, TDOUBLE, NCREG, RESC1, " ldd [AL],A1 \t\t! (u)int64 -> double\n" " fxtod A1,A1\n", }, { SCONV, INCREG, SOREG, TINT|TSHORT|TCHAR, SCREG, TDOUBLE, NCREG, RESC1, " ld [AL],A1 \t\t! int32/16/8 -> double\n" " fitod A1,A1\n", }, // XXX need 'lds' 'ldh' 'ld', etc. { SCONV, INBREG, SCREG, TDOUBLE, SBREG, TFLOAT, NBREG, RESC1, " fdtos AL,A1 \t\t! double -> float\n",}, { SCONV, INCREG, SBREG, TFLOAT, SCREG, TDOUBLE, NCREG, RESC1, " fstod AL,A1 \t\t! float -> double\n",}, { SCONV, INAREG, SBREG, TFLOAT, SAREG, TINT, NAREG|NBREG, RESC1, " fstoi AL,A2 \t\t! float -> int\n" " st A2,[%fp+2047]\n" " nop\n" " ld [%fp+2047],A1\n" " nop\n",}, { SCONV, INAREG, SCREG, TDOUBLE, SAREG, TINT, NAREG|NCREG, RESC1, " fdtoi AL,A2 \t\t! double -> int\n" " st A2,[%fp+2047]\n" " nop\n" " ld [%fp+2047],A1\n" " nop\n",}, /* Multiplication and division */ { MUL, INAREG, SAREG, TANY, SAREG, TANY, NAREG|NASR|NASL, RESC1, " mulx AL,AR,A1 ! multiply\n", }, { MUL, INBREG, SBREG, TFLOAT, SBREG, TFLOAT, NBREG|NBSR|NBSL, RESC1, " fmuls AL,AR,A1 ! multiply float\n", }, { MUL, INCREG, SCREG, TDOUBLE, SCREG, TDOUBLE, NCREG|NCSR|NCSL, RESC1, " fmuld AL,AR,A1 ! multiply double\n", }, { DIV, INAREG, SAREG, TUNSIGNED|TUSHORT|TUCHAR|TU64, SAREG, TUNSIGNED|TUSHORT|TUCHAR|TU64, NAREG|NASR|NASL, RESC1, " udivx AL,AR,A1 ! unsigned division\n", }, { DIV, INAREG, SAREG, TINT|TSHORT|TCHAR|TS64, SAREG, TINT|TSHORT|TCHAR|TS64, NAREG|NASR|NASL, RESC1, " sdivx AL,AR,A1 ! signed division\n", }, { DIV, INBREG, SBREG, TFLOAT, SBREG, TFLOAT, NBREG|NBSR|NBSL, RESC1, " fdivs AL,AR,A1 ! divide float\n", }, { DIV, INCREG, SCREG, TDOUBLE, SCREG, TDOUBLE, NCREG|NCSR|NCSL, RESC1, " fdivd AL,AR,A1 ! divide double\n", }, { MOD, INAREG, SAREG, TUNSIGNED|TUSHORT|TUCHAR|TU64, SAREG, TUNSIGNED|TUSHORT|TUCHAR|TU64, NAREG, RESC1, " udivx AL,AR,A1 ! unsigned modulo\n" " mulx A1,AR,A1\n" " sub AL,A1,A1\n", }, { MOD, INAREG, SAREG, TINT|TSHORT|TCHAR|TS64, SAREG, TINT|TSHORT|TCHAR|TS64, NAREG, RESC1, " sdivx AL,AR,A1 ! signed modulo\n" " mulx A1,AR,A1\n" " sub AL,A1,A1\n", }, { PLUS, INAREG, SAREG, TANY, SAREG, TANY, NAREG|NASL, RESC1, " add AL,AR,A1\n", }, { PLUS, INBREG, SBREG, TFLOAT, SBREG, TFLOAT, NBREG|NBSL, RESC1, " fadds AL,AR,A1\n", }, { PLUS, INCREG, SCREG, TDOUBLE, SCREG, TDOUBLE, NCREG|NCSL, RESC1, " faddd AL,AR,A1\n", }, { PLUS, INAREG, SAREG, TANY, SCON, TANY, (3*NAREG), RESC1, "ZA", }, { MINUS, INAREG, SAREG, TANY, SAREG, TANY, NAREG|NASL, RESC1, " sub AL,AR,A1\n", }, { MINUS, INBREG, SBREG, TANY, SBREG, TANY, NBREG|NBSL|NBSR, RESC1, " fsubs AL,AR,A1\n", }, { MINUS, INCREG, SCREG, TANY, SCREG, TANY, NCREG|NCSL|NBSR, RESC1, " fsubd AL,AR,A1\n", }, { MINUS, INAREG, SAREG, TANY, SCON, TANY, (3*NAREG), RESC1, "ZB", }, { UMINUS, INAREG, SAREG, TANY, SANY, TANY, NAREG|NASL, RESC1, " sub %g0,AL,A1\n", }, { UMINUS, INBREG, SBREG, TANY, SANY, TANY, NBREG|NBSL, RESC1, " fsubs %g0,AL,A1\n", }, { UMINUS, INCREG, SCREG, TANY, SANY, TANY, NCREG|NCSL, RESC1, " fsubd %g0,AL,A1\n", }, /* Shifts */ { RS, INAREG, SAREG, TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG|SCON, TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, " srl AL,AR,A1 ! shift right\n", }, { RS, INAREG, SAREG, T64, SAREG|SCON, T64|TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, " srlx AL,AR,A1 ! shift right\n", }, { LS, INAREG, SAREG, TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR, SAREG|SCON, TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, " sll AL,AR,A1 ! shift left\n", }, { LS, INAREG, SAREG, T64, SAREG|SCON, TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR, NAREG|NASL, RESC1, " sllx AL,AR,A1 ! shift left\n", }, { COMPL, INAREG, SAREG, TANY, SANY, TANY, NAREG|NASL, RESC1, " not AL,A1 ! complement\n", }, /* Assignments */ { ASSIGN, FOREFF|INAREG, /* FIXME: Remove [,] here and add them in adrput instead. */ SAREG|SOREG, TINT|TUNSIGNED, SAREG, TINT|TUNSIGNED, 0, RDEST, " stw AR,[AL] ! store (u)int32\n" " nop\n", }, { ASSIGN, FOREFF|INAREG, SOREG, TSHORT|TUSHORT, SAREG, TSHORT|TUSHORT, 0, RDEST, " sth AR,[AL] ! store (u)int16\n" " nop\n", }, { ASSIGN, FOREFF|INAREG, SOREG, TCHAR|TUCHAR, SAREG, TCHAR|TUCHAR, 0, RDEST, " stb AR,[AL] ! store (u)int8\n" " nop\n", }, { ASSIGN, FOREFF|INAREG, SOREG, T64, SAREG, T64, 0, RDEST, " stx AR,[AL] ! store (u)int64\n" " nop\n", }, { ASSIGN, FOREFF|INBREG, SOREG, TFLOAT, SBREG, TFLOAT, 0, RDEST, " st AR,[AL] ! store float\n" " nop\n", }, { ASSIGN, FOREFF|INBREG, SOREG, TINT, SBREG, TINT, 0, RDEST, " st AR,[AL] ! store int from fp address\n" " nop\n", }, { ASSIGN, FOREFF|INCREG, SOREG, TDOUBLE, SCREG, TDOUBLE, 0, RDEST, " std AR,[AL] ! store double\n" " nop\n", }, { ASSIGN, FOREFF|INCREG, SOREG, TINT, SCREG, TINT, 0, RDEST, " st AR,[AL] ! store int from fp address\n" " nop\n", }, { ASSIGN, FOREFF|INAREG, SNAME, TINT|TUNSIGNED, SAREG, TINT|TUNSIGNED, NAREG, RDEST, " sethi %h44(AL),A1 \t! store (u)int32 into sname\n" " or A1,%m44(AL),A1\n" " sllx A1,12,A1\n" " stw AR,[A1+%l44(AL)]\n" " nop\n", }, { ASSIGN, FOREFF|INAREG, SNAME, TSHORT|TUSHORT, SAREG, TSHORT|TUSHORT, NAREG, RDEST, " sethi %h44(AL),A1 \t! store (u)int16 into sname\n" " or A1,%m44(AL),A1\n" " sllx A1,12,A1\n" " sth AR,[A1+%l44(AL)]\n" " nop\n", }, { ASSIGN, FOREFF|INAREG, SNAME, TCHAR|TUCHAR, SAREG, TCHAR|TUCHAR, NAREG, RDEST, " sethi %h44(AL),A1 \t! store (u)int8 into sname\n" " or A1,%m44(AL),A1\n" " sllx A1,12,A1\n" " stb AR,[A1+%l44(AL)]\n" " nop\n", }, { ASSIGN, FOREFF|INAREG, SNAME, T64, SAREG, T64, NAREG, RDEST, " sethi %h44(AL),A1 \t! store (u)int64 into sname\n" " or A1,%m44(AL),A1\n" " sllx A1,12,A1\n" " stx AR,[A1+%l44(AL)]\n" " nop\n", }, { ASSIGN, FOREFF|INBREG, SNAME, TFLOAT|TINT, SBREG, TFLOAT|TINT, NAREG, RDEST, " sethi %h44(AL),A1 \t! store float into sname\n" " or A1,%m44(AL),A1\n" " sllx A1,12,A1\n" " st AR,[A1+%l44(AL)]\n" " nop\n", }, { ASSIGN, FOREFF|INCREG, SNAME, TDOUBLE, SCREG, TDOUBLE, NAREG, RDEST, " sethi %h44(AL),A1 \t! store double into sname\n" " or A1,%m44(AL),A1\n" " sllx A1,12,A1\n" " std AR,[A1+%l44(AL)]\n" " nop\n", }, { ASSIGN, FOREFF|INCREG, SNAME, TINT, SCREG, TINT, NAREG, RDEST, " sethi %h44(AL),A1 \t! store int into sname\n" " or A1,%m44(AL),A1\n" " sllx A1,12,A1\n" " st AR,[A1+%l44(AL)]\n" " nop\n", }, { ASSIGN, FOREFF|INAREG, SAREG, TANY, SAREG, TANY, 0, RDEST, " mov AR,AL ! register move\n", }, { ASSIGN, FOREFF|INBREG, SBREG, TANY, SBREG, TANY, 0, RDEST, " fmovs AR,AL ! move float\n", }, { ASSIGN, FOREFF|INCREG, SCREG, TANY, SCREG, TANY, 0, RDEST, " fmovd AR,AL ! move double\n", }, /* Structure assignment. */ { STASG, INAREG|FOREFF, SOREG|SNAME, TANY, SAREG, TPTRTO|TANY, NSPECIAL, RDEST, "ZQ", }, /* Comparisons. */ { EQ, FORCC, SAREG, TANY, SAREG, TANY, 0, RESCC, " cmp AL,AR ! eq\n" " be LC\n" " nop\n", }, { NE, FORCC, SAREG, TANY, SAREG, TANY, 0, RESCC, " cmp AL,AR ! ne\n" " bne LC\n" " nop\n", }, { OPLOG, FORCC, SAREG, TANY, SZERO, TANY, 0, RESCC, " O AL,LC\n" " nop\n", }, { OPLOG, FORCC, SAREG, TANY, SAREG, TANY, NAREG|NASL, RESCC, " sub AL,AR,A1 ! oplog\n" " O A1,LC\n" " nop\n", }, { OPLOG, FORCC, SAREG, TANY, SCCON, TANY, NAREG|NASL, RESCC, " sub AL,AR,A1 ! oplog sccon\n" " O A1,LC\n" " nop\n", }, { OPLOG, FORCC, SBREG, TFLOAT, SBREG, TFLOAT, NBREG, RESCC, " fcmps AL,AR ! oplog float\n" " ZF LC\n", }, { OPLOG, FORCC, SOREG, TFLOAT, SBREG, TFLOAT, NBREG, RESCC, " ld [AL], A1 ! oplog float oreg\n" " nop\n" " fcmps A1,AR\n" " ZF LC\n", }, { OPLOG, FORCC, SCREG, TDOUBLE, SCREG, TDOUBLE, NCREG, RESCC, " fcmpd AL,AR ! oplog double\n" " ZF LC\n", }, { OPLOG, FORCC, SOREG, TDOUBLE, SCREG, TDOUBLE, NCREG, RESCC, " ldd [AL], A1 ! oplog double oreg\n" " nop\n" " fcmpd A1,AR\n" " ZF LC\n", }, /* Load constants to register. */ { OPLTYPE, INAREG, SCON, TANY, SNAME, T64, NAREG, RESC1, " sethi %h44(AL),A1\t ! load const (u)int64 to reg\n" " or A1,%m44(AL),A1\n" " sllx A1,12,A1\n" " ldx [A1+%l44(AL)],A1\n" " nop\n", }, { OPLTYPE, INAREG, SCON, TANY, SNAME, TINT, NAREG, RESC1, " sethi %h44(AL),A1\t ! load const int32 to reg\n" " or A1,%m44(AL),A1\n" " sllx A1,12,A1\n" " ldsw [A1+%l44(AL)],A1\n" " nop\n", }, { OPLTYPE, INAREG, SCON, TANY, SNAME, TUNSIGNED, NAREG, RESC1, " sethi %h44(AL),A1\t! load const uint32 to reg\n" " or A1,%m44(AL),A1\n" " sllx A1,12,A1\n" " lduw [A1+%l44(AL)],A1\n" " nop\n", }, { OPLTYPE, INAREG, SCON, TANY, SNAME, TSHORT, NAREG, RESC1, " sethi %h44(AL),A1\t! load const int16 to reg\n" " or A1,%m44(AL),A1\n" " sllx A1,12,A1\n" " ldsh [A1+%l44(AL)],A1\n" " nop\n", }, { OPLTYPE, INAREG, SCON, TANY, SNAME, TUSHORT, NAREG, RESC1, " sethi %h44(AL),A1\t ! load const uint16 to reg\n" " or A1,%m44(AL),A1\n" " sllx A1,12,A1\n" " lduh [A1+%l44(AL)],A1\n" " nop\n", }, { OPLTYPE, INAREG, SCON, TANY, SNAME, TCHAR, NAREG, RESC1, " sethi %h44(AL),A1\t\t! load const int8 to reg\n" " or A1,%m44(AL),A1\n" " sllx A1,12,A1\n" " ldsb [A1+%l44(AL)],A1\n" " nop\n", }, { OPLTYPE, INAREG, SCON, TANY, SNAME, TUCHAR, NAREG, RESC1, " sethi %h44(AL),A1\t! load const uint8 to reg\n" " or A1,%m44(AL),A1\n" " sllx A1,12,A1\n" " ldub [A1+%l44(AL)],A1\n" " nop\n", }, { OPLTYPE, INBREG, SBREG, TANY, SNAME, TANY, NAREG|NBREG, RESC2, " sethi %h44(AL),A1\t\t! load const to fp reg\n" " or A1,%m44(AL),A1\n" " sllx A1,12,A1\n" " ld [A1+%l44(AL)],A2\n" " nop\n", }, { OPLTYPE, INCREG, SCREG, TANY, SNAME, TANY, NAREG|NCREG, RESC2, " sethi %h44(AL),A1\t\t! load const to fp reg\n" " or A1,%m44(AL),A1\n" " sllx A1,12,A1\n" " ldd [A1+%l44(AL)],A2\n" " nop\n", }, { OPLTYPE, INAREG, SANY, TANY, SCON, TANY, (2*NAREG), RESC1, "ZC" }, /* Convert LTYPE to reg. */ { OPLTYPE, INAREG, SAREG, TANY, SOREG, TCHAR, NAREG, RESC1, " ldsb [AL],A1 ! load int8 to reg\n" " nop\n", }, { OPLTYPE, INAREG, SAREG, TANY, SOREG, TUCHAR, NAREG, RESC1, " ldub [AL],A1 ! load uint8 to reg\n" " nop\n", }, { OPLTYPE, INAREG, SAREG, TANY, SOREG, TSHORT, NAREG, RESC1, " ldsh [AL],A1 ! load int16 to reg\n" " nop\n", }, { OPLTYPE, INAREG, SAREG, TANY, SOREG, TUSHORT, NAREG, RESC1, " lduh [AL],A1 ! load uint16 to reg\n" " nop\n", }, { OPLTYPE, INAREG, SAREG, TANY, SOREG, TINT, NAREG, RESC1, " ldsw [AL],A1 ! load int32 to reg\n" " nop\n", }, { OPLTYPE, INAREG, SAREG, TANY, SOREG, TUNSIGNED, NAREG, RESC1, " lduw [AL],A1 ! load uint32 to reg\n" " nop\n", }, { OPLTYPE, INAREG, SAREG, TANY, SOREG, T64, NAREG, RESC1, " ldx [AL],A1 ! load (u)int64 to reg\n" " nop\n", }, { OPLTYPE, INAREG, SANY, TANY, SZERO, TANY, NAREG, RESC1, " mov \%g0,A1\t ! load 0 to reg\n", }, { OPLTYPE, INBREG, SBREG, TFLOAT, SOREG, TFLOAT, NBREG, RESC1, " ld [AL],A1 ! load float to reg\n" " nop\n", }, { OPLTYPE, INCREG, SCREG, TDOUBLE, SOREG, TDOUBLE, NCREG, RESC1, " ldd [AL],A1 ! load double to reg\n" " nop\n", }, /* Jumps. */ { GOTO, FOREFF, SCON, TANY, SANY, TANY, 0, RNOP, " call LL ! goto LL\n" " nop\n", }, { UCALL, FOREFF, SCON, TANY, SANY, TANY, 0, 0, " call CL ! void CL()\n" " nop\n", }, { UCALL, INAREG, SCON, TANY, SAREG, TANY, NAREG, RESC1, " call CL ! = CL()\n" " nop\n", }, { CALL, FOREFF, SCON, TANY, SANY, TANY, 0, 0, " call CL ! void CL(constant)\n" " nop\n", }, { CALL, INAREG, SCON, TANY, SAREG, TANY, NAREG, RESC1, " call CL ! = CL(constant)\n" " nop\n", }, { CALL, INBREG, SCON, TANY, SBREG, TFLOAT, NBREG, RESC1, " call CL ! = CL(constant)\n" " nop\n", }, { CALL, INCREG, SCON, TANY, SCREG, TDOUBLE, NCREG, RESC1, " call CL ! = CL(constant)\n" " nop\n", }, { CALL, INAREG, SAREG, TANY, SAREG, TANY, NAREG, RESC1, " call AL ! = AL(args)\n" " nop\n", }, { CALL, FOREFF, SAREG, TANY, SANY, TANY, 0, 0, " call AL ! void AL(args)\n" " nop\n", }, { UCALL, FOREFF, SAREG, TANY, SANY, TANY, 0, 0, " call AL ! (*AL)()\n" " nop\n", }, { UCALL, INAREG, SAREG, TANY, SAREG, TANY, NAREG, RESC1, " call AL ! = (*AL)()\n" " nop\n", }, { CALL, INAREG, SAREG, TANY, SAREG, TANY, NAREG, RESC1, " call AL ! = (*AL)(args)\n" " nop\n", }, /* Function arguments. */ { FUNARG, FOREFF, SAREG, T64, SANY, TANY, 0, 0, " stx AL,[%sp+AR] \t! save func arg to stack\n" " nop\n", }, { FUNARG, FOREFF, SAREG, TINT|TUNSIGNED, SANY, TANY, 0, 0, " stw AL,[%sp+AR] \t! save func arg to stack\n" " nop\n", }, { FUNARG, FOREFF, SAREG, TSHORT|TUSHORT, SANY, TANY, 0, 0, " sth AL,[%sp+AR] \t! save func arg to stack\n" " nop\n", }, { FUNARG, FOREFF, SAREG, TCHAR|TUCHAR, SANY, TANY, 0, 0, " stb AL,[%sp+AR] \t! save func arg to stack\n" " nop\n", }, { FUNARG, FOREFF, SBREG, TFLOAT, SANY, TANY, 0, 0, " st AL,[%sp+AR] \t! save func arg to stack\n" " nop\n", }, { FUNARG, FOREFF, SCREG, TDOUBLE, SANY, TANY, 0, 0, " std AL,[%sp+AR] \t! save func arg to stack\n" " nop\n", }, /* Indirection. */ { OPSIMP, INAREG, SAREG, TANY, SAREG, TANY, NAREG|NASR|NASL, RESC1, " O AL,AR,A1\n", }, { UMUL, INAREG, SAREG, T64, SOREG, T64, NAREG, RESC1, " ldx [AL],A1 ! (u)int64 load\n" " nop\n", }, { UMUL, INAREG, SAREG, TINT, SOREG, TINT, NAREG, RESC1, " ldsw [AL],A1 ! int32 load\n" " nop\n", }, { UMUL, INAREG, SAREG, TUNSIGNED, SOREG, TUNSIGNED, NAREG, RESC1, " lduw [AL],A1 ! uint32 load\n" " nop\n", }, { UMUL, INAREG, SAREG, TCHAR, SOREG, TCHAR, NAREG, RESC1, " ldsb [AL],A1 ! int8 load\n" " nop\n", }, { UMUL, INAREG, SAREG, TUCHAR, SOREG, TUCHAR, NAREG, RESC1, " ldub [AL],A1 ! uint8 load\n" " nop\n", }, { UMUL, INAREG, SAREG, TSHORT, SOREG, TSHORT, NAREG, RESC1, " ldsh [AL],A1 ! int16 load\n" " nop\n", }, { UMUL, INAREG, SAREG, TUSHORT, SOREG, TUSHORT, NAREG, RESC1, " lduh [AL],A1 ! uint16 load\n" " nop\n", }, { UMUL, INBREG, SAREG, TFLOAT, SOREG, TFLOAT, NBREG, RESC1, " ld [AL],A1 ! load float\n" " nop\n", }, { UMUL, INCREG, SAREG, TDOUBLE, SOREG, TDOUBLE, NCREG, RESC1, " ldd [AL],A1 ! load double\n" " nop\n", }, { FREE,FREE,FREE,FREE,FREE,FREE,FREE,FREE, "ERR: printing free op\n" }, }; int tablesize = sizeof(table)/sizeof(table[0]); pcc-20181216/arch/superh004075500017500000000000000000001340533064000136315ustar raggewheelpcc-20181216/arch/superh/CVS004075500017500000000000000000001340533064000142645ustar raggewheelpcc-20181216/arch/superh/CVS/Root010064400017500000000000000000111340533064000151760ustar raggewheel/cvsroot pcc-20181216/arch/superh/CVS/Repository010064400017500000000000000000201340533064000164320ustar raggewheelpcc/arch/superh pcc-20181216/arch/superh/CVS/Entries010064400017500000000000000000021340533064000156640ustar raggewheelD pcc-20181216/arch/vax004075500017500000000000000000001340533064000131215ustar raggewheelpcc-20181216/arch/vax/CVS004075500017500000000000000000001340533064000135545ustar raggewheelpcc-20181216/arch/vax/CVS/Root010064400017500000000000000000111340533064000144660ustar raggewheel/cvsroot pcc-20181216/arch/vax/CVS/Repository010064400017500000000000000000151340533064000157260ustar raggewheelpcc/arch/vax pcc-20181216/arch/vax/CVS/Entries010064400017500000000000000003721340533064000151660ustar raggewheel/code.c/1.28/Tue Apr 3 14:49:46 2018// /local.c/1.34/Wed Apr 4 17:34:07 2018// /local2.c/1.44/Tue Apr 3 14:49:46 2018// /macdefs.h/1.23/Sat Mar 5 15:53:04 2016// /order.c/1.11/Wed Apr 11 07:27:35 2018// /table.c/1.28/Sun Oct 12 10:05:28 2014// D pcc-20181216/arch/vax/code.c010064400017500000000000000245761326071221200142670ustar raggewheel/* $Id: code.c,v 1.28 2018/04/03 14:49:46 ragge Exp $ */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code and documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditionsand the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ # include "pass1.h" #ifndef LANG_CXX #define NODE P1ND #undef NIL #define NIL NULL #define tfree p1tfree #define talloc p1alloc #define ccopy p1tcopy #endif /* * Print out assembler segment name. */ void setseg(int seg, char *name) { switch (seg) { case PROG: name = ".text"; break; case DATA: case LDATA: name = ".data"; break; case STRNG: case RDATA: name = ".section .rodata"; break; case UDATA: break; case DTORS: name = ".section .dtors,\"aw\",@progbits"; break; case CTORS: name = ".section .ctors,\"aw\",@progbits"; break; case TLSDATA: case TLSUDATA: uerror("FIXME: unsupported segment %d", seg); break; case PICRDATA: name = ".section .data.rel.ro.local,\"aw\",@progbits"; break; case PICDATA: name = ".section .data.rel,\"aw\",@progbits"; break; case PICLDATA: name = ".section .data.rel.local,\"aw\",@progbits"; break; case NMSEG: printf("\t.section %s,\"a%c\",@progbits\n", name, cftnsp ? 'x' : 'w'); return; } printf("\t%s\n", name); } /* * Define everything needed to print out some data (or text). * This means segment, alignment, visibility, etc. */ void defloc(struct symtab *sp) { char *name; name = getexname(sp); if (sp->sclass == EXTDEF) { printf("\t.globl %s\n", name); if (ISFTN(sp->stype)) { printf("\t.type %s,@function\n", name); } else { printf("\t.type %s,@object\n", name); printf("\t.size %s,%d\n", name, (int)tsize(sp->stype, sp->sdf, sp->sap)/SZCHAR); } } if (sp->slevel == 0) printf("%s:\n", name); else printf(LABFMT ":\n", sp->soffset); } static int strtemp; void efcode(void) { TWORD t; NODE *p, *q; /* code for the end of a function */ if (cftnsp->stype != STRTY+FTN && cftnsp->stype != UNIONTY+FTN) return; t = PTR+BTYPE(cftnsp->stype); /* Create struct assignment */ q = tempnode(strtemp, t, 0, cftnsp->sap); q = buildtree(UMUL, q, NIL); p = block(REG, NIL, NIL, t, 0, cftnsp->sap); regno(p) = R0; p = buildtree(UMUL, p, NIL); p = buildtree(ASSIGN, q, p); ecomp(p); /* put hidden arg in r0 on return */ q = tempnode(strtemp, INT, 0, 0); p = block(REG, NIL, NIL, INT, 0, 0); regno(p) = R0; ecomp(buildtree(ASSIGN, p, q)); } void bfcode(struct symtab **sp, int n) { struct symtab *sp2; NODE *p, *q; int i, argbase, sz; if (cftnsp->stype == STRTY+FTN || cftnsp->stype == UNIONTY+FTN) { /* Move return address into temporary */ p = tempnode(0, INT, 0, 0); strtemp = regno(p); q = block(REG, 0, 0, INT, 0, 0); regno(q) = R1; ecomp(buildtree(ASSIGN, p, q)); } /* correct arg alignment XXX should be done somewhere else */ argbase = ARGINIT; for (i = 0; i < n; i++) { sp2 = sp[i]; sz = tsize(sp2->stype, sp2->sdf, sp2->sap); SETOFF(sz, SZINT); sp2->soffset = argbase; argbase += sz; } if (xtemps == 0) return; /* put arguments in temporaries */ for (i = 0; i < n; i++) { if (sp[i]->stype == STRTY || sp[i]->stype == UNIONTY || cisreg(sp[i]->stype) == 0) continue; if (cqual(sp[i]->stype, sp[i]->squal) & VOL) continue; sp2 = sp[i]; p = tempnode(0, sp[i]->stype, sp[i]->sdf, sp[i]->sap); p = buildtree(ASSIGN, p, nametree(sp2)); sp[i]->soffset = regno(p->n_left); sp[i]->sflags |= STNODE; ecomp(p); } } void ejobcode(int flag) { /* called just before final exit */ /* flag is 1 if errors, 0 if none */ } void bjobcode(void) { astypnames[INT] = astypnames[UNSIGNED] = "\t.long"; astypnames[SHORT] = astypnames[USHORT] = "\t.word"; } #if 0 aobeg(void) { /* called before removing automatics from stab */ } aocode(struct symtab *p) { /* called when automatic p removed from stab */ } aoend(void) { /* called after removing all automatics from stab */ } #endif void fldty(struct symtab *p) { /* fix up type of field p */ } /* * XXX - fix genswitch. */ int mygenswitch(int num, TWORD type, struct swents **p, int n) { return 0; } #ifdef notyet struct sw heapsw[SWITSZ]; /* heap for switches */ genswitch(register struct sw *p, int n) { /* p points to an array of structures, each consisting of a constant value and a label. The first is >=0 if there is a default label; its value is the label number The entries p[1] to p[n] are the nontrivial cases */ register i; register CONSZ j, range; register dlab, swlab; range = p[n].sval-p[1].sval; if( range>0 && range <= 3*n && n>=4 ){ /* implement a direct switch */ swlab = getlab(); dlab = p->slab >= 0 ? p->slab : getlab(); /* already in r0 */ printf(" casel r0,$%ld,$%ld\n", p[1].sval, range); deflab1(swlab); for( i=1,j=p[1].sval; i<=n; j++) { printf(" .word " LABFMT "-" LABFMT "\n", (j == p[i].sval ? ((j=p[i++].sval), p[i-1].slab) : dlab), swlab); } if( p->slab >= 0 ) branch( dlab ); else deflab1(dlab); return; } if( n>8 ) { /* heap switch */ heapsw[0].slab = dlab = p->slab >= 0 ? p->slab : getlab(); makeheap(p, n, 1); /* build heap */ walkheap(1, n); /* produce code */ if( p->slab >= 0 ) branch( dlab ); else deflab1(dlab); return; } /* debugging code */ /* out for the moment if( n >= 4 ) werror( "inefficient switch: %d, %d", n, (int) (range/n) ); */ /* simple switch code */ for( i=1; i<=n; ++i ){ /* already in r0 */ printf( " cmpl r0,$" ); printf( CONFMT, p[i].sval ); printf( "\n jeql " LBLFMT "\n", p[i].slab ); } if( p->slab>=0 ) branch( p->slab ); } makeheap(register struct sw *p, int m, int n) { register int q; q = select(m); heapsw[n] = p[q]; if( q>1 ) makeheap(p, q-1, 2*n); if( q m ) break; l = ((k = i/2 - 1) + 1)/2; return( l + (m-k < l ? m-k : l)); } walkheap(int start, int limit) { int label; if( start > limit ) return; printf(" cmpl r0,$%d\n", heapsw[start].sval); printf(" jeql " LBLFMT "\n", heapsw[start].slab); if( (2*start) > limit ) { printf(" jbr " LBLFMT "\n", heapsw[0].slab); return; } if( (2*start+1) <= limit ) { label = getlab(); printf(" jgtr " LBLFMT "\n", label); } else printf(" jgtr " LBLFMT "\n", heapsw[0].slab); walkheap( 2*start, limit); if( (2*start+1) <= limit ) { deflab1(label); walkheap( 2*start+1, limit); } } #endif /* * Called with a function call with arguments as argument. * This is done early in buildtree() and only done once. */ NODE * funcode(NODE *p) { NODE *r, *l; /* Fix function call arguments. On vax, just add funarg */ for (r = p->n_right; r->n_op == CM; r = r->n_left) { if (r->n_right->n_op != STARG) { r->n_right = intprom(r->n_right); r->n_right = block(FUNARG, r->n_right, NIL, r->n_right->n_type, r->n_right->n_df, r->n_right->n_ap); } } if (r->n_op != STARG) { l = talloc(); *l = *r; r->n_op = FUNARG; r->n_left = l; r->n_left = intprom(r->n_left); r->n_type = r->n_left->n_type; } return p; } /* * Generate the builtin code for FFS. */ NODE * builtin_ffs(const struct bitable *bt, NODE *a) { NODE *p, *q, *r; p = tempnode(0, bt->rt, 0, 0); r = block(XARG, ccopy(p), NIL, INT, 0, 0); r->n_name = "=&r"; q = block(XARG, a, NIL, INT, 0, 0); q->n_name = "g"; q = block(CM, r, q, INT, 0, 0); q = block(XASM, q, block(ICON, 0, 0, STRTY, 0, 0), INT, 0, 0); q->n_name = "ffs $0,$32,%1,%0;bneq 1f;mnegl $1,%0;1:;incl %0"; p = block(COMOP, q, p, bt->rt, 0, 0); return p; } NODE * builtin_ffsl(const struct bitable *bt, NODE *a) { return builtin_ffs(bt, a); } NODE * builtin_ffsll(const struct bitable *bt, NODE *a) { cerror("builtin_ffsll unimplemented"); return NIL; } NODE * builtin_return_address(const struct bitable *bt, NODE *a) { NODE *f; int v; if (a->n_op != ICON) goto bad; v = glval(a); tfree(a); if (v != 0) { werror("unsupported argument"); return xbcon(0, NULL, VOID|PTR); } f = block(REG, NIL, NIL, INCREF(PTR+CHAR), 0, 0); regno(f) = FPREG; f = block(UMUL, block(PLUS, f, bcon(16), INCREF(PTR+CHAR), 0, 0), NIL, PTR+CHAR, 0, 0); f = makety(f, PTR+VOID, 0, 0, 0); return f; bad: uerror("bad argument to __builtin_return_address"); return bcon(0); } NODE * builtin_frame_address(const struct bitable *bt, NODE *a) { int nframes; NODE *f; if (a->n_op != ICON) goto bad; nframes = glval(a); tfree(a); f = block(REG, NIL, NIL, PTR+CHAR, 0, 0); regno(f) = FPREG; while (nframes--) { f = block(UMUL, block(PLUS, f, bcon(12), INCREF(PTR+CHAR), 0, 0), NIL, PTR+CHAR, 0, 0); f = makety(f, PTR+CHAR, 0, 0, 0); } return f; bad: uerror("bad argument to __builtin_frame_address"); return bcon(0); } /* * Return "canonical frame address". */ NODE * builtin_cfa(const struct bitable *bt, NODE *a) { uerror("missing builtin_cfa"); return bcon(0); } pcc-20181216/arch/vax/local.c010064400017500000000000000210211326120621700144310ustar raggewheel/* $Id: local.c,v 1.34 2018/04/04 17:34:07 ragge Exp $ */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code and documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditionsand the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ # include "pass1.h" #ifndef LANG_CXX #define NODE P1ND #undef NIL #define NIL NULL #define nfree p1nfree #define fwalk p1fwalk #endif static void r1arg(NODE *p, NODE *q); #define IALLOC(sz) (isinlining ? permalloc(sz) : tmpalloc(sz)) /* this file contains code which is dependent on the target machine */ NODE * clocal(p) NODE *p; { /* this is called to do local transformations on an expression tree preparitory to its being written out in intermediate code. */ /* the major essential job is rewriting the automatic variables and arguments in terms of REG and OREG nodes */ /* conversion ops which are not necessary are also clobbered here */ /* in addition, any special features (such as rewriting exclusive or) are easily handled here as well */ register struct symtab *q; register NODE *r, *l; register int o; register int ml; #ifdef PCC_DEBUG if (xdebug) { printf("clocal(%p)\n", p); if (xdebug>1) fwalk(p, eprint, 0); } #endif switch( o = p->n_op ){ case NAME: if((q = p->n_sp) == 0 ) { /* already processed; ignore... */ return(p); } switch( q->sclass ){ case REGISTER: case AUTO: case PARAM: /* fake up a structure reference */ r = block( REG, NIL, NIL, PTR+STRTY, 0, 0 ); slval(r, 0); regno(r) = q->sclass==PARAM?ARGREG:FPREG; p = stref( block( STREF, r, p, 0, 0, 0 ) ); break; } break; case FORCE: p->n_op = ASSIGN; p->n_right = p->n_left; p->n_left = block(REG, NIL, NIL, p->n_type, 0, 0); p->n_left->n_rval = p->n_left->n_type == BOOL ? RETREG(CHAR) : RETREG(p->n_type); break; case SCONV: l = p->n_left; ml = p->n_type; #if 0 if (ml == INT && l->n_type == UNSIGNED) { p = nfree(p); break; } #endif if (l->n_op == ICON) { if (l->n_sp == 0) { p->n_type = UNSIGNED; concast(l, p->n_type); } else if (ml != INT && ml != UNSIGNED) break; l->n_type = ml; l->n_ap = 0; p = nfree(p); break; } break; case STCALL: /* see if we have been here before */ for (r = p->n_right; r->n_op == CM; r = r->n_left) ; if (r->n_op == ASSIGN) break; /* FALLTHROUGH */ case USTCALL: /* Allocate buffer on stack to bounce via */ /* create fake symtab here */ q = getsymtab("77fake", STEMP); q->stype = BTYPE(p->n_type); q->sdf = p->n_df; q->sap = p->n_ap; q->soffset = NOOFFSET; q->sclass = AUTO; oalloc(q, &autooff); r1arg(p, buildtree(ADDROF, nametree(q), 0)); break; } #ifdef PCC_DEBUG if (xdebug) { printf("clocal end(%p)\n", p); if (xdebug>1) fwalk(p, eprint, 0); } #endif return(p); } /* * Add R1 with the dest address as arg to a struct return call. */ static void r1arg(NODE *p, NODE *q) { NODE *r; r = block(REG, NIL, NIL, PTR|VOID, 0, 0); regno(r) = R1; r = buildtree(ASSIGN, r, q); if (p->n_op == USTCALL) { p->n_op = STCALL; p->n_right = r; } else if (p->n_right->n_op != CM) { p->n_right = block(CM, r, p->n_right, INT, 0, 0); } else { for (q = p->n_right; q->n_left->n_op == CM; q = q->n_left) ; q->n_left = block(CM, r, q->n_left, INT, 0, 0); } } void myp2tree(NODE *p) { struct symtab *sp; if ((cdope(p->n_op) & CALLFLG) && p->n_left->n_op == ADDROF && p->n_left->n_left->n_op == NAME) { NODE *q = p->n_left->n_left; nfree(p->n_left); p->n_left = q; q->n_op = ICON; } if (p->n_op != FCON) return; sp = IALLOC(sizeof(struct symtab)); sp->sclass = STATIC; sp->sap = 0; sp->slevel = 1; /* fake numeric label */ sp->soffset = getlab(); sp->sflags = 0; sp->stype = p->n_type; sp->squal = (CON >> TSHIFT); sp->sname = NULL; locctr(DATA, sp); defloc(sp); inval(0, tsize(sp->stype, sp->sdf, sp->sap), p); p->n_op = NAME; slval(p, 0); p->n_sp = sp; } /* * Can we take & of a NAME? */ int andable(NODE *p) { /* for now, delay name reference to table, for PIC code generation */ /* functions are called by name, convert they in myp2tree */ return 0; } /* is an automatic variable of type t OK for a register variable */ int cisreg(TWORD t) { return(1); /* all are now */ } /* * Allocate off bits on the stack. p is a tree that when evaluated * is the multiply count for off, t is a storeable node where to write * the allocated address. */ void spalloc(NODE *t, NODE *p, OFFSZ off) { NODE *sp; p = buildtree(MUL, p, bcon(off/SZCHAR)); /* XXX word alignment? */ /* sub the size from sp */ sp = block(REG, NIL, NIL, p->n_type, 0, 0); slval(sp, 0); sp->n_rval = STKREG; ecomp(buildtree(MINUSEQ, sp, p)); /* save the address of sp */ sp = block(REG, NIL, NIL, PTR+INT, t->n_df, t->n_ap); slval(sp, 0); sp->n_rval = STKREG; t->n_type = sp->n_type; ecomp(buildtree(ASSIGN, t, sp)); /* Emit! */ } char * exname( p ) char *p; { /* make a name look like an external name in the local machine */ /* vad is elf now */ if (p == NULL) return ""; return( p ); } /* map types which are not defined on the local machine */ TWORD ctype(TWORD type) { switch( BTYPE(type) ){ case LONG: MODTYPE(type,INT); break; case ULONG: MODTYPE(type,UNSIGNED); break; case LDOUBLE: /* for now */ MODTYPE(type,DOUBLE); } return( type ); } void calldec(NODE *p, NODE *q) { } void extdec(struct symtab *q) { } /* make a common declaration for id, if reasonable */ void defzero(struct symtab *sp) { int off, al; char *name; name = getexname(sp); off = tsize(sp->stype, sp->sdf, sp->sap); SETOFF(off,SZCHAR); off /= SZCHAR; al = talign(sp->stype, sp->sap)/SZCHAR; if (sp->sclass == STATIC) { if (sp->slevel == 0) printf("\t.local %s\n", name); else printf("\t.local " LABFMT "\n", sp->soffset); } if (sp->slevel == 0) { printf("\t.comm %s,0%o,%d\n", name, off, al); } else printf("\t.comm " LABFMT ",0%o,%d\n", sp->soffset, off, al); } /* * print out a constant node, may be associated with a label. * Do not free the node after use. * off is bit offset from the beginning of the aggregate * fsz is the number of bits this is referring to * XXX - floating point constants may be wrong if cross-compiling. */ int ninval(CONSZ off, int fsz, NODE *p) { union { float f; double d; long double l; int i[3]; } u; switch (p->n_type) { case LDOUBLE: u.i[2] = 0; u.l = (long double)((FLT *)p->n_dcon)->fp; printf("\t.long\t0x%x,0x%x,0x%x\n", u.i[0], u.i[1], u.i[2]); break; case DOUBLE: u.d = (double)((FLT *)p->n_dcon)->fp; printf("\t.long\t0x%x,0x%x\n", u.i[0], u.i[1]); break; case FLOAT: u.f = (float)((FLT *)p->n_dcon)->fp; printf("\t.long\t0x%x\n", u.i[0]); break; default: return 0; } return 1; } /* * Give target the opportunity of handling pragmas. */ int mypragma(char *str) { return 0; } /* * Called when a identifier has been declared, to give target last word. */ void fixdef(struct symtab *sp) { } void pass1_lastchance(struct interpass *ip) { } pcc-20181216/arch/vax/local2.c010064400017500000000000000742001326071221200145160ustar raggewheel/* $Id: local2.c,v 1.44 2018/04/03 14:49:46 ragge Exp $ */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code and documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditionsand the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ # include "pass2.h" # include "ctype.h" /* a lot of the machine dependent parts of the second pass */ static void prtype(NODE *n); static void acon(NODE *p); /* * Print out the prolog assembler. * addto and regoff are already calculated. */ void prologue(struct interpass_prolog *ipp) { printf(" .word 0x%llx\n", (unsigned long long)p2env.p_regs[0]); if (p2maxautooff) printf(" subl2 $%d,%%sp\n", p2maxautooff); if (pflag) { int i = getlab2(); printf("\tmovab\t" LABFMT ",%%r0\n", i); printf("\tjsb\t__mcount\n"); printf("\t.data\n"); printf("\t.align 2\n"); printf(LABFMT ":\t.long\t0\n", i); printf("\t.text\n"); } } /* * Called after all instructions in a function are emitted. * Generates code for epilog here. */ void eoftn(struct interpass_prolog *ipp) { if (ipp->ipp_ip.ip_lbl == 0) return; /* no code needs to be generated */ printf(" ret\n"); } struct hoptab { int opmask; char * opstring; } ioptab[] = { { PLUS, "add", }, { MINUS, "sub", }, { MUL, "mul", }, { DIV, "div", }, { OR, "bis", }, { ER, "xor", }, { AND, "bic", }, { -1, "" }, }; void hopcode( f, o ){ /* output the appropriate string from the above table */ register struct hoptab *q; for( q = ioptab; q->opmask>=0; ++q ){ if( q->opmask == o ){ printf( "%s", q->opstring ); /* tbl if( f == 'F' ) printf( "e" ); else if( f == 'D' ) printf( "d" ); tbl */ /* tbl */ switch( f ) { case 'L': case 'W': case 'B': case 'D': case 'F': printf("%c", tolower(f)); break; } /* tbl */ return; } } cerror( "no hoptab for %s", opst[o] ); } char * rnames[] = { /* keyed to register number tokens */ "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7", "%r8", "%r9", "%r10", "%r11", "%ap", "%fp", "%sp", "%pc", /* The concatenated regs has the name of the lowest */ "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7", "%r8", "%r9", "%r10" }; int tlen(NODE *p) { switch(p->n_type) { case CHAR: case UCHAR: return(1); case SHORT: case USHORT: return(2); case DOUBLE: case LONGLONG: case ULONGLONG: return(8); default: return(4); } } void prtype(NODE *n) { static char pt[] = { 0, 0, 'b', 'b', 'w', 'w', 'l', 'l', 0, 0, 'q', 'q', 'f', 'd' }; TWORD t = n->n_type; if (ISPTR(t)) t = UNSIGNED; if (t > DOUBLE || pt[t] == 0) comperr("prtype: bad type"); putchar(pt[t]); } /* * Emit conversions as given by the following table. Dest is always reg, * if it should be something else let peephole optimizer deal with it. * This code ensures type correctness in 32-bit registers. * XXX is that necessary? * * From To * char uchar short ushort int uint ll ull float double * char movb movb cvtbw cvtbw cvtbl cvtbl A A cvtbf cvtbd * uchar movb movb movzbw movzbw movzbl movzbl B B G G * short movb movb movw movw cvtwl cvtwl C(A) C(A) cvtwf cvtwd * ushrt movb movb movw movw movzwl movzwl D(B) D(B) H H * int movb movb movw movw movl movl E E cvtlf cvtld * uint movb movb movw movw movl movl F F I I * ll movb movb movw movw movl movl movq movq J K * ull movb movb movw movw movl movl movq movq L M * float cvtfb cvtfb cvtfw cvtfw cvtfl cvtfl N O movf cvtfd * doubl cvtdb cvtdb cvtdw cvtdw cvtdl cvtdl P Q cvtdf movd * * A: cvtbl + sign extend * B: movzbl + zero extend * G: movzbw + cvtwX * H: movzwl + cvtwX * I: cvtld + addX * J: call __floatdisf * K: call __floatdidf * L: xxx + call __floatdisf * M: xxx + call __floatdidf * N: call __fixsfdi * O: call __fixunssfdi * P: call __fixdfdi * Q: call __fixunsdfdi */ #define MVD 1 /* mov + dest type */ #define CVT 2 /* cvt + src type + dst type */ #define MVZ 3 /* movz + src type + dst type */ #define CSE 4 /* cvt + src type + l + sign extend upper */ #define MZE 5 /* movz + src type + l + zero extend upper */ #define MLE 6 /* movl + sign extend upper */ #define MLZ 7 /* movl + zero extend upper */ #define MZC 8 /* movz + cvt */ static char scary[][10] = { { MVD, MVD, CVT, CVT, CVT, CVT, CSE, CSE, CVT, CVT }, { MVD, MVD, MVZ, MVZ, MVZ, MVZ, MZE, MZE, MZC, MZC }, { MVD, MVD, MVD, MVD, CVT, CVT, CSE, CSE, CVT, CVT }, { MVD, MVD, MVD, MVD, MVZ, MVZ, MZE, MZE, MZC, MZC }, { MVD, MVD, MVD, MVD, MVD, MVD, MLE, MLE, CVT, CVT }, { MVD, MVD, MVD, MVD, MVD, MVD, MLZ, MLZ, 'I', 'I' }, { MVD, MVD, MVD, MVD, MVD, MVD, MVD, MVD, 'J', 'K' }, { MVD, MVD, MVD, MVD, MVD, MVD, MVD, MVD, 'L', 'M' }, { CVT, CVT, CVT, CVT, CVT, CVT, 'N', 'O', MVD, CVT }, { CVT, CVT, CVT, CVT, CVT, CVT, 'P', 'Q', CVT, MVD }, }; static void sconv(NODE *p) { NODE *l = p->n_left; TWORD ts, td; int o; /* * Source node may be in register or memory. * Result is always in register. */ ts = l->n_type; if (ISPTR(ts)) ts = UNSIGNED; td = p->n_type; ts = ts < LONG ? ts-2 : ts-4; td = td < LONG ? td-2 : td-4; o = scary[ts][td]; switch (o) { case MLE: case MLZ: expand(p, INAREG|INBREG, "\tmovl\tAL,A1\n"); break; case MVD: if (l->n_op == REG && regno(l) == regno(getlr(p, '1'))) break; /* unneccessary move */ expand(p, INAREG|INBREG, "\tmovZR\tAL,A1\n"); break; case CSE: expand(p, INAREG|INBREG, "\tcvtZLl\tAL,A1\n"); break; case CVT: expand(p, INAREG|INBREG, "\tcvtZLZR\tAL,A1\n"); break; case MZE: expand(p, INAREG|INBREG, "\tmovzZLl\tAL,A1\n"); break; case MVZ: expand(p, INAREG|INBREG, "\tmovzZLZR\tAL,A1\n"); break; case MZC: expand(p, INAREG|INBREG, "\tmovzZLl\tAL,A1\n"); expand(p, INAREG|INBREG, "\tcvtlZR\tA1,A1\n"); break; case 'I': /* unsigned to double */ expand(p, INAREG|INBREG, "\tcvtld\tAL,A1\n"); printf("\tjgeq\t1f\n"); expand(p, INAREG|INBREG, "\taddd2\t$0d4.294967296e+9,A1\n"); printf("1:\n"); break; default: comperr("unsupported conversion %d", o); } switch (o) { case MLE: case CSE: expand(p, INBREG, "\tashl\t$-31,A1,U1\n"); break; case MLZ: case MZE: expand(p, INAREG|INBREG, "\tclrl\tU1\n"); break; } } /* * Assign a constant from p to q. Both are expected to be leaves by now. * This is for 64-bit integers. */ static void casg64(NODE *p) { NODE *l, *r; char *str; int mneg = 1; l = p->n_left; r = p->n_right; #ifdef PCC_DEBUG if (r->n_op != ICON) comperr("casg"); #endif if (r->n_name[0] != '\0') { /* named constant, nothing to do */ str = "movq\tAR,AL"; mneg = 0; } else if (getlval(r) == 0) { str = "clrq\tAL"; mneg = 0; } else if (getlval(r) < 0) { if (getlval(r) >= -63) { setlval(r, -getlval(r)); str = "mnegl\tAR,AL"; } else if (getlval(r) >= -128) { str = "cvtbl\tAR,AL"; } else if (getlval(r) >= -32768) { str = "cvtwl\tAR,AL"; } else if (getlval(r) >= -4294967296LL) { str = "movl\tAR,AL"; } else { str = "movq\tAR,AL"; mneg = 0; } } else { mneg = 0; if (getlval(r) <= 63 || getlval(r) > 4294967295LL) { str = "movq\tAR,AL"; } else if (getlval(r) <= 255) { str = "movzbl\tAR,AL\n\tclrl\tUL"; } else if (getlval(r) <= 65535) { str = "movzwl\tAR,AL\n\tclrl\tUL"; } else /* if (getlval(r) <= 4294967295) */ { str = "movl\tAR,AL\n\tclrl\tUL"; } } expand(p, FOREFF, str); if (mneg) expand(p, FOREFF, "\n\tmnegl $1,UL"); } /* * Assign a constant from p to q. Both are expected to be leaves by now. * This is only for 32-bit integer types. */ static void casg(NODE *p) { NODE *l, *r; char *str; l = p->n_left; r = p->n_right; #ifdef PCC_DEBUG if (r->n_op != ICON) comperr("casg"); #endif if (r->n_name[0] != '\0') { /* named constant, nothing to do */ str = "movZL\tAR,AL"; } else if (getlval(r) == 0) { str = "clrZL\tAL"; } else if (getlval(r) < 0) { if (getlval(r) >= -63) { setlval(r, -getlval(r)); str = "mnegZL\tAR,AL"; } else if (getlval(r) >= -128) { if (l->n_type == CHAR) str = "movb\tAR,AL"; else str = "cvtbZL\tAR,AL"; } else if (getlval(r) >= -32768) { if (l->n_type == SHORT) str = "movw\tAR,AL"; else str = "cvtwZL\tAR,AL"; } else str = "movZL\tAR,AL"; } else { if (getlval(r) <= 63 || getlval(r) > 65535) { str = "movZL\tAR,AL"; } else if (getlval(r) <= 255) { str = l->n_type < SHORT ? "movb\tAR,AL" : "movzbZL\tAR,AL"; } else /* if (getlval(r) <= 65535) */ { str = l->n_type < INT ? "movw\tAR,AL" : "movzwZL\tAR,AL"; } } expand(p, FOREFF, str); } /* * Emit code to compare two longlong numbers. */ static void twollcomp(NODE *p) { int u; int s = getlab2(); int e = p->n_label; int cb1, cb2; u = p->n_op; switch (p->n_op) { case NE: cb1 = 0; cb2 = NE; break; case EQ: cb1 = NE; cb2 = 0; break; case LE: case LT: u += (ULE-LE); /* FALLTHROUGH */ case ULE: case ULT: cb1 = GT; cb2 = LT; break; case GE: case GT: u += (ULE-LE); /* FALLTHROUGH */ case UGE: case UGT: cb1 = LT; cb2 = GT; break; default: cb1 = cb2 = 0; /* XXX gcc */ } if (p->n_op >= ULE) cb1 += 4, cb2 += 4; expand(p, 0, " cmpl UL,UR\n"); if (cb1) cbgen(cb1, s); if (cb2) cbgen(cb2, e); expand(p, 0, " cmpl AL,AR\n"); cbgen(u, e); deflab(s); } void zzzcode(NODE *p, int c) { NODE *l, *r; TWORD t; int m; char *ch; switch (c) { case 'N': /* logical ops, turned into 0-1 */ /* use register given by register 1 */ cbgen( 0, m=getlab2()); deflab( p->n_label ); printf( " clrl %s\n", rnames[getlr( p, '1' )->n_rval] ); deflab( m ); return; case 'A': /* Assign a constant directly to a memory position */ printf("\t"); if (p->n_type < LONG || ISPTR(p->n_type)) casg(p); else casg64(p); printf("\n"); break; case 'B': /* long long compare */ twollcomp(p); break; case 'C': /* num words pushed on arg stack */ printf("$%d", p->n_qual); break; case 'D': /* INCR and DECR */ zzzcode(p->n_left, 'A'); printf("\n "); #if 0 case 'E': /* INCR and DECR, FOREFF */ if (getlval(p->n_right) == 1) { printf("%s", (p->n_op == INCR ? "inc" : "dec") ); prtype(p->n_left); printf(" "); adrput(stdout, p->n_left); return; } printf("%s", (p->n_op == INCR ? "add" : "sub") ); prtype(p->n_left); printf("2 "); adrput(stdout, p->n_right); printf(","); adrput(p->n_left); return; #endif case 'F': /* register type of right operand */ { register NODE *n; register int ty; n = getlr( p, 'R' ); ty = n->n_type; if (x2debug) printf("->%d<-", ty); if ( ty==DOUBLE) printf("d"); else if ( ty==FLOAT ) printf("f"); else printf("l"); return; } case 'G': /* emit conversion instructions */ sconv(p); break; case 'J': /* jump or ret? */ { struct interpass *ip = DLIST_PREV((struct interpass *)p2env.epp, qelem); if (ip->type != IP_DEFLAB || ip->ip_lbl != getlval(getlr(p, 'L'))) expand(p, FOREFF, "jbr LL"); else printf("ret"); } break; case 'L': /* type of left operand */ case 'R': /* type of right operand */ { register NODE *n; n = getlr ( p, c); if (x2debug) printf("->%d<-", n->n_type); prtype(n); return; } case 'l': /* print out long long constant as hex */ case 'r': /* works around a bug in gas */ l = getlr(p, c == 'l' ? 'L' : 'R'); if (l->n_op == ICON && ISLONGLONG(l->n_type)) { printf("$0x%llx", getlval(l)); } else adrput(stdout, l); break; case 'O': /* print out emulated ops */ expand(p, FOREFF, "\tmovq AR,-(%sp)\n"); expand(p, FOREFF, "\tmovq AL,-(%sp)\n"); if (p->n_op == DIV && p->n_type == ULONGLONG) ch = "udiv"; else if (p->n_op == DIV) ch = "div"; else if (p->n_op == MOD && p->n_type == ULONGLONG) ch = "umod"; else if (p->n_op == MOD) ch = "mod"; else if (p->n_op == MUL) ch = "mul"; else ch = 0, comperr("ZO %d", p->n_op); printf("\tcalls $4,__%sdi3\n", ch); break; case 'Z': /* complement mask for bit instr */ printf("$%lld", ~getlval(p->n_right)); return; case 'U': /* 32 - n, for unsigned right shifts */ t = DEUNSIGN(p->n_left->n_type); m = t == CHAR ? 8 : t == SHORT ? 16 : 32; printf("$" CONFMT, m - getlval(p->n_right)); return; case 'T': /* rounded structure length for arguments */ { int size; size = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0); SETOFF( size, 4); printf("$%d", size); return; } case 'S': /* structure assignment */ { register int size; size = attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0); SETOFF(size, 4); l = r = NULL; /* XXX gcc */ if( p->n_op == STASG ){ l = p->n_left; r = p->n_right; } else if( p->n_op == STARG ){ /* store an arg into a temporary */ printf("\tsubl2 $%d,%%sp\n", size < 4 ? 4 : size); l = mklnode(OREG, 0, SP, INT); r = p->n_left; } else cerror( "STASG bad" ); if( r->n_op == ICON ) r->n_op = NAME; else if( r->n_op == REG ) r->n_op = OREG; else if( r->n_op != OREG ) cerror( "STASG-r" ); if (size != 0) { if( size <= 0 || size > 65535 ) cerror("structure size <0=0 or >65535"); switch(size) { case 1: printf(" movb "); break; case 2: printf(" movw "); break; case 4: printf(" movl "); break; case 8: printf(" movq "); break; default: printf(" movc3 $%d,", size); break; } adrput(stdout, r); printf(","); adrput(stdout, l); printf("\n"); } if( r->n_op == NAME ) r->n_op = ICON; else if( r->n_op == OREG ) r->n_op = REG; if (p->n_op == STARG) tfree(l); } break; default: comperr("illegal zzzcode '%c'", c); } } void rmove(int rt, int rs, TWORD t) { char c = (t == FLOAT ? 'f' : t == DOUBLE ? 'd' : t == LONGLONG || t == ULONGLONG ? 'q' : 'l'); printf(" mov%c %s,%s\n", c, rnames[rt], rnames[rs]); } int rewfld(NODE *p) { return(1); } #if 0 int callreg(NODE *p) { return( R0 ); } int base(register NODE *p) { register int o = p->op; if( (o==ICON && p->name[0] != '\0')) return( 100 ); /* ie no base reg */ if( o==REG ) return( p->rval ); if( (o==PLUS || o==MINUS) && p->left->op == REG && p->right->op==ICON) return( p->left->rval ); if( o==OREG && !R2TEST(p->rval) && (p->type==INT || p->type==UNSIGNED || ISPTR(p->type)) ) return( p->rval + 0200*1 ); if( o==INCR && p->left->op==REG ) return( p->left->rval + 0200*2 ); if( o==ASG MINUS && p->left->op==REG) return( p->left->rval + 0200*4 ); if( o==UNARY MUL && p->left->op==INCR && p->left->left->op==REG && (p->type==INT || p->type==UNSIGNED || ISPTR(p->type)) ) return( p->left->left->rval + 0200*(1+2) ); return( -1 ); } int offset(register NODE *p, int tyl) { if( tyl==1 && p->op==REG && (p->type==INT || p->type==UNSIGNED) ) return( p->rval ); if( (p->op==LS && p->left->op==REG && (p->left->type==INT || p->left->type==UNSIGNED) && (p->right->op==ICON && p->right->name[0]=='\0') && (1<right->lval)==tyl)) return( p->left->rval ); return( -1 ); } #endif #if 0 void makeor2( p, q, b, o) register NODE *p, *q; register int b, o; { register NODE *t; NODE *f; p->n_op = OREG; f = p->n_left; /* have to free this subtree later */ /* init base */ switch (q->n_op) { case ICON: case REG: case OREG: t = q; break; case MINUS: q->n_right->n_lval = -q->n_right->n_lval; case PLUS: t = q->n_right; break; case UMUL: t = q->n_left->n_left; break; default: cerror("illegal makeor2"); t = NULL; /* XXX gcc */ } p->n_lval = t->n_lval; p->n_name = t->n_name; /* init offset */ p->n_rval = R2PACK( (b & 0177), o, (b>>7) ); tfree(f); return; } int canaddr( p ) NODE *p; { register int o = p->n_op; if( o==NAME || o==REG || o==ICON || o==OREG || (o==UMUL && shumul(p->n_left, STARNM|SOREG)) ) return(1); return(0); } shltype( o, p ) register NODE *p; { return( o== REG || o == NAME || o == ICON || o == OREG || ( o==UMUL && shumul(p->n_left, STARNM|SOREG)) ); } #endif int fldexpand(NODE *p, int cookie, char **cp) { return 0; } int flshape(register NODE *p) { return( p->n_op == REG || p->n_op == NAME || p->n_op == ICON || (p->n_op == OREG && (!R2TEST(p->n_rval) || tlen(p) == 1)) ); } int shtemp(register NODE *p) { if( p->n_op == STARG ) p = p->n_left; return( p->n_op==NAME || p->n_op ==ICON || p->n_op == OREG || (p->n_op==UMUL && shumul(p->n_left, STARNM|SOREG)) ); } /* * Shape matches for UMUL. Cooperates with offstar(). */ int shumul(NODE *p, int shape) { if (x2debug) printf("shumul(%p)\n", p); /* Turns currently anything into OREG on vax */ if (shape & SOREG) return SROREG; return SRNOPE; } #ifdef notdef int shumul( p, shape ) register NODE *p; int shape; { register int o; if (x2debug) { printf("\nshumul:op=%d,lop=%d,rop=%d", p->n_op, p->n_left->n_op, p->n_right->n_op); printf(" prname=%s,plty=%d, prlval=%lld\n", p->n_right->n_name, p->n_left->n_type, p->n_right->n_lval); } o = p->n_op; if( o == NAME || (o == OREG && !R2TEST(p->n_rval)) || o == ICON ) if (shape & STARNM) return SRDIR; if( ( o == INCR || o == ASG MINUS ) && ( p->n_left->n_op == REG && p->n_right->n_op == ICON ) && p->n_right->n_name[0] == '\0' ) { switch (p->n_left->n_type) { case CHAR|PTR: case UCHAR|PTR: o = 1; break; case SHORT|PTR: case USHORT|PTR: o = 2; break; case INT|PTR: case UNSIGNED|PTR: case LONG|PTR: case ULONG|PTR: case FLOAT|PTR: o = 4; break; case DOUBLE|PTR: o = 8; break; default: if ( ISPTR(p->n_left->n_type) ) { o = 4; break; } else return(0); } return( p->n_right->n_lval == o ? STARREG : 0); } return( SRNOPE ); } #endif void adrcon(CONSZ val) { comperr("adrcon"); printf( "$" ); printf( CONFMT, val ); } void conput(FILE *fp, NODE *p) { switch( p->n_op ){ case ICON: acon( p ); return; case REG: printf( "%s", rnames[p->n_rval] ); return; default: cerror( "illegal conput" ); } } void insput(register NODE *p) { cerror( "insput" ); } /* * Write out the upper address, like the upper register of a 2-register * reference, or the next memory location. */ void upput(NODE *p, int size) { size /= SZCHAR; switch (p->n_op) { case REG: printf("%s", rnames[regno(p)-16+1]); break; case NAME: if (kflag) comperr("upput NAME"); case OREG: setlval(p, getlval(p) + size); adrput(stdout, p); setlval(p, getlval(p) - size); break; case ICON: printf("$" CONFMT, (getlval(p) >> 32) & 0xffffffff); break; default: comperr("upput bad op %d size %d", p->n_op, size); } } void adrput(FILE *fp, NODE *p) { register int r; /* output an address, with offsets, from p */ if( p->n_op == FLD ){ p = p->n_left; } switch( p->n_op ){ case NAME: acon( p ); return; case ICON: /* addressable value of the constant */ if (p->n_name[0] == '\0') /* uses xxxab */ printf("$"); if (ISLONGLONG(p->n_type)) printf("0x%llx", getlval(p)); else acon(p); return; case REG: printf( "%s", rnames[p->n_rval] ); return; case OREG: r = p->n_rval; if( R2TEST(r) ){ /* double indexing */ register int flags; flags = R2UPK3(r); if( flags & 1 ) printf("*"); if( flags & 4 ) printf("-"); if( getlval(p) != 0 || p->n_name[0] != '\0' ) acon(p); if( R2UPK1(r) != 100) printf( "(%s)", rnames[R2UPK1(r)] ); if( flags & 2 ) printf("+"); printf( "[%s]", rnames[R2UPK2(r)] ); return; } if( r == AP ){ /* in the argument region */ if( getlval(p) <= 0 || p->n_name[0] != '\0' ) werror( "bad arg temp" ); printf( CONFMT, getlval(p) ); printf( "(%%ap)" ); return; } if( getlval(p) != 0 || p->n_name[0] != '\0') acon( p ); printf( "(%s)", rnames[p->n_rval] ); return; case UMUL: /* STARNM or STARREG found */ if( tshape(p, STARNM) ) { printf( "*" ); adrput(0, p->n_left); } else { /* STARREG - really auto inc or dec */ register NODE *q; /* tbl p = p->n_left; p->n_left->n_op = OREG; if( p->n_op == INCR ) { adrput( p->n_left ); printf( "+" ); } else { printf( "-" ); adrput( p->n_left ); } tbl */ #ifdef notyet printf("%c(%s)%c", (p->n_left->n_op==INCR ? '\0' : '-'), rnames[p->n_left->n_left->n_rval], (p->n_left->n_op==INCR ? '+' : '\0') ); #else printf("%c(%s)%c", '-', rnames[p->n_left->n_left->n_rval], '\0' ); #endif p->n_op = OREG; p->n_rval = p->n_left->n_left->n_rval; q = p->n_left; #ifdef notyet setlval(p, (p->n_left->n_op == INCR ? -p->n_left->n_right->n_lval : 0)); #else setlval(p, 0); #endif p->n_name[0] = '\0'; tfree(q); } return; default: cerror( "illegal address" ); return; } } /* * print out a constant */ void acon(NODE *p) { int u = (int)getlval(p); CONSZ v = u; if (p->n_name[0] == '\0') { printf(CONFMT, v); } else if( getlval(p) == 0 ) { printf("%s", p->n_name); } else { printf("%s+", p->n_name); printf(CONFMT, v); } } #if 0 genscall( p, cookie ) register NODE *p; { /* structure valued call */ return( gencall( p, cookie ) ); } /* tbl */ int gc_numbytes; /* tbl */ gencall( p, cookie ) register NODE *p; { /* generate the call given by p */ register NODE *p1, *ptemp; register temp, temp1; register m; if( p->right ) temp = argsize( p->right ); else temp = 0; if( p->op == STCALL || p->op == UNARY STCALL ){ /* set aside room for structure return */ if( p->stsize > temp ) temp1 = p->stsize; else temp1 = temp; } if( temp > maxargs ) maxargs = temp; SETOFF(temp1,4); if( p->right ){ /* make temp node, put offset in, and generate args */ ptemp = talloc(); ptemp->op = OREG; setlval(ptemp, -1); ptemp->rval = SP; ptemp->name[0] = '\0'; ptemp->rall = NOPREF; ptemp->su = 0; genargs( p->right, ptemp ); nfree(ptemp); } p1 = p->left; if( p1->op != ICON ){ if( p1->op != REG ){ if( p1->op != OREG || R2TEST(p1->rval) ){ if( p1->op != NAME ){ order( p1, INAREG ); } } } } /* if( p1->op == REG && p->rval == R5 ){ cerror( "call register overwrite" ); } */ /* tbl setup gc_numbytes so reference to ZC works */ gc_numbytes = temp; /* tbl */ p->op = UNARY CALL; m = match( p, INTAREG|INTBREG ); /* tbl switch( temp ) { case 0: break; case 2: printf( " tst (%sp)+\n" ); break; case 4: printf( " cmp (%sp)+,(%sp)+\n" ); break; default: printf( " add $%d,%sp\n", temp); } tbl */ return(m != MDONE); } #endif static char * ccbranches[] = { "jeql", "jneq", "jleq", "jlss", "jgeq", "jgtr", "jlequ", "jlssu", "jgequ", "jgtru", }; /* * printf conditional and unconditional branches */ void cbgen(int o, int lab) { if (o == 0) { printf(" jbr " LABFMT "\n", lab); } else { if (o > UGT) comperr("bad conditional branch: %s", opst[o]); printf("\t%s\t" LABFMT "\n", ccbranches[o-EQ], lab); } } static void mkcall(NODE *p, char *name) { p->n_op = CALL; p->n_right = mkunode(FUNARG, p->n_left, 0, p->n_left->n_type); p->n_left = mklnode(ICON, 0, 0, FTN|p->n_type); p->n_left->n_name = name; } /* do local tree transformations and optimizations */ static void optim2(NODE *p, void *arg) { NODE *r, *s; TWORD lt; switch (p->n_op) { case DIV: case MOD: if (p->n_type == USHORT || p->n_type == UCHAR) { r = mkunode(SCONV, p->n_left, 0, UNSIGNED); r = mkunode(FUNARG, r, 0, UNSIGNED); s = mkunode(SCONV, p->n_right, 0, UNSIGNED); s = mkunode(FUNARG, s, 0, UNSIGNED); r = mkbinode(CM, r, s, INT); s = mklnode(ICON, 0, 0, FTN|UNSIGNED); s->n_name = p->n_op == MOD ? "__urem" : "__udiv"; p->n_left = mkbinode(CALL, s, r, UNSIGNED); p->n_op = SCONV; } else if (p->n_type == UNSIGNED) { p->n_left = mkunode(FUNARG, p->n_left, 0, UNSIGNED); p->n_right = mkunode(FUNARG, p->n_right, 0, UNSIGNED); p->n_right = mkbinode(CM, p->n_left, p->n_right, INT); p->n_left = mklnode(ICON, 0, 0, FTN|UNSIGNED); p->n_left->n_name = p->n_op == MOD ? "__urem" : "__udiv"; p->n_op = CALL; } break; case RS: if (p->n_type == ULONGLONG) { p->n_right = mkbinode(CM, mkunode(FUNARG, p->n_left, 0, p->n_left->n_type), mkunode(FUNARG, p->n_right, 0, p->n_right->n_type), INT); p->n_left = mklnode(ICON, 0, 0, FTN|p->n_type); p->n_left->n_name = "__lshrdi3"; p->n_op = CALL; } else if (p->n_type == INT || p->n_type == LONGLONG) { /* convert >> to << with negative shift count */ /* RS of char & short must use extv */ if (p->n_right->n_op == ICON) { setlval(p->n_right, -getlval(p->n_right)); } else if (p->n_right->n_op == UMINUS) { r = p->n_right->n_left; nfree(p->n_right); p->n_right = r; } else { p->n_right = mkunode(UMINUS, p->n_right, 0, p->n_right->n_type); } p->n_op = LS; } break; case AND: /* commute L and R to eliminate compliments and constants */ if ((p->n_left->n_op == ICON && p->n_left->n_name[0] == 0) || p->n_left->n_op==COMPL) { r = p->n_left; p->n_left = p->n_right; p->n_right = r; } /* change meaning of AND to ~R&L - bic on pdp11 */ r = p->n_right; if (r->n_op == ICON && r->n_name[0] == 0) { /* compliment constant */ setlval(r, ~getlval(r)); } else if (r->n_op == COMPL) { /* ~~A => A */ s = r->n_left; nfree(r); p->n_right = s; } else { /* insert complement node */ p->n_right = mkunode(COMPL, r, 0, r->n_type); } break; case SCONV: lt = p->n_left->n_type; switch (p->n_type) { case LONGLONG: if (lt == FLOAT) mkcall(p, "__fixsfdi"); else if (lt == DOUBLE) mkcall(p, "__fixdfdi"); break; case ULONGLONG: if (lt == FLOAT) mkcall(p, "__fixunssfdi"); else if (lt == DOUBLE) mkcall(p, "__fixunsdfdi"); break; case FLOAT: if (lt == LONGLONG) mkcall(p, "__floatdisf"); else if (lt == ULONGLONG) { p->n_left = mkunode(SCONV, p->n_left,0, DOUBLE); p->n_type = FLOAT; mkcall(p->n_left, "__floatundidf"); } else if (lt == UNSIGNED) { /* insert an extra double-to-float sconv */ p->n_left = mkunode(SCONV, p->n_left,0, DOUBLE); } break; case DOUBLE: if (lt == LONGLONG) mkcall(p, "__floatdidf"); else if (lt == ULONGLONG) mkcall(p, "__floatundidf"); break; } break; } } static void aofname(NODE *p, void *arg) { int o = optype(p->n_op); TWORD t; if (o == LTYPE || p->n_op == ADDROF) return; t = p->n_left->n_type; if (p->n_left->n_op == NAME && ISLONGLONG(t)) p->n_left = mkunode(UMUL, mkunode(ADDROF, p->n_left, 0, INCREF(t)), 0, t); if (o == BITYPE && p->n_right->n_op == NAME && ISLONGLONG(p->n_right->n_type)) { t = p->n_right->n_type; p->n_right = mkunode(UMUL, mkunode(ADDROF, p->n_right, 0, INCREF(t)), 0, t); } } void myreader(struct interpass *ipole) { struct interpass *ip; DLIST_FOREACH(ip, ipole, qelem) { if (ip->type != IP_NODE) continue; if (kflag) walkf(ip->ip_node, aofname, 0); walkf(ip->ip_node, optim2, 0); } } void mycanon(NODE *p) { } void myoptim(struct interpass *ip) { } /* * Return argument size in regs. */ static int argsiz(NODE *p) { TWORD t = p->n_type; if (t == STRTY || t == UNIONTY) return (attr_find(p->n_ap, ATTR_P2STRUCT)->iarg(0)+3)/4; return szty(t); } /* * Last chance to do something before calling a function. */ void lastcall(NODE *p) { NODE *op = p; int size = 0; /* Calculate argument sizes */ p->n_qual = 0; if (p->n_op != CALL && p->n_op != FORTCALL && p->n_op != STCALL) return; for (p = p->n_right; p->n_op == CM; p = p->n_left) size += argsiz(p->n_right); if (p->n_op != ASSIGN) size += argsiz(p); op->n_qual = size; /* XXX */ } /* * Return a class suitable for a specific type. */ int gclass(TWORD t) { return (szty(t) == 2 ? CLASSB : CLASSA); } /* * For class c, find worst-case displacement of the number of * registers in the array r[] indexed by class. */ int COLORMAP(int c, int *r) { int num; int a,b; a = r[CLASSA]; b = r[CLASSB]; switch (c) { case CLASSA: /* there are 12 classa, so min 6 classb are needed to block */ num = b * 2; num += a; return num < 12; case CLASSB: if (b > 3) return 0; if (b > 2 && a) return 0; if (b > 1 && a > 2) return 0; if (b && a > 3) return 0; if (a > 5) return 0; return 1; } comperr("COLORMAP"); return 0; /* XXX gcc */ } /* * Special shapes. */ int special(NODE *p, int shape) { return SRNOPE; } /* * Target-dependent command-line options. */ void mflags(char *str) { } /* * Do something target-dependent for xasm arguments. * Supposed to find target-specific constraints and rewrite them. */ int myxasm(struct interpass *ip, NODE *p) { char *c; int i; /* Discard o<> constraints since they will not be generated */ for (c = p->n_name; *c; c++) { if (*c == 'o' || *c == '<' || *c == '>') { for (i = 0; c[i]; i++) c[i] = c[i+1]; c--; } } return 0; } int xasmconstregs(char *s) { int i; for (i = 0; i < 16; i++) if (strcmp(&rnames[i][1], s) == 0) return i; return -1; } pcc-20181216/arch/vax/macdefs.h010064400017500000000000000164721266660034000147670ustar raggewheel/* $Id: macdefs.h,v 1.23 2016/03/05 15:53:04 ragge Exp $ */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code and documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditionsand the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ # define makecc(val,i) lastcon = (lastcon<<8)|((val<<24)>>24); # define ARGINIT 32 # define AUTOINIT 0 # define SZCHAR 8 # define SZBOOL 8 # define SZINT 32 # define SZFLOAT 32 # define SZDOUBLE 64 # define SZLDOUBLE 64 /* XXX use longer? */ # define SZLONG 32 # define SZLONGLONG 64 # define SZSHORT 16 # define SZPOINT(t) 32 # define ALCHAR 8 # define ALBOOL 8 # define ALINT 32 # define ALFLOAT 32 # define ALDOUBLE 32 # define ALLDOUBLE 32 # define ALLONG 32 # define ALLONGLONG 32 # define ALSHORT 16 # define ALPOINT 32 # define ALSTRUCT 8 # define ALSTACK 32 #define MYVAARGSZ SZINT /* * Min/max values. */ #define MIN_CHAR -128 #define MAX_CHAR 127 #define MAX_UCHAR 255 #define MIN_SHORT -32768 #define MAX_SHORT 32767 #define MAX_USHORT 65535 #define MIN_INT (-0x7fffffff-1) #define MAX_INT 0x7fffffff #define MAX_UNSIGNED 0xffffffff #define MIN_LONG MIN_INT #define MAX_LONG MAX_INT #define MAX_ULONG MAX_UNSIGNED #define MIN_LONGLONG 0x8000000000000000LL #define MAX_LONGLONG 0x7fffffffffffffffLL #define MAX_ULONGLONG 0xffffffffffffffffULL /* Default char is signed */ #undef CHAR_UNSIGNED #define BOOL_TYPE CHAR /* what used to store _Bool */ #define HASP2ALIGN /* size in which constants are converted */ /* should be long if feasable */ typedef long long CONSZ; typedef unsigned long long U_CONSZ; # define CONFMT "%lld" # define LABFMT ".L%d" # define STABLBL ".LL%d" /* size in which offsets are kept * should be large enough to cover address space in bits */ typedef long long OFFSZ; /* register cookie for stack poINTer */ /* show stack grows negatively */ #define BACKAUTO #define BACKTEMP /* show field hardware support on VAX */ /* XXX notyet */ #undef FIELDOPS /* bytes are numbered from right to left */ #define TARGET_ENDIAN TARGET_LE #define UNALIGNED_ACCESS /* we want prtree included */ # define STDPRTREE /* VAX-11/780 Registers */ /* scratch registers */ # define R0 0 # define R1 1 # define R2 2 # define R3 3 # define R4 4 # define R5 5 /* register variables */ # define R6 6 # define R7 7 # define R8 8 # define R9 9 # define R10 10 # define R11 11 /* special purpose */ # define AP 12 /* argument pointer */ # define FP 13 /* frame pointer */ # define SP 14 /* stack pointer */ # define PC 15 /* program counter */ /* floating registers */ /* there are no floating point registers on the VAX */ /* but there are concatenated regs */ /* we call them XR? */ #define XR0 16 #define XR1 17 #define XR2 18 #define XR3 19 #define XR4 20 #define XR5 21 #define XR6 22 #define XR7 23 #define XR8 24 #define XR9 25 #define XR10 26 extern int fregs; extern int maxargs; # define BYTEOFF(x) ((x)&03) # define wdal(k) (BYTEOFF(k)==0) # define REGSZ 16 # define TMPREG FP //# define R2REGS /* permit double indexing */ # define STOARG(p) /* just evaluate the arguments, and be done with it... */ # define STOFARG(p) # define STOSTARG(p) # define genfcall(a,b) gencall(a,b) # define NESTCALL /* * Register allocator stuff. * The register allocator sees this as 16 general regs (AREGs) * and 11 64-bit concatenated regs. (BREGs) */ #define MAXREGS 033 /* 27 registers */ #define RSTATUS \ SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, SAREG|TEMPREG, \ SAREG|TEMPREG, SAREG|TEMPREG, SAREG|PERMREG, SAREG|PERMREG, \ SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, SAREG|PERMREG, \ 0, 0, 0, 0, /* do not care about ap, fp, sp or pc */ \ SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, SBREG, \ SBREG, SBREG, SBREG, #define ROVERLAP \ { XR0, -1 }, \ { XR0, XR1, -1 }, \ { XR1, XR2, -1 }, \ { XR2, XR3, -1 }, \ { XR3, XR4, -1 }, \ { XR4, XR5, -1 }, \ { XR5, XR6, -1 }, \ { XR6, XR7, -1 }, \ { XR7, XR8, -1 }, \ { XR8, XR9, -1 }, \ { XR9, XR10, -1 }, \ { XR10, -1 }, \ { -1 }, \ { -1 }, \ { -1 }, \ { -1 }, \ { R0, R1, XR1, -1 }, \ { R1, R2, XR0, XR2, -1 }, \ { R2, R3, XR1, XR3, -1 }, \ { R3, R4, XR2, XR4, -1 }, \ { R4, R5, XR3, XR5, -1 }, \ { R5, R6, XR4, XR6, -1 }, \ { R6, R7, XR5, XR7, -1 }, \ { R7, R8, XR6, XR8, -1 }, \ { R8, R9, XR7, XR9, -1 }, \ { R9, R10, XR8, XR10, -1 }, \ { R10, R11, XR9, -1 }, #define NUMCLASS 2 /* highest number of reg classes used */ /* size, in registers, needed to hold thing of type t */ #define szty(t) (((t) == DOUBLE || (t) == LONGLONG || (t) == ULONGLONG) ? 2 : 1) #define FPREG FP /* frame pointer */ #define STKREG SP #define ARGREG AP #define DECRA(x,y) (((x) >> (y*6)) & 63) /* decode encoded regs */ #define ENCRD(x) (x) /* Encode dest reg in n_reg */ #define ENCRA1(x) ((x) << 6) /* A1 */ #define ENCRA2(x) ((x) << 12) /* A2 */ #define ENCRA(x,y) ((x) << (6+y*6)) /* encode regs in int */ #define PCLASS(p) (szty(p->n_type) == 2 ? SBREG : SAREG) #define RETREG(x) (szty(x) == 2 ? XR0 : R0) #define GCLASS(x) (x < XR0 ? CLASSA : CLASSB) int xasmconstregs(char *s); #define XASMCONSTREGS(x) xasmconstregs(x) int COLORMAP(int c, int *r); #define SNCON (MAXSPECIAL+1) /* named constand */ #define TARGET_FLT_EVAL_METHOD 0 /* all as their type */ /* * Builtins. */ #ifdef LANG_CXX #define P1ND struct node #else #define P1ND struct p1node #endif struct p1node; struct bitable; #define TARGET_FFS /* target-specific ffs */ P1ND *builtin_ffs(const struct bitable *, P1ND *a); P1ND *builtin_ffsl(const struct bitable *, P1ND *a); P1ND *builtin_ffsll(const struct bitable *, P1ND *a); #undef P1ND pcc-20181216/arch/vax/order.c010064400017500000000000000336121326333434700144730ustar raggewheel/* $Id: order.c,v 1.11 2018/04/11 07:27:35 ragge Exp $ */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code and documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditionsand the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ # include "pass2.h" int canaddr(NODE *); int maxargs = { -1 }; #if 0 stoasg( p, o ) register NODE *p; { /* should the assignment op p be stored, given that it lies as the right operand of o (or the left, if o==UNARY MUL) */ /* if( p->op == INCR || p->op == DECR ) return; if( o==UNARY MUL && p->left->op == REG && !isbreg(p->left->rval) ) SETSTO(p,INAREG); */ } int deltest( p ) register NODE *p; { /* should we delay the INCR or DECR operation p */ p = p->n_left; return( p->n_op == REG || p->n_op == NAME || p->n_op == OREG ); } autoincr( p ) NODE *p; { register NODE *q = p->left, *r; if( q->op == INCR && (r=q->left)->op == REG && ISPTR(q->type) && p->type == DECREF(q->type) && tlen(p) == q->right->lval ) return(1); return(0); } mkadrs(p) register NODE *p; { register o; o = p->op; if( asgop(o) ){ if( p->left->su >= p->right->su ){ if( p->left->op == UNARY MUL ){ SETSTO( p->left->left, INTEMP ); } else if( p->left->op == FLD && p->left->left->op == UNARY MUL ){ SETSTO( p->left->left->left, INTEMP ); } else { /* should be only structure assignment */ SETSTO( p->left, INTEMP ); } } else SETSTO( p->right, INTEMP ); } else { if( p->left->su > p->right->su ){ SETSTO( p->left, INTEMP ); } else { SETSTO( p->right, INTEMP ); } } } #endif int notoff(TWORD t, int r, CONSZ off, char *cp) { /* is it legal to make an OREG or NAME entry which has an * offset of off, (from a register of r), if the * resulting thing had type t */ /* if( r == R0 ) return( 1 ); / * NO */ return(0); /* YES */ } # define max(x,y) ((x)<(y)?(y):(x)) #if 0 sucomp( p ) register NODE *p; { /* set the su field in the node to the sethi-ullman number, or local equivalent */ register o, ty, sul, sur, r; o = p->op; ty = optype( o ); p->su = szty( p->type ); /* 2 for float or double, else 1 */; if( ty == LTYPE ){ if( o == OREG ){ r = p->rval; /* oreg cost is (worst case) 1 + number of temp registers used */ if( R2TEST(r) ){ if( R2UPK1(r)!=100 && istreg(R2UPK1(r)) ) ++p->su; if( istreg(R2UPK2(r)) ) ++p->su; } else { if( istreg( r ) ) ++p->su; } } if( p->su == szty(p->type) && (p->op!=REG || !istreg(p->rval)) && (p->type==INT || p->type==UNSIGNED || p->type==DOUBLE) ) p->su = 0; return; } else if( ty == UTYPE ){ switch( o ) { case UNARY CALL: case UNARY STCALL: p->su = fregs; /* all regs needed */ return; default: p->su = p->left->su + (szty( p->type ) > 1 ? 2 : 0) ; return; } } /* If rhs needs n, lhs needs m, regular su computation */ sul = p->left->su; sur = p->right->su; if( o == ASSIGN ){ /* computed by doing right, then left (if not in mem), then doing it */ p->su = max(sur,sul+1); return; } if( o == CALL || o == STCALL ){ /* in effect, takes all free registers */ p->su = fregs; return; } if( o == STASG ){ /* right, then left */ p->su = max( max( 1+sul, sur), fregs ); return; } if( asgop(o) ){ /* computed by doing right, doing left address, doing left, op, and store */ p->su = max(sur,sul+2); /* if( o==ASG MUL || o==ASG DIV || o==ASG MOD) p->su = max(p->su,fregs); */ return; } switch( o ){ case ANDAND: case OROR: case QUEST: case COLON: case COMOP: p->su = max( max(sul,sur), 1); return; case PLUS: case OR: case ER: /* commutative ops; put harder on left */ if( p->right->su > p->left->su && !istnode(p->left) ){ register NODE *temp; temp = p->left; p->left = p->right; p->right = temp; } break; } /* binary op, computed by left, then right, then do op */ p->su = max(sul,szty(p->right->type)+sur); /* if( o==MUL||o==DIV||o==MOD) p->su = max(p->su,fregs); */ } int radebug = 0; rallo( p, down ) NODE *p; { /* do register allocation */ register o, type, down1, down2, ty; if( radebug ) printf( "rallo( %o, %d )\n", p, down ); down2 = NOPREF; p->rall = down; down1 = ( down &= ~MUSTDO ); ty = optype( o = p->op ); type = p->type; if( type == DOUBLE || type == FLOAT ){ if( o == FORCE ) down1 = R0|MUSTDO; } else switch( o ) { case ASSIGN: down1 = NOPREF; down2 = down; break; /* case MUL: case DIV: case MOD: down1 = R3|MUSTDO; down2 = R5|MUSTDO; break; case ASG MUL: case ASG DIV: case ASG MOD: p->left->rall = down1 = R3|MUSTDO; if( p->left->op == UNARY MUL ){ rallo( p->left->left, R4|MUSTDO ); } else if( p->left->op == FLD && p->left->left->op == UNARY MUL ){ rallo( p->left->left->left, R4|MUSTDO ); } else rallo( p->left, R3|MUSTDO ); rallo( p->right, R5|MUSTDO ); return; */ case CALL: case STASG: case EQ: case NE: case GT: case GE: case LT: case LE: case NOT: case ANDAND: case OROR: down1 = NOPREF; break; case FORCE: down1 = R0|MUSTDO; break; } if( ty != LTYPE ) rallo( p->left, down1 ); if( ty == BITYPE ) rallo( p->right, down2 ); } #endif /* * Turn a UMUL-referenced node into OREG. * Be careful about register classes, this is a place where classes change. */ void offstar(NODE *p, int shape) { NODE *r; if (x2debug) printf("offstar(%p)\n", p); if (isreg(p)) return; /* Is already OREG */ r = p->n_right; if( p->n_op == PLUS || p->n_op == MINUS ){ if( r->n_op == ICON ){ if (isreg(p->n_left) == 0) (void)geninsn(p->n_left, INAREG); /* Converted in ormake() */ return; } #if 0 if (r->n_op == LS && r->n_right->n_op == ICON && r->n_right->n_lval == 2 && p->n_op == PLUS) { if (isreg(p->n_left) == 0) (void)geninsn(p->n_left, INAREG); if (isreg(r->n_left) == 0) (void)geninsn(r->n_left, INAREG); return; } #endif } (void)geninsn(p, INAREG); } #if 0 void offstar( p, s ) register NODE *p; { if( p->n_op == PLUS ) { if( p->n_left->n_su == fregs ) { order( p->n_left, INAREG ); return; } else if( p->n_right->n_su == fregs ) { order( p->n_right, INAREG ); return; } if( p->n_left->n_op==LS && (p->n_left->n_left->n_op!=REG || tlen(p->n_left->n_left)!=sizeof(int) ) ) { order( p->n_left->n_left, INAREG ); return; } if( p->n_right->n_op==LS && (p->n_right->n_left->n_op!=REG || tlen(p->n_right->n_left)!=sizeof(int) ) ) { order( p->n_right->n_left, INAREG ); return; } if( p->n_type == (PTR|CHAR) || p->n_type == (PTR|UCHAR) ) { if( p->n_left->n_op!=REG || tlen(p->n_left)!=sizeof(int) ) { order( p->n_left, INAREG ); return; } else if( p->n_right->n_op!=REG || tlen(p->n_right)!=sizeof(int) ) { order(p->n_right, INAREG); return; } } } if( p->n_op == PLUS || p->n_op == MINUS ){ if( p->n_right->n_op == ICON ){ p = p->n_left; order( p , INAREG); return; } } if( p->n_op == UMUL && !canaddr(p) ) { offstar( p->n_left, 0 ); return; } order( p, INAREG ); } #endif int setbin( p ) register NODE *p; { #if 0 register int ro, rt; rt = p->n_right->n_type; ro = p->n_right->n_op; if( canaddr( p->n_left ) && !canaddr( p->n_right ) ) { /* address rhs */ if( ro == UMUL ) { offstar( p->n_right->n_left, 0 ); return(1); } else { order( p->n_right, INAREG|SOREG ); return(1); } } if( !istnode( p->n_left) ) { /* try putting LHS into a reg */ /* order( p->n_left, logop(p->n_op)?(INAREG|INBREG|INTAREG|INTBREG|SOREG):(INTAREG|INTBREG|SOREG) );*/ order( p->n_left, INAREG|INTAREG|INBREG|INTBREG|SOREG ); return(1); } else if( ro == UNARY MUL && rt != CHAR && rt != UCHAR ){ offstar( p->n_right->n_left ); return(1); } else if( rt == CHAR || rt == UCHAR || rt == SHORT || rt == USHORT || (ro != REG && ro != NAME && ro != OREG && ro != ICON ) ){ order( p->n_right, INAREG|INBREG ); return(1); } /* else if( logop(p->n_op) && rt==USHORT ){ / * must get rhs into register */ /* order( p->n_right, INAREG ); return( 1 ); } */ #endif return(0); } #if 0 int setstr( p ) register NODE *p; { /* structure assignment */ if( p->right->op != REG ){ order( p->right, INTAREG ); return(1); } p = p->left; if( p->op != NAME && p->op != OREG ){ if( p->op != UNARY MUL ) cerror( "bad setstr" ); order( p->left, INTAREG ); return( 1 ); } return( 0 ); } #endif int setasg( p, s ) register NODE *p; { #if 0 /* setup for assignment operator */ if( !canaddr(p->n_right) ) { if( p->n_right->n_op == UNARY MUL ) offstar(p->n_right->n_left); else order( p->n_right, INAREG|INBREG|SOREG ); return(1); } if( p->n_left->n_op == UMUL ) { offstar( p->n_left->n_left ); return(1); } if( p->left->op == FLD && p->left->left->op == UNARY MUL ){ offstar( p->left->left->left ); return(1); } /* FLD patch */ if( p->left->op == FLD && !(p->right->type==INT || p->right->type==UNSIGNED)) { order( p->right, INAREG); return(1); } /* end of FLD patch */ #endif return(0); } /* setup for unary operator */ int setuni(NODE *p, int cookie) { return 0; } #if 0 int setasop( p ) register NODE *p; { /* setup for =ops */ register rt, ro; rt = p->right->type; ro = p->right->op; if( ro == UNARY MUL && rt != CHAR ){ offstar( p->right->left ); return(1); } if( ( rt == CHAR || rt == SHORT || rt == UCHAR || rt == USHORT || ( ro != REG && ro != ICON && ro != NAME && ro != OREG ) ) ){ order( p->right, INAREG|INBREG ); return(1); } /* if( (p->op == ASG LS || p->op == ASG RS) && ro != ICON && ro != REG ){ order( p->right, INAREG ); return(1); } */ p = p->left; if( p->op == FLD ) p = p->left; switch( p->op ){ case REG: case ICON: case NAME: case OREG: return(0); case UNARY MUL: if( p->left->op==OREG ) return(0); else offstar( p->left ); return(1); } cerror( "illegal setasop" ); } #endif void deflab(int l) { printf(LABFMT ":\n", l); } #if 0 genargs( p, ptemp ) register NODE *p, *ptemp; { register NODE *pasg; register align; register size; register TWORD type; /* generate code for the arguments */ /* first, do the arguments on the right */ while( p->op == CM ){ genargs( p->right, ptemp ); p->op = FREE; p = p->left; } if( p->op == STARG ){ /* structure valued argument */ size = p->stsize; align = p->stalign; /* ptemp->lval = (ptemp->lval/align)*align; / * SETOFF for negative numbers */ ptemp->lval = 0; /* all moves to (sp) */ p->op = STASG; p->right = p->left; p->left = tcopy( ptemp ); /* the following line is done only with the knowledge that it will be undone by the STASG node, with the offset (lval) field retained */ if( p->right->op == OREG ) p->right->op = REG; /* only for temporaries */ order( p, FORARG ); ptemp->lval += size; return; } /* ordinary case */ order( p, FORARG ); } argsize( p ) register NODE *p; { register t; t = 0; if( p->op == CM ){ t = argsize( p->left ); p = p->right; } if( p->type == DOUBLE || p->type == FLOAT ){ SETOFF( t, 4 ); return( t+8 ); } else if( p->op == STARG ){ SETOFF( t, 4 ); /* alignment */ return( t + ((p->stsize+3)/4)*4 ); /* size */ } else { SETOFF( t, 4 ); return( t+4 ); } } #endif /* * Special handling of some instruction register allocation. */ struct rspecial * nspecial(struct optab *q) { switch (q->op) { case STARG: case STASG: { static struct rspecial s[] = { { NEVER, R0, }, { NEVER, R1, }, { NEVER, R2, }, { NEVER, R3, }, { NEVER, R4, }, { NEVER, R5 }, { 0 } }; return s; } case MOD: case MUL: case DIV: { static struct rspecial s[] = { { NEVER, R0, }, { NEVER, R1, }, { NEVER, R2, }, { NEVER, R3, }, { NEVER, R4, }, { NEVER, R5 }, { NRES, XR0 }, { 0 }, }; return s; } default: comperr("nspecial"); return NULL; } } /* * Set evaluation order of a binary node if it differs from default. */ int setorder(NODE *p) { return 0; /* nothing differs on vax */ } /* * Do the actual conversion of offstar-found OREGs into real OREGs. */ void myormake(NODE *q) { if (x2debug) printf("myormake(%p)\n", q); } /* * Set registers "live" at function calls (like arguments in registers). * This is for liveness analysis of registers. */ int * livecall(NODE *p) { static int r[1] = { -1 }; /* Terminate with -1 */ return &r[0]; } /* * Signal whether the instruction is acceptable for this target. */ int acceptable(struct optab *op) { return 1; } pcc-20181216/arch/vax/table.c010064400017500000000000000406471241645115000144440ustar raggewheel/* $Id: table.c,v 1.28 2014/10/12 10:05:28 ragge Exp $ */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code and documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditionsand the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ # include "pass2.h" # define WPTR TPTRTO|TINT|TFLOAT|TDOUBLE|TPOINT|TUNSIGNED # define SAWM SNAME|SOREG|STARNM|STARREG # define AWD SAWM|SCON /* tbl */ # define TANYSIGNED TINT|TSHORT|TCHAR # define TANYUSIGNED TPOINT|TUNSIGNED|TUSHORT|TUCHAR # define TANYFIXED TANYSIGNED|TANYUSIGNED # define TWORD TINT|TUNSIGNED|TPOINT /* tbl */ # define TLL TLONGLONG|TULONGLONG # define TBREG TLONGLONG|TULONGLONG|TDOUBLE # define TAREG TANYFIXED|TFLOAT struct optab table[] = { /* First entry must be an empty entry */ { -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", }, /* PCONVs are usually not necessary */ { PCONV, INAREG, SAREG, TWORD, SAREG, TWORD, 0, RLEFT, "", }, { PCONV, INAREG|INAREG, SAREG|AWD, TCHAR|TSHORT, SANY, TPOINT, NAREG|NASL, RESC1, " cvtZLl AL,A1\n", }, { PCONV, INAREG|INAREG, SAREG|AWD, TUCHAR|TUSHORT, SANY, TPOINT, NAREG|NASL, RESC1, " movzZLl AL,A1\n", }, /* Handle conversions in C code */ { SCONV, INAREG, SAREG|AWD, TAREG, SANY, TANY, NAREG|NASL, RESC1|RESCC, "ZG", }, { SCONV, INAREG, SBREG|AWD, TBREG, SANY, TANY, NAREG|NASL, RESC1|RESCC, "ZG", }, { SCONV, INBREG, SBREG|AWD, TBREG, SANY, TANY, NBREG|NBSL, RESC1|RESCC, "ZG", }, { SCONV, INBREG, SAREG|AWD, TAREG, SANY, TANY, NBREG|NBSL, RESC1|RESCC, "ZG", }, { GOTO, FOREFF, SCON, TANY, SANY, TANY, 0, RNOP, " ZJ\n", }, { GOTO, FOREFF, SAREG, TANY, SANY, TANY, 0, RNOP, " jmp (AL)\n", }, { STARG, FOREFF, SCON|SAREG, TANY, SANY, TANY, NSPECIAL, RNOP, "ZS", }, { ADDROF, INAREG, SNAME, TANY, SAREG, TANY, NAREG, RESC1, " movab AL,A1\n", }, { STASG, FOREFF, SNAME|SOREG, TANY, SCON|SAREG, TANY, NSPECIAL, RNOP, "ZS", }, { STASG, INAREG, SNAME|SOREG, TANY, SCON, TANY, NSPECIAL|NAREG, RDEST, "ZS movl AR,A1\n", }, { STASG, INAREG, SNAME|SOREG, TANY, SAREG, TANY, NSPECIAL, RDEST, " pushl AR\nZS movl (%sp)+,AR\n", }, { FLD, INAREG|INAREG, SANY, TANY, SFLD, TANYSIGNED, NAREG|NASR, RESC1, " extv H,S,AR,A1\n", }, { FLD, INAREG|INAREG, SANY, TANY, SFLD, TANYUSIGNED, NAREG|NASR, RESC1, " extzv H,S,AR,A1\n", }, #if 0 { FLD, FORARG, SANY, TANY, SFLD, ANYSIGNED, 0, RNULL, " extv H,S,AR,-(%sp)\n", }, { FLD, FORARG, SANY, TANY, SFLD, ANYUSIGNED, 0, RNULL, " extzv H,S,AR,-(%sp)\n", }, #endif { OPLOG, FORCC, SBREG|AWD, TLONGLONG|TULONGLONG, SBREG|AWD, TLONGLONG|TULONGLONG, 0, 0, "ZB", }, { OPLOG, FORCC, SAREG|AWD, TWORD, SAREG|AWD, TWORD, 0, RESCC, " cmpl AL,AR\n", }, { OPLOG, FORCC, SAREG|AWD, TSHORT|TUSHORT, SAREG|AWD, TSHORT|TUSHORT, 0, RESCC, " cmpw AL,AR\n", }, { OPLOG, FORCC, SAREG|AWD, TCHAR|TUCHAR, SAREG|AWD, TCHAR|TUCHAR, 0, RESCC, " cmpb AL,AR\n", }, { OPLOG, FORCC, SAREG|AWD, TSHORT|TUSHORT, SSCON, TANY, 0, RESCC, " cmpw AL,AR\n", }, { OPLOG, FORCC, SAREG|AWD, TCHAR|TUCHAR, SCCON, TANY, 0, RESCC, " cmpb AL,AR\n", }, { OPLOG, FORCC, SBREG|AWD, TDOUBLE, SBREG|AWD, TDOUBLE, 0, RESCC, " cmpd AL,AR\n", }, { OPLOG, FORCC, SAREG|AWD, TFLOAT, SAREG|AWD, TFLOAT, 0, RESCC, " cmpf AL,AR\n", }, { CCODES, INAREG|INAREG, SANY, TANY, SANY, TANY, NAREG, RESC1, " movl $1,A1\nZN", }, /* * Subroutine calls. */ { CALL, FOREFF, SCON, TANY, SANY, TANY, 0, 0, " calls ZC,CL\n", }, { UCALL, FOREFF, SCON, TANY, SANY, TANY, 0, 0, " calls $0,CL\n", }, { CALL, INAREG, SCON, TANY, SANY, TAREG, NAREG|NASL, RESC1, /* should be register 0 */ " calls ZC,CL # 1\n", }, { UCALL, INAREG, SCON, TANY, SANY, TAREG, NAREG|NASL, RESC1, /* should be register 0 */ " calls $0,CL\n", }, { CALL, INBREG, SCON, TANY, SANY, TBREG, NBREG|NBSL, RESC1, /* should be register 0 */ " calls ZC,CL # 2\n", }, { UCALL, INBREG, SCON, TANY, SANY, TBREG, NBREG|NASL, RESC1, /* should be register 0 */ " calls $0,CL\n", }, { CALL, INBREG, SAREG, TANY, SANY, TBREG, NBREG|NBSL, RESC1, /* should be 0 */ " calls ZC,(AL)\n", }, { UCALL, INBREG, SAREG, TANY, SANY, TBREG, NBREG|NBSL, RESC1, /* should be 0 */ " calls ZC,(AL)\n", }, { CALL, FOREFF, SAREG, TANY, SANY, TANY, 0, 0, /* should be 0 */ " calls ZC,(AL)\n", }, { CALL, INAREG, SAREG, TANY, SANY, TAREG, NAREG|NASL, RESC1, /* should be 0 */ " calls ZC,(AL)\n", }, { UCALL, FOREFF, SAREG, TANY, SANY, TANY, 0, 0, /* should be 0 */ " calls ZC,(AL)\n", }, { UCALL, INAREG, SAREG, TANY, SANY, TAREG, NAREG|NASL, RESC1, /* should be 0 */ " calls ZC,(AL)\n", }, #if 0 { UCALL, FOREFF, SNAME, TANY, SANY, TANY, 0, 0, /* really reg 0 */ " calls ZC,*AL\n", }, { UCALL, INAREG, SNAME, TANY, SANY, TAREG, NAREG|NASL, RESC1, /* really reg 0 */ " calls ZC,*AL\n", }, { UCALL, FOREFF, SSOREG, TANY, SANY, TANY, 0, 0, /* really reg 0 */ " calls ZC,*AL\n", }, { UCALL, INAREG, SSOREG, TANY, SANY, TAREG, NAREG|NASL, RESC1, /* really reg 0 */ " calls ZC,*AL\n", }, #endif { STCALL, INAREG, SCON, TANY, SANY, TAREG, NAREG|NASL, RESC1, /* should be register 0 */ " calls ZC,CL\n", }, { STCALL, FOREFF, SCON, TANY, SANY, TAREG, NAREG|NASL, 0, /* should be register 0 */ " calls ZC,CL\n", }, { STCALL, INAREG, SAREG, TANY, SANY, TAREG, NAREG|NASL, RESC1, /* should be 0 */ " calls ZC,(AL)\n", }, { STCALL, FOREFF, SAREG, TANY, SANY, TAREG, NAREG|NASL, 0, /* should be 0 */ " calls ZC,(AL)\n", }, /* * Function arguments */ { FUNARG, FOREFF, SCON|SAREG|SNAME|SOREG, TANY, SANY, TWORD|TPOINT|TFLOAT, 0, RNULL, " pushl AL\n" }, { FUNARG, FOREFF, SCON|SBREG|SNAME|SOREG, TLL|TDOUBLE, SANY, TANY, 0, RNULL, " movq Zl,-(%sp)\n" }, /* RS for signed <= int converted to negative LS */ #if 0 /* RS ulonglong converted to function call */ /* RS longlong converted to negative LS */ { RS, INBREG|FORCC, SBREG|AWD, TLONGLONG, SAREG|SBREG|AWD, TANY, NBREG|NBSL|NBSR, RESC1|RESCC, " ashq AR,AL,A1\n", }, #endif { RS, INAREG|FORCC, SAREG, TUCHAR, SAREG|SAWM, TANYFIXED, NAREG, RLEFT|RESCC, " subl3 AR,$8,A1\n extzv AR,A1,AL,AL\n", }, { RS, INAREG|FORCC, SAREG, TUSHORT, SAREG|SAWM, TANYFIXED, NAREG, RLEFT|RESCC, " subl3 AR,$16,A1\n extzv AR,A1,AL,AL\n", }, { RS, INAREG|FORCC, SAREG, TUNSIGNED, SAREG|SAWM, TANYFIXED, NAREG, RLEFT|RESCC, " subl3 AR,$32,A1\n extzv AR,A1,AL,AL\n", }, { RS, INAREG|FORCC, SAREG, TUNSIGNED|TUSHORT|TUCHAR, SCON, TANY, NAREG|NASL, RESC1|RESCC, " extzv AR,ZU,AL,A1\n", }, /* extv only for short and char, rest uses ashl/q */ { RS, INAREG|FORCC, SAREG, TSHORT|TCHAR, SCON, TANY, NAREG|NASL, RESC1|RESCC, " extv AR,ZU,AL,A1\n", }, { LS, INBREG|FORCC, SBREG|AWD, TLL, SAREG|SBREG|AWD, TANY, NBREG|NBSL|NBSR, RESC1|RESCC, " ashq AR,Zl,A1\n", }, { LS, INAREG|INAREG|FORCC, SAREG|AWD, TANYFIXED, SAREG|AWD, TANYFIXED, NAREG|NASL|NASR, RESC1|RESCC, " ashl AR,AL,A1\n", }, #if 0 { INCR, FOREFF, SAREG|AWD, TANY, SANY, TANY, 0, RLEFT, " ZE\n", }, { DECR, FOREFF, SAREG|AWD, TANY, SCON, TANY, 0, RLEFT, " ZE\n", }, { INCR, INAREG|INAREG, SAREG|AWD, TANY, SCON, TANY, NAREG, RESC1, " ZD\n", }, { DECR, INAREG|INAREG, SAREG|AWD, TANY, SCON, TANY, NAREG, RESC1, " ZD\n", }, #endif /* Assign to 64-bit register, three entries */ /* Have FOREFF first to catch mem-mem moves */ { ASSIGN, FOREFF, SBREG|AWD, TBREG, SCON, TBREG, 0, 0, "ZA", }, { ASSIGN, FOREFF, SBREG|AWD, TBREG, SBREG|AWD, TBREG, 0, 0, " movq Zr,AL\n", }, { ASSIGN, INBREG, SBREG, TBREG, SBREG|AWD, TBREG, 0, RDEST, " movq Zr,AL\n", }, { ASSIGN, INBREG, SBREG|AWD, TBREG, SBREG, TBREG, 0, RDEST, " movq AR,AL\n", }, /* Assign to 32-bit register, three entries */ { ASSIGN, FOREFF|FORCC, SAREG|AWD, TAREG, SCON, TAREG, 0, RESCC, "ZA", }, { ASSIGN, FOREFF|FORCC, SAREG|AWD, TAREG, SAREG|AWD, TAREG, 0, RESCC, " movZL AR,AL\n", }, { ASSIGN, INAREG|FORCC, SAREG, TAREG, SAREG|AWD, TAREG, 0, RDEST|RESCC, " movZL AR,AL\n", }, { ASSIGN, INAREG|FORCC, SAREG|AWD, TAREG, SAREG, TAREG, 0, RDEST|RESCC, " movZL AR,AL\n", }, /* Bitfields, not yet */ { ASSIGN, INAREG|FOREFF|FORCC, SFLD, TANY, SAREG|AWD, TWORD, 0, RDEST|RESCC, " insv AR,H,S,AL\n", }, { ASSIGN, INAREG|FOREFF|FORCC, SAREG|AWD, TWORD, SFLD, TANYSIGNED, 0, RDEST|RESCC, " extv H,S,AR,AL\n", }, { ASSIGN, INAREG|FOREFF|FORCC, SAREG|AWD, TWORD, SFLD, TANYUSIGNED, 0, RDEST|RESCC, " extzv H,S,AR,AL\n", }, /* dummy UNARY MUL entry to get U* to possibly match OPLTYPE */ { UMUL, FOREFF, SCC, TANY, SCC, TANY, 0, RNULL, " HELP HELP HELP\n", }, { UMUL, INBREG, SANY, TPOINT, SOREG, TBREG, NBREG|NBSL, RESC1, " movq AL,A1\n", }, { UMUL, INAREG, SANY, TPOINT|TWORD, SOREG, TPOINT|TWORD, NAREG|NASL, RESC1, " movl AL,A1\n", }, { UMUL, INAREG, SANY, TPOINT|TSHORT|TUSHORT, SOREG, TPOINT|TSHORT|TUSHORT, NAREG|NASL, RESC1, " movw AL,A1\n", }, { UMUL, INAREG, SANY, TPOINT|TCHAR|TUCHAR, SOREG, TPOINT|TCHAR|TUCHAR, NAREG|NASL, RESC1, " movb AL,A1\n", }, #if 0 { REG, FORARG, SANY, TANY, SAREG, TDOUBLE|TFLOAT, 0, RNULL, " movZR AR,-(%sp)\n", }, { REG, INTEMP, SANY, TANY, SAREG, TDOUBLE, 2*NTEMP, RESC1, " movd AR,A1\n", }, { REG, INTEMP, SANY, TANY, SAREG, TANY, NTEMP, RESC1, " movZF AR,A1\n", }, #endif { OPLTYPE, INBREG, SANY, TANY, SCON|SOREG|SNAME, TLONGLONG|TULONGLONG, NBREG, RESC1, " movq Zl,A1\n", }, { OPLTYPE, INBREG, SANY, TANY, SANY, TBREG, NBREG|NBSR, RESC1, " movZR AR,A1\n", }, { OPLTYPE, INAREG|INAREG, SANY, TANY, SANY, TAREG, NAREG|NASR, RESC1, " movZR AR,A1\n", }, { OPLTYPE, FORCC, SANY, TANY, SANY, TANY, 0, RESCC, " tstZR AR\n", }, #if 0 { OPLTYPE, FORARG, SANY, TANY, SANY, TWORD, 0, RNULL, " pushl AR\n", }, { OPLTYPE, FORARG, SANY, TANY, SANY, TCHAR|TSHORT, 0, RNULL, " cvtZRl AR,-(%sp)\n", }, { OPLTYPE, FORARG, SANY, TANY, SANY, TUCHAR|TUSHORT, 0, RNULL, " movzZRl AR,-(%sp)\n", }, { OPLTYPE, FORARG, SANY, TANY, SANY, TDOUBLE, 0, RNULL, " movd AR,-(%sp)\n", }, { OPLTYPE, FORARG, SANY, TANY, SANY, TFLOAT, 0, RNULL, " cvtfd AR,-(%sp)\n", }, #endif { UMINUS, INBREG, SBREG|AWD, TLL, SANY, TLL, NBREG|NBSL, RESC1|RESCC, " mnegl UL,U1\n mnegl AL,A1\n sbwc $0,U1\n", }, { UMINUS, INAREG|FORCC, SAREG|AWD, TAREG|TDOUBLE, SANY, TANY, NAREG|NASL, RESC1|RESCC, " mnegZL AL,A1\n", }, { UMINUS, INBREG|FORCC, SBREG|AWD, TDOUBLE, SANY, TANY, NBREG|NASL, RESC1|RESCC, " mnegZL AL,A1\n", }, { COMPL, INBREG, SBREG|AWD, TLL, SANY, TLL, NBREG|NBSL, RESC1|RESCC, " mcoml AL,A1\n mcoml UL,U1\n", }, { COMPL, INAREG|FORCC, SAREG|AWD, TINT|TUNSIGNED, SANY, TANY, NAREG|NASL, RESC1|RESCC, " mcomZL AL,A1\n", }, { COMPL, INAREG|FORCC, SAREG|AWD, TANYSIGNED|TANYUSIGNED, SANY, TANY, NAREG|NASL, RESC1|RESCC, " cvtZLl AL,A1\n mcoml A1,A1\n", }, { AND, FORCC, SAREG|AWD, TWORD, SCON, TWORD, 0, RESCC, " bitl ZZ,AL\n", }, { AND, FORCC, SAREG|AWD, TSHORT|TUSHORT, SSCON, TWORD, 0, RESCC, " bitw ZZ,AL\n", }, { AND, FORCC, SAREG|AWD, TCHAR|TUCHAR, SCCON, TWORD, 0, RESCC, " bitb ZZ,AL\n", }, { MUL, INAREG|FORCC, SAREG|AWD, TANYFIXED, SAREG|AWD, TANYFIXED, NAREG|NASL|NASR, RESC1|RESCC, " mulZL3 AR,AL,A1\n", }, { OPMUL, INAREG|INAREG|FORCC, SAREG, TINT|TUNSIGNED|TLONG|TULONG, SAREG|AWD, TINT|TUNSIGNED|TLONG|TULONG, 0, RLEFT|RESCC, " OL2 AR,AL\n", }, { OPMUL, INAREG|INAREG|FORCC, SAREG|AWD, TINT|TUNSIGNED|TLONG|TULONG, SAREG|AWD, TINT|TUNSIGNED|TLONG|TULONG, NAREG|NASL|NASR, RESC1|RESCC, " OL3 AR,AL,A1\n", }, { MOD, INAREG|INAREG, SAREG|AWD, TINT, SAREG|AWD, TINT, NAREG, RESC1, " divl3 AR,AL,A1\n mull2 AR,A1\n subl3 A1,AL,A1\n", }, { PLUS, INBREG|FORCC, SBREG, TLL, SBREG|AWD, TLL, 0, RLEFT, " addl2 AR,AL\n" " adwc UR,UL\n", }, { PLUS, INAREG|FORCC, SAREG, TANYFIXED, SONE, TANY, 0, RLEFT|RESCC, " incZL AL\n", }, { MINUS, INAREG|FORCC, SAREG, TANYFIXED, SONE, TANY, 0, RLEFT|RESCC, " decZL AL\n", }, { MINUS, INBREG|FORCC, SBREG, TLL, SBREG|AWD, TLL, 0, RLEFT, " subl2 AR,AL\n" " sbwc UR,UL\n", }, { DIV, INBREG, SBREG|AWD, TLL, SBREG|AWD, TLL, NSPECIAL|NBREG|NBSL|NBSR, RESC1, "ZO", }, { MOD, INBREG, SBREG|AWD, TLL, SBREG|AWD, TLL, NSPECIAL|NBREG|NBSL|NBSR, RESC1, "ZO", }, { MUL, INBREG, SBREG|AWD, TLL, SBREG|AWD, TLL, NSPECIAL|NBREG|NBSL|NBSR, RESC1, "ZO", }, { OR, INBREG, SBREG, TLL, SBREG|AWD, TLL, 0, RLEFT, " bisl2 AR,AL\n bisl2 UR,UL\n", }, { OR, INBREG, SBREG|AWD, TLL, SBREG|AWD, TLL, NBREG, RESC1, " bisl3 AR,AL,A1\n bisl3 UR,UL,U1\n", }, { ER, INBREG, SBREG, TLL, SBREG|AWD, TLL, 0, RLEFT, " xorl2 AR,AL\n xorl2 UR,UL\n", }, { ER, INBREG, SBREG|AWD, TLL, SBREG|AWD, TLL, NBREG, RESC1, " xorl3 AR,AL,A1\n xorl3 UR,UL,U1\n", }, { AND, INBREG, SBREG, TLL, SBREG|AWD, TLL, 0, RLEFT, " bicl2 AR,AL\n bicl2 UR,UL\n", }, { AND, INBREG, SBREG|AWD, TLL, SBREG|AWD, TLL, NBREG, RESC1, " bicl3 AR,AL,A1\n bicl3 UR,UL,U1\n", }, { OPSIMP, INAREG|FOREFF|FORCC, SAREG, TWORD, SAREG|AWD, TWORD, 0, RLEFT|RESCC, " OL2 AR,AL\n", }, { OPSIMP, INAREG|FORCC, SAREG|AWD, TWORD, SAREG|AWD, TWORD, NAREG|NASL|NASR, RESC1|RESCC, " OL3 AR,AL,A1\n", }, { OPSIMP, INAREG|FOREFF|FORCC, SAREG, TSHORT|TUSHORT, SAREG|AWD, TSHORT|TUSHORT, 0, RLEFT|RESCC, " OW2 AR,AL\n", }, { OPSIMP, INAREG|FORCC, SAREG|AWD, TSHORT|TUSHORT, SAREG|AWD, TSHORT|TUSHORT, NAREG|NASL|NASR, RESC1|RESCC, " OW3 AR,AL,A1\n", }, { OPSIMP, INAREG|FOREFF|FORCC, SAREG, TCHAR|TUCHAR, SAREG|AWD, TCHAR|TUCHAR, 0, RLEFT|RESCC, " OB2 AR,AL\n", }, { OPSIMP, INAREG|FORCC, SAREG|AWD, TCHAR|TUCHAR, SAREG|AWD, TCHAR|TUCHAR, NAREG|NASL|NASR, RESC1|RESCC, " OB3 AR,AL,A1\n", }, { OPFLOAT, INAREG|FORCC, SAREG, TFLOAT, SAREG|AWD, TFLOAT, 0, RLEFT|RESCC, " OF2 AR,AL\n", }, { OPFLOAT, INAREG|FORCC, SAREG|AWD, TFLOAT, SAREG|AWD, TFLOAT, NAREG|NASL|NASR, RESC1|RESCC, " OF3 AR,AL,A1\n", }, { OPFLOAT, INBREG|FORCC, SBREG, TDOUBLE, SBREG|AWD, TDOUBLE, 0, RLEFT|RESCC, " OD2 AR,AL\n", }, { OPFLOAT, INBREG|FORCC, SBREG|AWD, TDOUBLE, SBREG|AWD, TDOUBLE, NBREG|NBSL|NBSR, RESC1|RESCC, " OD3 AR,AL,A1\n", }, #if 0 /* XXX probably wrong */ { OPFLOAT, INAREG|INAREG|FORCC, SAREG|AWD, TFLOAT, SAREG|AWD, TDOUBLE, NAREG|NASL, RESC1|RESCC, " cvtfd AL,A1\n OD2 AR,A1\n", }, { OPFLOAT, INAREG|INAREG|FORCC, SAREG|AWD, TDOUBLE, SAREG|AWD, TFLOAT, NAREG|NASR, RESC1|RESCC, " cvtfd AR,A1\n OD3 A1,AL,A1\n", }, { OPFLOAT, INAREG|INAREG|FORCC, SAREG|AWD, TFLOAT, SAREG|AWD, TFLOAT, NAREG|NASL|NASR, RESC1|RESCC, " OF3 AR,AL,A1\n cvtfd A1,A1\n", }, #endif /* Default actions for hard trees ... */ # define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,"" { UMUL, DF( UMUL ), }, { ASSIGN, DF(ASSIGN), }, { STASG, DF(STASG), }, { OPLEAF, DF(NAME), }, { OPLOG, FORCC, SANY, TANY, SANY, TANY, REWRITE, BITYPE, "", }, { OPUNARY, DF(UMINUS), }, { OPANY, DF(BITYPE), }, { FREE, FREE, FREE, FREE, FREE, FREE, FREE, FREE, "help; I'm in trouble\n" } }; pcc-20181216/cc004075500017500000000000000000001340533064100117745ustar raggewheelpcc-20181216/cc/CVS004075500017500000000000000000001340533064100124275ustar raggewheelpcc-20181216/cc/CVS/Root010064400017500000000000000000111340533064000133400ustar raggewheel/cvsroot pcc-20181216/cc/CVS/Repository010064400017500000000000000000071340533064000146010ustar raggewheelpcc/cc pcc-20181216/cc/CVS/Entries010064400017500000000000000001461340533064100140400ustar raggewheel/Makefile.in/1.9/Sun Jan 1 16:27:25 2012// D/cc//// D/ccom//// D/cpp//// D/cxxcom//// D/driver//// D pcc-20181216/cc/Makefile.in010064400017500000000000000013531170010455500141160ustar raggewheel# $Id: Makefile.in,v 1.9 2012/01/01 16:27:25 ragge Exp $ # # Makefile.in for top-level of pcc. # @SET_MAKE@ ALL_SUBDIRS= cc cpp ccom cxxcom DIST_SUBDIRS= $(ALL_SUBDIRS) driver all install clean: @for subdir in $(ALL_SUBDIRS); do \ _nextdir_=$${_thisdir_+$$_thisdir_/}$$subdir; \ echo "===> $$_nextdir_"; \ (_thisdir_=$$_nextdir_; export _thisdir_; cd $$subdir && \ exec $(MAKE) $(MFLAGS) $@) || exit $$?; \ echo "<=== $$_nextdir_"; \ done distclean: @for subdir in $(DIST_SUBDIRS); do \ _nextdir_=$${_thisdir_+$$_thisdir_/}$$subdir; \ echo "===> $$_nextdir_"; \ (_thisdir_=$$_nextdir_; export _thisdir_; cd $$subdir && \ exec $(MAKE) $(MFLAGS) $@) || exit $$?; \ echo "<=== $$_nextdir_"; \ done rm -f Makefile pcc-20181216/cc/cc004075500017500000000000000000001340533064000123605ustar raggewheelpcc-20181216/cc/cc/CVS004075500017500000000000000000001340533064000130135ustar raggewheelpcc-20181216/cc/cc/CVS/Root010064400017500000000000000000111340533064000137250ustar raggewheel/cvsroot pcc-20181216/cc/cc/CVS/Repository010064400017500000000000000000121340533064000151620ustar raggewheelpcc/cc/cc pcc-20181216/cc/cc/CVS/Entries010064400017500000000000000001741340533064000144250ustar raggewheel/Makefile.in/1.38/Tue Sep 11 11:24:08 2018// /cc.1/1.45/Mon Oct 10 11:27:49 2016// /cc.c/1.321/Sat Dec 15 09:11:17 2018// D pcc-20181216/cc/cc/Makefile.in010064400017500000000000000046171334572273000145210ustar raggewheel# $Id: Makefile.in,v 1.38 2018/09/11 11:24:08 ragge Exp $ # # Makefile.in for the cc part of pcc. # VPATH=@srcdir@ srcdir=@srcdir@ top_srcdir=@top_srcdir@ top_builddir=@top_builddir@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ libdir = @libdir@ libexecdir = @libexecdir@ includedir = @includedir@ datarootdir = @datarootdir@ mandir = @mandir@ CC = @CC@ EXEEXT = @EXEEXT@ BINPREFIX = @BINPREFIX@ TARGOS = @targos@ TARGOSVER = @targosver@ TARGMACH = @targmach@ TARGMACHDIR = @targmachdir@ TARGET = @target@ VERSION = @PACKAGE_VERSION@ PCCLIBDIR = $(libdir)/pcc/$(TARGET)/$(VERSION)/lib PCCINCDIR = $(libdir)/pcc/$(TARGET)/$(VERSION)/include CFLAGS = @CFLAGS@ @ADD_CFLAGS@ CPPFLAGS = @CPPFLAGS@ -DLIBEXECDIR=\"$(libexecdir)/\" \ @ADD_CPPFLAGS@ -DINCLUDEDIR=\"$(includedir)/\" \ -DPCCINCDIR=\"$(PCCINCDIR)/\" -DPCCLIBDIR=\"$(PCCLIBDIR)/\" \ -Dos_$(TARGOS) -Dmach_$(TARGMACH) -DTARGOSVER=$(TARGOSVER) \ -DCXXPROGNAME=\"$(BINPREFIX)p++$(EXEEXT)\" \ -DCPPROGNAME=\"$(BINPREFIX)pcpp$(EXEEXT)\" \ -I$(top_srcdir)/cc/driver -I$(top_builddir) \ -I$(top_srcdir)/os/$(TARGOS) -I$(MIPDIR) -I$(MDIR) -I$(COMMONDIR) LIBS = @LIBS@ LDFLAGS = @LDFLAGS@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ MIPDIR=$(top_srcdir)/mip MDIR=$(top_srcdir)/arch/$(TARGMACHDIR) COMMONDIR=$(top_srcdir)/common DEST=cc$(EXEEXT) DRIVERS=pcc pcpp p++ all: $(DEST) OBJS= cc.o compat.o strlist.o xalloc.o cc.o: $(srcdir)/cc.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/cc.c compat.o: $(COMMONDIR)/compat.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(COMMONDIR)/compat.c strlist.o: $(top_srcdir)/cc/driver/strlist.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(top_srcdir)/cc/driver/strlist.c xalloc.o: $(top_srcdir)/cc/driver/xalloc.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(top_srcdir)/cc/driver/xalloc.c $(DEST): $(OBJS) $(CC) $(LDFLAGS) $(OBJS) -o $@ $(LIBS) install: test -z "$(DESTDIR)$(bindir)" || mkdir -p "$(DESTDIR)$(bindir)" test -z "$(DESTDIR)$(mandir)/man1" || mkdir -p "$(DESTDIR)$(mandir)/man1" @for driver in $(DRIVERS); do \ $(INSTALL_PROGRAM) $(DEST) $(DESTDIR)$(bindir)/$(BINPREFIX)$$driver$(EXEEXT); \ $(INSTALL_DATA) $(srcdir)/cc.1 $(DESTDIR)$(mandir)/man1/$$driver.1; \ done test -z "$(DESTDIR)$(PCCINCDIR)" || mkdir -p "$(DESTDIR)$(PCCINCDIR)" test -z "$(DESTDIR)$(PCCLIBDIR)" || mkdir -p "$(DESTDIR)$(PCCLIBDIR)" clean: rm -f $(OBJS) $(DEST) distclean: clean rm -f Makefile pcc-20181216/cc/cc/cc.1010064400017500000000000000226361277667546500131470ustar raggewheel.\" $Id: cc.1,v 1.45 2016/10/10 11:27:49 ragge Exp $ .\" .\" Copyright (c) 2007 Jeremy C. Reed .\" .\" Permission to use, copy, modify, and/or distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR AND CONTRIBUTORS DISCLAIM .\" ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHOR AND .\" CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL .\" DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR .\" PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS .\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF .\" THIS SOFTWARE. .\" .Dd June 20, 2014 .Dt CC 1 .Os .Sh NAME .Nm cc .Nd front-end to the C compiler .Sh SYNOPSIS .Nm .Op Fl cEgkMPSstvX .Op Fl ansi .Op Fl B Ns Ar prefix .Op Fl D Ar macro Ns Oo = Ns Ar value Oc .Op Fl d Ns Ar flags .Op Fl f Ns Ar feature .Op Fl I Ar path .Op Fl include Ar file .Op Fl isystem Ar path .Op Fl L Ns Ar path .Op Fl m Ns Ar option .Op Fl nodefaultlibs .Op Fl nostartfiles .Op Fl nostdinc .Op Fl nostdlib .Op Fl O Ns Oo Ar level Oc .Op Fl o Ar outfile .Op Fl pg .Op Fl pthread .Op Fl shared .Op Fl static .Op Fl std= Ns Ar standard .Op Fl U Ar macro .Op Fl Wa Ns , Ns Ar options .Op Fl Wc Ns , Ns Ar options .Op Fl Wl Ns , Ns Ar options .Op Fl Wp Ns , Ns Ar options .Op Fl x Ar language .Op Fl z Ar keyword .Op Ar .Sh DESCRIPTION The .Nm utility provides a front-end to the .Dq portable C compiler . Multiple files may be given on the command line. Unrecognized options are sent directly to .Xr ld 1 . .Pp .\" Brief description of its syntax: Filenames that end with .Sy \&.c are passed via .Xr cpp 1 \(-> .Xr ccom 1 \(-> .Xr as 1 \(-> .Xr ld 1 . .Pp Filenames that end with .Sy \&.i are passed via .Xr ccom 1 \(-> .Xr as 1 \(-> .Xr ld 1 . .Pp Filenames that end with .Sy \&.s are passed via .Xr as 1 \(-> .Xr ld 1 . .Pp Filenames that end with .Sy \&.S are passed via .Xr cpp 1 \(-> .Xr as 1 \(-> .Xr ld 1 . .Pp Filenames that end with .Sy \&.o are passed directly to .Xr ld 1 . .Pp .\" The options are as follows: .Bl -tag -width Ds .It Fl ansi Synonym for .Fl std=c89 . .It Fl B Ns Ar prefix Define alternate prefix path for .Xr cpp 1 , .Xr ccom 1 , .Xr as 1 , or .Xr ld 1 executables. .\" TODO: provide an example of -B .It Fl C Passed to the .Xr cpp 1 preprocessor to not discard comments. .It Fl c Stop after generating object code with .Xr as 1 . Do not link. The resulting object output is saved as a filename with a .Dq \&.o suffix unless .Fl o option is used. Note: cannot be combined with .Fl o if multiple files are given. .It Fl D Ar macro Ns Oo = Ns Ar value Oc Passed to the .Xr cpp 1 preprocessor to define .Ar macro with an optional .Ar value . .It Fl d Ns Ar flags Debug options. .Ar flags is a string of characters, which signify the following actions. .Bl -tag -width ".Sy M" .It Sy M Cause the preprocessor to output a list of macro definitions. .El .Lp any unknown flags are ignored. .It Fl E Stop after preprocessing with .Xr cpp 1 . Do not compile, assemble, or link. Output is sent to standard output unless the .Fl o option is used. .It Fl ffreestanding Assume a freestanding environment. .It Fl fPIC Generate PIC code. .\" TODO: document about avoiding machine-specific maximum size? .It Fl fpic Tells C compiler to generate PIC code and tells assembler that PIC code has been generated. .\" TODO: document difference between PIC and pic .It Fl funsigned-char Tell the compiler to treat .Sq char types as if they were unsigned unless explicitly defined otherwise. .Fl fsigned-char can be used to signify the opposite behaviour. The default for the .Sq char type depends on the compiler target architecture. .It Fl fstack-protector Tell the compiler to wrap functions with code which checks at runtime that a stack overflow has not occurred. When stack protection is in effect, the .Dv __SSP__ macro will be defined. .\" other -f GCC compatibility flags are ignored for now .It Fl g Send .Fl g flag to .Xr ccom 1 to create debug output. Debug information output can be disabled with .Fl g0 . .It Fl I Ar path Passed to the .Xr cpp 1 preprocessor to add header search directory to override system defaults. .It Fl include Ar file Tells the .Xr cpp 1 preprocessor to include the .Ar file during preprocessing. .It Fl isystem Ar path Defines .Ar path as a system header directory for the .Xr cpp 1 preprocessor. .It Fl k Generate PIC code. See .Fl fpic option. .It Fl L Ns Ar path Passed to the linker, to add .Ar path to the list of directories searched for shared libraries. .It Fl M Pass .Fl M flag to .Xr cpp 1 to generate dependencies for .Xr make 1 . .It Fl m Ns Ar option Target-dependent options. Multiple .Fl m options can be given, the following are supported: .Bl -tag -width PowerPC .It ARM \-mlittle-endian \-mbig-endian \-mfpe=fpa \-mfpe=vpf \-msoft-float \-march=armv1 \-march=armv2 \-march=armv2a \-march=armv3 \-march=armv4 \-march=armv4t \-march=armv4tej \-march=armv5 \-march=armv6 \-march=armv6t2 \-march=armv6kz \-march=armv6k \-march=armv7 .It HPPA .It i386 .It MIPS \-mlittle-endian \-mbig-endian \-mhard-float \-msoft-float .It PDP-10 .It PowerPC .It Sparc64 .It VAX .El .It Fl nodefaultlibs Do not link with the system default libraries (libc, etc.) .It Fl nostartfiles Do not link with the system startup files (crt0.c, etc.) .It Fl nostdinc Do not use the system include paths (/usr/include, etc.) .It Fl nostdlib Do not link with the system default libraries or startup files. .It Fl O Ns Oo Ar level Oc Enable compiler optimizations. Currently, for levels higher than zero, this defines .Dv __OPTIMIZE__ in the .Xr cpp 1 preprocessor, and passes .Fl xdce , .Fl xdeljumps , .Fl xtemps and .Fl xinline to .Xr ccom 1 . If no level is given the optimization level is .Fl O1 . Optimizations can be disabled using .Fl O0 . In situations where multiple optimization flags are given, the last flag is the one used. .It Fl o Ar outfile Save result to .Ar outfile . .It Fl P Inhibit generation of line markers in preprocessor output. This is sometimes useful when running the preprocessor on something other than C code. .It Fl pg Enable profiling on the generated executable. .It Fl pthread Defines the .Dv _PTHREADS preprocessor identifier for .Xr cpp 1 , and adds .Fl lpthread to the .Xr ld 1 linker arguments. .It Fl S Stop after compilation by .Xr ccom 1 . Do not assemble and do not link. The resulting assembler-language output is saved as a filename with a .Dq \&.s suffix unless the .Fl o option is used. Note: cannot be combined with .Fl o if multiple files are given. .It Fl s Passed to .Xr ld 1 to remove all symbol table and relocation information from the generated executable. This option is silently ignored if .Nm does not invoke the linker. .It Fl shared Create a shared object of the result. Tells the linker not to generate an executable. .It Fl static Do not use dynamic linkage. By default, it will link using the dynamic linker options and/or shared objects for the platform. .It Fl std= Ns Ar standard Compile to the specified .Ar standard . Accepted values for .Ar standard are .Ar c89 , .Ar c99 , .Ar gnu89 , .Ar gnu99 , .Ar gnu9x , and .Ar c11 . .It Fl t Passed to .Xr cpp 1 to suppress some default macro definitions and enable use of traditional C preprocessor syntax. .It Fl U Ar macro Passes to the .Xr cpp 1 preprocessor to remove the initial macro definition. .It Fl v Outputs the version of .Nm and shows commands as they are run with their command line arguments. .It Fl ### As per .Fl v except that the commands are not run, and the arguments will be quoted if they contain unusual characters or spaces. .It Fl Wa Ns , Ns Ar options Comma separated list of options for the assembler. .It Fl Wc Ns , Ns Ar options Comma separated list of options for the compiler. .It Fl Wl Ns , Ns Ar options Comma separated list of options for the linker. .It Fl Wp Ns , Ns Ar options Comma separated list of options for the preprocessor. .It Fl X Don't remove temporary files on exit. .It Fl x Ar language GCC compatibility option; specify the language in use rather than interpreting the filename extension. Currently known language values are .Sy none , .Sy c , .Sy c++ , .Sy assembler and .Sy assembler-with-cpp . Any unknown .Fl x options are passed to .Xr ccom 1 . .It Fl z Ar keyword Passed to .Xr ld 1 . Please refer to the documentation of your linker for acceptable values of .Ar keyword . .El .Ss Predefined Macros A few macros are predefined by .Nm when sent to .Xr cpp 1 . .Bl -diag .It __PCC__ Set to the major version of .Xr pcc 1 . These macros can be used to select code based on .Xr pcc 1 compatibility. See the .Fl v option. .It __PCC_MINOR__ Set to the minor version. .It __PCC_MINORMINOR__ Set to the minor-minor version \(em the number after the minor version. .It _PTHREADS Defined when .Fl pthread switch is used. .It __ASSEMBLER__ Defined when input files have a .S suffix, or if the .Fl x Ns assembler-with-cpp option is specified. .El .Pp Also system- and/or machine-dependent macros may also be predefined; for example: .Dv __NetBSD__ , .Dv __ELF__ , and .Dv __i386__ . .Sh SEE ALSO .Xr as 1 , .Xr ccom 1 , .Xr cpp 1 , .Xr ld 1 .Sh HISTORY The .Nm command comes from the original Portable C Compiler by .An "S. C. Johnson" , written in the late 70's. .Pp This product includes software developed or owned by Caldera International, Inc. pcc-20181216/cc/cc/cc.c010064400017500000000000001420471340514246500132030ustar raggewheel/* $Id: cc.c,v 1.321 2018/12/15 09:11:17 plunky Exp $ */ /*- * Copyright (c) 2011 Joerg Sonnenberger . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code and documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditionsand the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Front-end to the C compiler. * * Brief description of its syntax: * - Files that end with .c are passed via cpp->ccom->as->ld * - Files that end with .i are passed via ccom->as->ld * - Files that end with .S are passed via cpp->as->ld * - Files that end with .s are passed via as->ld * - Files that end with .o are passed directly to ld * - Multiple files may be given on the command line. * - Unrecognized options are all sent directly to ld. * -c or -S cannot be combined with -o if multiple files are given. * * This file should be rewritten readable. */ #include "config.h" #include #ifdef HAVE_SYS_WAIT_H #include #endif #include #include #include #ifdef HAVE_LIBGEN_H #include #endif #include #include #include #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include #ifdef _WIN32 #include #include #include #define F_OK 0x00 #define R_OK 0x04 #define W_OK 0x02 #define X_OK R_OK #endif #include "compat.h" #include "macdefs.h" #include "xalloc.h" #include "strlist.h" #include "ccconfig.h" /* C command */ #define CC_DRIVER #include "softfloat.h" /* for CPP floating point macros */ #define MKS(x) _MKS(x) #define _MKS(x) #x /* default program names in pcc */ /* May be overridden if cross-compiler is generated */ #ifndef CXXPROGNAME /* name as C++ front end */ #define CXXPROGNAME "c++" #endif #ifndef CPPROGNAME #define CPPROGNAME "cpp" /* name as CPP front end */ #endif #ifndef PREPROCESSOR #define PREPROCESSOR "cpp" /* "real" preprocessor name */ #endif #ifndef COMPILER #define COMPILER "ccom" #endif #ifndef CXXCOMPILER #define CXXCOMPILER "cxxcom" #endif #ifndef ASSEMBLER #define ASSEMBLER "as" #endif #ifndef LINKER #define LINKER "ld" #endif char *passp = PREPROCESSOR; char *pass0 = COMPILER; char *passxx0 = CXXCOMPILER; char *as = ASSEMBLER; char *ld = LINKER; char *sysroot = "", *isysroot; /* crt files using pcc default names */ #ifndef CRTBEGIN_S #define CRTBEGIN_S "crtbeginS.o" #endif #ifndef CRTEND_S #define CRTEND_S "crtendS.o" #endif #ifndef CRTBEGIN_T #define CRTBEGIN_T "crtbeginT.o" #endif #ifndef CRTEND_T #define CRTEND_T "crtendT.o" #endif #ifndef CRTBEGIN #define CRTBEGIN "crtbegin.o" #endif #ifndef CRTEND #define CRTEND "crtend.o" #endif #ifndef CRTI #define CRTI "crti.o" #endif #ifndef CRTN #define CRTN "crtn.o" #endif #ifndef CRT0 #define CRT0 "crt0.o" #endif #ifndef GCRT0 #define GCRT0 "gcrt0.o" #endif #ifndef RCRT0 #define RCRT0 "rcrt0.o" #endif /* preprocessor stuff */ #ifndef STDINC #define STDINC "/usr/include/" #endif #ifdef MULTIARCH_PATH #define STDINC_MA STDINC MULTIARCH_PATH "/" #endif char *cppadd[] = CPPADD; char *cppmdadd[] = CPPMDADD; /* Default libraries and search paths */ #ifndef PCCLIBDIR /* set by autoconf */ #define PCCLIBDIR NULL #endif #ifndef LIBDIR #define LIBDIR "/usr/lib/" #endif #ifndef DEFLIBDIRS /* default library search paths */ #ifdef MULTIARCH_PATH #define DEFLIBDIRS { LIBDIR, LIBDIR MULTIARCH_PATH "/", 0 } #else #define DEFLIBDIRS { LIBDIR, 0 } #endif #endif #ifndef DEFLIBS /* default libraries included */ #define DEFLIBS { "-lpcc", "-lc", "-lpcc", 0 } #endif #ifndef DEFPROFLIBS /* default profiling libraries */ #define DEFPROFLIBS { "-lpcc", "-lc_p", "-lpcc", 0 } #endif #ifndef DEFCXXLIBS /* default c++ libraries */ #define DEFCXXLIBS { "-lp++", "-lpcc", "-lc", "-lpcc", 0 } #endif #ifndef STARTLABEL #define STARTLABEL "__start" #endif #ifndef DYNLINKARG #define DYNLINKARG "-dynamic-linker" #endif #ifndef DYNLINKLIB #define DYNLINKLIB NULL #endif char *dynlinkarg = DYNLINKARG; char *dynlinklib = DYNLINKLIB; char *pcclibdir = PCCLIBDIR; char *deflibdirs[] = DEFLIBDIRS; char *deflibs[] = DEFLIBS; char *defproflibs[] = DEFPROFLIBS; char *defcxxlibs[] = DEFCXXLIBS; char *outfile, *MFfile, *fname; static char **lav; static int lac; static char *find_file(const char *file, struct strlist *path, int mode); static int preprocess_input(char *input, char *output, int dodep); static int compile_input(char *input, char *output); static int assemble_input(char *input, char *output); static int run_linker(void); static int strlist_exec(struct strlist *l); char *cat(const char *, const char *); char *setsuf(char *, char); int cxxsuf(char *); int getsuf(char *); char *getsufp(char *s); int main(int, char *[]); void errorx(int, char *, ...); int cunlink(char *); void exandrm(char *); void dexit(int); void idexit(int); char *gettmp(void); void oerror(char *); char *argnxt(char *, char *); char *nxtopt(char *o); void setup_cpp_flags(void); void setup_ccom_flags(void); void setup_as_flags(void); void setup_ld_flags(void); static void expand_sysroot(void); #ifdef _WIN32 char *win32pathsubst(char *); char *win32commandline(struct strlist *l); #endif int sspflag; int freestanding; int Sflag; int cflag; int gflag; int rflag; int vflag; int noexec; /* -### */ int tflag; int Eflag; int Oflag; int kflag; /* generate PIC/pic code */ #define F_PIC 1 #define F_pic 2 int Mflag, needM, MDflag, MMDflag; /* dependencies only */ int pgflag; int pieflag; int Xflag; int nostartfiles, Bstatic, shared; int nostdinc, nostdlib; int pthreads; int xgnu89, xgnu99, c89defs, c99defs, c11defs; int ascpp; #ifdef CHAR_UNSIGNED int xuchar = 1; #else int xuchar = 0; #endif int cxxflag; int cppflag; int printprogname, printfilename, printsearchdirs; enum { SC11, STRAD, SC89, SGNU89, SC99, SGNU99 } cstd; #ifdef SOFTFLOAT int softfloat = 1; #else int softfloat = 0; #endif #ifdef TARGET_BIG_ENDIAN int bigendian = 1; #else int bigendian = 0; #endif #ifdef mach_amd64 int amd64_i386; #endif #define match(a,b) (strcmp(a,b) == 0) /* handle gcc warning emulations */ struct Wflags { char *name; int flags; #define INWALL 1 #define INWEXTRA 2 } Wflags[] = { { "truncate", 0 }, { "strict-prototypes", 0 }, { "missing-prototypes", INWEXTRA }, { "implicit-int", INWALL }, { "implicit-function-declaration", INWALL }, { "shadow", INWEXTRA }, { "pointer-sign", INWALL }, { "sign-compare", INWEXTRA }, { "unknown-pragmas", INWALL }, { "unreachable-code", INWEXTRA }, { "deprecated-declarations", INWEXTRA }, { "attributes", 0 }, { "uninitialized", INWEXTRA }, { NULL, 0 }, }; #ifndef USHORT /* copied from mip/manifest.h */ #define USHORT 5 #define INT 6 #define UNSIGNED 7 #endif /* * Wide char defines. */ #if WCHAR_TYPE == USHORT #define WCT "short unsigned int" #define WCM "65535U" #if WCHAR_SIZE != 2 #error WCHAR_TYPE vs. WCHAR_SIZE mismatch #endif #elif WCHAR_TYPE == INT #define WCT "int" #define WCM "2147483647" #if WCHAR_SIZE != 4 #error WCHAR_TYPE vs. WCHAR_SIZE mismatch #endif #elif WCHAR_TYPE == UNSIGNED #define WCT "unsigned int" #define WCM "4294967295U" #if WCHAR_SIZE != 4 #error WCHAR_TYPE vs. WCHAR_SIZE mismatch #endif #else #error WCHAR_TYPE not defined or invalid #endif #ifdef GCC_COMPAT #ifndef REGISTER_PREFIX #define REGISTER_PREFIX "" #endif #ifndef USER_LABEL_PREFIX #define USER_LABEL_PREFIX "" #endif #endif #ifndef PCC_WINT_TYPE #define PCC_WINT_TYPE "unsigned int" #endif #ifndef PCC_SIZE_TYPE #define PCC_SIZE_TYPE "unsigned long" #endif #ifndef PCC_PTRDIFF_TYPE #define PCC_PTRDIFF_TYPE "long int" #endif struct strlist preprocessor_flags; struct strlist depflags; struct strlist incdirs; struct strlist user_sysincdirs; struct strlist includes; struct strlist sysincdirs; struct strlist dirafterdirs; struct strlist crtdirs; struct strlist libdirs; struct strlist progdirs; struct strlist early_linker_flags; struct strlist middle_linker_flags; struct strlist late_linker_flags; struct strlist inputs; struct strlist assembler_flags; struct strlist temp_outputs; struct strlist compiler_flags; int main(int argc, char *argv[]) { struct Wflags *Wf; struct string *s; char *t, *u, *argp; char *msuffix; int ninput, j; lav = argv; lac = argc; ninput = 0; strlist_init(&crtdirs); strlist_init(&libdirs); strlist_init(&progdirs); strlist_init(&preprocessor_flags); strlist_init(&incdirs); strlist_init(&user_sysincdirs); strlist_init(&includes); strlist_init(&sysincdirs); strlist_init(&dirafterdirs); strlist_init(&depflags); strlist_init(&early_linker_flags); strlist_init(&middle_linker_flags); strlist_init(&late_linker_flags); strlist_init(&inputs); strlist_init(&assembler_flags); strlist_init(&temp_outputs); strlist_init(&compiler_flags); if ((t = strrchr(argv[0], '/'))) t++; else t = argv[0]; if (match(t, CXXPROGNAME)) { cxxflag = 1; } else if (match(t, CPPROGNAME)) { Eflag = cppflag = 1; } #ifdef PCC_EARLY_SETUP PCC_EARLY_SETUP #endif #ifdef _WIN32 /* have to prefix path early. -B may override */ incdir = win32pathsubst(incdir); altincdir = win32pathsubst(altincdir); libdir = win32pathsubst(libdir); #ifdef PCCINCDIR pccincdir = win32pathsubst(pccincdir); pxxincdir = win32pathsubst(pxxincdir); #endif #ifdef PCCLIBDIR pcclibdir = win32pathsubst(pcclibdir); #endif passp = win32pathsubst(passp); pass0 = win32pathsubst(pass0); #ifdef STARTFILES for (i = 0; startfiles[i] != NULL; i++) startfiles[i] = win32pathsubst(startfiles[i]); for (i = 0; endfiles[i] != NULL; i++) endfiles[i] = win32pathsubst(endfiles[i]); #endif #ifdef STARTFILES_T for (i = 0; startfiles_T[i] != NULL; i++) startfiles_T[i] = win32pathsubst(startfiles_T[i]); for (i = 0; endfiles_T[i] != NULL; i++) endfiles_T[i] = win32pathsubst(endfiles_T[i]); #endif #ifdef STARTFILES_S for (i = 0; startfiles_S[i] != NULL; i++) startfiles_S[i] = win32pathsubst(startfiles_S[i]); for (i = 0; endfiles_S[i] != NULL; i++) endfiles_S[i] = win32pathsubst(endfiles_S[i]); #endif #endif while (--lac) { ++lav; argp = *lav; #ifdef PCC_EARLY_ARG_CHECK PCC_EARLY_ARG_CHECK #endif if (*argp != '-' || match(argp, "-")) { /* Check for duplicate .o files. */ if (getsuf(argp) == 'o') { j = 0; STRLIST_FOREACH(s, &inputs) if (match(argp, s->value)) j++; if (j) continue; /* skip it */ } strlist_append(&inputs, argp); ninput++; continue; } switch (argp[1]) { default: oerror(argp); break; case '#': if (match(argp, "-###")) { printf("%s\n", VERSSTR); vflag++; noexec++; } else oerror(argp); break; case '-': /* double -'s */ if (match(argp, "--version")) { printf("%s\n", VERSSTR); return 0; } else if (strncmp(argp, "--sysroot=", 10) == 0) { sysroot = argp + 10; } else if (strncmp(argp, "--sysroot", 9) == 0) { sysroot = nxtopt(argp); } else if (strcmp(argp, "--param") == 0) { /* NOTHING YET */; (void)nxtopt(0); /* ignore arg */ } else oerror(argp); break; case 'a': /* only -ansi switch for now */ if (match(argp, "-ansi")) cstd = SC89; else oerror(argp); break; case 'B': /* other search paths for binaries */ t = nxtopt("-B"); strlist_append(&crtdirs, t); strlist_append(&libdirs, t); strlist_append(&progdirs, t); break; case 'C': if (match(argp, "-C") || match(argp, "-CC")) strlist_append(&preprocessor_flags, argp); else oerror(argp); break; case 'c': cflag++; break; case 'd': /* debug options */ if (match(argp, "-dumpmachine")) { /* Print target and immediately exit */ puts(TARGSTR); exit(0); } if (match(argp, "-dumpversion")) { /* Print claimed gcc level, immediately exit */ puts("4.3.1"); exit(0); } for (t = &argp[2]; *t; t++) { if (*t == 'M') strlist_append(&preprocessor_flags, "-dM"); /* ignore others */ } break; case 'E': Eflag++; break; case 'f': /* GCC compatibility flags */ u = &argp[2]; j = 0; if (strncmp(u, "no-", 3) == 0) j = 1, u += 3; if (match(u, "PIC") || match(u, "pic")) { kflag = j ? 0 : *u == 'P' ? F_PIC : F_pic; } else if (match(u, "PIE") || match(u, "pie")) { kflag = j ? 0 : *u == 'P' ? F_PIC : F_pic; } else if (match(u, "freestanding")) { freestanding = j ? 0 : 1; } else if (match(u, "signed-char")) { xuchar = j ? 1 : 0; } else if (match(u, "unsigned-char")) { xuchar = j ? 0 : 1; } else if (match(u, "stack-protector") || match(u, "stack-protector-all")) { sspflag = j ? 0 : 1; } /* silently ignore the rest */ break; case 'g': /* create debug output */ if (argp[2] == '0') gflag = 0; else gflag++; break; case 'X': Xflag++; break; case 'D': case 'U': strlist_append(&preprocessor_flags, argp); if (argp[2] != 0) break; strlist_append(&preprocessor_flags, nxtopt(argp)); break; case 'I': /* Add include dirs */ strlist_append(&incdirs, nxtopt("-I")); break; case 'i': if (match(argp, "-isystem")) { strlist_append(&user_sysincdirs, nxtopt(0)); } else if (match(argp, "-include")) { strlist_append(&includes, nxtopt(0)); } else if (match(argp, "-isysroot")) { isysroot = nxtopt(0); } else if (strcmp(argp, "-idirafter") == 0) { strlist_append(&dirafterdirs, nxtopt(0)); } else oerror(argp); break; case 'k': /* generate PIC code */ kflag = argp[2] ? argp[2] - '0' : F_pic; break; case 'l': case 'L': if (argp[2] == 0) argp = cat(argp, nxtopt(0)); strlist_append(&inputs, argp); break; case 'm': /* target-dependent options */ if (strncmp(argp, "-march=", 6) == 0) { strlist_append(&compiler_flags, argp); break; } #ifdef mach_amd64 if (strncmp(argp, "-mcmodel=", 9) == 0) { strlist_append(&compiler_flags, argp); break; } /* need to call i386 ccom for this */ if (strcmp(argp, "-melf_i386") == 0) { pass0 = LIBEXECDIR "/ccom_i386"; amd64_i386 = 1; break; } #endif #if defined(mach_arm) || defined(mach_mips) || defined(mach_mips64) if (match(argp, "-mbig-endian")) { bigendian = 1; strlist_append(&compiler_flags, argp); break; } if (match(argp, "-mlittle-endian")) { bigendian = 0; strlist_append(&compiler_flags, argp); break; } if (match(argp, "-msoft-float")) { softfloat = 1; strlist_append(&compiler_flags, argp); break; } #endif #if defined(mach_mips) || defined(mach_mips64) if (match(argp, "-mhard-float")) { softfloat = 0; strlist_append(&compiler_flags, argp); break; } #endif strlist_append(&middle_linker_flags, argp); if (argp[2] == 0) { t = nxtopt(0); strlist_append(&middle_linker_flags, t); } break; case 'n': /* handle -n flags */ if (strcmp(argp, "-nostdinc") == 0) nostdinc++; else if (strcmp(argp, "-nostdlib") == 0) { nostdlib++; nostartfiles++; } else if (strcmp(argp, "-nostartfiles") == 0) nostartfiles = 1; else if (strcmp(argp, "-nodefaultlibs") == 0) nostdlib++; else if (strcmp(argp, "-nopie") == 0) { strlist_append(&middle_linker_flags, argp); pieflag = 0; } else oerror(argp); break; case 'p': if (strcmp(argp, "-pg") == 0 || strcmp(argp, "-p") == 0) pgflag++; else if (strcmp(argp, "-pthread") == 0) pthreads++; else if (strcmp(argp, "-pipe") == 0) /* NOTHING YET */; else if (strcmp(argp, "-pedantic") == 0) /* NOTHING YET */; else if ((t = argnxt(argp, "-print-prog-name="))) { fname = t; printprogname = 1; } else if ((t = argnxt(argp, "-print-file-name="))) { fname = t; printfilename = 1; } else if (match(argp, "-print-libgcc-file-name")) { fname = "libpcc.a"; printfilename = 1; } else if (match(argp, "-print-search-dirs")) { printsearchdirs = 1; } else if (match(argp, "-pie")) { strlist_append(&middle_linker_flags, argp); pieflag = 1; } else oerror(argp); break; case 'R': if (argp[2] == 0) argp = cat(argp, nxtopt(0)); strlist_append(&middle_linker_flags, argp); break; case 'r': if (match(argp, "-rdynamic")) { strlist_append(&middle_linker_flags, "--export-dynamic"); } else if (match(argp, "-r")) { rflag = 1; } else oerror(argp); break; case 'T': strlist_append(&inputs, argp); if (argp[2] == 0 || strcmp(argp, "-Ttext") == 0 || strcmp(argp, "-Tdata") == 0 || strcmp(argp, "-Tbss") == 0) strlist_append(&inputs, nxtopt(0)); break; case 's': if (match(argp, "-shared")) { shared = 1; } else if (match(argp, "-static")) { Bstatic = 1; } else if (match(argp, "-symbolic")) { strlist_append(&middle_linker_flags, "-Bsymbolic"); } else if (strncmp(argp, "-std=", 5) == 0) { if (strcmp(&argp[5], "c11") == 0) cstd = SC11; else if (strcmp(&argp[5], "gnu99") == 0 || strcmp(&argp[5], "gnu9x") == 0) cstd = SGNU99; else if (strcmp(&argp[5], "c89") == 0) cstd = SC89; else if (strcmp(&argp[5], "gnu89") == 0) cstd = SGNU89; else if (strcmp(&argp[5], "c99") == 0) cstd = SC99; else oerror(argp); } else if (match(argp, "-s")) { strlist_append(&middle_linker_flags, argp); } else oerror(argp); break; case 'S': Sflag++; cflag++; break; case 't': tflag++; cstd = STRAD; break; case 'o': if (outfile) errorx(8, "too many -o"); outfile = nxtopt("-o"); break; case 'O': if (argp[2] == '\0') /* gcc does -O1, clang does -O2 */ Oflag = 1; /* do what gcc does */ else if (argp[3] == '\0' && isdigit((unsigned char)argp[2])) Oflag = argp[2] - '0'; else if (argp[3] == '\0' && argp[2] == 's') Oflag = 1; /* optimize for space only */ else oerror(argp); break; case 'P': strlist_append(&preprocessor_flags, argp); break; case 'M': needM = 1; if (match(argp, "-M")) { Mflag++; strlist_append(&depflags, argp); } else if (match(argp, "-MP")) { strlist_append(&depflags, "-xMP"); } else if (match(argp, "-MF")) { MFfile = nxtopt("-MF"); } else if (match(argp, "-MT") || match(argp, "-MQ")) { t = cat("-xMT,", nxtopt("-MT")); t[3] = argp[2]; strlist_append(&depflags, t); } else if (match(argp, "-MD")) { MDflag++; needM = 0; strlist_append(&depflags, "-M"); } else if (match(argp, "-MMD")) { MMDflag++; needM = 0; strlist_append(&depflags, "-M"); strlist_append(&depflags, "-xMMD"); } else oerror(argp); break; case 'v': printf("%s\n", VERSSTR); vflag++; break; case 'w': /* no warnings at all emitted */ strlist_append(&compiler_flags, "-w"); break; case 'W': /* Ignore (most of) W-flags */ if ((t = argnxt(argp, "-Wl,"))) { u = strtok(t, ","); do { strlist_append(&inputs, u); } while ((u = strtok(NULL, ",")) != NULL); } else if ((t = argnxt(argp, "-Wa,"))) { u = strtok(t, ","); do { strlist_append(&assembler_flags, u); } while ((u = strtok(NULL, ",")) != NULL); } else if ((t = argnxt(argp, "-Wc,"))) { u = strtok(t, ","); do { strlist_append(&compiler_flags, u); } while ((u = strtok(NULL, ",")) != NULL); } else if ((t = argnxt(argp, "-Wp,"))) { u = strtok(t, ","); do { strlist_append(&preprocessor_flags, u); } while ((u = strtok(NULL, ",")) != NULL); } else if (strcmp(argp, "-Werror") == 0) { strlist_append(&compiler_flags, "-Werror"); strlist_append(&preprocessor_flags, "-E"); } else if (strcmp(argp, "-Wall") == 0) { for (Wf = Wflags; Wf->name; Wf++) if (Wf->flags & INWALL) strlist_append(&compiler_flags, cat("-W", Wf->name)); } else if (strcmp(argp, "-Wextra") == 0 || strcmp(argp, "-W") == 0) { for (Wf = Wflags; Wf->name; Wf++) if (Wf->flags & INWEXTRA) strlist_append(&compiler_flags, cat("-W", Wf->name)); } else if (strcmp(argp, "-WW") == 0) { for (Wf = Wflags; Wf->name; Wf++) strlist_append(&compiler_flags, cat("-W", Wf->name)); } else { /* pass through, if supported */ t = &argp[2]; if (strncmp(t, "no-", 3) == 0) t += 3; if (strncmp(t, "error=", 6) == 0) t += 6; for (Wf = Wflags; Wf->name; Wf++) { if (strcmp(t, Wf->name) == 0) strlist_append(&compiler_flags, argp); } } break; case 'x': t = nxtopt("-x"); if (match(t, "none")) strlist_append(&inputs, ")"); else if (match(t, "c")) strlist_append(&inputs, ")c"); else if (match(t, "assembler")) strlist_append(&inputs, ")s"); else if (match(t, "assembler-with-cpp")) strlist_append(&inputs, ")S"); else if (match(t, "c++")) strlist_append(&inputs, ")c++"); else { strlist_append(&compiler_flags, "-x"); strlist_append(&compiler_flags, t); } break; case 'z': argp = cat(argp, nxtopt(0)); strlist_append(&middle_linker_flags, argp); break; } continue; } /* Sanity checking */ if (cppflag) { if (ninput == 0) { strlist_append(&inputs, "-"); ninput++; } else if (ninput > 2 || (ninput == 2 && outfile)) { errorx(8, "too many files"); } else if (ninput == 2) { outfile = STRLIST_NEXT(STRLIST_FIRST(&inputs))->value; STRLIST_FIRST(&inputs)->next = NULL; ninput--; } } if (tflag && Eflag == 0) errorx(8,"-t only allowed fi -E given"); /* Correct C standard */ switch (cstd) { case STRAD: break; case SC89: c89defs = 1; break; case SGNU89: xgnu89 = c89defs = 1; break; case SC99: c89defs = c99defs = 1; break; case SGNU99: c89defs = c99defs = xgnu99 = 1; break; case SC11: c89defs = c11defs = 1; break; } if (ninput == 0 && !(printprogname || printfilename || printsearchdirs)) errorx(8, "no input files"); if (outfile && (cflag || Sflag || Eflag) && ninput > 1) errorx(8, "-o given with -c || -E || -S and more than one file"); #if 0 if (outfile && clist[0] && strcmp(outfile, clist[0]) == 0) errorx(8, "output file will be clobbered"); #endif if (needM && !Mflag && !MDflag && !MMDflag) errorx(8, "to make dependencies needs -M"); if (signal(SIGINT, SIG_IGN) != SIG_IGN) /* interrupt */ signal(SIGINT, idexit); if (signal(SIGTERM, SIG_IGN) != SIG_IGN) /* terminate */ signal(SIGTERM, idexit); /* after arg parsing */ strlist_append(&progdirs, LIBEXECDIR); if (pcclibdir) strlist_append(&crtdirs, pcclibdir); for (j = 0; deflibdirs[j]; j++) { if (sysroot) deflibdirs[j] = cat(sysroot, deflibdirs[j]); strlist_append(&crtdirs, deflibdirs[j]); } setup_cpp_flags(); setup_ccom_flags(); setup_as_flags(); if (isysroot == NULL) isysroot = sysroot; expand_sysroot(); if (printprogname) { printf("%s\n", find_file(fname, &progdirs, X_OK)); return 0; } else if (printfilename) { printf("%s\n", find_file(fname, &crtdirs, R_OK)); return 0; } else if (printsearchdirs) { printf("install: %s\n", LIBEXECDIR); printf("programs: ="); strlist_print(&progdirs, stdout, 0, ":"); printf("\n"); printf("libraries: ="); strlist_print(&crtdirs, stdout, 0, ":"); printf("\n"); return 0; } msuffix = NULL; STRLIST_FOREACH(s, &inputs) { char *suffix; char *ifile, *ofile = NULL; ifile = s->value; if (ifile[0] == ')') { /* -x source type given */ msuffix = ifile[1] ? &ifile[1] : NULL; continue; } if (ifile[0] == '-' && ifile[1] == 0) suffix = msuffix ? msuffix : "c"; else if (ifile[0] == '-') suffix = "o"; /* source files cannot begin with - */ else if (msuffix) suffix = msuffix; else suffix = getsufp(ifile); /* * C preprocessor */ ascpp = match(suffix, "S"); if (ascpp || cppflag || match(suffix, "c") || cxxsuf(suffix)) { /* find out next output file */ if (Mflag || MDflag || MMDflag) { char *Mofile = NULL; if (MFfile) Mofile = MFfile; else if (outfile) Mofile = setsuf(outfile, 'd'); else if (MDflag || MMDflag) Mofile = setsuf(ifile, 'd'); if (preprocess_input(ifile, Mofile, 1)) exandrm(Mofile); } if (Mflag) continue; if (Eflag) { /* last pass */ ofile = outfile; } else { /* to temp file */ strlist_append(&temp_outputs, ofile = gettmp()); } if (preprocess_input(ifile, ofile, 0)) exandrm(ofile); if (Eflag) continue; ifile = ofile; suffix = match(suffix, "S") ? "s" : "i"; } /* * C compiler */ if (match(suffix, "i")) { /* find out next output file */ if (Sflag) { ofile = outfile; if (outfile == NULL) ofile = setsuf(s->value, 's'); } else strlist_append(&temp_outputs, ofile = gettmp()); if (compile_input(ifile, ofile)) exandrm(ofile); if (Sflag) continue; ifile = ofile; suffix = "s"; } /* * Assembler */ if (match(suffix, "s")) { if (cflag) { ofile = outfile; if (ofile == NULL) ofile = setsuf(s->value, 'o'); } else { strlist_append(&temp_outputs, ofile = gettmp()); /* strlist_append linker */ } if (assemble_input(ifile, ofile)) exandrm(ofile); ifile = ofile; } strlist_append(&middle_linker_flags, ifile); } if (cflag || Eflag || Mflag) dexit(0); /* * Linker */ setup_ld_flags(); if (run_linker()) exandrm(0); #ifdef notdef strlist_free(&crtdirs); strlist_free(&libdirs); strlist_free(&progdirs); strlist_free(&incdirs); strlist_free(&preprocessor_flags); strlist_free(&user_sysincdirs); strlist_free(&includes); strlist_free(&sysincdirs); strlist_free(&dirafterdirs); strlist_free(&depflags); strlist_free(&early_linker_flags); strlist_free(&middle_linker_flags); strlist_free(&late_linker_flags); strlist_free(&inputs); strlist_free(&assembler_flags); strlist_free(&temp_outputs); strlist_free(&compiler_flags); #endif dexit(0); return 0; } /* * exit and cleanup after interrupt. */ void idexit(int arg) { dexit(100); } /* * exit and cleanup. */ void dexit(int eval) { struct string *s; if (!Xflag) { STRLIST_FOREACH(s, &temp_outputs) cunlink(s->value); } exit(eval); } /* * Called when something failed. */ void exandrm(char *s) { if (s && *s) strlist_append(&temp_outputs, s); dexit(1); } /* * complain and exit. */ void errorx(int eval, char *s, ...) { va_list ap; va_start(ap, s); fputs("error: ", stderr); vfprintf(stderr, s, ap); putc('\n', stderr); va_end(ap); dexit(eval); } static char * find_file(const char *file, struct strlist *path, int mode) { struct string *s; char *f; size_t lf, lp; int need_sep; lf = strlen(file); STRLIST_FOREACH(s, path) { lp = strlen(s->value); need_sep = (lp && s->value[lp - 1] != '/') ? 1 : 0; f = xmalloc(lp + lf + need_sep + 1); memcpy(f, s->value, lp); if (need_sep) f[lp] = '/'; memcpy(f + lp + need_sep, file, lf + 1); if (access(f, mode) == 0) return f; free(f); } return xstrdup(file); } #ifdef TWOPASS static int compile_input(char *input, char *output) { struct strlist args; char *tfile; int retval; strlist_append(&temp_outputs, tfile = gettmp()); strlist_init(&args); strlist_append_list(&args, &compiler_flags); strlist_append(&args, input); strlist_append(&args, tfile); strlist_prepend(&args, find_file(cxxflag ? "cxx0" : "cc0", &progdirs, X_OK)); retval = strlist_exec(&args); strlist_free(&args); if (retval) return retval; strlist_init(&args); strlist_append_list(&args, &compiler_flags); strlist_append(&args, tfile); strlist_append(&args, output); strlist_prepend(&args, find_file(cxxflag ? "cxx1" : "cc1", &progdirs, X_OK)); retval = strlist_exec(&args); strlist_free(&args); return retval; } #else static int compile_input(char *input, char *output) { struct strlist args; int retval; strlist_init(&args); strlist_append_list(&args, &compiler_flags); strlist_append(&args, input); strlist_append(&args, output); strlist_prepend(&args, find_file(cxxflag ? passxx0 : pass0, &progdirs, X_OK)); retval = strlist_exec(&args); strlist_free(&args); return retval; } #endif static int assemble_input(char *input, char *output) { struct strlist args; int retval; strlist_init(&args); #ifdef PCC_EARLY_AS_ARGS PCC_EARLY_AS_ARGS #endif strlist_append_list(&args, &assembler_flags); strlist_append(&args, input); strlist_append(&args, "-o"); strlist_append(&args, output); strlist_prepend(&args, find_file(as, &progdirs, X_OK)); #ifdef PCC_LATE_AS_ARGS PCC_LATE_AS_ARGS #endif retval = strlist_exec(&args); strlist_free(&args); return retval; } static int preprocess_input(char *input, char *output, int dodep) { struct strlist args; struct string *s; int retval; strlist_init(&args); strlist_append_list(&args, &preprocessor_flags); if (ascpp) { strlist_append(&args, "-A"); strlist_append(&args, "-D__ASSEMBLER__"); } STRLIST_FOREACH(s, &includes) { strlist_append(&args, "-i"); strlist_append(&args, s->value); } STRLIST_FOREACH(s, &incdirs) { strlist_append(&args, "-I"); strlist_append(&args, s->value); } STRLIST_FOREACH(s, &user_sysincdirs) { strlist_append(&args, "-S"); strlist_append(&args, s->value); } if (!nostdinc) { STRLIST_FOREACH(s, &sysincdirs) { strlist_append(&args, "-S"); strlist_append(&args, s->value); } } STRLIST_FOREACH(s, &dirafterdirs) { strlist_append(&args, "-S"); strlist_append(&args, s->value); } if (dodep) strlist_append_list(&args, &depflags); strlist_append(&args, input); if (output) strlist_append(&args, output); strlist_prepend(&args, find_file(passp, &progdirs, X_OK)); retval = strlist_exec(&args); strlist_free(&args); return retval; } static int run_linker(void) { struct strlist linker_flags; int retval; if (outfile) { strlist_prepend(&early_linker_flags, outfile); strlist_prepend(&early_linker_flags, "-o"); } strlist_init(&linker_flags); strlist_append_list(&linker_flags, &early_linker_flags); strlist_append_list(&linker_flags, &middle_linker_flags); strlist_append_list(&linker_flags, &late_linker_flags); strlist_prepend(&linker_flags, find_file(ld, &progdirs, X_OK)); retval = strlist_exec(&linker_flags); strlist_free(&linker_flags); return retval; } static char *cxxt[] = { "cc", "cp", "cxx", "cpp", "CPP", "c++", "C" }; int cxxsuf(char *s) { unsigned i; for (i = 0; i < sizeof(cxxt)/sizeof(cxxt[0]); i++) if (strcmp(s, cxxt[i]) == 0) return 1; return 0; } char * getsufp(char *s) { register char *p; if ((p = strrchr(s, '.')) && p[1] != '\0') return &p[1]; return ""; } int getsuf(char *s) { register char *p; if ((p = strrchr(s, '.')) && p[1] != '\0' && p[2] == '\0') return p[1]; return(0); } /* * Get basename of string s, copy it and change its suffix to ch. */ char * setsuf(char *s, char ch) { char *e, *p, *rp; e = NULL; for (p = s; *p; p++) { if (*p == '/') s = p + 1; if (*p == '.') e = p; } if (s > e) e = p; rp = p = xmalloc(e - s + 3); while (s < e) *p++ = *s++; *p++ = '.'; *p++ = ch; *p = '\0'; return rp; } #ifdef _WIN32 static int strlist_exec(struct strlist *l) { char *cmd; STARTUPINFO si; PROCESS_INFORMATION pi; DWORD exitCode; BOOL ok; cmd = win32commandline(l); if (vflag) printf("%s\n", cmd); if (noexec) return 0; ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); ok = CreateProcess(NULL, // the executable program cmd, // the command line arguments NULL, // ignored NULL, // ignored TRUE, // inherit handles HIGH_PRIORITY_CLASS, NULL, // ignored NULL, // ignored &si, &pi); if (!ok) errorx(100, "Can't find %s\n", STRLIST_FIRST(l)->value); WaitForSingleObject(pi.hProcess, INFINITE); GetExitCodeProcess(pi.hProcess, &exitCode); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); return (exitCode != 0); } #else static int strlist_exec(struct strlist *l) { sig_atomic_t exit_now = 0; sig_atomic_t child; char **argv; size_t argc; ssize_t result; int rv; strlist_make_array(l, &argv, &argc); if (vflag) { printf("Calling "); strlist_print(l, stdout, noexec, " "); printf("\n"); } if (noexec) return 0; switch ((child = fork())) { case 0: execvp(argv[0], argv); result = write(STDERR_FILENO, "Exec of ", 8); result = write(STDERR_FILENO, argv[0], strlen(argv[0])); result = write(STDERR_FILENO, " failed\n", 8); (void)result; _exit(127); case -1: errorx(1, "fork failed"); default: while (waitpid(child, &rv, 0) == -1 && errno == EINTR) /* nothing */(void)0; rv = WEXITSTATUS(rv); if (rv) errorx(1, "%s terminated with status %d", argv[0], rv); while (argc-- > 0) free(argv[argc]); free(argv); break; } return exit_now; } #endif /* * Catenate two (optional) strings together */ char * cat(const char *a, const char *b) { size_t len; char *rv; len = (a ? strlen(a) : 0) + (b ? strlen(b) : 0) + 1; rv = xmalloc(len); snprintf(rv, len, "%s%s", (a ? a : ""), (b ? b : "")); return rv; } int cunlink(char *f) { if (f==0 || Xflag) return(0); return (unlink(f)); } #ifdef _WIN32 char * gettmp(void) { DWORD pathSize; char pathBuffer[MAX_PATH + 1]; char tempFilename[MAX_PATH]; UINT uniqueNum; pathSize = GetTempPath(sizeof(pathBuffer), pathBuffer); if (pathSize == 0 || pathSize > sizeof(pathBuffer)) pathBuffer[0] = '\0'; uniqueNum = GetTempFileName(pathBuffer, "ctm", 0, tempFilename); if (uniqueNum == 0) errorx(8, "GetTempFileName failed: path \"%s\"", pathBuffer); return xstrdup(tempFilename); } #else char * gettmp(void) { char *sfn = xstrdup("/tmp/ctm.XXXXXX"); int fd = -1; if ((fd = mkstemp(sfn)) == -1) errorx(8, "%s: %s\n", sfn, strerror(errno)); close(fd); return sfn; } #endif static void expand_sysroot(void) { struct string *s; struct strlist *lists[] = { &crtdirs, &sysincdirs, &incdirs, &user_sysincdirs, &libdirs, &progdirs, &dirafterdirs, NULL }; const char *sysroots[] = { sysroot, isysroot, isysroot, isysroot, sysroot, sysroot, isysroot, NULL }; size_t i, sysroot_len, value_len; char *path; assert(sizeof(lists) / sizeof(lists[0]) == sizeof(sysroots) / sizeof(sysroots[0])); for (i = 0; lists[i] != NULL; ++i) { STRLIST_FOREACH(s, lists[i]) { if (s->value[0] != '=') continue; sysroot_len = strlen(sysroots[i]); /* Skipped '=' compensates additional space for '\0' */ value_len = strlen(s->value); path = xmalloc(sysroot_len + value_len); memcpy(path, sysroots[i], sysroot_len); memcpy(path + sysroot_len, s->value + 1, value_len); free(s->value); s->value = path; } } } void oerror(char *s) { errorx(8, "unknown option '%s'", s); } /* * See if m matches the beginning of string str, if it does return the * remaining of str, otherwise NULL. */ char * argnxt(char *str, char *m) { if (strncmp(str, m, strlen(m))) return NULL; /* No match */ return str + strlen(m); } /* * Return next argument to option, or complain. */ char * nxtopt(char *o) { size_t l; if (o != NULL) { l = strlen(o); if (lav[0][l] != 0) return &lav[0][l]; } if (lac == 1) errorx(8, "missing argument to '%s'", o); lav++; lac--; return lav[0]; } struct flgcheck { int *flag; int set; char *def; } cppflgcheck[] = { { &vflag, 1, "-v" }, { &c99defs, 1, "-D__STDC_VERSION__=199901L" }, { &c11defs, 1, "-D__STDC_VERSION__=201112L" }, { &c89defs, 1, "-D__STDC__=1" }, { &freestanding, 1, "-D__STDC_HOSTED__=0" }, { &freestanding, 0, "-D__STDC_HOSTED__=1" }, { &cxxflag, 1, "-D__cplusplus" }, { &xuchar, 1, "-D__CHAR_UNSIGNED__" }, { &sspflag, 1, "-D__SSP__" }, { &pthreads, 1, "-D_PTHREADS" }, { &Oflag, 1, "-D__OPTIMIZE__" }, { &tflag, 1, "-t" }, { &kflag, 1, "-D__PIC__" }, { 0 }, }; static void cksetflags(struct flgcheck *fs, struct strlist *sl, int which) { void (*fn)(struct strlist *, const char *); fn = which == 'p' ? strlist_prepend : strlist_append; for (; fs->flag; fs++) { if (fs->set && *fs->flag) fn(sl, fs->def); if (!fs->set && !*fs->flag) fn(sl, fs->def); } } #ifndef TARGET_LE #define TARGET_LE 1 #define TARGET_BE 2 #define TARGET_PDP 3 #define TARGET_ANY 4 #endif static char *defflags[] = { "-D__PCC__=" MKS(PCC_MAJOR), "-D__PCC_MINOR__=" MKS(PCC_MINOR), "-D__PCC_MINORMINOR__=" MKS(PCC_MINORMINOR), "-D__VERSION__=" MKS(VERSSTR), "-D__SCHAR_MAX__=" MKS(MAX_CHAR), "-D__SHRT_MAX__=" MKS(MAX_SHORT), "-D__INT_MAX__=" MKS(MAX_INT), "-D__LONG_MAX__=" MKS(MAX_LONG), "-D__LONG_LONG_MAX__=" MKS(MAX_LONGLONG), "-D__STDC_ISO_10646__=200009L", "-D__WCHAR_TYPE__=" WCT, "-D__SIZEOF_WCHAR_T__=" MKS(WCHAR_SIZE), "-D__WCHAR_MAX__=" WCM, "-D__WINT_TYPE__=" PCC_WINT_TYPE, "-D__SIZE_TYPE__=" PCC_SIZE_TYPE, "-D__PTRDIFF_TYPE__=" PCC_PTRDIFF_TYPE, "-D__SIZEOF_WINT_T__=4", "-D__ORDER_LITTLE_ENDIAN__=1234", "-D__ORDER_BIG_ENDIAN__=4321", "-D__ORDER_PDP_ENDIAN__=3412", #ifndef NO_C11 "-D__STDC_UTF_16__=1", "-D__STDC_UTF_32__=1", "-D__STDC_NO_ATOMICS__=1", "-D__STDC_NO_THREADS__=1", #endif /* * These should probably be changeable during runtime... */ #if TARGET_ENDIAN == TARGET_BE "-D__FLOAT_WORD_ORDER__=__ORDER_BIG_ENDIAN__", "-D__BYTE_ORDER__=__ORDER_BIG_ENDIAN__", #elif TARGET_ENDIAN == TARGET_PDP "-D__FLOAT_WORD_ORDER__=__ORDER_PDP_ENDIAN__", "-D__BYTE_ORDER__=__ORDER_PDP_ENDIAN__", #elif TARGET_ENDIAN == TARGET_LE "-D__FLOAT_WORD_ORDER__=__ORDER_LITTLE_ENDIAN__", "-D__BYTE_ORDER__=__ORDER_LITTLE_ENDIAN__", #else #error Unknown endian... #endif }; static char *gcppflags[] = { #ifndef os_win32 #ifdef GCC_COMPAT "-D__GNUC__=4", "-D__GNUC_MINOR__=3", "-D__GNUC_PATCHLEVEL__=1", "-D__REGISTER_PREFIX__=" REGISTER_PREFIX, "-D__USER_LABEL_PREFIX__=" USER_LABEL_PREFIX, #if SZLONG == 64 "-D__SIZEOF_LONG__=8", #elif SZLONG == 32 "-D__SIZEOF_LONG__=4", #endif #if SZPOINT(CHAR) == 64 "-D__SIZEOF_POINTER__=8", #elif SZPOINT(CHAR) == 32 "-D__SIZEOF_POINTER__=4", #endif #endif #endif NULL }; /* Use floating point definitions form softfloat.h */ static char *fpflags[] = { #ifdef TARGET_FLT_EVAL_METHOD "-D__FLT_EVAL_METHOD__=" MKS(TARGET_FLT_EVAL_METHOD), #endif #ifdef FLT_PREFIX "-D__FLT_RADIX__=" MKS(C(FLT_PREFIX,_RADIX)), "-D__FLT_DIG__=" MKS(C(FLT_PREFIX,_DIG)), "-D__FLT_EPSILON__=" MKS(C(FLT_PREFIX,_EPSILON)), "-D__FLT_MANT_DIG__=" MKS(C(FLT_PREFIX,_MANT_DIG)), "-D__FLT_MAX_10_EXP__=" MKS(C(FLT_PREFIX,_MAX_10_EXP)), "-D__FLT_MAX_EXP__=" MKS(C(FLT_PREFIX,_MAX_EXP)), "-D__FLT_MAX__=" MKS(C(FLT_PREFIX,_MAX)), "-D__FLT_MIN_10_EXP__=" MKS(C(FLT_PREFIX,_MIN_10_EXP)), "-D__FLT_MIN_EXP__=" MKS(C(FLT_PREFIX,_MIN_EXP)), "-D__FLT_MIN__=" MKS(C(FLT_PREFIX,_MIN)), #endif #ifdef DBL_PREFIX "-D__DBL_DIG__=" MKS(C(DBL_PREFIX,_DIG)), "-D__DBL_EPSILON__=" MKS(C(DBL_PREFIX,_EPSILON)), "-D__DBL_MANT_DIG__=" MKS(C(DBL_PREFIX,_MANT_DIG)), "-D__DBL_MAX_10_EXP__=" MKS(C(DBL_PREFIX,_MAX_10_EXP)), "-D__DBL_MAX_EXP__=" MKS(C(DBL_PREFIX,_MAX_EXP)), "-D__DBL_MAX__=" MKS(C(DBL_PREFIX,_MAX)), "-D__DBL_MIN_10_EXP__=" MKS(C(DBL_PREFIX,_MIN_10_EXP)), "-D__DBL_MIN_EXP__=" MKS(C(DBL_PREFIX,_MIN_EXP)), "-D__DBL_MIN__=" MKS(C(DBL_PREFIX,_MIN)), #endif #ifdef LDBL_PREFIX "-D__LDBL_DIG__=" MKS(C(LDBL_PREFIX,_DIG)), "-D__LDBL_EPSILON__=" MKS(C(LDBL_PREFIX,_EPSILON)), "-D__LDBL_MANT_DIG__=" MKS(C(LDBL_PREFIX,_MANT_DIG)), "-D__LDBL_MAX_10_EXP__=" MKS(C(LDBL_PREFIX,_MAX_10_EXP)), "-D__LDBL_MAX_EXP__=" MKS(C(LDBL_PREFIX,_MAX_EXP)), "-D__LDBL_MAX__=" MKS(C(LDBL_PREFIX,_MAX)), "-D__LDBL_MIN_10_EXP__=" MKS(C(LDBL_PREFIX,_MIN_10_EXP)), "-D__LDBL_MIN_EXP__=" MKS(C(LDBL_PREFIX,_MIN_EXP)), "-D__LDBL_MIN__=" MKS(C(LDBL_PREFIX,_MIN)), #endif NULL }; /* * Configure the standard cpp flags. */ void setup_cpp_flags(void) { int i; /* a bunch of misc defines */ for (i = 0; i < (int)sizeof(defflags)/(int)sizeof(char *); i++) strlist_prepend(&preprocessor_flags, defflags[i]); for (i = 0; gcppflags[i]; i++) strlist_prepend(&preprocessor_flags, gcppflags[i]); strlist_prepend(&preprocessor_flags, xgnu89 ? "-D__GNUC_GNU_INLINE__" : "-D__GNUC_STDC_INLINE__"); cksetflags(cppflgcheck, &preprocessor_flags, 'p'); /* Create time and date defines */ if (tflag == 0) { char buf[100]; /* larger than needed */ time_t t = time(NULL); char *n = ctime(&t); n[19] = 0; snprintf(buf, sizeof buf, "-D__TIME__=\"%s\"", n+11); strlist_prepend(&preprocessor_flags, xstrdup(buf)); n[24] = n[11] = 0; snprintf(buf, sizeof buf, "-D__DATE__=\"%s%s\"", n+4, n+20); strlist_prepend(&preprocessor_flags, xstrdup(buf)); } for (i = 0; fpflags[i]; i++) strlist_prepend(&preprocessor_flags, fpflags[i]); for (i = 0; cppadd[i]; i++) strlist_prepend(&preprocessor_flags, cppadd[i]); for (i = 0; cppmdadd[i]; i++) strlist_prepend(&preprocessor_flags, cppmdadd[i]); /* Include dirs */ strlist_append(&sysincdirs, "=" INCLUDEDIR "pcc/"); #ifdef STDINC_MA strlist_append(&sysincdirs, "=" STDINC_MA); #endif strlist_append(&sysincdirs, "=" STDINC); #ifdef PCCINCDIR if (cxxflag) strlist_append(&sysincdirs, "=" PCCINCDIR "/c++"); strlist_append(&sysincdirs, "=" PCCINCDIR); #endif } struct flgcheck ccomflgcheck[] = { { &Oflag, 1, "-xtemps" }, { &Oflag, 1, "-xdeljumps" }, { &Oflag, 1, "-xinline" }, { &Oflag, 1, "-xdce" }, { &Oflag, 1, "-xssa" }, { &freestanding, 1, "-ffreestanding" }, { &pgflag, 1, "-p" }, { &gflag, 1, "-g" }, { &xgnu89, 1, "-xgnu89" }, { &xgnu99, 1, "-xgnu99" }, { &xuchar, 1, "-xuchar" }, #if !defined(os_sunos) && !defined(mach_i386) { &vflag, 1, "-v" }, #endif #ifdef os_darwin { &Bstatic, 0, "-k" }, #elif defined(os_sunos) && defined(mach_i386) { &kflag, 1, "-K" }, { &kflag, 1, "pic" }, #else { &kflag, 1, "-k" }, #endif { &sspflag, 1, "-fstack-protector" }, { 0 } }; void setup_ccom_flags(void) { cksetflags(ccomflgcheck, &compiler_flags, 'a'); } #if defined(USE_YASM) || defined(os_win32) || defined(os_darwin) || \ (defined(os_sunos) && defined(mach_sparc64)) static int one = 1; #endif struct flgcheck asflgcheck[] = { #if defined(USE_YASM) { &one, 1, "-p" }, { &one, 1, "gnu" }, { &one, 1, "-f" }, #if defined(os_win32) { &one, 1, "win32" }, #elif defined(os_darwin) { &one, 1, "macho" }, #else { &one, 1, "elf" }, #endif #endif #if defined(os_sunos) && defined(mach_sparc64) { &one, 1, "-m64" }, #endif #if defined(os_darwin) { &Bstatic, 1, "-static" }, #endif #if !defined(USE_YASM) { &vflag, 1, "-v" }, #endif #if defined(os_openbsd) && defined(mach_mips64) { &kflag, 1, "-KPIC" }, #else { &kflag, 1, "-k" }, #endif #ifdef os_darwin { &one, 1, "-arch" }, #if mach_amd64 { &amd64_i386, 1, "i386" }, { &amd64_i386, 0, "x86_64" }, #else { &one, 1, "i386" }, #endif #else #ifdef mach_amd64 { &amd64_i386, 1, "--32" }, #endif #endif { 0 } }; void setup_as_flags(void) { #ifdef PCC_SETUP_AS_ARGS PCC_SETUP_AS_ARGS #endif cksetflags(asflgcheck, &assembler_flags, 'a'); } struct flgcheck ldflgcheck[] = { #ifndef MSLINKER { &vflag, 1, "-v" }, #endif #ifdef os_darwin { &shared, 1, "-dylib" }, #elif defined(os_win32) { &shared, 1, "-Bdynamic" }, #else { &shared, 1, "-shared" }, #endif #if !defined(os_sunos) && !defined(os_win32) #ifndef os_darwin { &shared, 0, "-d" }, #endif #endif #ifdef os_darwin { &Bstatic, 1, "-static" }, #else { &Bstatic, 1, "-Bstatic" }, #endif #if !defined(os_darwin) && !defined(os_sunos) { &gflag, 1, "-g" }, #endif { &pthreads, 1, "-lpthread" }, { 0 }, }; static void strap(struct strlist *sh, struct strlist *cd, char *n, int where) { void (*fn)(struct strlist *, const char *); char *fil; if (n == 0) return; /* no crtfile */ fn = where == 'p' ? strlist_prepend : strlist_append; fil = find_file(n, cd, R_OK); (*fn)(sh, fil); } void setup_ld_flags(void) { char *b, *e; int i; #ifdef PCC_SETUP_LD_ARGS PCC_SETUP_LD_ARGS #endif cksetflags(ldflgcheck, &early_linker_flags, 'a'); if (Bstatic == 0 && shared == 0 && rflag == 0) { if (dynlinklib) { strlist_append(&early_linker_flags, dynlinkarg); strlist_append(&early_linker_flags, dynlinklib); } strlist_append(&early_linker_flags, "-e"); strlist_append(&early_linker_flags, STARTLABEL); } if (shared == 0 && rflag) strlist_append(&early_linker_flags, "-r"); #ifdef STARTLABEL_S if (shared == 1) { strlist_append(&early_linker_flags, "-e"); strlist_append(&early_linker_flags, STARTLABEL_S); } #endif if (sysroot && *sysroot) strlist_append(&early_linker_flags, cat("--sysroot=", sysroot)); if (!nostdlib) { /* library search paths */ if (pcclibdir) strlist_append(&late_linker_flags, cat("-L", pcclibdir)); for (i = 0; deflibdirs[i]; i++) strlist_append(&late_linker_flags, cat("-L", deflibdirs[i])); /* standard libraries */ if (pgflag) { for (i = 0; defproflibs[i]; i++) strlist_append(&late_linker_flags, defproflibs[i]); } else if (cxxflag) { for (i = 0; defcxxlibs[i]; i++) strlist_append(&late_linker_flags, defcxxlibs[i]); } else { for (i = 0; deflibs[i]; i++) strlist_append(&late_linker_flags, deflibs[i]); } } if (!nostartfiles) { if (Bstatic) { b = CRTBEGIN_T; e = CRTEND_T; } else if (shared /* || pieflag */) { b = CRTBEGIN_S; e = CRTEND_S; } else { b = CRTBEGIN; e = CRTEND; } strap(&middle_linker_flags, &crtdirs, b, 'p'); strap(&late_linker_flags, &crtdirs, e, 'a'); strap(&middle_linker_flags, &crtdirs, CRTI, 'p'); strap(&late_linker_flags, &crtdirs, CRTN, 'a'); #ifdef os_win32 /* * On Win32 Cygwin/MinGW runtimes, the profiling code gcrtN.o * comes in addition to crtN.o or dllcrtN.o */ if (pgflag) strap(&middle_linker_flags, &crtdirs, GCRT0, 'p'); if (shared == 0) b = CRT0; else b = CRT0_S; /* dllcrtN.o */ strap(&middle_linker_flags, &crtdirs, b, 'p'); #else if (shared == 0) { if (pgflag) b = GCRT0; else if (pieflag) b = RCRT0; else b = CRT0; strap(&middle_linker_flags, &crtdirs, b, 'p'); } #endif } } #ifdef _WIN32 char * win32pathsubst(char *s) { char env[1024]; DWORD len; len = ExpandEnvironmentStrings(s, env, sizeof(env)); if (len == 0 || len > sizeof(env)) errorx(8, "ExpandEnvironmentStrings failed, len %lu", len); len--; /* skip nil */ while (len-- > 0 && (env[len] == '/' || env[len] == '\\')) env[len] = '\0'; return xstrdup(env); } char * win32commandline(struct strlist *l) { const struct string *s; char *cmd; char *p; int len; int j, k; len = 0; STRLIST_FOREACH(s, l) { len++; for (j = 0; s->value[j] != '\0'; j++) { if (s->value[j] == '\"') { for (k = j-1; k >= 0 && s->value[k] == '\\'; k--) len++; len++; } len++; } for (k = j-1; k >= 0 && s->value[k] == '\\'; k--) len++; len++; len++; } p = cmd = xmalloc(len); STRLIST_FOREACH(s, l) { *p++ = '\"'; for (j = 0; s->value[j] != '\0'; j++) { if (s->value[j] == '\"') { for (k = j-1; k >= 0 && s->value[k] == '\\'; k--) *p++ = '\\'; *p++ = '\\'; } *p++ = s->value[j]; } for (k = j-1; k >= 0 && s->value[k] == '\\'; k--) *p++ = '\\'; *p++ = '\"'; *p++ = ' '; } p[-1] = '\0'; return cmd; } #endif pcc-20181216/cc/ccom004075500017500000000000000000001340533064000127145ustar raggewheelpcc-20181216/cc/ccom/CVS004075500017500000000000000000001340533064000133475ustar raggewheelpcc-20181216/cc/ccom/CVS/Root010064400017500000000000000000111340533064000142610ustar raggewheel/cvsroot pcc-20181216/cc/ccom/CVS/Repository010064400017500000000000000000141340533064000155200ustar raggewheelpcc/cc/ccom pcc-20181216/cc/ccom/CVS/Entries010064400017500000000000000013671340533064000147660ustar raggewheel/Makefile.in/1.50/Thu Mar 2 21:10:45 2017// /builtins.c/1.75/Sun Dec 2 18:40:46 2018// /ccom.1/1.33/Sat Dec 15 09:12:14 2018// /cgram.y/1.420/Sun Dec 2 18:40:46 2018// /dwarf.c/1.2/Tue Mar 8 18:17:45 2016// /dwarf.h/1.1/Sun Feb 21 11:11:55 2016// /gcc_compat.c/1.122/Thu Mar 8 12:23:00 2018// /init.c/1.106/Sun Dec 2 18:40:46 2018// /inline.c/1.66/Mon Sep 26 16:45:43 2016// /main.c/1.136/Fri Nov 23 14:43:06 2018// /optim.c/1.65/Sat Jul 9 15:59:43 2016// /pass1.h/1.316/Sun Dec 2 18:40:46 2018// /pftn.c/1.430/Sun Dec 2 18:40:46 2018// /scan.l/1.157/Sun Dec 2 18:40:46 2018// /softfloat.c/1.4/Wed Jul 29 12:32:34 2009// /stabs.c/1.35/Tue Sep 15 20:01:10 2015// /symtabs.c/1.39/Tue Oct 11 13:48:24 2016// /trees.c/1.387/Sun Dec 2 18:40:46 2018// D pcc-20181216/cc/ccom/Makefile.in010064400017500000000000000140231305610512500150350ustar raggewheel# $Id: Makefile.in,v 1.50 2017/03/02 21:10:45 ragge Exp $ # # Makefile.in for ccom # VPATH=@srcdir@ srcdir=@srcdir@ top_srcdir=@top_srcdir@ builddir=@builddir@ top_builddir=@top_builddir@ CC = @CC@ EXEEXT = @EXEEXT@ BINPREFIX = @BINPREFIX@ CC_FOR_BUILD = @CC_FOR_BUILD@ CFLAGS = @CFLAGS@ @ADD_CFLAGS@ CPPFLAGS = @CPPFLAGS@ @ADD_CPPFLAGS@ -D_ISOC99_SOURCE \ -Dos_$(TARGOS) -Dmach_$(TARGMACH) \ -I$(srcdir) -I$(builddir) -I$(top_builddir) -I$(MIPDIR) -I$(MDIR) \ -I$(top_srcdir)/os/$(TARGOS) -I$(COMMONDIR) LIBS = @LIBS@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LFLAGS = LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ YACC = @YACC@ YFLAGS = @YFLAGS@ TARGOS = @targos@ TARGOSVER = @targosver@ TARGMACH = @targmach@ prefix = @prefix@ exec_prefix = @exec_prefix@ libexecdir = @libexecdir@ datarootdir = @datarootdir@ mandir = @mandir@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ CCOM=$(BINPREFIX)ccom$(EXEEXT) CC0=$(BINPREFIX)cc0$(EXEEXT) CC1=$(BINPREFIX)cc1$(EXEEXT) CF0=@CF0@ CF1=@CF1@ MDIR=$(top_srcdir)/arch/$(TARGMACH) MIPDIR=$(top_srcdir)/mip COMMONDIR=$(top_srcdir)/common DEST=@CCNAMES@ MANPAGE=$(BINPREFIX)ccom MKEXT=mkext$(EXEEXT) all: $(DEST) OBJS= builtins.o cgram.o code.o common.o compat.o dwarf.o external.o \ gcc_compat.o init.o inline.o local.o local2.o main.o strtodg.o \ match.o optim.o optim2.o order.o pftn.o reader.o softfloat.o \ regs.o scan.o stabs.o symtabs.o table.o trees.o unicode.o OBJS0= builtins.o cgram.o code.o common.o compat.o dwarf.o external.o \ gcc_compat.o init.o inline.o local.o main.o \ optim.o pftn.o softfloat.o strtodg.o \ scan.o stabs.o symtabs.o trees.o unicode.o OBJS1= common2.o compat.o external.o \ local2.o main2.o \ match.o optim2.o order.o reader.o \ regs.o table.o LOBJS= mkext.lo common.lo table.lo HDRS= $(srcdir)/pass1.h $(MIPDIR)/pass2.h $(MIPDIR)/manifest.h \ $(MDIR)/macdefs.h $(MIPDIR)/node.h $(COMMONDIR)/compat.h \ $(COMMONDIR)/unicode.h # # round 1: generate external.[ch], cgram.[ch] & scan.c # $(LOBJS): $(HDRS) mkext.lo: $(MIPDIR)/mkext.c $(CC_FOR_BUILD) $(CFLAGS) $(CPPFLAGS) -DMKEXT -c -o $@ $(MIPDIR)/mkext.c common.lo: $(MIPDIR)/common.c $(CC_FOR_BUILD) $(CFLAGS) $(CPPFLAGS) -DMKEXT -c -o $@ $(MIPDIR)/common.c table.lo: $(MDIR)/table.c $(CC_FOR_BUILD) $(CFLAGS) $(CPPFLAGS) -DMKEXT -c -o $@ $(MDIR)/table.c $(MKEXT): $(LOBJS) $(CC_FOR_BUILD) $(LDFLAGS) $(LOBJS) -o $@ $(LIBS) external.c: $(MKEXT) $(builddir)/$(MKEXT) cgram.c: $(srcdir)/cgram.y $(YACC) $(YFLAGS) -d $(srcdir)/cgram.y mv -f y.tab.c cgram.c mv -f y.tab.h cgram.h scan.c: $(srcdir)/scan.l $(LEX) $(LFLAGS) $(srcdir)/scan.l mv -f $(LEX_OUTPUT_ROOT).c scan.c # # round 2: compile $(OBJS) # $(OBJS): $(HDRS) external.c cgram.c builtins.o: $(srcdir)/builtins.c $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/builtins.c cgram.o: cgram.c $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ cgram.c code.o: $(MDIR)/code.c $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/code.c common.o: $(MIPDIR)/common.c $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/common.c common2.o: $(MIPDIR)/common.c $(CC) $(CF1) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/common.c compat.o: $(COMMONDIR)/compat.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(COMMONDIR)/compat.c dwarf.o: $(srcdir)/dwarf.c $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/dwarf.c external.o: external.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ external.c gcc_compat.o: $(srcdir)/gcc_compat.c $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/gcc_compat.c init.o: $(srcdir)/init.c $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/init.c inline.o: $(srcdir)/inline.c $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/inline.c local.o: $(MDIR)/local.c $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/local.c local2.o: $(MDIR)/local2.c $(CC) $(CF1) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/local2.c main.o: $(srcdir)/main.c $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/main.c main2.o: $(srcdir)/main.c $(CC) $(CF1) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/main.c match.o: $(MIPDIR)/match.c $(CC) $(CF1) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/match.c optim.o: $(srcdir)/optim.c $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/optim.c optim2.o: $(MIPDIR)/optim2.c $(CC) $(CF1) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/optim2.c order.o: $(MDIR)/order.c $(CC) $(CF1) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/order.c pftn.o: $(srcdir)/pftn.c $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/pftn.c reader.o: $(MIPDIR)/reader.c $(CC) $(CF1) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/reader.c regs.o: $(MIPDIR)/regs.c $(CC) $(CF1) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/regs.c scan.o: scan.c $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ scan.c softfloat.o: $(COMMONDIR)/softfloat.c $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(COMMONDIR)/softfloat.c stabs.o: $(srcdir)/stabs.c $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/stabs.c strtodg.o: $(COMMONDIR)/strtodg.c $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(COMMONDIR)/strtodg.c symtabs.o: $(srcdir)/symtabs.c $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/symtabs.c table.o: $(MDIR)/table.c $(CC) $(CF1) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/table.c trees.o: $(srcdir)/trees.c $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/trees.c unicode.o: $(COMMONDIR)/unicode.c $(CC) $(CF0) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(COMMONDIR)/unicode.c # # round 3: build $(DEST) # $(CCOM): $(OBJS) $(CC) $(LDFLAGS) $(OBJS) -o $@ $(LIBS) $(CC0): $(OBJS0) $(CC) $(LDFLAGS) $(OBJS0) -o $@ $(LIBS) $(CC1): $(OBJS1) $(CC) $(LDFLAGS) $(OBJS1) -o $@ $(LIBS) install: $(DEST) test -z "$(DESTDIR)$(libexecdir)" || mkdir -p "$(DESTDIR)$(libexecdir)" $(INSTALL_PROGRAM) $(DEST) $(DESTDIR)$(libexecdir) test -z "$(DESTDIR)$(mandir)/man1" || mkdir -p "$(DESTDIR)$(mandir)/man1" $(INSTALL_DATA) $(srcdir)/ccom.1 $(DESTDIR)$(mandir)/man1/$(MANPAGE).1 clean: rm -f $(DEST) $(OBJS0) $(OBJS1) $(MKEXT) $(LOBJS) \ $(LEX_OUTPUT_ROOT).c scan.c y.tab.[ch] cgram.[ch] external.[ch] distclean: clean rm -f Makefile pcc-20181216/cc/ccom/builtins.c010064400017500000000000000713601340102345600147740ustar raggewheel/* $Id: builtins.c,v 1.75 2018/12/02 18:40:46 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass1.h" #define ccopy p1tcopy #ifndef MIN #define MIN(a,b) (((a)<(b))?(a):(b)) #endif #ifndef MAX #define MAX(a,b) (((a)>(b))?(a):(b)) #endif #ifndef NO_C_BUILTINS extern int dimfuncnt; /* * replace an alloca function with direct allocation on stack. * return a destination temp node. */ static P1ND * builtin_alloca(const struct bitable *bt, P1ND *a) { P1ND *t, *u; #ifdef notyet if (xnobuiltins) return NULL; #endif t = tempnode(0, VOID|PTR, 0, 0); u = tempnode(regno(t), VOID|PTR, 0, 0); spalloc(t, a, SZCHAR); return u; } /* * Determine if a value is known to be constant at compile-time and * hence that PCC can perform constant-folding on expressions involving * that value. */ static P1ND * builtin_constant_p(const struct bitable *bt, P1ND *a) { P1ND *f; int isconst; p1walkf(a, putjops, 0); for (f = a; f->n_op == COMOP; f = f->n_right) ; isconst = nncon(f); p1tfree(a); return bcon(isconst); } /* * Hint to the compiler whether this expression will evaluate true or false. * Just ignored for now. */ static P1ND * builtin_expect(const struct bitable *bt, P1ND *a) { P1ND *f; if (a && a->n_op == CM) { p1tfree(a->n_right); f = a->n_left; p1nfree(a); a = f; } return a; } /* * Take integer absolute value. * Simply does: ((((x)>>(8*sizeof(x)-1))^(x))-((x)>>(8*sizeof(x)-1))) */ static P1ND * builtin_abs(const struct bitable *bt, P1ND *a) { P1ND *p, *q, *r, *t, *t2, *t3; int tmp1, tmp2, shift; if (a->n_type != INT) a = cast(a, INT, 0); if (a->n_op == ICON) { if (glval(a) < 0) slval(a, -glval(a)); p = a; } else { t = tempnode(0, a->n_type, a->n_df, a->n_ap); tmp1 = regno(t); p = buildtree(ASSIGN, t, a); t = tempnode(tmp1, a->n_type, a->n_df, a->n_ap); shift = (int)tsize(a->n_type, a->n_df, a->n_ap) - 1; q = buildtree(RS, t, bcon(shift)); t2 = tempnode(0, a->n_type, a->n_df, a->n_ap); tmp2 = regno(t2); q = buildtree(ASSIGN, t2, q); t = tempnode(tmp1, a->n_type, a->n_df, a->n_ap); t2 = tempnode(tmp2, a->n_type, a->n_df, a->n_ap); t3 = tempnode(tmp2, a->n_type, a->n_df, a->n_ap); r = buildtree(MINUS, buildtree(ER, t, t2), t3); p = buildtree(COMOP, p, buildtree(COMOP, q, r)); } return p; } #define cmop(x,y) buildtree(COMOP, x, y) #define lblnod(l) nlabel(l) #ifndef TARGET_BSWAP static P1ND * builtin_bswap16(const struct bitable *bt, P1ND *a) { P1ND *f, *t1, *t2; t1 = buildtree(LS, buildtree(AND, ccopy(a), bcon(255)), bcon(8)); t2 = buildtree(AND, buildtree(RS, a, bcon(8)), bcon(255)); f = buildtree(OR, t1, t2); return f; } static P1ND * builtin_bswap32(const struct bitable *bt, P1ND *a) { P1ND *f, *t1, *t2, *t3, *t4; t1 = buildtree(LS, buildtree(AND, ccopy(a), bcon(255)), bcon(24)); t2 = buildtree(LS, buildtree(AND, ccopy(a), bcon(255 << 8)), bcon(8)); t3 = buildtree(AND, buildtree(RS, ccopy(a), bcon(8)), bcon(255 << 8)); t4 = buildtree(AND, buildtree(RS, a, bcon(24)), bcon(255)); f = buildtree(OR, buildtree(OR, t1, t2), buildtree(OR, t3, t4)); return f; } static P1ND * builtin_bswap64(const struct bitable *bt, P1ND *a) { P1ND *f, *t1, *t2, *t3, *t4, *t5, *t6, *t7, *t8; #define X(x) xbcon(x, NULL, ctype(ULONGLONG)) t1 = buildtree(LS, buildtree(AND, ccopy(a), X(255)), bcon(56)); t2 = buildtree(LS, buildtree(AND, ccopy(a), X(255 << 8)), bcon(40)); t3 = buildtree(LS, buildtree(AND, ccopy(a), X(255 << 16)), bcon(24)); t4 = buildtree(LS, buildtree(AND, ccopy(a), X(255 << 24)), bcon(8)); t5 = buildtree(AND, buildtree(RS, ccopy(a), bcon(8)), X(255 << 24)); t6 = buildtree(AND, buildtree(RS, ccopy(a), bcon(24)), X(255 << 16)); t7 = buildtree(AND, buildtree(RS, ccopy(a), bcon(40)), X(255 << 8)); t8 = buildtree(AND, buildtree(RS, a, bcon(56)), X(255)); f = buildtree(OR, buildtree(OR, buildtree(OR, t1, t2), buildtree(OR, t3, t4)), buildtree(OR, buildtree(OR, t5, t6), buildtree(OR, t7, t8))); return f; #undef X } #endif #ifndef TARGET_CXZ /* * Find number of beginning 0's in a word of type t. * t should be deunsigned. */ static P1ND * builtin_cxz(P1ND *a, TWORD t, int isclz) { P1ND *t101, *t102; P1ND *rn, *p; int l15, l16, l17; int sz; t = ctype(t); sz = (int)tsize(t, 0, 0); t101 = tempnode(0, INT, 0, 0); t102 = tempnode(0, t, 0, 0); l15 = getlab(); l16 = getlab(); l17 = getlab(); rn = buildtree(ASSIGN, ccopy(t102), a); rn = cmop(rn, buildtree(ASSIGN, ccopy(t101), bcon(0))); rn = cmop(rn, lblnod(l16)); p = buildtree(CBRANCH, buildtree(GE, ccopy(t101), bcon(sz)), bcon(l15)); rn = cmop(rn, p); if (isclz) { p = buildtree(CBRANCH, buildtree(GE, ccopy(t102), bcon(0)), bcon(l17)); } else { p = buildtree(CBRANCH, buildtree(EQ, buildtree(AND, ccopy(t102), bcon(1)), bcon(0)), bcon(l17)); } rn = cmop(rn, p); rn = cmop(rn, block(GOTO, bcon(l15), NULL, INT, 0, 0)); rn = cmop(rn, lblnod(l17)); rn = cmop(rn, buildtree(isclz ? LSEQ : RSEQ , t102, bcon(1))); rn = cmop(rn, buildtree(INCR, ccopy(t101), bcon(1))); rn = cmop(rn, block(GOTO, bcon(l16), NULL, INT, 0, 0)); rn = cmop(rn, lblnod(l15)); return cmop(rn, t101); } static P1ND * builtin_clz(const struct bitable *bt, P1ND *a) { return builtin_cxz(a, INT, 1); } static P1ND * builtin_clzl(const struct bitable *bt, P1ND *a) { return builtin_cxz(a, LONG, 1); } static P1ND * builtin_clzll(const struct bitable *bt, P1ND *a) { return builtin_cxz(a, LONGLONG, 1); } static P1ND * builtin_ctz(const struct bitable *bt, P1ND *a) { return builtin_cxz(a, INT, 0); } static P1ND * builtin_ctzl(const struct bitable *bt, P1ND *a) { return builtin_cxz(a, LONG, 0); } static P1ND * builtin_ctzll(const struct bitable *bt, P1ND *a) { return builtin_cxz(a, LONGLONG, 0); } #endif #ifndef TARGET_ERA static P1ND * builtin_era(const struct bitable *bt, P1ND *a) { return a; /* Just pass through */ } #endif #ifndef TARGET_FFS /* * Find number of beginning 0's in a word of type t. * t should be deunsigned. */ static P1ND * builtin_ff(P1ND *a, TWORD t) { P1ND *t101, *t102; P1ND *rn, *p; int l15, l16, l17; int sz; t = ctype(t); sz = (int)tsize(t, 0, 0)+1; t101 = tempnode(0, INT, 0, 0); t102 = tempnode(0, t, 0, 0); l15 = getlab(); l16 = getlab(); l17 = getlab(); rn = buildtree(ASSIGN, ccopy(t101), bcon(0)); rn = cmop(rn, buildtree(ASSIGN, ccopy(t102), a)); p = buildtree(CBRANCH, buildtree(EQ, ccopy(t102), bcon(0)), bcon(l15)); rn = cmop(rn, p); rn = cmop(rn, buildtree(INCR, ccopy(t101), bcon(1))); rn = cmop(rn, lblnod(l16)); p = buildtree(CBRANCH, buildtree(GE, ccopy(t101), bcon(sz)), bcon(l15)); rn = cmop(rn, p); p = buildtree(CBRANCH, buildtree(EQ, buildtree(AND, ccopy(t102), bcon(1)), bcon(0)), bcon(l17)); rn = cmop(rn, p); rn = cmop(rn, block(GOTO, bcon(l15), NULL, INT, 0, 0)); rn = cmop(rn, lblnod(l17)); rn = cmop(rn, buildtree(RSEQ, t102, bcon(1))); rn = cmop(rn, buildtree(INCR, ccopy(t101), bcon(1))); rn = cmop(rn, block(GOTO, bcon(l16), NULL, INT, 0, 0)); rn = cmop(rn, lblnod(l15)); return cmop(rn, t101); } static P1ND * builtin_ffs(const struct bitable *bt, P1ND *a) { return builtin_ff(a, INT); } static P1ND * builtin_ffsl(const struct bitable *bt, P1ND *a) { return builtin_ff(a, LONG); } static P1ND * builtin_ffsll(const struct bitable *bt, P1ND *a) { return builtin_ff(a, LONGLONG); } #endif static P1ND * builtin_popcnt(P1ND *a, TWORD t) { P1ND *t101, *t102; P1ND *rn, *p; int l15, l16, l17; t101 = tempnode(0, INT, 0, 0); /* counter for set bits */ t102 = tempnode(0, t, 0, 0); /* input data */ l15 = getlab(); l16 = getlab(); l17 = getlab(); rn = buildtree(ASSIGN, ccopy(t101), bcon(0)); /* bit counter set to 0 */ p = buildtree(ASSIGN, ccopy(t102), a); /* input data */ rn = cmop(rn, p); rn = cmop(rn, lblnod(l15)); /* place a label here */ p = buildtree(CBRANCH, buildtree(EQ, buildtree(AND, ccopy(t102), bcon(1)), bcon(0)), bcon(l16)); /* if (t103 & 1) == 0, goto l16 */ rn = cmop(rn, p); rn = cmop(rn, buildtree(INCR, ccopy(t101), bcon(1))); /* bit counter plus 1 */ rn = cmop(rn, lblnod(l16)); /* label */ rn = cmop(rn, buildtree(RSEQ, t102, bcon(1))); /* right-shift input data 1 position */ p = buildtree(CBRANCH, buildtree(EQ, ccopy(t102), bcon(0)), bcon(l17)); /* if all bits unset, goto l17 */ rn = cmop(rn, p); rn = cmop(rn, block(GOTO, bcon(l15), NULL, INT, 0, 0)); /* go to the beginning of loop */ rn = cmop(rn, lblnod(l17)); /* label, loop exit here */ return cmop(rn, t101); } static P1ND * builtin_popcount(const struct bitable *bt, P1ND *a) { return builtin_popcnt(a, UNSIGNED); } static P1ND * builtin_popcountl(const struct bitable *bt, P1ND *a) { return builtin_popcnt(a, ULONG); } static P1ND * builtin_popcountll(const struct bitable *bt, P1ND *a) { return builtin_popcnt(a, ULONGLONG); } /* * Get size of object, if possible. * 0 = whole object, 1 == closest object. Return -1 if not available. * 2 == max of rem object, 3 == min of rem obj. Return 0 if not available. */ static P1ND * builtin_object_size(const struct bitable *bt, P1ND *a) { CONSZ v = icons(a->n_right); int r; if (v < 0 || v > 3) uerror("arg2 must be between 0 and 3"); r = v < 2 ? -1 : 0; a = p1nfree(a); #ifdef notyet if (ISPTR(a->n_type)) { a = buildtree(UMUL, a, 0); a = optloop(a); a = doszof(a); } #else p1walkf(a, putjops, 0); /* if ?: exists */ p1tfree(a); #endif return xbcon(r, NULL, bt->rt); } #ifndef TARGET_STDARGS static P1ND * builtin_stdarg_start(const struct bitable *bt, P1ND *a) { P1ND *p, *q; int sz; /* must first deal with argument size; use int size */ p = a->n_right; if (p->n_type < INT) { sz = (int)(SZINT/tsize(p->n_type, p->n_df, p->n_ap)); } else sz = 1; /* do the real job */ p = buildtree(ADDROF, p, NULL); /* address of last arg */ #ifdef BACKAUTO p = optim(buildtree(PLUS, p, bcon(sz))); /* add one to it (next arg) */ #else p = optim(buildtree(MINUS, p, bcon(sz))); /* add one to it (next arg) */ #endif q = block(NAME, NULL, NULL, PTR+VOID, 0, 0); /* create cast node */ q = buildtree(CAST, q, p); /* cast to void * (for assignment) */ p = q->n_right; p1nfree(q->n_left); p1nfree(q); p = buildtree(ASSIGN, a->n_left, p); /* assign to ap */ p1nfree(a); return p; } static P1ND * builtin_va_arg(const struct bitable *bt, P1ND *a) { P1ND *p, *q, *r, *rv; int sz, nodnum; /* create a copy to a temp node of current ap */ p = ccopy(a->n_left); q = tempnode(0, p->n_type, p->n_df, p->n_ap); nodnum = regno(q); rv = buildtree(ASSIGN, q, p); r = a->n_right; sz = (int)tsize(r->n_type, r->n_df, r->n_ap); #ifdef MYVAARGSZ SETOFF(sz, MYVAARGSZ); #endif sz /= SZCHAR; /* add one to ap */ #ifdef BACKAUTO rv = buildtree(COMOP, rv , buildtree(PLUSEQ, a->n_left, bcon(sz))); #else #error fix wrong eval order in builtin_va_arg ecomp(buildtree(MINUSEQ, a->n_left, bcon(sz))); #endif p1nfree(a->n_right); p1nfree(a); r = tempnode(nodnum, INCREF(r->n_type), r->n_df, r->n_ap); return buildtree(COMOP, rv, buildtree(UMUL, r, NULL)); } static P1ND * builtin_va_end(const struct bitable *bt, P1ND *a) { return a; /* may have side effects */ } static P1ND * builtin_va_copy(const struct bitable *bt, P1ND *a) { P1ND *f; f = buildtree(ASSIGN, a->n_left, a->n_right); p1nfree(a); return f; } #endif /* TARGET_STDARGS */ /* * For unimplemented "builtin" functions, try to invoke the * non-builtin name */ static P1ND * binhelp(P1ND *a, TWORD rt, char *n) { P1ND *f = block(NAME, NULL, NULL, INT, 0, 0); int oblvl = blevel; blevel = 0; f->n_sp = lookup(addname(n), SNORMAL); blevel = oblvl; if (f->n_sp->sclass == SNULL) { f->n_sp->sclass = EXTERN; f->n_sp->stype = INCREF(rt)+(FTN-PTR); f->n_sp->sdf = permalloc(sizeof(union dimfun)); dimfuncnt++; f->n_sp->sdf->dfun = NULL; } f->n_type = f->n_sp->stype; f = clocal(f); return buildtree(CALL, f, a); } static P1ND * builtin_unimp(const struct bitable *bt, P1ND *a) { return binhelp(a, bt->rt, &bt->name[10]); } #if 0 static P1ND * builtin_unimp_f(P1ND *f, P1ND *a, TWORD rt) { return binhelp(f, a, rt, f->n_sp->sname); } #endif #ifndef TARGET_PREFETCH static P1ND * builtin_prefetch(const struct bitable *bt, P1ND *a) { p1tfree(a); return bcon(0); } #endif /* * check if compatible types. * XXX - all enum are considered equal types */ static P1ND * builtin_tc(const struct bitable *bt, P1ND *a) { P1ND *p; if (a == NULL || a->n_op != CM || a->n_left->n_op != TYPE || a->n_right->n_op != TYPE) uerror("bad %s arg", bt->name); p = bcon(a->n_left->n_type == a->n_right->n_type); p1nfree(a->n_left); p1nfree(a->n_right); p1nfree(a); return p; } static void putinlbl(P1ND *p, void *arg) { if (p->n_op == COMOP && p->n_left->n_op == GOTO) { int v = (int)glval(p->n_left->n_left); send_passt(IP_DEFLAB, v+1); } } /* * Similar to ?: */ static P1ND * builtin_ce(const struct bitable *bt, P1ND *a) { P1ND *p; if (a == NULL || a->n_op != CM || a->n_left->n_op != CM || a->n_left->n_left->n_op == CM) uerror("bad %s arg", bt->name); if (nncon(a->n_left->n_left) == 0) uerror("arg not constant"); if (glval(a)) { p = a->n_left->n_right; a->n_left->n_op = UMUL; /* for p1tfree() */ p1walkf(a->n_right, putinlbl, 0); } else { p = a->n_right; a->n_op = UMUL; /* for p1tfree() */ p1walkf(a->n_left->n_right, putinlbl, 0); } p1tfree(a); return p; } static P1ND * builtin_classify_type(const struct bitable *bt, P1ND *a) { TWORD t = a->n_type; int rv; if (t == BOOL) rv = 4; else if (t == CHAR || t == UCHAR) rv = 2; else if (t <= ULONGLONG) rv = 1; else if (t == STRTY) rv = 12; else if (t == UNIONTY) rv = 13; else if (ISPTR(t)) rv = 5; else if (ISFTY(t)) rv = 8; else if (ISFTN(t)) rv = 10; else if (ISCTY(t)) rv = 9; else rv = -1; p1tfree(a); return bcon(rv); } #ifndef TARGET_ISMATH /* * Handle the builtin macros for the math functions is* * To get something that is be somewhat generic assume that * isnan() is a real function and that cast of a NaN type * to double will still be a NaN. */ static P1ND * mtisnan(P1ND *p) { return binhelp(cast(ccopy(p), DOUBLE, 0), INT, "isnan"); } static TWORD mtcheck(P1ND *p) { TWORD t1 = p->n_left->n_type, t2 = p->n_right->n_type; if ((t1 >= FLOAT && t1 <= LDOUBLE) || (t2 >= FLOAT && t2 <= LDOUBLE)) return MAX(t1, t2); return 0; } static P1ND * builtin_isunordered(const struct bitable *bt, P1ND *a) { P1ND *p; if (mtcheck(a) == 0) return bcon(0); p = buildtree(OROR, mtisnan(a->n_left), mtisnan(a->n_right)); p1tfree(a); return p; } static P1ND * builtin_isany(P1ND *a, TWORD rt, int cmpt) { P1ND *p, *q; TWORD t; if ((t = mtcheck(a)) == 0) return bcon(0); p = buildtree(OROR, mtisnan(a->n_left), mtisnan(a->n_right)); p = buildtree(NOT, p, NULL); q = buildtree(cmpt, cast(ccopy(a->n_left), t, 0), cast(ccopy(a->n_right), t, 0)); p = buildtree(ANDAND, p, q); p1tfree(a); return p; } static P1ND * builtin_isgreater(const struct bitable *bt, P1ND *a) { return builtin_isany(a, bt->rt, GT); } static P1ND * builtin_isgreaterequal(const struct bitable *bt, P1ND *a) { return builtin_isany(a, bt->rt, GE); } static P1ND * builtin_isless(const struct bitable *bt, P1ND *a) { return builtin_isany(a, bt->rt, LT); } static P1ND * builtin_islessequal(const struct bitable *bt, P1ND *a) { return builtin_isany(a, bt->rt, LE); } static P1ND * builtin_islessgreater(const struct bitable *bt, P1ND *a) { P1ND *p, *q, *r; TWORD t; if ((t = mtcheck(a)) == 0) return bcon(0); p = buildtree(OROR, mtisnan(a->n_left), mtisnan(a->n_right)); p = buildtree(NOT, p, NULL); q = buildtree(GT, cast(ccopy(a->n_left), t, 0), cast(ccopy(a->n_right), t, 0)); r = buildtree(LT, cast(ccopy(a->n_left), t, 0), cast(ccopy(a->n_right), t, 0)); q = buildtree(OROR, q, r); p = buildtree(ANDAND, p, q); p1tfree(a); return p; } #endif #ifndef TARGET_SIGNBIT static P1ND * builtin_signbit(const struct bitable *bt, P1ND *a) { return binhelp(a, INT, "__signbitd"); } static P1ND * builtin_signbitf(const struct bitable *bt, P1ND *a) { return binhelp(a, INT, "__signbitf"); } static P1ND * builtin_signbitl(const struct bitable *bt, P1ND *a) { return binhelp(a, INT, "__signbitl"); } #endif static P1ND * builtin_huge_val(const struct bitable *bt, P1ND *a) { P1ND *f = block(FCON, NULL, NULL, bt->rt, NULL, 0); f->n_scon = sfallo(); soft_huge_val(f->n_scon); return f; } /* * Return NANs, if reasonable. */ static P1ND * builtin_nanx(const struct bitable *bt, P1ND *a) { if (a == NULL || a->n_op == CM) { uerror("%s bad argument", bt->name); a = bcon(0); } else if (a->n_op == STRING && *a->n_name == '\0') { p1nfree(a); a = block(FCON, NULL, NULL, bt->rt, NULL, 0); a->n_scon = sfallo(); soft_nan(a->n_scon, NULL); } else a = binhelp(eve(a), bt->rt, &bt->name[10]); return a; } #ifndef NO_COMPLEX static P1ND * builtin_cir(const struct bitable *bt, P1ND *a) { char *n; if (a == NULL || a->n_op == CM) { uerror("wrong argument count to %s", bt->name); return bcon(0); } n = addname(bt->name[1] == 'r' ? "__real" : "__imag"); return cast(structref(a, DOT, n), bt->rt, 0); } #endif /* * Target defines, to implement target versions of the generic builtins */ #ifndef TARGET_MEMCMP #define builtin_memcmp builtin_unimp #endif #ifndef TARGET_MEMCPY #define builtin_memcpy builtin_unimp #endif #ifndef TARGET_MEMPCPY #define builtin_mempcpy builtin_unimp #endif #ifndef TARGET_MEMSET #define builtin_memset builtin_unimp #endif /* Reasonable type of size_t */ #ifndef SIZET #if SZINT == SZSHORT #define SIZET UNSIGNED #elif SZLONG > SZINT #define SIZET ULONG #else #define SIZET UNSIGNED #endif #endif static TWORD memcpyt[] = { VOID|PTR, VOID|PTR, SIZET, INT }; static TWORD memsett[] = { VOID|PTR, INT, SIZET, INT }; static TWORD allocat[] = { SIZET }; static TWORD expectt[] = { LONG, LONG }; static TWORD strcmpt[] = { CHAR|PTR, CHAR|PTR }; static TWORD strcpyt[] = { CHAR|PTR, CHAR|PTR, INT }; static TWORD strncpyt[] = { CHAR|PTR, CHAR|PTR, SIZET, INT }; static TWORD strchrt[] = { CHAR|PTR, INT }; static TWORD strcspnt[] = { CHAR|PTR, CHAR|PTR }; static TWORD strspnt[] = { CHAR|PTR, CHAR|PTR }; static TWORD strpbrkt[] = { CHAR|PTR, CHAR|PTR }; static TWORD nant[] = { CHAR|PTR }; static TWORD bitt[] = { UNSIGNED }; static TWORD bsw16t[] = { USHORT }; static TWORD bitlt[] = { ULONG }; static TWORD bitllt[] = { ULONGLONG }; static TWORD abst[] = { INT }; static TWORD fmaxft[] = { FLOAT, FLOAT }; static TWORD fmaxt[] = { DOUBLE, DOUBLE }; static TWORD fmaxlt[] = { LDOUBLE, LDOUBLE }; static TWORD scalbnft[] = { FLOAT, INT }; static TWORD scalbnt[] = { DOUBLE, INT }; static TWORD scalbnlt[] = { LDOUBLE, INT }; static const struct bitable bitable[] = { /* gnu universe only */ { "alloca", builtin_alloca, BTGNUONLY, 1, allocat, VOID|PTR }, #ifndef NO_COMPLEX /* builtins for complex operations */ { "crealf", builtin_cir, BTNOPROTO, 1, 0, FLOAT }, { "creal", builtin_cir, BTNOPROTO, 1, 0, DOUBLE }, { "creall", builtin_cir, BTNOPROTO, 1, 0, LDOUBLE }, { "cimagf", builtin_cir, BTNOPROTO, 1, 0, FLOAT }, { "cimag", builtin_cir, BTNOPROTO, 1, 0, DOUBLE }, { "cimagl", builtin_cir, BTNOPROTO, 1, 0, LDOUBLE }, #endif /* always existing builtins */ { "__builtin___memcpy_chk", builtin_unimp, 0, 4, memcpyt, VOID|PTR }, { "__builtin___mempcpy_chk", builtin_unimp, 0, 4, memcpyt, VOID|PTR }, { "__builtin___memmove_chk", builtin_unimp, 0, 4, memcpyt, VOID|PTR }, { "__builtin___memset_chk", builtin_unimp, 0, 4, memsett, VOID|PTR }, { "__builtin___strcat_chk", builtin_unimp, 0, 3, strcpyt, CHAR|PTR }, { "__builtin___strcpy_chk", builtin_unimp, 0, 3, strcpyt, CHAR|PTR }, { "__builtin___stpcpy_chk", builtin_unimp, 0, 3, strcpyt, CHAR|PTR }, { "__builtin___strncat_chk", builtin_unimp, 0, 4, strncpyt,CHAR|PTR }, { "__builtin___strncpy_chk", builtin_unimp, 0, 4, strncpyt,CHAR|PTR }, { "__builtin___stpncpy_chk", builtin_unimp, 0, 4, strncpyt,CHAR|PTR }, { "__builtin___printf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT }, { "__builtin___fprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT }, { "__builtin___sprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT }, { "__builtin___snprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT }, { "__builtin___vprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT }, { "__builtin___vfprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT }, { "__builtin___vsprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT }, { "__builtin___vsnprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT }, { "__builtin_alloca", builtin_alloca, 0, 1, allocat, VOID|PTR }, { "__builtin_abs", builtin_abs, 0, 1, abst, INT }, { "__builtin_bswap16", builtin_bswap16, 0, 1, bsw16t, USHORT }, { "__builtin_bswap32", builtin_bswap32, 0, 1, bitt, UNSIGNED }, { "__builtin_bswap64", builtin_bswap64, 0, 1, bitllt, ULONGLONG }, { "__builtin_choose_expr", builtin_ce, BTNOPROTO|BTNORVAL, 0, 0, 0 }, { "__builtin_clz", builtin_clz, 0, 1, bitt, INT }, { "__builtin_clzl", builtin_clzl, 0, 1, bitlt, INT }, { "__builtin_clzll", builtin_clzll, 0, 1, bitllt, INT }, { "__builtin_ctz", builtin_ctz, 0, 1, bitt, INT }, { "__builtin_ctzl", builtin_ctzl, 0, 1, bitlt, INT }, { "__builtin_ctzll", builtin_ctzll, 0, 1, bitllt, INT }, { "__builtin_extract_return_addr", builtin_era, 0, 1, memcpyt, VOID|PTR }, { "__builtin_ffs", builtin_ffs, 0, 1, bitt, INT }, { "__builtin_ffsl", builtin_ffsl, 0, 1, bitlt, INT }, { "__builtin_ffsll", builtin_ffsll, 0, 1, bitllt, INT }, { "__builtin_popcount", builtin_popcount, 0, 1, bitt, UNSIGNED }, { "__builtin_popcountl", builtin_popcountl, 0, 1, bitlt, ULONG }, { "__builtin_popcountll", builtin_popcountll, 0, 1, bitllt, ULONGLONG }, { "__builtin_classify_type", builtin_classify_type, 0, 1, 0, INT }, { "__builtin_constant_p", builtin_constant_p, 0, 1, 0, INT }, { "__builtin_copysignf", builtin_unimp, 0, 2, fmaxft, FLOAT }, { "__builtin_copysign", builtin_unimp, 0, 2, fmaxt, DOUBLE }, { "__builtin_copysignl", builtin_unimp, 0, 2, fmaxlt, LDOUBLE }, { "__builtin_expect", builtin_expect, 0, 2, expectt, LONG }, { "__builtin_memcmp", builtin_memcmp, 0, 3, memcpyt, INT }, { "__builtin_memcpy", builtin_memcpy, 0, 3, memcpyt, VOID|PTR }, { "__builtin_mempcpy", builtin_mempcpy, 0, 3, memcpyt, VOID|PTR }, { "__builtin_memset", builtin_memset, 0, 3, memsett, VOID|PTR }, { "__builtin_fabsf", builtin_unimp, 0, 1, fmaxft, FLOAT }, { "__builtin_fabs", builtin_unimp, 0, 1, fmaxt, DOUBLE }, { "__builtin_fabsl", builtin_unimp, 0, 1, fmaxlt, LDOUBLE }, { "__builtin_fmaxf", builtin_unimp, 0, 2, fmaxft, FLOAT }, { "__builtin_fmax", builtin_unimp, 0, 2, fmaxt, DOUBLE }, { "__builtin_fmaxl", builtin_unimp, 0, 2, fmaxlt, LDOUBLE }, { "__builtin_huge_valf", builtin_huge_val, 0, 0, 0, FLOAT }, { "__builtin_huge_val", builtin_huge_val, 0, 0, 0, DOUBLE }, { "__builtin_huge_vall", builtin_huge_val, 0, 0, 0, LDOUBLE }, { "__builtin_inff", builtin_huge_val, 0, 0, 0, FLOAT }, { "__builtin_inf", builtin_huge_val, 0, 0, 0, DOUBLE }, { "__builtin_infl", builtin_huge_val, 0, 0, 0, LDOUBLE }, { "__builtin_isgreater", builtin_isgreater, 0, 2, NULL, INT }, { "__builtin_isgreaterequal", builtin_isgreaterequal, 0, 2, NULL, INT }, { "__builtin_isinff", builtin_unimp, 0, 1, fmaxft, INT }, { "__builtin_isinf", builtin_unimp, 0, 1, fmaxt, INT }, { "__builtin_isinfl", builtin_unimp, 0, 1, fmaxlt, INT }, { "__builtin_isless", builtin_isless, 0, 2, NULL, INT }, { "__builtin_islessequal", builtin_islessequal, 0, 2, NULL, INT }, { "__builtin_islessgreater", builtin_islessgreater, 0, 2, NULL, INT }, { "__builtin_isnanf", builtin_unimp, 0, 1, fmaxft, INT }, { "__builtin_isnan", builtin_unimp, 0, 1, fmaxt, INT }, { "__builtin_isnanl", builtin_unimp, 0, 1, fmaxlt, INT }, { "__builtin_isunordered", builtin_isunordered, 0, 2, NULL, INT }, { "__builtin_logbf", builtin_unimp, 0, 1, fmaxft, FLOAT }, { "__builtin_logb", builtin_unimp, 0, 1, fmaxt, DOUBLE }, { "__builtin_logbl", builtin_unimp, 0, 1, fmaxlt, LDOUBLE }, { "__builtin_nanf", builtin_nanx, BTNOEVE, 1, nant, FLOAT }, { "__builtin_nan", builtin_nanx, BTNOEVE, 1, nant, DOUBLE }, { "__builtin_nanl", builtin_nanx, BTNOEVE, 1, nant, LDOUBLE }, { "__builtin_object_size", builtin_object_size, BTNOPROTO, 2, memsett, SIZET }, { "__builtin_prefetch", builtin_prefetch, 0, 1, memsett, VOID }, { "__builtin_scalbnf", builtin_unimp, 0, 2, scalbnft, FLOAT }, { "__builtin_scalbn", builtin_unimp, 0, 2, scalbnt, DOUBLE }, { "__builtin_scalbnl", builtin_unimp, 0, 2, scalbnlt, LDOUBLE }, { "__builtin_signbitf", builtin_signbitf, 0, 1, scalbnft, INT }, { "__builtin_signbit", builtin_signbit, 0, 1, scalbnt, INT }, { "__builtin_signbitl", builtin_signbitl, 0, 1, scalbnlt, INT }, { "__builtin_strcmp", builtin_unimp, 0, 2, strcmpt, INT }, { "__builtin_strcpy", builtin_unimp, 0, 2, strcpyt, CHAR|PTR }, { "__builtin_stpcpy", builtin_unimp, 0, 2, strcpyt, CHAR|PTR }, { "__builtin_strchr", builtin_unimp, 0, 2, strchrt, CHAR|PTR }, { "__builtin_strlen", builtin_unimp, 0, 1, strcmpt, SIZET }, { "__builtin_strrchr", builtin_unimp, 0, 2, strchrt, CHAR|PTR }, { "__builtin_strncpy", builtin_unimp, 0, 3, strncpyt, CHAR|PTR }, { "__builtin_strncat", builtin_unimp, 0, 3, strncpyt, CHAR|PTR }, { "__builtin_strcspn", builtin_unimp, 0, 2, strcspnt, SIZET }, { "__builtin_strspn", builtin_unimp, 0, 2, strspnt, SIZET }, { "__builtin_strstr", builtin_unimp, 0, 2, strcmpt, CHAR|PTR }, { "__builtin_strpbrk", builtin_unimp, 0, 2, strpbrkt, CHAR|PTR }, { "__builtin_types_compatible_p", builtin_tc, BTNOPROTO|BTNOEVE, 2, 0, INT }, #ifndef TARGET_STDARGS { "__builtin_stdarg_start", builtin_stdarg_start, 0, 2, 0, VOID }, { "__builtin_va_start", builtin_stdarg_start, 0, 2, 0, VOID }, { "__builtin_va_arg", builtin_va_arg, BTNORVAL|BTNOPROTO, 2, 0, 0 }, { "__builtin_va_end", builtin_va_end, 0, 1, 0, VOID }, { "__builtin_va_copy", builtin_va_copy, 0, 2, 0, VOID }, #endif { "__builtin_dwarf_cfa", builtin_cfa, 0, 0, 0, VOID|PTR }, { "__builtin_frame_address", builtin_frame_address, 0, 1, bitt, VOID|PTR }, { "__builtin_return_address", builtin_return_address, 0, 1, bitt, VOID|PTR }, #ifdef TARGET_BUILTINS TARGET_BUILTINS #endif }; /* * Check and cast arguments for builtins. */ static int acnt(P1ND *a, int narg, TWORD *tp) { P1ND *q; TWORD t; if (a == NULL) return narg; for (; a->n_op == CM; a = a->n_left, narg--) { if (tp == NULL) continue; q = a->n_right; t = ctype(tp[narg-1]); if (q->n_type == t) continue; a->n_right = ccast(q, t, 0, NULL, 0); } /* Last arg is ugly to deal with */ if (narg == 1 && tp != NULL && a->n_type != tp[0]) { q = p1alloc(); *q = *a; q = ccast(q, ctype(tp[0]), 0, NULL, 0); *a = *q; p1nfree(q); } return narg != 1; } P1ND * builtin_check(struct symtab *sp, P1ND *a) { const struct bitable *bt; if (sp->soffset < 0 || sp->soffset >= (int)(sizeof(bitable)/sizeof(bitable[0]))) cerror("builtin_check"); bt = &bitable[sp->soffset]; if ((bt->flags & BTNOEVE) == 0 && a != NULL) a = eve(a); if (((bt->flags & BTNOPROTO) == 0) && acnt(a, bt->narg, bt->tp)) { uerror("wrong argument count to %s", bt->name); return bcon(0); } return (*bt->fun)(bt, a); } /* * Put all builtin functions into the global symbol table. */ void builtin_init() { const struct bitable *bt; P1ND *p = block(TYPE, 0, 0, 0, 0, 0); struct symtab *sp; int i, d_debug; d_debug = ddebug; ddebug = 0; for (i = 0; i < (int)(sizeof(bitable)/sizeof(bitable[0])); i++) { bt = &bitable[i]; if ((bt->flags & BTGNUONLY) && xgnu99 == 0 && xgnu89 == 0) continue; /* not in c99 universe, at least for now */ sp = lookup(addname(bt->name), 0); if (bt->rt == 0 && (bt->flags & BTNORVAL) == 0) cerror("function '%s' has no return type", bt->name); p->n_type = INCREF(bt->rt) + (FTN-PTR); p->n_df = memset(permalloc(sizeof(union dimfun)), 0, sizeof(union dimfun)); dimfuncnt++; p->n_sp = sp; defid(p, EXTERN); sp->soffset = i; sp->sflags |= SBUILTIN; } p1nfree(p); ddebug = d_debug; } #endif pcc-20181216/cc/ccom/ccom.1010064400017500000000000000311631340514255600140060ustar raggewheel.\" $Id: ccom.1,v 1.33 2018/12/15 09:12:14 plunky Exp $ .\" .\" Copyright (c) 2007 Jeremy C. Reed .\" .\" Permission to use, copy, modify, and/or distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR AND CONTRIBUTORS DISCLAIM .\" ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHOR AND .\" CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL .\" DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR .\" PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS .\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF .\" THIS SOFTWARE. .\" .Dd March 22, 2012 .Dt CCOM 1 .Os .Sh NAME .Nm ccom .Nd C compiler .Sh SYNOPSIS .Nm .Op Fl gkpsv .Op Fl f Ar features .Op Fl m Ar options .Op Fl W Ar warnings .Op Fl X Ar flags .Op Fl x Ar settings .Op Fl Z Ar flags .Op infile .Op outfile .Sh DESCRIPTION The .Nm utility provides a C compiler. The frontend is usually .Xr pcc 1 . It is .Em not intended to be run directly. .Nm reads the C source from .Ar infile or standard input and writes the assembler source to .Ar outfile or to standard output. .Pp The options are as follows: .Bl -tag -width Ds .It Fl f Ar feature Enable language features. Multiple .Fl f options can be given, the following features are supported: .Bl -tag -width Ds .It Sy stack-protector Enable stack smashing protection. Currently the same as .Sy stack-protector-all . .It Sy stack-protector-all Enable stack smashing protection for all functions. .It Sy pack-struct Ns Oo = Ns Ar n Oc Specify maximum alignment for structure members, similar to a #pragma pack statement at the start of the file. If no value is given, the default is 1. .It Sy freestanding Emit code for a freestanding environment. Currently not implemented. .El .It Fl g Include debugging information in the output code for use by symbolic and source-level debuggers. Currently this uses the .Sy stabs format, encoding information in .Em s Ns ymbol Em tab Ns le entrie Ns Em s. .It Fl k Generate PIC code. .It Fl m Ar option Target-specific options, used in machine-dependent code. Multiple .Fl m options can be given, the following options are supported: .Bl -tag -width PowerPC .It AMD64 .It ARM .Sy little-endian , .Sy big-endian , .Sy fpe=fpa , .Sy fpe=vpf , .Sy soft-float , .Sy arch=armv1 , .Sy arch=armv2 , .Sy arch=armv2a , .Sy arch=armv3 , .Sy arch=armv4 , .Sy arch=armv4t , .Sy arch=armv4tej , .Sy arch=armv5 , .Sy arch=armv5te , .Sy arch=armv5tej , .Sy arch=armv6 , .Sy arch=armv6t2 , .Sy arch=armv6kz , .Sy arch=armv6k No \*(Am .Sy arch=armv7 . .It HPPA .It i386 .It M16C .It MIPS .Sy little-endian No \*(Am .Sy big-endian . .It NOVA .It PDP-10 .It PDP-11 .It PowerPC .Sy little-endian , .Sy big-endian , .Sy soft-float No \*(Am .Sy hard-float . .It Sparc64 .It VAX .El .It Fl p Generate profiling code. .It Fl s Print statistics to standard error when complete. This includes: name table entries, name string size, permanent allocated memory, temporary allocated memory, lost memory, argument list unions, dimension/function unions, struct/union/enum blocks, inline node count, inline control blocks, and permanent symtab entries. .\" TODO: explain units for above? .It Fl v Display version. .It Fl W Ar warning Do some basic checks and emit warnings about possible coding problems. Multiple .Fl W options can be given, the following warnings are supported: .Bl -tag -width Ds .It Sy error Ns Oo = Ns Ar warning Oc Enable .Ar warning , and treat it as an error condition. If a specific warning is not given, producing any warning will cause an error. .It Sy attributes Warn when unsupported attributes are used. This warning is enabled by default. .It Sy deprecated-declarations Report whenever a symbol marked with the .Sq deprecated attribute is used. This warning is enabled by default. .It Sy implicit-function-declaration (TODO) Require explicit prototypes for all called functions. .It Sy implicit-int (TODO) Warn when a function declaration lacks a type. .It Sy missing-prototypes Require explicit prototypes for all global function definitions. .It Sy pointer-sign Warn when pointer operations are done with mismatched signed and unsigned values. .It Sy sign-compare (TODO) Warn about comparisons between signed and unsigned values. .It Sy strict-prototypes (TODO) Require that function prototypes are strictly C99. .It Sy shadow Report when a local variable shadows something from a higher scope. .It Sy truncate Report when integer values may be implicitly truncated to fit a smaller type. .It Sy uninitialized A variable is read before being written. .It Sy unknown-pragmas Report unhandled pragma statements. .It Sy unreachable-code Report statements that cannot be executed. .El .Pp Any of the above may be prefixed with .Dq no- in order to disable the effect. .\" .It Fl X Ar flags C specific debugging where .Ar flags is one or more of the following: .Pp .Bl -tag -compact -width Ds .It Sy b Building of parse trees .It Sy d Declarations (using multiple .Sy d flags gives more output) .It Sy e Pass1 trees at exit .It Sy i Initializations .It Sy n Memory allocations .It Sy o Turn off optimisations .It Sy p Prototypes .It Sy s Inlining .It Sy t Type conversions .It Sy x Target-specific flag, used in machine-dependent code .El .\" .It Fl x Ar setting Enable .Ar setting in the compiler. Multiple .Fl x options can be given, the following settings are supported: .Bl -tag -width Ds .It Sy ccp Apply sparse conditional constant propagation techniques for optimization. Currently not implemented. .It Sy dce Do dead code elimination. .It Sy deljumps Delete redundant jumps and dead code. .It Sy gnu89 .It Sy gnu99 Use GNU C semantics rather than C99 for some things. Currently only inline. .It Sy inline Replace calls to functions marked with an inline specifier with a copy of the actual function. .It Sy ssa Convert statements into static single assignment form for optimization. Not yet finished. .It Sy tailcall Enable optimization of tail-recursion functions. Currently not implemented. .It Sy temps Locate automatic variables into registers where possible, for further optimization by the register allocator. .It Sy uchar Treat character constants as unsigned values. .El .\" .It Fl Z Ar flags Code generator (pass2) specific debugging where .Ar flags is one or more of the following: .Pp .Bl -tag -compact -width Ds .It Sy b Basic block and SSA building .It Sy c Code printout .It Sy e Trees when entering pass2 .It Sy f Instruction matcher, may provide much output .It Sy g Print flow graphs .It Sy n Memory allocation .It Sy o Instruction generator .It Sy r Register allocator .It Sy s Shape matching in instruction generator .It Sy t Type matching in instruction generator .It Sy u Sethi-Ullman computations .It Sy x Target-specific flag, used in machine-dependent code .El .El .Sh PRAGMAS Input lines starting with a .Dq #pragma directive can be used to modify behaviour of .Nm during compilation. All tokens up to the first unescaped newline are considered part of the pragma command, with the following operations being recognized: .Bl -tag -width Ds .It Sy STDC Standard C99 operator follows. Currently no C99 operations are implemented, and any directives starting with this token will be silently ignored. .It Sy GCC diagnostic Ar effect Qq Ar option GNU C compatibility. Alter the effects of compiler diagnostics. The required .Ar effect should be stated as .Sy warning , .Sy error or .Sy ignored , followed by the compiler diagnostic .Ar option in double quotes. For example, to force unknown pragmas to always generate an error, a standard header might include .Bd -literal -offset 2n #pragma GCC diagnostic error "-Wunknown-pragmas" .Ed .It Sy GCC poison Ar identifier ... GNU C compatibility. Cause an error if any of the following .Ar identifier Ns s subsequently appear in the code .Pq but not in any macro expansions . Currently not implemented. .It Sy GCC system_header GNU C compatibility. Currently not implemented. .It Sy GCC visibility GNU C compatibility. Currently not implemented. .It Sy pack Ns Pq Op Ar n Set the default maximum alignment for structures and unions, such that members will have their natural alignment requirements clamped at this value and may be stored misaligned. If .Ar n is not given, the alignment is reset to the target default. .It Sy pack Ns Pq Sy push Ns Op , Ar n Push the current pack setting onto an internal stack then, if .Ar n is given, change the default alignment for structures and unions. Currently not implemented. .It Sy pack Ns Pq Sy pop Change the pack setting to the most recently pushed value, and remove that setting from the stack. Currently not implemented. .It Sy packed Op Ar n Set the maximum alignment for the structure or union defined in the current statement. If .Ar n is not given, the default value of 1 is used. .Pq Currently this works except Ar n is not used .It Sy aligned Op Ar n Set the minimum alignment for the structure or union defined in the current statement. .It Sy rename Ar name Provide an alternative .Ar name which will be used to reference the object declared in the current statement. .It Sy weak Ar name Ns Op = Ns Ar alias Mark .Ar name as a weak rather than a global symbol, to allow its definition to be overridden at link time. If an .Ar alias is given, this will be used as the default value of .Ar name . .It Sy ident Currently not implemented. .El .Lp and the following target-specific operations are handled by machine-dependent code: .Bl -tag -width Ds .It Sy tls For AMD64 and i386 targets, the variable declared in the current statement will be referenced via the .Dq thread-local storage mechanism. .It Sy init For AMD64, ARM, HPPA, i386, MIPS and PowerPC targets, when the current statement is a function declaration, generate a reference in the .Sy .ctors section, enabling library code to call the function prior to entering .Fn main . .It Sy fini For AMD64, ARM, HPPA, i386, MIPS and PowerPC targets, when the current statement is a function declaration, generate a reference in the .Sy .dtors section, enabling library code to call the function when .Fn main returns or the .Fn exit function is called. .It Sy section Ar name For AMD64, ARM, HPPA and i386 targets, place the subsequent code in the named section. .Pq This is currently broken . .It Sy alias Ar name For AMD64, HPPA and i386 targets, emit assembler instructions providing an alias for the symbol defined by the current statement. .It Sy stdcall For i386 targets, enable .Dq stdcall semantics during code generation, where function arguments are passed on the stack in right-to-left order, and the callee is responsible for adjusting the stack pointer before returning. Any function result is passed in the EAX register. On win32, the function name is postfixed with an .Dq @ and the size of the stack adjustment. .It Sy cdecl For i386 targets, enable .Dq cdecl semantics during code generation, where function arguments are passed on the stack in right-to-left order, and the caller is responsible for cleaning up the stack after the function returns. Any function result is passed in the EAX register. This is the default. .It Sy fastcall For i386-win32 targets, enable .Dq fastcall semantics during code generation. .Po Currently this is equivalent to .Sy stdcall , which is likely wrong .Pc . .It Sy dllimport For i386-win32 targets, references to the external symbol defined by the current statement will be made via indirect access through a location identified by the symbol name prefixed with .Dq __imp_ . .It Sy dllexport For i386-win32 targets, the external symbol declared by the current statement will be exported as an indirect reference to be accessed with .Sy dllimport . The global locator will be the symbol name prefixed with .Dq __imp_ . Currently this is not completely implemented. .El .Pp Any unknown .Dq #pragma directives will be ignored unless the .Fl Wunknown-pragmas diagnostic is in effect. .Sh SEE ALSO .Xr as 1 , .Xr cpp 1 , .Xr pcc 1 .Sh HISTORY The .Nm compiler is based on the original Portable C Compiler by .An "S. C. Johnson" , written in the late 70's. Even though much of the compiler has been rewritten .Pq about 50% of the frontend code and 80% of the backend , some of the basics still remain. Most is written by .An "Anders Magnusson" , with the exception of the data-flow analysis part and the SSA conversion code which is written by .An "Peter A Jonsson" , and the Mips port that were written as part of a project by undergraduate students at Lulea University of Technology. .Pp This product includes software developed or owned by Caldera International, Inc. pcc-20181216/cc/ccom/cgram.y010064400017500000000000001576441340102345600142740ustar raggewheel/* $Id: cgram.y,v 1.420 2018/12/02 18:40:46 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code and documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Comments for this grammar file. Ragge 021123 * * ANSI support required rewrite of the function header and declaration * rules almost totally. * * The lex/yacc shared keywords are now split from the keywords used * in the rest of the compiler, to simplify use of other frontends. */ /* * At last count, there were 5 shift/reduce and no reduce/reduce conflicts * All are accounted for; * One is "dangling else" * Two is in attribute parsing * Two is in ({ }) parsing */ /* * Token used in C lex/yacc communications. */ %token C_STRING /* a string constant */ %token C_ICON /* an integer constant */ %token C_FCON /* a floating point constant */ %token C_NAME /* an identifier */ %token C_TYPENAME /* a typedef'd name */ %token C_ANDAND /* && */ %token C_OROR /* || */ %token C_GOTO /* unconditional goto */ %token C_RETURN /* return from function */ %token C_TYPE /* a type */ %token C_CLASS /* a storage class */ %token C_ASOP /* assignment ops */ %token C_RELOP /* <=, <, >=, > */ %token C_EQUOP /* ==, != */ %token C_DIVOP /* /, % */ %token C_SHIFTOP /* <<, >> */ %token C_INCOP /* ++, -- */ %token C_UNOP /* !, ~ */ %token C_STROP /* ., -> */ %token C_STRUCT %token C_IF %token C_ELSE %token C_SWITCH %token C_BREAK %token C_CONTINUE %token C_WHILE %token C_DO %token C_FOR %token C_DEFAULT %token C_CASE %token C_SIZEOF %token C_ENUM %token C_ELLIPSIS %token C_QUALIFIER %token C_FUNSPEC %token C_ASM %token NOMATCH %token C_TYPEOF /* COMPAT_GCC */ %token C_ATTRIBUTE /* COMPAT_GCC */ %token PCC_OFFSETOF %token GCC_DESIG /* C11 keywords */ %token C_STATICASSERT %token C_ALIGNAS %token C_ALIGNOF %token C_GENERIC %token C_ATOMIC /* * Precedence */ %left ',' %right '=' C_ASOP %right '?' ':' %left C_OROR %left C_ANDAND %left '|' %left '^' %left '&' %left C_EQUOP %left C_RELOP %left C_SHIFTOP %left '+' '-' %left '*' C_DIVOP %right C_UNOP %right C_INCOP C_SIZEOF %left '[' '(' C_STROP %{ # include "pass1.h" # include # include # include int fun_inline; /* Reading an inline function */ int oldstyle; /* Current function being defined */ static struct symtab *xnf; extern int enummer, tvaloff, inattr; extern struct rstack *rpole; static int alwinl; P1ND *cftnod; static int attrwarn = 1; #define NORETYP SNOCREAT /* no return type, save in unused field in symtab */ struct genlist { struct genlist *next; P1ND *p; TWORD t; }; P1ND *bdty(int op, ...); static void fend(void); static void fundef(P1ND *tp, P1ND *p); static void olddecl(P1ND *p, P1ND *a); static struct symtab *init_declarator(P1ND *tn, P1ND *p, int assign, P1ND *a, char *as); static void resetbc(int mask); static void swend(void); static void addcase(P1ND *p); #ifdef GCC_COMPAT static void gcccase(P1ND *p, P1ND *); #endif static struct attr *gcc_attr_wrapper(P1ND *p); static void adddef(void); static void savebc(void); static void swstart(int, TWORD); static void genswitch(int, TWORD, struct swents **, int); static char *mkpstr(char *str); static struct symtab *clbrace(P1ND *); static P1ND *cmop(P1ND *l, P1ND *r); static P1ND *xcmop(P1ND *out, P1ND *in, P1ND *str); static void mkxasm(char *str, P1ND *p); static P1ND *xasmop(char *str, P1ND *p); static P1ND *biop(int op, P1ND *l, P1ND *r); static void flend(void); static P1ND *gccexpr(int bn, P1ND *q); static char * simname(char *s); static P1ND *tyof(P1ND *); /* COMPAT_GCC */ static P1ND *voidcon(void); static P1ND *funargs(P1ND *p); static void oldargs(P1ND *p); static void uawarn(P1ND *p, char *s); static int con_e(P1ND *p); static void dainit(P1ND *d, P1ND *a); static P1ND *tymfix(P1ND *p); static P1ND *namekill(P1ND *p, int clr); static P1ND *aryfix(P1ND *p); static P1ND *dogen(struct genlist *g, P1ND *e); static struct genlist *newgen(P1ND *p, P1ND *q); static struct genlist *addgen(struct genlist *g, struct genlist *h); static void savlab(int); static void xcbranch(P1ND *, int); extern int *mkclabs(void); #define TYMFIX(inp) { \ P1ND *pp = inp; \ inp = tymerge(pp->n_left, pp->n_right); \ p1nfree(pp->n_left); p1nfree(pp); } struct xalloc; extern struct xalloc *bkpole, *sapole; extern int cbkp, cstp; extern int usdnodes; struct bks { struct xalloc *ptr; int off; }; /* * State for saving current switch state (when nested switches). */ struct savbc { struct savbc *next; int brklab; int contlab; int flostat; int swx; struct xalloc *bkptr; int bkoff; struct xalloc *stptr; int stoff; int numnode; } *savbc, *savctx; %} %union { TWORD type; int intval; P1ND *nodep; struct symtab *symp; struct rstack *rp; char *strp; struct bks *bkp; struct flt flt; struct genlist *g; } /* define types */ %start ext_def_list %type ifelprefix ifprefix whprefix forprefix doprefix switchpart xbegin %type e .e term enum_dcl struct_dcl cast_type declarator elist type_sq cf_spec merge_attribs e2 ecq parameter_declaration abstract_declarator initializer parameter_type_list parameter_list declaration_specifiers designation specifier_qualifier_list merge_specifiers identifier_list arg_param_list type_qualifier_list designator_list designator xasm oplist oper cnstr funtype typeof attribute attribute_specifier /* COMPAT_GCC */ attribute_list attr_spec_list attr_var /* COMPAT_GCC */ %type gen_ass_list gen_assoc %type string C_STRING GCC_DESIG svstr %type str_head %type xnfdeclarator clbrace enum_head %type C_STRUCT C_RELOP C_DIVOP C_SHIFTOP C_ANDAND C_OROR C_STROP C_INCOP C_UNOP C_ASOP C_EQUOP %type C_TYPE C_QUALIFIER C_CLASS C_FUNSPEC %type C_ICON %type C_FCON %type C_NAME C_TYPENAME %% ext_def_list: ext_def_list external_def | { ftnend(); } ; external_def: funtype kr_args compoundstmt { fend(); } | declaration { blevel = 0; symclear(0); } | asmstatement ';' | ';' | error { blevel = 0; } ; funtype: /* no type given */ declarator { fundef(mkty(INT, 0, 0), $1); cftnsp->sflags |= NORETYP; } | declaration_specifiers declarator { fundef($1,$2); } ; kr_args: /* empty */ | arg_dcl_list ; /* * Returns a node pointer or NULL, if no types at all given. * Type trees are checked for correctness and merged into one * type node in typenode(). */ declaration_specifiers: merge_attribs { $$ = typenode($1); } ; merge_attribs: type_sq { $$ = $1; } | type_sq merge_attribs { $$ = cmop($2, $1); } | cf_spec { $$ = $1; } | cf_spec merge_attribs { $$ = cmop($2, $1); } ; type_sq: C_TYPE { $$ = mkty($1, 0, 0); } | C_TYPENAME { struct symtab *sp = lookup($1, 0); if (sp->stype == ENUMTY) { sp->stype = strmemb(sp->sap)->stype; } $$ = mkty(sp->stype, sp->sdf, sp->sap); $$->n_sp = sp; } | struct_dcl { $$ = $1; } | enum_dcl { $$ = $1; } | C_QUALIFIER { $$ = block(QUALIFIER, NULL, NULL, 0, 0, 0); $$->n_qual = $1; } | attribute_specifier { $$ = biop(ATTRIB, $1, 0); } | C_ALIGNAS '(' e ')' { $$ = biop(ALIGN, NULL, NULL); slval($$, con_e($3)); } | C_ALIGNAS '(' cast_type ')' { TYMFIX($3); $$ = biop(ALIGN, NULL, NULL); slval($$, talign($3->n_type, $3->n_ap)/SZCHAR); p1tfree($3); } | C_ATOMIC { uerror("_Atomic not supported"); $$ = bcon(0); } | C_ATOMIC '(' cast_type ')' { uerror("_Atomic not supported"); $$ = $3; } | typeof { $$ = $1; } ; cf_spec: C_CLASS { $$ = block(CLASS, NULL, NULL, $1, 0, 0); } | C_FUNSPEC { $$ = block(FUNSPEC, NULL, NULL, $1, 0, 0); } ; typeof: C_TYPEOF '(' e ')' { $$ = tyof(eve($3)); } | C_TYPEOF '(' cast_type ')' { TYMFIX($3); $$ = tyof($3); } ; attribute_specifier : C_ATTRIBUTE '(' '(' attribute_list ')' ')' { $$ = $4; } /*COMPAT_GCC*/ ; attribute_list: attribute | attribute ',' attribute_list { $$ = cmop($3, $1); } ; attribute: { #ifdef GCC_COMPAT $$ = voidcon(); #endif } | C_NAME { $$ = bdty(NAME, $1); } | C_NAME '(' elist ')' { $$ = bdty($3 == NULL ? UCALL : CALL, bdty(NAME, $1), $3); } ; /* * Adds a pointer list to front of the declarators. */ declarator: '*' declarator { $$ = bdty(UMUL, $2); } | '*' type_qualifier_list declarator { $$ = $2; $$->n_left = $3; } | C_NAME { $$ = bdty(NAME, $1); } | '(' attr_spec_list declarator ')' { $$ = $3; $$->n_ap = attr_add($$->n_ap, gcc_attr_wrapper($2)); } | '(' declarator ')' { $$ = $2; } | declarator '[' ecq ']' { $$ = biop(LB, $1, $3); } | declarator '(' parameter_type_list ')' { $$ = bdty(CALL, $1, $3); } | declarator '(' identifier_list ')' { $$ = bdty(CALL, $1, $3); oldstyle = 1; } | declarator '(' ')' { $$ = bdty(UCALL, $1); } ; ecq: maybe_r { $$ = bcon(NOOFFSET); } | e { $$ = $1; } | r e { $$ = $2; } | c maybe_r e { $$ = $3; } | r c e { $$ = $3; } | '*' { $$ = bcon(NOOFFSET); } | r '*' { $$ = bcon(NOOFFSET); } ; r: C_QUALIFIER { if ($1 != 0) uerror("bad qualifier"); } ; c: C_CLASS { if ($1 != STATIC) uerror("bad class keyword"); } ; type_qualifier_list: C_QUALIFIER { $$ = biop(UMUL, 0, 0); $$->n_qual = $1; } | type_qualifier_list C_QUALIFIER { $$ = $1; $$->n_qual |= $2; } | attribute_specifier { $$ = block(UMUL, NULL, NULL, 0, 0, gcc_attr_wrapper($1)); } | type_qualifier_list attribute_specifier { $1->n_ap = attr_add($1->n_ap, gcc_attr_wrapper($2)); } ; identifier_list: C_NAME { $$ = bdty(NAME, $1); oldargs($$); } | identifier_list ',' C_NAME { $$ = cmop($1, bdty(NAME, $3)); oldargs($$->n_right); } ; /* * Returns as parameter_list, but can add an additional ELLIPSIS node. */ parameter_type_list: parameter_list { $$ = $1; } | parameter_list ',' C_ELLIPSIS { $$ = cmop($1, biop(ELLIPSIS, NULL, NULL)); } ; /* * Returns a linked lists of nodes of op CM with parameters on * its right and additional CM nodes of its left pointer. * No CM nodes if only one parameter. */ parameter_list: parameter_declaration { $$ = $1; } | parameter_list ',' parameter_declaration { $$ = cmop($1, $3); } ; /* * Returns a node pointer to the declaration. */ parameter_declaration: declaration_specifiers declarator attr_var { if (glval($1) != SNULL && glval($1) != REGISTER) uerror("illegal parameter class"); $$ = block(TYMERGE, $1, $2, INT, 0, gcc_attr_wrapper($3)); } | declaration_specifiers abstract_declarator { $1->n_ap = attr_add($1->n_ap, $2->n_ap); $$ = block(TYMERGE, $1, $2, INT, 0, 0); } | declaration_specifiers { $$ = block(TYMERGE, $1, bdty(NAME, NULL), INT, 0, 0); } ; abstract_declarator: '*' { $$ = bdty(UMUL, bdty(NAME, NULL)); } | '*' type_qualifier_list { $$ = $2; $$->n_left = bdty(NAME, NULL); } | '*' abstract_declarator { $$ = bdty(UMUL, $2); } | '*' type_qualifier_list abstract_declarator { $$ = $2; $$->n_left = $3; } | '(' abstract_declarator ')' { $$ = $2; } | '[' maybe_r ']' attr_var { $$ = block(LB, bdty(NAME, NULL), bcon(NOOFFSET), INT, 0, gcc_attr_wrapper($4)); } | '[' e ']' attr_var { $$ = block(LB, bdty(NAME, NULL), $2, INT, 0, gcc_attr_wrapper($4)); } | abstract_declarator '[' maybe_r ']' attr_var { $$ = block(LB, $1, bcon(NOOFFSET), INT, 0, gcc_attr_wrapper($5)); } | abstract_declarator '[' e ']' attr_var { $$ = block(LB, $1, $3, INT, 0, gcc_attr_wrapper($5)); } | '(' ')' attr_var { $$ = bdty(UCALL, bdty(NAME, NULL)); $$->n_ap = gcc_attr_wrapper($3); } | '(' ib2 parameter_type_list ')' attr_var { $$ = block(CALL, bdty(NAME, NULL), $3, INT, 0, gcc_attr_wrapper($5)); } | abstract_declarator '(' ')' attr_var { $$ = block(UCALL, $1, NULL, INT, 0, gcc_attr_wrapper($4)); } | abstract_declarator '(' ib2 parameter_type_list ')' attr_var { $$ = block(CALL, $1, $4, INT, 0, gcc_attr_wrapper($6)); } ; ib2: { } ; maybe_r: { } | C_QUALIFIER { } ; /* * K&R arg declaration, between ) and { */ arg_dcl_list: arg_declaration | arg_dcl_list arg_declaration ; arg_declaration: declaration_specifiers arg_param_list ';' { p1nfree($1); } ; arg_param_list: declarator attr_var { olddecl(block(TYMERGE, p1tcopy($0), $1, INT, 0, 0), $2); } | arg_param_list ',' declarator attr_var { olddecl(block(TYMERGE, p1tcopy($0), $3, INT, 0, 0), $4); } ; /* * Declarations in beginning of blocks. */ block_item_list: block_item | block_item_list block_item ; block_item: declaration | statement { stmtfree(); } ; /* * Here starts the old YACC code. */ /* * Variables are declared in init_declarator. */ declaration: declaration_specifiers ';' { p1tfree($1); fun_inline = 0; } | declaration_specifiers init_declarator_list ';' { p1tfree($1); fun_inline = 0; } | C_STATICASSERT '(' e ',' string ')' ';' { int r = con_e($3); if (r == 0) /* false */ uerror($5); } ; /* * Normal declaration of variables. curtype contains the current type node. * Returns nothing, variables are declared in init_declarator. */ init_declarator_list: init_declarator { symclear(blevel); } | init_declarator_list ',' attr_var { $$ = $0; } init_declarator { uawarn($3, "init_declarator"); symclear(blevel); } ; enum_dcl: enum_head '{' moe_list optcomma '}' { $$ = enumdcl($1); } | C_ENUM C_NAME { $$ = enumref($2); } ; enum_head: C_ENUM { $$ = enumhd(NULL); } | C_ENUM C_NAME { $$ = enumhd($2); } ; moe_list: moe | moe_list ',' moe ; moe: C_NAME { moedef($1); } | C_TYPENAME { moedef($1); } | C_NAME '=' e { enummer = con_e($3); moedef($1); } | C_TYPENAME '=' e { enummer = con_e($3); moedef($1); } ; struct_dcl: str_head '{' struct_dcl_list '}' { P1ND *p; $$ = dclstruct($1); if (pragma_allpacked) { p = bdty(CALL, bdty(NAME, "packed"), bcon(pragma_allpacked)); $$->n_ap = attr_add($$->n_ap,gcc_attr_wrapper(p)); } } | C_STRUCT attr_var C_NAME { $$ = rstruct($3,$1); uawarn($2, "struct_dcl"); } /*COMPAT_GCC*/ | str_head '{' '}' { $$ = dclstruct($1); } ; attr_var: { P1ND *q, *p; p = pragma_aligned ? bdty(CALL, bdty(NAME, "aligned"), bcon(pragma_aligned)) : NULL; if (pragma_packed) { q = bdty(NAME, "packed"); p = (p == NULL ? q : cmop(p, q)); } pragma_aligned = pragma_packed = 0; $$ = p; } /*COMPAT_GCC*/ | attr_spec_list ; attr_spec_list: attribute_specifier | attr_spec_list attribute_specifier { $$ = cmop($1, $2); } ; str_head: C_STRUCT attr_var { $$ = bstruct(NULL, $1, $2); } | C_STRUCT attr_var C_NAME { $$ = bstruct($3, $1, $2); } ; struct_dcl_list: struct_declaration | struct_dcl_list struct_declaration ; struct_declaration: specifier_qualifier_list struct_declarator_list optsemi { p1tfree($1); } ; optsemi: ';' { } | optsemi ';' { werror("extra ; in struct"); } ; specifier_qualifier_list: merge_specifiers { $$ = typenode($1); } ; merge_specifiers: type_sq merge_specifiers { $$ = cmop($2, $1); } | type_sq { $$ = $1; } ; struct_declarator_list: struct_declarator { symclear(blevel); } | struct_declarator_list ',' { $$=$0; } struct_declarator { symclear(blevel); } ; struct_declarator: declarator attr_var { P1ND *p; $1 = aryfix($1); p = tymerge($0, tymfix($1)); if ($2) p->n_ap = attr_add(p->n_ap, gcc_attr_wrapper($2)); soumemb(p, (char *)$1->n_sp, 0); p1tfree(p); } | ':' e { int ie = con_e($2); if (fldchk(ie)) ie = 1; falloc(NULL, ie, $0); } | declarator ':' e { int ie = con_e($3); if (fldchk(ie)) ie = 1; if ($1->n_op == NAME) { /* XXX - tymfix() may alter $1 */ tymerge($0, tymfix($1)); soumemb($1, (char *)$1->n_sp, FIELD | ie); p1nfree($1); } else uerror("illegal declarator"); } | declarator ':' e attr_spec_list { int ie = con_e($3); if (fldchk(ie)) ie = 1; if ($1->n_op == NAME) { /* XXX - tymfix() may alter $1 */ tymerge($0, tymfix($1)); if ($4) $1->n_ap = attr_add($1->n_ap, gcc_attr_wrapper($4)); soumemb($1, (char *)$1->n_sp, FIELD | ie); p1nfree($1); } else uerror("illegal declarator"); } | /* unnamed member */ { P1ND *p = $0; char *c = permalloc(10); if (p->n_type != STRTY && p->n_type != UNIONTY) uerror("bad unnamed member type"); snprintf(c, 10, "*%dFAKE", getlab()); soumemb(p, c, 0); } ; /* always preceeded by attributes */ xnfdeclarator: declarator attr_var { $$ = xnf = init_declarator($0, $1, 1, $2, 0); } | declarator C_ASM '(' svstr ')' { $$ = xnf = init_declarator($0, $1, 1, NULL, $4); } ; /* * Handles declarations and assignments. * Returns nothing. */ init_declarator: declarator attr_var { init_declarator($0, $1, 0, $2, 0); } | declarator C_ASM '(' svstr ')' attr_var { init_declarator($0, $1, 0, $6, $4); } | xnfdeclarator '=' e { if ($1->sclass == STATIC || $1->sclass == EXTDEF) statinit++; simpleinit($1, eve($3)); if ($1->sclass == STATIC || $1->sclass == EXTDEF) statinit--; xnf = NULL; } | xnfdeclarator '=' begbr init_list optcomma '}' { endinit(0); xnf = NULL; } /*COMPAT_GCC*/ | xnfdeclarator '=' begbr '}' { endinit(0); xnf = NULL; } ; begbr: '{' { beginit($-1); } ; initializer: e %prec ',' { $$ = eve($1); } | ibrace init_list optcomma '}' { $$ = NULL; } | ibrace '}' { asginit(bcon(0)); $$ = NULL; } ; init_list: designation initializer { dainit($1, $2); } | init_list ',' designation initializer { dainit($3, $4); } ; designation: designator_list '=' { desinit($1); $$ = NULL; } | GCC_DESIG { desinit(bdty(NAME, $1)); $$ = NULL; } | '[' e C_ELLIPSIS e ']' '=' { $$ = biop(CM, $2, $4); } | { $$ = NULL; } ; designator_list: designator { $$ = $1; } | designator_list designator { $$ = $2; $$->n_left = $1; } ; designator: '[' e ']' { int ie = con_e($2); if (ie < 0) { uerror("designator must be non-negative"); ie = 0; } $$ = biop(LB, NULL, bcon(ie)); } | C_STROP C_TYPENAME { if ($1 != DOT) uerror("invalid designator"); $$ = bdty(NAME, $2); } | C_STROP C_NAME { if ($1 != DOT) uerror("invalid designator"); $$ = bdty(NAME, $2); } ; optcomma : /* VOID */ | ',' ; ibrace: '{' { ilbrace(); } ; /* STATEMENTS */ compoundstmt: begin block_item_list '}' { flend(); } | begin '}' { flend(); } ; begin: '{' { struct savbc *bc = malloc(sizeof(struct savbc)); if (blevel == 1) { #ifdef STABS if (gflag) stabs_line(lineno); #endif dclargs(); } #ifdef STABS if (gflag && blevel > 1) stabs_lbrac(blevel+1); #endif ++blevel; oldstyle = 0; bc->contlab = autooff; bc->next = savctx; bc->bkptr = bkpole; bc->bkoff = cbkp; bc->stptr = sapole; bc->stoff = cstp; bc->numnode = usdnodes; usdnodes = 0; bkpole = sapole = NULL; cbkp = cstp = 0; savctx = bc; if (!isinlining && sspflag && blevel == 2) sspstart(); } ; statement: e ';' { ecomp(eve($1)); symclear(blevel); } | compoundstmt | ifprefix statement { plabel($1); reached = 1; } | ifelprefix statement { if ($1 != NOLAB) { plabel( $1); reached = 1; } } | whprefix statement { branch(contlab); plabel( brklab ); if( (flostat&FBRK) || !(flostat&FLOOP)) reached = 1; else reached = 0; resetbc(0); } | doprefix statement C_WHILE '(' e ')' ';' { plabel(contlab); if (flostat & FCONT) reached = 1; if (reached) cbranch(buildtree(NE, eve($5), bcon(0)), bcon($1)); else p1tfree(eve($5)); plabel( brklab); reached = 1; resetbc(0); } | forprefix .e ')' statement { plabel( contlab ); if( flostat&FCONT ) reached = 1; if( $2 ) ecomp( $2 ); branch($1); plabel( brklab ); if( (flostat&FBRK) || !(flostat&FLOOP) ) reached = 1; else reached = 0; resetbc(0); blevel--; symclear(blevel); } | switchpart statement { if( reached ) branch( brklab ); plabel( $1 ); swend(); plabel( brklab); if( (flostat&FBRK) || !(flostat&FDEF) ) reached = 1; resetbc(FCONT); } | C_BREAK ';' { if (brklab == NOLAB) uerror("illegal break"); else if (reached) branch(brklab); flostat |= FBRK; reached = 0; } | C_CONTINUE ';' { if (contlab == NOLAB) uerror("illegal continue"); else branch(contlab); flostat |= FCONT; goto rch; } | C_RETURN ';' { branch(retlab); if (cftnsp->stype != VOID && (cftnsp->sflags & NORETYP) == 0 && cftnsp->stype != VOID+FTN) uerror("return value required"); rch: if (!reached) warner(Wunreachable_code); reached = 0; } | C_RETURN e ';' { P1ND *p, *q; p = nametree(cftnsp); p->n_type = DECREF(p->n_type); q = eve($2); #ifdef TARGET_TIMODE { P1ND *r; if ((r = gcc_eval_ticast(RETURN, p, q)) != NULL) q = r; } #endif #ifndef NO_COMPLEX if (ANYCX(q) || ANYCX(p)) q = cxret(q, p); else if (ISITY(p->n_type) || ISITY(q->n_type)) { q = imret(q, p); if (ISITY(p->n_type)) p->n_type -= (FIMAG-FLOAT); if (ISITY(q->n_type)) q->n_type -= (FIMAG-FLOAT); } #endif p = buildtree(RETURN, p, q); if (p->n_type == VOID) { ecomp(p->n_right); } else { if (cftnod == NULL) { P1ND *r = tempnode(0, p->n_type, p->n_df, p->n_ap); cftnod = tmpalloc(sizeof(P1ND)); *cftnod = *r; p1tfree(r); } ecomp(buildtree(ASSIGN, p1tcopy(cftnod), p->n_right)); } p1tfree(p->n_left); p1nfree(p); branch(retlab); reached = 0; } | C_GOTO C_NAME ';' { gotolabel($2); goto rch; } | C_GOTO '*' e ';' { ecomp(biop(GOTO, eve($3), NULL)); } | asmstatement ';' | ';' | error ';' | error '}' | label statement ; asmstatement: C_ASM mvol '(' svstr ')' { send_passt(IP_ASM, mkpstr($4)); } | C_ASM mvol '(' svstr xasm ')' { mkxasm($4, $5); } ; svstr: string { $$ = addstring($1); } ; mvol: /* empty */ | C_QUALIFIER { } ; xasm: ':' oplist { $$ = xcmop($2, NULL, NULL); } | ':' oplist ':' oplist { $$ = xcmop($2, $4, NULL); } | ':' oplist ':' oplist ':' cnstr { $$ = xcmop($2, $4, $6); } ; oplist: /* nothing */ { $$ = NULL; } | oper { $$ = $1; } ; oper: svstr '(' e ')' { $$ = xasmop($1, pconvert(eve($3))); } | oper ',' svstr '(' e ')' { $$ = cmop($1, xasmop($3, pconvert(eve($5)))); } ; cnstr: svstr { $$ = xasmop($1, bcon(0)); } | cnstr ',' svstr { $$ = cmop($1, xasmop($3, bcon(0))); } ; label: C_NAME ':' attr_var { deflabel($1, $3); reached = 1; } | C_TYPENAME ':' attr_var { deflabel($1, $3); reached = 1; } | C_CASE e ':' { addcase(eve($2)); reached = 1; } /* COMPAT_GCC */| C_CASE e C_ELLIPSIS e ':' { #ifdef GCC_COMPAT gcccase(eve($2), eve($4)); reached = 1; #endif } | C_DEFAULT ':' { reached = 1; adddef(); flostat |= FDEF; } ; doprefix: C_DO { savebc(); brklab = getlab(); contlab = getlab(); plabel( $$ = getlab()); reached = 1; } ; ifprefix: C_IF '(' e ')' { xcbranch(eve($3), $$ = getlab()); reached = 1; } ; ifelprefix: ifprefix statement C_ELSE { if (reached) branch($$ = getlab()); else $$ = NOLAB; plabel( $1); reached = 1; } ; whprefix: C_WHILE '(' e ')' { savebc(); $3 = eve($3); if ($3->n_op == ICON && glval($3) != 0) flostat = FLOOP | (flostat & FP_CONTR_CBR); plabel( contlab = getlab()); reached = 1; brklab = getlab(); if (flostat & FLOOP) p1tfree($3); else xcbranch($3, brklab); } ; forprefix: C_FOR '(' .e ';' .e ';' { ++blevel; if ($3) ecomp($3); savebc(); contlab = getlab(); brklab = getlab(); plabel( $$ = getlab()); reached = 1; if ($5) xcbranch($5, brklab); else flostat |= FLOOP; } | C_FOR '(' { ++blevel; } declaration .e ';' { savebc(); contlab = getlab(); brklab = getlab(); plabel( $$ = getlab()); reached = 1; if ($5) xcbranch($5, brklab); else flostat |= FLOOP; } ; switchpart: C_SWITCH '(' e ')' { P1ND *p; int num; TWORD t; savebc(); brklab = getlab(); $3 = eve($3); if (!ISINTEGER($3->n_type)) { uerror("switch expression must have integer " "type"); t = INT; } else { $3 = intprom($3); t = $3->n_type; } p = tempnode(0, t, 0, 0); num = regno(p); ecomp(buildtree(ASSIGN, p, $3)); branch( $$ = getlab()); swstart(num, t); reached = 0; } ; /* EXPRESSIONS */ .e: e { $$ = eve($1); } | { $$=0; } ; elist: { $$ = NULL; } | e2 { $$ = $1; } ; e2: e %prec ',' | e2 ',' e { $$ = biop(CM, $1, $3); } | e2 ',' cast_type { /* hack for stdarg */ TYMFIX($3); $3->n_op = TYPE; $$ = biop(CM, $1, $3); } | cast_type { TYMFIX($1); $1->n_op = TYPE; $$ = $1; } ; /* * Precedence order of operators. */ e: e ',' e { $$ = biop(COMOP, $1, $3); } | e '=' e { $$ = biop(ASSIGN, $1, $3); } | e C_ASOP e { $$ = biop($2, $1, $3); } | e '?' e ':' e { $$=biop(QUEST, $1, biop(COLON, $3, $5)); } /* COMPAT_GCC */| e '?' ':' e { $$ = biop(BIQUEST, $1, $4); } | e C_OROR e { $$ = biop($2, $1, $3); } | e C_ANDAND e { $$ = biop($2, $1, $3); } | e '|' e { $$ = biop(OR, $1, $3); } | e '^' e { $$ = biop(ER, $1, $3); } | e '&' e { $$ = biop(AND, $1, $3); } | e C_EQUOP e { $$ = biop($2, $1, $3); } | e C_RELOP e { $$ = biop($2, $1, $3); } | e C_SHIFTOP e { $$ = biop($2, $1, $3); } | e '+' e { $$ = biop(PLUS, $1, $3); } | e '-' e { $$ = biop(MINUS, $1, $3); } | e C_DIVOP e { $$ = biop($2, $1, $3); } | e '*' e { $$ = biop(MUL, $1, $3); } | term ; xbegin: begin { $$ = getlab(); getlab(); getlab(); branch($$); plabel(($$)+2); } ; term: term C_INCOP { $$ = biop($2, $1, bcon(1)); } | '*' term { $$ = biop(UMUL, $2, NULL); } | '&' term { $$ = biop(ADDROF, $2, NULL); } | '-' term { $$ = biop(UMINUS, $2, NULL ); } | '+' term { $$ = biop(UPLUS, $2, NULL ); } | C_UNOP term { $$ = biop($1, $2, NULL); } | C_INCOP term { $$ = biop($1 == INCR ? PLUSEQ : MINUSEQ, $2, bcon(1)); } | C_SIZEOF xa term { $$ = biop(SZOF, $3, bcon(0)); inattr = $2; } | '(' cast_type ')' term %prec C_INCOP { TYMFIX($2); $$ = biop(CAST, $2, $4); } | C_SIZEOF xa '(' cast_type ')' %prec C_SIZEOF { $$ = biop(SZOF, $4, bcon(1)); inattr = $2; } | C_ALIGNOF xa '(' cast_type ')' { int al; TYMFIX($4); al = talign($4->n_type, $4->n_ap); $$ = bcon(al/SZCHAR); inattr = $2; p1tfree($4); } | '(' cast_type ')' clbrace init_list optcomma '}' { endinit(0); $$ = bdty(NAME, $4); $$->n_op = CLOP; } | '(' cast_type ')' clbrace '}' { endinit(0); $$ = bdty(NAME, $4); $$->n_op = CLOP; } | term '[' e ']' { $$ = biop(LB, $1, $3); } | C_NAME '(' elist ')' { $$ = biop($3 ? CALL : UCALL, bdty(NAME, $1), $3); } | term '(' elist ')' { $$ = biop($3 ? CALL : UCALL, $1, $3); } | term C_STROP C_NAME { $$ = biop($2, $1, bdty(NAME, $3)); } | term C_STROP C_TYPENAME { $$ = biop($2, $1, bdty(NAME, $3));} | C_NAME %prec C_SIZEOF /* below ( */{ $$ = bdty(NAME, $1); } | PCC_OFFSETOF '(' cast_type ',' term ')' { TYMFIX($3); $3->n_type = INCREF($3->n_type); $3 = biop(CAST, $3, bcon(0)); if ($5->n_op == NAME) { $$ = biop(STREF, $3, $5); } else { P1ND *p = $5; while (p->n_left->n_op != NAME) p = p->n_left; p->n_left = biop(STREF, $3, p->n_left); $$ = $5; } $$ = biop(ADDROF, $$, NULL); $3 = block(NAME, NULL, NULL, ENUNSIGN(INTPTR), 0, 0); $$ = biop(CAST, $3, $$); } | C_ICON { $$ = $1; } | C_FCON { $$ = bdty(FCON, &($1)); } | svstr { $$ = bdty(STRING, $1, styp()); } | '(' e ')' { $$=$2; } | '(' xbegin e ';' '}' ')' { $$ = gccexpr($2, eve($3)); } | '(' xbegin block_item_list e ';' '}' ')' { $$ = gccexpr($2, eve($4)); } | '(' xbegin block_item_list '}' ')' { $$ = gccexpr($2, voidcon()); } | C_ANDAND C_NAME { struct symtab *s = lookup($2, SLBLNAME|STEMP); if (s->soffset == 0) { s->soffset = -getlab(); s->sclass = STATIC; } savlab(s->soffset); $$ = biop(ADDROF, bdty(GOTO, $2), NULL); } | C_GENERIC '(' e ',' gen_ass_list ')' { $$ = dogen($5, $3); } ; gen_ass_list: gen_assoc { $$ = $1; } | gen_ass_list ',' gen_assoc { $$ = addgen($1, $3); } ; gen_assoc: cast_type ':' e { TYMFIX($1); $$ = newgen($1, $3); } | C_DEFAULT ':' e { $$ = newgen(0, $3); } ; xa: { $$ = inattr; inattr = 0; } ; clbrace: '{' { P1ND *q = $-1; TYMFIX(q); $$ = clbrace(q); } ; string: C_STRING { $$ = stradd(NULL, $1); } | string C_STRING { $$ = stradd($1, $2); } ; cast_type: specifier_qualifier_list { $$ = biop(TYMERGE, $1, bdty(NAME, NULL)); } | specifier_qualifier_list abstract_declarator { $$ = biop(TYMERGE, $1, aryfix($2)); } ; %% P1ND * mkty(TWORD t, union dimfun *d, struct attr *sue) { return block(TYPE, NULL, NULL, t, d, sue); } P1ND * bdty(int op, ...) { FLT *f2; CONSZ c; va_list ap; int val; register P1ND *q; va_start(ap, op); q = biop(op, NULL, NULL); switch (op) { case UMUL: case UCALL: q->n_left = va_arg(ap, P1ND *); q->n_rval = 0; break; case FCON: f2 = va_arg(ap, FLT *); q->n_scon = sfallo(); *q->n_scon = f2->sf; q->n_type = f2->t; break; case CALL: q->n_left = va_arg(ap, P1ND *); q->n_right = va_arg(ap, P1ND *); break; case LB: q->n_left = va_arg(ap, P1ND *); if ((val = va_arg(ap, int)) <= 0) { uerror("array size must be positive"); val = 1; } q->n_right = bcon(val); break; case GOTO: /* for named labels */ q->n_ap = attr_add(q->n_ap, attr_new(ATTR_P1LABELS, 1)); /* FALLTHROUGH */ case NAME: q->n_op = NAME; q->n_sp = va_arg(ap, struct symtab *); /* XXX survive tymerge */ break; case STRING: q->n_type = PTR|CHAR; q->n_name = va_arg(ap, char *); c = va_arg(ap, TWORD); slval(q, c); break; default: cerror("bad bdty"); } va_end(ap); return q; } static void flend(void) { struct savbc *sc; if (!isinlining && sspflag && blevel == 2) sspend(); #ifdef STABS if (gflag && blevel > 2) stabs_rbrac(blevel); #endif --blevel; if( blevel == 1 ) blevel = 0; symclear(blevel); /* Clean ut the symbol table */ if (autooff > maxautooff) maxautooff = autooff; autooff = savctx->contlab; blkfree(); stmtfree(); bkpole = savctx->bkptr; cbkp = savctx->bkoff; sapole = savctx->stptr; cstp = savctx->stoff; usdnodes = savctx->numnode; sc = savctx->next; free(savctx); savctx = sc; } /* * XXX workaround routines for block level cleansing in gcc compat mode. * Temporary should be re reserved for this value before. */ static P1ND * p1mcopy(P1ND *p) { P1ND *q; q = xmalloc(sizeof(P1ND)); *q = *p; switch (coptype(q->n_op)) { case BITYPE: q->n_right = p1mcopy(p->n_right); /* FALLTHROUGH */ case UTYPE: q->n_left = p1mcopy(p->n_left); } return(q); } static void p1mfree(P1ND *p) { int o = coptype(p->n_op); if (o == BITYPE) p1mfree(p->n_right); if (o != LTYPE) p1mfree(p->n_left); free(p); } static P1ND * gccexpr(int bn, P1ND *q) { P1ND *r, *p, *s; branch(bn+4); plabel(bn); r = buildtree(COMOP, biop(GOTO, bcon(bn+2), NULL), q); /* XXX hack to survive flend() */ s = p1mcopy(r); p1tfree(r); flend(); r = p1tcopy(s); p1mfree(s); q = r->n_right; /* XXX end hack */ if (!(q->n_op == ICON && q->n_type == STRTY) && (r->n_type != VOID)) { p = tempnode(0, q->n_type, q->n_df, q->n_ap); r = buildtree(ASSIGN, p1tcopy(p), r); r = buildtree(COMOP, r, p); } return r; } static void savebc(void) { struct savbc *bc = malloc(sizeof(struct savbc)); bc->brklab = brklab; bc->contlab = contlab; bc->flostat = flostat; bc->next = savbc; savbc = bc; flostat &= FP_CONTR_CBR; } static void resetbc(int mask) { struct savbc *bc; flostat = savbc->flostat | (flostat&mask); contlab = savbc->contlab; brklab = savbc->brklab; bc = savbc->next; free(savbc); savbc = bc; } struct swdef { struct swdef *next; /* Next in list */ int deflbl; /* Label for "default" */ struct swents *ents; /* Linked sorted list of case entries */ int nents; /* # of entries in list */ int num; /* Node value will end up in */ TWORD type; /* Type of switch expression */ } *swpole; /* * add case to switch */ static void addcase(P1ND *p) { struct swents **put, *w, *sw = malloc(sizeof(struct swents)); CONSZ val; p = optloop(p); /* change enum to ints */ if (p->n_op != ICON || p->n_sp != NULL) { uerror( "non-constant case expression"); return; } if (swpole == NULL) { uerror("case not in switch"); return; } if (DEUNSIGN(swpole->type) != DEUNSIGN(p->n_type)) { val = glval(p); p = makety(p, swpole->type, 0, 0, 0); if (p->n_op != ICON) cerror("could not cast case value to type of switch " "expression"); if (glval(p) != val) werror("case expression truncated"); } sw->sval = glval(p); p1tfree(p); put = &swpole->ents; if (ISUNSIGNED(swpole->type)) { for (w = swpole->ents; w != NULL && (U_CONSZ)w->sval < (U_CONSZ)sw->sval; w = w->next) put = &w->next; } else { for (w = swpole->ents; w != NULL && w->sval < sw->sval; w = w->next) put = &w->next; } if (w != NULL && w->sval == sw->sval) { uerror("duplicate case in switch"); return; } plabel(sw->slab = getlab()); *put = sw; sw->next = w; swpole->nents++; } #ifdef GCC_COMPAT void gcccase(P1ND *ln, P1ND *hn) { CONSZ i, l, h; l = icons(optim(ln)); h = icons(optim(hn)); if (h < l) i = l, l = h, h = i; for (i = l; i <= h; i++) addcase(xbcon(i, NULL, hn->n_type)); } #endif /* * add default case to switch */ static void adddef(void) { if (swpole == NULL) uerror("default not inside switch"); else if (swpole->deflbl != 0) uerror("duplicate default in switch"); else plabel( swpole->deflbl = getlab()); } static void swstart(int num, TWORD type) { struct swdef *sw = malloc(sizeof(struct swdef)); sw->deflbl = sw->nents = 0; sw->ents = NULL; sw->next = swpole; sw->num = num; sw->type = type; swpole = sw; } /* * end a switch block */ static void swend(void) { struct swents *sw, **swp; struct swdef *sp; int i; sw = FUNALLO(sizeof(struct swents)); swp = FUNALLO(sizeof(struct swents *) * (swpole->nents+1)); sw->slab = swpole->deflbl; swp[0] = sw; for (i = 1; i <= swpole->nents; i++) { swp[i] = swpole->ents; swpole->ents = swpole->ents->next; } genswitch(swpole->num, swpole->type, swp, swpole->nents); FUNFREE(sw); FUNFREE(swp); while (swpole->ents) { sw = swpole->ents; swpole->ents = sw->next; free(sw); } sp = swpole->next; free(swpole); swpole = sp; } /* * num: tempnode the value of the switch expression is in * type: type of the switch expression * * p points to an array of structures, each consisting * of a constant value and a label. * The first is >=0 if there is a default label; * its value is the label number * The entries p[1] to p[n] are the nontrivial cases * n is the number of case statements (length of list) */ static void genswitch(int num, TWORD type, struct swents **p, int n) { P1ND *r, *q; int i; if (mygenswitch(num, type, p, n)) return; /* simple switch code */ for (i = 1; i <= n; ++i) { /* already in 1 */ r = tempnode(num, type, 0, 0); q = xbcon(p[i]->sval, NULL, type); r = buildtree(NE, r, clocal(q)); xcbranch(r, p[i]->slab); } if (p[0]->slab > 0) branch(p[0]->slab); } /* * Declare a variable or prototype. */ static struct symtab * init_declarator(P1ND *tn, P1ND *p, int assign, P1ND *a, char *as) { int class = (int)glval(tn); struct symtab *sp; p = aryfix(p); p = tymerge(tn, p); if (a) { struct attr *ap = gcc_attr_wrapper(a); p->n_ap = attr_add(p->n_ap, ap); } p->n_sp = sp = lookup((char *)p->n_sp, 0); /* XXX */ if (fun_inline && ISFTN(p->n_type)) sp->sflags |= SINLINE; if (!ISFTN(p->n_type)) { if (assign) { defid2(p, class, as); sp = p->n_sp; sp->sflags |= SASG; if (sp->sflags & SDYNARRAY) uerror("can't initialize dynamic arrays"); lcommdel(sp); } else nidcl2(p, class, as); } else { extern P1ND *parlink; if (assign) uerror("cannot initialise function"); defid2(p, uclass(class), as); sp = p->n_sp; if (sp->sdf->dfun == 0 && !issyshdr) warner(Wstrict_prototypes); if (parlink) { /* dynamic sized arrays in prototypes */ p1tfree(parlink); /* Free delayed tree */ parlink = NULL; } } p1tfree(p); if (issyshdr) sp->sflags |= SINSYS; /* declared in system header */ return sp; } /* * Declare old-stype function arguments. */ static void oldargs(P1ND *p) { blevel++; p->n_op = TYPE; p->n_type = FARG; p->n_sp = lookup((char *)p->n_sp, 0);/* XXX */ defid(p, PARAM); blevel--; } /* * Set NAME nodes to a null name and index of LB nodes to NOOFFSET * unless clr is one, in that case preserve variable name. */ static P1ND * namekill(P1ND *p, int clr) { P1ND *q; int o = p->n_op; switch (coptype(o)) { case LTYPE: if (o == NAME) { if (clr) p->n_sp = NULL; else p->n_sp = lookup((char *)p->n_sp, 0);/* XXX */ } break; case UTYPE: p->n_left = namekill(p->n_left, clr); break; case BITYPE: p->n_left = namekill(p->n_left, clr); if (o == LB) { if (clr) { p1tfree(p->n_right); p->n_right = bcon(NOOFFSET); } else p->n_right = eve(p->n_right); } else if (o == CALL) p->n_right = namekill(p->n_right, 1); else p->n_right = namekill(p->n_right, clr); if (o == TYMERGE) { q = tymerge(p->n_left, p->n_right); q->n_ap = attr_add(q->n_ap, p->n_ap); p1tfree(p->n_left); p1nfree(p); p = q; } break; } return p; } /* * Declare function arguments. */ static P1ND * funargs(P1ND *p) { extern P1ND *arrstk[10]; if (p->n_op == ELLIPSIS) return p; p = namekill(p, 0); if (ISFTN(p->n_type)) p->n_type = INCREF(p->n_type); if (ISARY(p->n_type)) { p->n_type += (PTR-ARY); if (p->n_df->ddim == -1) p1tfree(arrstk[0]), arrstk[0] = NULL; p->n_df++; } if (p->n_type == VOID && p->n_sp->sname == NULL) return p; /* sanitycheck later */ else if (p->n_sp->sname == NULL) uerror("argument missing"); else defid(p, PARAM); return p; } static P1ND * listfw(P1ND *p, P1ND * (*f)(P1ND *)) { if (p->n_op == CM) { p->n_left = listfw(p->n_left, f); p->n_right = (*f)(p->n_right); } else p = (*f)(p); return p; } /* * Declare a function. */ static void fundef(P1ND *tp, P1ND *p) { extern int prolab; struct symtab *s; P1ND *q, *typ; int class = (int)glval(tp), oclass, ctval; /* * We discard all names except for those needed for * parameter declaration. While doing that, also change * non-constant array sizes to unknown. */ ctval = tvaloff; for (q = p; coptype(q->n_op) != LTYPE && q->n_left->n_op != NAME; q = q->n_left) { if (q->n_op == CALL) q->n_right = namekill(q->n_right, 1); } if (q->n_op != CALL && q->n_op != UCALL) { uerror("invalid function definition"); p = bdty(UCALL, p); } else if (q->n_op == CALL) { blevel = 1; argoff = ARGINIT; if (oldstyle == 0) q->n_right = listfw(q->n_right, funargs); ftnarg(q); blevel = 0; } p = typ = tymerge(tp, p); #ifdef GCC_COMPAT /* gcc seems to discard __builtin_ when declaring functions */ if (strncmp("__builtin_", (char *)typ->n_sp, 10) == 0) typ->n_sp = (struct symtab *)((char *)typ->n_sp + 10); #endif s = typ->n_sp = lookup((char *)typ->n_sp, 0); /* XXX */ oclass = s->sclass; if (class == STATIC && oclass == EXTERN) werror("%s was first declared extern, then static", s->sname); if (fun_inline) { /* special syntax for inline functions */ if (! strcmp(s->sname,"main")) uerror("cannot inline main()"); s->sflags |= SINLINE; inline_start(s, class); if (class == EXTERN) class = EXTDEF; } else if (class == EXTERN) class = SNULL; /* same result */ cftnsp = s; defid(p, class); if (s->sdf->dfun == 0 && !issyshdr) warner(Wstrict_prototypes); #ifdef GCC_COMPAT if (attr_find(p->n_ap, GCC_ATYP_ALW_INL)) { /* Temporary turn on temps to make always_inline work */ alwinl = 1; if (xtemps == 0) alwinl |= 2; xtemps = 1; } #endif prolab = getlab(); send_passt(IP_PROLOG, -1, getexname(cftnsp), cftnsp->stype, cftnsp->sclass == EXTDEF, prolab, ctval); blevel++; #ifdef STABS if (gflag) stabs_func(s); #endif p1tfree(tp); p1tfree(p); } static void fend(void) { if (blevel) cerror("function level error"); ftnend(); fun_inline = 0; if (alwinl & 2) xtemps = 0; alwinl = 0; cftnsp = NULL; } P1ND * structref(P1ND *p, int f, char *name) { P1ND *r; if (f == DOT) p = buildtree(ADDROF, p, NULL); r = biop(NAME, NULL, NULL); r->n_name = name; r = buildtree(STREF, p, r); return r; } static void olddecl(P1ND *p, P1ND *a) { struct symtab *s; p = namekill(p, 0); s = p->n_sp; if (s->slevel != 1 || s->stype == UNDEF) uerror("parameter '%s' not defined", s->sname); else if (s->stype != FARG) uerror("parameter '%s' redefined", s->sname); s->stype = p->n_type; s->sdf = p->n_df; s->sap = p->n_ap; if (ISARY(s->stype)) { s->stype += (PTR-ARY); s->sdf++; } else if (s->stype == FLOAT) s->stype = DOUBLE; if (a) attr_add(s->sap, gcc_attr_wrapper(a)); p1nfree(p); } void branch(int lbl) { int r = reached++; ecomp(biop(GOTO, bcon(lbl), NULL)); reached = r; } /* * Create a printable string based on an encoded string. */ static char * mkpstr(char *str) { char *os, *s; size_t l = strlen(str) + 3; /* \t + \n + \0 */ os = s = stmtalloc(l); *s++ = '\t'; while (*str) { if (*str == '\\') *s++ = esccon(&str); else *s++ = *str++; } *s++ = '\n'; *s = 0; return os; } /* * Fake a symtab entry for compound literals. */ static struct symtab * clbrace(P1ND *p) { struct symtab *sp; sp = getsymtab(simname("cl"), STEMP); sp->stype = p->n_type; sp->squal = p->n_qual; sp->sdf = p->n_df; sp->sap = p->n_ap; p1tfree(p); if (blevel == 0 && xnf != NULL) { sp->sclass = STATIC; sp->slevel = 2; sp->soffset = getlab(); } else { sp->sclass = blevel ? AUTO : STATIC; if (!ISARY(sp->stype) || sp->sdf->ddim != NOOFFSET) { sp->soffset = NOOFFSET; oalloc(sp, &autooff); } } beginit(sp); return sp; } char * simname(char *s) { size_t len = strlen(s) + 10 + 1; char *w = tmpalloc(len); /* uncommon */ snprintf(w, len, "%s%d", s, getlab()); return w; } P1ND * biop(int op, P1ND *l, P1ND *r) { return block(op, l, r, INT, 0, 0); } static P1ND * cmop(P1ND *l, P1ND *r) { return biop(CM, l, r); } static P1ND * voidcon(void) { return block(ICON, NULL, NULL, STRTY, 0, 0); } /* Support for extended assembler a' la' gcc style follows below */ static P1ND * xmrg(P1ND *out, P1ND *in) { P1ND *p = in; if (p->n_op == XARG) { in = cmop(out, p); } else { while (p->n_left->n_op == CM) p = p->n_left; p->n_left = cmop(out, p->n_left); } return in; } /* * Put together in and out node lists in one list, and balance it with * the constraints on the right side of a CM node. */ static P1ND * xcmop(P1ND *out, P1ND *in, P1ND *str) { P1ND *p, *q; if (out) { /* D out-list sanity check */ for (p = out; p->n_op == CM; p = p->n_left) { q = p->n_right; if (q->n_name[0] != '=' && q->n_name[0] != '+') uerror("output missing ="); } if (p->n_name[0] != '=' && p->n_name[0] != '+') uerror("output missing ="); if (in == NULL) p = out; else p = xmrg(out, in); } else if (in) { p = in; } else p = voidcon(); if (str == NULL) str = voidcon(); return cmop(p, str); } /* * Generate a XARG node based on a string and an expression. */ static P1ND * xasmop(char *str, P1ND *p) { p = biop(XARG, p, NULL); p->n_name = str; return p; } /* * Generate a XASM node based on a string and an expression. */ static void mkxasm(char *str, P1ND *p) { P1ND *q; q = biop(XASM, p->n_left, p->n_right); q->n_name = str; p1nfree(p); ecomp(optloop(q)); } static struct attr * gcc_attr_wrapper(P1ND *p) { #ifdef GCC_COMPAT return gcc_attr_parse(p); #else if (p != NULL) uerror("gcc attribute used"); return NULL; #endif } #ifdef GCC_COMPAT static P1ND * tyof(P1ND *p) { static struct symtab spp; P1ND *q = block(TYPE, NULL, NULL, p->n_type, p->n_df, p->n_ap); q->n_qual = p->n_qual; q->n_sp = &spp; /* for typenode */ p1walkf(p, putjops, 0); p1tfree(p); return q; } #else static P1ND * tyof(P1ND *p) { uerror("typeof gcc extension"); return bcon(0); } #endif /* * Traverse an unhandled expression tree bottom-up and call buildtree() * or equivalent as needed. */ P1ND * eve(P1ND *p) { struct symtab *sp; P1ND *r, *p1, *p2; int x; p1 = p->n_left; p2 = p->n_right; switch (p->n_op) { case NAME: sp = lookup((char *)p->n_sp, attr_find(p->n_ap, ATTR_P1LABELS) ? SLBLNAME|STEMP : 0); if (sp->sflags & SINLINE) inline_ref(sp); r = nametree(sp); if (sp->sflags & SDYNARRAY) r = buildtree(UMUL, r, NULL); #ifdef GCC_COMPAT if (attr_find(sp->sap, GCC_ATYP_DEPRECATED)) warner(Wdeprecated_declarations, sp->sname); #endif break; case DOT: case STREF: r = structref(eve(p1), p->n_op, (char *)p2->n_sp); p1nfree(p2); break; case CAST: p2 = eve(p2); #ifndef NO_COMPLEX if (ANYCX(p1) || ANYCX(p2)) { r = cxcast(p1, p2); break; } #endif #ifdef TARGET_TIMODE if ((r = gcc_eval_ticast(CAST, p1, p2)) != NULL) break; #endif p1 = buildtree(CAST, p1, p2); p1nfree(p1->n_left); r = p1->n_right; p1nfree(p1); break; case SZOF: x = xinline; xinline = 0; /* XXX hack */ if (glval(p2) == 0) p1 = eve(p1); else TYMFIX(p1); p1nfree(p2); r = doszof(p1); xinline = x; break; case LB: p1 = eve(p1); p2 = eve(p2); #ifdef TARGET_TIMODE if (isti(p2)) { P1ND *s = block(NAME, NULL, NULL, LONG, 0, 0); if ((r = gcc_eval_ticast(CAST, s, p2)) != NULL) p2 = r; p1nfree(s); } #endif r = buildtree(UMUL, buildtree(PLUS, p1, p2), NULL); break; case COMPL: #ifndef NO_COMPLEX p1 = eve(p1); if (ANYCX(p1)) r = cxconj(p1); else r = buildtree(COMPL, p1, NULL); break; #endif case UPLUS: r = eve(p1); if (r->n_op == FLD || r->n_type < INT) r = buildtree(PLUS, r, bcon(0)); /* must be size int */ break; case UMINUS: #ifndef NO_COMPLEX p1 = eve(p1); if (ANYCX(p1)) r = cxop(UMINUS, p1, p1); else r = buildtree(UMINUS, p1, NULL); break; #endif case NOT: case UMUL: p1 = eve(p1); #ifdef TARGET_TIMODE if ((r = gcc_eval_tiuni(p->n_op, p1)) != NULL) break; #endif #ifndef NO_COMPLEX if (p->n_op == NOT && ANYCX(p1)) p1 = cxop(NE, p1, bcon(0)); #endif r = buildtree(p->n_op, p1, NULL); break; case ADDROF: r = eve(p1); if (ISFTN(p->n_type)/* || ISARY(p->n_type) */){ #ifdef notdef werror( "& before array or function: ignored" ); #endif } else r = buildtree(ADDROF, r, NULL); break; case UCALL: p2 = NULL; /* FALLTHROUGH */ case CALL: if (p1->n_op == NAME) { sp = lookup((char *)p1->n_sp, 0); #ifndef NO_C_BUILTINS if (sp->sflags & SBUILTIN) { p1nfree(p1); r = builtin_check(sp, p2); break; } #endif if (sp->stype == UNDEF) { p1->n_type = FTN|INT; p1->n_sp = sp; p1->n_ap = NULL; defid(p1, EXTERN); } p1nfree(p1); #ifdef GCC_COMPAT if (attr_find(sp->sap, GCC_ATYP_DEPRECATED)) warner(Wdeprecated_declarations, sp->sname); #endif if (p->n_op == CALL) p2 = eve(p2); r = doacall(sp, nametree(sp), p2); } else { if (p->n_op == CALL) p2 = eve(p2); r = doacall(NULL, eve(p1), p2); } break; #ifndef NO_COMPLEX case XREAL: case XIMAG: p1 = eve(p1); r = cxelem(p->n_op, p1); break; #endif case COLON: case MUL: case DIV: case PLUS: case MINUS: case ASSIGN: case EQ: case NE: case OROR: case ANDAND: #ifndef NO_COMPLEX p1 = eve(p1); p2 = eve(p2); #ifdef TARGET_TIMODE if ((r = gcc_eval_timode(p->n_op, p1, p2)) != NULL) break; #endif if (ANYCX(p1) || ANYCX(p2)) { r = cxop(p->n_op, p1, p2); } else if (ISITY(p1->n_type) || ISITY(p2->n_type)) { r = imop(p->n_op, p1, p2); } else r = buildtree(p->n_op, p1, p2); break; #endif case MOD: case CM: case GT: case GE: case LT: case LE: case RS: case LS: case RSEQ: case LSEQ: case AND: case OR: case ER: case EREQ: case OREQ: case ANDEQ: case QUEST: p1 = eve(p1); p2 = eve(p2); #ifdef TARGET_TIMODE if ((r = gcc_eval_timode(p->n_op, p1, p2)) != NULL) break; #endif r = buildtree(p->n_op, p1, p2); break; case BIQUEST: /* gcc e ?: e op */ p1 = eve(p1); r = tempnode(0, p1->n_type, p1->n_df, p1->n_ap); p2 = eve(biop(COLON, p1tcopy(r), p2)); r = buildtree(QUEST, buildtree(ASSIGN, r, p1), p2); break; case INCR: case DECR: case MODEQ: case MINUSEQ: case PLUSEQ: case MULEQ: case DIVEQ: p1 = eve(p1); p2 = eve(p2); #ifdef TARGET_TIMODE if ((r = gcc_eval_timode(p->n_op, p1, p2)) != NULL) break; #endif #ifndef NO_COMPLEX if (ANYCX(p1) || ANYCX(p2)) { r = cxop(UNASG p->n_op, p1tcopy(p1), p2); r = cxop(ASSIGN, p1, r); break; } else if (ISITY(p1->n_type) || ISITY(p2->n_type)) { r = imop(UNASG p->n_op, p1tcopy(p1), p2); r = cxop(ASSIGN, p1, r); break; } /* FALLTHROUGH */ #endif r = buildtree(p->n_op, p1, p2); break; case STRING: r = strend(p->n_name, (TWORD)glval(p)); break; case COMOP: if (p1->n_op == GOTO) { /* inside ({ }), eve already called */ r = buildtree(p->n_op, p1, p2); } else { p1 = eve(p1); r = buildtree(p->n_op, p1, eve(p2)); } break; case TYPE: case ICON: case FCON: case TEMP: return p; case CLOP: r = nametree(p->n_sp); break; default: #ifdef PCC_DEBUG p1fwalk(p, eprint, 0); #endif cerror("eve"); r = NULL; } p1nfree(p); return r; } int con_e(P1ND *p) { return (int)icons(optloop(eve(p))); } void uawarn(P1ND *p, char *s) { if (p == 0) return; if (attrwarn) werror("unhandled %s attribute", s); p1tfree(p); } static void dainit(P1ND *d, P1ND *a) { if (d == NULL) { asginit(a); } else if (d->n_op == CM) { int is = con_e(d->n_left); int ie = con_e(d->n_right); int i; p1nfree(d); if (ie < is) uerror("negative initializer range"); desinit(biop(LB, NULL, bcon(is))); for (i = is; i < ie; i++) asginit(p1tcopy(a)); asginit(a); } else { cerror("dainit"); } } /* * Traverse down and tymerge() where appropriate. */ static P1ND * tymfix(P1ND *p) { P1ND *q; int o = coptype(p->n_op); switch (o) { case LTYPE: break; case UTYPE: p->n_left = tymfix(p->n_left); break; case BITYPE: p->n_left = tymfix(p->n_left); p->n_right = tymfix(p->n_right); if (p->n_op == TYMERGE) { q = tymerge(p->n_left, p->n_right); q->n_ap = attr_add(q->n_ap, p->n_ap); p1tfree(p->n_left); p1nfree(p); p = q; } break; } return p; } static P1ND * aryfix(P1ND *p) { P1ND *q; for (q = p; q->n_op != NAME; q = q->n_left) { if (q->n_op == LB) { q->n_right = optloop(eve(q->n_right)); if ((blevel == 0 || rpole != NULL) && !nncon(q->n_right)) uerror("array size not constant"); /* * Checks according to 6.7.5.2 clause 1: * "...the expression shall have an integer type." * "If the expression is a constant expression, * it shall have a value greater than zero." */ if (!ISINTEGER(q->n_right->n_type)) werror("array size is not an integer"); else if (q->n_right->n_op == ICON && glval(q->n_right) < 0 && glval(q->n_right) != NOOFFSET) { uerror("array size cannot be negative"); slval(q->n_right, 1); } } else if (q->n_op == CALL) q->n_right = namekill(q->n_right, 1); } return p; } struct labs { struct labs *next; int lab; } *labp; static void savlab(int lab) { struct labs *l = tmpalloc(sizeof(struct labs)); /* uncommon */ l->lab = lab < 0 ? -lab : lab; l->next = labp; labp = l; } int * mkclabs(void) { struct labs *l; int i, *rv; for (i = 0, l = labp; l; l = l->next, i++) ; rv = tmpalloc((i+1)*sizeof(int)); /* uncommon */ for (i = 0, l = labp; l; l = l->next, i++) rv[i] = l->lab; rv[i] = 0; labp = 0; return rv; } void xcbranch(P1ND *p, int lab) { #ifndef NO_COMPLEX if (ANYCX(p)) p = cxop(NE, p, bcon(0)); #endif cbranch(buildtree(NOT, p, NULL), bcon(lab)); } /* * New a case entry to genlist. * tn is type, e is expression. */ static struct genlist * newgen(P1ND *tn, P1ND *e) { struct genlist *ng; TWORD t; if (tn) { t = tn->n_type; p1tfree(tn); } else t = 0; /* add new entry */ ng = malloc(sizeof(struct genlist)); ng->next = NULL; ng->t = t; ng->p = e; return ng; } /* * Add a case entry to genlist. * g is list, ng is new entry. */ static struct genlist * addgen(struct genlist *g, struct genlist *ng) { struct genlist *w; /* search for duplicate type */ for (w = g; w; w = w->next) { if (w->t == ng->t) uerror("duplicate type in _Generic"); } ng->next = g; return ng; } static P1ND * dogen(struct genlist *g, P1ND *e) { struct genlist *ng; P1ND *w, *p; e = eve(e); /* search for direct match */ for (ng = g, w = p = NULL; ng; ng = ng->next) { if (ng->t == 0) p = ng->p; /* save default */ if (e->n_type == ng->t) w = ng->p; } /* if no match, use generic */ if (w == NULL) { if (p == NULL) { uerror("_Generic: no default found"); p = bcon(0); } w = p; } /* free tree */ while (g) { if (g->p != w) p1tfree(g->p); ng = g->next; free(g); g = ng; } p1tfree(e); return w; } pcc-20181216/cc/ccom/dwarf.c010064400017500000000000000123751266761351100142610ustar raggewheel/* $Id: dwarf.c,v 1.2 2016/03/08 18:17:45 ragge Exp $ */ /* * Copyright (c) 2016 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Expect just ELF for now. */ #include "pass1.h" #ifdef DWARF #include #include #include "dwarf.h" /* * Basic DWARF definitions, from specification. */ #define DVERSION 3 /* dwarf version */ #define DLABEL ".LD%d" #define DW64 (SZPOINT(VOID)/SZCHAR == 8) static int dwseg = -1; enum { DINFO, DABBREV, DSTR }; static char *segn[] = { ".debug_info", ".debug_abbrev", ".debug_str" }; static int debug_info_sz, debug_info_sz_lbl; static int debug_abbrev_beg_lbl; static int dwcfl, dwbtext, dwetext; static char *dwname; static int dwlab(void) { static int dwlbl; return dwlbl++; } static void dwarfseg(int seg) { if (seg == dwseg) return; /* XXX target code? */ printf("\t.section\t%s,\"\",@progbits\n", segn[seg]); lastloc = NOSEG; dwseg = seg; } static void dwslab(int seg, int lbl) { dwarfseg(seg); printf(PRTPREF DLABEL ":\n", lbl); } static void p1b(int v) { printf(PRTPREF "%s 0x%x\n", astypnames[CHAR], v); } static void p2w(int v) { printf(PRTPREF "%s 0x%x\n", astypnames[SHORT], v); } static int leb128(int d) { if (d > 127) cerror("FIXME: leb128 > 127"); p1b(d); return 1; } static void al128(int d) { dwarfseg(DABBREV); leb128(d); } static void apair(int d, int e) { dwarfseg(DABBREV); leb128(d); leb128(e); } static void strng(char *s) { printf(PRTPREF "\t.ascii \"%s\\0\"\n", s); /* XXX common code? */ } static void istring(char *str) { dwarfseg(DINFO); strng(str); debug_info_sz += (strlen(str) + 1); } static void dwslabstr(int lbl, char *s) { dwslab(DSTR, lbl); strng(s); } static void ilbl(int l) { dwarfseg(DINFO); printf(PRTPREF "%s " DLABEL "\n", astypnames[LONG], l); debug_info_sz += (DW64 * 4 + 4); } static void il128(int d) { dwarfseg(DINFO); debug_info_sz += leb128(d); } static void p412l(int lbl) { if (DW64) printf(PRTPREF "%s 0xffffff00\n", astypnames[INT]); printf(PRTPREF "%s " DLABEL "\n", astypnames[LONG], lbl); } static void info1b(int v) { dwarfseg(DINFO); p1b(v); debug_info_sz++; } static void info2w(int v) { dwarfseg(DINFO); p2w(v); debug_info_sz += 2; } static void info412l(int lbl) { dwarfseg(DINFO); p412l(lbl); debug_info_sz += (DW64 * 8 + 4); } void dwarf_init(char *iname) { char buf[MAXPATHLEN]; /* * Setup sections. * We'll print out the basic stuff early so that not * so much context must be kept around. */ dwname = iname; debug_info_sz_lbl = dwlab(); debug_abbrev_beg_lbl = dwlab(); /* begin with setting up the compilation unit header */ info412l(debug_info_sz_lbl); debug_info_sz = 0; info2w(DVERSION); info412l(debug_abbrev_beg_lbl); info1b(SZPOINT(VOID)/SZCHAR); /* Define abbrev table */ dwslab(DABBREV, debug_abbrev_beg_lbl); /* compile unit follows, both in abbrev and info table */ /* Recommended stuff here as in the documentation */ al128(1); /* always first entry */ al128(DW_TAG_compile_unit); al128(DW_CHILDREN_yes); apair(DW_AT_name, DW_FORM_strp); /* file name; e.g. foo.c */ apair(DW_AT_producer, DW_FORM_string); /* producer; PCC 1.2.3 */ apair(DW_AT_comp_dir, DW_FORM_string); /* working directory */ apair(DW_AT_language, DW_FORM_data1); /* C99 */ apair(DW_AT_low_pc, DW_FORM_addr); /* start text */ apair(DW_AT_high_pc, DW_FORM_addr); /* end text */ apair(0, 0); /* Above in info table */ il128(1); /* first entry */ ilbl(dwcfl = dwlab()); istring(PACKAGE_STRING); istring(getcwd(buf, MAXPATHLEN)); il128(DW_LANG_C99); ilbl(dwbtext = dwlab()); ilbl(dwetext = dwlab()); locctr(PROG, NULL); printf(PRTPREF DLABEL ":\n", dwbtext); } void dwarf_file(char *fn) { /* if first file name, print out as initial and remember */ if (dwcfl) { dwslabstr(dwcfl, fn); dwcfl = 0; } /* XXX add more here */ } void dwarf_end() { locctr(PROG, NULL); printf(PRTPREF DLABEL ":\n", dwetext); if (dwcfl) dwslabstr(dwcfl, dwname ? dwname : ""); printf(PRTPREF "\t.set " DLABEL ",%d\n", debug_info_sz_lbl, debug_info_sz); } #endif pcc-20181216/cc/ccom/dwarf.h010064400017500000000000000140351266231557300142630ustar raggewheel #define DW_TAG_array_type 0x01 #define DW_TAG_class_type 0x02 #define DW_TAG_entry_point 0x03 #define DW_TAG_enumeration_type 0x04 #define DW_TAG_formal_parameter 0x05 #define DW_TAG_imported_declaration 0x08 #define DW_TAG_label 0x0a #define DW_TAG_lexical_block 0x0b #define DW_TAG_member 0x0d #define DW_TAG_pointer_type 0x0f #define DW_TAG_reference_type 0x10 #define DW_TAG_compile_unit 0x11 #define DW_TAG_string_type 0x12 #define DW_TAG_structure_type 0x13 #define DW_TAG_subroutine_type 0x15 #define DW_TAG_typedef 0x16 #define DW_TAG_union_type 0x17 #define DW_TAG_unspecified_parameters 0x18 #define DW_TAG_variant 0x19 #define DW_TAG_common_block 0x1a #define DW_TAG_common_inclusion 0x1b #define DW_TAG_inheritance 0x1c #define DW_TAG_inlined_subroutine 0x1d #define DW_TAG_module 0x1e #define DW_TAG_ptr_to_member_type 0x1f #define DW_TAG_set_type 0x20 #define DW_TAG_subrange_type 0x21 #define DW_TAG_with_stmt 0x22 #define DW_TAG_access_declaration 0x23 #define DW_TAG_base_type 0x24 #define DW_TAG_catch_block 0x25 #define DW_TAG_const_type 0x26 #define DW_TAG_constant 0x27 #define DW_TAG_enumerator 0x28 #define DW_TAG_file_type 0x29 #define DW_TAG_friend 0x2a #define DW_TAG_namelist 0x2b #define DW_TAG_namelist_item 0x2c #define DW_TAG_packed_type 0x2d #define DW_TAG_subprogram 0x2e #define DW_TAG_template_type_parameter 0x2f #define DW_TAG_template_value_parameter 0x30 #define DW_TAG_thrown_type 0x31 #define DW_TAG_try_block 0x32 #define DW_TAG_variant_part 0x33 #define DW_TAG_variable 0x34 #define DW_TAG_volatile_type 0x35 #define DW_TAG_dwarf_procedure 0x36 #define DW_TAG_restrict_type 0x37 #define DW_TAG_interface_type 0x38 #define DW_TAG_namespace 0x39 #define DW_TAG_imported_module 0x3a #define DW_TAG_unspecified_type 0x3b #define DW_TAG_partial_unit 0x3c #define DW_TAG_imported_unit 0x3d #define DW_TAG_condition 0x3f #define DW_TAG_shared_type 0x40 #define DW_TAG_lo_user 0x4080 #define DW_TAG_hi_user 0xffff #define DW_CHILDREN_no 0 #define DW_CHILDREN_yes 1 #define DW_AT_sibling 0x01 /* reference */ #define DW_AT_location 0x02 /* block, loclistptr */ #define DW_AT_name 0x03 /* string */ #define DW_AT_ordering 0x09 /* constant */ #define DW_AT_byte_size 0x0b /* block, constant, reference */ #define DW_AT_bit_offset 0x0c /* block, constant, reference */ #define DW_AT_bit_size 0x0d /* block, constant, reference */ #define DW_AT_stmt_list 0x10 #define DW_AT_low_pc 0x11 #define DW_AT_high_pc 0x12 #define DW_AT_language 0x13 #define DW_AT_discr 0x15 #define DW_AT_discr_value 0x16 #define DW_AT_visibility 0x17 #define DW_AT_import 0x18 #define DW_AT_string_length 0x19 #define DW_AT_common_reference 0x1a #define DW_AT_comp_dir 0x1b #define DW_AT_const_value 0x1c #define DW_AT_containing_type 0x1d #define DW_AT_default_value 0x1e #define DW_AT_inline 0x20 #define DW_AT_is_optional 0x21 #define DW_AT_lower_bound 0x22 #define DW_AT_producer 0x25 #define DW_AT_prototyped 0x27 #define DW_AT_return_addr 0x2a #define DW_AT_start_scope 0x2c #define DW_AT_bit_stride 0x2e #define DW_AT_upper_bound 0x2f #define DW_AT_abstract_origin 0x31 #define DW_AT_accessibility 0x32 #define DW_AT_address_class 0x33 #define DW_AT_artificial 0x34 #define DW_AT_base_types 0x35 #define DW_AT_calling_convention 0x36 #define DW_AT_count 0x37 #define DW_AT_data_member_location 0x38 #define DW_AT_decl_column 0x39 #define DW_AT_decl_file 0x3a #define DW_AT_decl_line 0x3b #define DW_AT_declaration 0x3c #define DW_AT_discr_list 0x3d #define DW_AT_encoding 0x3e #define DW_AT_external 0x3f #define DW_AT_frame_base 0x40 #define DW_AT_friend 0x41 #define DW_AT_identifier_case 0x42 #define DW_AT_macro_info 0x43 #define DW_AT_namelist_item 0x44 #define DW_AT_priority 0x45 #define DW_AT_segment 0x46 #define DW_AT_specification 0x47 #define DW_AT_static_link 0x48 #define DW_AT_type 0x49 #define DW_AT_use_location 0x4a #define DW_AT_variable_parameter 0x4b #define DW_AT_virtuality 0x4c #define DW_AT_vtable_elem_location 0x4d #define DW_AT_allocated 0x4e #define DW_AT_associated 0x4f #define DW_AT_data_location 0x50 #define DW_AT_byte_stride 0x51 #define DW_AT_entry_pc 0x52 #define DW_AT_use_UTF8 0x53 #define DW_AT_extension 0x54 #define DW_AT_ranges 0x55 #define DW_AT_trampoline 0x56 #define DW_AT_call_column 0x57 #define DW_AT_call_file 0x58 #define DW_AT_call_line 0x59 #define DW_AT_description 0x5a #define DW_AT_binary_scale 0x5b #define DW_AT_decimal_scale 0x5c #define DW_AT_small 0x5d #define DW_AT_decimal_sign 0x5e #define DW_AT_digit_count 0x5f #define DW_AT_picture_string 0x60 #define DW_AT_mutable 0x61 #define DW_AT_threads_scaled 0x62 #define DW_AT_explicit 0x63 #define DW_AT_object_pointer 0x64 #define DW_AT_endianity 0x65 #define DW_AT_elemental 0x66 #define DW_AT_pure 0x67 #define DW_AT_recursive 0x68 /* flag */ #define DW_AT_lo_user 0x2000 #define DW_AT_hi_user 0x3fff #define DW_FORM_addr 0x01 #define DW_FORM_block2 0x03 #define DW_FORM_block4 0x04 #define DW_FORM_data2 0x05 /* constant */ #define DW_FORM_data4 0x06 /* constant, lineptr, loclistptr... */ #define DW_FORM_data8 0x07 #define DW_FORM_string 0x08 #define DW_FORM_block 0x09 #define DW_FORM_block1 0x0a #define DW_FORM_data1 0x0b /* constant */ #define DW_FORM_flag 0x0c #define DW_FORM_sdata 0x0d /* constant */ #define DW_FORM_strp 0x0e #define DW_FORM_udata 0x0f #define DW_FORM_ref_addr 0x10 #define DW_FORM_ref1 0x11 #define DW_FORM_ref2 0x12 #define DW_FORM_ref4 0x13 #define DW_FORM_ref8 0x14 #define DW_FORM_ref_udata 0x15 #define DW_FORM_indirect 0x16 #define DW_LANG_C89 0x01 #define DW_LANG_C 0x02 #define DW_LANG_Ada83 0x03 #define DW_LANG_C_plus_plus 0x04 #define DW_LANG_Cobol74 0x05 #define DW_LANG_Cobol85 0x06 #define DW_LANG_Fortran77 0x07 #define DW_LANG_Fortran90 0x08 #define DW_LANG_Pascal83 0x09 #define DW_LANG_Modula2 0x0a #define DW_LANG_Java 0x0b #define DW_LANG_C99 0x0c #define DW_LANG_Ada95 0x0d #define DW_LANG_Fortran95 0x0e #define DW_LANG_PLI 0x0f #define DW_LANG_ObjC 0x10 #define DW_LANG_ObjC_plus_plus 0x11 #define DW_LANG_UPC 0x12 #define DW_LANG_D 0x13 #define DW_LANG_lo_user 0x8000 #define DW_LANG_hi_user 0xffff pcc-20181216/cc/ccom/gcc_compat.c010064400017500000000000000625611325022544400152500ustar raggewheel/* $Id: gcc_compat.c,v 1.122 2018/03/08 12:23:00 ragge Exp $ */ /* * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Routines to support some of the gcc extensions to C. */ #ifdef GCC_COMPAT #include "pass1.h" #include "cgram.h" #include #define NODE P1ND #define nfree p1nfree #define tfree p1tfree static struct kw { char *name, *ptr; int rv; } kw[] = { /* * Do NOT change the order of these entries unless you know * what you're doing! */ /* 0 */ { "__asm", NULL, C_ASM }, /* 1 */ { "__signed", NULL, 0 }, /* 2 */ { "__inline", NULL, 0 }, /* 3 */ { "__const", NULL, 0 }, /* 4 */ { "__asm__", NULL, C_ASM }, /* 5 */ { "__inline__", NULL, 0 }, /* 6 */ { "__thread", NULL, 0 }, /* 7 */ { "__FUNCTION__", NULL, 0 }, /* 8 */ { "__volatile", NULL, 0 }, /* 9 */ { "__volatile__", NULL, 0 }, /* 10 */{ "__restrict", NULL, -1 }, /* 11 */{ "__typeof__", NULL, C_TYPEOF }, /* 12 */{ "typeof", NULL, C_TYPEOF }, /* 13 */{ "__extension__", NULL, -1 }, /* 14 */{ "__signed__", NULL, 0 }, /* 15 */{ "__attribute__", NULL, 0 }, /* 16 */{ "__attribute", NULL, 0 }, /* 17 */{ "__real__", NULL, 0 }, /* 18 */{ "__imag__", NULL, 0 }, /* 19 */{ "__builtin_offsetof", NULL, PCC_OFFSETOF }, /* 20 */{ "__PRETTY_FUNCTION__", NULL, 0 }, /* 21 */{ "__alignof__", NULL, C_ALIGNOF }, /* 22 */{ "__typeof", NULL, C_TYPEOF }, /* 23 */{ "__alignof", NULL, C_ALIGNOF }, /* 24 */{ "__restrict__", NULL, -1 }, { NULL, NULL, 0 }, }; /* g77 stuff */ #if SZFLOAT == SZLONG #define G77_INTEGER LONG #define G77_UINTEGER ULONG #elif SZFLOAT == SZINT #define G77_INTEGER INT #define G77_UINTEGER UNSIGNED #else #error fix g77 stuff #endif #if SZFLOAT*2 == SZLONG #define G77_LONGINT LONG #define G77_ULONGINT ULONG #elif SZFLOAT*2 == SZLONGLONG #define G77_LONGINT LONGLONG #define G77_ULONGINT ULONGLONG #else #error fix g77 long stuff #endif static TWORD g77t[] = { G77_INTEGER, G77_UINTEGER, G77_LONGINT, G77_ULONGINT }; static char *g77n[] = { "__g77_integer", "__g77_uinteger", "__g77_longint", "__g77_ulongint" }; #ifdef TARGET_TIMODE static char *loti, *hiti, *TISTR; static char *lotf, *hitf, *TFSTR; static char *loctf, *hictf, *loitf, *hiitf, *TCSTR; static struct symtab *tisp, *tfsp, *tcsp, *ucmpti2sp, *cmpti2sp, *subvti3sp, *addvti3sp, *mulvti3sp, *divti3sp, *udivti3sp, *modti3sp, *umodti3sp, *ashlti3sp, *ashrti3sp, *lshrti3sp, *floatuntixfsp; #define TYPE_TI 800 #define TYPE_TF 864 #define TYPE_TC 928 struct tifuns { struct symtab **sp; char *fun; TWORD type; int apt; } tifuns[] = { { &cmpti2sp, "__cmpti2", INT, 0 }, { &ucmpti2sp, "__ucmpti2", INT, 0 }, { &addvti3sp, "__addvti3", STRTY, 1 }, { &subvti3sp, "__subvti3", STRTY, 1 }, { &mulvti3sp, "__mulvti3", STRTY, 1 }, { &divti3sp, "__divti3", STRTY, 1 }, { &modti3sp, "__modti3", STRTY, 1 }, { &udivti3sp, "__udivti3", STRTY, 2 }, { &umodti3sp, "__umodti3", STRTY, 2 }, { &ashlti3sp, "__ashlti3", STRTY, 2 }, { &ashrti3sp, "__ashrti3", STRTY, 2 }, { &lshrti3sp, "__lshrti3", STRTY, 2 }, { &floatuntixfsp, "__floatuntixf", LDOUBLE, 0 }, }; static struct symtab * addftn(char *n, TWORD t) { NODE *p = block(TYPE, 0, 0, 0, 0, 0); struct symtab *sp; sp = lookup(addname(n), 0); p->n_type = INCREF(t) + (FTN-PTR); p->n_sp = sp; p->n_df = memset(permalloc(sizeof(union dimfun)), 0, sizeof(union dimfun)); defid(p, EXTERN); nfree(p); return sp; } static struct symtab * addstr(char *n, char *typ) { NODE *p = block(NAME, NIL, NIL, FLOAT, 0, 0); struct symtab *sp; NODE *q; struct attr *ap; struct rstack *rp; extern struct rstack *rpole; p->n_type = ctype(ULONGLONG); rpole = rp = bstruct(NULL, STNAME, NULL); if (typ[1] == 'I') { soumemb(p, loti, 0); soumemb(p, hiti, 0); } else if (typ[1] == 'F') { soumemb(p, lotf, 0); soumemb(p, hitf, 0); } else { soumemb(p, loctf, 0); soumemb(p, hictf, 0); soumemb(p, loitf, 0); soumemb(p, hiitf, 0); } q = dclstruct(rp); sp = q->n_sp = lookup(addname(n), 0); defid(q, TYPEDEF); ap = attr_new(GCC_ATYP_MODE, 3); ap->sarg(0) = addname(typ); ap->iarg(1) = 0; sp->sap = attr_add(sp->sap, ap); nfree(q); nfree(p); return sp; } #endif void gcc_init(void) { struct kw *kwp; NODE *p; TWORD t; int i, d_debug; d_debug = ddebug; ddebug = 0; for (kwp = kw; kwp->name; kwp++) kwp->ptr = addname(kwp->name); for (i = 0; i < 4; i++) { struct symtab *sp; t = ctype(g77t[i]); p = block(NAME, NIL, NIL, t, NULL, 0); sp = lookup(addname(g77n[i]), 0); p->n_sp = sp; defid(p, TYPEDEF); nfree(p); } ddebug = d_debug; #ifdef TARGET_TIMODE { struct attr *ap2; loti = addname("__loti"); hiti = addname("__hiti"); TISTR = addname("TI"); tisp = addstr("0ti", "TI"); lotf = addname("__lotf"); hitf = addname("__hitf"); TFSTR = addname("TF"); tfsp = addstr("0tf", "TF"); loctf = addname("__loctf"); hictf = addname("__hictf"); loitf = addname("__loitf"); hiitf = addname("__hiitf"); TCSTR = addname("TC"); tcsp = addstr("0tc", "TC"); ap2 = attr_new(GCC_ATYP_MODE, 3); ap2->sarg(0) = TISTR; ap2->iarg(1) = 1; ap2 = attr_add(tisp->sap, ap2); for (i = 0; i < (int)(sizeof(tifuns)/sizeof(tifuns[0])); i++) { *tifuns[i].sp = addftn(tifuns[i].fun, tifuns[i].type); switch (tifuns[i].apt) { case 0: /* nothing */ break; case 1: /* just tisp */ (*tifuns[i].sp)->sap = tisp->sap; break; case 2: /* mode string */ (*tifuns[i].sp)->sap = ap2; } } } #endif } #define TS "\n#pragma tls\n# %d\n" #define TLLEN sizeof(TS)+10 /* * See if a string matches a gcc keyword. */ int gcc_keyword(char *str) { extern int inattr, parlvl, parbal; char tlbuf[TLLEN], *tw; struct kw *kwp; int i; /* XXX hack, should pass everything in expressions */ if (str == kw[21].ptr) return kw[21].rv; if (inattr) return 0; for (i = 0, kwp = kw; kwp->name; kwp++, i++) if (str == kwp->ptr) break; if (kwp->name == NULL) return 0; if (kwp->rv) return kwp->rv; switch (i) { case 1: /* __signed */ case 14: /* __signed__ */ yylval.type = SIGNED; return C_TYPE; case 2: /* __inline */ case 5: /* __inline__ */ yylval.type = INLINE; return C_FUNSPEC; case 3: /* __const */ yylval.type = CON; return C_QUALIFIER; case 6: /* __thread */ snprintf(tlbuf, TLLEN, TS, lineno); tw = &tlbuf[strlen(tlbuf)]; while (tw > tlbuf) cunput(*--tw); return -1; case 7: /* __FUNCTION__ */ case 20: /* __PRETTY_FUNCTION__ */ if (cftnsp == NULL) { uerror("%s outside function", kwp->name); yylval.strp = ""; } else yylval.strp = cftnsp->sname; /* XXX - not C99 */ return C_STRING; case 8: /* __volatile */ case 9: /* __volatile__ */ yylval.type = VOL; return C_QUALIFIER; case 15: /* __attribute__ */ case 16: /* __attribute */ inattr = 1; parlvl = parbal; return C_ATTRIBUTE; case 17: /* __real__ */ yylval.intval = XREAL; return C_UNOP; case 18: /* __imag__ */ yylval.intval = XIMAG; return C_UNOP; } cerror("gcc_keyword"); return 0; } #ifndef TARGET_ATTR #define TARGET_ATTR(p, sue) 0 #endif #ifndef ALMAX #define ALMAX (ALLDOUBLE > ALLONGLONG ? ALLDOUBLE : ALLONGLONG) #endif /* allowed number of args */ #define A_0ARG 0x01 #define A_1ARG 0x02 #define A_2ARG 0x04 #define A_3ARG 0x08 /* arg # is a name */ #define A1_NAME 0x10 #define A2_NAME 0x20 #define A3_NAME 0x40 #define A_MANY 0x80 /* arg # is "string" */ #define A1_STR 0x100 #define A2_STR 0x200 #define A3_STR 0x400 #ifdef __MSC__ #define CS(x) #else #define CS(x) [x] = #endif struct atax { int typ; char *name; } atax[GCC_ATYP_MAX] = { CS(ATTR_NONE) { 0, NULL }, CS(ATTR_COMPLEX) { 0, NULL }, CS(xxxATTR_BASETYP) { 0, NULL }, CS(ATTR_QUALTYP) { 0, NULL }, CS(ATTR_STRUCT) { 0, NULL }, CS(ATTR_ALIGNED) { A_0ARG|A_1ARG, "aligned" }, CS(ATTR_NORETURN) { A_0ARG, "noreturn" }, CS(ATTR_P1LABELS) { A_0ARG, "p1labels" }, CS(ATTR_SONAME) { A_1ARG|A1_STR, "soname" }, CS(GCC_ATYP_PACKED) { A_0ARG|A_1ARG, "packed" }, CS(GCC_ATYP_SECTION) { A_1ARG|A1_STR, "section" }, CS(GCC_ATYP_TRANSP_UNION) { A_0ARG, "transparent_union" }, CS(GCC_ATYP_UNUSED) { A_0ARG, "unused" }, CS(GCC_ATYP_DEPRECATED) { A_0ARG, "deprecated" }, CS(GCC_ATYP_MAYALIAS) { A_0ARG, "may_alias" }, CS(GCC_ATYP_MODE) { A_1ARG|A1_NAME, "mode" }, CS(GCC_ATYP_FORMAT) { A_3ARG|A1_NAME, "format" }, CS(GCC_ATYP_NONNULL) { A_MANY, "nonnull" }, CS(GCC_ATYP_SENTINEL) { A_0ARG|A_1ARG, "sentinel" }, CS(GCC_ATYP_WEAK) { A_0ARG, "weak" }, CS(GCC_ATYP_FORMATARG) { A_1ARG, "format_arg" }, CS(GCC_ATYP_GNU_INLINE) { A_0ARG, "gnu_inline" }, CS(GCC_ATYP_MALLOC) { A_0ARG, "malloc" }, CS(GCC_ATYP_NOTHROW) { A_0ARG, "nothrow" }, CS(GCC_ATYP_CONST) { A_0ARG, "const" }, CS(GCC_ATYP_PURE) { A_0ARG, "pure" }, CS(GCC_ATYP_CONSTRUCTOR) { A_0ARG, "constructor" }, CS(GCC_ATYP_DESTRUCTOR) { A_0ARG, "destructor" }, CS(GCC_ATYP_VISIBILITY) { A_1ARG|A1_STR, "visibility" }, CS(GCC_ATYP_STDCALL) { A_0ARG, "stdcall" }, CS(GCC_ATYP_CDECL) { A_0ARG, "cdecl" }, CS(GCC_ATYP_WARN_UNUSED_RESULT) { A_0ARG, "warn_unused_result" }, CS(GCC_ATYP_USED) { A_0ARG, "used" }, CS(GCC_ATYP_NO_INSTR_FUN) { A_0ARG, "no_instrument_function" }, CS(GCC_ATYP_NOINLINE) { A_0ARG, "noinline" }, CS(GCC_ATYP_ALIAS) { A_1ARG|A1_STR, "alias" }, CS(GCC_ATYP_WEAKREF) { A_0ARG|A_1ARG|A1_STR, "weakref" }, CS(GCC_ATYP_ALLOCSZ) { A_1ARG|A_2ARG, "alloc_size" }, CS(GCC_ATYP_ALW_INL) { A_0ARG, "always_inline" }, CS(GCC_ATYP_TLSMODEL) { A_1ARG|A1_STR, "tls_model" }, CS(GCC_ATYP_ALIASWEAK) { A_1ARG|A1_STR, "aliasweak" }, CS(GCC_ATYP_RETURNS_TWICE) { A_0ARG, "returns_twice" }, CS(GCC_ATYP_WARNING) { A_1ARG|A1_STR, "warning" }, CS(GCC_ATYP_NOCLONE) { A_0ARG, "noclone" }, CS(GCC_ATYP_REGPARM) { A_1ARG, "regparm" }, CS(GCC_ATYP_FASTCALL) { A_0ARG, "fastcall" }, CS(GCC_ATYP_BOUNDED) { A_3ARG|A_MANY|A1_NAME, "bounded" }, CS(GCC_ATYP_WEAKIMPORT) { A_0ARG, "weak_import" }, }; #if SZPOINT(CHAR) == SZLONGLONG #define GPT LONGLONG #else #define GPT INT #endif struct atax mods[] = { { 0, NULL }, { INT, "SI" }, { INT, "word" }, { GPT, "pointer" }, { CHAR, "byte" }, { CHAR, "QI" }, { SHORT, "HI" }, { LONGLONG, "DI" }, { FLOAT, "SF" }, { DOUBLE, "DF" }, { LDOUBLE, "XF" }, { FCOMPLEX, "SC" }, { COMPLEX, "DC" }, { LCOMPLEX, "XC" }, { INT, "libgcc_cmp_return" }, { INT, "libgcc_shift_count" }, { LONG, "unwind_word" }, #ifdef TARGET_TIMODE { 800, "TI" }, { 864, "TF" }, { 928, "TC" }, #endif #ifdef TARGET_MODS TARGET_MODS #endif }; #define ATSZ (sizeof(mods)/sizeof(mods[0])) static int amatch(char *s, struct atax *at, int mx) { int i; size_t len; if (s[0] == '_' && s[1] == '_') s += 2; len = strlen(s); if (len > 2 && s[len-1] == '_' && s[len-2] == '_') len -= 2; for (i = 0; i < mx; i++) { char *t = at[i].name; if (t != NULL && strncmp(s, t, len) == 0 && t[len] == 0) return i; } return 0; } static void setaarg(int str, union aarg *aa, NODE *p) { if (str) { if (((str & (A1_STR|A2_STR|A3_STR)) && p->n_op != STRING) || ((str & (A1_NAME|A2_NAME|A3_NAME)) && p->n_op != NAME)) uerror("bad arg to attribute"); if (p->n_op == STRING) { aa->sarg = p->n_name; /* saved in cgram.y */ } else aa->sarg = (char *)p->n_sp; nfree(p); } else aa->iarg = (int)icons(eve(p)); } /* * Parse attributes from an argument list. */ static struct attr * gcc_attribs(NODE *p) { NODE *q, *r; struct attr *ap; char *name = NULL, *c; int cw, attr, narg; if (p->n_op == NAME) { name = (char *)p->n_sp; } else if (p->n_op == CALL || p->n_op == UCALL) { name = (char *)p->n_left->n_sp; } else if (p->n_op == ICON && p->n_type == STRTY) { return NULL; } else cerror("bad variable attribute"); if ((attr = amatch(name, atax, GCC_ATYP_MAX)) == 0) { warner(Wattributes, name); ap = NULL; goto out; } narg = 0; if (p->n_op == CALL) for (narg = 1, q = p->n_right; q->n_op == CM; q = q->n_left) narg++; cw = atax[attr].typ; if (!(cw & A_MANY) && ((narg > 3) || ((cw & (1 << narg)) == 0))) { uerror("wrong attribute arg count"); return NULL; } ap = attr_new(attr, 3); /* XXX should be narg */ q = p->n_right; switch (narg) { default: /* XXX */ while (narg-- > 3) { r = q; q = q->n_left; tfree(r->n_right); nfree(r); } /* FALLTHROUGH */ case 3: setaarg(cw & (A3_NAME|A3_STR), &ap->aa[2], q->n_right); r = q; q = q->n_left; nfree(r); /* FALLTHROUGH */ case 2: setaarg(cw & (A2_NAME|A2_STR), &ap->aa[1], q->n_right); r = q; q = q->n_left; nfree(r); /* FALLTHROUGH */ case 1: setaarg(cw & (A1_NAME|A1_STR), &ap->aa[0], q); p->n_op = UCALL; /* FALLTHROUGH */ case 0: break; } /* some attributes must be massaged special */ switch (attr) { case ATTR_ALIGNED: if (narg == 0) ap->aa[0].iarg = ALMAX; else ap->aa[0].iarg *= SZCHAR; break; case GCC_ATYP_PACKED: if (narg == 0) ap->aa[0].iarg = 1; /* bitwise align */ else ap->aa[0].iarg *= SZCHAR; break; case GCC_ATYP_VISIBILITY: c = ap->aa[0].sarg; if (strcmp(c, "default") && strcmp(c, "hidden") && strcmp(c, "internal") && strcmp(c, "protected")) werror("unknown visibility %s", c); break; case GCC_ATYP_TLSMODEL: c = ap->aa[0].sarg; if (strcmp(c, "global-dynamic") && strcmp(c, "local-dynamic") && strcmp(c, "initial-exec") && strcmp(c, "local-exec")) werror("unknown tls model %s", c); break; default: break; } out: return ap; } /* * Extract attributes from a node tree and return attribute entries * based on its contents. */ struct attr * gcc_attr_parse(NODE *p) { struct attr *b, *c; if (p == NIL) return NULL; if (p->n_op != CM) { b = gcc_attribs(p); tfree(p); } else { b = gcc_attr_parse(p->n_left); c = gcc_attr_parse(p->n_right); nfree(p); b = b ? attr_add(b, c) : c; } return b; } /* * Fixup struct/unions depending on attributes. */ void gcc_tcattrfix(NODE *p) { struct symtab *sp; struct attr *ap; int sz, coff, csz, al, oal, mxal; if (!ISSOU(p->n_type)) /* only for structs or unions */ return; if ((ap = attr_find(p->n_ap, GCC_ATYP_PACKED)) == NULL) return; /* nothing to fix */ al = ap->iarg(0); mxal = 0; /* Must repack struct */ coff = csz = 0; for (sp = strmemb(ap); sp; sp = sp->snext) { oal = talign(sp->stype, sp->sap); if (oal > al) oal = al; if (mxal < oal) mxal = oal; if (sp->sclass & FIELD) sz = sp->sclass&FLDSIZ; else sz = (int)tsize(sp->stype, sp->sdf, sp->sap); sp->soffset = upoff(sz, oal, &coff); if (coff > csz) csz = coff; if (p->n_type == UNIONTY) coff = 0; } if (mxal < ALCHAR) mxal = ALCHAR; /* for bitfields */ SETOFF(csz, mxal); /* Roundup to whatever */ ap = attr_find(p->n_ap, ATTR_STRUCT); ap->amsize = csz; ap = attr_find(p->n_ap, ATTR_ALIGNED); ap->iarg(0) = mxal; } /* * gcc-specific pragmas. */ int pragmas_gcc(char *t) { char u; extern char *pragstore; if (strcmp((t = pragtok(NULL)), "diagnostic") == 0) { int warn, err; if (strcmp((t = pragtok(NULL)), "ignored") == 0) warn = 0, err = 0; else if (strcmp(t, "warning") == 0) warn = 1, err = 0; else if (strcmp(t, "error") == 0) warn = 1, err = 1; else return 1; if (eat('\"') || eat('-')) return 1; for (t = pragstore; *t && *t != '\"'; t++) ; u = *t; *t = 0; Wset(pragstore + 1, warn, err); *t = u; } else if (strcmp(t, "poison") == 0) { /* currently ignore */; } else if (strcmp(t, "visibility") == 0) { /* currently ignore */; } else if (strcmp(t, "system_header") == 0) { /* currently ignore */; } else werror("gcc pragma unsupported"); return 0; } /* * Fixup types when modes given in defid(). */ void gcc_modefix(NODE *p) { struct attr *ap; #ifdef TARGET_TIMODE struct attr *a2; #endif struct symtab *sp; char *s; int i, u; if ((ap = attr_find(p->n_ap, GCC_ATYP_MODE)) == NULL) return; u = ISUNSIGNED(BTYPE(p->n_type)); if ((i = amatch(ap->aa[0].sarg, mods, ATSZ)) == 0) { werror("unknown mode arg %s", ap->aa[0].sarg); return; } i = mods[i].typ; if (i >= 1 && i <= MAXTYPES) { MODTYPE(p->n_type, ctype(i)); if (u) p->n_type = ENUNSIGN(p->n_type); } else switch (i) { #ifdef TARGET_TIMODE case 864: case 928: case 800: if (BTYPE(p->n_type) == STRTY) break; MODTYPE(p->n_type, tisp->stype); p->n_df = tisp->sdf; p->n_ap = tisp->sap; if (ap->iarg(1) == u) break; /* must add a new mode struct to avoid overwriting */ a2 = attr_new(GCC_ATYP_MODE, 3); a2->sarg(0) = ap->sarg(0); a2->iarg(1) = u; p->n_ap = attr_add(p->n_ap, a2); break; #endif case FCOMPLEX: case COMPLEX: case LCOMPLEX: /* Destination should have been converted to a struct already */ if (BTYPE(p->n_type) != STRTY) uerror("gcc_modefix: complex not STRTY"); i -= (FCOMPLEX-FLOAT); ap = strattr(p->n_ap); sp = ap->amlist; if (sp->stype == (unsigned)i) return; /* Already correct type */ /* we must change to another struct */ s = i == FLOAT ? "0f" : i == DOUBLE ? "0d" : i == LDOUBLE ? "0l" : 0; sp = lookup(addname(s), 0); for (ap = sp->sap; ap != NULL; ap = ap->next) p->n_ap = attr_add(p->n_ap, attr_dup(ap)); break; default: cerror("gcc_modefix"); } } #ifdef TARGET_TIMODE /* * Return ap if this node is a TI node, else NULL. */ struct attr * isti(NODE *p) { struct attr *ap; if (p->n_type != STRTY) return NULL; if ((ap = attr_find(p->n_ap, GCC_ATYP_MODE)) == NULL) return NULL; if (strcmp(ap->sarg(0), TISTR) && strcmp(ap->sarg(0), TFSTR) && strcmp(ap->sarg(0), TCSTR)) return NULL; return ap; } static char * tistack(void) { struct symtab *sp, *sp2; char buf[12]; NODE *q; char *n; /* allocate space on stack */ snprintf(buf, 12, "%d", getlab()); n = addname(buf); sp = lookup(n, 0); sp2 = tisp; q = block(TYPE, NIL, NIL, sp2->stype, sp2->sdf, sp2->sap); q->n_sp = sp; nidcl2(q, AUTO, 0); nfree(q); return n; } #define biop(x,y,z) block(x, y, z, INT, 0, 0) /* * Create a ti node from something not a ti node. * This usually means: allocate space on stack, store val, give stack address. */ static NODE * ticast(NODE *p, int u) { CONSZ val; NODE *q; char *n; int u2; n = tistack(); /* store val */ switch (p->n_op) { case ICON: val = 0; if (u == 0 && glval(p) < 0) val = -1; q = eve(biop(DOT, bdty(NAME, n), bdty(NAME, loti))); q = buildtree(ASSIGN, q, p); p = biop(DOT, bdty(NAME, n), bdty(NAME, hiti)); p = eve(biop(ASSIGN, p, bcon(val))); q = buildtree(COMOP, q, p); p = buildtree(COMOP, q, eve(bdty(NAME, n))); break; default: u2 = ISUNSIGNED(p->n_type); q = eve(biop(DOT, bdty(NAME, n), bdty(NAME, loti))); q = buildtree(ASSIGN, q, p); p = biop(DOT, bdty(NAME, n), bdty(NAME, hiti)); if (u2) { p = eve(biop(ASSIGN, p, bcon(0))); } else { q = buildtree(ASSIGN, eve(p1tcopy(p)), q); p = buildtree(RSEQ, eve(p), bcon(SZLONG-1)); } q = buildtree(COMOP, q, p); p = buildtree(COMOP, q, eve(bdty(NAME, n))); break; } return p; } /* * Check if we may have to do a cast to/from TI. */ NODE * gcc_eval_ticast(int op, NODE *p1, NODE *p2) { struct attr *a1, *a2; int t; a2 = NULL; /* XXX flow analysis */ if ((a1 = isti(p1)) == NULL && (a2 = isti(p2)) == NULL) return NIL; if (op == RETURN) p1 = p1tcopy(p1); if (a1 == NULL) { if (a2 == NULL) cerror("gcc_eval_ticast error"); switch (p1->n_type) { case LDOUBLE: p2 = doacall(floatuntixfsp, nametree(floatuntixfsp), p2); tfree(p1); break; case ULONG: case LONG: p2 = cast(structref(p2, DOT, loti), p1->n_type, 0); tfree(p1); break; case VOID: return NIL; default: uerror("gcc_eval_ticast: %d", p1->n_type); } return p2; } /* p2 can be anything, but we must cast it to p1 */ t = a1->iarg(1); if (p2->n_type == STRTY && (a2 = attr_find(p2->n_ap, GCC_ATYP_MODE)) && strcmp(a2->sarg(0), TISTR) == 0) { /* Already TI, just add extra mode bits */ a2 = attr_new(GCC_ATYP_MODE, 3); a2->sarg(0) = TISTR; a2->iarg(1) = t; p2->n_ap = attr_add(p2->n_ap, a2); } else { p2 = ticast(p2, t); } tfree(p1); return p2; } /* * Apply a unary op on a TI value. */ NODE * gcc_eval_tiuni(int op, NODE *p1) { struct attr *a1; NODE *p; if ((a1 = isti(p1)) == NULL) return NULL; switch (op) { case UMINUS: p = ticast(bcon(0), 0); p = buildtree(CM, p, p1); p = doacall(subvti3sp, nametree(subvti3sp), p); break; case UMUL: p = NULL; default: uerror("unsupported unary TI mode op %d", op); p = NULL; } return p; } /* * Evaluate AND/OR/ER. p1 and p2 are pointers to ti struct. */ static NODE * gcc_andorer(int op, NODE *p1, NODE *p2) { char *n = tistack(); NODE *p, *t1, *t2, *p3; t1 = tempnode(0, p1->n_type, p1->n_df, p1->n_ap); t2 = tempnode(0, p2->n_type, p2->n_df, p2->n_ap); p1 = buildtree(ASSIGN, p1tcopy(t1), p1); p2 = buildtree(ASSIGN, p1tcopy(t2), p2); p = buildtree(COMOP, p1, p2); p3 = buildtree(ADDROF, eve(bdty(NAME, n)), NIL); p1 = buildtree(ASSIGN, structref(p1tcopy(p3), STREF, hiti), buildtree(op, structref(p1tcopy(t1), STREF, hiti), structref(p1tcopy(t2), STREF, hiti))); p = buildtree(COMOP, p, p1); p1 = buildtree(ASSIGN, structref(p1tcopy(p3), STREF, loti), buildtree(op, structref(t1, STREF, loti), structref(t2, STREF, loti))); p = buildtree(COMOP, p, p1); p = buildtree(COMOP, p, buildtree(UMUL, p3, NIL)); return p; } /* * Ensure that a 128-bit assign succeeds. * If left is not TI, make right not TI, * else if left _is_ TI, make right TI, * else do nothing. */ static NODE * timodeassign(NODE *p1, NODE *p2) { struct attr *a1, *a2; a1 = isti(p1); a2 = isti(p2); if (a1 && a2 == NULL) { p2 = ticast(p2, a1->iarg(1)); } else if (a1 == NULL && a2) { if (ISFTY(p1->n_type)) cerror("cannot TI float convert"); p2 = structref(p2, DOT, loti); } return buildtree(ASSIGN, p1, p2); } /* * Evaluate 128-bit operands. */ NODE * gcc_eval_timode(int op, NODE *p1, NODE *p2) { struct attr *a1, *a2; struct symtab *sp; NODE *p; int isu = 0, gotti, isaop; if (op == CM) return buildtree(op, p1, p2); a1 = isti(p1); a2 = isti(p2); if (a1 == NULL && a2 == NULL) return NULL; if (op == ASSIGN) return timodeassign(p1, p2); gotti = (a1 != NULL); gotti += (a2 != NULL); if (gotti == 0) return NULL; if (a1 != NULL) isu = a1->iarg(1); if (a2 != NULL && !isu) isu = a2->iarg(1); if (a1 == NULL) { p1 = ticast(p1, isu); a1 = attr_find(p1->n_ap, GCC_ATYP_MODE); } if (a2 == NULL && (cdope(op) & SHFFLG) == 0) { p2 = ticast(p2, isu); a2 = attr_find(p2->n_ap, GCC_ATYP_MODE); } switch (op) { case GT: case GE: case LT: case LE: case EQ: case NE: /* change to call */ sp = isu ? ucmpti2sp : cmpti2sp; p = doacall(sp, nametree(sp), buildtree(CM, p1, p2)); p = buildtree(op, p, bcon(1)); break; case AND: case ER: case OR: if (!ISPTR(p1->n_type)) p1 = buildtree(ADDROF, p1, NIL); if (!ISPTR(p2->n_type)) p2 = buildtree(ADDROF, p2, NIL); p = gcc_andorer(op, p1, p2); break; case LSEQ: case RSEQ: case LS: case RS: sp = op == LS || op == LSEQ ? ashlti3sp : isu ? lshrti3sp : ashrti3sp; p2 = cast(p2, INT, 0); /* XXX p1 p1tcopy may have side effects */ p = doacall(sp, nametree(sp), buildtree(CM, p1tcopy(p1), p2)); if (op == LSEQ || op == RSEQ) { p = buildtree(ASSIGN, p1, p); } else tfree(p1); break; case PLUSEQ: case MINUSEQ: case MULEQ: case DIVEQ: case MODEQ: case PLUS: case MINUS: case MUL: case DIV: case MOD: isaop = (cdope(op)&ASGOPFLG); if (isaop) op = UNASG op; sp = op == PLUS ? addvti3sp : op == MINUS ? subvti3sp : op == MUL ? mulvti3sp : op == DIV ? (isu ? udivti3sp : divti3sp) : op == MOD ? (isu ? umodti3sp : modti3sp) : 0; /* XXX p1 p1tcopy may have side effects */ p = doacall(sp, nametree(sp), buildtree(CM, p1tcopy(p1), p2)); if (isaop) p = buildtree(ASSIGN, p1, p); else tfree(p1); break; default: uerror("unsupported TImode op %d", op); p = bcon(0); } return p; } #endif #ifdef PCC_DEBUG void dump_attr(struct attr *ap) { printf("attributes; "); for (; ap; ap = ap->next) { if (ap->atype >= GCC_ATYP_MAX) { printf("bad type %d, ", ap->atype); } else if (atax[ap->atype].name == 0) { char *c = ap->atype == ATTR_COMPLEX ? "complex" : ap->atype == ATTR_STRUCT ? "struct" : "badtype"; printf("%s, ", c); } else { printf("%s: ", atax[ap->atype].name); if (atax[ap->atype].typ & A1_STR) printf("%s ", ap->sarg(0)); else printf("%d %d %d, ", ap->iarg(0), ap->iarg(1), ap->iarg(2)); } } printf("\n"); } #endif #endif pcc-20181216/cc/ccom/init.c010064400017500000000000000723021340102345600141030ustar raggewheel/* $Id: init.c,v 1.106 2018/12/02 18:40:46 ragge Exp $ */ /* * Copyright (c) 2004, 2007 Anders Magnusson (ragge@ludd.ltu.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code and documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "pass1.h" #include "unicode.h" #include #define NODE P1ND #define tfree p1tfree #define nfree p1nfree #define fwalk p1fwalk /* * The following machine-dependent routines may be called during * initialization: * * zbits(OFFSZ, int) - sets int bits of zero at position OFFSZ. * infld(CONSZ off, int fsz, CONSZ val) * - sets the bitfield val starting at off and size fsz. * ninval(CONSZ off, int fsz, NODE *) * - prints an integer constant which may have * a label associated with it, located at off and * size fsz. * * Initialization may be of different kind: * - Initialization at compile-time, all values are constants and laid * out in memory. Static or extern variables outside functions. * - Initialization at run-time, written to their values as code. * * Currently run-time-initialized variables are only initialized by using * move instructions. An optimization might be to detect that it is * initialized with constants and therefore copied from readonly memory. */ /* * The base element(s) of an initialized variable is kept in a linked * list, allocated while initialized. * * When a scalar is found, entries are popped of the instk until it's * possible to find an entry for a new scalar; then onstk() is called * to get the correct type and size of that scalar. * * If a right brace is found, pop the stack until a matching left brace * were found while filling the elements with zeros. This left brace is * also marking where the current level is for designated initializations. * * Position entries are increased when traversing back down into the stack. */ /* * Good-to-know entries from symtab: * soffset - # of bits from beginning of this structure. */ /* * TO FIX: * - Alignment of structs on like i386 char members. */ /* * Struct used in array initialisation. */ static struct instk { struct instk *in_prev; /* linked list */ struct symtab *in_lnk; /* member in structure initializations */ struct symtab *in_sym; /* symtab index */ union dimfun *in_df; /* dimenston of array */ TWORD in_t; /* type for this level */ int in_n; /* number of arrays seen so far */ int in_fl; /* flag which says if this level is controlled by {} */ } *pstk, pbase; int doing_init, statinit; static struct symtab *csym; #ifdef PCC_DEBUG static void prtstk(struct instk *in); #endif /* * Linked lists for initializations. */ struct ilist { struct ilist *next; CONSZ off; /* bit offset of this entry */ int fsz; /* bit size of this entry */ NODE *n; /* node containing this data info */ }; struct llist { SLIST_ENTRY(llist) next; CONSZ begsz; /* bit offset of this entry */ struct ilist *il; }; static SLIST_HEAD(llh, llist) lpole; static CONSZ basesz; static int numents; /* # of array entries allocated */ static struct initctx { struct initctx *prev; struct instk *pstk; struct symtab *psym; struct llh lpole; CONSZ basesz; int numents; } *inilnk; static struct ilist * getil(struct ilist *next, CONSZ b, int sz, NODE *n) { struct ilist *il = tmpalloc(sizeof(struct ilist)); il->off = b; il->fsz = sz; il->n = n; il->next = next; return il; } /* * Allocate a new struct defining a block of initializers appended to the * end of the llist. Return that entry. */ static struct llist * getll(void) { struct llist *ll; ll = tmpalloc(sizeof(struct llist)); ll->begsz = numents * basesz; ll->il = NULL; SLIST_INSERT_LAST(&lpole, ll, next); numents++; return ll; } /* * Return structure containing off bitnumber. * Allocate more entries, if needed. */ static struct llist * setll(OFFSZ off) { struct llist *ll = NULL; /* Ensure that we have enough entries */ while (off >= basesz * numents) ll = getll(); if (ll != NULL && ll->begsz <= off && ll->begsz + basesz > off) return ll; SLIST_FOREACH(ll, &lpole, next) if (ll->begsz <= off && ll->begsz + basesz > off) break; return ll; /* ``cannot fail'' */ } char *astypnames[] = { 0, 0, "\t.byte", "\t.byte", "\t.short", "\t.short", "\t.word", "\t.word", "\t.long", "\t.long", "\t.quad", "\t.quad", "ERR", "ERR", "ERR", }; void inval(CONSZ off, int fsz, NODE *p) { struct symtab *sp; CONSZ val; TWORD t; #ifndef NO_COMPLEX if (ANYCX(p) && p->n_left->n_right->n_right->n_op == FCON && p->n_left->n_left->n_right->n_op == FCON) { NODE *r = p->n_left->n_right->n_right; int sz = (int)tsize(r->n_type, r->n_df, r->n_ap); ninval(off, sz, p->n_left->n_left->n_right); ninval(off, sz, r); tfree(p); return; } #endif if (p->n_op != ICON && p->n_op != FCON) { uerror("constant required"); return; } if (p->n_type == BOOL) { if ((U_CONSZ)glval(p) > 1) slval(p, 1); p->n_type = BOOL_TYPE; } if (ninval(off, fsz, p)) return; /* dealt with in local.c */ t = p->n_type; if (t > BTMASK) t = INTPTR; val = (CONSZ)(glval(p) & SZMASK(sztable[t])); if (t <= ULONGLONG) { sp = p->n_sp; printf(PRTPREF "%s ",astypnames[t]); if (val || sp == NULL) printf(CONFMT, val); if (val && sp != NULL) printf("+"); if (sp != NULL) { if ((sp->sclass == STATIC && sp->slevel > 0)) { /* fix problem with &&label not defined yet */ int o = sp->soffset; printf(LABFMT, o < 0 ? -o : o); if ((sp->sflags & SMASK) == SSTRING) sp->sflags |= SASG; } else printf("%s", getexname(sp)); } printf("\n"); } else if (t == FLOAT || t == DOUBLE || t == LDOUBLE) { uint32_t *ufp; int i, nbits; ufp = soft_toush(p->n_scon, t, &nbits); for (i = 0; i < sztable[t]; i += SZINT) { printf(PRTPREF "%s %u\n", astypnames[INT], (i < nbits ? ufp[i/SZINT] : 0)); } } else cerror("inval: unhandled type %d", (int)t); } #ifndef MYBFINIT static int inbits; static CONSZ xinval; /* * Initialize a bitfield. * XXX - use U_CONSZ? */ void infld(CONSZ off, int fsz, CONSZ val) { #ifdef PCC_DEBUG if (idebug) printf("infld off " CONFMT ", fsz %d, val " CONFMT " inbits %d\n", off, fsz, val, inbits); #endif val &= SZMASK(fsz); #if TARGET_ENDIAN == TARGET_BE while (fsz + inbits >= SZCHAR) { int shsz = SZCHAR-inbits; xinval = (xinval << shsz) | (val >> (fsz - shsz)); printf(PRTPREF "%s " CONFMT "\n", astypnames[CHAR], xinval & SZMASK(SZCHAR)); fsz -= shsz; val &= SZMASK(fsz); xinval = inbits = 0; } if (fsz) { xinval = (xinval << fsz) | val; inbits += fsz; } #else while (fsz + inbits >= SZCHAR) { int shsz = SZCHAR-inbits; xinval |= (val << inbits); printf(PRTPREF "%s " CONFMT "\n", astypnames[CHAR], (CONSZ)(xinval & SZMASK(SZCHAR))); fsz -= shsz; val >>= shsz; xinval = inbits = 0; } if (fsz) { xinval |= (val << inbits); inbits += fsz; } #endif } char *asspace = "\t.space"; /* * set fsz bits in sequence to zero. */ void zbits(OFFSZ off, int fsz) { int m; #ifdef PCC_DEBUG if (idebug) printf("zbits off " CONFMT ", fsz %d inbits %d\n", off, fsz, inbits); #endif #if TARGET_ENDIAN == TARGET_BE if ((m = (inbits % SZCHAR))) { m = SZCHAR - m; if (fsz < m) { inbits += fsz; xinval <<= fsz; return; } else { fsz -= m; xinval <<= m; printf(PRTPREF "%s " CONFMT "\n", astypnames[CHAR], xinval & SZMASK(SZCHAR)); xinval = inbits = 0; } } #else if ((m = (inbits % SZCHAR))) { m = SZCHAR - m; if (fsz < m) { inbits += fsz; return; } else { fsz -= m; printf(PRTPREF "%s " CONFMT "\n", astypnames[CHAR], (CONSZ)(xinval & SZMASK(SZCHAR))); xinval = inbits = 0; } } #endif if (fsz >= SZCHAR) { printf(PRTPREF "%s %d\n", asspace, fsz/SZCHAR); fsz -= (fsz/SZCHAR) * SZCHAR; } if (fsz) { xinval = 0; inbits = fsz; } } #endif /* * beginning of initialization; allocate space to store initialized data. * remember storage class for writeout in endinit(). * p is the newly declarated type. */ void beginit(struct symtab *sp) { struct initctx *ict; struct instk *is = &pbase; #ifdef PCC_DEBUG if (idebug) printf("beginit(%p), sclass %s\n", sp, scnames(sp->sclass)); #endif if (pstk) { #ifdef PCC_DEBUG if (idebug) printf("beginit: saving ctx pstk %p\n", pstk); #endif /* save old context */ ict = tmpalloc(sizeof(struct initctx)); ict->prev = inilnk; inilnk = ict; ict->pstk = pstk; ict->psym = csym; ict->lpole = lpole; ict->basesz = basesz; ict->numents = numents; is = tmpalloc(sizeof(struct instk)); } csym = sp; numents = 0; /* no entries in array list */ if (ISARY(sp->stype)) { basesz = tsize(DECREF(sp->stype), sp->sdf+1, sp->sap); if (basesz == 0) { uerror("array has incomplete type"); basesz = SZINT; } } else basesz = tsize(sp->stype, sp->sdf, sp->sap); SLIST_INIT(&lpole); /* first element */ if (ISSOU(sp->stype)) { is->in_lnk = strmemb(sp->sap); } else is->in_lnk = NULL; is->in_n = 0; is->in_t = sp->stype; is->in_sym = sp; is->in_df = sp->sdf; is->in_fl = 0; is->in_prev = NULL; pstk = is; doing_init++; if (sp->sclass == STATIC || sp->sclass == EXTDEF) statinit++; } /* * Push a new entry on the initializer stack. * The new entry will be "decremented" to the new sub-type of the previous * entry when called. * Popping of entries is done elsewhere. */ static void stkpush(void) { struct instk *is; struct symtab *sq, *sp; TWORD t; if (pstk == NULL) { sp = csym; t = 0; } else { t = pstk->in_t; sp = pstk->in_sym; } #ifdef PCC_DEBUG if (idebug) { printf("stkpush: '%s' %s ", sp->sname, scnames(sp->sclass)); tprint(t, 0); } #endif /* * Figure out what the next initializer will be, and push it on * the stack. If this is an array, just decrement type, if it * is a struct or union, extract the next element. */ is = tmpalloc(sizeof(struct instk)); is->in_fl = 0; is->in_n = 0; if (pstk == NULL) { /* stack empty */ is->in_lnk = ISSOU(sp->stype) ? strmemb(sp->sap) : NULL; is->in_t = sp->stype; is->in_sym = sp; is->in_df = sp->sdf; } else if (ISSOU(t)) { sq = pstk->in_lnk; if (sq == NULL) { uerror("excess of initializing elements"); } else { is->in_lnk = ISSOU(sq->stype) ? strmemb(sq->sap) : NULL; is->in_t = sq->stype; is->in_sym = sq; is->in_df = sq->sdf; } } else if (ISARY(t)) { is->in_lnk = ISSOU(DECREF(t)) ? strmemb(pstk->in_sym->sap) : 0; is->in_t = DECREF(t); is->in_sym = sp; if (pstk->in_df->ddim != NOOFFSET && pstk->in_df->ddim && pstk->in_n >= pstk->in_df->ddim) { werror("excess of initializing elements"); pstk->in_n--; } is->in_df = pstk->in_df+1; } else uerror("too many left braces"); is->in_prev = pstk; pstk = is; #ifdef PCC_DEBUG if (idebug) { printf(" newtype "); tprint(is->in_t, 0); printf("\n"); } #endif } /* * pop down to either next level that can handle a new initializer or * to the next braced level. */ static void stkpop(void) { #ifdef PCC_DEBUG if (idebug) printf("stkpop\n"); #endif for (; pstk; pstk = pstk->in_prev) { if (pstk->in_t == STRTY && pstk->in_lnk != NULL) { pstk->in_lnk = pstk->in_lnk->snext; if (pstk->in_lnk != NULL) break; } if (ISSOU(pstk->in_t) && pstk->in_fl) break; /* need } */ if (ISARY(pstk->in_t)) { pstk->in_n++; if (pstk->in_fl) break; if (pstk->in_df->ddim == NOOFFSET || pstk->in_n < pstk->in_df->ddim) break; /* ger more elements */ } } #ifdef PCC_DEBUG if (idebug > 1) prtstk(pstk); #endif } /* * Count how many elements an array may consist of. */ static int acalc(struct instk *is, int n) { if (is == NULL || !ISARY(is->in_t)) return 0; return acalc(is->in_prev, n * is->in_df->ddim) + n * is->in_n; } /* * Find current bit offset of the top element on the stack from * the beginning of the aggregate. */ static CONSZ findoff(void) { struct instk *is; OFFSZ off; #ifdef PCC_DEBUG if (ISARY(pstk->in_t)) cerror("findoff on bad type %x", pstk->in_t); #endif /* * Offset calculations. If: * - previous type is STRTY, soffset has in-struct offset. * - this type is ARY, offset is ninit*stsize. */ for (off = 0, is = pstk; is; is = is->in_prev) { if (is->in_prev && is->in_prev->in_t == STRTY) off += is->in_sym->soffset; if (ISARY(is->in_t)) { /* suesize is the basic type, so adjust */ TWORD t = is->in_t; OFFSZ o; while (ISARY(t)) t = DECREF(t); if (ISPTR(t)) { o = SZPOINT(t); /* XXX use tsize() */ } else { o = tsize(t, is->in_sym->sdf, is->in_sym->sap); } off += o * acalc(is, 1); while (is->in_prev && ISARY(is->in_prev->in_t)) { if (is->in_prev->in_prev && is->in_prev->in_prev->in_t == STRTY) off += is->in_sym->soffset; is = is->in_prev; } } } #ifdef PCC_DEBUG if (idebug>1) { printf("findoff: off " CONFMT "\n", off); prtstk(pstk); } #endif return off; } /* * Insert the node p with size fsz at position off. * Bit fields are already dealt with, so a node of correct type * with correct alignment and correct bit offset is given. */ static void nsetval(CONSZ off, int fsz, NODE *p) { struct llist *ll; struct ilist *il; if (idebug>1) printf("setval: off " CONFMT " fsz %d p %p\n", off, fsz, p); if (fsz == 0) return; ll = setll(off); off -= ll->begsz; if (ll->il == NULL) { ll->il = getil(NULL, off, fsz, p); } else { il = ll->il; if (il->off > off) { ll->il = getil(ll->il, off, fsz, p); } else { for (il = ll->il; il->next; il = il->next) if (il->off <= off && il->next->off > off) break; if (il->off == off) { /* replace */ nfree(il->n); il->n = p; } else il->next = getil(il->next, off, fsz, p); } } } /* * take care of generating a value for the initializer p * inoff has the current offset (last bit written) * in the current word being generated * Returns the offset. */ CONSZ scalinit(NODE *p) { CONSZ woff; NODE *q; int fsz; #ifdef PCC_DEBUG if (idebug > 2) { printf("scalinit(%p)\n", p); fwalk(p, eprint, 0); prtstk(pstk); } #endif if (nerrors) return 0; p = optim(p); #ifdef notdef /* leave to the target to decide if useable */ if (csym->sclass != AUTO && p->n_op != ICON && p->n_op != FCON && p->n_op != NAME) cerror("scalinit not leaf"); #endif /* Out of elements? */ if (pstk == NULL) { uerror("excess of initializing elements"); return 0; } /* * Get to the simple type if needed. */ while (ISSOU(pstk->in_t) || ISARY(pstk->in_t)) { stkpush(); /* If we are doing auto struct init */ if (ISSOU(pstk->in_t) && ISSOU(p->n_type) && suemeq(pstk->in_sym->sap, p->n_ap)) { pstk->in_lnk = NULL; /* this elem is initialized */ break; } } if (ISSOU(pstk->in_t) == 0) { /* let buildtree do typechecking (and casting) */ q = block(NAME, NIL,NIL, pstk->in_t, pstk->in_df, pstk->in_sym->sap); p = buildtree(ASSIGN, q, p); nfree(p->n_left); q = p->n_right; nfree(p); } else q = p; q = optloop(q); woff = findoff(); /* bitfield sizes are special */ if (pstk->in_sym->sclass & FIELD) fsz = -(pstk->in_sym->sclass & FLDSIZ); else fsz = (int)tsize(pstk->in_t, pstk->in_sym->sdf, pstk->in_sym->sap); nsetval(woff, fsz, q); if (q->n_op == ICON && q->n_sp && ((q->n_sp->sflags & SMASK) == SSTRING)) q->n_sp->sflags |= SASG; stkpop(); #ifdef PCC_DEBUG if (idebug > 2) { printf("scalinit e(%p)\n", q); } #endif return woff; } /* * Generate code to insert a value into a bitfield. */ static void insbf(OFFSZ off, int fsz, int val) { struct symtab sym; NODE *p, *r; TWORD typ; #ifdef PCC_DEBUG if (idebug > 1) printf("insbf: off " CONFMT " fsz %d val %d\n", off, fsz, val); #endif if (fsz == 0) return; /* small opt: do char instead of bf asg */ if ((off & (ALCHAR-1)) == 0 && fsz == SZCHAR) typ = CHAR; else typ = INT; /* Fake a struct reference */ p = buildtree(ADDROF, nametree(csym), NIL); sym.stype = typ; sym.squal = 0; sym.sdf = 0; sym.sap = NULL; sym.soffset = (int)off; sym.sclass = (char)(typ == INT ? FIELD | fsz : MOU); r = xbcon(0, &sym, typ); p = block(STREF, p, r, INT, 0, 0); ecomp(buildtree(ASSIGN, stref(p), bcon(val))); } /* * Clear a bitfield, starting at off and size fsz. */ static void clearbf(OFFSZ off, OFFSZ fsz) { /* Pad up to the next even initializer */ if ((off & (ALCHAR-1)) || (fsz < SZCHAR)) { int ba = (int)(((off + (SZCHAR-1)) & ~(SZCHAR-1)) - off); if (ba > fsz) ba = (int)fsz; insbf(off, ba, 0); off += ba; fsz -= ba; } while (fsz >= SZCHAR) { insbf(off, SZCHAR, 0); off += SZCHAR; fsz -= SZCHAR; } if (fsz) insbf(off, fsz, 0); } /* * final step of initialization. * print out init nodes and generate copy code (if needed). */ void endinit(int seg) { struct llist *ll; struct ilist *il; int fsz; OFFSZ lastoff, tbit; #ifdef PCC_DEBUG if (idebug) printf("endinit()\n"); #endif /* Calculate total block size */ if (ISARY(csym->stype) && csym->sdf->ddim == NOOFFSET) { tbit = numents*basesz; /* open-ended arrays */ csym->sdf->ddim = numents; if (csym->sclass == AUTO) { /* Get stack space */ csym->soffset = NOOFFSET; oalloc(csym, &autooff); } } else tbit = tsize(csym->stype, csym->sdf, csym->sap); /* Setup symbols */ if (csym->sclass != AUTO) { locctr(seg ? UDATA : DATA, csym); defloc(csym); } /* Traverse all entries and print'em out */ lastoff = 0; SLIST_FOREACH(ll, &lpole, next) { for (il = ll->il; il; il = il->next) { #ifdef PCC_DEBUG if (idebug > 1) { printf("off " CONFMT " size %d val " CONFMT " type ", ll->begsz+il->off, il->fsz, glval(il->n)); tprint(il->n->n_type, 0); printf("\n"); } #endif fsz = il->fsz; if (csym->sclass == AUTO) { struct symtab sym; NODE *p, *r, *n; if (ll->begsz + il->off > lastoff) clearbf(lastoff, (ll->begsz + il->off) - lastoff); /* Fake a struct reference */ p = buildtree(ADDROF, nametree(csym), NIL); n = il->n; sym.stype = n->n_type; sym.squal = n->n_qual; sym.sdf = n->n_df; sym.sap = n->n_ap; sym.soffset = (int)(ll->begsz + il->off); sym.sclass = (char)(fsz < 0 ? FIELD | -fsz : 0); r = xbcon(0, &sym, INT); p = block(STREF, p, r, INT, 0, 0); ecomp(buildtree(ASSIGN, stref(p), il->n)); if (fsz < 0) fsz = -fsz; } else { if (ll->begsz + il->off > lastoff) zbits(lastoff, (ll->begsz + il->off) - lastoff); if (fsz < 0) { fsz = -fsz; infld(il->off, fsz, glval(il->n)); } else inval(il->off, fsz, il->n); tfree(il->n); } lastoff = ll->begsz + il->off + fsz; } } if (csym->sclass == AUTO) { clearbf(lastoff, tbit-lastoff); } else zbits(lastoff, tbit-lastoff); doing_init--; if (csym->sclass == STATIC || csym->sclass == EXTDEF) statinit--; endictx(); } void endictx(void) { struct initctx *ict = inilnk; if (ict == NULL) return; pstk = ict->pstk; csym = ict->psym; lpole = ict->lpole; basesz = ict->basesz; numents = ict->numents; inilnk = inilnk->prev; #ifdef PCC_DEBUG if (idebug) printf("endinit: restoring ctx pstk %p\n", pstk); #endif } /* * process an initializer's left brace */ void ilbrace(void) { #ifdef PCC_DEBUG if (idebug) printf("ilbrace()\n"); #endif if (pstk == NULL) return; stkpush(); pstk->in_fl = 1; /* mark lbrace */ #ifdef PCC_DEBUG if (idebug > 1) prtstk(pstk); #endif } /* * called when a '}' is seen */ void irbrace(void) { #ifdef PCC_DEBUG if (idebug) printf("irbrace()\n"); if (idebug > 2) prtstk(pstk); #endif if (pstk == NULL) return; /* Got right brace, search for corresponding in the stack */ for (; pstk->in_prev != NULL; pstk = pstk->in_prev) { if(!pstk->in_fl) continue; /* we have one now */ pstk->in_fl = 0; /* cancel { */ if (ISARY(pstk->in_t)) pstk->in_n = pstk->in_df->ddim; else if (pstk->in_t == STRTY) { while (pstk->in_lnk != NULL && pstk->in_lnk->snext != NULL) pstk->in_lnk = pstk->in_lnk->snext; } stkpop(); return; } } static struct symtab * felem(struct symtab *sp, char *n) { struct symtab *rs; for (; sp; sp = sp->snext) { if (sp->sname[0] == '*') { if ((rs = felem(strattr(sp->sap)->amlist, n)) != NULL) return rs; } else if (sp->sname == n) return sp; } return sp; } /* * Create a new init stack based on given elements. */ static void mkstack(NODE *p) { #ifdef PCC_DEBUG if (idebug) { printf("mkstack: %p\n", p); if (idebug > 1 && p) fwalk(p, eprint, 0); } #endif if (p == NULL) return; mkstack(p->n_left); switch (p->n_op) { case LB: /* Array index */ if (p->n_right->n_op != ICON) cerror("mkstack"); if (!ISARY(pstk->in_t)) uerror("array indexing non-array"); pstk->in_n = (int)glval(p->n_right); nfree(p->n_right); break; case NAME: if (pstk->in_lnk) { pstk->in_lnk = felem(pstk->in_lnk, (char *)p->n_sp); if (pstk->in_lnk == NULL) uerror("member missing"); } else { uerror("not a struct/union"); } break; default: cerror("mkstack2"); } nfree(p); stkpush(); } /* * Initialize a specific element, as per C99. */ void desinit(NODE *p) { int op = p->n_op; if (pstk == NULL) stkpush(); /* passed end of array */ while (pstk->in_prev && pstk->in_fl == 0) pstk = pstk->in_prev; /* Empty stack */ if (ISSOU(pstk->in_t)) pstk->in_lnk = strmemb(pstk->in_sym->sap); mkstack(p); /* Setup for assignment */ /* pop one step if SOU, ilbrace will push */ if (op == NAME || op == LB) pstk = pstk->in_prev; #ifdef PCC_DEBUG if (idebug > 1) { printf("desinit e\n"); prtstk(pstk); } #endif } /* * Convert a string to an array of char/wchar for asginit. */ static void strcvt(NODE *p) { NODE *q = p; char *s; int i; #ifdef mach_arm /* XXX */ if (p->n_op == UMUL && p->n_left->n_op == ADDROF) p = p->n_left->n_left; #endif for (s = p->n_sp->sname; *s != 0; ) { if (p->n_type == ARY+WCHAR_TYPE) i = (int)u82cp(&s); else if (*s == '\\') i = esccon(&s); else i = (unsigned char)*s++; asginit(bcon(i)); } tfree(q); } /* * Do an assignment to a struct element. */ void asginit(NODE *p) { int g; #ifdef PCC_DEBUG if (idebug) printf("asginit %p\n", p); if (idebug > 1 && p) fwalk(p, eprint, 0); #endif /* convert string to array of char/wchar */ if (p && (DEUNSIGN(p->n_type) == ARY+CHAR || p->n_type == ARY+WCHAR_TYPE)) { struct instk *is; TWORD t; t = p->n_type == ARY+WCHAR_TYPE ? ARY+WCHAR_TYPE : ARY+CHAR; /* * ...but only if next element is ARY+CHAR, otherwise * just fall through. */ /* HACKHACKHACK */ is = pstk; if (pstk == NULL) stkpush(); while (ISSOU(pstk->in_t) || ISARY(pstk->in_t)) stkpush(); if (pstk->in_prev && (DEUNSIGN(pstk->in_prev->in_t) == t || pstk->in_prev->in_t == t)) { pstk = pstk->in_prev; if ((g = pstk->in_fl) == 0) pstk->in_fl = 1; /* simulate ilbrace */ strcvt(p); if (g == 0) irbrace(); /* will fill with zeroes */ return; } else pstk = is; /* no array of char */ /* END HACKHACKHACK */ } if (p == NULL) { /* only end of compound stmt */ irbrace(); } else /* assign next element */ scalinit(p); } #ifdef PCC_DEBUG void prtstk(struct instk *in) { int i, o = 0; printf("init stack:\n"); for (; in != NULL; in = in->in_prev) { for (i = 0; i < o; i++) printf(" "); printf("%p) '%s' ", in, in->in_sym->sname); tprint(in->in_t, 0); printf(" %s ", scnames(in->in_sym->sclass)); if (in->in_df /* && in->in_df->ddim */) printf("arydim=%d ", in->in_df->ddim); printf("ninit=%d ", in->in_n); if (BTYPE(in->in_t) == STRTY || ISARY(in->in_t)) printf("stsize=%d ", (int)tsize(in->in_t, in->in_df, in->in_sym->sap)); if (in->in_fl) printf("{ "); printf("soff=%d ", in->in_sym->soffset); if (in->in_t == STRTY) { if (in->in_lnk) printf("curel %s ", in->in_lnk->sname); else printf("END struct"); } printf("\n"); o++; } } #endif /* * Do a simple initialization. * At block 0, just print out the value, at higher levels generate * appropriate code. */ void simpleinit(struct symtab *sp, NODE *p) { NODE *q, *r, *nt; TWORD t; int sz; /* May be an initialization of an array of char by a string */ if ((DEUNSIGN(p->n_type) == ARY+CHAR && DEUNSIGN(sp->stype) == ARY+CHAR) || (DEUNSIGN(p->n_type) == DEUNSIGN(ARY+WCHAR_TYPE) && DEUNSIGN(sp->stype) == DEUNSIGN(ARY+WCHAR_TYPE))) { /* Handle "aaa" as { 'a', 'a', 'a' } */ beginit(sp); strcvt(p); if (csym->sdf->ddim == NOOFFSET) scalinit(bcon(0)); /* Null-term arrays */ endinit(0); return; } nt = nametree(sp); switch (sp->sclass) { case STATIC: case EXTDEF: q = nt; locctr(DATA, sp); defloc(sp); #ifndef NO_COMPLEX if (ANYCX(q) || ANYCX(p)) { r = cxop(ASSIGN, q, p); /* XXX must unwind the code generated here */ /* We can rely on correct code generated */ p = r->n_left->n_right->n_left; r->n_left->n_right->n_left = bcon(0); tfree(r); r = p->n_left->n_right; sz = (int)tsize(r->n_type, r->n_df, r->n_ap); inval(0, sz, r); inval(0, sz, p->n_right->n_right); tfree(p); break; } else if (ISITY(p->n_type) || ISITY(q->n_type)) { /* XXX merge this with code from imop() */ int li = 0, ri = 0; if (ISITY(p->n_type)) li = 1, p->n_type = p->n_type - (FIMAG-FLOAT); if (ISITY(q->n_type)) ri = 1, q->n_type = q->n_type - (FIMAG-FLOAT); if (!(li && ri)) { tfree(p); p = bcon(0); } /* continue below */ } #endif #ifdef TARGET_TIMODE struct attr *ap; if ((ap = attr_find(sp->sap, GCC_ATYP_MODE)) && strcmp(ap->aa[0].sarg, "TI") == 0) { if (p->n_op != ICON) uerror("need to handle TImode initializer "); sz = (int)tsize(sp->stype, sp->sdf, sp->sap); p->n_type = ctype(LONGLONG); inval(0, sz/2, p); slval(p, 0); /* XXX fix signed types */ inval(0, sz/2, p); tfree(p); tfree(q); break; } #endif if (p->n_op == NAME && p->n_sp && (p->n_sp->sflags & SMASK) == SSTRING) p->n_sp->sflags |= SASG; p = optloop(buildtree(ASSIGN, nt, p)); q = p->n_right; t = q->n_type; sz = (int)tsize(t, q->n_df, q->n_ap); inval(0, sz, q); tfree(p); break; case AUTO: case REGISTER: if (ISARY(sp->stype)) cerror("no array init"); q = nt; #ifdef TARGET_TIMODE if ((r = gcc_eval_timode(ASSIGN, q, p)) != NULL) ; else #endif #ifndef NO_COMPLEX if (ANYCX(q) || ANYCX(p)) r = cxop(ASSIGN, q, p); else if (ISITY(p->n_type) || ISITY(q->n_type)) r = imop(ASSIGN, q, p); else #endif r = buildtree(ASSIGN, q, p); ecomp(r); break; default: uerror("illegal initialization"); } } pcc-20181216/cc/ccom/inline.c010064400017500000000000000371071277225026700144360ustar raggewheel/* $Id: inline.c,v 1.66 2016/09/26 16:45:43 ragge Exp $ */ /* * Copyright (c) 2003, 2008 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "pass1.h" #include /* * Simple description of how the inlining works: * A function found with the keyword "inline" is always saved. * If it also has the keyword "extern" it is written out thereafter. * If it has the keyword "static" it will be written out if it is referenced. * inlining will only be done if -xinline is given, and only if it is * possible to inline the function. */ static void printip(struct interpass *pole); struct ntds { int temp; TWORD type; union dimfun *df; struct attr *attr; }; /* * ilink from ipole points to the next struct in the list of functions. */ static struct istat { SLIST_ENTRY(istat) link; struct symtab *sp; int flags; #define CANINL 1 /* function is possible to inline */ #define WRITTEN 2 /* function is written out */ #define REFD 4 /* Referenced but not yet written out */ struct ntds *nt;/* Array of arg temp type data */ int nargs; /* number of args in array */ int retval; /* number of return temporary, if any */ struct interpass shead; } *cifun; static SLIST_HEAD(, istat) ipole = { NULL, &ipole.q_forw }; static int nlabs, svclass; #define IP_REF (MAXIP+1) #ifdef PCC_DEBUG #define SDEBUG(x) if (sdebug) printf x #else #define SDEBUG(x) #endif int isinlining; int inlstatcnt; #define SZSI sizeof(struct istat) int istatsz = SZSI; #define ialloc() memset(permalloc(SZSI), 0, SZSI); inlstatcnt++ /* * Get prolog/epilog for a function. */ static struct interpass_prolog * getprol(struct istat *is, int type) { struct interpass *ip; DLIST_FOREACH(ip, &is->shead, qelem) if (ip->type == type) return (struct interpass_prolog *)ip; cerror("getprol: %d not found", type); return 0; /* XXX */ } static struct istat * findfun(struct symtab *sp) { struct istat *is; SLIST_FOREACH(is, &ipole, link) if (is->sp == sp) return is; return NULL; } static void refnode(struct symtab *sp) { struct interpass *ip; SDEBUG(("refnode(%s)\n", sp->sname)); ip = permalloc(sizeof(*ip)); ip->type = IP_REF; ip->ip_name = (char *)sp; inline_addarg(ip); } /* * Save attributes permanent. */ static struct attr * inapcopy(struct attr *ap) { struct attr *nap = attr_dup(ap); if (ap->next) nap->next = inapcopy(ap->next); return nap; } /* * Copy a tree onto the permanent heap to save for inline. */ static NODE * intcopy(NODE *p) { NODE *q = permalloc(sizeof(NODE)); int o = coptype(p->n_op); /* XXX pass2 optype? */ *q = *p; if (nlabs > 1 && (p->n_op == REG || p->n_op == OREG) && regno(p) == FPREG) SLIST_FIRST(&ipole)->flags &= ~CANINL; /* no stack refs */ if (q->n_ap) q->n_ap = inapcopy(q->n_ap); if (q->n_op == NAME || q->n_op == ICON || q->n_op == XASM || q->n_op == XARG) { if (*q->n_name) q->n_name = xstrdup(q->n_name); /* XXX permstrdup */ else q->n_name = ""; } if (o == BITYPE) q->n_right = intcopy(q->n_right); if (o != LTYPE) q->n_left = intcopy(q->n_left); return q; } void inline_addarg(struct interpass *ip) { struct interpass_prolog *ipp; NODE *q; static int g = 0; extern P1ND *cftnod; SDEBUG(("inline_addarg(%p)\n", ip)); DLIST_INSERT_BEFORE(&cifun->shead, ip, qelem); switch (ip->type) { case IP_ASM: ip->ip_asm = xstrdup(ip->ip_asm); break; case IP_DEFLAB: nlabs++; break; case IP_NODE: q = ip->ip_node; ip->ip_node = intcopy(ip->ip_node); tfree(q); break; case IP_EPILOG: ipp = (struct interpass_prolog *)ip; if (ipp->ip_labels[0]) uerror("no computed goto in inlined functions"); ipp->ip_labels = &g; break; } if (cftnod) cifun->retval = regno(cftnod); } /* * Called to setup for inlining of a new function. */ void inline_start(struct symtab *sp, int class) { struct istat *is; SDEBUG(("inline_start(\"%s\")\n", sp->sname)); if (isinlining) cerror("already inlining function"); svclass = class; if ((is = findfun(sp)) != 0) { if (!DLIST_ISEMPTY(&is->shead, qelem)) uerror("inline function already defined"); } else { is = ialloc(); is->sp = sp; SLIST_INSERT_FIRST(&ipole, is, link); DLIST_INIT(&is->shead, qelem); } cifun = is; nlabs = 0; isinlining++; } /* * End of an inline function. In C99 an inline function declared "extern" * should also have external linkage and are therefore printed out. * * Gcc inline syntax is a mess, see matrix below on emitting functions: * without extern * -std= - gnu89 gnu99 * gcc 3.3.5: ja ja ja * gcc 4.1.3: ja ja ja * gcc 4.3.1 ja ja nej * * with extern * gcc 3.3.5: nej nej nej * gcc 4.1.3: nej nej nej * gcc 4.3.1 nej nej ja * * The above is only true if extern is given on the same line as the * function declaration. If given as a separate definition it do not count. * * The attribute gnu_inline sets gnu89 behaviour. * Since pcc mimics gcc 4.3.1 that is the behaviour we emulate. */ void inline_end(void) { struct symtab *sp = cifun->sp; SDEBUG(("inline_end()\n")); if (sdebug)printip(&cifun->shead); isinlining = 0; if (xgnu89 && svclass == SNULL) sp->sclass = EXTERN; #ifdef GCC_COMPAT if (sp->sclass != STATIC && (attr_find(sp->sap, GCC_ATYP_GNU_INLINE) || xgnu89)) { if (sp->sclass == EXTDEF) sp->sclass = EXTERN; else sp->sclass = EXTDEF; } #endif if (sp->sclass == EXTDEF) { cifun->flags |= REFD; inline_prtout(); } } /* * Called when an inline function is found, to be sure that it will * be written out. * The function may not be defined when inline_ref() is called. */ void inline_ref(struct symtab *sp) { struct istat *w; SDEBUG(("inline_ref(\"%s\")\n", sp->sname)); if (sp->sclass == SNULL) return; /* only inline, no references */ if (isinlining) { refnode(sp); } else { SLIST_FOREACH(w,&ipole, link) { if (w->sp != sp) continue; w->flags |= REFD; return; } /* function not yet defined, print out when found */ w = ialloc(); w->sp = sp; w->flags |= REFD; SLIST_INSERT_FIRST(&ipole, w, link); DLIST_INIT(&w->shead, qelem); } } static void puto(struct istat *w) { struct interpass_prolog *ipp, *epp, *pp; struct interpass *ip, *nip; extern int crslab; int lbloff = 0; /* Copy the saved function and print it out */ ipp = 0; /* XXX data flow analysis */ DLIST_FOREACH(ip, &w->shead, qelem) { switch (ip->type) { case IP_EPILOG: case IP_PROLOG: if (ip->type == IP_PROLOG) { ipp = (struct interpass_prolog *)ip; /* fix label offsets */ lbloff = crslab - ipp->ip_lblnum; } else { epp = (struct interpass_prolog *)ip; crslab += (epp->ip_lblnum - ipp->ip_lblnum); } pp = xmalloc(sizeof(struct interpass_prolog)); memcpy(pp, ip, sizeof(struct interpass_prolog)); pp->ip_lblnum += lbloff; #ifdef PCC_DEBUG if (ip->type == IP_EPILOG && crslab != pp->ip_lblnum) cerror("puto: %d != %d", crslab, pp->ip_lblnum); #endif pass2_compile((struct interpass *)pp); break; case IP_REF: inline_ref((struct symtab *)ip->ip_name); break; default: nip = xmalloc(sizeof(struct interpass)); *nip = *ip; if (nip->type == IP_NODE) { NODE *p; p = nip->ip_node = tcopy(nip->ip_node); if (p->n_op == GOTO) slval(p->n_left, glval(p->n_left) + lbloff); else if (p->n_op == CBRANCH) slval(p->n_right, glval(p->n_right) + lbloff); } else if (nip->type == IP_DEFLAB) nip->ip_lbl += lbloff; pass2_compile(nip); break; } } w->flags |= WRITTEN; } /* * printout functions that are referenced. */ void inline_prtout(void) { struct istat *w; int gotone = 0; SLIST_FOREACH(w, &ipole, link) { if ((w->flags & (REFD|WRITTEN)) == REFD && !DLIST_ISEMPTY(&w->shead, qelem)) { locctr(PROG, w->sp); defloc(w->sp); puto(w); w->flags |= WRITTEN; gotone++; } } if (gotone) inline_prtout(); } #if 1 static void printip(struct interpass *pole) { static char *foo[] = { 0, "NODE", "PROLOG", "STKOFF", "EPILOG", "DEFLAB", "DEFNAM", "ASM" }; struct interpass *ip; struct interpass_prolog *ipplg, *epplg; DLIST_FOREACH(ip, pole, qelem) { if (ip->type > MAXIP) printf("IP(%d) (%p): ", ip->type, ip); else printf("%s (%p): ", foo[ip->type], ip); switch (ip->type) { case IP_NODE: printf("\n"); #ifdef PCC_DEBUG #ifndef TWOPASS { extern void e2print(NODE *p, int down, int *a, int *b); fwalk(ip->ip_node, e2print, 0); break; } #endif #endif case IP_PROLOG: ipplg = (struct interpass_prolog *)ip; printf("%s %s autos %d mintemp %d minlbl %d\n", ipplg->ipp_name, ipplg->ipp_vis ? "(local)" : "", ipplg->ipp_autos, ipplg->ip_tmpnum, ipplg->ip_lblnum); break; case IP_EPILOG: epplg = (struct interpass_prolog *)ip; printf("%s %s autos %d mintemp %d minlbl %d\n", epplg->ipp_name, epplg->ipp_vis ? "(local)" : "", epplg->ipp_autos, epplg->ip_tmpnum, epplg->ip_lblnum); break; case IP_DEFLAB: printf(LABFMT "\n", ip->ip_lbl); break; case IP_DEFNAM: printf("\n"); break; case IP_ASM: printf("%s", ip->ip_asm); break; default: break; } } } #endif static int toff; static P1ND * mnode(struct ntds *nt, P1ND *p) { P1ND *q; int num = nt->temp + toff; if (p->n_op == CM) { q = p->n_right; q = tempnode(num, nt->type, nt->df, nt->attr); nt--; p->n_right = buildtree(ASSIGN, q, p->n_right); p->n_left = mnode(nt, p->n_left); p->n_op = COMOP; } else { p = pconvert(p); q = tempnode(num, nt->type, nt->df, nt->attr); p = buildtree(ASSIGN, q, p); } return p; } static void rtmps(NODE *p, void *arg) { if (p->n_op == TEMP) regno(p) += toff; } /* * Inline a function. Returns the return value. * There are two major things that must be converted when * inlining a function: * - Label numbers must be updated with an offset. * - The stack block must be relocated (add to REG or OREG). * - Temporaries should be updated (but no must) * * Extra tricky: The call is P1ND, nut the resulting tree is already NODE... */ P1ND * inlinetree(struct symtab *sp, P1ND *f, P1ND *ap) { extern int crslab, tvaloff; struct istat *is = findfun(sp); struct interpass *ip, *ipf, *ipl; struct interpass_prolog *ipp, *ipe; int lmin, l0, l1, l2, gainl, n; NODE *pp; P1ND *p, *rp; if (is == NULL || nerrors) { inline_ref(sp); /* prototype of not yet declared inline ftn */ return NULL; } SDEBUG(("inlinetree(%p,%p) OK %d\n", f, ap, is->flags & CANINL)); #ifdef GCC_COMPAT gainl = attr_find(sp->sap, GCC_ATYP_ALW_INL) != NULL; #else gainl = 0; #endif n = nerrors; if ((is->flags & CANINL) == 0 && gainl) werror("cannot inline but always_inline"); nerrors = n; if ((is->flags & CANINL) == 0 || (xinline == 0 && gainl == 0)) { if (is->sp->sclass == STATIC || is->sp->sclass == USTATIC) inline_ref(sp); return NULL; } if (isinlining && cifun->sp == sp) { /* Do not try to inline ourselves */ inline_ref(sp); return NULL; } #ifdef mach_i386 if (kflag) { is->flags |= REFD; /* if static inline, emit */ return NULL; /* XXX cannot handle hidden ebx arg */ } #endif /* emit jumps to surround inline function */ branch(l0 = getlab()); plabel(l1 = getlab()); l2 = getlab(); SDEBUG(("branch labels %d,%d,%d\n", l0, l1, l2)); /* From here it is NODE */ ipp = getprol(is, IP_PROLOG); ipe = getprol(is, IP_EPILOG); /* Fix label & temp offsets */ SDEBUG(("pre-offsets crslab %d tvaloff %d\n", crslab, tvaloff)); lmin = crslab - ipp->ip_lblnum; crslab += (ipe->ip_lblnum - ipp->ip_lblnum) + 2; toff = tvaloff - ipp->ip_tmpnum; tvaloff += (ipe->ip_tmpnum - ipp->ip_tmpnum) + 1; SDEBUG(("offsets crslab %d lmin %d tvaloff %d toff %d\n", crslab, lmin, tvaloff, toff)); /* traverse until first real label */ n = 0; DLIST_FOREACH(ipf, &is->shead, qelem) { if (ipf->type == IP_REF) inline_ref((struct symtab *)ipf->ip_name); if (ipf->type == IP_DEFLAB && n++ == 1) break; } /* traverse backwards to last label */ DLIST_FOREACH_REVERSE(ipl, &is->shead, qelem) { if (ipl->type == IP_REF) inline_ref((struct symtab *)ipl->ip_name); if (ipl->type == IP_DEFLAB) break; } /* So, walk over all statements and emit them */ for (ip = ipf; ip != ipl; ip = DLIST_NEXT(ip, qelem)) { switch (ip->type) { case IP_NODE: pp = tcopy(ip->ip_node); if (pp->n_op == GOTO) slval(pp->n_left, glval(pp->n_left) + lmin); else if (pp->n_op == CBRANCH) slval(pp->n_right, glval(pp->n_right) + lmin); walkf(pp, rtmps, 0); #ifdef PCC_DEBUG #ifndef TWOPASS if (sdebug) { extern void e2print(NODE *p, int down, int *a, int *b); printf("converted node\n"); fwalk(ip->ip_node, e2print, 0); fwalk(pp, e2print, 0); } #endif #endif send_passt(IP_NODE, pp); break; case IP_DEFLAB: SDEBUG(("converted label %d to %d\n", ip->ip_lbl, ip->ip_lbl + lmin)); send_passt(IP_DEFLAB, ip->ip_lbl + lmin); break; case IP_ASM: send_passt(IP_ASM, ip->ip_asm); break; case IP_REF: inline_ref((struct symtab *)ip->ip_name); break; default: cerror("bad inline stmt %d", ip->type); } } SDEBUG(("last label %d to %d\n", ip->ip_lbl, ip->ip_lbl + lmin)); send_passt(IP_DEFLAB, ip->ip_lbl + lmin); branch(l2); plabel(l0); /* Here we are P1ND again */ rp = block(GOTO, bcon(l1), NULL, INT, 0, 0); if (is->retval) p = tempnode(is->retval + toff, DECREF(sp->stype), sp->sdf, sp->sap); else p = xbcon(0, NULL, DECREF(sp->stype)); rp = buildtree(COMOP, rp, p); if (is->nargs) { p = mnode(&is->nt[is->nargs-1], ap); rp = buildtree(COMOP, p, rp); } p1tfree(f); return rp; } void inline_args(struct symtab **sp, int nargs) { union arglist *al; struct istat *cf; TWORD t; int i; SDEBUG(("inline_args\n")); cf = cifun; /* * First handle arguments. We currently do not inline anything if: * - function has varargs * - function args are volatile, checked if no temp node is asg'd. */ /* XXX - this is ugly, invent something better */ if (cf->sp->sdf->dfun == NULL) return; /* no prototype */ for (al = cf->sp->sdf->dfun; al->type != TNULL; al++) { t = al->type; if (t == TELLIPSIS) return; /* cannot inline */ if (ISSOU(BTYPE(t))) al++; for (; t > BTMASK; t = DECREF(t)) if (ISARY(t) || ISFTN(t)) al++; } if (nargs) { for (i = 0; i < nargs; i++) if ((sp[i]->sflags & STNODE) == 0) return; /* not temporary */ cf->nt = permalloc(sizeof(struct ntds)*nargs); for (i = 0; i < nargs; i++) { cf->nt[i].temp = sp[i]->soffset; cf->nt[i].type = sp[i]->stype; cf->nt[i].df = sp[i]->sdf; cf->nt[i].attr = sp[i]->sap; } } cf->nargs = nargs; cf->flags |= CANINL; } pcc-20181216/cc/ccom/main.c010064400017500000000000000247031337601077200140760ustar raggewheel/* $Id: main.c,v 1.136 2018/11/23 14:43:06 ragge Exp $ */ /* * Copyright (c) 2002 Anders Magnusson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #ifdef HAVE_UNISTD_H #include #endif #include #include #include #include "pass1.h" #include "pass2.h" int bdebug, ddebug, edebug, idebug, ndebug; int odebug, pdebug, sdebug, tdebug, xdebug, wdebug; int b2debug, c2debug, e2debug, f2debug, g2debug, o2debug; int r2debug, s2debug, t2debug, u2debug, x2debug; int gflag, kflag; int pflag, sflag; int sspflag; int xscp, xssa, xtailcall, xtemps, xdeljumps, xdce, xinline, xccp, xgnu89, xgnu99; int xuchar; int freestanding; char *prgname, *ftitle; static void prtstats(void); static void usage(void) { (void)fprintf(stderr, "usage: %s [option] [infile] [outfile]...\n", prgname); exit(1); } static void segvcatch(int a) { char buf[1024]; snprintf(buf, sizeof buf, "%sinternal compiler error: %s, line %d\n", nerrors ? "" : "major ", ftitle, lineno); (void)write(STDERR_FILENO, buf, strlen(buf)); _exit(1); } static void xopt(char *str) { if (strcmp(str, "ssa") == 0) xssa++; else if (strcmp(str, "tailcall") == 0) xtailcall++; else if (strcmp(str, "temps") == 0) xtemps++; else if (strcmp(str, "deljumps") == 0) xdeljumps++; else if (strcmp(str, "dce") == 0) xdce++; else if (strcmp(str, "inline") == 0) xinline++; else if (strcmp(str, "ccp") == 0) xccp++; else if (strcmp(str, "scp") == 0) xscp++; else if (strcmp(str, "gnu89") == 0) xgnu89++; else if (strcmp(str, "gnu99") == 0) xgnu99++; else if (strcmp(str, "uchar") == 0) xuchar++; else { fprintf(stderr, "unknown -x option '%s'\n", str); usage(); } } static void fflags(char *str) { int flagval = 1; if (strncmp("no-", str, 3) == 0) { str += 3; flagval = 0; } #ifndef PASS2 if (strcmp(str, "stack-protector") == 0) sspflag = flagval; else if (strcmp(str, "stack-protector-all") == 0) sspflag = flagval; else if (strncmp(str, "pack-struct", 11) == 0) pragma_allpacked = (strlen(str) > 12 ? atoi(str+12) : 1); else if (strcmp(str, "freestanding") == 0) freestanding = flagval; else { fprintf(stderr, "unknown -f option '%s'\n", str); usage(); } #endif } /* control multiple files */ int main(int argc, char *argv[]) { int ch, sdflag; //kflag = 1; #ifdef TIMING struct timeval t1, t2; (void)gettimeofday(&t1, NULL); #endif prgname = argv[0]; while ((ch = getopt(argc, argv, "OT:VW:X:Z:f:gkm:psvwx:")) != -1) { switch (ch) { #ifndef PASS2 case 'X': /* pass1 debugging */ while (*optarg) switch (*optarg++) { case 'b': ++bdebug; break; /* buildtree */ case 'd': ++ddebug; break; /* declarations */ case 'e': ++edebug; break; /* pass1 exit */ case 'i': ++idebug; break; /* initializations */ case 'n': ++ndebug; break; /* node allocation */ case 'o': ++odebug; break; /* optim */ case 'p': ++pdebug; break; /* prototype */ case 's': ++sdebug; break; /* inline */ case 't': ++tdebug; break; /* type match */ case 'x': ++xdebug; break; /* MD code */ default: fprintf(stderr, "unknown -X flag '%c'\n", optarg[-1]); exit(1); } break; #endif #ifndef PASS1 case 'Z': /* pass2 debugging */ while (*optarg) switch (*optarg++) { case 'b': /* basic block and SSA building */ ++b2debug; break; case 'c': /* code printout */ ++c2debug; break; case 'e': /* print tree upon pass2 enter */ ++e2debug; break; case 'f': /* instruction matching */ ++f2debug; break; case 'g': /* print flow graphs */ ++g2debug; break; case 'n': /* node allocation */ ++ndebug; break; case 'o': /* instruction generator */ ++o2debug; break; case 'r': /* register alloc/graph coloring */ ++r2debug; break; case 's': /* shape matching */ ++s2debug; break; case 't': /* type matching */ ++t2debug; break; case 'u': /* Sethi-Ullman debugging */ ++u2debug; break; case 'x': /* target specific */ ++x2debug; break; default: fprintf(stderr, "unknown -Z flag '%c'\n", optarg[-1]); exit(1); } break; #endif case 'f': /* Language */ fflags(optarg); break; case 'g': /* Debugging */ ++gflag; break; case 'k': /* PIC code */ ++kflag; break; case 'm': /* Target-specific */ mflags(optarg); break; case 'p': /* Profiling */ ++pflag; break; case 's': /* Statistics */ ++sflag; break; case 'w': /* No warnings emitted */ ++wdebug; break; case 'W': /* Enable different warnings */ Wflags(optarg); break; case 'x': /* Different settings */ xopt(optarg); break; case 'v': printf("ccom: %s\n", VERSSTR); break; case '?': default: usage(); } } argc -= optind; argv += optind; ftitle = xstrdup(""); if (argc > 0 && strcmp(argv[0], "-") != 0) { if (freopen(argv[0], "r", stdin) == NULL) { fprintf(stderr, "open input file '%s':", argv[0]); perror(NULL); exit(1); } } if (argc > 1 && strcmp(argv[1], "-") != 0) { if (freopen(argv[1], "w", stdout) == NULL) { fprintf(stderr, "open output file '%s':", argv[1]); perror(NULL); exit(1); } } mkdope(); signal(SIGSEGV, segvcatch); #ifdef SIGBUS signal(SIGBUS, segvcatch); #endif #ifndef PASS2 lineno = 1; sdflag = ddebug; ddebug = 0; flostat = FP_CONTR_CBR; #ifdef GCC_COMPAT gcc_init(); #endif /* starts past any of the above */ reached = 1; bjobcode(); #ifndef TARGET_VALIST { P1ND *p = block(NAME, NULL, NULL, PTR|CHAR, NULL, 0); struct symtab *sp = lookup(addname("__builtin_va_list"), 0); p->n_sp = sp; defid(p, TYPEDEF); p1nfree(p); } #endif complinit(); kwinit(); #ifndef NO_BUILTIN builtin_init(); #endif ddebug = sdflag; #ifdef DWARF if (gflag) dwarf_init(argc ? argv[0] : ""); #endif #ifdef STABS if (gflag) { stabs_file(argc ? argv[0] : ""); stabs_init(); } #endif if (sspflag) sspinit(); #endif /* PASS2 */ #ifndef PASS1 fregs = FREGS; /* number of free registers */ #ifdef PASS2 mainp2(); #endif #endif #ifndef PASS2 (void) yyparse(); yyaccpt(); if (!nerrors) { lcommprint(); #ifndef NO_STRING_SAVE strprint(); #endif } #endif #ifndef PASS2 #ifdef STABS if (gflag) stabs_efile(argc ? argv[0] : ""); #endif ejobcode( nerrors ? 1 : 0 ); #endif #ifdef TIMING (void)gettimeofday(&t2, NULL); t2.tv_sec -= t1.tv_sec; t2.tv_usec -= t1.tv_usec; if (t2.tv_usec < 0) { t2.tv_usec += 1000000; t2.tv_sec -= 1; } fprintf(stderr, "ccom total time: %ld s %ld us\n", t2.tv_sec, t2.tv_usec); #endif #ifdef DWARF if (gflag) dwarf_end(); #endif if (sflag) prtstats(); return(nerrors?1:0); } void prtstats(void) { #ifndef PASS2 extern int nametabs, namestrlen, treestrsz; extern int arglistcnt, dimfuncnt, inlstatcnt; extern int symtabcnt, suedefcnt, strtabs, strstrlen; extern int blkalloccnt, lcommsz, istatsz; extern int savstringsz, newattrsz, nodesszcnt, symtreecnt; #endif extern size_t permallocsize, tmpallocsize, lostmem; /* common allocations */ fprintf(stderr, "Permanent allocated memory: %zu B\n", permallocsize); fprintf(stderr, "Temporary allocated memory: %zu B\n", tmpallocsize); fprintf(stderr, "Lost memory: %zu B\n", lostmem); #ifndef PASS2 /* pass1 allocations */ fprintf(stderr, "Name table entries: %d pcs\n", nametabs); fprintf(stderr, "String table entries: %d pcs\n", strtabs); fprintf(stderr, "Argument list unions: %d pcs\n", arglistcnt); fprintf(stderr, "Dimension/function unions: %d pcs\n", dimfuncnt); fprintf(stderr, "Struct/union/enum blocks: %d pcs\n", suedefcnt); fprintf(stderr, "Inline control blocks: %d pcs\n", inlstatcnt); fprintf(stderr, "Permanent symtab entries: %d pcs\n", symtabcnt); fprintf(stderr, "\n"); fprintf(stderr, "Name table tree size: %d B\n", nametabs * treestrsz); fprintf(stderr, "Name string size: %d B\n", namestrlen); fprintf(stderr, "String table tree size: %d B\n", strtabs * treestrsz); fprintf(stderr, "String size: %d B\n", strstrlen); fprintf(stderr, "Inline control block size: %d B\n", inlstatcnt * istatsz); fprintf(stderr, "Argument list size: %d B\n", arglistcnt * (int)sizeof(union arglist)); fprintf(stderr, "Dimension/function size: %d B\n", dimfuncnt * (int)sizeof(union dimfun)); fprintf(stderr, "Permanent symtab size: %d B\n", symtabcnt * (int)sizeof(struct symtab)); fprintf(stderr, "Symtab tree size: %d B\n", symtreecnt * treestrsz); fprintf(stderr, "lcomm struct size: %d B\n", lcommsz); fprintf(stderr, "blkalloc size: %d B\n", blkalloccnt); fprintf(stderr, "(saved strings size): %d B\n", savstringsz); fprintf(stderr, "attribute size: %d B\n", newattrsz); fprintf(stderr, "nodes size: %d B\n", nodesszcnt); fprintf(stderr, "\n"); fprintf(stderr, "Not accounted for: %d B\n", (int)permallocsize-(nametabs * treestrsz)-namestrlen-strstrlen- (arglistcnt * (int)sizeof(union arglist))-(strtabs * treestrsz)- (dimfuncnt * (int)sizeof(union dimfun))-(inlstatcnt * istatsz)- (symtabcnt * (int)sizeof(struct symtab))-(symtreecnt * treestrsz)- lcommsz-blkalloccnt-newattrsz-nodesszcnt); #endif } pcc-20181216/cc/ccom/optim.c010064400017500000000000000266531274021755700143140ustar raggewheel/* $Id: optim.c,v 1.65 2016/07/09 15:59:43 ragge Exp $ */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code and documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditionsand the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ # include "pass1.h" #define NODE P1ND #define nfree p1nfree #define tfree p1tfree # define SWAP(p,q) {sp=p; p=q; q=sp;} # define RCON(p) (p->n_right->n_op==ICON) # define RO(p) p->n_right->n_op # define RV(p) glval(p->n_right) # define LCON(p) (p->n_left->n_op==ICON) # define LO(p) p->n_left->n_op # define LV(p) glval(p->n_left) /* remove left node */ static NODE * zapleft(NODE *p) { NODE *q; q = p->n_left; nfree(p->n_right); nfree(p); return q; } /* * fortran function arguments */ static NODE * fortarg(NODE *p) { if( p->n_op == CM ){ p->n_left = fortarg( p->n_left ); p->n_right = fortarg( p->n_right ); return(p); } while( ISPTR(p->n_type) ){ p = buildtree( UMUL, p, NIL ); } return( optim(p) ); } /* mapping relationals when the sides are reversed */ short revrel[] ={ EQ, NE, GE, GT, LE, LT, UGE, UGT, ULE, ULT }; /* * local optimizations, most of which are probably * machine independent */ NODE * optim(NODE *p) { int o, ty; NODE *sp, *q; OFFSZ sz; int i; if (odebug) return(p); ty = coptype(p->n_op); if( ty == LTYPE ) return(p); if( ty == BITYPE ) p->n_right = optim(p->n_right); p->n_left = optim(p->n_left); /* collect constants */ again: o = p->n_op; switch(o){ case SCONV: if (concast(p->n_left, p->n_type)) { q = p->n_left; nfree(p); p = q; break; } /* FALLTHROUGH */ case PCONV: if (p->n_type != VOID) p = clocal(p); break; case FORTCALL: p->n_right = fortarg( p->n_right ); break; case ADDROF: if (LO(p) == TEMP) break; if( LO(p) != NAME ) cerror( "& error" ); if( !andable(p->n_left) && !statinit) break; LO(p) = ICON; setuleft: /* paint over the type of the left hand side with the type of the top */ p->n_left->n_type = p->n_type; p->n_left->n_df = p->n_df; p->n_left->n_ap = p->n_ap; q = p->n_left; nfree(p); p = q; break; case NOT: case UMINUS: case COMPL: if (LCON(p) && conval(p->n_left, o, p->n_left)) p = nfree(p); break; case UMUL: /* Do not discard ADDROF TEMP's */ if (LO(p) == ADDROF && LO(p->n_left) != TEMP) { q = p->n_left->n_left; nfree(p->n_left); nfree(p); p = q; break; } if( LO(p) != ICON ) break; LO(p) = NAME; goto setuleft; case RS: if (LCON(p) && RCON(p) && conval(p->n_left, o, p->n_right)) goto zapright; sz = tsize(p->n_type, p->n_df, p->n_ap); if (LO(p) == RS && RCON(p->n_left) && RCON(p) && (RV(p) + RV(p->n_left)) < sz) { /* two right-shift by constants */ RV(p) += RV(p->n_left); p->n_left = zapleft(p->n_left); } #if 0 else if (LO(p) == LS && RCON(p->n_left) && RCON(p)) { RV(p) -= RV(p->n_left); if (RV(p) < 0) o = p->n_op = LS, RV(p) = -RV(p); p->n_left = zapleft(p->n_left); } #endif if (RO(p) == ICON) { if (RV(p) < 0) { RV(p) = -RV(p); p->n_op = LS; goto again; } #ifdef notyet /* must check for side effects, --a >> 32; */ if (RV(p) >= tsize(p->n_type, p->n_df, p->n_sue) && ISUNSIGNED(p->n_type)) { /* ignore signed shifts */ /* too many shifts */ tfree(p->n_left); nfree(p->n_right); p->n_op = ICON; p->n_lval = 0; p->n_sp = NULL; } else #endif /* avoid larger shifts than type size */ if (RV(p) >= sz) werror("shift larger than type"); if (RV(p) == 0) p = zapleft(p); } break; case LS: if (LCON(p) && RCON(p) && conval(p->n_left, o, p->n_right)) goto zapright; sz = tsize(p->n_type, p->n_df, p->n_ap); if (LO(p) == LS && RCON(p->n_left) && RCON(p)) { /* two left-shift by constants */ RV(p) += RV(p->n_left); p->n_left = zapleft(p->n_left); } #if 0 else if (LO(p) == RS && RCON(p->n_left) && RCON(p)) { RV(p) -= RV(p->n_left); p->n_left = zapleft(p->n_left); } #endif if (RO(p) == ICON) { if (RV(p) < 0) { RV(p) = -RV(p); p->n_op = RS; goto again; } #ifdef notyet /* must check for side effects */ if (RV(p) >= tsize(p->n_type, p->n_df, p->n_sue)) { /* too many shifts */ tfree(p->n_left); nfree(p->n_right); p->n_op = ICON; p->n_lval = 0; p->n_sp = NULL; } else #endif /* avoid larger shifts than type size */ if (RV(p) >= sz) werror("shift larger than type"); if (RV(p) == 0) p = zapleft(p); } break; case QUEST: if (!LCON(p)) break; if (LV(p) == 0) { q = p->n_right->n_right; } else { q = p->n_right->n_left; p->n_right->n_left = p->n_right->n_right; } p->n_right->n_op = UMUL; /* for tfree() */ p1walkf(p, putjops, 0); tfree(p); p = q; break; case MINUS: if (LCON(p) && RCON(p) && p->n_left->n_sp == p->n_right->n_sp) { /* link-time constants, but both are the same */ /* solve it now by forgetting the symbols */ p->n_left->n_sp = p->n_right->n_sp = NULL; } if( !nncon(p->n_right) ) break; RV(p) = -RV(p); o = p->n_op = PLUS; /* FALLTHROUGH */ case MUL: /* * Check for u=(x-y)+z; where all vars are pointers to * the same struct. This has two advantages: * 1: avoid a mul+div * 2: even if not allowed, people may get surprised if this * calculation do not give correct result if using * unaligned structs. */ if (o == MUL && p->n_type == INTPTR && RCON(p) && LO(p) == DIV && RCON(p->n_left) && RV(p) == RV(p->n_left) && LO(p->n_left) == MINUS) { q = p->n_left->n_left; if (q->n_left->n_type == PTR+STRTY && q->n_right->n_type == PTR+STRTY && strmemb(q->n_left->n_ap) == strmemb(q->n_right->n_ap)) { p = zapleft(p); p = zapleft(p); } } /* FALLTHROUGH */ case PLUS: case AND: case OR: case ER: /* commutative ops; for now, just collect constants */ /* someday, do it right */ if( nncon(p->n_left) || ( LCON(p) && !RCON(p) ) ) SWAP( p->n_left, p->n_right ); /* make ops tower to the left, not the right */ if( RO(p) == o ){ SWAP(p->n_left, p->n_right); #ifdef notdef /* Yetch, this breaks type correctness in trees */ /* Code was probably written before types */ /* All we can do here is swap and pray */ NODE *t1, *t2, *t3; t1 = p->n_left; sp = p->n_right; t2 = sp->n_left; t3 = sp->n_right; /* now, put together again */ p->n_left = sp; sp->n_left = t1; sp->n_right = t2; sp->n_type = p->n_type; p->n_right = t3; #endif } if(o == PLUS && LO(p) == MINUS && RCON(p) && RCON(p->n_left) && conval(p->n_right, MINUS, p->n_left->n_right)){ zapleft: q = p->n_left->n_left; nfree(p->n_left->n_right); nfree(p->n_left); p->n_left = q; } if( RCON(p) && LO(p)==o && RCON(p->n_left) && conval( p->n_right, o, p->n_left->n_right ) ){ goto zapleft; } else if( LCON(p) && RCON(p) && conval( p->n_left, o, p->n_right ) ){ zapright: nfree(p->n_right); q = makety(p->n_left, p->n_type, p->n_qual, p->n_df, p->n_ap); nfree(p); p = clocal(q); break; } /* change muls to shifts */ if( o == MUL && nncon(p->n_right) && (i=ispow2(RV(p)))>=0){ if( i == 0 ) { /* multiplication by 1 */ goto zapright; } o = p->n_op = LS; p->n_right->n_type = INT; p->n_right->n_df = NULL; RV(p) = i; } /* change +'s of negative consts back to - */ if( o==PLUS && nncon(p->n_right) && RV(p)<0 ){ RV(p) = -RV(p); o = p->n_op = MINUS; } /* remove ops with RHS 0 */ if ((o == PLUS || o == MINUS || o == OR || o == ER) && nncon(p->n_right) && RV(p) == 0) { goto zapright; } break; case DIV: if( nncon( p->n_right ) && glval(p->n_right) == 1 ) goto zapright; if (LCON(p) && RCON(p) && conval(p->n_left, DIV, p->n_right)) goto zapright; if (RCON(p) && ISUNSIGNED(p->n_type) && (i=ispow2(RV(p))) > 0) { p->n_op = RS; RV(p) = i; q = p->n_right; if(tsize(q->n_type, q->n_df, q->n_ap) > SZINT) p->n_right = makety(q, INT, 0, 0, 0); break; } break; case MOD: if (RCON(p) && ISUNSIGNED(p->n_type) && ispow2(RV(p)) > 0) { p->n_op = AND; RV(p) = RV(p) -1; break; } break; case EQ: case NE: case LT: case LE: case GT: case GE: case ULT: case ULE: case UGT: case UGE: if (LCON(p) && RCON(p) && !ISPTR(p->n_left->n_type) && !ISPTR(p->n_right->n_type)) { /* Do constant evaluation */ q = p->n_left; if (conval(q, o, p->n_right)) { nfree(p->n_right); nfree(p); p = q; break; } } if( !LCON(p) ) break; /* exchange operands */ sp = p->n_left; p->n_left = p->n_right; p->n_right = sp; p->n_op = revrel[p->n_op - EQ ]; break; case CBRANCH: if (LCON(p)) { if (LV(p) == 0) { tfree(p); p = bcon(0); } else { tfree(p->n_left); p->n_left = p->n_right; p->n_op = GOTO; } } break; #ifdef notyet case ASSIGN: /* Simple test to avoid two branches */ if (RO(p) != NE) break; q = p->n_right; if (RCON(q) && RV(q) == 0 && LO(q) == AND && RCON(q->n_left) && (i = ispow2(RV(q->n_left))) && q->n_left->n_type == INT) { q->n_op = RS; RV(q) = i; } break; #endif case ANDAND: if (!nncon(p->n_left)) break; if (LV(p) == 0) { /* right not evaluated */ p1walkf(p, putjops, 0); p1tfree(p); p = bcon(0); #ifdef notyet /* result may be logical value */ } else { q = p->n_right; nfree(nfree(p)); p = cast(q, INT, 0); #endif } break; case OROR: if (!nncon(p->n_left)) break; if (LV(p) != 0) { /* right not evaluated */ p1walkf(p, putjops, 0); p1tfree(p); p = bcon(1); #ifdef notyet /* result may be logical value */ } else { q = p->n_right; nfree(nfree(p)); p = cast(q, INT, 0); #endif } break; } return(p); } int ispow2(CONSZ c) { int i; if( c <= 0 || (c&(c-1)) ) return(-1); for( i=0; c>1; ++i) c >>= 1; return(i); } int nncon(NODE *p) { /* is p a constant without a name */ return( p->n_op == ICON && p->n_sp == NULL ); } pcc-20181216/cc/ccom/pass1.h010064400017500000000000000464131340102345600142000ustar raggewheel/* $Id: pass1.h,v 1.316 2018/12/02 18:40:46 ragge Exp $ */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code and documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditionsand the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include #include #include #ifdef HAVE_STDINT_H #include #endif #include #ifndef MKEXT #include "external.h" #else typedef unsigned int bittype; /* XXX - for basicblock */ #endif #include "manifest.h" #include "softfloat.h" /* * Storage classes */ #define SNULL 0 #define AUTO 1 #define EXTERN 2 #define STATIC 3 #define REGISTER 4 #define EXTDEF 5 #define THLOCAL 6 #define KEYWORD 7 #define MOS 8 #define PARAM 9 #define STNAME 10 #define MOU 11 #define UNAME 12 #define TYPEDEF 13 /* #define FORTRAN 14 */ #define ENAME 15 #define MOE 16 /* #define UFORTRAN 17 */ #define USTATIC 18 /* field size is ORed in */ #define FIELD 0200 #define FLDSIZ 0177 extern char *scnames(int); /* * Symbol table flags */ #define SNORMAL 0 #define STAGNAME 01 #define SLBLNAME 02 #define SMOSNAME 03 #define SSTRING 04 #define NSTYPES 05 #define SMASK 07 #define STLS 00010 /* Thread Local Support variable */ #define SINSYS 00020 /* Declared in system header */ #define SSTMT SINSYS /* Allocate symtab on statement stack */ #define SNOCREAT 00040 /* don't create a symbol in lookup() */ #define STEMP 00100 /* Allocate symtab from temp or perm mem */ #define SDYNARRAY 00200 /* symbol is dynamic array on stack */ #define SINLINE 00400 /* function is of type inline */ #define SBLK SINLINE /* Allocate symtab from blk mem */ #define STNODE 01000 /* symbol shall be a temporary node */ #define SBUILTIN 02000 /* this is a builtin function */ #define SASG 04000 /* symbol is assigned to already */ #define SINREG 010000 /* variable is put in reg */ /* alignment of initialized quantities */ #ifndef AL_INIT #define AL_INIT ALINT #endif struct rstack; struct symtab; union arglist; #ifdef GCC_COMPAT struct gcc_attr_pack; #endif /* * Dimension/prototype information. * ddim > 0 holds the dimension of an array. * ddim < 0 is a dynamic array and refers to a tempnode. * ...unless: * ddim == NOOFFSET, an array without dimenston, "[]" * ddim == -1, dynamic array while building before defid. */ union dimfun { int ddim; /* Dimension of an array */ union arglist *dfun; /* Prototype index */ }; /* * Argument list member info when storing prototypes. */ union arglist { TWORD type; union dimfun *df; struct attr *sap; }; #define TNULL INCREF(FARG) /* pointer to FARG -- impossible type */ #define TELLIPSIS INCREF(INCREF(FARG)) /* * Symbol table definition. */ struct symtab { struct symtab *snext; /* link to other symbols in the same scope */ int soffset; /* offset or value */ char sclass; /* storage class */ char slevel; /* scope level */ short sflags; /* flags, see below */ char *sname; /* Symbol name */ TWORD stype; /* type word */ TWORD squal; /* qualifier word */ union dimfun *sdf; /* ptr to the dimension/prototype array */ struct attr *sap; /* the base type attribute list */ }; #define ISSOU(ty) ((ty) == STRTY || (ty) == UNIONTY) /* * External definitions */ struct swents { /* switch table */ struct swents *next; /* Next struct in linked list */ CONSZ sval; /* case value */ int slab; /* associated label */ }; int mygenswitch(int, TWORD, struct swents **, int); extern int blevel; extern int oldstyle; extern int lineno, nerrors, issyshdr; extern char *ftitle; extern struct symtab *cftnsp; extern int autooff, maxautooff, argoff; extern OFFSZ inoff; extern int reached; extern int isinlining; extern int xinline, xgnu89, xgnu99; extern int bdebug, ddebug, edebug, idebug, ndebug; extern int odebug, pdebug, sdebug, tdebug, xdebug; /* various labels */ extern int brklab; extern int contlab; extern int flostat, fp_contract; extern int retlab; extern int doing_init, statinit; extern short sztable[]; extern char *astypnames[]; /* pragma globals */ extern int pragma_allpacked, pragma_packed, pragma_aligned; /* * Flags used in the (elementary) flow analysis ... */ #define FBRK 02 #define FCONT 04 #define FDEF 010 #define FLOOP 020 #define FP_CONTR_CBR 040 /* use same flag field */ /* * Location counters */ #define NOSEG -1 #define PROG 0 /* (ro) program segment */ #define DATA 1 /* (rw) data segment */ #define RDATA 2 /* (ro) data segment */ #define LDATA 3 /* (rw) local data */ #define UDATA 4 /* (rw) uninitialized data */ #define STRNG 5 /* (ro) string segment */ #define PICDATA 6 /* (rw) relocatable data segment */ #define PICRDATA 7 /* (ro) relocatable data segment */ #define PICLDATA 8 /* (rw) local relocatable data */ #define TLSDATA 9 /* (rw) TLS data segment */ #define TLSUDATA 10 /* (rw) TLS uninitialized segment */ #define CTORS 11 /* constructor */ #define DTORS 12 /* destructor */ #define NMSEG 13 /* other (named) segment */ extern int lastloc; void locctr(int type, struct symtab *sp); void setseg(int type, char *name); void defalign(int al); void symdirec(struct symtab *sp); /* * Tree struct for pass1. */ struct flt; typedef struct p1node { int n_op; TWORD n_type; TWORD n_qual; union { char * _name; union dimfun *_df; } n_5; struct attr *n_ap; union { struct { union { struct p1node *_left; CONSZ _val; } n_l; union { struct p1node *_right; int _rval; struct symtab *_sp; } n_r; } n_u; struct softfloat *_scon; } n_f; } P1ND; #define glval(p) ((p)->n_f.n_u.n_l._val) #define slval(p,v) ((p)->n_f.n_u.n_l._val = (v)) #define n_ccon n_f._ccon #define n_scon n_f._scon /* mark an offset which is undefined */ #define NOOFFSET (-10201) /* declarations of various functions */ extern P1ND *buildtree(int, P1ND *, P1ND *r), *mkty(unsigned, union dimfun *, struct attr *), *rstruct(char *, int), *dclstruct(struct rstack *), *strend(char *, TWORD), *tymerge(P1ND *, P1ND *), *stref(P1ND *), #ifdef WORD_ADDRESSED *offcon(OFFSZ, TWORD, union dimfun *, struct attr *), #endif *bcon(int), *xbcon(CONSZ, struct symtab *, TWORD), *bpsize(P1ND *), *convert(P1ND *, int), *pconvert(P1ND *), *oconvert(P1ND *), *ptmatch(P1ND *), *makety(P1ND *, TWORD, TWORD, union dimfun *, struct attr *), *block(int, P1ND *, P1ND *, TWORD, union dimfun *, struct attr *), *doszof(P1ND *), *p1alloc(void), *optim(P1ND *), *clocal(P1ND *), *tempnode(int, TWORD, union dimfun *, struct attr *), *eve(P1ND *), *doacall(struct symtab *, P1ND *, P1ND *); P1ND *intprom(P1ND *); OFFSZ tsize(TWORD, union dimfun *, struct attr *), psize(P1ND *); P1ND * typenode(P1ND *new); void spalloc(P1ND *, P1ND *, OFFSZ); char *exname(char *); struct flt floatcon(char *); struct flt fhexcon(char *); P1ND *bdty(int op, ...); extern struct rstack *rpole; int oalloc(struct symtab *, int *); void deflabel(char *, P1ND *); void gotolabel(char *); unsigned int esccon(char **); void inline_start(struct symtab *, int class); void inline_end(void); void inline_addarg(struct interpass *); void inline_ref(struct symtab *); void inline_prtout(void); void inline_args(struct symtab **, int); P1ND *inlinetree(struct symtab *, P1ND *, P1ND *); void ftnarg(P1ND *); struct rstack *bstruct(char *, int, P1ND *); void moedef(char *); void beginit(struct symtab *); void simpleinit(struct symtab *, P1ND *); struct symtab *lookup(char *, int); struct symtab *getsymtab(char *, int); char *addstring(char *); char *addname(char *); void symclear(int); struct symtab *hide(struct symtab *); void soumemb(P1ND *, char *, int); int talign(unsigned int, struct attr *); void bfcode(struct symtab **, int); int chkftn(union arglist *, union arglist *); void branch(int); void cbranch(P1ND *, P1ND *); void extdec(struct symtab *); void defzero(struct symtab *); int falloc(struct symtab *, int, P1ND *); TWORD ctype(TWORD); void inval(CONSZ, int, P1ND *); int ninval(CONSZ, int, P1ND *); void infld(CONSZ, int, CONSZ); void zbits(CONSZ, int); void instring(struct symtab *); void inwstring(struct symtab *); void plabel(int); void bjobcode(void); void ejobcode(int); void calldec(P1ND *, P1ND *); int cisreg(TWORD); void asginit(P1ND *); void desinit(P1ND *); void endinit(int); void endictx(void); void sspinit(void); void sspstart(void); void sspend(void); void ilbrace(void); void irbrace(void); CONSZ scalinit(P1ND *); void p1print(char *, ...); char *copst(int); int cdope(int); void myp2tree(P1ND *); void lcommprint(void), strprint(void); void lcommdel(struct symtab *); P1ND *funcode(P1ND *); struct symtab *enumhd(char *); P1ND *enumdcl(struct symtab *); P1ND *enumref(char *); CONSZ icons(P1ND *); CONSZ valcast(CONSZ v, TWORD t); int mypragma(char *); char *pragtok(char *); int eat(int); void fixdef(struct symtab *); int cqual(TWORD, TWORD); void defloc(struct symtab *); int fldchk(int); int nncon(P1ND *); void cunput(char); P1ND *nametree(struct symtab *sp); void pass1_lastchance(struct interpass *); void fldty(struct symtab *p); struct suedef *sueget(struct suedef *p); void complinit(void); void kwinit(void); P1ND *structref(P1ND *p, int f, char *name); P1ND *cxop(int op, P1ND *l, P1ND *r); P1ND *imop(int op, P1ND *l, P1ND *r); P1ND *cxelem(int op, P1ND *p); P1ND *cxconj(P1ND *p); P1ND *cxcast(P1ND *p1, P1ND *p2); P1ND *cxret(P1ND *p, P1ND *q); P1ND *imret(P1ND *p, P1ND *q); P1ND *cast(P1ND *p, TWORD t, TWORD q); P1ND *ccast(P1ND *p, TWORD t, TWORD u, union dimfun *df, struct attr *sue); int andable(P1ND *); int conval(P1ND *, int, P1ND *); int ispow2(CONSZ); void defid(P1ND *q, int class); void defid2(P1ND *q, int class, char *astr); void efcode(void); void ecomp(P1ND *p); int upoff(int size, int alignment, int *poff); void nidcl(P1ND *p, int class); void nidcl2(P1ND *p, int class, char *astr); void eprint(P1ND *, int, int *, int *); int uclass(int class); int notlval(P1ND *); void ecode(P1ND *p); void ftnend(void); void dclargs(void); int suemeq(struct attr *s1, struct attr *s2); struct symtab *strmemb(struct attr *ap); int yylex(void); void yyerror(char *); int pragmas_gcc(char *t); int concast(P1ND *p, TWORD t); char *stradd(char *old, char *new); #ifdef WORD_ADDRESSED #define rmpconv(p) (p) #else P1ND *rmpconv(P1ND *); #endif P1ND *optloop(P1ND *); P1ND *nlabel(int label); TWORD styp(void); void *stmtalloc(size_t); void *blkalloc(size_t); void stmtfree(void); void blkfree(void); char *getexname(struct symtab *sp); void putjops(P1ND *p, void *arg); void p1walkf(P1ND *, void (*f)(P1ND *, void *), void *); void p1fwalk(P1ND *t, void (*f)(P1ND *, int, int *, int *), int down); void p1listf(P1ND *p, void (*f)(P1ND *)); void p1flist(P1ND *p, void (*f)(P1ND *, void *), void *); P1ND *p1nfree(P1ND *); void p1tfree(P1ND *); P1ND *p1tcopy(P1ND *); struct flt { struct softfloat sf; TWORD t; }; typedef struct flt FLT; #define sfallo() stmtalloc(sizeof(struct softfloat)) /* * Only allowed to do float evaluation if either doing * static (compile-time) initialization or FP_CONTRACT is YES. */ #define CAN_EVAL_FLOAT() (statinit || (flostat & FP_CONTR_CBR)) #define FLOAT_ISZERO(p) soft_isz(p) #define FLOAT_NEG(p) soft_neg(p) #define FLOAT_FP2FP(f,t) soft_fp2fp(f, t) #define FLOAT_EQ(d1,d2) soft_cmp(d1, d2, EQ) #define FLOAT_NE(d1,d2) soft_cmp(d1, d2, NE) #define FLOAT_GT(d1,d2) soft_cmp(d1, d2, GT) #define FLOAT_GE(d1,d2) soft_cmp(d1, d2, GE) #define FLOAT_LE(d1,d2) soft_cmp(d1, d2, LE) #define FLOAT_LT(d1,d2) soft_cmp(d1, d2, LT) #define FLOAT_INT2FP(f,p,t) soft_int2fp(f, p, t, ctype(LDOUBLE)) #define FLOAT_FP2INT(i,d,t) i = soft_fp2int(d, t) #define FLOAT_PLUS(p1,p2) \ soft_plus(p1->n_scon, p2->n_scon, p1->n_type) #define FLOAT_MINUS(p1,p2) \ soft_minus(p1->n_scon, p2->n_scon, p1->n_type) #define FLOAT_MUL(p1,p2) \ soft_mul(p1->n_scon, p2->n_scon, p1->n_type) #define FLOAT_DIV(p1,p2) \ soft_div(p1->n_scon, p2->n_scon, p1->n_type) enum { ATTR_FIRST = ATTR_MI_MAX + 1, /* PCC used attributes */ ATTR_COMPLEX, /* Internal definition of complex */ xxxATTR_BASETYP, /* Internal; see below */ ATTR_QUALTYP, /* Internal; const/volatile, see below */ ATTR_ALIGNED, /* Internal; also used as gcc type attribute */ ATTR_NORETURN, /* Function does not return */ ATTR_STRUCT, /* Internal; element list */ #define ATTR_MAX ATTR_STRUCT ATTR_P1LABELS, /* used to store stuff while parsing */ ATTR_SONAME, /* output name of symbol */ #ifdef GCC_COMPAT /* type attributes */ GCC_ATYP_PACKED, GCC_ATYP_SECTION, GCC_ATYP_TRANSP_UNION, GCC_ATYP_UNUSED, GCC_ATYP_DEPRECATED, GCC_ATYP_MAYALIAS, /* variable attributes */ GCC_ATYP_MODE, /* function attributes */ GCC_ATYP_FORMAT, GCC_ATYP_NONNULL, GCC_ATYP_SENTINEL, GCC_ATYP_WEAK, GCC_ATYP_FORMATARG, GCC_ATYP_GNU_INLINE, GCC_ATYP_MALLOC, GCC_ATYP_NOTHROW, GCC_ATYP_CONST, GCC_ATYP_PURE, GCC_ATYP_CONSTRUCTOR, GCC_ATYP_DESTRUCTOR, GCC_ATYP_VISIBILITY, GCC_ATYP_WARN_UNUSED_RESULT, GCC_ATYP_USED, GCC_ATYP_NO_INSTR_FUN, GCC_ATYP_NOINLINE, GCC_ATYP_ALIAS, GCC_ATYP_WEAKREF, GCC_ATYP_ALLOCSZ, GCC_ATYP_ALW_INL, GCC_ATYP_TLSMODEL, GCC_ATYP_ALIASWEAK, GCC_ATYP_RETURNS_TWICE, GCC_ATYP_WARNING, GCC_ATYP_NOCLONE, GCC_ATYP_REGPARM, GCC_ATYP_FASTCALL, /* other stuff */ GCC_ATYP_BOUNDED, /* OpenBSD extra boundary checks */ /* OSX toolchain */ GCC_ATYP_WEAKIMPORT, GCC_ATYP_MAX, #endif #ifdef ATTR_P1_TARGET ATTR_P1_TARGET, #endif ATTR_P1_MAX }; /* #ifdef notdef * ATTR_BASETYP has the following layout: * aa[0].iarg has size * aa[1].iarg has alignment #endif * ATTR_QUALTYP has the following layout: * aa[0].iarg has CON/VOL + FUN/ARY/PTR * Not defined yet... * aa[3].iarg is dimension for arrays (XXX future) * aa[3].varg is function defs for functions. */ #ifdef notdef #define atypsz aa[0].iarg #define aalign aa[1].iarg #endif /* * ATTR_STRUCT member list. */ #define amlist aa[0].varg #define amsize aa[1].iarg #define strattr(x) (attr_find(x, ATTR_STRUCT)) void gcc_init(void); int gcc_keyword(char *); struct attr *gcc_attr_parse(P1ND *); void gcc_tcattrfix(P1ND *); struct gcc_attrib *gcc_get_attr(struct suedef *, int); void dump_attr(struct attr *gap); void gcc_modefix(P1ND *); P1ND *gcc_eval_timode(int op, P1ND *, P1ND *); P1ND *gcc_eval_ticast(int op, P1ND *, P1ND *); P1ND *gcc_eval_tiuni(int op, P1ND *); struct attr *isti(P1ND *p); #ifndef NO_C_BUILTINS struct bitable { char *name; P1ND *(*fun)(const struct bitable *, P1ND *a); short flags; #define BTNOPROTO 001 #define BTNORVAL 002 #define BTNOEVE 004 #define BTGNUONLY 010 short narg; TWORD *tp; TWORD rt; }; P1ND *builtin_check(struct symtab *, P1ND *a); void builtin_init(void); /* Some builtins targets need to implement */ P1ND *builtin_frame_address(const struct bitable *bt, P1ND *a); P1ND *builtin_return_address(const struct bitable *bt, P1ND *a); P1ND *builtin_cfa(const struct bitable *bt, P1ND *a); #endif #ifdef STABS void stabs_init(void); void stabs_file(char *); void stabs_efile(char *); void stabs_line(int); void stabs_rbrac(int); void stabs_lbrac(int); void stabs_func(struct symtab *); void stabs_newsym(struct symtab *); void stabs_chgsym(struct symtab *); void stabs_struct(struct symtab *, struct attr *); #endif #ifdef DWARF void dwarf_init(char *); void dwarf_file(char *); void dwarf_end(void); #endif #ifndef CHARCAST /* to make character constants into character connstants */ /* this is a macro to defend against cross-compilers, etc. */ #define CHARCAST(x) (char)(x) #endif /* sometimes int is smaller than pointers */ #if SZPOINT(CHAR) <= SZINT #define INTPTR INT #elif SZPOINT(CHAR) <= SZLONG #define INTPTR LONG #elif SZPOINT(CHAR) <= SZLONGLONG #define INTPTR LONGLONG #else #error int size unknown #endif /* Generate a bitmask from a given type size */ #define SZMASK(y) ((((1LL << ((y)-1))-1) << 1) | 1) /* * finction specifiers. */ #define INLINE 1 #define NORETURN 2 /* * C compiler first pass extra defines. */ #define QUALIFIER (MAXOP+1) #define CLASS (MAXOP+2) #define RB (MAXOP+3) #define DOT (MAXOP+4) #define ELLIPSIS (MAXOP+5) #define TYPE (MAXOP+6) #define LB (MAXOP+7) #define COMOP (MAXOP+8) #define QUEST (MAXOP+9) #define COLON (MAXOP+10) #define ANDAND (MAXOP+11) #define OROR (MAXOP+12) #define NOT (MAXOP+13) #define CAST (MAXOP+14) #define STRING (MAXOP+15) /* The following must be in the same order as their NOASG counterparts */ #define PLUSEQ (MAXOP+16) #define MINUSEQ (MAXOP+17) #define DIVEQ (MAXOP+18) #define MODEQ (MAXOP+19) #define MULEQ (MAXOP+20) #define ANDEQ (MAXOP+21) #define OREQ (MAXOP+22) #define EREQ (MAXOP+23) #define LSEQ (MAXOP+24) #define RSEQ (MAXOP+25) #define UNASG (-(PLUSEQ-PLUS))+ #define INCR (MAXOP+26) #define DECR (MAXOP+27) #define SZOF (MAXOP+28) #define CLOP (MAXOP+29) #define ATTRIB (MAXOP+30) #define XREAL (MAXOP+31) #define XIMAG (MAXOP+32) #define TYMERGE (MAXOP+33) #define LABEL (MAXOP+34) #define BIQUEST (MAXOP+35) #define UPLUS (MAXOP+36) #define ALIGN (MAXOP+37) #define FUNSPEC (MAXOP+38) #define STREF (MAXOP+39) /* * The following types are only used in pass1. */ #define SIGNED (MAXTYPES+1) #define FARG (MAXTYPES+2) #define FIMAG (MAXTYPES+3) #define IMAG (MAXTYPES+4) #define LIMAG (MAXTYPES+5) #define FCOMPLEX (MAXTYPES+6) #define COMPLEX (MAXTYPES+7) #define LCOMPLEX (MAXTYPES+8) #define ENUMTY (MAXTYPES+9) #define ISFTY(x) ((x) >= FLOAT && (x) <= LDOUBLE) #define ISCTY(x) ((x) >= FCOMPLEX && (x) <= LCOMPLEX) #define ISITY(x) ((x) >= FIMAG && (x) <= LIMAG) #define ANYCX(p) (p->n_type == STRTY && attr_find(p->n_ap, ATTR_COMPLEX)) #define coptype(o) (cdope(o)&TYFLG) #define clogop(o) (cdope(o)&LOGFLG) #define casgop(o) (cdope(o)&ASGFLG) #ifdef TWOPASS #define PRTPREF "* " #else #define PRTPREF "" #endif /* * Allocation routines. */ #if defined(__PCC__) || defined(__GNUC__) #define FUNALLO(x) __builtin_alloca(x) #define FUNFREE(x) #elif defined(HAVE_ALLOCA) #define FUNALLO(x) alloca(x) #define FUNFREE(x) #else #define FUNALLO(x) malloc(x) #define FUNFREE(x) free(x) #endif pcc-20181216/cc/ccom/pftn.c010064400017500000000000002233271340102345600141140ustar raggewheel/* $Id: pftn.c,v 1.430 2018/12/02 18:40:46 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code and documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditionsand the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Many changes from the 32V sources, among them: * - New symbol table manager (moved to another file). * - Prototype saving/checks. */ # include "pass1.h" #include "unicode.h" #include #include #include "cgram.h" #define NODE P1ND #define tfree p1tfree #define nfree p1nfree #define ccopy p1tcopy #define flist p1flist #define fwalk p1fwalk struct symtab *cftnsp; int arglistcnt, dimfuncnt; /* statistics */ int symtabcnt, suedefcnt; /* statistics */ int lcommsz, blkalloccnt; int autooff, /* the next unused automatic offset */ maxautooff, /* highest used automatic offset in function */ argoff; /* the next unused argument offset */ int retlab = NOLAB; /* return label for subroutine */ int brklab; int contlab; int flostat; int blevel; int reached, prolab; struct params; #define MKTY(p, t, d, s) r = p1alloc(); *r = *p; \ r = argcast(r, t, d, s); *p = *r; nfree(r); /* * Linked list stack while reading in structs. */ struct rstack { struct rstack *rnext; int rsou; int rstr; struct symtab *rsym; struct symtab *rb; struct attr *ap; int flags; #define LASTELM 1 } *rpole; /* * Linked list for parameter (and struct elements) declaration. */ static struct params { struct params *prev; struct symtab *sym; } *lparam; static int nparams; /* defines used for getting things off of the initialization stack */ NODE *arrstk[10]; int arrstkp; static int intcompare; NODE *parlink; void fixtype(NODE *p, int class); int fixclass(int class, TWORD type); static void dynalloc(struct symtab *p, int *poff); static void evalidx(struct symtab *p); int isdyn(struct symtab *p); void inforce(OFFSZ n); void vfdalign(int n); static void ssave(struct symtab *); #ifdef PCC_DEBUG static void alprint(union arglist *al, int in); #endif static void lcommadd(struct symtab *sp); static NODE *mkcmplx(NODE *p, TWORD dt); static void cxargfixup(NODE *arg, TWORD dt, struct attr *ap); extern int fun_inline; void defid(NODE *q, int class) { defid2(q, class, 0); } static void addsoname(struct symtab *sp, char *so) { struct attr *ap = attr_new(ATTR_SONAME, 1); ap->sarg(0) = so; sp->sap = attr_add(sp->sap, ap); } /* * Declaration of an identifier. Handles redeclarations, hiding, * incomplete types and forward declarations. * * q is a TYPE node setup after parsing with n_type, n_df and n_ap. * n_sp is a pointer to the not-yet initalized symbol table entry * unless it's a redeclaration or supposed to hide a variable. */ void defid2(NODE *q, int class, char *astr) { struct attr *ap; struct symtab *p; TWORD type, qual; TWORD stp, stq; int scl; union dimfun *dsym, *ddef; int slev, temp, changed; if (q == NIL) return; /* an error was detected */ #ifdef GCC_COMPAT gcc_modefix(q); #endif p = q->n_sp; if (p->sname == NULL) cerror("defining null identifier"); #ifdef PCC_DEBUG if (ddebug) { printf("defid(%s '%s'(%p), ", p->sname, "soname" , p); tprint(q->n_type, q->n_qual); printf(", %s, (%p)), level %d\n\t", scnames(class), q->n_df, blevel); #ifdef GCC_COMPAT dump_attr(q->n_ap); #endif } #endif fixtype(q, class); type = q->n_type; qual = q->n_qual; class = fixclass(class, type); stp = p->stype; stq = p->squal; slev = p->slevel; #ifdef PCC_DEBUG if (ddebug) { printf(" modified to "); tprint(type, qual); printf(", %s\n", scnames(class)); printf(" previous def'n: "); tprint(stp, stq); printf(", %s, (%p,%p)), level %d\n", scnames(p->sclass), p->sdf, p->sap, slev); } #endif if (blevel == 1) { switch (class) { default: if (!(class&FIELD) && !ISFTN(type)) uerror("declared argument %s missing", p->sname ); break; case MOS: case MOU: cerror("field5"); case TYPEDEF: case PARAM: break; } } if (stp == UNDEF) goto enter; /* New symbol */ if (type != stp) goto mismatch; if (blevel > slev && (class == AUTO || class == REGISTER)) /* new scope */ goto mismatch; /* * test (and possibly adjust) dimensions. * also check that prototypes are correct. */ dsym = p->sdf; ddef = q->n_df; changed = 0; for (temp = type; temp & TMASK; temp = DECREF(temp)) { if (ISARY(temp)) { if (dsym->ddim == NOOFFSET) { dsym->ddim = ddef->ddim; changed = 1; } else if (ddef->ddim != NOOFFSET && dsym->ddim!=ddef->ddim) { goto mismatch; } ++dsym; ++ddef; } else if (ISFTN(temp)) { /* add a late-defined prototype here */ if (!oldstyle && dsym->dfun == NULL) dsym->dfun = ddef->dfun; if (!oldstyle && ddef->dfun != NULL && chkftn(dsym->dfun, ddef->dfun)) uerror("declaration doesn't match prototype"); dsym++, ddef++; } } #ifdef STABS if (changed && gflag) stabs_chgsym(p); /* symbol changed */ #endif /* check that redeclarations are to the same structure */ if (temp == STRTY || temp == UNIONTY) { if (strmemb(p->sap) != strmemb(q->n_ap)) goto mismatch; } scl = p->sclass; #ifdef PCC_DEBUG if (ddebug) printf(" previous class: %s\n", scnames(scl)); #endif /* * Its allowed to add attributes to existing declarations. * Be careful though not to trash existing attributes. * XXX - code below is probably not correct. */ if (p->sap && p->sap->atype <= ATTR_MAX) { /* nothing special, just overwrite */ p->sap = q->n_ap; } else { if (p->slevel == blevel) { for (ap = q->n_ap; ap; ap = ap->next) { if (ap->atype > ATTR_MAX) p->sap = attr_add(p->sap, attr_dup(ap)); } } else p->sap = q->n_ap; } if (class & FIELD) cerror("field1"); switch(class) { case EXTERN: if (astr) addsoname(p, astr); switch( scl ){ case STATIC: case USTATIC: if( slev==0 ) goto done; break; case EXTDEF: case EXTERN: goto done; case SNULL: if (p->sflags & SINLINE) { p->sclass = EXTDEF; inline_ref(p); goto done; } break; } break; case STATIC: if (astr) addsoname(p, astr); if (scl==USTATIC || (scl==EXTERN && blevel==0)) { p->sclass = STATIC; goto done; } if (changed || (scl == STATIC && blevel == slev)) goto done; /* identical redeclaration */ break; case USTATIC: if (scl==STATIC || scl==USTATIC) goto done; break; case TYPEDEF: if (scl == class) goto done; break; case MOU: case MOS: cerror("field6"); case EXTDEF: switch (scl) { case EXTERN: p->sclass = EXTDEF; goto done; case USTATIC: p->sclass = STATIC; goto done; case SNULL: #ifdef GCC_COMPAT /* * Handle redeclarations of inlined functions. * This is allowed if the previous declaration is of * type gnu_inline. */ if (attr_find(p->sap, GCC_ATYP_GNU_INLINE)) goto done; #endif break; } break; case AUTO: case REGISTER: break; /* mismatch.. */ case SNULL: if (fun_inline && ISFTN(type)) { if (scl == EXTERN) { p->sclass = EXTDEF; inline_ref(p); } goto done; } break; } mismatch: /* * Only allowed for automatic variables. */ if ((blevel == 2 && slev == 1) || blevel <= slev || class == EXTERN) { uerror("redeclaration of %s", p->sname); return; } if ((ISFTN(p->stype) && ISFTN(type)) || (!ISFTN(p->stype) && !ISFTN(type))) warner(Wshadow, p->sname, p->slevel ? "local" : "global"); q->n_sp = p = hide(p); enter: /* make a new entry */ if (type == VOID && class != TYPEDEF) uerror("void not allowed for variables"); #ifdef PCC_DEBUG if(ddebug) printf(" new entry made\n"); #endif p->stype = type; p->squal = qual; p->sclass = (char)class; p->slevel = (char)blevel; p->soffset = NOOFFSET; if (q->n_ap) p->sap = attr_add(q->n_ap, p->sap); /* copy dimensions */ p->sdf = q->n_df; /* Do not save param info for old-style functions */ if (ISFTN(type) && oldstyle) p->sdf->dfun = NULL; if (arrstkp) evalidx(p); /* allocate offsets */ if (class&FIELD) { cerror("field2"); /* new entry */ } else switch (class) { case REGISTER: p->sclass = class = AUTO; if (astr != NULL) { #ifdef GCC_COMPAT if (blevel == 0) werror("no register assignment (yet)"); else if (astr != NULL) { int i; for (i = 0; i < MAXREGS; i++) { extern char *rnames[]; /* XXX */ if (strcmp(rnames[i], astr) == 0) { p->sflags |= SINREG; p->soffset = i; break; } } if (i != MAXREGS) break; werror("reg '%s' invalid", astr); } #endif } /* FALLTHROUGH */ case AUTO: if (isdyn(p)) { p->sflags |= SDYNARRAY; dynalloc(p, &autooff); } else oalloc(p, &autooff); break; case PARAM: if (q->n_type != FARG) oalloc(p, &argoff); break; case STATIC: case EXTDEF: case EXTERN: p->soffset = getlab(); /* FALLTHROUGH */ case USTATIC: if (astr) addsoname(p, astr); break; case MOU: case MOS: cerror("field7"); case SNULL: #ifdef notdef if (fun_inline) { p->slevel = 1; p->soffset = getlab(); } #endif break; } #ifdef STABS if (gflag && p->stype != FARG) stabs_newsym(p); #endif done: fixdef(p); /* Leave last word to target */ #ifndef HAVE_WEAKREF { struct attr *at; /* Refer renamed function */ if ((at = attr_find(p->sap, GCC_ATYP_WEAKREF))) addsoname(p, at->sarg(0)); } #endif #ifdef PCC_DEBUG if (ddebug) { printf( " sdf, offset: %p, %d\n\t", p->sdf, p->soffset); #ifdef GCC_COMPAT dump_attr(p->sap); #endif } #endif } void ssave(struct symtab *sym) { struct params *p; p = tmpalloc(sizeof(struct params)); p->prev = lparam; p->sym = sym; lparam = p; } /* * end of function */ void ftnend(void) { #ifdef GCC_COMPAT struct attr *gc, *gd; #endif extern int *mkclabs(void); extern NODE *cftnod; extern struct savbc *savbc; extern struct swdef *swpole; extern int tvaloff; char *c; if (retlab != NOLAB && nerrors == 0) { /* inside a real function */ plabel(retlab); if (cftnod) ecomp(buildtree(FORCE, p1tcopy(cftnod), NIL)); efcode(); /* struct return handled here */ c = getexname(cftnsp); SETOFF(maxautooff, ALCHAR); send_passt(IP_EPILOG, maxautooff/SZCHAR, c, cftnsp->stype, cftnsp->sclass == EXTDEF, retlab, tvaloff, mkclabs()); } cftnod = NIL; tcheck(); brklab = contlab = retlab = NOLAB; flostat &= FP_CONTR_CBR; if (nerrors == 0) { if (savbc != NULL) cerror("bcsave error"); if (lparam != NULL) cerror("parameter reset error"); if (swpole != NULL) cerror("switch error"); } #ifdef GCC_COMPAT if (cftnsp) { gc = attr_find(cftnsp->sap, GCC_ATYP_CONSTRUCTOR); gd = attr_find(cftnsp->sap, GCC_ATYP_DESTRUCTOR); if (gc || gd) { struct symtab sts = *cftnsp; NODE *p; sts.stype = INCREF(sts.stype); p = nametree(&sts); p->n_op = ICON; if (gc) { locctr(CTORS, NULL); inval(0, SZPOINT(0), p); } if (gd) { locctr(DTORS, NULL); inval(0, SZPOINT(0), p); } tfree(p); } } #endif savbc = NULL; lparam = NULL; cftnsp = NULL; maxautooff = autooff = AUTOINIT; reached = 1; if (isinlining) inline_end(); inline_prtout(); tmpfree(); /* Release memory resources */ } static struct symtab nulsym = { NULL, 0, 0, 0, 0, "null", INT, 0, NULL, NULL }; void dclargs(void) { union dimfun *df; union arglist *al; struct params *a; struct symtab *p, **parr = NULL; /* XXX gcc */ int i; /* * Deal with fun(void) properly. */ if (nparams == 1 && lparam->sym && lparam->sym->stype == VOID) goto done; /* * Generate a list for bfcode(). * Parameters were pushed in reverse order. */ if (nparams != 0) parr = FUNALLO(sizeof(struct symtab *) * nparams); if (nparams) for (a = lparam, i = 0; a != NULL; a = a->prev) { p = a->sym; parr[i++] = p; if (p == NULL) { uerror("parameter %d name missing", i); p = &nulsym; /* empty symtab */ } if (p->stype == FARG) p->stype = INT; if (ISARY(p->stype)) { p->stype += (PTR-ARY); p->sdf++; } else if (ISFTN(p->stype)) { werror("function declared as argument"); p->stype = INCREF(p->stype); } #ifdef STABS if (gflag) stabs_newsym(p); #endif } if (oldstyle && (df = cftnsp->sdf) && (al = df->dfun)) { /* * Check against prototype of oldstyle function. */ union arglist *al2, *alb; alb = al2 = FUNALLO(sizeof(union arglist) * nparams * 3 + 1); for (i = 0; i < nparams; i++) { TWORD type = parr[i]->stype; (al2++)->type = type; if (ISSOU(BTYPE(type))) (al2++)->sap = parr[i]->sap; while (!ISFTN(type) && !ISARY(type) && type > BTMASK) type = DECREF(type); if (type > BTMASK) (al2++)->df = parr[i]->sdf; } al2->type = TNULL; intcompare = 1; if (chkftn(al, alb)) uerror("function doesn't match prototype"); FUNFREE(alb); intcompare = 0; } if (oldstyle && nparams) { /* Must recalculate offset for oldstyle args here */ argoff = ARGINIT; for (i = 0; i < nparams; i++) { parr[i]->soffset = NOOFFSET; oalloc(parr[i], &argoff); } } done: autooff = AUTOINIT; plabel(prolab); /* after prolog, used in optimization */ retlab = getlab(); bfcode(parr, nparams); if (fun_inline && (xinline #ifdef GCC_COMPAT || attr_find(cftnsp->sap, GCC_ATYP_ALW_INL) #endif )) inline_args(parr, nparams); FUNFREE(parr); plabel(getlab()); /* used when spilling */ if (parlink) ecomp(parlink); parlink = NIL; lparam = NULL; nparams = 0; symclear(1); /* In case of function pointer args */ } /* * basic attributes for structs and enums */ static struct attr * seattr(void) { return attr_add(attr_new(ATTR_ALIGNED, 4), attr_new(ATTR_STRUCT, 2)); } /* * Struct/union/enum symtab construction. */ static void defstr(struct symtab *sp, int class) { sp->sclass = (char)class; if (class == STNAME) sp->stype = STRTY; else if (class == UNAME) sp->stype = UNIONTY; else if (class == ENAME) sp->stype = ENUMTY; } /* * Declare a struct/union/enum tag. * If not found, create a new tag with UNDEF type. */ static struct symtab * deftag(char *name, int class) { struct symtab *sp; if ((sp = lookup(name, STAGNAME))->sap == NULL) { /* New tag */ defstr(sp, class); } else if (sp->sclass != class) uerror("tag %s redeclared", name); return sp; } /* * reference to a structure or union, with no definition */ NODE * rstruct(char *tag, int soru) { struct symtab *sp; sp = deftag(tag, soru); if (sp->sap == NULL) sp->sap = seattr(); return mkty(sp->stype, 0, sp->sap); } static int enumlow, enumhigh; int enummer; /* * Declare a member of enum. */ void moedef(char *name) { struct symtab *sp; sp = lookup(name, SNORMAL); if (sp->stype == UNDEF || (sp->slevel < blevel)) { if (sp->stype != UNDEF) sp = hide(sp); sp->stype = INT; /* always */ sp->sclass = MOE; sp->soffset = enummer; } else uerror("%s redeclared", name); if (enummer < enumlow) enumlow = enummer; if (enummer > enumhigh) enumhigh = enummer; enummer++; } /* * Declare an enum tag. Complain if already defined. */ struct symtab * enumhd(char *name) { struct attr *ap; struct symtab *sp; enummer = enumlow = enumhigh = 0; if (name == NULL) return NULL; sp = deftag(name, ENAME); if (sp->stype != ENUMTY) { if (sp->slevel == blevel) uerror("%s redeclared", name); sp = hide(sp); defstr(sp, ENAME); } if (sp->sap == NULL) ap = sp->sap = attr_new(ATTR_STRUCT, 4); else ap = attr_find(sp->sap, ATTR_STRUCT); ap->amlist = sp; return sp; } /* * finish declaration of an enum */ NODE * enumdcl(struct symtab *sp) { NODE *p; TWORD t; #ifdef ENUMSIZE t = ENUMSIZE(enumhigh, enumlow); #else t = ctype(enumlow < 0 ? INT : UNSIGNED); #ifdef notdef if (enumhigh <= MAX_CHAR && enumlow >= MIN_CHAR) t = ctype(CHAR); else if (enumhigh <= MAX_SHORT && enumlow >= MIN_SHORT) t = ctype(SHORT); else t = ctype(INT); #endif #endif if (sp) sp->stype = t; p = mkty(t, 0, 0); p->n_sp = sp; return p; } /* * Handle reference to an enum */ NODE * enumref(char *name) { struct symtab *sp; NODE *p; sp = lookup(name, STAGNAME); #ifdef notdef /* * 6.7.2.3 Clause 2: * "A type specifier of the form 'enum identifier' without an * enumerator list shall only appear after the type it specifies * is complete." */ if (sp->sclass != ENAME) uerror("enum %s undeclared", name); #endif if (sp->sclass == SNULL) { /* declare existence of enum */ sp = enumhd(name); sp->stype = ENUMTY; } p = mkty(sp->stype, 0, sp->sap); p->n_sp = sp; return p; } /* * begining of structure or union declaration * It's an error if this routine is called twice with the same struct. */ struct rstack * bstruct(char *name, int soru, NODE *gp) { struct rstack *r; struct symtab *sp; struct attr *ap, *gap; #ifdef GCC_COMPAT gap = gp ? gcc_attr_parse(gp) : NULL; #else gap = NULL; #endif if (name != NULL) { sp = deftag(name, soru); if (sp->sap == NULL) sp->sap = seattr(); ap = attr_find(sp->sap, ATTR_ALIGNED); if (ap->iarg(0) != 0) { if (sp->slevel < blevel) { sp = hide(sp); defstr(sp, soru); sp->sap = seattr(); } else uerror("%s redeclared", name); } gap = sp->sap = attr_add(sp->sap, gap); } else { gap = attr_add(seattr(), gap); sp = NULL; } r = tmpcalloc(sizeof(struct rstack)); r->rsou = soru; r->rsym = sp; r->rb = NULL; r->ap = gap; r->rnext = rpole; rpole = r; return r; } /* * Called after a struct is declared to restore the environment. * - If ALSTRUCT is defined, this will be the struct alignment and the * struct size will be a multiple of ALSTRUCT, otherwise it will use * the alignment of the largest struct member. */ NODE * dclstruct(struct rstack *r) { NODE *n; struct attr *aps, *apb; struct symtab *sp; int al, sa, sz; apb = attr_find(r->ap, ATTR_ALIGNED); aps = attr_find(r->ap, ATTR_STRUCT); aps->amlist = r->rb; #ifdef ALSTRUCT al = ALSTRUCT; #else al = ALCHAR; #endif /* * extract size and alignment, calculate offsets */ for (sp = r->rb; sp; sp = sp->snext) { sa = talign(sp->stype, sp->sap); if (sp->sclass & FIELD) sz = sp->sclass&FLDSIZ; else sz = (int)tsize(sp->stype, sp->sdf, sp->sap); if (sz > rpole->rstr) rpole->rstr = sz; /* for use with unions */ /* * set al, the alignment, to the lcm of the alignments * of the members. */ SETOFF(al, sa); } SETOFF(rpole->rstr, al); aps->amsize = rpole->rstr; apb->iarg(0) = al; #ifdef PCC_DEBUG if (ddebug) { printf("dclstruct(%s): size=%d, align=%d\n", r->rsym ? r->rsym->sname : "??", aps->amsize, apb->iarg(0)); } if (ddebug>1) { printf("\tsize %d align %d link %p\n", aps->amsize, apb->iarg(0), aps->amlist); for (sp = aps->amlist; sp != NULL; sp = sp->snext) { printf("\tmember %s(%p)\n", sp->sname, sp); } } #endif #ifdef STABS if (gflag) stabs_struct(r->rsym, r->ap); #endif rpole = r->rnext; n = mkty(r->rsou == STNAME ? STRTY : UNIONTY, 0, r->ap); n->n_sp = r->rsym; n->n_qual |= 1; /* definition place XXX used by attributes */ return n; } /* * Add a new member to the current struct or union being declared. */ void soumemb(NODE *n, char *name, int class) { struct symtab *sp, *lsp; int incomp, tsz, al; TWORD t; if (rpole == NULL) cerror("soumemb"); /* check if tag name exists */ lsp = NULL; for (sp = rpole->rb; sp != NULL; lsp = sp, sp = sp->snext) if (*name != '*' && sp->sname == name) uerror("redeclaration of %s", name); sp = getsymtab(name, SMOSNAME); if (rpole->rb == NULL) rpole->rb = sp; else lsp->snext = sp; n->n_sp = sp; sp->stype = n->n_type; sp->squal = n->n_qual; sp->slevel = blevel; sp->sap = n->n_ap; sp->sdf = n->n_df; if (class & FIELD) { sp->sclass = (char)class; if (rpole->rsou == UNAME) rpole->rstr = 0; falloc(sp, class&FLDSIZ, NIL); } else if (rpole->rsou == STNAME || rpole->rsou == UNAME) { sp->sclass = rpole->rsou == STNAME ? MOS : MOU; if (sp->sclass == MOU) rpole->rstr = 0; al = talign(sp->stype, sp->sap); tsz = (int)tsize(sp->stype, sp->sdf, sp->sap); sp->soffset = upoff(tsz, al, &rpole->rstr); } /* * 6.7.2.1 clause 16: * "...the last member of a structure with more than one * named member may have incomplete array type;" */ if (ISARY(sp->stype) && sp->sdf->ddim == NOOFFSET) incomp = 1; else incomp = 0; if ((rpole->flags & LASTELM) || (rpole->rb == sp && incomp == 1)) uerror("incomplete array in struct"); if (incomp == 1) rpole->flags |= LASTELM; /* * 6.7.2.1 clause 2: * "...such a structure shall not be a member of a structure * or an element of an array." */ t = sp->stype; if (rpole->rsou != STNAME || BTYPE(t) != STRTY) return; /* not for unions */ while (ISARY(t)) t = DECREF(t); if (ISPTR(t)) return; if ((lsp = strmemb(sp->sap)) != NULL) { for (; lsp->snext; lsp = lsp->snext) ; if (ISARY(lsp->stype) && lsp->snext && lsp->sdf->ddim == NOOFFSET) uerror("incomplete struct in struct"); } } /* * error printing routine in parser */ void yyerror(char *s) { uerror(s); } void yyaccpt(void); void yyaccpt(void) { ftnend(); } /* * p is top of type list given to tymerge later. * Find correct CALL node and declare parameters from there. */ void ftnarg(NODE *p) { NODE *q; #ifdef PCC_DEBUG if (ddebug > 2) printf("ftnarg(%p)\n", p); #endif /* * Push argument symtab entries onto param stack in reverse order, * due to the nature of the stack it will be reclaimed correct. */ for (; p->n_op != NAME; p = p->n_left) { if (p->n_op == UCALL && p->n_left->n_op == NAME) return; /* Nothing to enter */ if (p->n_op == CALL && p->n_left->n_op == NAME) break; } p = p->n_right; while (p->n_op == CM) { q = p->n_right; if (q->n_op != ELLIPSIS) { ssave(q->n_sp); nparams++; #ifdef PCC_DEBUG if (ddebug > 2) printf(" saving sym %s (%p) from (%p)\n", q->n_sp->sname, q->n_sp, q); #endif } p = p->n_left; } ssave(p->n_sp); if (p->n_type != VOID) nparams++; #ifdef PCC_DEBUG if (ddebug > 2) printf(" saving sym %s (%p) from (%p)\n", nparams ? p->n_sp->sname : "", p->n_sp, p); #endif } /* * compute the alignment of an object with type ty, sizeoff index s */ int talign(unsigned int ty, struct attr *apl) { struct attr *al; int a; for (; ty > BTMASK; ty = DECREF(ty)) { switch (ty & TMASK) { case PTR: return(ALPOINT); case ARY: continue; case FTN: cerror("compiler takes alignment of function"); } } /* check for alignment attribute */ if ((al = attr_find(apl, ATTR_ALIGNED))) { if ((a = al->iarg(0)) == 0) { uerror("no alignment"); a = ALINT; } return a; } #ifndef NO_COMPLEX if (ISITY(ty)) ty -= (FIMAG-FLOAT); #endif ty = BTYPE(ty); if (ty >= CHAR && ty <= ULONGLONG && ISUNSIGNED(ty)) ty = DEUNSIGN(ty); switch (ty) { #ifdef GCC_COMPAT case VOID: a = ALCHAR; break; /* GCC */ #endif case BOOL: a = ALBOOL; break; case CHAR: a = ALCHAR; break; case SHORT: a = ALSHORT; break; case INT: a = ALINT; break; case LONG: a = ALLONG; break; case LONGLONG: a = ALLONGLONG; break; case FLOAT: a = ALFLOAT; break; case DOUBLE: a = ALDOUBLE; break; case LDOUBLE: a = ALLDOUBLE; break; default: uerror("no alignment"); a = ALINT; } return a; } short sztable[] = { 0, SZBOOL, SZCHAR, SZCHAR, SZSHORT, SZSHORT, SZINT, SZINT, SZLONG, SZLONG, SZLONGLONG, SZLONGLONG, SZFLOAT, SZDOUBLE, SZLDOUBLE }; /* compute the size associated with type ty, * dimoff d, and sizoff s */ /* BETTER NOT BE CALLED WHEN t, d, and s REFER TO A BIT FIELD... */ OFFSZ tsize(TWORD ty, union dimfun *d, struct attr *apl) { struct attr *ap, *ap2; OFFSZ mult, sz; mult = 1; for (; ty > BTMASK; ty = DECREF(ty)) { switch (ty & TMASK) { case FTN: #ifdef GCC_COMPAT return SZCHAR; #else uerror( "cannot take size of function"); #endif case PTR: return( SZPOINT(ty) * mult ); case ARY: if (d->ddim == NOOFFSET) return 0; if (d->ddim < 0) cerror("tsize: dynarray"); mult *= d->ddim; d++; } } #ifndef NO_COMPLEX if (ISITY(ty)) ty -= (FIMAG-FLOAT); #endif if (ty == VOID) ty = CHAR; if (ty <= LDOUBLE) sz = sztable[ty]; else if (ISSOU(ty)) { if ((ap = strattr(apl)) == NULL || (ap2 = attr_find(apl, ATTR_ALIGNED)) == NULL || (ap2->iarg(0) == 0)) { uerror("unknown structure/union/enum"); sz = SZINT; } else sz = ap->amsize; } else { uerror("unknown type"); sz = SZINT; } return((unsigned int)sz * mult); } #ifndef MYINSTRING /* * Print out a string of characters. * Assume that the assembler understands C-style escape * sequences. */ void instring(struct symtab *sp) { unsigned short sh[2]; char *s, *str; TWORD t; NODE *p; locctr(STRNG, sp); defloc(sp); t = BTYPE(sp->stype); str = s = sp->sname; if (t == ctype(USHORT)) { /* convert to UTF-16 */ p = xbcon(0, NULL, t); while (*s) { cp2u16(u82cp(&s), sh); if ((glval(p) = sh[0])) inval(0, SZSHORT, p); if ((glval(p) = sh[1])) inval(0, SZSHORT, p); } slval(p, 0); inval(0, SZSHORT, p); nfree(p); } else if (t == ctype(SZINT < 32 ? ULONG : UNSIGNED) || t == ctype(SZINT < 32 ? LONG : INT)) { /* convert to UTF-32 */ p = xbcon(0, NULL, t); while (*s) { slval(p, u82cp(&s)); inval(0, SZINT < 32 ? SZLONG : SZINT, p); } slval(p, 0); inval(0, SZINT < 32 ? SZLONG : SZINT, p); nfree(p); } else if (t == CHAR || t == UCHAR) { printf(PRTPREF "\t.ascii \""); while (*s) { if (*s == '\\') (void)esccon(&s); else s++; if (s - str > 60) { fwrite(str, 1, s - str, stdout); printf("\"\n" PRTPREF "\t.ascii \""); str = s; } } fwrite(str, 1, s - str, stdout); printf("\\0\"\n"); } else cerror("instring %ld", t); } #endif /* * update the offset pointed to by poff; return the * offset of a value of size `size', alignment `alignment', * given that off is increasing */ int upoff(int size, int alignment, int *poff) { int off; off = *poff; SETOFF(off, alignment); if (off < 0) cerror("structure or stack overgrown"); /* wrapped */ *poff = off+size; return (off); } /* * allocate p with offset *poff, and update *poff */ int oalloc(struct symtab *p, int *poff ) { int al, off, tsz; int noff; /* * Only generate tempnodes if we are optimizing, * and only for integers, floats or pointers, * and not if the type on this level is volatile. */ if (xtemps && ((p->sclass == AUTO) || (p->sclass == REGISTER)) && (p->stype < STRTY || ISPTR(p->stype)) && !(cqual(p->stype, p->squal) & VOL) && cisreg(p->stype)) { NODE *tn = tempnode(0, p->stype, p->sdf, p->sap); p->soffset = regno(tn); p->sflags |= STNODE; nfree(tn); return 0; } al = talign(p->stype, p->sap); noff = off = *poff; tsz = (int)tsize(p->stype, p->sdf, p->sap); #ifdef BACKAUTO if (p->sclass == AUTO) { noff = off + tsz; if (noff < 0) cerror("stack overflow"); SETOFF(noff, al); off = -noff; } else #endif if (p->sclass == PARAM && (p->stype == CHAR || p->stype == UCHAR || p->stype == SHORT || p->stype == USHORT || p->stype == BOOL)) { off = upoff(SZINT, ALINT, &noff); #if TARGET_ENDIAN == TARGET_BE off = noff - tsz; #endif } else { off = upoff(tsz, al, &noff); } if (p->sclass != REGISTER) { /* in case we are allocating stack space for register arguments */ if (p->soffset == NOOFFSET) p->soffset = off; else if(off != p->soffset) return(1); } *poff = noff; return(0); } /* * Delay emission of code generated in argument headers. */ static void edelay(NODE *p) { if (blevel == 1) { /* Delay until after declarations */ if (parlink == NULL) parlink = p; else parlink = block(COMOP, parlink, p, 0, 0, 0); } else ecomp(p); } /* * Traverse through the array args, evaluate them and put the * resulting temp numbers in the dim fields. */ static void evalidx(struct symtab *sp) { union dimfun *df; NODE *p; TWORD t; int astkp = 0; if (arrstk[0] == NIL) astkp++; /* for parameter arrays */ if (isdyn(sp)) sp->sflags |= SDYNARRAY; df = sp->sdf; for (t = sp->stype; t > BTMASK; t = DECREF(t)) { if (!ISARY(t)) continue; if (df->ddim == -1) { p = tempnode(0, INT, 0, 0); df->ddim = -regno(p); edelay(buildtree(ASSIGN, p, arrstk[astkp++])); } df++; } arrstkp = 0; } /* * Return 1 if dynamic array, 0 otherwise. */ int isdyn(struct symtab *sp) { union dimfun *df = sp->sdf; TWORD t; for (t = sp->stype; t > BTMASK; t = DECREF(t)) { if (!ISARY(t)) return 0; if (df->ddim < 0 && df->ddim != NOOFFSET) return 1; df++; } return 0; } /* * Allocate space on the stack for dynamic arrays (or at least keep track * of the index). * Strategy is as follows: * - first entry is a pointer to the dynamic datatype. * - if it's a one-dimensional array this will be the only entry used. * - if it's a multi-dimensional array the following (numdim-1) integers * will contain the sizes to multiply the indexes with. * - code to write the dimension sizes this will be generated here. * - code to allocate space on the stack will be generated here. */ static void dynalloc(struct symtab *p, int *poff) { union dimfun *df; NODE *n, *tn, *pol; TWORD t; /* * The pointer to the array is not necessarily stored in a * TEMP node, but if it is, its number is in the soffset field; */ t = p->stype; p->sflags |= STNODE; p->stype = INCREF(p->stype); /* Make this an indirect pointer */ tn = tempnode(0, p->stype, p->sdf, p->sap); p->soffset = regno(tn); df = p->sdf; pol = bcon(1); for (; t > BTMASK; t = DECREF(t)) { if (!ISARY(t)) break; if (df->ddim < 0) n = tempnode(-df->ddim, INT, 0, 0); else n = bcon(df->ddim); pol = buildtree(MUL, pol, n); df++; } /* Create stack gap */ spalloc(tn, pol, tsize(t, 0, p->sap)); } /* * allocate a field of width w * new is 0 if new entry, 1 if redefinition, -1 if alignment */ int falloc(struct symtab *p, int w, NODE *pty) { TWORD otype, type; int al,sz; otype = type = p ? p->stype : pty->n_type; if (type == BOOL) type = BOOL_TYPE; if (!ISINTEGER(type)) { uerror("illegal field type"); type = INT; } al = talign(type, NULL); sz = (int)tsize(type, NULL, NULL); if (w > sz) { uerror("field too big"); w = sz; } if (w == 0) { /* align only */ SETOFF(rpole->rstr, al); if (p != NULL) uerror("zero size field"); return(0); } if (rpole->rstr%al + w > sz) SETOFF(rpole->rstr, al); if (p == NULL) { rpole->rstr += w; /* we know it will fit */ return(0); } /* establish the field */ p->soffset = rpole->rstr; rpole->rstr += w; p->stype = otype; fldty(p); return(0); } /* * Check if this symbol should be a common or must be handled in data seg. */ static void commchk(struct symtab *sp) { if ((sp->sflags & STLS) #ifdef GCC_COMPAT || attr_find(sp->sap, GCC_ATYP_SECTION) #endif ) { /* TLS handled in data segment */ if (sp->sclass == EXTERN) sp->sclass = EXTDEF; beginit(sp); endinit(1); } else { symdirec(sp); defzero(sp); } } void nidcl(NODE *p, int class) { nidcl2(p, class, 0); } /* * handle unitialized declarations assumed to be not functions: * int a; * extern int a; * static int a; */ void nidcl2(NODE *p, int class, char *astr) { struct symtab *sp; int commflag = 0; /* compute class */ if (class == SNULL) { if (blevel > 1) class = AUTO; else if (blevel != 0 || rpole) cerror( "nidcl error" ); else /* blevel = 0 */ commflag = 1, class = EXTERN; } defid2(p, class, astr); sp = p->n_sp; /* check if forward decl */ if (ISARY(sp->stype) && sp->sdf->ddim == NOOFFSET) return; if (sp->sflags & SASG) return; /* already initialized */ switch (class) { case EXTDEF: /* simulate initialization by 0 */ simpleinit(p->n_sp, bcon(0)); break; case EXTERN: if (commflag) lcommadd(p->n_sp); else extdec(p->n_sp); break; case STATIC: if (blevel == 0) lcommadd(p->n_sp); else commchk(p->n_sp); break; } } struct lcd { SLIST_ENTRY(lcd) next; struct symtab *sp; }; static SLIST_HEAD(, lcd) lhead = { NULL, &lhead.q_forw}; /* * Add a local common statement to the printout list. */ void lcommadd(struct symtab *sp) { struct lcd *lc, *lcp; lcp = NULL; SLIST_FOREACH(lc, &lhead, next) { if (lc->sp == sp) return; /* already exists */ if (lc->sp == NULL && lcp == NULL) lcp = lc; } if (lcp == NULL) { lc = permalloc(sizeof(struct lcd)); lcommsz += sizeof(struct lcd); lc->sp = sp; SLIST_INSERT_LAST(&lhead, lc, next); } else lcp->sp = sp; } /* * Delete a local common statement. */ void lcommdel(struct symtab *sp) { struct lcd *lc; SLIST_FOREACH(lc, &lhead, next) { if (lc->sp == sp) { lc->sp = NULL; return; } } } /* * Print out the remaining common statements. */ void lcommprint(void) { struct lcd *lc; SLIST_FOREACH(lc, &lhead, next) { if (lc->sp != NULL) commchk(lc->sp); } } /* * Merge given types to a single node. * Any type can end up here. * p is the old node, q is the old (if any). * CLASS is AUTO, EXTERN, REGISTER, STATIC or TYPEDEF. * QUALIFIER is VOL or CON * TYPE is CHAR, SHORT, INT, LONG, SIGNED, UNSIGNED, VOID, BOOL, FLOAT, * DOUBLE, STRTY, UNIONTY. */ struct typctx { int class, qual, sig, uns, cmplx, imag, err, align; TWORD type; NODE *saved; struct attr *pre, *post; }; static void typwalk(NODE *p, void *arg) { struct typctx *tc = arg; #define cmop(x,y) block(CM, x, y, INT, 0, 0) switch (p->n_op) { case ALIGN: if (tc->align < glval(p)) tc->align = (int)glval(p); break; case ATTRIB: #ifdef GCC_COMPAT if (tc->saved && (tc->saved->n_qual & 1)) { tc->post = attr_add(tc->post,gcc_attr_parse(p->n_left)); } else { tc->pre = attr_add(tc->pre, gcc_attr_parse(p->n_left)); } p->n_left = bcon(0); /* For tfree() */ #else uerror("gcc type attribute used"); #endif break; case CLASS: if (p->n_type == 0) break; /* inline hack */ if (tc->class) tc->err = 1; /* max 1 class */ tc->class = p->n_type; break; case FUNSPEC: if (p->n_type == INLINE) { fun_inline = 1; } else if (p->n_type == NORETURN) { tc->pre = attr_add(tc->pre, attr_new(ATTR_NORETURN, 3)); } else tc->err = 1; break; case QUALIFIER: if (p->n_qual == 0 && ((tc->saved && !ISPTR(tc->saved->n_type)) || (tc->saved == 0))) uerror("invalid use of 'restrict'"); tc->qual |= p->n_qual >> TSHIFT; break; case TYPE: if (p->n_sp != NULL || ISSOU(p->n_type)) { /* typedef, enum or struct/union */ if (tc->saved || tc->type) tc->err = 1; #ifdef GCC_COMPAT if (ISSOU(p->n_type) && p->n_left) { if (tc->post) cerror("typwalk"); tc->post = gcc_attr_parse(p->n_left); } #endif tc->saved = ccopy(p); break; } switch (p->n_type) { case BOOL: case CHAR: case FLOAT: case VOID: if (tc->type) tc->err = 1; tc->type = p->n_type; break; case DOUBLE: if (tc->type == 0) tc->type = DOUBLE; else if (tc->type == LONG) tc->type = LDOUBLE; else tc->err = 1; break; case SHORT: if (tc->type == 0 || tc->type == INT) tc->type = SHORT; else tc->err = 1; break; case INT: if (tc->type == SHORT || tc->type == LONG || tc->type == LONGLONG) break; else if (tc->type == 0) tc->type = INT; else tc->err = 1; break; case LONG: if (tc->type == 0) tc->type = LONG; else if (tc->type == INT) break; else if (tc->type == LONG) tc->type = LONGLONG; else if (tc->type == DOUBLE) tc->type = LDOUBLE; else tc->err = 1; break; case SIGNED: if (tc->sig || tc->uns) tc->err = 1; tc->sig = 1; break; case UNSIGNED: if (tc->sig || tc->uns) tc->err = 1; tc->uns = 1; break; case COMPLEX: tc->cmplx = 1; break; case IMAG: tc->imag = 1; break; default: cerror("typwalk"); } } } NODE * typenode(NODE *p) { struct attr *ap; struct symtab *sp; struct typctx tc; NODE *q; char *c; memset(&tc, 0, sizeof(struct typctx)); flist(p, typwalk, &tc); tfree(p); if (tc.err) goto bad; if (tc.cmplx || tc.imag) { if (tc.type == 0) tc.type = DOUBLE; if ((tc.cmplx && tc.imag) || tc.sig || tc.uns || !ISFTY(tc.type)) goto bad; if (tc.cmplx) { c = tc.type == DOUBLE ? "0d" : tc.type == FLOAT ? "0f" : "0l"; sp = lookup(addname(c), 0); tc.type = STRTY; tc.saved = mkty(tc.type, sp->sdf, sp->sap); tc.saved->n_sp = sp; tc.type = 0; } else tc.type += (FIMAG-FLOAT); } if (tc.saved && tc.type) goto bad; if (tc.sig || tc.uns) { if (tc.type == 0) tc.type = tc.sig ? INT : UNSIGNED; if (tc.type > ULONGLONG) goto bad; if (tc.uns) tc.type = ENUNSIGN(tc.type); } if (xuchar && tc.type == CHAR && tc.sig == 0) tc.type = UCHAR; #ifdef GCC_COMPAT if (pragma_packed) { q = bdty(CALL, bdty(NAME, "packed"), bcon(pragma_packed)); tc.post = attr_add(tc.post, gcc_attr_parse(q)); } if (pragma_aligned) { /* Deal with relevant pragmas */ if (tc.align < pragma_aligned) tc.align = pragma_aligned; } pragma_aligned = pragma_packed = 0; #endif if ((q = tc.saved) == NULL) { TWORD t; if ((t = BTYPE(tc.type)) > LDOUBLE && t != VOID && t != BOOL && !(t >= FIMAG && t <= LIMAG)) cerror("typenode2 t %x", tc.type); if (t == UNDEF) { t = INT; MODTYPE(tc.type, INT); } q = mkty(tc.type, 0, 0); } q->n_ap = attr_add(q->n_ap, tc.post); q->n_qual = tc.qual; slval(q, tc.class); #ifdef GCC_COMPAT if (tc.post) { /* Can only occur for TYPEDEF, STRUCT or UNION */ if (tc.saved == NULL) cerror("typenode"); if (tc.saved->n_sp) /* trailer attributes for structs */ tc.saved->n_sp->sap = q->n_ap; } if (tc.pre) q->n_ap = attr_add(q->n_ap, tc.pre); gcc_tcattrfix(q); #endif if (tc.align && (ap = attr_find(q->n_ap, ATTR_ALIGNED)) && ap->iarg(0) && tc.align > talign(q->n_type, q->n_ap)/SZCHAR) { q->n_ap = attr_add(q->n_ap, attr_new(ATTR_ALIGNED, 1)); q->n_ap->aa[0].iarg = SZCHAR * tc.align; } return q; bad: uerror("illegal type combination"); return mkty(INT, 0, 0); } struct tylnk { struct tylnk *next; union dimfun df; }; /* * Retrieve all CM-separated argument types, sizes and dimensions and * put them in an array. * XXX - can only check first type level, side effects? */ static union arglist * arglist(NODE *n) { union arglist *al; NODE *w = n, **ap; int num, cnt, i, j, k; TWORD ty; #ifdef PCC_DEBUG if (pdebug) { printf("arglist %p\n", n); fwalk(n, eprint, 0); } #endif /* First: how much to allocate */ for (num = cnt = 0, w = n; w->n_op == CM; w = w->n_left) { cnt++; /* Number of levels */ num++; /* At least one per step */ if (w->n_right->n_op == ELLIPSIS) continue; ty = w->n_right->n_type; if (ty == ENUMTY) { uerror("arg %d enum undeclared", cnt); ty = w->n_right->n_type = INT; } if (BTYPE(ty) == STRTY || BTYPE(ty) == UNIONTY) num++; while (!ISFTN(ty) && !ISARY(ty) && ty > BTMASK) ty = DECREF(ty); if (ty > BTMASK) num++; } cnt++; ty = w->n_type; if (BTYPE(ty) == ENUMTY) { struct attr *app = attr_find(w->n_ap, ATTR_STRUCT); struct symtab *sp; if (app == NULL) uerror("arg %d enum undeclared", cnt); sp = app->amlist; if (sp->stype != ENUMTY) MODTYPE(ty, sp->stype); w->n_type = ty; } if (ty == ENUMTY) { uerror("arg %d enum undeclared", cnt); ty = w->n_type = INT; } if (BTYPE(ty) == STRTY || BTYPE(ty) == UNIONTY) num++; while (!ISFTN(ty) && !ISARY(ty) && ty > BTMASK) ty = DECREF(ty); if (ty > BTMASK) num++; num += 2; /* TEND + last arg type */ /* Second: Create list to work on */ ap = FUNALLO(sizeof(NODE *) * cnt); al = permalloc(sizeof(union arglist) * num); arglistcnt += num; for (w = n, i = 0; w->n_op == CM; w = w->n_left) ap[i++] = w->n_right; ap[i] = w; /* Third: Create actual arg list */ for (k = 0, j = i; j >= 0; j--) { if (ap[j]->n_op == ELLIPSIS) { al[k++].type = TELLIPSIS; ap[j]->n_op = ICON; /* for tfree() */ continue; } /* Convert arrays to pointers */ if (ISARY(ap[j]->n_type)) { ap[j]->n_type += (PTR-ARY); ap[j]->n_df++; } /* Convert (silently) functions to pointers */ if (ISFTN(ap[j]->n_type)) ap[j]->n_type = INCREF(ap[j]->n_type); ty = ap[j]->n_type; #ifdef GCC_COMPAT if (ty == UNIONTY && attr_find(ap[j]->n_ap, GCC_ATYP_TRANSP_UNION)){ /* transparent unions must have compatible types * shortcut here: if pointers, set void *, * otherwise btype. */ struct symtab *sp = strmemb(ap[j]->n_ap); ty = ISPTR(sp->stype) ? PTR|VOID : sp->stype; } #endif al[k++].type = ty; if (BTYPE(ty) == STRTY || BTYPE(ty) == UNIONTY) al[k++].sap = ap[j]->n_ap; while (!ISFTN(ty) && !ISARY(ty) && ty > BTMASK) ty = DECREF(ty); if (ty > BTMASK) al[k++].df = ap[j]->n_df; } al[k++].type = TNULL; if (k > num) cerror("arglist: k%d > num%d", k, num); tfree(n); FUNFREE(ap); #ifdef PCC_DEBUG if (pdebug) alprint(al, 0); #endif return al; } static void tylkadd(union dimfun dim, struct tylnk **tylkp, int *ntdim) { (*tylkp)->next = tmpalloc(sizeof(struct tylnk)); *tylkp = (*tylkp)->next; (*tylkp)->next = NULL; (*tylkp)->df = dim; (*ntdim)++; } /* * build a type, and stash away dimensions, * from a parse tree of the declaration * the type is build top down, the dimensions bottom up */ static void tyreduce(NODE *p, struct tylnk **tylkp, int *ntdim) { union dimfun dim; NODE *r = NULL; int o; TWORD t, q; o = p->n_op; if (o == NAME) { p->n_qual = DECQAL(p->n_qual); return; } t = INCREF(p->n_type); q = p->n_qual; switch (o) { case CALL: t += (FTN-PTR); dim.dfun = arglist(p->n_right); break; case UCALL: t += (FTN-PTR); dim.dfun = NULL; break; case LB: t += (ARY-PTR); if (p->n_right->n_op != ICON) { r = p->n_right; o = RB; } else { dim.ddim = (int)glval(p->n_right); nfree(p->n_right); #ifdef notdef /* XXX - check dimensions at usage time */ if (dim.ddim == NOOFFSET && p->n_left->n_op == LB) uerror("null dimension"); #endif } break; } p->n_left->n_type = t; p->n_left->n_qual = INCQAL(q) | p->n_left->n_qual; tyreduce(p->n_left, tylkp, ntdim); if (o == LB || o == UCALL || o == CALL) tylkadd(dim, tylkp, ntdim); if (o == RB) { dim.ddim = -1; tylkadd(dim, tylkp, ntdim); arrstk[arrstkp++] = r; } p->n_sp = p->n_left->n_sp; p->n_type = p->n_left->n_type; p->n_qual = p->n_left->n_qual; } /* * merge type typ with identifier idp. * idp is returned as a NAME node with correct types, * typ is untouched since multiple declarations uses it. * typ has type attributes, idp can never carry such attributes * so on return just a pointer to the typ attributes is returned. */ NODE * tymerge(NODE *typ, NODE *idp) { TWORD t; NODE *p; union dimfun *j; struct tylnk *base, tylnk, *tylkp; struct attr *bap; int ntdim, i; #ifdef PCC_DEBUG if (ddebug > 2) { printf("tymerge(%p,%p)\n", typ, idp); fwalk(typ, eprint, 0); fwalk(idp, eprint, 0); } #endif if (typ->n_op != TYPE) cerror("tymerge: arg 1"); bap = typ->n_ap; idp->n_type = typ->n_type; idp->n_qual |= typ->n_qual; tylkp = &tylnk; tylkp->next = NULL; ntdim = 0; tyreduce(idp, &tylkp, &ntdim); for (t = typ->n_type, j = typ->n_df; t&TMASK; t = DECREF(t)) if (ISARY(t) || ISFTN(t)) tylkadd(*j++, &tylkp, &ntdim); if (ntdim) { union dimfun *a = permalloc(sizeof(union dimfun) * ntdim); dimfuncnt += ntdim; for (i = 0, base = tylnk.next; base; base = base->next, i++) a[i] = base->df; idp->n_df = a; } else idp->n_df = NULL; /* now idp is a single node: fix up type */ if ((t = ctype(idp->n_type)) != idp->n_type) idp->n_type = t; if (idp->n_op != NAME) { for (p = idp->n_left; p->n_op != NAME; p = nfree(p)) ; nfree(p); idp->n_op = NAME; } /* carefully not destroy any type attributes */ if (idp->n_ap != NULL) { struct attr *ap = idp->n_ap; while (ap->next) ap = ap->next; ap->next = bap; } else idp->n_ap = bap; return(idp); } static NODE * argcast(NODE *p, TWORD t, union dimfun *d, struct attr *ap) { NODE *u, *r = p1alloc(); r->n_op = NAME; r->n_type = t; r->n_qual = 0; /* XXX */ r->n_df = d; r->n_ap = ap; u = buildtree(CAST, r, p); nfree(u->n_left); r = u->n_right; nfree(u); return r; } #ifdef PCC_DEBUG /* * Print a prototype. */ static void alprint(union arglist *al, int in) { TWORD t; int i = 0, j; for (; al->type != TNULL; al++) { for (j = in; j > 0; j--) printf(" "); printf("arg %d: ", i++); t = al->type; tprint(t, 0); while (t > BTMASK) { if (ISARY(t)) { al++; printf(" dim %d ", al->df->ddim); } else if (ISFTN(t)) { al++; if (al->df->dfun) { printf("\n"); alprint(al->df->dfun, in+1); } } t = DECREF(t); } if (ISSOU(t)) { al++; printf(" (size %d align %d)", (int)tsize(t, 0, al->sap), (int)talign(t, al->sap)); } printf("\n"); } if (in == 0) printf("end arglist\n"); } #endif int suemeq(struct attr *s1, struct attr *s2) { return (strmemb(s1) == strmemb(s2)); } /* * Sanity-check old-style args. */ static NODE * oldarg(NODE *p) { if (p->n_op == TYPE) uerror("type is not an argument"); if (p->n_type == FLOAT) return cast(p, DOUBLE, p->n_qual); return p; } /* * Do prototype checking and add conversions before calling a function. * Argument f is function and a is a CM-separated list of arguments. * Returns a merged node (via buildtree() of function and arguments. */ NODE * doacall(struct symtab *sp, NODE *f, NODE *a) { NODE *w, *r; union arglist *al; struct ap { struct ap *next; NODE *node; } *at, *apole = NULL, *apary = NULL; int i, argidx/* , hasarray = 0*/; TWORD type, arrt; #ifdef PCC_DEBUG if (ddebug) { printf("doacall.\n"); fwalk(f, eprint, 0); if (a) fwalk(a, eprint, 0); } #endif /* First let MD code do something */ calldec(f, a); /* XXX XXX hack */ if ((f->n_op == CALL) && f->n_left->n_op == ADDROF && f->n_left->n_left->n_op == NAME && (f->n_left->n_left->n_type & 0x7e0) == 0x4c0) goto build; /* XXX XXX hack */ /* Check for undefined or late defined enums */ if (BTYPE(f->n_type) == ENUMTY) { /* not-yet check if declared enum */ struct symtab *sq = strmemb(f->n_ap); if (sq->stype != ENUMTY) MODTYPE(f->n_type, sq->stype); if (BTYPE(f->n_type) == ENUMTY) uerror("enum %s not declared", sq->sname); } /* * Do some basic checks. */ if (f->n_df == NULL || (al = f->n_df[0].dfun) == NULL) { /* * Handle non-prototype declarations. */ if (f->n_op == NAME && f->n_sp != NULL) { if (strncmp(f->n_sp->sname, "__builtin", 9) != 0 && (f->n_sp->sflags & SINSYS) == 0) warner(Wmissing_prototypes, f->n_sp->sname); } else warner(Wmissing_prototypes, ""); /* floats must be cast to double */ if (a == NULL) goto build; if (a->n_op != CM) { a = oldarg(a); } else { for (w = a; w->n_left->n_op == CM; w = w->n_left) w->n_right = oldarg(w->n_right); w->n_left = oldarg(w->n_left); w->n_right = oldarg(w->n_right); } goto build; } if (al->type == VOID) { if (a != NULL) uerror("function takes no arguments"); goto build; /* void function */ } else { if (a == NULL) { uerror("function needs arguments"); goto build; } } #ifdef PCC_DEBUG if (pdebug) { printf("arglist for %s\n", f->n_sp != NULL ? f->n_sp->sname : "function pointer"); alprint(al, 0); } #endif /* * Create a list of pointers to the nodes given as arg. */ for (w = a, i = 1; w->n_op == CM; w = w->n_left) i++; apary = FUNALLO(sizeof(struct ap) * i); for (w = a, i = 0; w->n_op == CM; w = w->n_left) { at = &apary[i++]; at->node = w->n_right; at->next = apole; apole = at; } at = &apary[i]; at->node = w; at->next = apole; apole = at; /* * Do the typechecking by walking up the list. */ argidx = 1; while (al->type != TNULL) { if (al->type == TELLIPSIS) { /* convert the rest of float to double */ for (; apole; apole = apole->next) { if (apole->node->n_type != FLOAT) continue; MKTY(apole->node, DOUBLE, 0, 0); } goto build; } if (apole == NULL) { uerror("too few arguments to function"); goto build; } /* al = prototyp, apole = argument till ftn */ /* type = argumentets typ, arrt = prototypens typ */ type = apole->node->n_type; arrt = al->type; #if 0 if ((hasarray = ISARY(arrt))) arrt += (PTR-ARY); #endif /* Taking addresses of arrays are meaningless in expressions */ /* but people tend to do that and also use in prototypes */ /* this is mostly a problem with typedefs */ if (ISARY(type)) { if (ISPTR(arrt) && ISARY(DECREF(arrt))) type = INCREF(type); else type += (PTR-ARY); } else if (ISPTR(type) && !ISARY(DECREF(type)) && ISPTR(arrt) && ISARY(DECREF(arrt))) { type += (ARY-PTR); type = INCREF(type); } /* Check structs */ if (type <= BTMASK && arrt <= BTMASK) { #ifndef NO_COMPLEX if ((type != arrt) && (ANYCX(apole->node) || (arrt == STRTY && attr_find(al[1].sap, ATTR_COMPLEX)))) { cxargfixup(apole->node, arrt, al[1].sap); } else #endif if (type != arrt) { if (ISSOU(BTYPE(type)) || ISSOU(BTYPE(arrt))) { incomp: uerror("incompatible types for arg %d", argidx); } else { MKTY(apole->node, arrt, 0, 0) } #ifndef NO_COMPLEX } else if (type == STRTY && attr_find(apole->node->n_ap, ATTR_COMPLEX) && attr_find(al[1].sap, ATTR_COMPLEX)) { /* Both are complex */ if (strmemb(apole->node->n_ap)->stype != strmemb(al[1].sap)->stype) { /* must convert to correct type */ w = p1alloc(); *w = *apole->node; w = mkcmplx(w, strmemb(al[1].sap)->stype); *apole->node = *w; nfree(w); } goto out; #endif } else if (ISSOU(BTYPE(type))) { if (!suemeq(apole->node->n_ap, al[1].sap)) goto incomp; } goto out; } /* XXX should (recusively) check return type and arg list of func ptr arg XXX */ if (ISFTN(DECREF(arrt)) && ISFTN(type)) type = INCREF(type); /* Hereafter its only pointers (or arrays) left */ /* Check for struct/union intermixing with other types */ if (((type <= BTMASK) && ISSOU(BTYPE(type))) || ((arrt <= BTMASK) && ISSOU(BTYPE(arrt)))) goto incomp; /* Check for struct/union compatibility */ if (type == arrt) { if (ISSOU(BTYPE(type))) { if (suemeq(apole->node->n_ap, al[1].sap)) goto out; } else goto out; } if (BTYPE(arrt) == VOID && type > BTMASK) goto skip; /* void *f = some pointer */ if (arrt > BTMASK && BTYPE(type) == VOID) goto skip; /* some *f = void pointer */ if (apole->node->n_op == ICON && glval(apole->node) == 0) goto skip; /* Anything assigned a zero */ if ((type & ~BTMASK) == (arrt & ~BTMASK)) { /* do not complain for pointers with signedness */ if ((DEUNSIGN(BTYPE(type)) == DEUNSIGN(BTYPE(arrt))) && (BTYPE(type) != BTYPE(arrt))) { warner(Wpointer_sign); goto skip; } } werror("implicit conversion of argument %d due to prototype", argidx); skip: if (ISSOU(BTYPE(arrt))) { MKTY(apole->node, arrt, 0, al[1].sap) } else { MKTY(apole->node, arrt, 0, 0) } out: al++; if (ISSOU(BTYPE(arrt))) al++; #if 0 while (arrt > BTMASK && !ISFTN(arrt)) arrt = DECREF(arrt); if (ISFTN(arrt) || hasarray) al++; #else while (arrt > BTMASK) { if (ISARY(arrt) || ISFTN(arrt)) { al++; break; } arrt = DECREF(arrt); } #endif apole = apole->next; argidx++; } if (apole != NULL) uerror("too many arguments to function"); build: if (apary) FUNFREE(apary); if (sp != NULL && (sp->sflags & SINLINE) && (w = inlinetree(sp, f, a))) return w; return buildtree(a == NIL ? UCALL : CALL, f, a); } static int chk2(TWORD type, union dimfun *dsym, union dimfun *ddef) { while (type > BTMASK) { switch (type & TMASK) { case ARY: /* may be declared without dimension */ if (dsym->ddim == NOOFFSET) dsym->ddim = ddef->ddim; if (dsym->ddim < 0 && ddef->ddim < 0) ; /* dynamic arrays as arguments */ else if (ddef->ddim > 0 && dsym->ddim != ddef->ddim) return 1; dsym++, ddef++; break; case FTN: /* old-style function headers with function pointers * will most likely not have a prototype. * This is not considered an error. */ if (ddef->dfun == NULL) { #ifdef notyet werror("declaration not a prototype"); #endif } else if (chkftn(dsym->dfun, ddef->dfun)) return 1; dsym++, ddef++; break; } type = DECREF(type); } return 0; } /* * Compare two function argument lists to see if they match. */ int chkftn(union arglist *usym, union arglist *udef) { TWORD t2; int ty, tyn; if (usym == NULL) return 0; if (cftnsp != NULL && udef == NULL && usym->type == VOID) return 0; /* foo() { function with foo(void); prototype */ if (udef == NULL && usym->type != TNULL) return 1; while (usym->type != TNULL) { if (usym->type == udef->type) goto done; /* * If an old-style declaration, then all types smaller than * int are given as int parameters. */ if (intcompare) { ty = BTYPE(usym->type); tyn = BTYPE(udef->type); if (ty == tyn || ty != INT) return 1; if (tyn == CHAR || tyn == UCHAR || tyn == SHORT || tyn == USHORT) goto done; return 1; } else return 1; done: ty = BTYPE(usym->type); t2 = usym->type; if (ISSOU(ty)) { usym++, udef++; if (suemeq(usym->sap, udef->sap) == 0) return 1; } while (!ISFTN(t2) && !ISARY(t2) && t2 > BTMASK) t2 = DECREF(t2); if (t2 > BTMASK) { usym++, udef++; if (chk2(t2, usym->df, udef->df)) return 1; } usym++, udef++; } if (usym->type != udef->type) return 1; return 0; } void fixtype(NODE *p, int class) { unsigned int t, type; int mod1, mod2; /* fix up the types, and check for legality */ /* forward declared enums */ if (BTYPE(p->n_sp->stype) == ENUMTY) { MODTYPE(p->n_sp->stype, strmemb(p->n_sp->sap)->stype); } if( (type = p->n_type) == UNDEF ) return; if ((mod2 = (type&TMASK))) { t = DECREF(type); while( mod1=mod2, mod2 = (t&TMASK) ){ if( mod1 == ARY && mod2 == FTN ){ uerror( "array of functions is illegal" ); type = 0; } else if( mod1 == FTN && ( mod2 == ARY || mod2 == FTN ) ){ uerror( "function returns illegal type" ); type = 0; } t = DECREF(t); } } /* detect function arguments, watching out for structure declarations */ if (rpole && ISFTN(type)) { uerror("function illegal in structure or union"); type = INCREF(type); } p->n_type = type; } /* * give undefined version of class */ int uclass(int class) { if (class == SNULL) return(EXTERN); else if (class == STATIC) return(USTATIC); else return(class); } int fixclass(int class, TWORD type) { extern int fun_inline; /* first, fix null class */ if (class == SNULL) { if (fun_inline && ISFTN(type)) return SNULL; if (rpole) cerror("field8"); else if (blevel == 0) class = EXTDEF; else class = AUTO; } /* now, do general checking */ if( ISFTN( type ) ){ switch( class ) { default: uerror( "function has illegal storage class" ); case AUTO: class = EXTERN; case EXTERN: case EXTDEF: case TYPEDEF: case STATIC: case USTATIC: ; } } if (class & FIELD) { cerror("field3"); } switch (class) { case MOS: case MOU: cerror("field4"); case REGISTER: if (blevel == 0) uerror("illegal register declaration"); if (blevel == 1) return(PARAM); else return(REGISTER); case AUTO: if( blevel < 2 ) uerror( "illegal ULABEL class" ); return( class ); case EXTERN: case STATIC: case EXTDEF: case TYPEDEF: case USTATIC: case PARAM: return( class ); default: cerror( "illegal class: %d", class ); /* NOTREACHED */ } return 0; /* XXX */ } /* * Generates a goto statement; sets up label number etc. */ void gotolabel(char *name) { struct symtab *s = lookup(name, SLBLNAME|STEMP); if (s->soffset == 0) { s->soffset = -getlab(); s->sclass = STATIC; } branch(s->soffset < 0 ? -s->soffset : s->soffset); } /* * Sets a label for gotos. */ void deflabel(char *name, NODE *p) { struct symtab *s = lookup(name, SLBLNAME|STEMP); #ifdef GCC_COMPAT s->sap = gcc_attr_parse(p); #endif if (s->soffset > 0) uerror("label '%s' redefined", name); if (s->soffset == 0) { s->soffset = getlab(); s->sclass = STATIC; } if (s->soffset < 0) s->soffset = -s->soffset; plabel( s->soffset); } struct symtab * getsymtab(char *name, int flags) { struct symtab *s; if (flags & SSTMT) { s = stmtalloc(sizeof(struct symtab)); } else if (flags & SBLK) { s = blkalloc(sizeof(struct symtab)); } else if (flags & STEMP) { s = tmpalloc(sizeof(struct symtab)); } else { s = permalloc(sizeof(struct symtab)); symtabcnt++; } s->sname = name; s->snext = NULL; s->stype = UNDEF; s->squal = 0; s->sclass = SNULL; s->sflags = (short)(flags & SMASK); s->soffset = 0; s->slevel = (char)blevel; s->sdf = NULL; s->sap = NULL; return s; } int fldchk(int sz) { if (rpole->rsou != STNAME && rpole->rsou != UNAME) uerror("field outside of structure"); if (sz < 0 || sz >= FIELD) { uerror("illegal field size"); return 1; } return 0; } #ifdef PCC_DEBUG static char * ccnames[] = { /* names of storage classes */ "SNULL", "AUTO", "EXTERN", "STATIC", "REGISTER", "EXTDEF", "LABEL", "ULABEL", "MOS", "PARAM", "STNAME", "MOU", "UNAME", "TYPEDEF", "FORTRAN", "ENAME", "MOE", "UFORTRAN", "USTATIC", }; char * scnames(int c) { /* return the name for storage class c */ static char buf[12]; if( c&FIELD ){ snprintf( buf, sizeof(buf), "FIELD[%d]", c&FLDSIZ ); return( buf ); } return( ccnames[c] ); } #endif #if 0 static char *stack_chk_fail = "__stack_smash_handler"; static char *stack_chk_guard = "__guard"; #else static char *stack_chk_fail = "__stack_chk_fail"; static char *stack_chk_guard = "__stack_chk_guard"; #endif static char *stack_chk_canary = "__stack_chk_canary"; void sspinit(void) { NODE *p; p = block(NAME, NIL, NIL, FTN+VOID, 0, 0); p->n_sp = lookup(stack_chk_fail, SNORMAL); defid(p, EXTERN); nfree(p); p = block(NAME, NIL, NIL, INT, 0, 0); p->n_sp = lookup(stack_chk_guard, SNORMAL); defid(p, EXTERN); nfree(p); } void sspstart(void) { NODE *p, *q; q = block(NAME, NIL, NIL, INT, 0, 0); q->n_sp = lookup(stack_chk_guard, SNORMAL); q = clocal(q); p = block(REG, NIL, NIL, INCREF(INT), 0, 0); slval(p, 0); p->n_rval = FPREG; p = cast(p, INT, 0); q = buildtree(ER, p, q); p = block(NAME, NIL, NIL, INT, 0, 0); p->n_qual = VOL >> TSHIFT; p->n_sp = lookup(stack_chk_canary, SNORMAL); defid(p, AUTO); p = clocal(p); ecomp(buildtree(ASSIGN, p, q)); } void sspend(void) { NODE *p, *q; TWORD t; int lab; if (retlab != NOLAB) { plabel(retlab); retlab = getlab(); } t = DECREF(cftnsp->stype); if (t == BOOL) t = BOOL_TYPE; p = block(NAME, NIL, NIL, INT, 0, 0); p->n_sp = lookup(stack_chk_canary, SNORMAL); p = clocal(p); q = block(REG, NIL, NIL, INCREF(INT), 0, 0); slval(q, 0); q->n_rval = FPREG; q = cast(q, INT, 0); q = buildtree(ER, p, q); p = block(NAME, NIL, NIL, INT, 0, 0); p->n_sp = lookup(stack_chk_guard, SNORMAL); p = clocal(p); lab = getlab(); cbranch(buildtree(EQ, p, q), bcon(lab)); p = block(NAME, NIL, NIL, FTN+VOID, 0, 0); p->n_sp = lookup(stack_chk_fail, SNORMAL); p = clocal(p); q = eve(bdty(STRING, cftnsp->sname, PTR|CHAR)); ecomp(buildtree(CALL, p, q)); plabel(lab); } /* * Fetch pointer to first member in a struct list. */ struct symtab * strmemb(struct attr *ap) { if ((ap = attr_find(ap, ATTR_STRUCT)) == NULL) cerror("strmemb"); return ap->amlist; } #ifndef NO_COMPLEX static char *real, *imag; static struct symtab *cxsp[3], *cxmul[3], *cxdiv[3]; static char *cxnmul[] = { "__mulsc3", "__muldc3", "__mulxc3" }; static char *cxndiv[] = { "__divsc3", "__divdc3", "__divxc3" }; /* * As complex numbers internally are handled as structs, create * these by hand-crafting them. */ void complinit(void) { struct attr *ap; struct rstack *rp; NODE *p, *q; char *n[] = { "0f", "0d", "0l" }; int i, d_debug; d_debug = ddebug; ddebug = 0; real = addname("__real"); imag = addname("__imag"); p = block(NAME, NIL, NIL, FLOAT, 0, 0); for (i = 0; i < 3; i++) { p->n_type = FLOAT+i; rpole = rp = bstruct(NULL, STNAME, NULL); soumemb(p, real, 0); soumemb(p, imag, 0); q = dclstruct(rp); cxsp[i] = q->n_sp = lookup(addname(n[i]), 0); defid(q, TYPEDEF); ap = attr_new(ATTR_COMPLEX, 0); q->n_sp->sap = attr_add(q->n_sp->sap, ap); nfree(q); } /* create function declarations for external ops */ for (i = 0; i < 3; i++) { cxnmul[i] = addname(cxnmul[i]); p->n_sp = cxmul[i] = lookup(cxnmul[i], 0); p->n_type = FTN|STRTY; p->n_ap = cxsp[i]->sap; p->n_df = cxsp[i]->sdf; defid2(p, EXTERN, 0); cxmul[i]->sdf = permalloc(sizeof(union dimfun)); dimfuncnt++; cxmul[i]->sdf->dfun = NULL; cxndiv[i] = addname(cxndiv[i]); p->n_sp = cxdiv[i] = lookup(cxndiv[i], 0); p->n_type = FTN|STRTY; p->n_ap = cxsp[i]->sap; p->n_df = cxsp[i]->sdf; defid2(p, EXTERN, 0); cxdiv[i]->sdf = permalloc(sizeof(union dimfun)); dimfuncnt++; cxdiv[i]->sdf->dfun = NULL; } nfree(p); ddebug = d_debug; } static TWORD maxtt(NODE *p) { TWORD t; t = ANYCX(p) ? strmemb(p->n_ap)->stype : p->n_type; t = BTYPE(t); if (t == VOID) t = CHAR; /* pointers */ if (ISITY(t)) t -= (FIMAG - FLOAT); return t; } /* * Return the highest real floating point type. * Known that at least one type is complex or imaginary. */ static TWORD maxtyp(NODE *l, NODE *r) { TWORD tl, tr, t; tl = maxtt(l); tr = maxtt(r); t = tl > tr ? tl : tr; if (!ISFTY(t)) cerror("maxtyp"); return t; } /* * Fetch space on stack for complex struct. */ static NODE * cxstore(TWORD t) { struct symtab s; s = *cxsp[t - FLOAT]; s.sclass = AUTO; s.soffset = NOOFFSET; oalloc(&s, &autooff); return nametree(&s); } #define comop(x,y) buildtree(COMOP, x, y) /* * Convert node p to complex type dt. */ static NODE * mkcmplx(NODE *p, TWORD dt) { NODE *q, *r, *i, *t; if (!ANYCX(p)) { /* Not complex, convert to complex on stack */ q = cxstore(dt); if (ISITY(p->n_type)) { p->n_type = p->n_type - FIMAG + FLOAT; r = bcon(0); i = p; } else { if (ISPTR(p->n_type)) p = cast(p, INTPTR, 0); r = p; i = bcon(0); } p = buildtree(ASSIGN, structref(ccopy(q), DOT, real), r); p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, imag), i)); p = comop(p, q); } else { if (strmemb(p->n_ap)->stype != dt) { q = cxstore(dt); p = buildtree(ADDROF, p, NIL); t = tempnode(0, p->n_type, p->n_df, p->n_ap); p = buildtree(ASSIGN, ccopy(t), p); p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, real), structref(ccopy(t), STREF, real))); p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, imag), structref(t, STREF, imag))); p = comop(p, q); } } return p; } static NODE * cxasg(NODE *l, NODE *r) { TWORD tl, tr; tl = strattr(l->n_ap) ? strmemb(l->n_ap)->stype : 0; tr = strattr(r->n_ap) ? strmemb(r->n_ap)->stype : 0; if (ANYCX(l) && ANYCX(r) && tl != tr) { /* different types in structs */ r = mkcmplx(r, tl); } else if (!ANYCX(l)) r = structref(r, DOT, ISITY(l->n_type) ? imag : real); else if (!ANYCX(r)) r = mkcmplx(r, tl); return buildtree(ASSIGN, l, r); } /* * Fixup complex operations. * At least one operand is complex. */ NODE * cxop(int op, NODE *l, NODE *r) { TWORD mxtyp; NODE *p, *q; NODE *ltemp, *rtemp; NODE *real_l, *imag_l; NODE *real_r, *imag_r; real_r = imag_r = NULL; /* bad uninit var warning */ if (op == ASSIGN) return cxasg(l, r); mxtyp = maxtyp(l, r); l = mkcmplx(l, mxtyp); if (op != UMINUS) r = mkcmplx(r, mxtyp); if (op == COLON) return buildtree(COLON, l, r); /* put a pointer to left and right elements in a TEMP */ l = buildtree(ADDROF, l, NIL); ltemp = tempnode(0, l->n_type, l->n_df, l->n_ap); l = buildtree(ASSIGN, ccopy(ltemp), l); if (op != UMINUS) { r = buildtree(ADDROF, r, NIL); rtemp = tempnode(0, r->n_type, r->n_df, r->n_ap); r = buildtree(ASSIGN, ccopy(rtemp), r); p = comop(l, r); } else p = l; /* create the four trees needed for calculation */ real_l = structref(ccopy(ltemp), STREF, real); imag_l = structref(ltemp, STREF, imag); if (op != UMINUS) { real_r = structref(ccopy(rtemp), STREF, real); imag_r = structref(rtemp, STREF, imag); } /* get storage on stack for the result */ q = cxstore(mxtyp); switch (op) { case NE: case EQ: tfree(q); p = buildtree(op, comop(p, real_l), real_r); q = buildtree(op, imag_l, imag_r); p = buildtree(op == EQ ? ANDAND : OROR, p, q); return p; case ANDAND: case OROR: /* go via EQ to get INT of it */ tfree(q); p = buildtree(NE, comop(p, real_l), bcon(0)); /* gets INT */ q = buildtree(NE, imag_l, bcon(0)); p = buildtree(OR, p, q); q = buildtree(NE, real_r, bcon(0)); q = buildtree(OR, q, buildtree(NE, imag_r, bcon(0))); p = buildtree(op, p, q); return p; case UMINUS: p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, real), buildtree(op, real_l, NIL))); p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, imag), buildtree(op, imag_l, NIL))); break; case PLUS: case MINUS: p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, real), buildtree(op, real_l, real_r))); p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, imag), buildtree(op, imag_l, imag_r))); break; case MUL: case DIV: /* Complex mul is "complex" */ /* (u+iv)*(x+iy)=((u*x)-(v*y))+i(v*x+y*u) */ /* Complex div is even more "complex" */ /* (u+iv)/(x+iy)=(u*x+v*y)/(x*x+y*y)+i((v*x-u*y)/(x*x+y*y)) */ /* but we need to do it via a subroutine */ tfree(q); p = buildtree(CM, comop(p, real_l), imag_l); p = buildtree(CM, p, real_r); p = buildtree(CM, p, imag_r); q = nametree(op == DIV ? cxdiv[mxtyp-FLOAT] : cxmul[mxtyp-FLOAT]); return buildtree(CALL, q, p); break; default: uerror("illegal operator %s", copst(op)); } return comop(p, q); } /* * Fixup imaginary operations. * At least one operand is imaginary, none is complex. */ NODE * imop(int op, NODE *l, NODE *r) { NODE *p, *q; TWORD mxtyp; int li, ri; li = ri = 0; if (ISITY(l->n_type)) li = 1, l->n_type = l->n_type - (FIMAG-FLOAT); if (ISITY(r->n_type)) ri = 1, r->n_type = r->n_type - (FIMAG-FLOAT); mxtyp = maxtyp(l, r); switch (op) { case ASSIGN: /* if both are imag, store value, otherwise store 0.0 */ if (!(li && ri)) { tfree(r); r = bcon(0); } p = buildtree(ASSIGN, l, r); p->n_type += (FIMAG-FLOAT); break; case PLUS: if (li && ri) { p = buildtree(PLUS, l, r); p->n_type += (FIMAG-FLOAT); } else { /* If one is imaginary and one is real, make complex */ if (li) q = l, l = r, r = q; /* switch */ q = cxstore(mxtyp); p = buildtree(ASSIGN, structref(ccopy(q), DOT, real), l); p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, imag), r)); p = comop(p, q); } break; case MINUS: if (li && ri) { p = buildtree(MINUS, l, r); p->n_type += (FIMAG-FLOAT); } else if (li) { q = cxstore(mxtyp); p = buildtree(ASSIGN, structref(ccopy(q), DOT, real), buildtree(UMINUS, r, NIL)); p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, imag), l)); p = comop(p, q); } else /* if (ri) */ { q = cxstore(mxtyp); p = buildtree(ASSIGN, structref(ccopy(q), DOT, real), l); p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, imag), buildtree(UMINUS, r, NIL))); p = comop(p, q); } break; case MUL: p = buildtree(MUL, l, r); if (li && ri) p = buildtree(UMINUS, p, NIL); if (li ^ ri) p->n_type += (FIMAG-FLOAT); break; case DIV: p = buildtree(DIV, l, r); if (ri && !li) p = buildtree(UMINUS, p, NIL); if (li ^ ri) p->n_type += (FIMAG-FLOAT); break; case EQ: case NE: case LT: case LE: case GT: case GE: if (li ^ ri) { /* always 0 */ tfree(l); tfree(r); p = bcon(0); } else p = buildtree(op, l, r); break; default: cerror("imop"); p = NULL; } return p; } NODE * cxelem(int op, NODE *p) { if (ANYCX(p)) { p = structref(p, DOT, op == XREAL ? real : imag); } else if (op == XIMAG) { /* XXX sanitycheck? */ tfree(p); p = bcon(0); } return p; } NODE * cxconj(NODE *p) { NODE *q, *r; /* XXX side effects? */ q = cxstore(strmemb(p->n_ap)->stype); r = buildtree(ASSIGN, structref(ccopy(q), DOT, real), structref(ccopy(p), DOT, real)); r = comop(r, buildtree(ASSIGN, structref(ccopy(q), DOT, imag), buildtree(UMINUS, structref(p, DOT, imag), NIL))); return comop(r, q); } /* * Prepare for return. * There may be implicit casts to other types. */ NODE * imret(NODE *p, NODE *q) { if (ISITY(q->n_type) && ISITY(p->n_type)) { if (p->n_type != q->n_type) { p->n_type -= (FIMAG-FLOAT); p = cast(p, q->n_type - (FIMAG-FLOAT), 0); p->n_type += (FIMAG-FLOAT); } } else { p1tfree(p); if (ISITY(q->n_type)) { p = block(FCON, 0, 0, q->n_type, 0, 0); p->n_scon = sfallo(); FLOAT_INT2FP(p->n_scon, 0, INT); } else p = bcon(0); } return p; } /* * Prepare for return. * There may be implicit casts to other types. */ NODE * cxret(NODE *p, NODE *q) { if (ANYCX(q)) { /* Return complex type */ p = mkcmplx(p, strmemb(q->n_ap)->stype); } else if (q->n_type < STRTY || ISITY(q->n_type)) { /* real or imag */ p = structref(p, DOT, ISITY(q->n_type) ? imag : real); if (p->n_type != q->n_type) p = cast(p, q->n_type, 0); } else cerror("cxred failing type"); return p; } /* * either p1 or p2 is complex, so fixup the remaining type accordingly. */ NODE * cxcast(NODE *p1, NODE *p2) { if (ANYCX(p1) && ANYCX(p2)) { if (p1->n_type != p2->n_type) p2 = mkcmplx(p2, p1->n_type); } else if (ANYCX(p1)) { p2 = mkcmplx(p2, strmemb(p1->n_ap)->stype); } else /* if (ANYCX(p2)) */ { p2 = cast(structref(p2, DOT, real), p1->n_type, 0); } nfree(p1); return p2; } static void cxargfixup(NODE *a, TWORD dt, struct attr *ap) { NODE *p; TWORD t; p = p1alloc(); *p = *a; if (dt == STRTY) { /* dest complex */ t = strmemb(ap)->stype; p = mkcmplx(p, t); } else { /* src complex, not dest */ p = structref(p, DOT, ISFTY(dt) ? real : imag); } *a = *p; nfree(p); } #endif /* * Allocations: * permalloc() Never freed. in pass2. * tmpalloc() during a function lifetime, then freed. in pass2. * blkalloc() during a block lifetime. Variables etc. In pass1. * stmtalloc() during a statement lifetime. Expression trees. In pass1. */ /* * Short-time allocations during statements. */ #define MEMCHUNKSZ 8192 /* 8k per allocation */ struct balloc { char a1; union { long long l; long double d; } a2; }; #define ALIGNMENT offsetof(struct balloc, a2) #define ROUNDUP(x) (((x) + ((ALIGNMENT)-1)) & ~((ALIGNMENT)-1)) #define MAXSZ MEMCHUNKSZ-sizeof(struct xalloc *) struct xalloc { struct xalloc *next; union { long long b; /* for initial alignment */ long double d; char elm[MAXSZ]; }; } *sapole, *bkpole; int cstp, cbkp; void * stmtalloc(size_t size) { struct xalloc *xp; void *rv; size = ROUNDUP(size); if (size > MAXSZ) cerror("stmtalloc"); if (sapole == 0 || (size + cstp) > MAXSZ) { xp = xmalloc(sizeof(struct xalloc)); xp->next = sapole; sapole = xp; cstp = 0; } rv = &sapole->elm[cstp]; cstp += (int)size; return rv; } void stmtfree(void) { extern P1ND *frelink; extern int usdnodes; struct xalloc *x1; if (usdnodes != 0) cerror("stmtfree: usdnodes %d", usdnodes); frelink = NULL; while (sapole) { x1 = sapole->next; free(sapole); sapole = x1; } cstp = 0; } void * blkalloc(size_t size) { struct xalloc *xp; void *rv; if (blevel < 2) return permalloc(size); size = ROUNDUP(size); if (size > MAXSZ) cerror("blkalloc"); if (bkpole == 0 || (size + cbkp) > MAXSZ) { xp = xmalloc(sizeof(struct xalloc)); xp->next = bkpole; bkpole = xp; cbkp = 0; } rv = &bkpole->elm[cbkp]; cbkp += (int)size; return rv; } void blkfree(void) { struct xalloc *x1; while (bkpole) { x1 = bkpole->next; free(bkpole); bkpole = x1; } cbkp = 0; } pcc-20181216/cc/ccom/scan.l010064400017500000000000000441761340102345600141050ustar raggewheel%{ /* $Id: scan.l,v 1.157 2018/12/02 18:40:46 ragge Exp $ */ /* * Copyright (c) 2002 Anders Magnusson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ %} B [0-1] D [0-9] L [a-zA-Z_] H [a-fA-F0-9] E [Ee][+-]?{D}+ P [Pp][+-]?{D}+ FS ((f|F|l|L)?i|i?(f|F|l|L)) IS (u|U|l|L|i)* UL ({L}|[\x80-\xFF]) UC (L|u|U) US (L|u|U|u8) %{ #include #include #include #include #include #include "pass1.h" #include "cgram.h" #include "unicode.h" #define bdebug flexbdebug static P1ND *cvtdig(int radix); static P1ND *charcon(void); static P1ND *wcharcon(void); static void control(int); static void pragma(void); static int dotfile; int notype, parbal, inattr, parlvl, nodinit, inoso; int kwdecode(struct symtab *s); #define CPP_IDENT 2 #define CPP_LINE 3 #define CPP_HASH 4 #ifdef STABS #define STABS_LINE(x) if (gflag && cftnsp) stabs_line(x) #else #define STABS_LINE(x) #endif #if defined(FLEX_SCANNER) && YY_FLEX_SUBMINOR_VERSION == 31 /* Hack to avoid unnecessary warnings */ FILE *yyget_in (void); FILE *yyget_out (void); int yyget_leng (void); char *yyget_text (void); void yyset_in (FILE *); void yyset_out (FILE *); int yyget_debug (void); void yyset_debug (int); int yylex_destroy (void); extern int yyget_lineno (void); extern void yyset_lineno (int); #endif %} %% {UL}({UL}|{D})* { struct symtab *s; int i = 0; yylval.strp = addname(yytext); if ((s = lookup(yylval.strp, SNOCREAT)) != NULL && s->sclass == KEYWORD) return kwdecode(s); #ifdef GCC_COMPAT if (doing_init && nodinit == 0) { /* check for name: for old gcc compat */ while ((i = input()) == ' ' || i == '\t') ; if (i == ':') return(GCC_DESIG); unput(i); } if ((i = gcc_keyword(yylval.strp)) > 0) { if (i == PCC_OFFSETOF) inoso = 1; return i; } #endif if (i == 0) { if (notype) return(C_NAME); return s && s->sclass == TYPEDEF ? notype=1, C_TYPENAME : C_NAME; } } 0[xX]{H}+{IS}? { yylval.nodep = cvtdig(16); return(C_ICON); } 0{D}+{IS}? { yylval.nodep = cvtdig(8); return(C_ICON); } 0[bB]{B}+{IS}? { yylval.nodep = cvtdig(2); return(C_ICON); } {D}+{IS}? { yylval.nodep = cvtdig(10); return(C_ICON); } {UC}'(\\.|[^\\'])*' { yylval.nodep = wcharcon(); return(C_ICON); } '(\\.|[^\\'])*' { yylval.nodep = charcon(); return(C_ICON); } {D}+{E}{FS}? { yylval.flt = floatcon(yytext); return(C_FCON); } {D}*"."{D}+({E})?{FS}? { yylval.flt = floatcon(yytext); return(C_FCON); } {D}+"."{D}*({E})?{FS}? { yylval.flt = floatcon(yytext); return(C_FCON); } 0[xX]{H}*"."{H}+{P}{FS}? { yylval.flt = fhexcon(yytext); return(C_FCON); } 0[xX]{H}+"."{P}{FS}? { yylval.flt = fhexcon(yytext); return(C_FCON); } 0[xX]{H}+{P}{FS}? { yylval.flt = fhexcon(yytext); return(C_FCON); } {US}?\"(\\.|[^\\"])*\" { yylval.strp = yytext; return C_STRING; } "..." { return(C_ELLIPSIS); } ">>=" { yylval.intval = RSEQ; return(C_ASOP); } "<<=" { yylval.intval = LSEQ; return(C_ASOP); } "+=" { yylval.intval = PLUSEQ; return(C_ASOP); } "-=" { yylval.intval = MINUSEQ; return(C_ASOP); } "*=" { yylval.intval = MULEQ; return(C_ASOP); } "/=" { yylval.intval = DIVEQ; return(C_ASOP); } "%=" { yylval.intval = MODEQ; return(C_ASOP); } "&=" { yylval.intval = ANDEQ; return(C_ASOP); } "^=" { yylval.intval = EREQ; return(C_ASOP); } "|=" { yylval.intval = OREQ; return(C_ASOP); } ">>" { yylval.intval = RS; return(C_SHIFTOP); } "<<" { yylval.intval = LS; return(C_SHIFTOP); } "++" { yylval.intval = INCR; return(C_INCOP); } "--" { yylval.intval = DECR; return(C_INCOP); } "->" { yylval.intval = STREF; return(C_STROP); } "&&" { yylval.intval = ANDAND; return(C_ANDAND); } "||" { yylval.intval = OROR; return(C_OROR); } "<=" { yylval.intval = LE; return(C_RELOP); } ">=" { yylval.intval = GE; return(C_RELOP); } "==" { yylval.intval = EQ; return(C_EQUOP); } "!=" { yylval.intval = NE; return(C_EQUOP); } ";" { notype = 0; return(';'); } ("{"|"<%") { notype = 0; return('{'); } ("}"|"%>") { if (rpole) notype = 1; return('}'); } "," { if (parbal && !inoso) notype = 0; if (parbal == 0) notype = 1; return(','); } ":" { if (doing_init) nodinit--; return(':'); } "=" { return('='); } "(" { parbal++; notype = 0; return('('); } ")" { parbal--; inoso = 0; if (parbal==0) { notype = 0; } if (inattr && parlvl == parbal) inattr = 0; return(')'); } ("["|"<:") { return('['); } ("]"|":>") { return(']'); } "." { yylval.intval = DOT; return(C_STROP); } "&" { return('&'); } "!" { yylval.intval = NOT; return(C_UNOP); } "~" { yylval.intval = COMPL; return(C_UNOP); } "-" { return('-'); } "+" { return('+'); } "*" { if (parbal && notype == 0) notype = 1; return('*'); } "/" { yylval.intval = DIV; return(C_DIVOP); } "%" { yylval.intval = MOD; return(C_DIVOP); } "<" { yylval.intval = LT; return(C_RELOP); } ">" { yylval.intval = GT; return(C_RELOP); } "^" { return('^'); } "|" { return('|'); } "?" { if (doing_init) nodinit++; return('?'); } ^#pragma[ \t].* { pragma(); } ^#ident[ \t].* { control(CPP_IDENT); } ^#line[ \t].* { control(CPP_LINE); } ^#.* { control(CPP_HASH); } [ \t\v\f] { } "\n" { ++lineno; STABS_LINE(lineno); } . { /* ignore bad characters */ } %% int lineno, issyshdr; int yywrap(void) { if (0) unput(0); /* quiet gcc */ return(1); } #define DEFKW 500 #define KWFUNC 501 #define KWNOT 502 struct keywords { char *name; int cword, wclass; } keywords[] = { { "__func__", 0, KWFUNC }, { "_Alignas", C_ALIGNAS, DEFKW }, { "_Alignof", C_ALIGNOF, DEFKW }, { "_Atomic", C_ATOMIC, DEFKW }, { "asm", C_ASM, DEFKW }, { "auto", AUTO, C_CLASS }, { "_Bool", BOOL, C_TYPE }, { "break", C_BREAK, DEFKW }, { "case", C_CASE, DEFKW }, { "char", CHAR, C_TYPE }, { "continue", C_CONTINUE, DEFKW }, { "_Complex", COMPLEX, C_TYPE }, { "const", CON, C_QUALIFIER }, { "default", C_DEFAULT, DEFKW }, { "do", C_DO, DEFKW }, { "double", DOUBLE, C_TYPE }, { "else", C_ELSE, DEFKW }, { "enum", C_ENUM, KWNOT }, { "extern", EXTERN, C_CLASS }, { "float", FLOAT, C_TYPE }, { "for", C_FOR, DEFKW }, { "_Generic", C_GENERIC, DEFKW }, { "goto", C_GOTO, KWNOT }, { "if", C_IF, DEFKW }, { "_Imaginary", IMAG, C_TYPE }, { "inline", INLINE, C_FUNSPEC }, { "int", INT, C_TYPE }, { "long", LONG, C_TYPE }, { "_Noreturn", NORETURN, C_FUNSPEC }, { "register", REGISTER, C_CLASS }, { "restrict", 0, C_QUALIFIER }, { "return", C_RETURN, DEFKW }, { "short", SHORT, C_TYPE }, { "signed", SIGNED, C_TYPE }, { "sizeof", C_SIZEOF, DEFKW }, { "static", STATIC, C_CLASS }, { "_Static_assert", C_STATICASSERT, DEFKW }, { "struct", STNAME, C_STRUCT }, { "switch", C_SWITCH, DEFKW }, { "_Thread_local", THLOCAL, C_CLASS }, { "typedef", TYPEDEF, C_CLASS }, { "union", UNAME, C_STRUCT }, { "unsigned", UNSIGNED, C_TYPE }, { "void", VOID, C_TYPE }, { "volatile", VOL, C_QUALIFIER }, { "while", C_WHILE, DEFKW }, }; void kwinit(void) { struct symtab *s; int i, n = sizeof(keywords) / sizeof(keywords[0]); for (i = 0; i < n; i++) { s = lookup(addname(keywords[i].name), 0); s->sclass = KEYWORD; s->soffset = i; } } int kwdecode(struct symtab *s) { struct keywords *kw = &keywords[s->soffset]; if (inattr && kw->cword != C_SIZEOF) return C_NAME; switch (kw->wclass) { case C_TYPE: yylval.type = kw->cword; notype=1; break; case C_CLASS: if (kw->cword == THLOCAL) uerror("_Thread_local not supported"); yylval.type = kw->cword; break; case C_QUALIFIER: yylval.type = kw->cword; break; case C_FUNSPEC: yylval.type = kw->cword; break; case DEFKW: return kw->cword; case KWFUNC: if (cftnsp == NULL) uerror("__func__ outside function"); yylval.strp = cftnsp->sname; return(C_STRING); case KWNOT: notype = 1; return kw->cword; case C_STRUCT: notype = 1; yylval.intval = kw->cword; break; default: cerror("keyword %s not found", kw->name); } return kw->wclass; } static TWORD endtyp(char *s) { TWORD tw = DOUBLE; for (; *s; s++) ; s--; if (*s == 'i' || *s == 'I') tw += (FIMAG-FLOAT), s--; if (*s == 'f' || *s == 'F') tw--, s--; else if (*s == 'l' || *s == 'L') tw++, s--; if ((*s == 'i' || *s == 'I') && ISFTY(tw)) tw += (FIMAG-FLOAT), s--; /* XXX complain */ return tw; } FLT fhexcon(char *s) { FLT flt; flt.t = ctype(endtyp(s)); strtosf(&flt.sf, s, flt.t); return flt; } FLT floatcon(char *s) { return fhexcon(s); } P1ND * cvtdig(int radix) { P1ND *p; TWORD ntype; unsigned long long v; char *ch = yytext; int n, numl, numu; if (radix == 16 || radix == 2) ch += 2; /* Skip 0x or 0b */ v = 0; while ((*ch >= '0' && *ch <= '9') || (*ch >= 'a' && *ch <= 'f') || (*ch >= 'A' && *ch <= 'F')) { v *= radix; n = *ch; n = (n <= '9' ? n - '0' : (n > 'F' ? n - 'a' : n - 'A') + 10); ch++; v += n; } /* Parse trailing chars */ ntype = INT; numl = numu = 0; for (n = 0; n < 3; n++) { if (*ch == 0) break; if ((*ch == 'l' || *ch == 'L') && numl < 2) ntype+=2, numl++; else if ((*ch == 'u' || *ch == 'U') && numu < 1) ntype = ENUNSIGN(ntype), numu++; else if (*ch == 'i') ntype = DOUBLE; else break; ch++; } if (*ch) uerror("constant has too many '%c'", *ch); switch (ntype) { case DOUBLE: /* special case */ p = block(FCON, NULL, NULL, IMAG, 0, 0); p->n_scon = sfallo(); FLOAT_INT2FP(p->n_scon, v, ULONGLONG); FLOAT_FP2FP(p->n_scon, DOUBLE); return p; case INT: case LONG: case LONGLONG: if (radix == 10) { if (ntype == LONGLONG) break; if (v > MAX_LONG) ntype = LONGLONG; else if (v > MAX_INT) ntype = LONG; } else { if (v > MAX_LONGLONG) { ntype = ULONGLONG; } else if (v > MAX_ULONG) { if (ntype < LONGLONG) ntype = LONGLONG; } else if (v > MAX_LONG) { if (ntype < ULONG) ntype = ULONG; } else if (v > MAX_UNSIGNED) { if (ntype < LONG) ntype = LONG; } else if (v > MAX_INT) { if (ntype < UNSIGNED) ntype = UNSIGNED; } } break; case UNSIGNED: case ULONG: if (v > MAX_ULONG) { ntype = ULONGLONG; } else if (v > MAX_UNSIGNED) ntype = ULONG; break; } ntype = ctype(ntype); p = xbcon(v, NULL, ntype); ASGLVAL(p->n_slval, v); return p; } /* * return value of escaped character constant */ unsigned int esccon(char **sptr) { unsigned int val; char *wr = *sptr; char c; wr++; /* skip \ */ switch (c = *wr++) { case 'a': val = '\a'; break; case 'b': val = '\b'; break; #ifdef GCC_COMPAT case 'e': val = '\033'; break; #endif case 'f': val = '\f'; break; case 'n': val = '\n'; break; case 'r': val = '\r'; break; case 't': val = '\t'; break; case 'v': val = '\v'; break; case '\"': val = '\"'; break; case '\'': val = '\''; break; case '\?': val = '\?'; break; case '\\': val = '\\'; break; case 'x': val = 0; for (;;) { c = *wr; if (c >= '0' && c <= '9') c = c - '0'; else if (c >= 'a' && c <= 'f') c = c - 'a' + 10; else if (c >= 'A' && c <= 'F') c = c - 'A' + 10; else break; val = (val << 4) + c; wr++; } break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': val = (c - '0'); c = *wr; if (c >= '0' && c <= '7') { wr++; val = (val << 3) + (c - '0'); c = *wr; if (c >= '0' && c <= '7') { wr++; val = (val << 3) + (c - '0'); } } break; default: werror("unknown escape sequence \\%c", c); val = c; break; } *sptr = wr; return val; } /* * Convert (one) character constant to an int. * Handle as unsigned except if only one character and char is signed. */ P1ND * charcon(void) { unsigned int val = 0, i = 0; char *pp = yytext; pp++; /* skip ' */ while (*pp != '\'') { val <<= SZCHAR; /* XXX big endian? */ if (*pp == '\\') val |= esccon(&pp); else val |= (*pp++ & ((1 << SZCHAR)-1)); i++; } if (i == 0) uerror("empty character constant"); else if (i == 1 && xuchar == 0) val = (signed char)val; /* XXX other sizes of char? */ else if (i > 1) werror("too many characters in character constant"); return bcon(val); } /* * Convert a wide-character constant to an unsigned int */ P1ND * wcharcon(void) { unsigned int val = 0, i = 0; char *pp = yytext; pp++; /* skip L */ pp++; /* skip ' */ while (*pp != '\'') { /* * although u82cp() does handle escaped values, we deal * with them directly since otherwise you can't process * values which might be valid utf8 prefix */ if (*pp == '\\') val = esccon(&pp); else val = (unsigned)u82cp(&pp); i++; } if (i == 0) uerror("empty wide-character constant"); else if (i > 1) werror("too many characters in wide-character constant"); return xbcon(val, NULL, ctype(UNSIGNED)); } #ifndef MYDOTFILE /* * Get basename and print it as '.file "basename.c"' */ static void printdotfile(char *file) { char *p; if ((p = strrchr(file, '/')) == NULL) p = file; else p++; printf(PRTPREF "\t.file \"%s\"\n", p); } #endif void control(int t) { char *wr = yytext; char *eptr; int val; wr++; /* Skip initial '#' */ switch (t) { case CPP_IDENT: return; /* Just skip these for now. */ case CPP_LINE: wr += 4; /* FALLTHROUGH */ case CPP_HASH: val = (unsigned)strtol(wr, &eptr, 10); if (wr == eptr) /* Illegal string */ goto bad; wr = eptr; lineno = val - 1; while (*wr && *wr != '\"') wr++; if (*wr == 0) return; if (*wr++ != '\"') goto bad; eptr = wr; while (*wr && *wr != '\"') wr++; if (*wr != '\"') goto bad; *wr++ = 0; free(ftitle); ftitle = xstrdup(eptr); while (*wr == ' ') wr++; issyshdr = 0; if (*wr == '3') issyshdr = 1; #ifdef DWARF if (gflag) dwarf_file(ftitle); #endif #ifdef STABS if (gflag) stabs_file(ftitle); #endif if (dotfile == 0) { dotfile++; printdotfile(ftitle); } } return; bad: werror("%s: illegal control", yytext); } int pragma_allpacked; int pragma_packed, pragma_aligned; static int pragmas_weak(char *str) { struct symtab *sp; char *s1, *s2; if ((s1 = pragtok(NULL)) == NULL) return 1; if ((s2 = pragtok(NULL)) == NULL) { sp = lookup(addname(s1), SNORMAL); #ifdef GCC_COMPAT sp->sap = attr_add(sp->sap, gcc_attr_parse(bdty(NAME, "weak"))); #else sp->sap = NULL; #endif } else if (*s2 == '=') { if ((s2 = pragtok(NULL)) == NULL) return 1; sp = lookup(addname(s2), SNORMAL); #ifdef GCC_COMPAT sp->sap = attr_add(sp->sap, gcc_attr_parse(bdty(CALL, bdty(NAME, "aliasweak"), bdty(STRING, s1, 0)))); #else sp->sap = NULL; #endif } else return 1; return 0; } char *pragstore; /* trivial tokenizer for pragmas */ #define ps pragstore char * pragtok(char *sin) { static char ss[2]; char *rv; if (sin) ps = sin; for (; isspace((int)*ps); ps++) ; if (*ps == 0) return NULL; for (rv = ps; isalpha((int)*ps) || isdigit((int)*ps) || *ps == '_'; ps++) ; ss[0] = *ps; if (rv == ps) { rv = ss, ps++; } else { *ps = 0; rv = tmpstrdup(rv); *ps = ss[0]; } return rv; } /* return 1 on error */ int eat(int ch) { char *s = pragtok(0); return (s == 0 || *s != ch); } static int pragmas_alpack(char *t) { char *s; int ap; ap = (s = pragtok(0)) ? atoi(s) : 1; if (strcmp(t, "packed") == 0) pragma_packed = ap; else pragma_aligned = ap; return 0; } /* * Packing control. */ static int pragmas_pack(char *t) { #define PACKSTKSZ 10 static int packstk[PACKSTKSZ], packptr; char *s; if (eat('(')) return 1; s = pragtok(0); if (*s == ')') return pragma_allpacked = 0; if (strcmp(s, "push") == 0) { if (packptr == PACKSTKSZ) uerror("too many push"); packstk[packptr++] = pragma_allpacked; s = pragtok(0); if (*s == ')') return 0; if (*s != ',') return 1; s = pragtok(0); } else if (strcmp(s, "pop") == 0) { if (packptr == 0) uerror("stack empty"); pragma_allpacked = packstk[--packptr]; return eat(')'); } if (*s < '0' || *s > '9') /* no number */ return 1; pragma_allpacked = atoi(s); return eat(')'); } static int pragmas_unsupp(char *t) { werror("#pragma %s unsupported", t); return 0; /* Just ignore */ } static int pragmas_stdc(char *t) { char *s = pragtok(0); if (strcmp(s, "FP_CONTRACT") == 0) { if (strcmp(s = pragtok(0), "ON") == 0) { flostat |= FP_CONTR_CBR; } else if (strcmp(s, "OFF") == 0) { flostat &= ~FP_CONTR_CBR; } } return 0; /* Just ignore */ } struct pragmas { char *name; int (*fun)(char *); } pragmas[] = { { "pack", pragmas_pack }, { "packed", pragmas_alpack }, { "aligned", pragmas_alpack }, { "rename", pragmas_unsupp }, #ifdef GCC_COMPAT { "GCC", pragmas_gcc }, #endif { "STDC", pragmas_stdc }, { "weak", pragmas_weak }, { "ident", NULL }, { 0 }, }; /* * got a full pragma line. Split it up here. */ static void pragma(void) { struct pragmas *p; char *t, *pt; if ((t = pragtok(&yytext[7])) != NULL) { pt = ps; for (p = pragmas; p->name; p++) { if (strcmp(t, p->name) == 0) { if (p->fun && (*p->fun)(t)) uerror("bad argument to #pragma"); return; } } ps = pt; if (mypragma(t)) return; } warner(Wunknown_pragmas, t, ps); } void cunput(char c) { unput(c); } pcc-20181216/cc/ccom/softfloat.c010064400017500000000000000154311123404054200151360ustar raggewheel/* $Id: softfloat.c,v 1.4 2009/07/29 12:32:34 ragge Exp $ */ /* * Copyright (c) 2008 Anders Magnusson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifdef SOFTFLOAT #include "pass1.h" /* * Floating point emulation to be used when cross-compiling. * Currently only supports F- and D-float, used in DEC machines. * Should be trivial to add other emulations. * * XXX - assumes that: * - long long is (at least) 64 bits * - int is at least 32 bits. * - short is 16 bits. */ #ifdef FDFLOAT /* * Useful macros to manipulate the float. */ #define DSIGN(w) (((w).fd1 >> 15) & 1) #define DSIGNSET(w,s) ((w).fd1 = (s << 15) | ((w).fd1 & 077777)) #define DEXP(w) (((w).fd1 >> 7) & 0377) #define DEXPSET(w,e) ((w).fd1 = (((e) & 0377) << 7) | ((w).fd1 & 0100177)) #define DMANTH(w) ((w).fd1 & 0177) #define DMANTHSET(w,m) ((w).fd1 = ((m) & 0177) | ((w).fd1 & 0177600)) typedef unsigned int lword; typedef unsigned long long dword; #define MAXMANT 0x100000000000000LL /* * Returns a zero dfloat. */ static SF nulldf(void) { SF rv; rv.fd1 = rv.fd2 = rv.fd3 = rv.fd4 = 0; return rv; } /* * Convert a (u)longlong to dfloat. * XXX - fails on too large (> 55 bits) numbers. */ SF soft_cast(CONSZ ll, TWORD t) { int i; SF rv; rv = nulldf(); if (ll == 0) return rv; /* fp is zero */ if (ll < 0) DSIGNSET(rv,1), ll = -ll; for (i = 0; ll > 0; i++, ll <<= 1) ; DEXPSET(rv, 192-i); DMANTHSET(rv, ll >> 56); rv.fd2 = ll >> 40; rv.fd3 = ll >> 24; rv.fd4 = ll >> 8; return rv; } /* * multiply two dfloat. Use chop, not round. */ SF soft_mul(SF p1, SF p2) { SF rv; lword a1[2], a2[2], res[4]; dword sum; res[0] = res[1] = res[2] = res[3] = 0; /* move mantissa into lwords */ a1[0] = p1.fd4 | (p1.fd3 << 16); a1[1] = p1.fd2 | DMANTH(p1) << 16 | 0x800000; a2[0] = p2.fd4 | (p2.fd3 << 16); a2[1] = p2.fd2 | DMANTH(p2) << 16 | 0x800000; #define MULONE(x,y,r) sum += (dword)a1[x] * (dword)a2[y]; sum += res[r]; \ res[r] = sum; sum >>= 32; sum = 0; MULONE(0, 0, 0); MULONE(1, 0, 1); res[2] = sum; sum = 0; MULONE(0, 1, 1); MULONE(1, 1, 2); res[3] = sum; rv.fd1 = 0; DSIGNSET(rv, DSIGN(p1) ^ DSIGN(p2)); DEXPSET(rv, DEXP(p1) + DEXP(p2) - 128); if (res[3] & 0x8000) { res[3] = (res[3] << 8) | (res[2] >> 24); res[2] = (res[2] << 8) | (res[1] >> 24); } else { DEXPSET(rv, DEXP(rv) - 1); res[3] = (res[3] << 9) | (res[2] >> 23); res[2] = (res[2] << 9) | (res[1] >> 23); } DMANTHSET(rv, res[3] >> 16); rv.fd2 = res[3]; rv.fd3 = res[2] >> 16; rv.fd4 = res[2]; return rv; } SF soft_div(SF t, SF n) { SF rv; dword T, N, K; int c; #define SHL(x,b) ((dword)(x) << b) T = SHL(1,55) | SHL(DMANTH(t), 48) | SHL(t.fd2, 32) | SHL(t.fd3, 16) | t.fd4; N = SHL(1,55) | SHL(DMANTH(n), 48) | SHL(n.fd2, 32) | SHL(n.fd3, 16) | n.fd4; c = T > N; for (K = 0; (K & 0x80000000000000ULL) == 0; ) { if (T >= N) { T -= N; K |= 1; } T <<= 1; K <<= 1; } rv.fd1 = 0; DSIGNSET(rv, DSIGN(t) ^ DSIGN(n)); DEXPSET(rv, DEXP(t) - DEXP(n) + 128 + c); DMANTHSET(rv, K >> 48); rv.fd2 = K >> 32; rv.fd3 = K >> 16; rv.fd4 = K; return rv; } /* * Negate a float number. Easy. */ SF soft_neg(SF sf) { int sign = DSIGN(sf) == 0; DSIGNSET(sf, sign); return sf; } /* * Return true if fp number is zero. */ int soft_isz(SF sf) { return (DEXP(sf) == 0); } int soft_cmp_eq(SF x1, SF x2) { cerror("soft_cmp_eq"); return 0; } int soft_cmp_ne(SF x1, SF x2) { cerror("soft_cmp_ne"); return 0; } int soft_cmp_le(SF x1, SF x2) { cerror("soft_cmp_le"); return 0; } int soft_cmp_lt(SF x1, SF x2) { cerror("soft_cmp_lt"); return 0; } int soft_cmp_ge(SF x1, SF x2) { cerror("soft_cmp_ge"); return 0; } int soft_cmp_gt(SF x1, SF x2) { cerror("soft_cmp_gt"); return 0; } /* * Convert a fp number to a CONSZ. */ CONSZ soft_val(SF sf) { CONSZ mant; int exp = DEXP(sf) - 128; mant = SHL(1,55) | SHL(DMANTH(sf), 48) | SHL(sf.fd2, 32) | SHL(sf.fd3, 16) | sf.fd4; while (exp < 0) mant >>= 1, exp++; while (exp > 0) mant <<= 1, exp--; return mant; } SF soft_plus(SF x1, SF x2) { cerror("soft_plus"); return x1; } SF soft_minus(SF x1, SF x2) { cerror("soft_minus"); return x1; } /* * Convert a hex constant to floating point number. */ NODE * fhexcon(char *s) { cerror("fhexcon"); return NULL; } /* * Convert a floating-point constant to D-float and store it in a NODE. */ NODE * floatcon(char *s) { NODE *p; dword mant; SF fl, flexp, exp5; int exp, negexp, bexp; exp = 0; mant = 0; #define ADDTO(sum, val) sum = sum * 10 + val - '0' for (; *s >= '0' && *s <= '9'; s++) { if (mant= '0' && *s <= '9'; s++) { if (mant= '0' && *s <= '9'; s++) ADDTO(eexp, *s); if (sign) eexp = -eexp; exp = exp + eexp; } negexp = 1; if (exp<0) { negexp = -1; exp = -exp; } flexp = soft_cast(1, INT); exp5 = soft_cast(5, INT); bexp = exp; fl = soft_cast(mant, INT); for (; exp; exp >>= 1) { if (exp&01) flexp = soft_mul(flexp, exp5); exp5 = soft_mul(exp5, exp5); } if (negexp<0) fl = soft_div(fl, flexp); else fl = soft_mul(fl, flexp); DEXPSET(fl, DEXP(fl) + negexp*bexp); p = block(FCON, NIL, NIL, DOUBLE, 0, MKSUE(DOUBLE)); /* XXX type */ p->n_dcon = fl; return p; } #else #error missing softfloat definition #endif #endif pcc-20181216/cc/ccom/stabs.c010064400017500000000000000273421257607440600142750ustar raggewheel/* $Id: stabs.c,v 1.35 2015/09/15 20:01:10 ragge Exp $ */ /* * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Simple implementation of the "stabs" debugging format. * Not complete but at least makes it possible to set breakpoints, * examine simple variables and do stack traces. * Based on the stabs documentation that follows gdb. */ #include "pass1.h" #ifdef STABS #include #include #include #define STABHASH 256 #define INTNUM 1 /* internal number of type "int" */ #undef BIT2BYTE /* from external.h */ #define BIT2BYTE(x) ((x)/SZCHAR) #ifndef STABLBL #error macdefs.h must define STABLBL #endif /* defines taken from BSD */ #define N_GSYM 0x20 /* global symbol */ #define N_FUN 0x24 /* procedure name */ #define N_LCSYM 0x28 /* bss segment variable */ #define N_RSYM 0x40 /* register variable */ #define N_SLINE 0x44 /* text segment line number */ #define N_SO 0x64 /* main source file name */ #define N_LSYM 0x80 /* stack variable */ #define N_SOL 0x84 /* included source file name */ #define N_PSYM 0xa0 /* parameter variable */ #define N_LBRAC 0xc0 /* left bracket */ #define N_RBRAC 0xe0 /* right bracket */ /* * Local type mapping * Types are defined as a typeword, a dimension pointer (in the case * of arrays) and struct/union/enum declarations. * Function prototypes are ignored. */ static struct stabtype { struct stabtype *next; /* linked list */ TWORD type; /* pcc type number */ union dimfun *df; /* dimension of arrays */ struct attr *ap; /* struct/union/enum declarations */ int num; /* local type number */ } *stabhash[STABHASH]; static int ntypes; static char *curfun; static int stablbl = 10; extern int inftn; void ptype(char *name, int num, int inhnum, long long min, long long max); struct stabtype *addtype(TWORD, union dimfun *, struct attr *); struct stabtype *findtype(TWORD t, union dimfun *df, struct attr *sue); void printtype(struct symtab *s, char *str, int len); void cprint(int p2, char *fmt, ...); #define MAXPSTR 100 extern int isinlining; /* * Output type definitions for the stab debugging format. * Note that "int" is always internal number 1. */ void stabs_init(void) { struct stabtype *st; #define ADDTYPE(y) addtype(y, NULL, 0) ptype("int", ADDTYPE(INT)->num, INTNUM, MIN_INT, MAX_INT); st = ADDTYPE(CHAR); ptype("char", st->num, st->num, 0, MAX_CHAR); ptype("short", ADDTYPE(SHORT)->num, INTNUM, MIN_SHORT, MAX_SHORT); ptype("long", ADDTYPE(LONG)->num, INTNUM, MIN_LONG, MAX_LONG); ptype("long long", ADDTYPE(LONGLONG)->num, INTNUM, MIN_LONGLONG, MAX_LONGLONG); ptype("unsigned char", ADDTYPE(UCHAR)->num, INTNUM, 0, MAX_UCHAR); ptype("unsigned short", ADDTYPE(USHORT)->num, INTNUM, 0, MAX_USHORT); ptype("unsigned int", ADDTYPE(UNSIGNED)->num, INTNUM, 0, MAX_UNSIGNED); ptype("unsigned long", ADDTYPE(ULONG)->num, INTNUM, 0, MAX_ULONG); ptype("unsigned long long", ADDTYPE(ULONGLONG)->num, INTNUM, 0, MAX_ULONGLONG); ptype("float", ADDTYPE(FLOAT)->num, INTNUM, 4, 0); ptype("double", ADDTYPE(DOUBLE)->num, INTNUM, 8, 0); ptype("long double", ADDTYPE(LDOUBLE)->num, INTNUM, 12, 0); st = ADDTYPE(VOID); cprint(0, "\t.stabs \"void:t%d=r%d\",%d,0,0,0\n", st->num, st->num, N_LSYM); } /* * Print a type in stabs format */ void ptype(char *name, int num, int inhnum, long long min, long long max) { cprint(0, "\t.stabs \"%s:t%d=r%d;%lld;%lld;\",%d,0,0,0\n", name, num, inhnum, min, max, N_LSYM); } /* * Add a new local type to the hash table. * The search key is the (type, df, sue) triple. */ struct stabtype * addtype(TWORD t, union dimfun *df, struct attr *ap) { struct stabtype *st; st = permalloc(sizeof(struct stabtype)); st->type = t; st->df = df; st->ap = ap; st->num = ++ntypes; st->next = stabhash[t & (STABHASH-1)]; stabhash[t & (STABHASH-1)] = st; return st; } /* * Search for a given type and return a type pointer (or NULL). */ struct stabtype * findtype(TWORD t, union dimfun *df, struct attr *ap) { struct stabtype *st; union dimfun *dw, *dx; TWORD tw; st = stabhash[t & (STABHASH-1)]; for (; st; st = st->next) { if (t != st->type || ap != st->ap) continue; /* Ok, type and sue matches, check dimensions */ if (st->df == NULL) return st; /* no arrays, got match */ dw = st->df; dx = df; tw = t; for (; tw > BTMASK; tw = DECREF(tw)) { if (ISARY(tw)) { if (dw->ddim == dx->ddim) dw++, dx++; else break; } } if (tw <= BTMASK) return st; } return NULL; } /* * Print current line number. */ void stabs_line(int line) { if (inftn == 0) return; /* ignore */ #ifdef STAB_LINE_ABSOLUTE cprint(1, "\t.stabn %d,0,%d," STABLBL "\n" STABLBL ":\n", N_SLINE, line, stablbl, stablbl); #else cprint(1, "\t.stabn %d,0,%d," STABLBL "-%s\n" STABLBL ":\n", N_SLINE, line, stablbl, curfun, stablbl); #endif stablbl++; } /* * Start of block. */ void stabs_lbrac(int blklvl) { #ifdef STAB_LINE_ABSOLUTE cprint(1, "\t.stabn %d,0,%d," STABLBL "\n" STABLBL ":\n", N_LBRAC, blklvl, stablbl, stablbl); #else cprint(1, "\t.stabn %d,0,%d," STABLBL "-%s\n" STABLBL ":\n", N_LBRAC, blklvl, stablbl, curfun, stablbl); #endif stablbl++; } /* * End of block. */ void stabs_rbrac(int blklvl) { #ifdef STAB_LINE_ABSOLUTE cprint(1, "\t.stabn %d,0,%d," STABLBL "\n" STABLBL ":\n", N_RBRAC, blklvl, stablbl, stablbl); #else cprint(1, "\t.stabn %d,0,%d," STABLBL "-%s\n" STABLBL ":\n", N_RBRAC, blklvl, stablbl, curfun, stablbl); #endif stablbl++; } static char *mainfile; /* * Print current file and set mark. */ void stabs_file(char *fname) { if (mainfile == NULL) mainfile = fname; /* first call */ cprint(inftn, "\t.stabs \"%s\",%d,0,0," STABLBL "\n" STABLBL ":\n", fname, fname == mainfile ? N_SO : N_SOL, stablbl, stablbl); stablbl++; } /* * Print end mark */ void stabs_efile(char *fname) { cprint(inftn, "\t.stabs \"\",%d,0,0," STABLBL "\n" STABLBL ":\n", fname == mainfile ? N_SO : N_SOL, stablbl, stablbl); stablbl++; } /* * Print beginning of function. */ void stabs_func(struct symtab *s) { char str[MAXPSTR]; curfun = getexname(s); printtype(s, str, sizeof(str)); cprint(1, "\t.stabs \"%s:%c%s\",%d,0,%d,%s\n", curfun, s->sclass == STATIC ? 'f' : 'F', str, N_FUN, 0, curfun); } /* * Print a (complex) type. * Will also create subtypes. * Printed string is like "20=*21=*1". */ void printtype(struct symtab *s, char *ostr, int len) { struct stabtype *st; union dimfun *df = s->sdf; struct attr *ap = s->sap; TWORD t = s->stype; int op = 0; /* Print out not-yet-found types */ if (ISFTN(t)) t = DECREF(t); st = findtype(t, df, ap); while (st == NULL && t > BTMASK) { st = addtype(t, df, ap); op+=snprintf(ostr+op, len - op, "%d=", st->num); if (ISFTN(t)) ostr[op++] = 'f'; else if (ISPTR(t)) ostr[op++] = '*'; else if (ISARY(t)) { op+=snprintf(ostr+op, len - op, "ar%d;0;%d;", INTNUM, df->ddim-1); } else cerror("printtype: notype"); if (ISARY(t)) df++; t = DECREF(t); st = findtype(t, df, ap); if (op > MAXPSTR-10) cerror("printtype: too difficult expression"); } /* print out basic type. may have to be entered in case of sue */ snprintf(ostr+op, len - op, "%d", st == NULL ? 1 : st->num); /* snprintf here null-terminated the string */ } void stabs_newsym(struct symtab *s) { extern int fun_inline; char *sname; char ostr[MAXPSTR]; OFFSZ suesize, sz; if (ISFTN(s->stype)) return; /* functions are handled separate */ if (s->sclass == STNAME || s->sclass == UNAME || s->sclass == MOS || s->sclass == ENAME || s->sclass == MOU || s->sclass == MOE || s->sclass == TYPEDEF || (s->sclass & FIELD) || ISSOU(s->stype)) return; /* XXX - fix structs */ sname = getexname(s); sz = tsize(s->stype, s->sdf, s->sap); suesize = BIT2BYTE(sz); if (suesize > 32767) suesize = 32767; else if (suesize < -32768) suesize = -32768; printtype(s, ostr, sizeof(ostr)); switch (s->sclass) { case PARAM: cprint(0, "\t.stabs \"%s:p%s\",%d,0," CONFMT ",%d\n", sname, ostr, N_PSYM, (CONSZ)suesize, BIT2BYTE(s->soffset)); break; case AUTO: cprint(0, "\t.stabs \"%s:%s\",%d,0," CONFMT ",%d\n", sname, ostr, N_LSYM, (CONSZ)suesize, BIT2BYTE(s->soffset)); break; case STATIC: if (blevel) cprint(0, "\t.stabs \"%s:V%s\",%d,0," CONFMT "," LABFMT "\n", sname, ostr, N_LCSYM, (CONSZ)suesize, s->soffset); else cprint(0, "\t.stabs \"%s:S%s\",%d,0," CONFMT ",%s\n", sname, ostr, N_LCSYM, (CONSZ)suesize, sname); break; case EXTERN: case EXTDEF: cprint(0, "\t.stabs \"%s:G%s\",%d,0," CONFMT ",0\n", sname, ostr, N_GSYM, (CONSZ)suesize); break; case REGISTER: cprint(0, "\t.stabs \"%s:r%s\",%d,0,%d,%d\n", sname, ostr, N_RSYM, 1, s->soffset); break; case SNULL: if (fun_inline) break; /* FALLTHROUGH */ default: cerror("fix stab_newsym; class %d", s->sclass); } } void stabs_chgsym(struct symtab *s) { } /* * define a struct. */ void stabs_struct(struct symtab *p, struct attr *ap) { } struct stabsv { SLIST_ENTRY(stabsv) next; char *str; } ; static SLIST_HEAD(, stabsv) stpole = { NULL, &stpole.q_forw }; /* * Global variable debug info is printed out directly. * For functions and their declarations, both the labels and * the debug info is put into ASM nodes and follows their statements * into pass2. * Due to the possible unsync between pass1 and 2 and where the * stabs info for text is sent over the following syncing is used: * curfun == 0 * print out everything; only data will be. * curfun != 0 && inftn == 0 * save in linked list * curfun != 0 && inftn != 0 * print linked list first, empty it, then arg. */ void cprint(int p2, char *fmt, ...) { #define CPBSZ 200 char buf[CPBSZ]; struct stabsv *w; va_list ap; char *str; if (isinlining) return; /* XXX do not save any inline functions currently */ va_start(ap, fmt); if (p2) { if (vsnprintf(buf, CPBSZ, fmt, ap) >= CPBSZ) werror("stab symbol line too long, truncating"); str = tmpstrdup(buf); if (inftn == 0) { w = tmpalloc(sizeof(struct stabsv)); w->str = str; SLIST_INSERT_LAST(&stpole, w, next); } else { if (stpole.q_last != &stpole.q_forw) { SLIST_FOREACH(w, &stpole, next) { send_passt(IP_ASM, w->str); } SLIST_INIT(&stpole); } send_passt(IP_ASM, str); } } else vprintf(fmt, ap); va_end(ap); } #endif pcc-20181216/cc/ccom/symtabs.c010064400017500000000000000332721277716665000146500ustar raggewheel/* $Id: symtabs.c,v 1.39 2016/10/11 13:48:24 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "pass1.h" #include "unicode.h" #include #define NODE P1ND #define fwalk p1fwalk /* * These definitions are used in the patricia tree that stores * the strings. */ #define LEFT_IS_LEAF 0x80000000 #define RIGHT_IS_LEAF 0x40000000 #define IS_LEFT_LEAF(x) (((x) & LEFT_IS_LEAF) != 0) #define IS_RIGHT_LEAF(x) (((x) & RIGHT_IS_LEAF) != 0) #define BITNO(x) ((x) & ~(LEFT_IS_LEAF|RIGHT_IS_LEAF)) #define CHECKBITS 8 struct tree { int bitno; struct tree *lr[2]; }; extern int dimfuncnt; static struct tree *firstname; int nametabs, namestrlen; static struct tree *firststr; int strtabs, strstrlen, symtreecnt; static char *symtab_add(char *key, struct tree **, int *, int *); int lastloc = NOSEG; int treestrsz = sizeof(struct tree); #define P_BIT(key, bit) (key[bit >> 3] >> (bit & 7)) & 1 #define getree() permalloc(sizeof(struct tree)) char * addname(char *key) { return symtab_add(key, &firstname, &nametabs, &namestrlen); } char * addstring(char *key) { return symtab_add(key, &firststr, &strtabs, &strstrlen); } /* * Add a name to the name stack (if its non-existing), * return its address. * This is a simple patricia implementation. */ static char * symtab_add(char *key, struct tree **first, int *tabs, int *stlen) { struct tree *w, *new, *last; int cix, bit, fbit, svbit, ix, bitno, len; char *m, *k, *sm; /* Count full string length */ for (k = key, len = 0; *k; k++, len++) ; switch (*tabs) { case 0: *first = (struct tree *)newstring(key, len); *stlen += (len + 1); (*tabs)++; return (char *)*first; case 1: m = (char *)*first; svbit = 0; /* XXX why? */ break; default: w = *first; bitno = len * CHECKBITS; for (;;) { bit = BITNO(w->bitno); fbit = bit > bitno ? 0 : P_BIT(key, bit); svbit = fbit ? IS_RIGHT_LEAF(w->bitno) : IS_LEFT_LEAF(w->bitno); w = w->lr[fbit]; if (svbit) { m = (char *)w; break; } } } sm = m; k = key; /* Check for correct string and return */ for (cix = 0; *m && *k && *m == *k; m++, k++, cix += CHECKBITS) ; if (*m == 0 && *k == 0) return sm; ix = *m ^ *k; while ((ix & 1) == 0) ix >>= 1, cix++; /* Create new node */ new = getree(); bit = P_BIT(key, cix); new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF); new->lr[bit] = (struct tree *)newstring(key, len); *stlen += (len + 1); if ((*tabs)++ == 1) { new->lr[!bit] = *first; new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF); *first = new; return (char *)new->lr[bit]; } w = *first; last = NULL; for (;;) { fbit = w->bitno; bitno = BITNO(w->bitno); if (bitno == cix) cerror("bitno == cix"); if (bitno > cix) break; svbit = P_BIT(key, bitno); last = w; w = w->lr[svbit]; if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF)) break; } new->lr[!bit] = w; if (last == NULL) { *first = new; } else { last->lr[svbit] = new; last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF); } if (bitno < cix) new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF); return (char *)new->lr[bit]; } static struct tree *sympole[NSTYPES]; static struct symtab *tmpsyms[NSTYPES]; int numsyms[NSTYPES]; /* * Inserts a symbol into the symbol tree. * Returns a struct symtab. */ struct symtab * lookup(char *key, int stype) { struct symtab *sym; struct tree *w, *new, *last; int cix, bit, fbit, svbit, bitno; int type, uselvl; intptr_t ix, match, code = (intptr_t)key; type = stype & SMASK; uselvl = (blevel > 0 && type != SSTRING); /* * The local symbols are kept in a simple linked list. * Check this list first. */ if (blevel > 0) for (sym = tmpsyms[type]; sym; sym = sym->snext) if (sym->sname == key) return sym; switch (numsyms[type]) { case 0: if (stype & SNOCREAT) return NULL; if (uselvl) { if (type == SNORMAL) stype |= SBLK; sym = getsymtab(key, stype); sym->snext = tmpsyms[type]; tmpsyms[type] = sym; return sym; } sympole[type] = (struct tree *)getsymtab(key, stype); numsyms[type]++; return (struct symtab *)sympole[type]; case 1: w = (struct tree *)sympole[type]; svbit = 0; /* XXX why? */ break; default: w = sympole[type]; for (;;) { bit = BITNO(w->bitno); fbit = (int)(code >> bit) & 1; svbit = fbit ? IS_RIGHT_LEAF(w->bitno) : IS_LEFT_LEAF(w->bitno); w = w->lr[fbit]; if (svbit) break; } } sym = (struct symtab *)w; match = (intptr_t)sym->sname; ix = code ^ match; if (ix == 0) return sym; else if (stype & SNOCREAT) return NULL; #ifdef PCC_DEBUG if (ddebug) printf(" adding %s as %s at level %d\n", key, uselvl ? "temp" : "perm", blevel); #endif /* * Insert into the linked list, if feasible. */ if (uselvl) { sym = getsymtab(key, stype|STEMP); sym->snext = tmpsyms[type]; tmpsyms[type] = sym; return sym; } /* * Need a new node. If type is SNORMAL and inside a function * the node must be allocated as permanent anyway. * This could be optimized by adding a remove routine, but it * may be more trouble than it is worth. */ if (stype == (STEMP|SNORMAL)) stype = SNORMAL; for (cix = 0; (ix & 1) == 0; ix >>= 1, cix++) ; new = (symtreecnt++, permalloc(sizeof(struct tree))); bit = (int)(code >> cix) & 1; new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF); new->lr[bit] = (struct tree *)getsymtab(key, stype); if (numsyms[type]++ == 1) { new->lr[!bit] = sympole[type]; new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF); sympole[type] = new; return (struct symtab *)new->lr[bit]; } w = sympole[type]; last = NULL; for (;;) { fbit = w->bitno; bitno = BITNO(w->bitno); if (bitno == cix) cerror("bitno == cix"); if (bitno > cix) break; svbit = (int)(code >> bitno) & 1; last = w; w = w->lr[svbit]; if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF)) break; } new->lr[!bit] = w; if (last == NULL) { sympole[type] = new; } else { last->lr[svbit] = new; last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF); } if (bitno < cix) new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF); return (struct symtab *)new->lr[bit]; } void symclear(int level) { struct symtab *s; int i; #ifdef PCC_DEBUG if (ddebug) printf("symclear(%d)\n", level); #endif if (level < 1) { for (i = 0; i < NSTYPES; i++) { s = tmpsyms[i]; tmpsyms[i] = 0; if (i != SLBLNAME) continue; while (s != NULL) { if (s->soffset < 0) uerror("label '%s' undefined",s->sname); s = s->snext; } } } else { for (i = 0; i < NSTYPES; i++) { if (i == SLBLNAME) continue; /* function scope */ while (tmpsyms[i] != NULL && tmpsyms[i]->slevel > level) { tmpsyms[i] = tmpsyms[i]->snext; } } } } struct symtab * hide(struct symtab *sym) { struct symtab *new; int typ = sym->sflags & SMASK; new = getsymtab(sym->sname, typ|STEMP); new->snext = tmpsyms[typ]; tmpsyms[typ] = new; #ifdef PCC_DEBUG if (ddebug) printf("\t%s hidden at level %d (%p -> %p)\n", sym->sname, blevel, sym, new); #endif return new; } /* * Extract correct segment for the specified symbol and call * target routines to print it out. * If symtab entry is specified, output alignment as well. */ void locctr(int seg, struct symtab *sp) { #ifdef GCC_COMPAT struct attr *ga; #endif if (seg == NOSEG) { ; } else if (sp == NULL) { if (lastloc != seg) setseg(seg, NULL); #ifdef GCC_COMPAT } else if ((ga = attr_find(sp->sap, GCC_ATYP_SECTION)) != NULL) { setseg(NMSEG, ga->sarg(0)); seg = NOSEG; #endif } else { if (seg == DATA) { if (ISCON(cqual(sp->stype, sp->squal))) seg = RDATA; else if (sp->sclass == STATIC) seg = LDATA; } if (sp->sflags & STLS) { if (seg == DATA || seg == LDATA) seg = TLSDATA; if (seg == UDATA) seg = TLSUDATA; } else if (kflag) { if (seg == DATA) seg = PICDATA; if (seg == RDATA) seg = PICRDATA; if (seg == LDATA) seg = PICLDATA; } if (lastloc != seg) setseg(seg, NULL); } lastloc = seg; /* setup alignment */ #ifndef ALFTN #define ALFTN ALINT #endif if (sp) { int al; if (ISFTN(sp->stype)) { al = ALFTN; } else al = talign(sp->stype, sp->sap); defalign(al); symdirec(sp); } } #ifndef MYALIGN void defalign(int al) { #ifdef HASP2ALIGN #define P2ALIGN(x) ispow2(x) #else #define P2ALIGN(x) (x) #endif if (al != ALCHAR) printf(PRTPREF "\t.align %d\n", P2ALIGN(al/ALCHAR)); } #endif #ifndef MYDIREC /* * Directives given as attributes to symbols. */ void symdirec(struct symtab *sp) { #ifdef GCC_COMPAT struct attr *ga; char *name; name = getexname(sp); if ((ga = attr_find(sp->sap, GCC_ATYP_WEAK)) != NULL) printf(PRTPREF "\t.weak %s\n", name); if ((ga = attr_find(sp->sap, GCC_ATYP_VISIBILITY)) && strcmp(ga->sarg(0), "default")) printf(PRTPREF "\t.%s %s\n", ga->sarg(0), name); if ((ga = attr_find(sp->sap, GCC_ATYP_ALIASWEAK))) { printf(PRTPREF "\t.weak %s\n", ga->sarg(0)); printf(PRTPREF "\t.set %s,%s\n", ga->sarg(0), name); } #endif } #endif char * getexname(struct symtab *sp) { struct attr *ap = attr_find(sp->sap, ATTR_SONAME); return (ap ? ap->sarg(0) : addname(exname(sp->sname))); } static char *csbuf; static int csbufp, cssz, strtype; #ifndef NO_STRING_SAVE static struct symtab *strpole; #endif #define STCHNK 128 static void savch(int ch) { if (csbufp == cssz) { cssz += STCHNK; csbuf = realloc(csbuf, cssz); } csbuf[csbufp++] = ch; } /* * save value as 3-digit octal escape sequence */ static void voct(unsigned int v) { savch('\\'); savch(((v & 0700) >> 6) + '0'); savch(((v & 0070) >> 3) + '0'); savch((v & 0007) + '0'); } /* * Add string new to string old. * String new must come directly after old. * new is expected to be utf-8. Will be cleaned slightly here. */ char * stradd(char *old, char *new) { if (old == NULL) { strtype = 0; csbufp = 0; } else if (old != csbuf) cerror("string synk error"); /* special hack for function names */ for (old = new; *old; old++) ; if (old[-1] != '\"') { do { savch(*new); } while (*new++); return csbuf; } if (*new != '\"') { int ny = *new++; if (ny == 'u' && *new == '8') ny = '8', new++; if (strtype && ny != strtype) uerror("clash in string types"); strtype = ny; } if (*new++ != '\"') cerror("snuff synk error"); while (*new != '\"') { if (*new == '\\') { voct(esccon(&new)); } else if (*new < ' ' || *new > '~') { voct(*(unsigned char *)new++); } else { savch(*new++); } } savch(0); csbufp--; return csbuf; } TWORD styp(void) { TWORD t; if (strtype == 0 || strtype == '8') t = xuchar ? UCHAR+ARY : CHAR+ARY; else if (strtype == 'u') t = ctype(USHORT)+ARY; else if (strtype == 'L') t = WCHAR_TYPE+ARY; else t = ctype(SZINT < 32 ? ULONG : UNSIGNED)+ARY; return t; } /* * Create a string struct. */ static void strst(struct symtab *sp, TWORD t) { char *wr; int i; sp->sclass = STATIC; sp->slevel = 1; sp->soffset = getlab(); sp->squal = (CON >> TSHIFT); #ifndef NO_STRING_SAVE sp->sdf = permalloc(sizeof(union dimfun)); #else sp->sdf = stmtalloc(sizeof(union dimfun)); #endif dimfuncnt++; sp->stype = t; for (wr = sp->sname, i = 1; *wr; i++) { if (strtype == 'L' || strtype == 'U' || strtype == 'u') (void)u82cp(&wr); else if (*wr == '\\') (void)esccon(&wr); else wr++; } sp->sdf->ddim = i; #ifndef NO_STRING_SAVE sp->snext = strpole; strpole = sp; #endif } /* * Save string (if needed) and return NODE for it. * String is already in utf-8 format. */ NODE * strend(char *s, TWORD t) { struct symtab *sp, *sp2; NODE *p; #ifdef NO_STRING_SAVE sp = getsymtab(s, SSTRING|SSTMT); #else s = addstring(s); sp = lookup(s, SSTRING); #endif if (sp->soffset && sp->stype != t) { /* same string stored but different type */ /* This is uncommon, create a new symtab struct for it */ sp2 = permalloc(sizeof(*sp)); *sp2 = *sp; strst(sp2, t); sp = sp2; } else if (sp->soffset == 0) { /* No string */ strst(sp, t); } if (cssz > STCHNK) { cssz = STCHNK; csbuf = realloc(csbuf, cssz); } #ifdef NO_STRING_SAVE instring(sp); #endif p = block(NAME, NIL, NIL, sp->stype, sp->sdf, sp->sap); p->n_sp = sp; return(clocal(p)); } #ifndef NO_STRING_SAVE /* * Print out strings that have been referenced. */ void strprint(void) { struct symtab *sp; for (sp = strpole; sp; sp = sp->snext) { if ((sp->sflags & SASG) == 0) continue; /* not referenced */ instring(sp); } } #endif pcc-20181216/cc/ccom/trees.c010064400017500000000000002203401340102345600142570ustar raggewheel/* $Id: trees.c,v 1.387 2018/12/02 18:40:46 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code and documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditionsand the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Some of the changes from 32V include: * - Understand "void" as type. * - Handle enums as ints everywhere. * - Convert some C-specific ops into branches. */ # include "pass1.h" # include "pass2.h" # include # include # include static void chkpun(P1ND *p); static int opact(P1ND *p); static int moditype(TWORD); static P1ND *strargs(P1ND *); static void rmcops(P1ND *p); static P1ND *tymatch(P1ND *p); static P1ND *rewincop(P1ND *p1, P1ND *p2, int op); static int has_se(P1ND *p); static struct symtab *findmember(struct symtab *, char *); int inftn; /* currently between epilog/prolog */ P1ND *cstknode(TWORD t, union dimfun *df, struct attr *ap); static char *tnames[] = { "undef", "farg", "char", "unsigned char", "short", "unsigned short", "int", "unsigned int", "long", "unsigned long", "long long", "unsigned long long", "float", "double", "long double", "strty", "unionty", "enumty", "moety", "void", "signed", /* pass1 */ "bool", /* pass1 */ "fimag", /* pass1 */ "dimag", /* pass1 */ "limag", /* pass1 */ "fcomplex", /* pass1 */ "dcomplex", /* pass1 */ "lcomplex", /* pass1 */ "enumty", /* pass1 */ "?", "?" }; /* some special actions, used in finding the type of nodes */ # define NCVT 01 # define PUN 02 # define TYPL 04 # define TYPR 010 # define TYMATCH 040 # define LVAL 0100 # define CVTO 0200 # define CVTL 0400 # define CVTR 01000 # define PTMATCH 02000 # define OTHER 04000 # define NCVTR 010000 # define PROML 020000 /* promote left operand */ /* node conventions: NAME: rval>0 is stab index for external rval<0 is -inlabel number lval is offset in bits ICON: lval has the value rval has the STAB index, or - label number, if a name whose address is in the constant rval = NONAME means no name REG: rval is reg. identification cookie */ /* negatives of relationals */ int p1negrel[] = { NE, EQ, GT, GE, LT, LE, UGT, UGE, ULT, ULE }; /* Have some defaults for most common targets */ #ifndef WORD_ADDRESSED #define offcon(o,t,d,ap) xbcon((o/SZCHAR), NULL, INTPTR) #define VBLOCK(p,b,t,d,a) buildtree(DIV, p, b) #define MBLOCK(p,b,t,d,a) buildtree(MUL, p, b) #else #define VBLOCK(p,b,t,d,a) block(PVCONV, p, b, t, d, a) #define MBLOCK(p,b,t,d,a) block(PMCONV, p, b, t, d, a) #endif P1ND * buildtree(int o, P1ND *l, P1ND *r) { P1ND *p, *q; int actions; int opty, n; struct symtab *sp = NULL; /* XXX gcc */ P1ND *lr, *ll; int evalflt = CAN_EVAL_FLOAT(); #ifdef PCC_DEBUG if (bdebug) { printf("buildtree(%s, %p, %p)\n", copst(o), l, r); if (l) p1fwalk(l, eprint, 0); if (r) p1fwalk(r, eprint, 0); } #endif opty = coptype(o); /* check for constants */ if (o == ANDAND || o == OROR || o == NOT) { if (l->n_op == FCON) { p = bcon(!FLOAT_ISZERO(l->n_scon)); p1nfree(l); l = p; } if (o != NOT && r->n_op == FCON) { p = bcon(!FLOAT_ISZERO(r->n_scon)); p1nfree(r); r = p; } } if( opty == UTYPE && l->n_op == ICON ){ switch( o ){ case NOT: case UMINUS: case COMPL: if( conval( l, o, l ) ) return(l); break; } } else if (o == NOT && l->n_op == FCON) { l = clocal(block(SCONV, l, NULL, INT, 0, 0)); } else if( o == UMINUS && l->n_op == FCON && evalflt){ FLOAT_NEG(l->n_scon); return(l); } else if( o==QUEST && (l->n_op==ICON || (l->n_op==NAME && ISARY(l->n_type)))) { CONSZ c = glval(l); if (l->n_op==NAME) c = 1; /* will become constant later */ p1nfree(l); if (c) { p1walkf(r->n_right, putjops, 0); p1tfree(r->n_right); l = r->n_left; } else { p1walkf(r->n_left, putjops, 0); p1tfree(r->n_left); l = r->n_right; } p1nfree(r); return(l); } else if( opty == BITYPE && l->n_op == ICON && r->n_op == ICON ){ switch( o ){ case PLUS: case MINUS: case MUL: case DIV: case MOD: /* * Do type propagation for simple types here. * The constant value is correct anyway. * Maybe this op shortcut should be removed? */ if (l->n_sp == NULL && r->n_sp == NULL && l->n_type < BTMASK && r->n_type < BTMASK) { if (l->n_type > r->n_type) r->n_type = l->n_type; else l->n_type = r->n_type; } /* FALLTHROUGH */ case ULT: case UGT: case ULE: case UGE: case LT: case GT: case LE: case GE: case EQ: case NE: case ANDAND: case OROR: case AND: case OR: case ER: case LS: case RS: if (!ISPTR(l->n_type) && !ISPTR(r->n_type)) { if( conval( l, o, r ) ) { p1nfree(r); return(l); } } break; } } else if (opty == BITYPE && (l->n_op == FCON || l->n_op == ICON) && (r->n_op == FCON || r->n_op == ICON) && (o == PLUS || o == MINUS || o == MUL || o == DIV || (o >= EQ && o <= GT) ) && evalflt) { /* at least one side is FCON */ #ifndef CC_DIV_0 if (o == DIV && ((r->n_op == ICON && glval(r) == 0) || (r->n_op == FCON && FLOAT_ISZERO(r->n_scon)))) goto runtime; /* HW dependent */ #endif if (l->n_op == ICON) { if (!concast(l, r->n_type)) cerror("fail cast const"); } else if (r->n_op == ICON) { if (!concast(r, l->n_type)) cerror("fail cast const"); } switch(o){ case PLUS: case MINUS: case MUL: case DIV: switch (o) { case PLUS: FLOAT_PLUS(l, r); break; case MINUS: FLOAT_MINUS(l, r); break; case MUL: FLOAT_MUL(l, r); break; case DIV: FLOAT_DIV(l, r); break; } p1nfree(r); return(l); case EQ: case NE: case LE: case LT: case GE: case GT: switch (o) { case EQ: n = FLOAT_EQ(l->n_scon, r->n_scon); break; case NE: n = FLOAT_NE(l->n_scon, r->n_scon); break; case LE: n = FLOAT_LE(l->n_scon, r->n_scon); break; case LT: n = FLOAT_LT(l->n_scon, r->n_scon); break; case GE: n = FLOAT_GE(l->n_scon, r->n_scon); break; case GT: n = FLOAT_GT(l->n_scon, r->n_scon); break; default: n = 0; /* XXX flow analysis */ } p1nfree(r); p1nfree(l); return bcon(n); } } else if ((cdope(o)&ASGOPFLG) && o != RETURN && o != CAST) { if (l->n_op == SCONV && l->n_left->n_op == FLD) l = p1nfree(l); /* * Handle side effects by storing address in temporary q. * Side effect nodes always have an UMUL. */ if (has_se(l)) { ll = l->n_left; q = cstknode(ll->n_type, ll->n_df, ll->n_ap); l->n_left = p1tcopy(q); q = buildtree(ASSIGN, q, ll); } else q = bcon(0); /* No side effects */ /* * Modify the trees so that the compound op is rewritten. */ /* avoid casting of LHS */ if ((cdope(o) & SIMPFLG) && ISINTEGER(l->n_type) && l->n_type != BOOL) r = ccast(r, l->n_type, l->n_qual, l->n_df, l->n_ap); r = buildtree(UNASG o, p1tcopy(l), r); r = buildtree(ASSIGN, l, r); l = q; o = COMOP; } else if (o == INCR || o == DECR) { if (l->n_op == SCONV && l->n_left->n_op == FLD) l = p1nfree(l); /* * Rewrite to (t=d,d=d+1,t) */ if (has_se(l)) { ll = l->n_left; q = cstknode(ll->n_type, ll->n_df, ll->n_ap); l->n_left = p1tcopy(q); q = buildtree(ASSIGN, q, ll); } else q = bcon(0); /* No side effects */ /* Boolean has special syntax. */ if (l->n_type == BOOL) { r = rewincop(l, r, o == INCR ? ASSIGN : EREQ); } else r = rewincop(l, r, o == INCR ? PLUSEQ : MINUSEQ); l = q; o = COMOP; } else if (o == ASSIGN && l->n_op == SCONV && l->n_left->n_op == FLD) { l = p1nfree(l); } #ifndef CC_DIV_0 runtime: #endif /* its real; we must make a new node */ p = block(o, l, r, INT, 0, 0); actions = opact(p); if (actions & PROML) p->n_left = intprom(p->n_left); if (actions & LVAL) { /* check left descendent */ if (notlval(p->n_left)) { uerror("lvalue required"); p1nfree(p); return l; #ifdef notyet } else { if ((l->n_type > BTMASK && ISCON(l->n_qual)) || (l->n_type <= BTMASK && ISCON(l->n_qual << TSHIFT))) if (blevel > 0) uerror("lvalue is declared const"); #endif } } if( actions & NCVTR ){ p->n_left = pconvert( p->n_left ); } else if( !(actions & NCVT ) ){ switch( opty ){ case BITYPE: p->n_right = pconvert( p->n_right ); /* FALLTHROUGH */ case UTYPE: p->n_left = pconvert( p->n_left ); } } if ((actions&PUN) && (o!=CAST)) chkpun(p); if( actions & (TYPL|TYPR) ){ q = (actions&TYPL) ? p->n_left : p->n_right; p->n_type = q->n_type; p->n_qual = q->n_qual; p->n_df = q->n_df; p->n_ap = q->n_ap; } if( actions & CVTL ) p = convert( p, CVTL ); if( actions & CVTR ) p = convert( p, CVTR ); if( actions & TYMATCH ) p = tymatch(p); if( actions & PTMATCH ) p = ptmatch(p); if( actions & OTHER ){ struct symtab *sp1; l = p->n_left; r = p->n_right; switch(o){ case NAME: cerror("buildtree NAME"); case STREF: /* p->x turned into *(p+offset) */ /* rhs must be a name; check correctness */ /* Find member symbol struct */ if (l->n_type != PTR+STRTY && l->n_type != PTR+UNIONTY){ uerror("struct or union required"); break; } if ((sp1 = strmemb(l->n_ap)) == NULL) { uerror("undefined struct or union"); break; } if ((sp = findmember(sp1, r->n_name)) == NULL) { uerror("member '%s' not declared", r->n_name); break; } r->n_sp = sp; p = stref(p); break; case UMUL: if (l->n_op == ADDROF) { p1nfree(p); p = p1nfree(l); } if( !ISPTR(l->n_type))uerror("illegal indirection"); p->n_type = DECREF(l->n_type); p->n_qual = DECREF(l->n_qual); p->n_df = l->n_df; p->n_ap = l->n_ap; break; case ADDROF: switch( l->n_op ){ case UMUL: p1nfree(p); p = p1nfree(l); /* FALLTHROUGH */ case TEMP: case NAME: p->n_type = INCREF(l->n_type); p->n_qual = INCQAL(l->n_qual); p->n_df = l->n_df; p->n_ap = l->n_ap; break; case COMOP: p1nfree(p); lr = buildtree(ADDROF, l->n_right, NULL); p = buildtree( COMOP, l->n_left, lr ); p1nfree(l); break; case QUEST: lr = buildtree( ADDROF, l->n_right->n_right, NULL ); ll = buildtree( ADDROF, l->n_right->n_left, NULL ); p1nfree(p); p1nfree(l->n_right); p = buildtree( QUEST, l->n_left, buildtree( COLON, ll, lr ) ); p1nfree(l); break; default: uerror("unacceptable operand of &: %d", l->n_op ); break; } break; case LS: case RS: /* must make type size at least int... */ if (p->n_type == CHAR || p->n_type == SHORT) { p->n_left = makety(l, INT, 0, 0, 0); } else if (p->n_type == UCHAR || p->n_type == USHORT) { p->n_left = makety(l, UNSIGNED, 0, 0, 0); } l = p->n_left; p->n_type = l->n_type; p->n_qual = l->n_qual; p->n_df = l->n_df; p->n_ap = l->n_ap; if(tsize(r->n_type, r->n_df, r->n_ap) > SZINT) p->n_right = makety(r, INT, 0, 0, 0); break; case RETURN: case ASSIGN: case CAST: /* structure assignment */ /* take the addresses of the two sides; then make an * operator using STASG and * the addresses of left and right */ if (strmemb(l->n_ap) != strmemb(r->n_ap)) uerror("assignment of different structures"); r = buildtree(ADDROF, r, NULL); l = block(STASG, l, r, r->n_type, r->n_df, r->n_ap); l = clocal(l); if( o == RETURN ){ p1nfree(p); p = l; break; } p->n_op = UMUL; p->n_left = l; p->n_right = NULL; break; case QUEST: /* fixup types of : */ if (r->n_left->n_type != p->n_type) r->n_left = makety(r->n_left, p->n_type, p->n_qual, p->n_df, p->n_ap); if (r->n_right->n_type != p->n_type) r->n_right = makety(r->n_right, p->n_type, p->n_qual, p->n_df, p->n_ap); break; case COLON: /* structure colon */ if (strmemb(l->n_ap) != strmemb(r->n_ap)) uerror( "type clash in conditional" ); break; case CALL: p->n_right = r = strargs(p->n_right); p = funcode(p); /* FALLTHROUGH */ case UCALL: if (!ISPTR(l->n_type)) uerror("illegal function"); p->n_type = DECREF(l->n_type); if (!ISFTN(p->n_type)) uerror("illegal function"); p->n_type = DECREF(p->n_type); p->n_df = l->n_df+1; /* add one for prototypes */ p->n_ap = l->n_ap; if (p->n_type == STRTY || p->n_type == UNIONTY) { /* function returning structure */ /* make function really return ptr to str., with * */ p->n_op += STCALL-CALL; p->n_type = INCREF(p->n_type); p = clocal(p); /* before recursing */ p = buildtree(UMUL, p, NULL); } break; default: cerror( "other code %d", o ); } } /* fixup type in bit-field assignment */ if (p->n_op == ASSIGN && l->n_op == FLD && UPKFSZ(l->n_rval) < SZINT) p = makety(p, INT, 0, 0, 0); /* * Allow (void)0 casts. * XXX - anything on the right side must be possible to cast. * XXX - remove void types further on. */ if (p->n_op == CAST && p->n_type == VOID && p->n_right->n_op == ICON) p->n_right->n_type = VOID; if (actions & CVTO) p = oconvert(p); p = clocal(p); #ifdef PCC_DEBUG if (bdebug) { printf("End of buildtree:\n"); p1fwalk(p, eprint, 0); } #endif return(p); } /* * Rewrite ++/-- to (t=p, p++, t) ops on types that do not act act as usual. */ static P1ND * rewincop(P1ND *p1, P1ND *p2, int op) { P1ND *t, *r; t = cstknode(p1->n_type, p1->n_df, p1->n_ap); r = buildtree(ASSIGN, p1tcopy(t), p1tcopy(p1)); r = buildtree(COMOP, r, buildtree(op, p1, eve(p2))); return buildtree(COMOP, r, t); } /* Find a member in a struct or union. May be an unnamed member */ static struct symtab * findmember(struct symtab *sp, char *s) { struct symtab *sp2, *sp3; for (; sp != NULL; sp = sp->snext) { if (sp->sname[0] == '*') { /* unnamed member, recurse down */ if ((sp2 = findmember(strmemb(sp->sap), s))) { sp3 = tmpalloc(sizeof (struct symtab)); *sp3 = *sp2; sp3->soffset += sp->soffset; return sp3; } } else if (sp->sname == s) return sp; } return NULL; } /* * Check if there will be a lost label destination inside of a ?: * It cannot be reached so just print it out. */ void putjops(P1ND *p, void *arg) { if (p->n_op == COMOP && p->n_left->n_op == GOTO) plabel((int)glval(p->n_left->n_left)+2); } /* * Build a name node based on a symtab entry. * broken out from buildtree(). */ P1ND * nametree(struct symtab *sp) { P1ND *p; p = block(NAME, NULL, NULL, sp->stype, sp->sdf, sp->sap); p->n_qual = sp->squal; p->n_sp = sp; #ifndef NO_C_BUILTINS if (sp->sname[0] == '_' && strncmp(sp->sname, "__builtin_", 10) == 0) return p; /* do not touch builtins here */ #endif if (sp->sflags & STNODE) { /* Generated for optimizer */ p->n_op = TEMP; p->n_rval = sp->soffset; } #ifdef GCC_COMPAT /* Get a label name */ if (sp->sflags == SLBLNAME) sp->stype = p->n_type = VOID; if (sp->sflags & SINREG) { p->n_op = REG; regno(p) = (int)sp->soffset; } #endif if (sp->stype == UNDEF) { uerror("%s undefined", sp->sname); /* make p look reasonable */ p->n_type = INT; p->n_df = NULL; defid(p, SNULL); } if (sp->sclass == MOE) { p->n_op = ICON; slval(p, sp->soffset); p->n_df = NULL; p->n_sp = NULL; } return clocal(p); } /* * Cast a node to another type by inserting a cast. * Just a nicer interface to buildtree. * Returns the new tree. */ P1ND * cast(P1ND *p, TWORD t, TWORD u) { P1ND *q; q = block(NAME, NULL, NULL, t, 0, 0); q->n_qual = u; q = buildtree(CAST, q, p); p = q->n_right; p1nfree(q->n_left); p1nfree(q); return p; } /* * Cast and complain if necessary by not inserining a cast. */ P1ND * ccast(P1ND *p, TWORD t, TWORD u, union dimfun *df, struct attr *ap) { P1ND *q; /* let buildtree do typechecking (and casting) */ q = block(NAME, NULL, NULL, t, df, ap); p = buildtree(ASSIGN, q, p); p1nfree(p->n_left); q = optim(p->n_right); p1nfree(p); return q; } /* * Do an actual cast of a constant (if possible). * Routine assumes 2-complement. p is cast to type t. * Returns 1 if handled, 0 otherwise. */ int concast(P1ND *p, TWORD t) { extern short sztable[]; int evalflt = CAN_EVAL_FLOAT(); CONSZ val; if (p->n_op != ICON && p->n_op != FCON) /* only constants */ return 0; if (p->n_op == ICON && p->n_sp != NULL) { /* no addresses */ if (t == BOOL) { slval(p, 1), p->n_type = BOOL, p->n_sp = NULL; return 1; } return 0; } if (((p->n_type & TMASK) && t != BOOL) || (t & TMASK)) /* no pointers */ return 0; //printf("concast till %d\n", t); //fwalk(p, eprint, 0); #define TYPMSK(y) ((((1LL << (y-1))-1) << 1) | 1) if (p->n_op == ICON) { val = glval(p); if (t == BOOL) { if (val) slval(p, 1); } else if (t <= ULONGLONG) { slval(p, val & TYPMSK(sztable[t])); if (!ISUNSIGNED(t)) { if (val & (1LL << (sztable[t]-1))) slval(p, glval(p) | ~TYPMSK(sztable[t])); } } else if (t <= LDOUBLE) { if (!evalflt) return 0; p->n_op = FCON; p->n_scon = sfallo(); FLOAT_INT2FP(p->n_scon, val, p->n_type); } } else { /* p->n_op == FCON */ if (!evalflt) return 0; if (t == BOOL) { p->n_op = ICON; slval(p, !FLOAT_ISZERO(p->n_scon)); p->n_sp = NULL; } else if (t <= ULONGLONG) { p->n_op = ICON; FLOAT_FP2INT(glval(p), p->n_scon, t); p->n_sp = NULL; } else { FLOAT_FP2FP(p->n_scon, t); } } p->n_type = t; //fwalk(p, eprint, 0); return 1; } /* * Do a conditional branch. */ void cbranch(P1ND *p, P1ND *q) { p = buildtree(CBRANCH, p, q); if (p->n_left->n_op == ICON) { if (glval(p->n_left) != 0) { branch((int)glval(q)); /* branch always */ reached = 0; } p1tfree(p); return; } ecomp(p); } P1ND * strargs(register P1ND *p) { /* rewrite structure flavored arguments */ if( p->n_op == CM ){ p->n_left = strargs( p->n_left ); p->n_right = strargs( p->n_right ); return( p ); } if( p->n_type == STRTY || p->n_type == UNIONTY ){ p = block(STARG, p, NULL, p->n_type, p->n_df, p->n_ap); p->n_left = buildtree( ADDROF, p->n_left, NULL ); p = clocal(p); } return( p ); } /* * apply the op o to the lval part of p; if binary, rhs is val */ int conval(P1ND *p, int o, P1ND *q) { TWORD tl = p->n_type, tr = q->n_type, td; int i, u; CONSZ val; U_CONSZ v1, v2; val = glval(q); /* make both sides same type */ if (tl < BTMASK && tr < BTMASK) { td = tl > tr ? tl : tr; if (td < INT) td = INT; u = ISUNSIGNED(td); if (tl != td) p = makety(p, td, 0, 0, 0); if (tr != td) q = makety(q, td, 0, 0, 0); } else u = ISUNSIGNED(tl) || ISUNSIGNED(tr); if( u && (o==LE||o==LT||o==GE||o==GT)) o += (UGE-GE); if (p->n_sp != NULL && q->n_sp != NULL) return(0); if (q->n_sp != NULL && o != PLUS) return(0); if (p->n_sp != NULL && o != PLUS && o != MINUS) return(0); v1 = glval(p); v2 = glval(q); if (v2 == 0 && (cdope(o) & DIVFLG)) return 0; /* leave division by zero to runtime */ switch( o ){ case PLUS: slval(p, (glval(p) + val)); if (p->n_sp == NULL) { p->n_right = q->n_right; p->n_type = q->n_type; } break; case MINUS: slval(p, (glval(p) - val)); break; case MUL: slval(p, (glval(p) * val)); break; case DIV: if (u) { v1 /= v2; slval(p, v1); } else slval(p, (glval(p) / val)); break; case MOD: if (u) { v1 %= v2; slval(p, v1); } else slval(p, (glval(p) % val)); break; case AND: slval(p, (glval(p) & val)); break; case OR: slval(p, (glval(p) | val)); break; case ER: slval(p, (glval(p) ^ val)); break; case LS: i = (int)val; slval(p, glval(p) << i); break; case RS: i = (int)val; if (u) { v1 = v1 >> i; slval(p, v1); } else { slval(p, glval(p) >> i); } break; case UMINUS: slval(p, (-glval(p))); break; case COMPL: slval(p, (~glval(p))); break; case NOT: slval(p, (!glval(p))); p->n_type = INT; break; case LT: slval(p, (glval(p) < val)); break; case LE: slval(p, (glval(p) <= val)); break; case GT: slval(p, (glval(p) > val)); break; case GE: slval(p, (glval(p) >= val)); break; case ULT: slval(p, (v1 < v2)); break; case ULE: slval(p, (v1 <= v2)); break; case UGT: slval(p, (v1 > v2)); break; case UGE: slval(p, (v1 >= v2)); break; case EQ: slval(p, (glval(p) == val)); break; case NE: slval(p, (glval(p) != val)); break; case ANDAND: slval(p, (glval(p) && val)); break; case OROR: slval(p, (glval(p) || val)); break; default: return(0); } /* Do the best in making everything type correct after calc */ if (clogop(o)) p->n_type = INT; if (p->n_sp == NULL && q->n_sp == NULL) { slval(p, valcast(glval(p), p->n_type)); } return(1); } /* * Ensure that v matches the type t; sign- or zero-extended * as suitable to CONSZ. * Only to be used for integer types. */ CONSZ valcast(CONSZ v, TWORD t) { CONSZ r; int sz; if (t < CHAR || t > ULONGLONG) return v; /* cannot cast */ if (t >= LONGLONG) return v; /* already largest */ #define M(x) ((((1ULL << ((x)-1)) - 1) << 1) + 1) #define NOTM(x) (~M(x)) #define SBIT(x) (1ULL << ((x)-1)) sz = (int)tsize(t, NULL, NULL); r = v & M(sz); if (!ISUNSIGNED(t) && (SBIT(sz) & r)) r = r | NOTM(sz); return r; } /* * Checks p for the existence of a pun. This is called when the op of p * is ASSIGN, RETURN, CAST, COLON, or relational. * One case is when enumerations are used: this applies only to lint. * In the other case, one operand is a pointer, the other integer type * we check that this integer is in fact a constant zero... * in the case of ASSIGN, any assignment of pointer to integer is illegal * this falls out, because the LHS is never 0. * XXX - check for COMOPs in assignment RHS? */ void chkpun(P1ND *p) { union dimfun *d1, *d2; P1ND *q; int t1, t2; t1 = p->n_left->n_type; t2 = p->n_right->n_type; switch (p->n_op) { case RETURN: /* return of void allowed but nothing else */ if (t1 == VOID && t2 == VOID) return; if (t1 == VOID) { werror("returning value from void function"); return; } if (t2 == VOID) { uerror("using void value"); return; } break; case COLON: if (t1 == VOID && t2 == VOID) return; break; default: if ((t1 == VOID && t2 != VOID) || (t1 != VOID && t2 == VOID)) { uerror("value of void expression used"); return; } break; } /* allow void pointer assignments in any direction */ if (BTYPE(t1) == VOID && (t2 & TMASK)) return; if (BTYPE(t2) == VOID && (t1 & TMASK)) return; /* boolean have special syntax */ if (t1 == BOOL) { if (!ISARY(t2)) /* Anything scalar */ return; } if (ISPTR(t1) || ISARY(t1)) q = p->n_right; else q = p->n_left; if (!ISPTR(q->n_type) && !ISARY(q->n_type)) { if (q->n_op != ICON || glval(q) != 0) werror("illegal combination of pointer and integer"); } else { if (t1 == t2) { if (ISSOU(BTYPE(t1)) && !suemeq(p->n_left->n_ap, p->n_right->n_ap)) werror("illegal structure pointer combination"); return; } d1 = p->n_left->n_df; d2 = p->n_right->n_df; for (;;) { if (ISARY(t1) || ISPTR(t1)) { if (!ISARY(t2) && !ISPTR(t2)) break; if (ISARY(t1) && ISARY(t2) && d1->ddim != d2->ddim) { werror("illegal array size combination"); return; } if (ISARY(t1)) ++d1; if (ISARY(t2)) ++d2; } else if (ISFTN(t1)) { if (chkftn(d1->dfun, d2->dfun)) { werror("illegal function " "pointer combination"); return; } ++d1; ++d2; } else break; t1 = DECREF(t1); t2 = DECREF(t2); } if (DEUNSIGN(t1) != DEUNSIGN(t2)) werror("illegal pointer combination"); else if (t1 != t2) warner(Wpointer_sign); } } static P1ND * offplus(P1ND *p, int off, TWORD t, TWORD q, union dimfun *d, struct attr *ap) { if (off != 0) { p = block(PLUS, p, offcon(off, t, d, ap), t, d, ap); p->n_qual = q; p = optim(p); } return buildtree(UMUL, p, NULL); } P1ND * stref(P1ND *p) { P1ND *r; struct attr *ap, *xap, *yap; union dimfun *d; TWORD t, q; int dsc, fsz; OFFSZ off; struct symtab *s; /* make p->x */ /* this is also used to reference automatic variables */ s = p->n_right->n_sp; p1nfree(p->n_right); r = p1nfree(p); #ifdef GCC_COMPAT xap = attr_find(r->n_ap, GCC_ATYP_PACKED); #else xap = NULL; #endif p = pconvert(r); /* make p look like ptr to x */ if (!ISPTR(p->n_type)) p->n_type = PTR+UNIONTY; t = INCREF(s->stype); q = INCQAL(s->squal); d = s->sdf; ap = s->sap; #ifdef GCC_COMPAT if ((yap = attr_find(ap, GCC_ATYP_PACKED)) != NULL) xap = yap; else if (xap != NULL) ap = attr_add(ap, attr_dup(xap)); /* xap set if packed struct */ #else yap = NULL; #endif p = makety(p, t, q, d, ap); /* compute the offset to be added */ off = s->soffset; dsc = s->sclass; if (dsc & FIELD) { TWORD ftyp = s->stype; int fal = talign(ftyp, ap); fsz = dsc&FLDSIZ; off = (off/fal)*fal; p = offplus(p, off, t, q, d, ap); p = block(FLD, p, NULL, ftyp, 0, ap); p->n_qual = q; p->n_rval = PKFIELD(fsz, s->soffset%fal); /* make type int or some other signed type */ if (fsz < SZINT) ftyp = INT; else if (fsz > SZINT && fsz < SZLONG && ftyp < LONG) ftyp = LONG; else if (fsz > SZLONG && fsz < SZLONGLONG && ftyp < LONGLONG) ftyp = LONGLONG; if (ftyp != p->n_type) p = makety(p, ftyp, 0, 0, 0); } else { p = offplus(p, off, t, q, d, ap); #ifndef CAN_UNALIGN /* if target cannot handle unaligned addresses, fix here */ #endif } p = clocal(p); return p; } int notlval(register P1ND *p) { /* return 0 if p an lvalue, 1 otherwise */ again: switch( p->n_op ){ case FLD: p = p->n_left; goto again; case NAME: case OREG: case UMUL: if( ISARY(p->n_type) || ISFTN(p->n_type) ) return(1); /* FALLTHROUGH */ case TEMP: case REG: return(0); default: return(1); } } /* make a constant node with value i */ P1ND * bcon(int i) { return xbcon(i, NULL, INT); } P1ND * xbcon(CONSZ val, struct symtab *sp, TWORD type) { P1ND *p; p = block(ICON, NULL, NULL, type, 0, 0); slval(p, val); p->n_sp = sp; return clocal(p); } P1ND * bpsize(P1ND *p) { int isdyn(struct symtab *sp); struct symtab s; P1ND *q, *r; TWORD t; int sz; s.stype = DECREF(p->n_type); s.sdf = p->n_df; if (isdyn(&s)) { q = bcon(1); for (t = s.stype; t > BTMASK; t = DECREF(t)) { if (ISPTR(t)) return buildtree(MUL, q, bcon(SZPOINT(t))); if (ISARY(t)) { if (s.sdf->ddim < 0) r = tempnode(-s.sdf->ddim, INT, 0, 0); else r = bcon(s.sdf->ddim/SZCHAR); q = buildtree(MUL, q, r); s.sdf++; } } sz = (int)tsize(t, s.sdf, p->n_ap); p = buildtree(MUL, q, bcon(sz/SZCHAR)); } else p = (offcon(psize(p), p->n_type, p->n_df, p->n_ap)); return p; } /* * p is a node of type pointer; psize returns the * size of the thing pointed to */ OFFSZ psize(P1ND *p) { if (!ISPTR(p->n_type)) { uerror("pointer required"); return(SZINT); } /* note: no pointers to fields */ return(tsize(DECREF(p->n_type), p->n_df, p->n_ap)); } /* * convert an operand of p * f is either CVTL or CVTR * operand has type int, and is converted by the size of the other side * convert is called when an integer is to be added to a pointer, for * example in arrays or structures. */ P1ND * convert(P1ND *p, int f) { union dimfun *df; TWORD ty, ty2; P1ND *q, *r, *s, *rv; if (f == CVTL) { q = p->n_left; s = p->n_right; } else { q = p->n_right; s = p->n_left; } ty2 = ty = DECREF(s->n_type); while (ISARY(ty)) ty = DECREF(ty); r = offcon(tsize(ty, s->n_df, s->n_ap), s->n_type, s->n_df, s->n_ap); ty = ty2; rv = bcon(1); df = s->n_df; while (ISARY(ty)) { rv = buildtree(MUL, rv, df->ddim >= 0 ? bcon(df->ddim) : tempnode(-df->ddim, INT, 0, 0)); df++; ty = DECREF(ty); } rv = clocal(MBLOCK(rv, r, INT, 0, 0)); rv = optim(rv); r = MBLOCK(q, rv, INT, 0, 0); r = clocal(r); /* * Indexing is only allowed with integer arguments, so insert * SCONV here if arg is not an integer. * XXX - complain? */ if (r->n_type != INTPTR) r = clocal(makety(r, INTPTR, 0, 0, 0)); if (f == CVTL) p->n_left = r; else p->n_right = r; return(p); } P1ND * pconvert(register P1ND *p) { /* if p should be changed into a pointer, do so */ if( ISARY( p->n_type) ){ p->n_type = DECREF( p->n_type ); ++p->n_df; return( buildtree( ADDROF, p, NULL ) ); } if( ISFTN( p->n_type) ) return( buildtree( ADDROF, p, NULL ) ); return( p ); } P1ND * oconvert(register P1ND *p) { /* convert the result itself: used for pointer and unsigned */ switch(p->n_op) { case LE: case LT: case GE: case GT: if(ISUNSIGNED(p->n_left->n_type) || ISUNSIGNED(p->n_right->n_type) || ISPTR(p->n_left->n_type) || ISPTR(p->n_right->n_type)) p->n_op += (ULE-LE); /* FALLTHROUGH */ case EQ: case NE: return( p ); case MINUS: p->n_type = INTPTR; p->n_ap = NULL; return(clocal(VBLOCK(p, bpsize(p->n_left), INT, 0, 0))); } cerror( "illegal oconvert: %d", p->n_op ); return(p); } /* * makes the operands of p agree; they are * either pointers or integers, by this time * with MINUS, the sizes must be the same * with COLON, the types must be the same */ P1ND * ptmatch(P1ND *p) { struct attr *ap, *ap2; union dimfun *d, *d2; TWORD t1, t2, t, q1, q2, q; int o; o = p->n_op; t = t1 = p->n_left->n_type; q = q1 = p->n_left->n_qual; t2 = p->n_right->n_type; q2 = p->n_right->n_qual; d = p->n_left->n_df; d2 = p->n_right->n_df; ap = p->n_left->n_ap; ap2 = p->n_right->n_ap; switch( o ){ case ASSIGN: case RETURN: { break; } case CAST: if (t == VOID) { /* just paint over */ p->n_right = block(SCONV, p->n_right, NULL, VOID, 0, 0); return p; } break; case MINUS: { int isdyn(struct symtab *sp); struct symtab s1, s2; s1.stype = DECREF(t); s1.sdf = d; s2.stype = DECREF(t2); s2.sdf = d2; if (isdyn(&s1) || isdyn(&s2)) ; /* We don't know */ else if (psize(p->n_left) != psize(p->n_right)) uerror("illegal pointer subtraction"); break; } case COLON: if (t1 != t2) { /* * Check for void pointer types. They are allowed * to cast to/from any pointers; 6.5.15 #6. * XXX qualified versions of void? */ if (ISPTR(t1) && ISPTR(t2)) { if (BTYPE(t1) == VOID) { t = t2; d = d2; ap = ap2; break; } if (BTYPE(t2) == VOID) break; } uerror("illegal types in :"); } break; default: /* must work harder: relationals or comparisons */ if( !ISPTR(t1) ){ t = t2; q = q2; d = d2; ap = ap2; break; } if( !ISPTR(t2) ){ break; } /* both are pointers */ if( talign(t2,ap2) < talign(t,ap) ){ t = t2; q = q2; ap = ap2; } break; } p->n_left = makety( p->n_left, t, q, d, ap ); p->n_right = makety( p->n_right, t, q, d, ap ); if( o!=MINUS && !clogop(o) ){ p->n_type = t; p->n_qual = q; p->n_df = d; p->n_ap = ap; } return(clocal(p)); } /* * Satisfy the types of various arithmetic binary ops. * * rules are: * if assignment, type of LHS * if any doubles, make double * else if any float make float * else if any longlongs, make long long * else if any longs, make long * else etcetc. * * If the op with the highest rank is unsigned, this is the resulting type. * See: 6.3.1.1 rank order equal of signed and unsigned types * 6.3.1.8 Usual arithmetic conversions */ static P1ND * tymatch(P1ND *p) { TWORD tl, tr, t; P1ND *l, *r; int o; o = p->n_op; r = p->n_right; l = p->n_left; tl = l->n_type; tr = r->n_type; if (tl == BOOL) tl = BOOL_TYPE; if (tr == BOOL) tr = BOOL_TYPE; if (casgop(o)) { if (r->n_op != ICON && tl < FLOAT && tr < FLOAT && tr > UNSIGNED && DEUNSIGN(tl) < DEUNSIGN(tr) && o != CAST) warner(Wtruncate, tnames[tr], tnames[tl]); if (l->n_type == BOOL && r->n_type != BOOL) { /* must create a ?: */ p->n_right = buildtree(QUEST, p->n_right, buildtree(COLON, bcon(1), bcon(0))); } p->n_right = makety(p->n_right, l->n_type, 0, 0, 0); t = p->n_type = l->n_type; p->n_ap = l->n_ap; } else { t = tl > tr ? tl : tr; /* MAX */ /* This depends on ctype() called early */ if (o != COLON && t < INT) t = INT; if (tl != t) p->n_left = makety(p->n_left, t, 0, 0, 0); if (tr != t) p->n_right = makety(p->n_right, t, 0, 0, 0); if (o == COLON && l->n_type == BOOL && r->n_type == BOOL) t = p->n_type = BOOL; else if (!clogop(o)) p->n_type = t; } #ifdef PCC_DEBUG if (tdebug) { printf("tymatch(%p): ", p); tprint(tl, 0); printf(" %s ", copst(o)); tprint(tr, 0); printf(" => "); tprint(t, 0); printf("\n"); p1fwalk(p, eprint, 0); } #endif return p; } /* * make p into type t by inserting a conversion */ P1ND * makety(P1ND *p, TWORD t, TWORD q, union dimfun *d, struct attr *ap) { if (t == p->n_type) { p->n_df = d; p->n_ap = ap; p->n_qual = q; return(p); } if (ISITY(t) || ISCTY(t) || ISITY(p->n_type) || ISCTY(p->n_type)) cerror("makety"); if (concast(p, t)) return clocal(p); p = block(t & TMASK ? PCONV : SCONV, p, NULL, t, d, ap); p->n_qual = q; return clocal(p); } P1ND * block(int o, P1ND *l, P1ND *r, TWORD t, union dimfun *d, struct attr *ap) { register P1ND *p; p = p1alloc(); p->n_rval = 0; p->n_op = o; slval(p, 0); p->n_left = l; p->n_right = r; p->n_type = t; p->n_qual = 0; p->n_df = d; p->n_ap = ap; return(p); } /* * Return the constant value from an ICON. */ CONSZ icons(P1ND *p) { /* if p is an integer constant, return its value */ CONSZ val; if (p->n_op != ICON || p->n_sp != NULL) { uerror( "constant expected"); val = 1; } else val = glval(p); p1tfree(p); return(val); } /* * the intent of this table is to examine the * operators, and to check them for * correctness. * * The table is searched for the op and the * modified type (where this is one of the * types INT (includes char and short), LONG, * DOUBLE (includes FLOAT), and POINTER * * The default action is to make the node type integer * * The actions taken include: * PUN check for puns * CVTL convert the left operand * CVTR convert the right operand * TYPL the type is determined by the left operand * TYPR the type is determined by the right operand * TYMATCH force type of left and right to match,by inserting conversions * PTMATCH like TYMATCH, but for pointers * LVAL left operand must be lval * CVTO convert the op * NCVT do not convert the operands * OTHER handled by code * NCVTR convert the left operand, not the right... * */ # define MINT 01 /* integer */ # define MDBI 02 /* integer or double */ # define MSTR 04 /* structure */ # define MPTR 010 /* pointer */ # define MPTI 020 /* pointer or integer */ int opact(P1ND *p) { int mt12, mt1, mt2, o; mt1 = mt2 = mt12 = 0; switch (coptype(o = p->n_op)) { case BITYPE: mt12=mt2 = moditype(p->n_right->n_type); /* FALLTHROUGH */ case UTYPE: mt12 &= (mt1 = moditype(p->n_left->n_type)); break; } switch( o ){ case NAME : case ICON : case FCON : case CALL : case UCALL: case UMUL: { return( OTHER ); } case UMINUS: if( mt1 & MDBI ) return( TYPL+PROML ); break; case COMPL: if( mt1 & MINT ) return( TYPL+PROML ); break; case ADDROF: return( NCVT+OTHER ); case NOT: return( PROML ); /* case INIT: */ case CM: case CBRANCH: case ANDAND: case OROR: return( 0 ); case MUL: case DIV: if( mt12 & MDBI ) return( TYMATCH ); break; case MOD: case AND: case OR: case ER: if( mt12 & MINT ) return( TYMATCH ); break; case LS: case RS: if( mt12 & MINT ) return( TYPL+OTHER+PROML ); break; case EQ: case NE: case LT: case LE: case GT: case GE: if( mt12 & MDBI ) return( TYMATCH+CVTO ); else if( mt12 & MPTR ) return( PTMATCH+PUN+CVTO ); else if( mt12 & MPTI ) return( PTMATCH+PUN ); else break; case QUEST: return( TYPR+OTHER ); case COMOP: return( TYPR ); case STREF: return( NCVTR+OTHER ); case FORCE: return( TYPL ); case COLON: if( mt12 & MDBI ) return( TYMATCH ); else if( mt12 & MPTR ) return( TYPL+PTMATCH+PUN ); else if( (mt1&MINT) && (mt2&MPTR) ) return( TYPR+PUN ); else if( (mt1&MPTR) && (mt2&MINT) ) return( TYPL+PUN ); else if( mt12 & MSTR ) return( NCVT+TYPL+OTHER ); break; case ASSIGN: case RETURN: if( mt12 & MSTR ) return( LVAL+NCVT+TYPL+OTHER ); /* FALLTHROUGH */ case CAST: if( mt12 & MDBI ) return( TYPL+LVAL+TYMATCH ); else if( mt1 & MPTR) return( LVAL+PTMATCH+PUN ); else if( mt12 & MPTI ) return( TYPL+LVAL+TYMATCH+PUN ); break; case MINUS: if (mt12 & MPTR) return(CVTO+PTMATCH+PUN); if (mt2 & MPTR) break; /* FALLTHROUGH */ case PLUS: if (mt12 & MDBI) return(TYMATCH); else if ((mt1&MPTR) && (mt2&MINT)) return(TYPL+CVTR); else if ((mt1&MINT) && (mt2&MPTR)) return(TYPR+CVTL); } uerror("operands of %s have incompatible types", copst(o)); return(NCVT); } int moditype(TWORD ty) { switch (ty) { case STRTY: case UNIONTY: return( MSTR ); case BOOL: case CHAR: case SHORT: case UCHAR: case USHORT: case UNSIGNED: case ULONG: case ULONGLONG: case INT: case LONG: case LONGLONG: return( MINT|MDBI|MPTI ); case FLOAT: case DOUBLE: case LDOUBLE: #ifndef NO_COMPLEX case FCOMPLEX: case COMPLEX: case LCOMPLEX: case FIMAG: case IMAG: case LIMAG: #endif return( MDBI ); default: return( MPTR|MPTI ); } } int tvaloff = MAXREGS+NPERMREG > 100 ? MAXREGS+NPERMREG + 100 : 100; /* * Returns a TEMP node with temp number nr. * If nr == 0, return a node with a new number. */ P1ND * tempnode(int nr, TWORD type, union dimfun *df, struct attr *ap) { P1ND *r; if (tvaloff == -NOOFFSET) tvaloff++; /* Skip this for array indexing */ r = block(TEMP, NULL, NULL, type, df, ap); regno(r) = nr ? nr : tvaloff; tvaloff += szty(type); return r; } /* * Do sizeof on p. */ P1ND * doszof(P1ND *p) { extern P1ND *arrstk[10]; extern int arrstkp; union dimfun *df; TWORD ty; P1ND *rv, *q; int astkp; if (p->n_op == FLD) uerror("can't apply sizeof to bit-field"); /* * Arrays may be dynamic, may need to make computations. */ rv = bcon(1); df = p->n_df; ty = p->n_type; astkp = 0; while (ISARY(ty)) { if (df->ddim == NOOFFSET) uerror("sizeof of incomplete type"); if (df->ddim < 0) { if (arrstkp) q = arrstk[astkp++]; else q = tempnode(-df->ddim, INT, 0, 0); } else q = bcon(df->ddim); rv = buildtree(MUL, rv, q); df++; ty = DECREF(ty); } rv = buildtree(MUL, rv, xbcon(tsize(ty, p->n_df, p->n_ap)/SZCHAR, NULL, INTPTR)); p1tfree(p); arrstkp = 0; /* XXX - may this fail? */ return rv; } #ifdef PCC_DEBUG void eprint(P1ND *p, int down, int *a, int *b) { int ty; *a = *b = down+1; while( down > 1 ){ printf( "\t" ); down -= 2; } if( down ) printf( " " ); ty = coptype( p->n_op ); printf("%p) %s, ", p, copst(p->n_op)); if (p->n_op == XARG || p->n_op == XASM) printf("id '%s', ", p->n_name); if (ty == LTYPE) { printf(CONFMT, glval(p)); if (p->n_op == NAME || p->n_op == ICON) printf(", %p, ", p->n_sp); #ifdef notyet else if (p->n_op == FCON) printf(", %Lf, ", p->n_dcon->fp); #endif else printf(", %d, ", p->n_rval); } tprint(p->n_type, p->n_qual); printf( ", %p, ", p->n_df); #ifdef GCC_COMPAT dump_attr(p->n_ap); #endif } # endif /* * Emit everything that should be emitted on the left side * of a comma operator, and remove the operator. * Do not traverse through QUEST, ANDAND and OROR. * Enable this for all targets when stable enough. */ static void comops(P1ND *p) { int o; P1ND *q; while (p->n_op == COMOP) { /* XXX hack for GCC ({ }) ops */ if (p->n_left->n_op == GOTO) { int v = (int)glval(p->n_left->n_left); ecomp(p->n_left); plabel(v+2); } else ecomp(p->n_left); /* will recurse if more COMOPs */ q = p->n_right; *p = *q; p1nfree(q); } o = coptype(p->n_op); if (p->n_op == QUEST || p->n_op == ANDAND || p->n_op == OROR) o = UTYPE; if (o != LTYPE) comops(p->n_left); if (o == BITYPE) comops(p->n_right); } /* * Walk up through the tree from the leaves, * removing constant operators. */ static void logwalk(P1ND *p) { int o = coptype(p->n_op); P1ND *l, *r; l = p->n_left; r = p->n_right; switch (o) { case LTYPE: return; case BITYPE: logwalk(r); /* FALLTHROUGH */ case UTYPE: logwalk(l); } if (!clogop(p->n_op)) return; if (p->n_op == NOT && l->n_op == ICON) { slval(p, (glval(l) == 0)); p1nfree(l); p->n_op = ICON; } if (l->n_op == ICON && r->n_op == ICON) { if (conval(l, p->n_op, r) == 0) { /* * people sometimes tend to do really odd compares, * like "if ("abc" == "def")" etc. * do it runtime instead. */ } else { slval(p, glval(l)); p->n_sp = NULL; p->n_op = ICON; p1nfree(l); p1nfree(r); } } } /* * Removes redundant logical operators for branch conditions. */ static void fixbranch(P1ND *p, int label) { logwalk(p); if (p->n_op == ICON) { if (glval(p) != 0 || p->n_sp != NULL) branch(label); p1nfree(p); } else { if (!clogop(p->n_op)) /* Always conditional */ p = buildtree(NE, p, bcon(0)); ecode(buildtree(CBRANCH, p, bcon(label))); } } /* * Write out logical expressions as branches. */ static void andorbr(P1ND *p, int true, int false) { P1ND *q; int o, lab; lab = -1; switch (o = p->n_op) { case EQ: case NE: /* * Remove redundant EQ/NE nodes. */ while (((o = p->n_left->n_op) == EQ || o == NE) && p->n_right->n_op == ICON) { o = p->n_op; q = p->n_left; if (glval(p->n_right) == 0) { p1nfree(p->n_right); *p = *q; p1nfree(q); if (o == EQ) p->n_op = p1negrel[p->n_op - EQ]; #if 0 p->n_op = NE; /* toggla */ #endif } else if (glval(p->n_right) == 1) { p1nfree(p->n_right); *p = *q; p1nfree(q); if (o == NE) p->n_op = p1negrel[p->n_op - EQ]; #if 0 p->n_op = EQ; /* toggla */ #endif } else break; /* XXX - should always be false */ } /* FALLTHROUGH */ case LE: case LT: case GE: case GT: calc: if (true < 0) { p->n_op = p1negrel[p->n_op - EQ]; p->n_ap = attr_add(p->n_ap, attr_new(ATTR_FP_SWAPPED, 3)); p->n_ap->aa[0].iarg = 1; true = false; false = -1; } rmcops(p->n_left); rmcops(p->n_right); fixbranch(p, true); if (false >= 0) branch(false); break; case ULE: case UGT: /* Convert to friendlier ops */ if (nncon(p->n_right) && glval(p->n_right) == 0) p->n_op = o == ULE ? EQ : NE; goto calc; case UGE: case ULT: /* Already true/false by definition */ if (nncon(p->n_right) && glval(p->n_right) == 0) { if (true < 0) { o = o == ULT ? UGE : ULT; true = false; } rmcops(p->n_left); ecode(p->n_left); rmcops(p->n_right); ecode(p->n_right); p1nfree(p); if (o == UGE) /* true */ branch(true); break; } goto calc; case ANDAND: lab = false<0 ? getlab() : false ; andorbr(p->n_left, -1, lab); comops(p->n_right); andorbr(p->n_right, true, false); if (false < 0) plabel( lab); p1nfree(p); break; case OROR: lab = true<0 ? getlab() : true; andorbr(p->n_left, lab, -1); comops(p->n_right); andorbr(p->n_right, true, false); if (true < 0) plabel( lab); p1nfree(p); break; case NOT: andorbr(p->n_left, false, true); p1nfree(p); break; default: rmcops(p); if (true >= 0) fixbranch(p, true); if (false >= 0) { if (true >= 0) branch(false); else fixbranch(buildtree(EQ, p, bcon(0)), false); } } } /* * Create a node for either TEMP or on-stack storage. */ P1ND * cstknode(TWORD t, union dimfun *df, struct attr *ap) { struct symtab *sp; /* create a symtab entry suitable for this type */ sp = getsymtab("0hej", SSTMT); sp->stype = t; sp->sdf = df; sp->sap = ap; sp->sclass = AUTO; sp->soffset = NOOFFSET; oalloc(sp, &autooff); return nametree(sp); } /* * Massage the output trees to remove C-specific nodes: * COMOPs are split into separate statements. * QUEST/COLON are rewritten to branches. * ANDAND/OROR/NOT are rewritten to branches for lazy-evaluation. * CBRANCH conditions are rewritten for lazy-evaluation. */ static void rmcops(P1ND *p) { TWORD type; P1ND *q, *r, *tval; int o, ty, lbl, lbl2; tval = NULL; o = p->n_op; ty = coptype(o); if (BTYPE(p->n_type) == ENUMTY) { /* fixup enum */ struct symtab *sp = strmemb(p->n_ap); MODTYPE(p->n_type, sp->stype); /* * XXX may fail if these are true: * - variable-sized enums * - non-byte-addressed targets. */ if (BTYPE(p->n_type) == ENUMTY && ISPTR(p->n_type)) MODTYPE(p->n_type, INT); /* INT ok? */ } switch (o) { case QUEST: /* * Create a branch node from ?: * || and && must be taken special care of. */ type = p->n_type; andorbr(p->n_left, -1, lbl = getlab()); /* Make ASSIGN node */ /* Only if type is not void */ q = p->n_right->n_left; comops(q); if (type != VOID) { tval = cstknode(q->n_type, q->n_df, q->n_ap); q = buildtree(ASSIGN, p1tcopy(tval), q); } rmcops(q); ecode(q); /* Done with assign */ branch(lbl2 = getlab()); plabel( lbl); q = p->n_right->n_right; comops(q); if (type != VOID) { q = buildtree(ASSIGN, p1tcopy(tval), q); } rmcops(q); ecode(q); /* Done with assign */ plabel( lbl2); p1nfree(p->n_right); if (p->n_type != VOID) { *p = *tval; p1nfree(tval); } else { p->n_op = ICON; slval(p, 0); p->n_sp = NULL; } break; case ULE: case ULT: case UGE: case UGT: case EQ: case NE: case LE: case LT: case GE: case GT: case ANDAND: case OROR: case NOT: #ifdef SPECIAL_CCODES #error fix for private CCODES handling #else r = p1alloc(); *r = *p; andorbr(r, -1, lbl = getlab()); tval = cstknode(p->n_type, p->n_df, p->n_ap); ecode(buildtree(ASSIGN, p1tcopy(tval), bcon(1))); branch(lbl2 = getlab()); plabel( lbl); ecode(buildtree(ASSIGN, p1tcopy(tval), bcon(0))); plabel( lbl2); *p = *tval; p1nfree(tval); #endif break; case CBRANCH: andorbr(p->n_left, glval(p->n_right), -1); p1nfree(p->n_right); p->n_op = ICON; p->n_type = VOID; break; case COMOP: cerror("COMOP error"); default: if (ty == LTYPE) return; rmcops(p->n_left); if (ty == BITYPE) rmcops(p->n_right); } } /* * Return 1 if an assignment is found. */ static int has_se(P1ND *p) { if (p->n_op == COMOP && p->n_left->n_op == GOTO) return 1; if (cdope(p->n_op) & ASGFLG) return 1; if (coptype(p->n_op) == LTYPE) return 0; if (has_se(p->n_left)) return 1; if (coptype(p->n_op) == BITYPE) return has_se(p->n_right); return 0; } #ifndef FIELDOPS /* avoid promotion to int */ #define TYPMOD(o, p, n, t) clocal(block(o, p, n, t, 0, 0)) #define TYPLS(p, n, t) TYPMOD(LS, p, n, t) #define TYPRS(p, n, t) TYPMOD(RS, p, n, t) #define TYPOR(p, q, t) TYPMOD(OR, p, q, t) #define TYPAND(p, q, t) TYPMOD(AND, p, q, t) /* * Read an unaligned bitfield from position pointed to by p starting at * off and size fsz and return a tree of type t with resulting data. * ct is the type we must use to read data. */ static P1ND * rdualfld(P1ND *p, TWORD t, TWORD ct, int off, int fsz) { int t2f, inbits, tsz, ctsz; P1ND *q, *r; ct = ENUNSIGN(ct); ctsz = (int)tsize(ct, 0, 0); /* traverse until first data byte */ for (t2f = 0; off >= ctsz; t2f++, off -= ctsz) ; #ifdef UNALIGNED_ACCESS /* try to squeeze it into an int */ if (off + fsz > ctsz && off + fsz <= SZINT) { ct = UNSIGNED; ctsz = SZINT; } #endif p = makety(p, PTR|ct, 0, 0, 0); if (off + fsz <= ctsz) { /* only one operation needed */ q = buildtree(UMUL, buildtree(PLUS, p, bcon(t2f)), 0); q = makety(q, t, 0, 0, 0); ctsz = tsize(t, 0, 0); q = buildtree(LS, q, bcon(ctsz-fsz-off)); q = buildtree(RS, q, bcon(ctsz-fsz)); } else { q = buildtree(UMUL, buildtree(PLUS, p1tcopy(p), bcon(t2f)), 0); q = makety(TYPRS(q, bcon(off), ct), t, 0, 0, 0); inbits = ctsz - off; t2f++; while (fsz > inbits) { r = buildtree(UMUL, buildtree(PLUS, p1tcopy(p), bcon(t2f)), 0); r = makety(r, t, 0, 0, 0); r = TYPLS(r, bcon(inbits), t); q = TYPOR(q, r, t); inbits += ctsz; t2f++; } /* sign/zero extend XXX - RS must sign extend */ tsz = (int)tsize(t, 0, 0); if (!ISUNSIGNED(t)) { t = DEUNSIGN(t); q = makety(q, t, 0, 0, 0); } q = TYPLS(q, bcon(tsz-fsz), t); q = TYPRS(q, bcon(tsz-fsz), t); p1tfree(p); } return q; } /* * Write val to a (unaligned) bitfield with length fsz positioned off bits * from d. Bitfield type is t, and type to use when writing is ct. * neither f nor d should have any side effects if copied. * Multiples of ct are supposed to be written without problems. * Both val and d are free'd after use. */ static P1ND * wrualfld(P1ND *val, P1ND *d, TWORD t, TWORD ct, int off, int fsz) { P1ND *p, *q, *r, *rn, *s; int ctsz, t2f, inbits; ctsz = (int)tsize(ct, 0, 0); ct = ENUNSIGN(ct); d = makety(d, PTR|ct, 0, 0, 0); for (t2f = 0; off >= ctsz; t2f++, off -= ctsz) ; if (off + fsz <= ctsz) { r = tempnode(0, ct, 0, 0); /* only one operation needed */ d = buildtree(UMUL, buildtree(PLUS, d, bcon(t2f)), 0); p = p1tcopy(d); p = TYPAND(p, xbcon(~(SZMASK(fsz) << off), 0, ct), ct); val = makety(val, ct, 0, 0, 0); q = TYPAND(val, xbcon(SZMASK(fsz), 0, ct), ct); q = buildtree(ASSIGN, p1tcopy(r), q); q = TYPLS(q, bcon(off), ct); p = TYPOR(p, q, ct); p = makety(p, t, 0, 0, 0); rn = buildtree(ASSIGN, d, p); rn = buildtree(COMOP, rn, makety(r, t, 0, 0, 0)); } else { s = makety(p1tcopy(val), t, 0, 0, 0); s = TYPAND(s, xbcon(SZMASK(fsz), 0, t), t); r = buildtree(UMUL, buildtree(PLUS, p1tcopy(d), bcon(t2f)), 0); p = p1tcopy(r); p = TYPAND(p, xbcon(SZMASK(off), 0, ct), ct); q = p1tcopy(val); q = TYPLS(q, bcon(off), t); q = makety(q, ct, 0, 0, 0); p = TYPOR(p, q, ct); rn = buildtree(ASSIGN, r, p); inbits = ctsz - off; t2f++; while (fsz > inbits+ctsz) { r = buildtree(UMUL, buildtree(PLUS, p1tcopy(d), bcon(t2f)), 0); q = p1tcopy(val); q = TYPRS(q, bcon(inbits), t); q = makety(q, ct, 0, 0, 0); rn = buildtree(COMOP, rn, buildtree(ASSIGN, r, q)); t2f++; inbits += ctsz; } r = buildtree(UMUL, buildtree(PLUS, d, bcon(t2f)), 0); p = p1tcopy(r); p = TYPAND(p, makety(xbcon(~SZMASK(fsz-inbits), 0, ct), ct, 0, 0, 0), ct); q = TYPRS(val, bcon(inbits), t); q = TYPAND(q, xbcon(SZMASK(fsz-inbits), 0, t), t); q = makety(q, ct, 0, 0, 0); p = TYPOR(p, q, ct); rn = buildtree(COMOP, rn, buildtree(ASSIGN, r, p)); rn = buildtree(COMOP, rn, s); } return rn; } /* * Rewrite bitfield operations to shifts. */ static P1ND * rmfldops(P1ND *p) { TWORD t, ct; P1ND *q, *r, *t1, *t2, *bt; int fsz, foff; if (p->n_op == FLD) { /* Rewrite a field read operation */ fsz = UPKFSZ(p->n_rval); foff = UPKFOFF(p->n_rval); q = buildtree(ADDROF, p->n_left, NULL); ct = t = p->n_type; if (t < INT) { t = INT; if (ISUNSIGNED(p->n_type)) t++; } #ifdef GCC_COMPAT if (attr_find(p->n_ap, GCC_ATYP_PACKED) && coptype(q->n_op) != LTYPE) { t1 = tempnode(0, q->n_type, 0, 0); bt = buildtree(ASSIGN, p1tcopy(t1), q); q = t1; #ifndef UNALIGNED_ACCESS ct = UCHAR; #endif } else #endif bt = bcon(0); #if TARGET_ENDIAN == TARGET_BE foff = (int)tsize(t, 0, 0) - fsz - foff; #endif q = rdualfld(q, t, ct, foff, fsz); if (fsz < SZINT) q = makety(q, INT, 0, 0, 0); if (p->n_type != INT) q = makety(q, p->n_type, 0, 0, 0); p->n_left = bt; p->n_right = q; p->n_op = COMOP; } else if (((cdope(p->n_op)&ASGOPFLG) || p->n_op == ASSIGN || p->n_op == INCR || p->n_op == DECR) && p->n_left->n_op == FLD) { /* * Rewrite a field write operation * More difficult than a read op since we must care * about side effects. */ q = p->n_left; fsz = UPKFSZ(q->n_rval); foff = UPKFOFF(q->n_rval); t = q->n_left->n_type; #if TARGET_ENDIAN == TARGET_BE foff = (int)tsize(t, 0, 0) - fsz - foff; #endif bt = NULL; if (p->n_right->n_op != ICON && p->n_right->n_op != NAME) { t2 = tempnode(0, p->n_right->n_type, 0, 0); bt = buildtree(ASSIGN, p1tcopy(t2), p->n_right); } else t2 = p->n_right; ct = t; #ifdef GCC_COMPAT #ifndef UNALIGNED_ACCESS if (attr_find(q->n_ap, GCC_ATYP_PACKED)) ct = UCHAR; #endif #endif /* t2 is what we have to write (RHS of ASSIGN) */ /* bt is (eventually) something that must be written */ if (q->n_left->n_op == UMUL) { /* LHS of assignment may have side effects */ q = q->n_left; t1 = tempnode(0, q->n_left->n_type, 0, 0); r = buildtree(ASSIGN, p1tcopy(t1), q->n_left); bt = bt ? block(COMOP, bt, r, INT, 0, 0) : r; q->n_left = t1; } t1 = buildtree(ADDROF, p->n_left->n_left, 0); /* t1 is lval where to write (and read) */ if (p->n_op == ASSIGN) { q = wrualfld(t2, t1, t, ct, foff, fsz); if (bt) q = block(COMOP, bt, q, t, 0, 0); p1nfree(p->n_left); p->n_left = bcon(0); p->n_right = q; p->n_op = COMOP; } else cerror("NOTASSIGN!"); t = p->n_type; if (ISUNSIGNED(p->n_type)) { /* mask away unwanted bits */ if ((t == LONGLONG && fsz == SZLONGLONG-1) || (t == LONG && fsz == SZLONG-1) || (t == INT && fsz == SZINT-1)) p = buildtree(AND, p, xbcon((1LL << fsz)-1, 0, t)); } else { /* Correct value in case of signed bitfield. */ if (t == LONGLONG) fsz = SZLONGLONG - fsz; else if (t == LONG) fsz = SZLONG - fsz; else fsz = SZINT - fsz; p = buildtree(LS, p, bcon(fsz)); #ifdef RS_DIVIDES p = buildtree(RS, p, bcon(fsz)); #else { p = buildtree(DIV, p, xbcon(1LL << fsz, 0, t)); /* avoid wrong sign if divisor gets negative */ if ((t == LONGLONG && fsz == SZLONGLONG-1) || (t == LONG && fsz == SZLONG-1) || (t == INT && fsz == SZINT-1)) p = buildtree(UMINUS, p, NULL); } #endif } } if (coptype(p->n_op) != LTYPE) p->n_left = rmfldops(p->n_left); if (coptype(p->n_op) == BITYPE) p->n_right = rmfldops(p->n_right); return p; } #endif void ecomp(P1ND *p) { #ifdef PCC_DEBUG if (edebug) { printf("ecomp\n"); p1fwalk(p, eprint, 0); } #endif if (!reached) { warner(Wunreachable_code); reached = 1; } p = optim(p); #ifndef FIELDOPS p = rmfldops(p); #endif comops(p); rmcops(p); if (p->n_op == ICON && p->n_type == VOID) p1tfree(p); else ecode(p); } #ifdef PASS1 /* * Print out full tree. * Nodes are already converted to pass2 style. */ static void p2print(NODE *p) { struct attr *ap; int ty, i; ty = optype(p->n_op); printf("\" %d ", p->n_op); printf("%d %d ", p->n_type, p->n_qual); if (ty == LTYPE) printf(CONFMT " ", glval(p)); if (ty != BITYPE) { if (p->n_op != NAME && p->n_op != ICON) printf("%d ", p->n_rval); } /* handle special cases */ if (p->n_op == NAME || p->n_op == ICON || p->n_op == XASM || p->n_op == XARG) printf("%s", p->n_name); if (p->n_ap) { printf(" + "); for (ap = p->n_ap; ap; ap = ap->next) { printf("%d %d ", ap->atype, ap->sz); for (i = 0; i < ap->sz; i++) printf("%d ", ap->iarg(i)); } } printf("\n"); if (ty != LTYPE) p2print(p->n_left); if (ty == BITYPE) p2print(p->n_right); } /* * Print out the code trees for pass2. * First on line is always a sync char, second is space: * ! - Prologue. * " - Node * ^ - Label * $ - Assembler statement * % - Epilog. * # - Line number * & - File name * * - Passthrough line. */ void pass2_compile(struct interpass *ip) { struct interpass_prolog *ipp; static int oldlineno; int i; if (oldlineno != ip->lineno) printf("# %d\n", oldlineno = ip->lineno); switch (ip->type) { case IP_PROLOG: ipp = (struct interpass_prolog *)ip; printf("! %d %d %d %d %d %s\n", ipp->ipp_type, ipp->ipp_vis, ip->ip_lbl, ipp->ip_tmpnum, ipp->ip_lblnum, ipp->ipp_name); #ifdef TARGET_IPP_MEMBERS printf("( "); target_members_print_prolog(ipp); printf("\n"); #endif break; case IP_NODE: p2print(ip->ip_node); tfree(ip->ip_node); break; case IP_DEFLAB: printf("^ %d\n", ip->ip_lbl); break; case IP_ASM: printf("$ %s\n", ip->ip_asm); break; case IP_EPILOG: ipp = (struct interpass_prolog *)ip; printf("%% %d %d %d %d %s", ipp->ipp_autos, ip->ip_lbl, ipp->ip_tmpnum, ipp->ip_lblnum, ipp->ipp_name); if (ipp->ip_labels[0]) { for (i = 0; ipp->ip_labels[i]; i++) ; printf(" + %d", i); for (i = 0; ipp->ip_labels[i]; i++) printf(" %d", ipp->ip_labels[i]); } printf("\n"); #ifdef TARGET_IPP_MEMBERS printf(") "); target_members_print_epilog(ipp); printf("\n"); #endif break; default: cerror("Missing %d", ip->type); } free(ip); } #endif static char * sptostr(struct symtab *sp) { char *cp = tmpalloc(32); int n = sp->soffset; if (n < 0) n = -n; snprintf(cp, 32, LABFMT, n); return cp; } static NODE * p2tree(P1ND *p) { struct attr *ap; struct symtab *q; NODE *np; int ty; myp2tree(p); /* local action can be taken here */ /* Fix left imaginary types */ if (ISITY(BTYPE(p->n_type))) MODTYPE(p->n_type, p->n_type - (FIMAG-FLOAT)); ty = coptype(p->n_op); np = memset(talloc(), 0, sizeof(NODE)); /* Copy common data */ np->n_op = p->n_op; np->n_type = p->n_type; np->n_qual = p->n_qual; if (ty != BITYPE) np->n_rval = p->n_rval; if (ty == LTYPE) { setlval(np, glval(p)); } /* cleanup attributes. * copy those that are supposed to go into pass2 */ for (ap = p->n_ap; ap; ap = ap->next) if (ap->atype < ATTR_MI_MAX) np->n_ap = attr_add(np->n_ap, attr_dup(ap)); switch( p->n_op ){ case NAME: case ICON: if ((q = p->n_sp) != NULL) { if ((q->sclass == STATIC && q->slevel > 0) #ifdef GCC_COMPAT || q->sflags == SLBLNAME #endif ) { np->n_name = sptostr(q); if ((q->sflags & SMASK) == SSTRING) q->sflags |= SASG; } else np->n_name = getexname(q); } else np->n_name = ""; break; case STASG: case STARG: case STCALL: case USTCALL: ap = attr_new(ATTR_P2STRUCT, 2); np->n_ap = attr_add(np->n_ap, ap); /* STASG used for stack array init */ if (p->n_op == STASG && ISARY(p->n_type)) { int size1 = (int)tsize(p->n_type, p->n_left->n_df, p->n_left->n_ap)/SZCHAR; ap->iarg(0) = (int)tsize(p->n_type, p->n_right->n_df, p->n_right->n_ap)/SZCHAR; if (size1 < ap->iarg(0)) ap->iarg(0) = size1; ap->iarg(1) = talign(p->n_type, p->n_left->n_ap)/SZCHAR; break; } /* set up size parameters */ ap->iarg(0) = (int)((tsize(STRTY, p->n_left->n_df, p->n_left->n_ap)+SZCHAR-1)/SZCHAR); ap->iarg(1) = talign(STRTY,p->n_left->n_ap)/SZCHAR; if (ap->iarg(1) == 0) ap->iarg(1) = 1; /* At least char for packed structs */ break; case XARG: case XASM: np->n_name = tmpstrdup(p->n_name); break; default: np->n_name = ""; } if (ty != LTYPE) np->n_left = p2tree(p->n_left); if (ty == BITYPE) np->n_right = p2tree(p->n_right); return np; } /* * Change void data types into char. */ static void delvoid(P1ND *p, void *arg) { /* Convert "PTR undef" (void *) to "PTR uchar" */ if (BTYPE(p->n_type) == VOID) p->n_type = (p->n_type & ~BTMASK) | UCHAR; if (BTYPE(p->n_type) == BOOL) { if (p->n_op == SCONV && p->n_type == BOOL) { /* create a jump and a set */ P1ND *r; int l, l2; r = tempnode(0, BOOL_TYPE, NULL, 0); cbranch(buildtree(EQ, p->n_left, bcon(0)), bcon(l = getlab())); *p = *r; ecode(buildtree(ASSIGN, p1tcopy(r), bcon(1))); branch(l2 = getlab()); plabel(l); ecode(buildtree(ASSIGN, r, bcon(0))); plabel(l2); } else p->n_type = (p->n_type & ~BTMASK) | BOOL_TYPE; } } /* * Change calls inside calls to separate statement. */ static P1ND * deldcall(P1ND *p, int split) { P1ND *q, *r; int o = p->n_op; if (cdope(o) & CALLFLG) { if (split) { q = cstknode(p->n_type, p->n_df, p->n_ap); r = p1tcopy(q); q = block(ASSIGN, q, p, p->n_type, p->n_df, p->n_ap); ecode(q); return r; } split++; } if (coptype(o) == BITYPE) p->n_right = deldcall(p->n_right, split); if (coptype(o) != LTYPE) p->n_left = deldcall(p->n_left, split); return p; } #ifndef WORD_ADDRESSED static P1ND * pprop(P1ND *p, TWORD t, struct attr *ap) { int o = p->n_op; TWORD t2; #ifdef PCC_DEBUG if (p->n_op == TEMP && p->n_type != t && !(ISPTR(p->n_type) && ISPTR(t))) { cerror("TEMP type change: %x -> %x", p->n_type, t); } #endif p->n_type = t; p->n_ap = ap; switch (o) { case UMUL: t = INCREF(t); break; case ADDROF: t2 = p->n_left->n_type; if (p->n_left->n_op == TEMP) { /* Will be converted to memory in pass2 */ /* Do not convert if: * - t2 not ptr and decref(t) != t2 * - decref(t) not ptr and decref(t) != t2 * XXX add PCONV again? Will be removed upwards. */ if ((!ISPTR(t2) && DECREF(t) != t2) || (ISPTR(t2) && !ISPTR(DECREF(t)))) ; /* Cannot convert this */ else p->n_left->n_type = DECREF(t); return p; } if (ISPTR(t2) && !ISPTR(DECREF(t))) break; /* not quite correct */ t = DECREF(t); break; case PCONV: return p; case PLUS: if (!ISPTR(p->n_left->n_type)) { if (!ISPTR(p->n_right->n_type)) cerror("%p: no * in PLUS", p); p->n_right = pprop(p->n_right, t, ap); } else p->n_left = pprop(p->n_left, t, ap); return p; case MINUS: if (ISPTR(p->n_left->n_type)) { if (ISPTR(p->n_right->n_type)) break; /* change both */ p->n_left = pprop(p->n_left, t, ap); } else p->n_right = pprop(p->n_right, t, ap); return p; case CALL: case UCALL: case STCALL: /* may end up here if struct passed in regs */ case USTCALL: return p; case STASG: /* if struct is cast to pointer */ return p; case ASSIGN: break; case COMOP: p->n_right = pprop(p->n_right, t, ap); return p; default: if (coptype(o) == LTYPE) break; #ifdef PCC_DEBUG p1fwalk(p, eprint, 0); #endif cerror("pprop op error %d\n", o); } if (coptype(o) == BITYPE) p->n_right = pprop(p->n_right, t, ap); if (coptype(o) != LTYPE) p->n_left = pprop(p->n_left, t, ap); return p; } /* * Search for PCONV's that can be removed while still keeping * the type correctness. */ P1ND * rmpconv(P1ND *p) { struct symtab *sp; int o = p->n_op; int ot = coptype(o); P1ND *q, *l; if (ot != LTYPE) p->n_left = rmpconv(p->n_left); if (ot == BITYPE) p->n_right = rmpconv(p->n_right); if (o != PCONV) return p; l = p->n_left; if (nncon(l) || (cdope(l->n_op) & CALLFLG)) ; /* Let any nonamed constant be cast to pointer directly */ else if (l->n_type >= INTPTR && l->n_op == ICON) { /* named constants only if >= pointer size */ /* create INTPTR type */ sp = l->n_sp; l->n_sp = NULL; concast(l, INTPTR); l->n_sp = sp; } else if (!ISPTR(l->n_type)) return p; q = pprop(p->n_left, p->n_type, p->n_ap); p1nfree(p); return q; } #endif P1ND * optloop(P1ND *p) { extern int usdnodes; int n; do { n = usdnodes; p = rmpconv(p); p = optim(p); } while (n != usdnodes); return p; } void ecode(P1ND *p) { NODE *r; /* walk the tree and write out the nodes.. */ if (nerrors) return; #ifdef GCC_COMPAT { P1ND *q = p; if (q->n_op == UMUL) q = p->n_left; if (cdope(q->n_op)&CALLFLG && attr_find(q->n_ap, GCC_ATYP_WARN_UNUSED_RESULT)) werror("return value ignored"); } #endif #ifndef WORD_ADDRESSED p = rmpconv(p); #endif p = optim(p); p = deldcall(p, 0); p1walkf(p, delvoid, 0); #ifdef PCC_DEBUG if (xdebug) { printf("Fulltree:\n"); p1fwalk(p, eprint, 0); } #endif if (p->n_op == LABEL) { plabel(glval(p->n_left)); p1tfree(p); return; } r = p2tree(p); p1tfree(p); send_passt(IP_NODE, r); } /* * Send something further on to the next pass. */ void send_passt(int type, ...) { struct interpass *ip; struct interpass_prolog *ipp; extern int crslab; va_list ap; int sz; va_start(ap, type); if (cftnsp == NULL && type != IP_ASM) { #ifdef notyet cerror("no function"); #endif if (type == IP_NODE) tfree(va_arg(ap, NODE *)); return; } if (type == IP_PROLOG || type == IP_EPILOG) sz = sizeof(struct interpass_prolog); else sz = sizeof(struct interpass); ip = xmalloc(sz); ip->type = type; ip->lineno = lineno; switch (type) { case IP_NODE: ip->ip_node = va_arg(ap, NODE *); break; case IP_EPILOG: if (!isinlining) { locctr(PROG, cftnsp); defloc(cftnsp); } /* FALLTHROUGH */ case IP_PROLOG: inftn = type == IP_PROLOG ? 1 : 0; ipp = (struct interpass_prolog *)ip; ipp->ipp_autos = va_arg(ap, int); ipp->ipp_name = va_arg(ap, char *); ipp->ipp_type = va_arg(ap, TWORD); ipp->ipp_vis = va_arg(ap, int); ip->ip_lbl = va_arg(ap, int); ipp->ip_tmpnum = va_arg(ap, int); ipp->ip_lblnum = crslab; ipp->ip_labels = va_arg(ap, int *);; if (type == IP_PROLOG) ipp->ip_lblnum-=2; break; case IP_DEFLAB: ip->ip_lbl = va_arg(ap, int); break; case IP_ASM: if (blevel == 0) { /* outside function */ printf("%s", va_arg(ap, char *)); va_end(ap); locctr(NOSEG, NULL); return; } ip->ip_asm = va_arg(ap, char *); ip->ip_asm = tmpstrdup(ip->ip_asm); break; default: cerror("bad send_passt type %d", type); } va_end(ap); pass1_lastchance(ip); /* target-specific info */ if (isinlining) inline_addarg(ip); else pass2_compile(ip); } char * copst(int op) { if (op <= MAXOP) return opst[op]; #define SNAM(x,y) case x: return #y; switch (op) { SNAM(QUALIFIER,QUALIFIER) SNAM(CLASS,CLASS) SNAM(RB,]) SNAM(DOT,.) SNAM(ELLIPSIS,...) SNAM(LB,[) SNAM(TYPE,TYPE) SNAM(COMOP,COMOP) SNAM(QUEST,?) SNAM(BIQUEST,?:) SNAM(COLON,:) SNAM(ANDAND,&&) SNAM(OROR,||) SNAM(NOT,!) SNAM(CAST,CAST) SNAM(PLUSEQ,+=) SNAM(MINUSEQ,-=) SNAM(MULEQ,*=) SNAM(DIVEQ,/=) SNAM(MODEQ,%=) SNAM(ANDEQ,&=) SNAM(OREQ,|=) SNAM(EREQ,^=) SNAM(LSEQ,<<=) SNAM(RSEQ,>>=) SNAM(INCR,++) SNAM(DECR,--) SNAM(STRING,STRING) SNAM(SZOF,SIZEOF) SNAM(ATTRIB,ATTRIBUTE) SNAM(TYMERGE,TYMERGE) SNAM(LABEL,LABEL) SNAM(UPLUS,U+) SNAM(ALIGN,ALIGNMENT) SNAM(FUNSPEC,FUNSPEC) SNAM(STREF,->) #ifdef GCC_COMPAT SNAM(XREAL,__real__) SNAM(XIMAG,__imag__) #endif default: cerror("bad copst %d", op); } return 0; /* XXX gcc */ } int cdope(int op) { if (op <= MAXOP) return dope[op]; switch (op) { case CLOP: case STRING: case QUALIFIER: case CLASS: case RB: case ELLIPSIS: case TYPE: case ALIGN: case FUNSPEC: return LTYPE; case DOT: case SZOF: case COMOP: case QUEST: case BIQUEST: case COLON: case LB: case TYMERGE: case STREF: return BITYPE; case XIMAG: case XREAL: case ATTRIB: case LABEL: case UPLUS: return UTYPE; case ANDAND: case OROR: return BITYPE|LOGFLG; case NOT: return UTYPE|LOGFLG; case CAST: return BITYPE|ASGFLG|ASGOPFLG; case PLUSEQ: return BITYPE|ASGFLG|ASGOPFLG|FLOFLG|SIMPFLG|COMMFLG; case MINUSEQ: return BITYPE|FLOFLG|SIMPFLG|ASGFLG|ASGOPFLG; case MULEQ: return BITYPE|FLOFLG|MULFLG|ASGFLG|ASGOPFLG; case OREQ: case EREQ: case ANDEQ: return BITYPE|SIMPFLG|COMMFLG|ASGFLG|ASGOPFLG; case DIVEQ: return BITYPE|FLOFLG|MULFLG|DIVFLG|ASGFLG|ASGOPFLG; case MODEQ: return BITYPE|DIVFLG|ASGFLG|ASGOPFLG; case LSEQ: case RSEQ: return BITYPE|SHFFLG|ASGFLG|ASGOPFLG; case INCR: case DECR: return BITYPE|ASGFLG; } cerror("cdope missing op %d", op); return 0; /* XXX gcc */ } /* * make a fresh copy of p */ P1ND * p1tcopy(P1ND *p) { P1ND *q; q = p1alloc(); *q = *p; switch (coptype(q->n_op)) { case BITYPE: q->n_right = p1tcopy(p->n_right); /* FALLTHROUGH */ case UTYPE: q->n_left = p1tcopy(p->n_left); } return(q); } P1ND *frelink; int usdnodes; /* * Free a node, and return its left descendant. * It is up to the caller to know whether the return value is usable. */ P1ND * p1nfree(P1ND *p) { P1ND *l; #ifdef PCC_DEBUG_NODES P1ND *q; #endif if (p == NULL) cerror("freeing blank node!"); l = p->n_left; if (p->n_op == FREE) cerror("freeing FREE node", p); #ifdef PCC_DEBUG_NODES q = frelink; while (q != NULL) { if (q == p) cerror("freeing free node %p", p); q = q->n_left; } #endif if (ndebug) printf("freeing p1node %p\n", p); p->n_op = FREE; p->n_left = frelink; frelink = p; usdnodes--; return l; } P1ND * p1alloc(void) { register P1ND *p; usdnodes++; if (frelink != NULL) { p = frelink; frelink = p->n_left; if (p->n_op != FREE) cerror("node not FREE: %p", p); if (ndebug) printf("alloc p1node %p from freelist\n", p); return p; } p = stmtalloc(sizeof(P1ND)); p->n_op = FREE; if (ndebug) printf("alloc p1node %p from memory\n", p); return p; } /* * free the tree p */ void p1tfree(P1ND *p) { #ifdef PCC_DEBUG if (p->n_op == FREE) cerror("freeing FREE node"); #endif p1walkf(p, (void (*)(P1ND *, void *))p1nfree, 0); } void p1fwalk(P1ND *t, void (*f)(P1ND *, int, int *, int *), int down) { int down1, down2; more: down1 = down2 = 0; (*f)(t, down, &down1, &down2); switch (coptype( t->n_op )) { case BITYPE: p1fwalk( t->n_left, f, down1 ); t = t->n_right; down = down2; goto more; case UTYPE: t = t->n_left; down = down1; goto more; } } void p1walkf(P1ND *t, void (*f)(P1ND *, void *), void *arg) { int opty; opty = coptype(t->n_op); if (opty != LTYPE) p1walkf( t->n_left, f, arg ); if (opty == BITYPE) p1walkf( t->n_right, f, arg ); (*f)(t, arg); } /* * Do a preorder walk of the CM list p and apply function f on each element. */ void p1flist(P1ND *p, void (*f)(P1ND *, void *), void *arg) { if (p->n_op == CM) { (*f)(p->n_right, arg); p1flist(p->n_left, f, arg); } else (*f)(p, arg); } /* * The same as flist but postorder. */ void p1listf(P1ND *p, void (*f)(P1ND *)) { if (p->n_op == CM) { p1listf(p->n_left, f); (*f)(p->n_right); } else (*f)(p); } P1ND * nlabel(int label) { return block(LABEL, bcon(label), NULL, 0, 0, 0); } /* * set PROG-seg label. */ void plabel(int label) { reached = 1; /* Will this always be correct? */ send_passt(IP_DEFLAB, label); } /* * Perform integer promotion on node n. */ P1ND * intprom(P1ND *n) { if (n->n_op == FLD && UPKFSZ(n->n_rval) < SZINT) return makety(n, INT, 0, 0, 0); if ((n->n_type >= CHAR && n->n_type < INT) || n->n_type == BOOL) { if ((n->n_type == UCHAR && MAX_UCHAR > MAX_INT) || (n->n_type == USHORT && MAX_USHORT > MAX_INT)) return makety(n, UNSIGNED, 0, 0, 0); return makety(n, INT, 0, 0, 0); } return n; } /* * Return CON/VOL/0, whichever are active for the current type. */ int cqual(TWORD t, TWORD q) { while (ISARY(t)) t = DECREF(t), q = DECQAL(q); if (t <= BTMASK) q <<= TSHIFT; return q & (CON|VOL); } int crslab = 11; /* * Return a number for internal labels. */ int getlab(void) { int l2 = crslab++; crslab++; return l2; } pcc-20181216/cc/cpp004075500017500000000000000000001340533064100125565ustar raggewheelpcc-20181216/cc/cpp/CVS004075500017500000000000000000001340533064100132115ustar raggewheelpcc-20181216/cc/cpp/CVS/Root010064400017500000000000000000111340533064000141220ustar raggewheel/cvsroot pcc-20181216/cc/cpp/CVS/Repository010064400017500000000000000000131340533064000153600ustar raggewheelpcc/cc/cpp pcc-20181216/cc/cpp/CVS/Entries010064400017500000000000000004511340533064100146210ustar raggewheel/Makefile.in/1.54/Tue Mar 8 18:42:13 2016// /cpc.c/1.8/Mon Aug 8 16:38:29 2016// /cpp.1/1.17/Tue Feb 26 19:27:38 2013// /cpp.c/1.304/Mon Dec 11 10:36:20 2017// /cpp.h/1.111/Sun Dec 4 12:55:05 2016// /cpy.y/1.21/Wed May 28 08:52:42 2014// /token.c/1.190/Wed Dec 12 17:43:02 2018// D/tests//// D pcc-20181216/cc/cpp/Makefile.in010064400017500000000000000040221266761640500147130ustar raggewheel# $Id: Makefile.in,v 1.54 2016/03/08 18:42:13 ragge Exp $ # # Makefile.in for cpp # VPATH=@srcdir@ srcdir=@srcdir@ top_srcdir=@top_srcdir@ builddir=@builddir@ top_builddir=@top_builddir@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ libexecdir = @libexecdir@ datarootdir = @datarootdir@ mandir = @mandir@ CC = @CC@ EXEEXT = @EXEEXT@ CFLAGS = @CFLAGS@ @ADD_CFLAGS@ CPPFLAGS = @CPPFLAGS@ @ADD_CPPFLAGS@ \ -I$(srcdir) -I$(top_builddir) -I$(builddir) -I$(MIPDIR) -I$(MDIR) \ -I$(COMMONDIR) LIBS = @LIBS@ LDFLAGS = @LDFLAGS@ YACC = @YACC@ YFLAGS = @YFLAGS@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ TARGMACH = @targmach@ MIPDIR=$(top_srcdir)/mip MDIR=$(top_srcdir)/arch/$(TARGMACH) COMMONDIR=$(top_srcdir)/common DEST=@BINPREFIX@cpp$(EXEEXT) MANPAGE=@BINPREFIX@cpp all: $(DEST) OBJS= compat.o cpp.o cpc.o token.o HDRS= cpp.h $(OBJS): $(HDRS) compat.o: $(COMMONDIR)/compat.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(COMMONDIR)/compat.c cpp.o: $(srcdir)/cpp.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/cpp.c cpc.o: $(srcdir)/cpc.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/cpc.c token.o: $(srcdir)/token.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/token.c $(DEST): $(OBJS) $(CC) $(LDFLAGS) $(OBJS) -o $@ $(LIBS) test: $(DEST) @for n in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ; do \ echo -n "test$${n} " ; \ ./$(DEST) < tests/test$${n} > tests/run$${n} && \ cmp tests/run$${n} tests/res$${n} && echo ; \ if test -f tests/res$${n}C ; then \ echo -n "test$${n}C " ; \ ./$(DEST) -C < tests/test$${n} > tests/run$${n}C && \ cmp tests/run$${n}C tests/res$${n}C && echo ; \ fi ; \ done install: test -z "$(DESTDIR)$(libexecdir)" || mkdir -p "$(DESTDIR)$(libexecdir)" $(INSTALL_PROGRAM) $(DEST) $(DESTDIR)$(libexecdir) test -z "$(DESTDIR)$(mandir)/man1" || mkdir -p "$(DESTDIR)$(mandir)/man1" $(INSTALL_DATA) $(srcdir)/cpp.1 $(DESTDIR)$(mandir)/man1/$(MANPAGE).1 clean: rm -f $(OBJS) $(DEST) tests/run* distclean: clean rm -f Makefile pcc-20181216/cc/cpp/cpc.c010064400017500000000000000140221275213260500135460ustar raggewheel/* $Id: cpc.c,v 1.8 2016/08/08 16:38:29 ragge Exp $ */ /* * Copyright (c) 2014 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Small recursive parser for #if statements. */ #include "cpp.h" static int ctok; typedef struct nd ND; struct nd yynode; void qloop(void (*fun)(ND *), ND *n1, int a0, int a1, int a2, int a3); void shft(void); int yyparse(void); void expr(ND *n1); void eqcol(ND *n1); void eoror(ND *n1); void eandand(ND *n1); void exor(ND *n1); void eand(ND *n1); void eqne(ND *n1); void eget(ND *n1); void elrs(ND *n1); void eplmin(ND *n1); void emdv(ND *n1); void eterm(ND *n1); void eval(int op, ND *n1, ND *n2); void shft(void) { ctok = yylex(); } int yyparse(void) { ND n1; shft(); expr(&n1); if (n1.op == 0) error("division by zero"); if (ctok != WARN) error("junk after expression"); return (int)n1.nd_val; } /* * evaluate a complete preprocessor #if expression. */ void expr(ND *n1) { for (;;) { eqcol(n1); if (ctok != ',') return; shft(); } } /* * evaluate ?: conditionals. */ void eqcol(ND *n1) { ND n2, n3; eoror(n1); if (ctok != '?') return; shft(); expr(&n2); if (ctok != ':') error("no : found"); shft(); eqcol(&n3); if (n1->nd_val) n1->nd_val = n2.nd_val, n1->op = n2.op; else n1->nd_val = n3.nd_val, n1->op = n3.op; } void eoror(ND *n1) { qloop(eandand, n1, OROR, 0, 0, 0); } void eandand(ND *n1) { qloop(exor, n1, ANDAND, 0, 0, 0); } void exor(ND *n1) { qloop(eand, n1, '|', '^', 0, 0); } void eand(ND *n1) { qloop(eqne, n1, '&', 0, 0, 0); } void eqne(ND *n1) { qloop(eget, n1, EQ, NE, 0, 0); } void eget(ND *n1) { qloop(elrs, n1, '<', '>', LE, GE); } void elrs(ND *n1) { qloop(eplmin, n1, LS, RS, 0, 0); } void eplmin(ND *n1) { qloop(emdv, n1, '+', '-', 0, 0); } void emdv(ND *n1) { qloop(eterm, n1, '*', '/', '%', 0); } /* * Loop to evaluate all operators on the same precedence level. */ void qloop(void (*fun)(ND *), ND *n1, int a0, int a1, int a2, int a3) { ND n2; int op; fun(n1); while (ctok == a0 || ctok == a1 || ctok == a2 || ctok == a3) { op = ctok; shft(); fun(&n2); eval(op, n1, &n2); } } static void gnum(int o, ND *n1) { n1->op = yynode.op; n1->nd_val = yynode.nd_val; shft(); } /* * Highest precedence operators + numeric terminals. */ void eterm(ND *n1) { int o = ctok; switch (o) { case '~': case '!': case '+': case '-': shft(); eterm(n1); eval(o, n1, 0); break; case NUMBER: case UNUMBER: gnum(o, n1); break; case '(': shft(); expr(n1); if (ctok == ')') { shft(); break; } /* FALLTHROUGH */ default: error("bad terminal (%d)", o); break; } } /* * keep all numeric evaluation here. * evaluated value returned in n1. */ void eval(int op, ND *n1, ND *n2) { if ((op == '/' || op == '%') && n2->nd_val == 0) n1->op = 0; if (n1->op == 0) return; /* div by zero involved */ /* unary ops */ if (n2 == 0) { switch (op) { case '+': break; case '-': n1->nd_val = -n1->nd_val; break; case '~': n1->nd_val = ~n1->nd_val; break; case '!': n1->nd_val = !n1->nd_val; n1->op = NUMBER; break; } return; } if (op == OROR && n1->nd_val) { n1->nd_val = 1, n1->op = NUMBER; return; } if (op == ANDAND && n1->nd_val == 0) { n1->op = NUMBER; return; } if (n2->op == 0) { n1->op = 0; return; } if (n2->op == UNUMBER) n1->op = UNUMBER; switch (op) { case OROR: if (n2->nd_val) n1->nd_val = 1; n1->op = NUMBER; break; case ANDAND: n1->nd_val = n2->nd_val != 0; n1->op = NUMBER; break; case '+': n1->nd_val += n2->nd_val; break; case '-': n1->nd_val -= n2->nd_val; break; case '|': n1->nd_val |= n2->nd_val; break; case '^': n1->nd_val ^= n2->nd_val; break; case '&': n1->nd_val &= n2->nd_val; break; case LS: n1->nd_val <<= n2->nd_val; break; case EQ: n1->nd_val = n1->nd_val == n2->nd_val; n1->op = NUMBER; break; case NE: n1->nd_val = n1->nd_val != n2->nd_val; n1->op = NUMBER; break; } if (n1->op == NUMBER) { switch (op) { case '*': n1->nd_val *= n2->nd_val; break; case '/': n1->nd_val /= n2->nd_val; break; case '%': n1->nd_val %= n2->nd_val; break; case '<': n1->nd_val = n1->nd_val < n2->nd_val; break; case '>': n1->nd_val = n1->nd_val > n2->nd_val; break; case LE: n1->nd_val = n1->nd_val <= n2->nd_val; break; case GE: n1->nd_val = n1->nd_val >= n2->nd_val; break; case RS: n1->nd_val >>= n2->nd_val; break; } } else /* op == UNUMBER */ { switch (op) { case '*': n1->nd_uval *= n2->nd_uval; break; case '/': n1->nd_uval /= n2->nd_uval; break; case '%': n1->nd_uval %= n2->nd_uval; break; case '<': n1->nd_uval = n1->nd_uval < n2->nd_uval; break; case '>': n1->nd_uval = n1->nd_uval > n2->nd_uval; break; case LE: n1->nd_uval = n1->nd_uval <= n2->nd_uval; break; case GE: n1->nd_uval = n1->nd_uval >= n2->nd_uval; break; case RS: n1->nd_uval >>= n2->nd_uval; break; } } } pcc-20181216/cc/cpp/cpp.1010064400017500000000000000142701211320625200134750ustar raggewheel.\" $Id: cpp.1,v 1.17 2013/02/26 19:27:38 plunky Exp $ .\" .\" Copyright (c) 2007 Jeremy C. Reed .\" .\" Permission to use, copy, modify, and/or distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above .\" copyright notice and this permission notice appear in all copies. .\" .\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR AND CONTRIBUTORS DISCLAIM .\" ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHOR AND .\" CONTRIBUTORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL .\" DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR .\" PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS .\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF .\" THIS SOFTWARE. .\" .Dd February 26, 2013 .Dt CPP 1 .Os .Sh NAME .Nm cpp .Nd C preprocessor .Sh SYNOPSIS .Nm .Op Fl ACEMPtVv .Op Fl D Ar macro Ns Oo = Ns Ar value Oc .Op Fl d Ar flags .Op Fl I Ar path .Op Fl i Ar file .Op Fl S Ar path .Op Fl U Ar macro .Op Ar infile | - .Op Ar outfile .Sh DESCRIPTION The .Nm utility is a macro preprocessor used by the .Xr pcc 1 compiler. It is mainly used to include header files, expand macro definitions, discard comments, and perform conditional compilation. .Nm is written to comply with the .St -isoC-99 specification. .Pp The .Ar infile input file is optional. If not provided or the file name is .Qq - (dash), .Nm reads its initial file from standard input. The .Ar outfile output file is also optional, with output written to standard output if not provided. .Pp The options are as follows: .Bl -tag -width Ds .It Fl A For assembler-with-cpp input: treat non-directive lines starting with a # as comments. .It Fl C Do not discard comments. .It Fl D Ar macro Ns Oo = Ns Ar value Oc Create a macro definition before processing any input, as if a .Lp .Dl #define Ar macro Ar value .Lp directive had appeared in the source. If .Ar value is not set on the command-line, then a value of 1 is used. .It Fl d Ar flags Modify output according to .Ar flags , which can be a list of character flags. The following flags are currently supported: .Bl -tag -width ".Sy M" .It Sy M Do not process any input, but output a list of .Dq #define statements for all defined macros other than builtin macros .Pq see below . .El .Lp any unknown flags are ignored. .It Fl E Modify the exit code, if there were any warnings. .It Fl I Ar path Add .Ar path to the list of directories searched by the .Dq #include directive. This may be used to override system include directories .Pq see Fl S No option . .Fl I may be specified multiple times and is cumulative. .It Fl i Ar file Include a file before processing any input, as if a .Lp .Dl #include Qo Ar file Qc .Lp directive had appeared in the source. .Fl i may be specified multiple times to include several files. .It Fl M Instead of producing a processed C code file, output a list of dependencies for .Xr make 1 , detailing the files that need to be processed when compiling the input. .It Fl P Inhibit generation of line markers. This is sometimes useful when running the preprocessor on something other than C code. .It Fl S Ar path Add .Ar path to the list of system directories searched by the .Dq #include directive. The .Fl S option may be specified multiple times and is cumulative. .It Fl t Traditional cpp syntax. Do not define the .Dv __TIME__ , .Dv __DATE__ , .Dv __STDC__ , and .Dv __STDC_VERSION__ macros. .It Fl U Ar macro Undefine a macro before processing any input, as if a .Lp .Dl #undef Ar macro .Lp directive had appeared in the source. .It Fl V Verbose debugging output. .Fl V can be repeated for greater detail. .Po This is only available if the .Nm program was built with .Dv PCC_DEBUG defined, which is the default .Pc . .It Fl v Display version. .El .Pp The .Fl D , .Fl i and .Fl U options are processed in the order that they appear on the command line, before any input is read but after the command line options have been scanned. .Pp Files referenced by the .Dq #include directive as .Qq ... , are first looked for in the current directory, then as per .Aq ... files, which are first looked for in the list of directories provided by any .Fl I options, then in the list of system directories provided by any .Fl S options. Note that .Nm does not define any include directories by default; if no .Fl I or .Fl S options are given, then only the current directory will be searched and no system files will be found. .Ss Builtin Macros A few macros are interpreted inside the .Nm cpp program: .Bl -diag .It __DATE__ Expands to a quoted string literal containing the date in the form .Qq Mmm dd yyyy , where the names of the months are the same as those generated by the .Xr asctime 3 function, and the first character of dd is a space character if the value is less than 10. .It __FILE__ Expands to a quoted string literal containing the presumed name of the current source file. When reading source from standard input, it expands to .Qq Aq stdin . .It __LINE__ Expands to an integer constant representing the presumed line number of the source line containing the macro. .It __STDC__ Expands to the integer constant .Dq 1 , meaning that the compiler conforms to .St -isoC . .It __STDC_VERSION__ Expands to the integer constant .Dq 199901L , indicating that .Nm conforms to .St -isoC-99 . .It __TIME__ Expands to a quoted string literal containing the time in the form .Qq hh:mm:ss as generated by the .Xr asctime 3 function. .El .Pp Also see the .Fl t option. .Sh EXIT STATUS The .Nm utility exits with one of the following values: .Lp .Bl -tag -width Ds -offset indent -compact .It 0 Successfully finished. .It 1 An error occurred. .It 2 The .Fl E option was given, and warnings were issued. .El .Sh SEE ALSO .Xr as 1 , .Xr ccom 1 , .Xr make 1 , .Xr pcc 1 , .Xr asctime 3 .Sh HISTORY The .Nm command comes from the original Portable C Compiler by .An "S. C. Johnson" , written in the late 70's. The code originates from the V6 preprocessor with some additions from V7 cpp and ansi/c99 support. .Pp A lot of the PCC code was rewritten by .An "Anders Magnusson" . .Pp This product includes software developed or owned by Caldera International, Inc. pcc-20181216/cc/cpp/cpp.c010064400017500000000000001460761321345764400136100ustar raggewheel/* $Id: cpp.c,v 1.304 2017/12/11 10:36:20 ragge Exp $ */ /* * Copyright (c) 2004,2010 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * The C preprocessor. * This code originates from the V6 preprocessor with some additions * from V7 cpp, and at last ansi/c99 support. * * - kfind() expands the input buffer onto an output buffer. * - exparg() expand one buffer into another. * Recurses into submac() for fun-like macros. * - submac() replaces the given macro. * Recurses into subarg() for fun-like macros. * - subarg() expands fun-like macros. * Create strings, concats args, recurses into exparg. */ #include "config.h" #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include #include #include #include #include "compat.h" #include "cpp.h" #ifndef S_ISDIR #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #endif /* * Buffers used: * - expansion buffers (BNORMAL) * - string buffers (used to store macros) */ static int counter, didexpand; /* C command */ int tflag; /* traditional cpp syntax */ #ifdef PCC_DEBUG int dflag; /* debug printouts */ static void prline(const usch *s); static void prrep(mvtyp); #define DPRINT(x) if (dflag) printf x #else #define DPRINT(x) #endif #define PUTOB(ob, ch) (ob->cptr == ob->bsz ? \ putob(ob, ch) : (void)(ob->buf[ob->cptr++] = ch)) static int istty; int Aflag, Cflag, Eflag, Mflag, dMflag, Pflag, MPflag, MMDflag; char *Mfile, *MPfile; char *Mxfile; int warnings, Mxlen, skpows; static usch utbuf[CPPBUF]; struct iobuf pb = { utbuf, 0, CPPBUF, 0, 1, BUTBUF }; static void macstr(const usch *s); #if LIBVMF struct vspace ibspc, macspc; int lckmacbuf; struct vseg *macvseg; #endif /* * macptr is an array of char pointers for stored macros. * macpos is the current encoded position. * nmacptr are # of allocated buffers so far. */ #if LIBVMF == 0 char **macptr; int nmacptr; #endif mvtyp macpos; /* include dirs */ struct incs { struct incs *next; usch *dir; dev_t dev; ino_t ino; } *incdir[2]; static struct symtab *filloc; static struct symtab *linloc; static struct symtab *pragloc; static struct symtab *defloc; static struct symtab *ctrloc; int trulvl; int flslvl; int elflvl; int elslvl; /* * Macro replacement list syntax: * - For object-type macros, replacement strings are stored as-is. * - For function-type macros, macro args are substituted for the * character WARN followed by the argument number. * - The value element points to the beginning of the string. * * The first character in the replacement list is the number of arguments: * VARG - ends with ellipsis, next char is argcount without ellips. * OBJCT - object-type macro * 0 - empty parenthesis, foo() * 1-> - number of args. * * WARN is used: * - in stored replacement lists to tell that an argument comes * - When expanding replacement lists to tell that the list ended. * * To ensure that an already expanded identifier won't get expanded * again a EBLOCK char + its number is stored directly before any * expanded identifier. */ /* args for lookup() */ #define FIND 0 #define ENTER 1 /* * No-replacement array. If a macro is found and exists in this array * then no replacement shall occur. */ struct blocker { struct blocker *next; struct symtab *sp; }; struct blocker *blkidx[RECMAX]; int blkidp; static struct iobuf *readargs(struct iobuf *, struct symtab *, const usch **); static struct iobuf *exparg(int, struct iobuf *, struct iobuf *, struct blocker *); static struct iobuf *subarg(struct symtab *sp, const usch **args, int, struct blocker *); static void usage(void); static usch *xstrdup(const usch *str); static void addidir(char *idir, struct incs **ww); static void vsheap(struct iobuf *, const char *, va_list); static int skipws(struct iobuf *ib); static int getyp(usch *s); static void macsav(int ch); static void fstrstr(struct iobuf *ib, struct iobuf *ob); int main(int argc, char **argv) { struct includ bic; struct iobuf *fb = getobuf(BNORMAL); register int ch; const usch *fn1, *fn2; char *a; #ifdef TIMING struct timeval t1, t2; (void)gettimeofday(&t1, NULL); #endif #if LIBVMF if (vminit(4)) error("vminit"); if (vmopen(&ibspc, NULL) < 0) error("vmopen ibspc"); if (vmopen(&macspc, NULL) < 0) error("vmopen macspc"); #endif while ((ch = getopt(argc, argv, "ACD:d:EI:i:MPS:tU:Vvx:")) != -1) { switch (ch) { case 'A': /* assembler input */ Aflag++; break; case 'C': /* Do not discard comments */ Cflag++; break; case 'E': /* treat warnings as errors */ Eflag++; break; case 'D': /* define something */ if ((a = strchr(optarg, '=')) != NULL) *a = ' '; bsheap(fb, "#define %s%s", optarg, a ? "\n" : " 1\n"); break; case 'i': /* include */ bsheap(fb, "#include \"%s\"\n", optarg); break; case 'U': /* undef */ bsheap(fb, "#undef %s\n", optarg); break; case 'd': while (*optarg) { switch(*optarg) { case 'M': /* display macro definitions */ dMflag = 1; Mflag = 1; break; default: /* ignore others */ break; } optarg++; } break; case 'I': case 'S': addidir(optarg, &incdir[ch == 'I' ? INCINC : SYSINC]); break; case 'M': /* Generate dependencies for make */ Mflag++; break; case 'P': /* Inhibit generation of line numbers */ Pflag++; break; case 't': tflag = 1; break; #ifdef PCC_DEBUG case 'V': dflag++; break; #endif case 'v': fprintf(stderr, "PCC preprocessor version "VERSSTR"\n"); break; case 'x': if (strcmp(optarg, "MMD") == 0) { MMDflag++; } else if (strcmp(optarg, "MP") == 0) { MPflag++; } else if (strncmp(optarg, "MT,", 3) == 0 || strncmp(optarg, "MQ,", 3) == 0) { int l = (int)strlen(optarg+3) + 2; char *cp, *up; if (optarg[1] == 'Q') for (cp = optarg+3; *cp; cp++) if (*cp == '$') l++; Mxlen += l; Mxfile = cp = realloc(Mxfile, Mxlen); for (up = Mxfile; *up; up++) ; if (up != Mxfile) *up++ = ' '; for (cp = optarg+3; *cp; cp++) { *up++ = *cp; if (optarg[1] == 'Q' && *cp == '$') *up++ = *cp; } *up = 0; } else usage(); break; case '?': default: usage(); } } argc -= optind; argv += optind; filloc = lookup((const usch *)"__FILE__", ENTER); linloc = lookup((const usch *)"__LINE__", ENTER); pragloc = lookup((const usch *)"_Pragma", ENTER); defloc = lookup((const usch *)"defined", ENTER); ctrloc = lookup((const usch *)"__COUNTER__", ENTER); #if LIBVMF macvseg = vmmapseg(&macspc, 0); vmlock(macvseg); #else macptr = xmalloc((nmacptr = 10) * sizeof(char **)); memset(macptr, 0, nmacptr * sizeof(char **)); macptr[0] = xmalloc(CPPBUF); #endif macsav(0); filloc->valoff = linloc->valoff = pragloc->valoff = ctrloc->valoff = defloc->valoff = 1; macstr((const usch *)"defined"); macsav(0); filloc->type = FILLOC; linloc->type = LINLOC; pragloc->type = PRAGLOC; defloc->type = DEFLOC; ctrloc->type = CTRLOC; if (Mflag && !dMflag) { char *c; if (argc < 1) error("-M and no infile"); if ((c = strrchr(argv[0], '/')) == NULL) c = argv[0]; else c++; Mfile = (char *)xstrdup((usch *)c); if (MPflag) MPfile = (char *)xstrdup((usch *)c); if (Mxfile) Mfile = Mxfile; if ((c = strrchr(Mfile, '.')) == NULL) error("-M and no extension: "); c[1] = 'o'; c[2] = 0; } if (argc == 2) { close(1); if (open(argv[1], O_WRONLY|O_CREAT, 0600) < 0) error("Can't creat %s", argv[1]); } istty = isatty(1); if (argc && strcmp(argv[0], "-")) { fn1 = fn2 = (usch *)argv[0]; } else { fn1 = NULL; fn2 = (const usch *)""; } /* initialization defines */ if (dMflag) write(1, fb->buf, fb->cptr); fb->buf[fb->cptr] = 0; memset(&bic, 0, sizeof(bic)); bic.fname = bic.orgfn = (const usch *)""; bic.lineno = 1; bic.infil = -1; bic.ib = fb; fb->bsz = fb->cptr; fb->cptr = 0; ifiles = &bic; fastscan(); bufree(fb); ifiles = NULL; /* end initial defines */ if (pushfile(fn1, fn2, 0, NULL)) error("cannot open %s", argv[0]); if (Mflag == 0) { if (skpows) pb.buf[pb.cptr++] = '\n'; write(1, pb.buf, pb.cptr); } #ifdef TIMING (void)gettimeofday(&t2, NULL); t2.tv_sec -= t1.tv_sec; t2.tv_usec -= t1.tv_usec; if (t2.tv_usec < 0) { t2.tv_usec += 1000000; t2.tv_sec -= 1; } fprintf(stderr, "cpp total time: %ld s %ld us\n", (long)t2.tv_sec, (long)t2.tv_usec); #endif if (Eflag && warnings > 0) return 2; return 0; } /* * Write a character to an out buffer. */ void putob(struct iobuf *ob, int ch) { if (ob->cptr == ob->bsz) { int sz = ob->bsz; switch (ob->type) { case BNORMAL: ob->buf = xrealloc(ob->buf, sz + CPPBUF+1); /* ob->cptr = ob->buf + sz; */ ob->bsz = sz + CPPBUF; break; case BMAC: macsav(ch); return; case BINBUF: error("putob"); case BUTBUF: if (Mflag == 0) (void)write(1, ob->buf, sz); ob->cptr = 0; break; } } ob->buf[ob->cptr++] = ch; } static struct iobuf * giob(int typ, const usch *bp, int bsz) { struct iobuf *iob = xmalloc(sizeof(struct iobuf)); if (bp == NULL) bp = xmalloc(bsz); iob->buf = (usch *)bp; iob->cptr = 0; iob->bsz = bsz; iob->ro = 0; iob->type = typ; return iob; } int nbufused; /* * Get a new buffer. */ struct iobuf * getobuf(int type) { struct iobuf *iob = 0; switch (type) { case BMAC: #if LIBVMF && 0 iob = giob(BINBUF, (usch *)vseg->s_cinfo, CPPBUF); #else iob = giob(BMAC, NULL, CPPBUF); #endif break; case BNORMAL: nbufused++; iob = giob(BNORMAL, NULL, CPPBUF); iob->bsz = CPPBUF-1; /* space for \0 */ break; case BINBUF: #if LIBVMF iob = giob(BINBUF, (usch *)ifiles->vseg->s_cinfo, CPPBUF); #else iob = giob(BINBUF, NULL, CPPBUF); #endif break; default: error("getobuf"); } return iob; } /* * Create a read-only input buffer. */ static struct iobuf * mkrobuf(const usch *s) { struct iobuf *iob; nbufused++; iob = giob(BNORMAL, s, strlen((char *)s)); iob->ro = 1; DPRINT(("mkrobuf %s\n", s)); return iob; } /* * Copy a buffer to another buffer. */ struct iobuf * buftobuf(struct iobuf *in, struct iobuf *iob) { int cp; DPRINT(("buftobuf in %p out %p instr %s\n", in, iob, in->buf)); if (iob == NULL) iob = getobuf(BNORMAL); for (cp = 0; cp < in->cptr; cp++) putob(iob, in->buf[cp]); return iob; } /* * Copy a string to a buffer. */ struct iobuf * strtobuf(const usch *str, struct iobuf *iob) { if (iob == NULL) iob = getobuf(BNORMAL); DPRINT(("strtobuf iob %p buf %p str %s\n", iob, iob->buf, str)); do { PUTOB(iob, *str); } while (*str++); iob->cptr--; return iob; } static void macsav(int ch) { int cpos = VALBUF(macpos); int cptr = VALPTR(macpos); char *mp; #if LIBVMF if (lckmacbuf != cpos) { vmmodify(macvseg); vmunlock(macvseg); macvseg = vmmapseg(&macspc, cpos); lckmacbuf = cpos; vmlock(macvseg); } mp = macvseg->s_cinfo; #else if (cpos == nmacptr) { macptr = xrealloc(macptr, (nmacptr + 10) * sizeof(char **)); memset(macptr+nmacptr, 0, 10 * sizeof(char **)); nmacptr += 10; } if ((mp = macptr[cpos]) == NULL) mp = macptr[cpos] = xmalloc(CPPBUF); #endif mp[cptr] = ch, macpos++; } static void macstr(const usch *s) { do { macsav(*s); } while (*s++ != 0); macpos--; } static int macget(mvtyp a) { #if LIBVMF struct vseg *vseg = vmmapseg(&macspc, VALBUF(a)); return vseg->s_cinfo[VALPTR(a)]; #else return macptr[VALBUF(a)][VALPTR(a)]; #endif } /* * Create a replacement buffer containing the macro to be substituted. * XXX - no need to copy if everything in one buffer. */ static struct iobuf * macrepbuf(mvtyp p) { struct iobuf *ob; int ch; ob = getobuf(BNORMAL); while ((ch = macget(p++))) { putob(ob, ch); if (ch == WARN) putob(ob, macget(p++)); } putob(ob, 0); ob->cptr = 0; return ob; } #define setcmbase() cmbase = macptr #define clrcmbase() macptr = cmbase void bufree(struct iobuf *iob) { if (iob->type == BNORMAL) nbufused--; if (iob->ro == 0) free(iob->buf); free(iob); } static void addidir(char *idir, struct incs **ww) { struct incs *w; struct stat st; if (stat(idir, &st) == -1 || !S_ISDIR(st.st_mode)) return; /* ignore */ if (*ww != NULL) { for (w = *ww; w->next; w = w->next) { #ifdef _WIN32 if (strcmp(w->dir, idir) == 0) return; #else if (w->dev == st.st_dev && w->ino == st.st_ino) return; #endif } #ifdef _WIN32 if (strcmp(w->dir, idir) == 0) return; #else if (w->dev == st.st_dev && w->ino == st.st_ino) return; #endif ww = &w->next; } if ((w = calloc(sizeof(struct incs), 1)) == NULL) error("couldn't add path %s", idir); w->dir = (usch *)idir; w->dev = st.st_dev; w->ino = st.st_ino; *ww = w; } void line(void) { struct iobuf *ib, *ob; usch *inp; int n, ln; ob = savln(); ob->cptr = 0; exparg(1, ob, ib = getobuf(BNORMAL), NULL); inp = ib->buf; while (ISWSNL(*inp)) inp++; n = 0; while (ISDIGIT(*inp)) n = n * 10 + *inp++ - '0'; /* Can only be decimal number here between 1-2147483647 */ if (n < 1 || n > 2147483647) goto bad; while (ISWSNL(*inp)) inp++; ln = n; ifiles->escln = 0; if (*inp == 0) goto out; if (getyp(inp) != STRING) goto bad; if (*inp != '\"') warning("#line only allows character literals"); ob->cptr = 0; ib->cptr = (int) (inp - ib->buf); fstrstr(ib, ob); inp = ib->buf + ib->cptr; ob->buf[--ob->cptr] = 0; /* remove trailing \" */ if (strcmp((char *)ifiles->fname, (char *)ob->buf+1)) ifiles->fname = xstrdup(ob->buf+1); while (ISWSNL(*inp)) inp++; if (*inp != 0) goto bad; out: ifiles->lineno = ln; prtline(1); ifiles->lineno--; bufree(ob); bufree(ib); return; bad: error("bad #line"); } #ifdef MACHOABI /* * Example: * Library/Frameworks/VideoToolbox.framework/Headers/VTSession.h * * Search for framework header file. * Return 1 on success. */ static int fsrch_macos_framework(const usch *fn, const usch *dir) { struct iobuf *ob; usch *s = (usch *)strchr((const char*)fn, '/'); usch *p, *q, *nm; int len = s - fn; if (s == NULL) return 0; nm = xstrdup(dir); p = xstrdup(fn); *(p + len) = 0; q = (usch *)strstr((const char *)nm, (const char *)p); if (q != NULL) { *q = 0; return fsrch_macos_framework(fn, nm); } free(p); p = nm + strlen((char *)nm) - 1; while (*p == '/') p--; while (*p != '/') p--; ++p; ob = bsheap(NULL, "%s/Frameworks/%s.framework/Headers%s", nm, fn, s); free(nm); nm = xstrdup(ob->buf); bufree(ob); if (pushfile(nm, fn, SYSINC, NULL) == 0) return 1; return 0; } #endif /* * Search for and include next file. * Return 1 on success. */ static int fsrch(const usch *fn, int idx, struct incs *w) { int i; for (i = idx; i < 2; i++) { if (i > idx) w = incdir[i]; for (; w; w = w->next) { int len = strlen((char *)w->dir) + strlen((char *)fn) + 2; /* '/' + \0 */ char *f = xmalloc(len); snprintf(f, len, "%s/%s", w->dir, fn); if (pushfile((usch *)f, fn, i, w->next) == 0) return 1; free(f); } } #ifdef MACHOABI /* * On MacOS, we may have to do some clever stuff * to resolve framework headers. */ { /* * Dig out org filename path and try to find. */ usch *p, *dir = xstrdup(ifiles->orgfn); if ((p = (usch *)strrchr((char *)dir, '/')) != NULL) { p[1] = 0; if (fsrch_macos_framework(fn, dir) == 1) return 1; } free(dir); if (fsrch_macos_framework(fn, (const usch *)"/Library/Frameworks/") == 1) return 1; if (fsrch_macos_framework(fn, (const usch *)"/System/Library/Frameworks/") == 1) return 1; } #endif return 0; } static void prem(void) { error("premature EOF"); } static struct iobuf * incfn(void) { struct iobuf *ob; struct symtab *nl; usch *dp; int c; if (spechr[c = skipws(NULL)] & C_ID0) { dp = readid(c); if ((nl = lookup(dp, FIND)) == NULL) return NULL; if ((ob = kfind(nl)) == 0) return NULL; } else { ob = getobuf(BNORMAL); putob(ob, c); while ((c = cinput()) && c != '\n') putob(ob, c); if (c != '\n') return NULL; cunput(c); } /* now we have an (expanded?) filename in obuf */ while (0 < ob->cptr && ISWS(ob->buf[ob->cptr-1])) ob->cptr--; if (ob->buf[0] != '\"' && ob->buf[0] != '<') return NULL; if (ob->buf[ob->cptr-1] != '\"' && ob->buf[ob->cptr-1] != '>') return NULL; ob->buf[ob->cptr-1] = 0; return ob; } /* * Include a file. Include order: * - For <...> files, first search -I directories, then system directories. * - For "..." files, first search "current" dir, then as <...> files. */ void include(void) { struct iobuf *ob; usch *fn, *nm = NULL; if (flslvl) return; if ((ob = incfn()) == NULL) /* get include file name in obuf */ error("bad #include"); fn = xstrdup(ob->buf) + 1; /* Save on string heap? */ bufree(ob); /* test absolute path first */ if (fn[0] == '/' && pushfile(fn, fn, 0, NULL) == 0) goto okret; if (fn[-1] == '\"') { /* nope, failed, try to create a path for it */ if ((nm = (usch *)strrchr((char *)ifiles->orgfn, '/'))) { ob = strtobuf((usch *)ifiles->orgfn, NULL); ob->cptr = (int)(nm - ifiles->orgfn) + 1; strtobuf(fn, ob); nm = xstrdup(ob->buf); bufree(ob); } else nm = xstrdup(fn); if (pushfile(nm, nm, 0, NULL) == 0) { free(fn-1); goto okret; } } if (fsrch(fn, 0, incdir[0])) goto okret; error("cannot find '%s'", fn); /* error() do not return */ okret: if (nm) free(nm); prtline(1); } void include_next(void) { struct iobuf *ob; usch *nm; if (flslvl) return; if ((ob = incfn()) == NULL) /* get include file name in obuf */ error("bad #include_next"); nm = xstrdup(ob->buf+1); bufree(ob); if (fsrch(nm, ifiles->idx, ifiles->incs) == 0) error("cannot find '%s'", nm); prtline(1); } /* * Compare two replacement lists, taking in account comments etc. */ static int cmprepl(mvtyp oin, mvtyp nin) { int o, n; for (; ; oin++, nin++) { /* comment skip */ o = macget(oin); n = macget(nin); if (o == '/' && macget(oin+1) == '*') { oin+=2; while (macget(oin) != '*' || macget(oin+1) != '/') oin++; oin += 2; } if (n == '/' && macget(nin+1) == '*') { nin+=2; while (macget(nin) != '*' || macget(nin+1) != '/') nin++; nin += 2; } while ((o = macget(oin)) == ' ' || o == '\t') oin++; while ((n = macget(nin)) == ' ' || n == '\t') nin++; if (o != n) return 1; if (o == 0) break; } return 0; } static int isell(void) { if (cinput() != '.' || cinput() != '.') return 0; return 1; } static int skipwscmnt(struct iobuf *ib) { /* XXX comment */ return skipws(ib); } static int findarg(usch *s, struct iobuf *ab, int *arg, int narg) { int i; for (i = 0; i < narg; i++) if (strcmp((char *)s, (char *)ab->buf + arg[i]) == 0) return i; return -1; } static void delews(mvtyp beg) { int c; mvtyp lastnonws = beg; macsav(0); for (;;beg++) { if ((c = macget(beg)) == 0) { macpos = ++lastnonws; return; } if (c == WARN) beg++; if (!ISWSNL(c)) lastnonws = beg; } } /* * gcc extensions: * #define e(a...) f(s, a) -> a works as __VA_ARGS__ * #define e(fmt, ...) f(s, fmt , ##__VA_ARGS__) -> remove , if no args */ void define(void) { extern int incmnt; struct iobuf *ab; struct symtab *np; usch cc[2], *vararg, *dp; int arg[MAXARGS+1]; int c, i, redef, oCflag, t; int type, narg; int wascon; mvtyp begpos; if (flslvl) return; oCflag = Cflag, Cflag = 0; /* Ignore comments here */ if (!ISID0(c = skipws(0))) goto bad; dp = readid(c); np = lookup(dp, ENTER); if (np->valoff) { redef = 1; } else { np->namep = xstrdup(dp); redef = 0; } type = OBJCT; narg = 0; ab = getobuf(BNORMAL); vararg = NULL; if ((c = cinput()) == '(') { type = FUNLIKE; /* function-like macros, deal with identifiers */ c = skipws(0); for (;;) { switch (c) { case ')': break; case '.': if (isell() == 0 || (c = skipws(0)) != ')') goto bad; vararg = (usch *)"__VA_ARGS__"; break; default: if (!ISID0(c)) goto bad; dp = bufid(c, ab); /* make sure there is no arg of same name */ if (findarg(dp, ab, arg, narg) >= 0) error("Duplicate parameter \"%s\"", dp); if (narg == MAXARGS) error("Too many macro args"); putob(ab, 0); arg[narg++] = (int)(dp - ab->buf); switch ((c = skipws(0))) { case ',': break; case ')': continue; case '.': if (isell() == 0 || skipws(0) != ')') goto bad; vararg = ab->buf + arg[--narg]; c = ')'; continue; default: goto bad; } c = skipws(0); } if (c == ')') break; } c = skipws(0); } else if (c == '\n') { /* #define foo */ ; } else if (c == 0) { prem(); } else if (!ISWS(c)) goto bad; Cflag = oCflag; /* Enable comments again */ begpos = macpos; if (ISWS(c)) c = skipwscmnt(0); /* parse replacement-list, substituting arguments */ wascon = 0; while (c != '\n') { incmnt++; cc[0] = c, cc[1] = cinput(); incmnt--; t = getyp(cc); cunput(cc[1]); switch (t) { case ' ': case '\t': macsav(' '); /* save only one space */ while ((c = cinput()) == ' ' || c == '\t') ; continue; case '#': if (cc[1] == '#') { /* concat op */ (void)cinput(); /* eat # */ delews(begpos); macsav(CONC); if (ISID0(c = skipws(0)) && type == FUNLIKE) wascon = 1; if (c == '\n') goto bad; /* 6.10.3.3 p1 */ continue; } if (type == OBJCT) { /* no meaning in object-type macro */ macsav('#'); break; } /* remove spaces between # and arg */ macsav(SNUFF); c = skipws(0); /* whitespace, ignore */ if (!ISID0(c)) goto bad; dp = readid(c); if (vararg && strcmp((char *)dp, (char *)vararg) == 0) { macsav(WARN); macsav(C99ARG); macsav(SNUFF); break; } if ((i = findarg(dp, ab, arg, narg)) < 0) goto bad; macsav(WARN); macsav(i); macsav(SNUFF); break; case CMNT: macsav(c), c = cinput(); if (c == '/') { do { macsav(c), c = cinput(); } while (c && c != '\n'); if (c == 0) goto bad; continue; } else { macsav(c); for (;;) { macsav(c = cinput()); back: if (c == '*') { macsav(c = cinput()); if (c == '/') break; if (c == '*') goto back; } } } break; case NUMBER: if (c == '.') macsav(c), c = cinput(); for (;;) { macsav(i = c), c = cinput(); if (c == '-' || c == '+') { if ((i & 0337) != 'E' && i != 'P') break; } else if ((c != '.') && ((spechr[c] & C_ID) == 0)) break; } continue; case STRING: if (c == 'L' || c == 'u' || c == 'U') { macsav(c); if ((c = cinput()) == '8') { macsav(c); c = cinput(); } } if (tflag) { macsav(c); } else { extern int instr; int bc; if (c == 'u' || c == 'U' || c == 'L') { macsav(c), c = cinput(); if (c == '8') macsav(c), c = cinput(); } bc = c; instr = 1; macsav(c), c = cinput(); while (c != bc) { if (c == '\\') macsav(c), c = cinput(); else if (c == '\n') goto bad; macsav(c), c = cinput(); } macsav(c); instr = 0; } break; case IDENT: dp = readid(c); if (type == OBJCT) { macstr(dp); break; /* keep on heap */ } if (vararg && strcmp((char *)dp, (char *)vararg) == 0) { macsav(WARN); macsav(wascon ? GCCARG : C99ARG); break; } /* check if its an argument */ if ((i = findarg(dp, ab, arg, narg)) < 0) { macstr(dp); break; } macsav(WARN); macsav(i); break; case 0: goto bad; default: macsav(c); break; } wascon = 0; c = cinput(); } cunput(c); /* remove trailing whitespace */ delews(begpos); macsav(0); if (vararg) type = VARG; if (macget(begpos) == CONC) goto bad; /* 6.10.3.3 p1 */ if (redef && ifiles->idx != SYSINC) { if (cmprepl(np->valoff, begpos) || np->type != type || np->narg != narg) { /* not equal */ np->valoff = begpos; warning("%s redefined (previously defined at \"%s\" line %d)", np->namep, np->file, np->line); } else macpos = begpos; /* forget this space */ } else np->valoff = begpos; np->type = type; np->narg = narg; #ifdef PCC_DEBUG if (dflag) { printf("!define %s: ", np->namep); if (type == OBJCT) printf("[object]"); else if (type == VARG) printf("[VARG%d]", narg); else printf("[%d]", narg); putchar('\''); prrep(np->valoff); printf("\'\n"); printf("%s: link %d off %d\n", np->namep, VALBUF(np->valoff), VALPTR(np->valoff)); } #endif bufree(ab); return; bad: error("bad #define"); } void warning(const char *fmt, ...) { va_list ap; if (ifiles != NULL) fprintf(stderr, "%s:%d: warning: ", ifiles->fname, ifiles->lineno); va_start(ap,fmt); vfprintf(stderr, fmt, ap); va_end(ap); fputc('\n', stderr); warnings++; } void error(const char *fmt, ...) { va_list ap; write(1, pb.buf, pb.cptr); if (ifiles != NULL) fprintf(stderr, "%s:%d: error: ", ifiles->fname, ifiles->lineno); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fputc('\n', stderr); exit(1); } static int pragwin(struct iobuf *ib) { return ib ? ib->buf[ib->cptr++] : cinput(); } static int skipws(struct iobuf *ib) { int t; while ((t = pragwin(ib)) == ' ' || t == '\t') ; return t; } /* * convert _Pragma() to #pragma for output. * Syntax is already correct. */ static void pragoper(struct iobuf *ib) { int t; if (skipws(ib) != '(' || ((t = skipws(ib)) != '\"' && t != 'L')) goto err; if (t == 'L' && (t = pragwin(ib)) != '\"') goto err; putstr((usch *)"\n#pragma "); while ((t = pragwin(ib)) != '\"') { if (t == BLKID) { pragwin(ib); continue; } if (t == '\"') continue; if (t == '\\') { if ((t = pragwin(ib)) != '\"' && t != '\\') putch('\\'); } putch(t); } prtline(1); if (skipws(ib) == ')') return; err: error("_Pragma() syntax error"); } #ifdef PCC_DEBUG static void prblocker(char *s, struct blocker *bl) { printf("%s (blocker): ", s); for (; bl; bl = bl->next) printf("%s ", bl->sp->namep); printf("\n"); } #else #define prblocker(x,y) #endif /* * Check if symtab is in blocklist based on index l. */ static int expok(struct symtab *sp, int l) { struct blocker *w; if (l == 0) return 1; #ifdef PCC_DEBUG if (dflag) prblocker("expok", blkidx[l]); #endif w = blkidx[l]; while (w) { if (w->sp == sp) return 0; w = w->next; } return 1; } /* * Check if symtab is in blocklist. */ static int expokb(struct symtab *sp, struct blocker *bl) { struct blocker *w; if (bl == 0) return 1; #ifdef PCC_DEBUG if (dflag) prblocker("expok", bl); #endif w = bl; while (w) { if (w->sp == sp) return 0; w = w->next; } return 1; } static struct blocker * blkget(struct symtab *sp, struct blocker *obl) { struct blocker *bl = calloc(sizeof(*obl), 1); bl->sp = sp; bl->next = obl; return bl; } static int blkix(struct blocker *obl) { if (blkidp > 1 && blkidx[blkidp-1] == obl) return blkidp-1; if (blkidp == RECMAX) error("blkix"); blkidx[blkidp] = obl; return blkidp++; } static struct blocker * mergeadd(struct blocker *bl, int m) { struct blocker *w, *ww; DPRINT(("mergeadd: %p %d\n", bl, m)); if (dflag > 1) { prblocker("mergeadd", bl); if (m) prblocker("mergeadd", blkidx[m]); } if (bl == 0) return blkidx[m]; if (m == 0) return bl; blkidx[blkidp] = bl; for (w = blkidx[m]; w; w = w->next) { ww = calloc(sizeof(*w), 1); ww->sp = w->sp; ww->next = blkidx[blkidp]; blkidx[blkidp] = ww; } DPRINT(("mergeadd return: %d ", blkidp)); #ifdef PCC_DEBUG if (dflag) prblocker("mergeadd", blkidx[blkidp]); #endif return blkidx[blkidp++]; } static void storeblk(int l, struct iobuf *ob) { DPRINT(("storeblk: %d\n", l)); putob(ob, BLKID); putob(ob, l); } /* * Save filename on heap (with escaped chars). */ static struct iobuf * unfname(void) { struct iobuf *ob = getobuf(BNORMAL); const usch *bp = ifiles->fname; putob(ob, '\"'); for (; *bp; bp++) { if (*bp == '\"' || *bp == '\'' || *bp == '\\') putob(ob, '\\'); putob(ob, *bp); } putob(ob, '\"'); return ob; } /* * Version of fastnum that reads from a string and saves in ob. * We know that it is a number before calling this routine. */ static void fstrnum(struct iobuf *ib, struct iobuf *ob) { usch *s = ib->buf+ib->cptr; int c2; if (*s == '.') { /* not digit, dot. Next will be digit */ putob(ob, *s++); } for (;;) { putob(ob, *s++); if ((c2 = (*s & 0337)) == 'E' || c2 == 'P') { if (s[1] != '-' && s[1] != '+') break; putob(ob, *s++); } else if ((*s != '.') && ((spechr[*s] & C_ID) == 0)) break; } ib->cptr = (int)(s - ib->buf); } /* * get a string or character constant. * similar to faststr. */ static void fstrstr(struct iobuf *ib, struct iobuf *ob) { usch *s = ib->buf+ib->cptr; int ch; if (*s == 'L' || *s == 'U' || *s == 'u') putob(ob, *s++); if (*s == '8') putob(ob, *s++); ch = *s; putob(ob, *s++); while (*s != ch) { if (*s == '\\') putob(ob, *s++); putob(ob, *s++); } putob(ob, *s++); ib->cptr = (int)(s - ib->buf); } /* * Save standard comments if found. */ static void fcmnt(struct iobuf *ib, struct iobuf *ob) { usch *s = ib->buf+ib->cptr; putob(ob, *s++); /* / */ putob(ob, *s++); /* * */ for (;;s++) { putob(ob, *s); if (s[-1] == '*' && *s == '/') break; } ib->cptr = (int)(s - ib->buf + 1); } static int getyp(usch *s) { if (ISID0(*s)) return IDENT; if ((*s == 'L' || *s == 'U' || *s == 'u') && (s[1] == '\'' || s[1] == '\"')) return STRING; if (s[0] == 'u' && s[1] == '8' && s[2] == '\"') return STRING; if (s[0] == '\'' || s[0] == '\"') return STRING; if (spechr[*s] & C_DIGIT) return NUMBER; if (*s == '.' && (spechr[s[1]] & C_DIGIT)) return NUMBER; if (*s == '/' && (s[1] == '/' || s[1] == '*')) return CMNT; return *s; } /* * Check ib and print out the symbols there. * If expandable symbols found recurse and expand them. * If last identifier on the input list is expandable return it. * Expect ib to be zero-terminated. */ static struct symtab * loopover(struct iobuf *ib, struct iobuf *ob) { struct iobuf *xb, *xob; struct symtab *sp; usch *cp; int l, c, t, cn; ib->cptr = 0; /* start from beginning */ #ifdef PCC_DEBUG if (dflag) { printf("loopover: '"); prline(ib->buf+ib->cptr); printf("'\n"); } #endif xb = getobuf(BNORMAL); while ((c = ib->buf[ib->cptr])) { switch (t = getyp(ib->buf+ib->cptr)) { case CMNT: fcmnt(ib, ob); continue; case NUMBER: fstrnum(ib, ob); continue; case STRING: xb->cptr = 0; fstrstr(ib, xb); xb->buf[xb->cptr] = 0; for (cp = xb->buf; *cp; cp++) { if (*cp <= BLKID) { if (*cp == BLKID) cp++; continue; } putob(ob, *cp); } continue; case BLKID: l = ib->buf[ib->cptr+1]; ib->cptr+=2; /* FALLTHROUGH */ case IDENT: if (t != BLKID) l = 0; /* * Tricky: if this is the last identifier * in the expanded list, and it is defined * as a function-like macro, then push it * back on the input stream and let fastscan * handle it as a new macro. * BUT: if this macro is blocked then this * should not be done. */ for (cn = ib->cptr; ISID(ib->buf[ib->cptr]); ib->cptr++) ; if ((sp = lookup(cn+ib->buf, FIND)) == NULL) { sstr: for (; cn < ib->cptr; cn++) putob(ob, ib->buf[cn]); continue; } if (expok(sp, l) == 0) { /* blocked */ goto sstr; } else { if (sp->type != OBJCT) { cn = ib->cptr; while (ISWS(ib->buf[ib->cptr])) ib->cptr++; if (ib->buf[ib->cptr] == 0) { bufree(xb); return sp; } ib->cptr = cn; } newmac: if ((xob = submac(sp, 1, ib, NULL)) == NULL) { strtobuf((usch *)sp->namep, ob); } else { sp = loopover(xob, ob); bufree(xob); if (sp != NULL) goto newmac; } } continue; default: putob(ob, c); } ib->cptr++; } bufree(xb); DPRINT(("loopover return 0\n")); return 0; } /* * Handle defined macro keywords found on input stream. * When finished print out the full expanded line. * Input here is from the lex buffer. * Return 1 if success, 0 otherwise. * Scanned data is stored on heap. Last scan prints out the buffer. */ struct iobuf * kfind(struct symtab *sp) { extern int inexpr; struct blocker *bl; struct iobuf *ib, *ob, *outb, *ab; const usch *argary[MAXARGS+1]; int c, n = 0; blkidp = 1; outb = NULL; DPRINT(("%d:enter kfind(%s)\n",0,sp->namep)); switch ((unsigned int)sp->type) { case FILLOC: ob = unfname(); return ob; case LINLOC: return bsheap(NULL, "%d", ifiles->lineno); case PRAGLOC: pragoper(NULL); return getobuf(BNORMAL); case DEFLOC: case OBJCT: bl = blkget(sp, NULL); ib = macrepbuf(sp->valoff); ob = getobuf(BNORMAL); ob = exparg(1, ib, ob, bl); bufree(ib); break; case CTRLOC: return bsheap(NULL, "%d", counter++); default: /* Search for '(' */ while (ISWSNL(c = cinput())) if (c == '\n') n++; if (c != '(') { if (inexpr == 0) putstr(sp->namep); if (n == 0) putch(' '); else for (ifiles->lineno += n; n; n--) putch('\n'); cunput(c); return 0; /* Failed */ } /* fetch arguments */ again: if ((ab = readargs(NULL, sp, argary)) == 0) error("readargs"); bl = blkget(sp, NULL); ib = subarg(sp, argary, 1, bl); bufree(ab); ob = getobuf(BNORMAL); ob = exparg(1, ib, ob, bl); bufree(ib); break; } /* * Loop over ob, output the data and remove remaining * directives. Start with extracting the last keyword (if any). */ putob(ob, 0); /* XXX needed? */ if (outb == NULL) outb = getobuf(BNORMAL); if ((sp = loopover(ob, outb))) { /* Search for '(' */ while (ISWSNL(c = cinput())) if (c == '\n') n++; if (c == '(') { bufree(ob); goto again; } cunput(c); strtobuf((usch *)sp->namep, outb); } bufree(ob); for (ifiles->lineno += n; n; n--) putob(outb, '\n'); if (nbufused != 1) error("lost buffer"); return outb; } /* * Replace and push-back on input stream the eventual replaced macro. * The check for whether it can expand or not should already have been done. * Blocks for this identifier will be added via insblock() after expansion. * The same as kfind but read a string. */ struct iobuf * submac(struct symtab *sp, int lvl, struct iobuf *ib, struct blocker *obl) { struct blocker *bl; struct iobuf *ob, *ab; const usch *argary[MAXARGS+1]; int cn; DPRINT(("%d:submac: trying '%s'\n", lvl, sp->namep)); switch ((unsigned int)sp->type) { case FILLOC: ob = unfname(); break; case LINLOC: ob = bsheap(NULL, "%d", ifiles->lineno); break; case PRAGLOC: pragoper(ib); ob = getobuf(BNORMAL); break; case OBJCT: bl = blkget(sp, obl); ib = macrepbuf(sp->valoff); ob = getobuf(BNORMAL); DPRINT(("%d:submac: calling exparg\n", lvl)); ob = exparg(lvl+1, ib, ob, bl); bufree(ib); DPRINT(("%d:submac: return exparg\n", lvl)); break; case CTRLOC: ob = bsheap(NULL, "%d", counter++); break; default: cn = ib->cptr; while (ISWSNL(ib->buf[ib->cptr])) ib->cptr++; if (ib->buf[ib->cptr] != '(') { ib->cptr = cn; return 0; } cn = ib->cptr++; if ((ab = readargs(ib, sp, argary)) == 0) { /* Bailed out in the middle of arg list */ ib->cptr = cn; /* XXX */ return 0; } bl = blkget(sp, obl); ib = subarg(sp, argary, lvl+1, bl); bufree(ab); ob = getobuf(BNORMAL); DPRINT(("%d:submac(: calling exparg\n", lvl)); ob = exparg(lvl+1, ib, ob, bl); bufree(ib); DPRINT(("%d:submac(: return exparg\n", lvl)); break; } putob(ob, 0); ob->cptr--; return ob; } static int skpws(void) { int c; while ((c = cinput()) == ' ' || c == '\t') ; return c; } /* * Read arguments and put in argument array. * Follow the guidelines from Fred Tydeman's proposal of line numbering. */ struct iobuf * readargs(struct iobuf *in, struct symtab *sp, const usch **args) { struct iobuf *ab, *saved; int infil, c, i, j, plev, narg, ellips = 0; int argary[MAXARGS+1]; DPRINT(("readargs\n")); narg = sp->narg; ellips = sp->type == VARG; saved = ifiles->ib; infil = ifiles->infil; if (in) ifiles->ib = in, ifiles->infil = -1; #ifdef PCC_DEBUG if (dflag > 1) { printf("narg %d varg %d: ", narg, ellips); prrep(sp->valoff); printf("\n"); } #endif /* * read arguments and store them on heap. */ ab = getobuf(BNORMAL); c = '('; for (i = 0; i < narg && c != ')'; i++) { argary[i] = ab->cptr; plev = 0; c = skpws(); for (;;) { if (plev == 0 && (c == ')' || c == ',')) break; if (c == '(') plev++; if (c == ')') plev--; switch (c) { case 0: if (in) { in->cptr--; /* qcchar() walks over */ ifiles->ib = saved; in = NULL; } else error("eof in macro"); break; case BLKID: putob(ab, c); putob(ab, ifiles->ib->buf[ifiles->ib->cptr++]); break; case '/': if ((c = cinput()) == '*' || c == '/') Ccmnt2(ab, c); else { putob(ab, '/'); cunput(c); } break; case '\n': ifiles->escln++; c = skpws(); if (c == '#') { ppdir(); } else { /* only if not first char on line */ if (argary[i] != ab->cptr) putob(ab, ' '); continue; } break; case '\"': case '\'': faststr(c, ab); break; default: if (ISID0(c)) { bufid(c, ab); } else putob(ab, c); break; } c = cinput(); } while (argary[i] < ab->cptr && ISWSNL(ab->buf[ab->cptr-1])) ab->cptr--; putob(ab, '\0'); #ifdef PCC_DEBUG if (dflag) { printf("readargs: save arg %d '", i); prline(ab->buf+argary[i]); printf("'\n"); } #endif } /* Handle varargs readin */ argary[i] = ab->cptr; putob(ab, 0); ab->cptr--; if (ellips && c != ')') { plev = 0; c = skpws(); for (;;) { if ((plev == 0 && c == ')') || c == 0) break; if (c == '(') plev++; if (c == ')') plev--; if (c == '\"' || c == '\'') { faststr(c, ab); } else putob(ab, c); if ((c = cinput()) == '\n') ifiles->escln++, c = ' '; } if (c == 0) error("unterminated macro invocation"); while (argary[i] < ab->cptr && ISWSNL(ab->buf[ab->cptr-1])) ab->cptr--; putob(ab, '\0'); #ifdef PCC_DEBUG if (dflag) { printf("readargs: vararg arg %d '", i); prline(ab->buf+argary[i]); printf("'\n"); } #endif } if (ellips) i++; if (narg == 0 && ellips == 0) c = skpws(); if (c != ')' || (i != narg && ellips == 0) || (i < narg && ellips == 1)) error("wrong arg count"); for (j = 0; j < i; j++) args[j] = ab->buf + argary[j]; ifiles->ib = saved, ifiles->infil = infil; return ab; } /* * escape "\ inside strings. */ static void escstr(const usch *bp, struct iobuf *ob) { int instr = 0; while (*bp) { if (!instr && ISWS(*bp)) { while (ISWS(*bp)) bp++; putob(ob, ' '); } if (*bp == '\'' || *bp == '"') { instr ^= 1; if (*bp == '"') putob(ob, '\\'); } if (instr && *bp == '\\') { putob(ob, *bp); if (bp[1] == '\"') putob(ob, *bp), putob(ob, *bp++); } putob(ob, *bp); bp++; } } /* * expand a function-like macro. * vp points to end of replacement-list * reads function arguments from input stream. * result is pushed-back for more scanning. */ struct iobuf * subarg(struct symtab *nl, const usch **args, int lvl, struct blocker *bl) { struct blocker *w; struct iobuf *ob, *cb, *nb, *vb; int narg, snuff, c2; const usch *sp, *bp, *ap, *vp; DPRINT(("%d:subarg '%s'\n", lvl, nl->namep)); ob = getobuf(BNORMAL); vb = macrepbuf(nl->valoff); vp = vb->buf; narg = nl->narg; sp = vp; snuff = 0; #ifdef PCC_DEBUG if (dflag>1) { printf("%d:subarg ARGlist for %s: '", lvl, nl->namep); prrep(nl->valoff); printf("'\n"); prblocker("subarg", bl); } #endif /* * walk forward over replacement-list while replacing * arguments. Arguments are macro-expanded if required. */ while (*sp) { if (*sp == SNUFF) putob(ob, '\"'), snuff ^= 1; else if (*sp == CONC) ; else if (*sp == WARN) { if (sp[1] == C99ARG) { bp = ap = args[narg]; sp++; #ifdef GCC_COMPAT } else if (sp[1] == GCCARG) { /* XXX remove last , not add 0 */ ap = args[narg]; if (ap[0] == 0) ap = (const usch *)"0"; bp = ap; sp++; #endif } else bp = ap = args[(int)*++sp]; #ifdef PCC_DEBUG if (dflag>1){ printf("%d:subarg GOTwarn; arglist '", lvl); prline(bp); printf("'\n"); } #endif c2 = (sp-2 < vp ? 0 : sp[-2]); if (c2 != CONC && !snuff && sp[1] != CONC) { /* * Expand an argument; 6.10.3.1: * "A parameter in the replacement list, * is replaced by the corresponding argument * after all macros contained therein have * been expanded.". */ w = bl ? bl->next : NULL; nb = mkrobuf(bp); DPRINT(("%d:subarg: calling exparg\n", lvl)); do { cb = nb; cb->cptr = 0; didexpand = 0; nb = getobuf(BNORMAL); nb = exparg(lvl+1, cb, nb, w); bufree(cb); } while (didexpand); DPRINT(("%d:subarg: return exparg\n", lvl)); strtobuf(nb->buf, ob); bufree(nb); } else { if (snuff) escstr(bp, ob); else strtobuf(bp, ob); } } else if (ISID0(*sp)) { if (lookup(sp, FIND)) storeblk(blkix(bl), ob); while (ISID(*sp)) putob(ob, *sp++); sp--; } else putob(ob, *sp); sp++; } putob(ob, 0); ob->cptr = 0; DPRINT(("%d:subarg retline %s\n", lvl, ob->buf)); bufree(vb); return ob; } /* * Do a (correct) expansion of a buffer of tokens. * Data is read from the input buffer, result on output buffer. * Expansion blocking is not altered here unless when tokens are * concatenated, in which case the blocking is removed. */ struct iobuf * exparg(int lvl, struct iobuf *ib, struct iobuf *ob, struct blocker *bl) { extern int inexpr; struct iobuf *nob, *tb; struct symtab *nl; int c, m; usch *cp; DPRINT(("%d:exparg: entry ib %s\n", lvl, ib->buf+ib->cptr)); #ifdef PCC_DEBUG if (dflag > 1) { printf("exparg entry: full "); prline(ib->buf+ib->cptr); printf("\n"); prblocker("exparg", bl); } #endif while ((c = getyp(ib->buf+ib->cptr)) != 0) { switch (c) { case CMNT: fcmnt(ib, ob); break; case NUMBER: fstrnum(ib, ob); break; case STRING: fstrstr(ib, ob); break; case BLKID: m = ib->buf[++ib->cptr]; ib->cptr++; /* FALLTHROUGH */ case IDENT: if (c != BLKID) m = 0; tb = getobuf(BNORMAL); cp = ib->buf+ib->cptr; for (; ISID(*cp) || *cp == BLKID; cp++) { if (*cp == BLKID) { /* XXX add to block list */ cp++; } else putob(tb, *cp); } tb->buf[tb->cptr] = 0; ib->cptr = (int)(cp - ib->buf); /* Any match? */ if ((nl = lookup(tb->buf, FIND)) == NULL) { buftobuf(tb, ob); } else if (inexpr && nl->type == DEFLOC) { /* Used in #if stmts */ int gotlp = 0; cp = ib->buf+ib->cptr; while (ISWS(*cp)) cp++; if (*cp == '(') gotlp++, cp++; while (ISWS(*cp)) cp++; if (!ISID0(*cp)) error("bad defined"); putob(ob, lookup(cp, FIND) ? '1' : '0'); while (ISID(*cp)) cp++; while (ISWS(*cp)) cp++; if (gotlp && *cp != ')') error("bad defined"); cp++; ib->cptr = (int)(cp - ib->buf); } else if (expokb(nl, bl) && expok(nl, m) && (nob = submac(nl, lvl+1, ib, bl))) { didexpand = 1; if (nob->buf[0] == '-' || nob->buf[0] == '+') putob(ob, ' '); strtobuf(nob->buf, ob); if (ob->cptr > 0 && (ob->buf[ob->cptr-1] == '-' || ob->buf[ob->cptr-1] == '+')) putob(ob, ' '); bufree(nob); } else { storeblk(blkix(mergeadd(bl, m)), ob); buftobuf(tb, ob); } bufree(tb); break; default: PUTOB(ob, c); ib->cptr++; break; } } putob(ob, 0); ob->cptr--; DPRINT(("%d:exparg return: ob %s\n", lvl, ob->buf)); #ifdef PCC_DEBUG if (dflag > 1) { printf("%d:exparg: full ", lvl); prline(ob->buf); printf("\n"); prblocker("exparg", bl); } #endif return ob; } #ifdef PCC_DEBUG static void blkprint(int idx) { struct blocker *bl = blkidx[idx]; printf("next) printf("%s ", bl->sp->namep); printf(")>"); } static void prrep(mvtyp ptr) { int s; while ((s = macget(ptr++))) { switch (s) { case WARN: s = macget(ptr++); if (s == C99ARG) printf(""); else if (s == GCCARG) printf(""); else printf("", s); break; case CONC: printf(""); break; case SNUFF: printf(""); break; case BLKID: blkprint(macget(ptr++)); break; default: printf("%c", s); break; } } } static void prline(const usch *s) { while (*s) { switch (*s) { case BLKID: blkprint(*++s); break; case WARN: printf(""); break; case CONC: printf(""); break; case SNUFF: printf(""); break; case '\n': printf(""); break; default: if (*s > 0x7f) printf("<0x%x>", *s); else printf("%c", *s); break; } s++; } } #endif void cntline(void) { if (skpows < 10) for (; skpows > 0; skpows--) putob(&pb, '\n'); else prtline(1); skpows = 0; } void putch(int ch) { if (skpows) { if (ch == '\n') skpows++; if (ISWSNL(ch)) return; cntline(); } else if (ch == '\n' && tflag == 0) { skpows = 1; return; } if (pb.cptr == pb.bsz) putob(&pb, ch); else pb.buf[pb.cptr++] = ch; if (ch == '\n' && istty && Mflag == 0) (void)write(1, pb.buf, pb.cptr), pb.cptr = 0; } void putstr(const usch *s) { if (skpows) cntline(); strtobuf(s, &pb); } /* * convert a number to an ascii string. Store it on the heap. */ static void num2str(struct iobuf *ob, int num) { static usch buf[12]; usch *b = buf; int m = 0; if (num < 0) num = -num, m = 1; do { *b++ = (usch)(num % 10 + '0'); num /= 10; } while (num); if (m) *b++ = '-'; while (b > buf) putob(ob, *--b); } /* * similar to sprintf, but only handles %c, %s and %d. * saves result on heap. */ static void vsheap(struct iobuf *ob, const char *fmt, va_list ap) { for (; *fmt; fmt++) { if (*fmt == '%') { fmt++; switch (*fmt) { case 's': strtobuf(va_arg(ap, usch *), ob); break; case 'd': num2str(ob, va_arg(ap, int)); break; case 'c': putob(ob, va_arg(ap, int)); break; default: error("bad sheap"); } } else putob(ob, *fmt); } putob(ob, 0); ob->cptr--; } struct iobuf * bsheap(struct iobuf *ob, const char *fmt, ...) { va_list ap; if (ob == NULL) ob = getobuf(BNORMAL); va_start(ap, fmt); vsheap(ob, fmt, ap); va_end(ap); return ob; } static void usage(void) { error("Usage: cpp [-Cdt] [-Dvar=val] [-Uvar] [-Ipath] [-Spath]"); } #ifdef notyet /* * Symbol table stuff. * The data structure used is a patricia tree implementation using only * bytes to store offsets. * The information stored is (lower address to higher): * * unsigned char bitno[2]; bit number in the string * unsigned char left[3]; offset from base to left element * unsigned char right[3]; offset from base to right element */ #endif /* * This patricia implementation is more-or-less the same as * used in ccom for string matching. */ struct tree { int bitno; struct tree *lr[2]; }; #define BITNO(x) ((x) & ~(LEFT_IS_LEAF|RIGHT_IS_LEAF)) #define LEFT_IS_LEAF 0x80000000 #define RIGHT_IS_LEAF 0x40000000 #define IS_LEFT_LEAF(x) (((x) & LEFT_IS_LEAF) != 0) #define IS_RIGHT_LEAF(x) (((x) & RIGHT_IS_LEAF) != 0) #define P_BIT(key, bit) (key[bit >> 3] >> (bit & 7)) & 1 #define CHECKBITS 8 static struct tree *sympole; static int numsyms; static struct tree * gtree(void) { static int ntrees; static struct tree *tp; if (ntrees == 0) { tp = xmalloc(CPPBUF); ntrees = CPPBUF/sizeof(*tp); } return &tp[--ntrees]; } /* * Allocate a symtab struct and store the string. */ static struct symtab * getsymtab(const usch *str) { static int nsyms; static struct symtab *spp; struct symtab *sp; if (nsyms == 0) { spp = xmalloc(CPPBUF); nsyms = CPPBUF/sizeof(*sp); } sp = &spp[--nsyms]; sp->namep = str; sp->valoff = 0; sp->file = ifiles ? ifiles->orgfn : (const usch *)""; sp->line = ifiles ? ifiles->lineno : 0; return sp; } /* * Do symbol lookup in a patricia tree. * Only do full string matching, no pointer optimisations. */ struct symtab * lookup(const usch *key, int enterf) { struct symtab *sp; struct tree *w, *new, *last; int len, cix, bit, fbit, svbit, ix, bitno; const usch *k, *m; /* Count full string length */ for (k = key, len = 0; ISID(*k) & C_ID; k++, len++) ; switch (numsyms) { case 0: /* no symbols yet */ if (enterf != ENTER) return NULL; sympole = (struct tree *)getsymtab(key); numsyms++; return (struct symtab *)sympole; case 1: w = sympole; svbit = 0; /* XXX gcc */ break; default: w = sympole; bitno = len * CHECKBITS; for (;;) { bit = BITNO(w->bitno); fbit = bit >= bitno ? 0 : P_BIT(key, bit); svbit = fbit ? IS_RIGHT_LEAF(w->bitno) : IS_LEFT_LEAF(w->bitno); w = w->lr[fbit]; if (svbit) break; } } sp = (struct symtab *)w; m = sp->namep; k = key; /* Check for correct string and return */ for (cix = 0; *m && ISID(*k) && *m == *k; m++, k++, cix += CHECKBITS) ; if (*m == 0 && ISID(*k) == 0) { if (enterf != ENTER && sp->valoff == 0) return NULL; return sp; } if (enterf != ENTER) return NULL; /* no string found and do not enter */ ix = *m ^ *k; while ((ix & 1) == 0) ix >>= 1, cix++; /* Create new node */ new = gtree(); bit = P_BIT(key, cix); new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF); new->lr[bit] = (struct tree *)getsymtab(key); if (numsyms++ == 1) { new->lr[!bit] = sympole; new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF); sympole = new; return (struct symtab *)new->lr[bit]; } w = sympole; last = NULL; for (;;) { fbit = w->bitno; bitno = BITNO(w->bitno); if (bitno == cix) error("bitno == cix"); if (bitno > cix) break; svbit = P_BIT(key, bitno); last = w; w = w->lr[svbit]; if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF)) break; } new->lr[!bit] = w; if (last == NULL) { sympole = new; } else { last->lr[svbit] = new; last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF); } if (bitno < cix) new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF); return (struct symtab *)new->lr[bit]; } void * xmalloc(int sz) { usch *rv; if ((rv = (void *)malloc(sz)) == NULL) error("xmalloc: out of mem"); return rv; } void * xrealloc(void *p, int sz) { usch *rv; if ((rv = (void *)realloc(p, sz)) == NULL) error("xrealloc: out of mem"); return rv; } static usch * xstrdup(const usch *str) { usch *rv; if ((rv = (usch *)strdup((const char *)str)) == NULL) error("xstrdup: out of mem"); return rv; } pcc-20181216/cc/cpp/cpp.h010064400017500000000000000144061302101105100135530ustar raggewheel/* $Id: cpp.h,v 1.111 2016/12/04 12:55:05 ragge Exp $ */ /* * Copyright (c) 2004,2010 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include /* for debug/printf */ #if LIBVMF #include #endif typedef unsigned char usch; extern int trulvl; extern int flslvl; extern int elflvl; extern int elslvl; extern int dflag; extern int tflag, Aflag, Cflag, Pflag; extern int Mflag, dMflag, MPflag, MMDflag; extern char *Mfile, *MPfile; extern int defining, inclevel; /* args for lookup() */ #define FIND 0 #define ENTER 1 /* buffer used internally */ #if SIZEOF_INT_P == 2 || LIBVMF #define CPPL2 10 typedef unsigned short mvtyp; #else #define CPPL2 14 typedef unsigned int mvtyp; #endif #define CPPBUF (1 << CPPL2) #define VALPTR(x) ((x) & (CPPBUF-1)) #define VALBUF(x) ((x) >> CPPL2) #define MKVAL(b, c) (((b) << CPPL2) + (c)) #define MAXARGS 128 /* Max # of args to a macro. Should be enough */ #define MAXIDSZ 63 /* Max length of C99 identifier; 5.2.4.1 */ #define PBMAX 10 /* min pushbackbuffer size */ #define FUNLIKE 0 #define CTRLOC 1 /* __COUNTER__ */ #define DEFLOC 2 /* defined */ #define PRAGLOC 3 /* _Pragma */ #define LINLOC 4 /* __LINE__ */ #define FILLOC 5 /* __FILE__ */ #define OBJCT 6 #define VARG 7 /* has varargs */ /* The following must be > MAXARGS since they are following WARN */ #define C99ARG 253 /* C99 vararg */ #define GCCARG 254 /* gcc vararg that may be replaced with 0 */ #define WARN 1 /* SOH, not legal char */ #define CONC 2 /* STX, not legal char */ #define SNUFF 3 /* ETX, not legal char */ #define BLKID 4 /* EOT, not legal char */ /* Used in macro expansion */ #define RECMAX 10000 /* max # of recursive macros */ #define MKB(l,h) (l+((h)<<8)) /* quick checks for some characters */ #define C_SPEC 0001 /* for fastscan() parsing */ #define C_2 0002 /* for yylex() tokenizing */ #define C_WSNL 0004 /* ' ','\t','\r','\n' */ #define C_ID 0010 /* [_a-zA-Z0-9] */ #define C_ID0 0020 /* [_a-zA-Z] */ #define C_Q 0040 /* [\r\\\?] */ #define C_DIGIT 0100 /* [0-9] */ #define C_HEX 0200 /* [0-9a-fA-F] */ extern usch spechr[]; #define ISWSNL(x) (spechr[x] & (C_WSNL)) #define ISWS(x) ((x) == '\t' || (x) == ' ') #define ISID(x) (spechr[x] & C_ID) #define ISID0(x) (spechr[x] & C_ID0) #define ISDIGIT(x) (spechr[x] & C_DIGIT) #define ISCQ(x) (spechr[x] & C_Q) /* buffer definition */ #define BNORMAL 0 /* standard buffer */ #define BMAC 1 /* store macro definitions */ #define BINBUF 2 /* read data from input files */ #define BUTBUF 3 /* write data to stdout */ struct iobuf { usch *buf; int cptr; /* current pointer */ int bsz; /* bufsize */ int ro:1, inuse:1, type:4; }; struct iobuf *getobuf(int); void putob(struct iobuf *ob, int ch); void bufree(struct iobuf *iob); extern struct iobuf pb; #define curptr ib->cptr #define maxread ib->bsz #define buffer ib->buf+PBMAX #define bbuf ib->buf #if LIBVMF extern struct vspace ibspc, macspc; #endif /* * definition for include file info */ struct includ { struct includ *next; const usch *fname; /* current fn, changed if #line found */ const usch *orgfn; /* current fn, not changed */ int lineno; int escln; /* escaped newlines, to be added */ int infil; struct iobuf *ib; int idx; void *incs; const usch *fn; #if LIBVMF struct vseg *vseg; #endif }; #define INCINC 0 #define SYSINC 1 extern struct includ *ifiles; /* Symbol table entry */ struct symtab { const usch *namep; mvtyp valoff; const usch *file; int line; unsigned char type:4, /* macro type */ wraps:1; /* macro wraps in buffer */ unsigned char narg; /* # of args (if feasible) */ }; /* * Struct used in parse tree evaluation. * op is one of: * - number type (NUMBER, UNUMBER) * - zero (0) if divided by zero. */ struct nd { int op; union { long long val; unsigned long long uval; } n; }; extern struct nd yynode; #define nd_val n.val #define nd_uval n.uval enum { NUMBER = 257, UNUMBER, LS, RS, EQ, NE, STRING, WSPACE, CMNT, IDENT, OROR, ANDAND, DEFINED, LE, GE }; #define SLO_IGNOREWS 001 struct symtab *lookup(const usch *namep, int enterf); struct blocker; struct iobuf *submac(struct symtab *nl, int, struct iobuf *, struct blocker *); struct iobuf *kfind(struct symtab *nl); void ppdir(void); void define(void); void include(void); void include_next(void); void line(void); int pushfile(const usch *fname, const usch *fn, int idx, void *incs); void prtline(int nl); int yylex(void); void cunput(int); int yyparse(void); void putch(int); void putstr(const usch *s); usch *sheap(const char *fmt, ...); struct iobuf *bsheap(struct iobuf *, const char *fmt, ...); struct iobuf *strtobuf(const usch *str, struct iobuf *iob); struct iobuf *buftobuf(struct iobuf *in, struct iobuf *iob); void warning(const char *fmt, ...); void error(const char *fmt, ...); int cinput(void); int inc2(void); void Ccmnt2(struct iobuf *, int); usch *bufid(int ch, struct iobuf *); usch *readid(int ch); struct iobuf *faststr(int bc, struct iobuf *); int fastnum(int ch, struct iobuf *); void *xrealloc(void *p, int sz); void *xmalloc(int sz); void fastscan(void); void cntline(void); struct iobuf *savln(void); pcc-20181216/cc/cpp/cpy.y010064400017500000000000000142551234132173200136250ustar raggewheel/* $Id: cpy.y,v 1.21 2014/05/28 08:52:42 plunky Exp $ */ /* * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code and documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ %{ #include "config.h" #include "cpp.h" void yyerror(const char *); int setd(int l, int r); #define EVALUNARY(tok, l, r) l.nd_val = tok r.nd_val; l.op = r.op #define EVALBIN(tok, d, l, r) \ d.op = setd(l.op, r.op); d.nd_val = l.nd_val tok r.nd_val #define EVALUBIN(tok, d, l, r, t) \ d.op = setd(l.op, r.op); \ if (d.op == NUMBER) d.nd_val = l.nd_val tok r.nd_val; \ else d.nd_uval = l.nd_uval tok r.nd_uval; \ if (t && d.op) d.op = NUMBER #define XEVALUBIN(tok, d, l, r) \ if (r.nd_val) { EVALUBIN(tok, d, l, r, 0); } else d.op = 0 %} %term stop %term EQ NE LE GE LS RS %term ANDAND OROR IDENT NUMBER UNUMBER DEFINED /* * The following terminals are not used in the yacc code. */ %term STRING WSPACE CMNT %left ',' %right '?' ':' %left OROR %left ANDAND %left '|' '^' %left '&' %binary EQ NE %binary '<' '>' LE GE %left LS RS %left '+' '-' %left '*' '/' '%' %right '!' '~' UMINUS %left '(' %union { struct nd node; } %type term e NUMBER UNUMBER %% S: e '\n' { if ($1.op == 0) error("division by zero"); return $1.nd_val; } e: e '*' e { EVALUBIN(*, $$, $1, $3, 0); } | e '/' e { XEVALUBIN(/, $$, $1, $3); } | e '%' e { XEVALUBIN(%, $$, $1, $3); } | e '+' e { EVALBIN(+, $$, $1, $3); } | e '-' e { EVALBIN(-, $$, $1, $3); } | e LS e { EVALBIN(<<, $$, $1, $3); } | e RS e { EVALUBIN(>>, $$, $1, $3, 0); } | e '<' e { EVALUBIN(<, $$, $1, $3, 1); } | e '>' e { EVALUBIN(>, $$, $1, $3, 1); } | e LE e { EVALUBIN(<=, $$, $1, $3, 1); } | e GE e { EVALUBIN(>=, $$, $1, $3, 1); } | e EQ e { EVALUBIN(==, $$, $1, $3, 1); } | e NE e { EVALUBIN(!=, $$, $1, $3, 1); } | e '&' e { EVALBIN(&, $$, $1, $3); } | e '^' e { EVALBIN(^, $$, $1, $3); } | e '|' e { EVALBIN(|, $$, $1, $3); } | e ANDAND e { $$ = $1; if ($1.nd_val) { $$.op = setd($1.op, $3.op); $$.nd_val = ($3.nd_val != 0); } if ($$.op == UNUMBER) $$.op = NUMBER; } | e OROR e { if ($1.nd_val != 0) { $$.nd_val = ($1.nd_val != 0); $$.op = $1.op; } else { $$.nd_val = ($3.nd_val != 0); $$.op = setd($1.op, $3.op); } if ($$.op == UNUMBER) $$.op = NUMBER; } | e '?' e ':' e { if ($1.op == 0) $$ = $1; else if ($1.nd_val) $$ = $3; else $$ = $5; } | e ',' e { $$.op = setd($1.op, $3.op); $$.nd_val = $3.nd_val; if ($$.op) $$.op = $3.op; } | term {$$ = $1;} term: '-' term %prec UMINUS { EVALUNARY(-, $$, $2); } | '+' term %prec UMINUS {$$ = $2;} | '!' term { $$.nd_val = ! $2.nd_val; $$.op = $2.op ? NUMBER : 0; } | '~' term { EVALUNARY(~, $$, $2); } | '(' e ')' {$$ = $2;} | DEFINED '(' NUMBER ')' {$$= $3;} | DEFINED NUMBER {$$ = $2;} | NUMBER {$$ = $1;} %% void yyerror(const char *err) { error(err); } /* * Set return type of an expression. */ int setd(int l, int r) { if (!l || !r) return 0; /* div by zero involved */ if (l == UNUMBER || r == UNUMBER) return UNUMBER; return NUMBER; } pcc-20181216/cc/cpp/token.c010064400017500000000000000653671340424424600141430ustar raggewheel/* $Id: token.c,v 1.190 2018/12/12 17:43:02 ragge Exp $ */ /* * Copyright (c) 2004,2009 Anders Magnusson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Tokenizer for the C preprocessor. * There are three main routines: * - fastscan() loops over the input stream searching for magic * characters that may require actions. * - yylex() returns something from the input stream that * is suitable for yacc. * * Other functions of common use: * - inpch() returns a raw character from the current input stream. * - inch() is like inpch but \\n and trigraphs are expanded. * - unch() pushes back a character to the input stream. * * Input data can be read from either stdio or a buffer. * If a buffer is read, it will return EOF when ended and then jump back * to the previous buffer. * - setibuf(usch *ptr). Buffer to read from, until NULL, return EOF. * When EOF returned, pop buffer. * - setobuf(usch *ptr). Buffer to write to * * There are three places data is read: * - fastscan() which has a small loop that will scan over input data. * - flscan() where everything is skipped except directives (flslvl) * - inch() that everything else uses. * * 5.1.1.2 Translation phases: * 1) Convert UCN to UTF-8 which is what pcc uses internally (chkucn). * Remove \r (unwanted) * Convert trigraphs (chktg) * 2) Remove \\\n. Need extra care for identifiers and #line. * 3) Tokenize. * Remove comments (fastcmnt) */ #include "config.h" #include #include #ifdef HAVE_UNISTD_H #include #endif #include #include "compat.h" #include "cpp.h" static void cvtdig(usch **); static int dig2num(int); static int charcon(usch **); static void elsestmt(void); static void ifdefstmt(void); static void ifndefstmt(void); static void endifstmt(void); static void ifstmt(void); static void cpperror(void); static void cppwarning(void); static void undefstmt(void); static void pragmastmt(void); static void elifstmt(void); static void unch(int c); #define UNCH(ib, ch) ib->buf[--ib->cptr] = ch /* protection against recursion in #include */ #define MAX_INCLEVEL 100 int inclevel; int incmnt, instr; extern int skpows; struct includ *ifiles; static void ucn(int n); static void fastcmnt2(int); static int chktg2(int ch); /* some common special combos for init */ #define C_NL (C_SPEC|C_WSNL) #define C_DX (C_SPEC|C_ID|C_DIGIT|C_HEX) #define C_I (C_SPEC|C_ID|C_ID0) #define C_IX (C_SPEC|C_ID|C_ID0|C_HEX) usch spechr[256] = { C_SPEC|C_Q, 0, 0, 0, C_SPEC, C_SPEC, 0, 0, 0, C_WSNL, C_NL, 0, 0, C_WSNL|C_Q, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, C_WSNL, C_2, C_SPEC, 0, 0, 0, C_2, C_SPEC, 0, 0, 0, C_2, 0, C_2, 0, C_SPEC|C_Q, C_DX, C_DX, C_DX, C_DX, C_DX, C_DX, C_DX, C_DX, C_DX, C_DX, 0, 0, C_2, C_2, C_2, C_SPEC|C_Q, 0, C_IX, C_IX, C_IX, C_IX, C_IX, C_IX, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, 0, C_SPEC|C_Q, 0, 0, C_I, 0, C_IX, C_IX, C_IX, C_IX, C_IX, C_IX, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, 0, C_2, 0, 0, 0, /* utf-8 */ C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, C_I, }; /* * fill up the input buffer * n tells how nany chars at least. 0 == standard. * 0 if EOF, != 0 if something could fill up buf. */ static int inpbuf(int n) { struct iobuf *ib = ifiles->ib; int len, sz = 0; if (n > 0) { if (ib->bsz > ib->cptr + n) return 1; /* enough in buffer */ sz = ib->bsz - ib->cptr; memcpy(ib->buf+PBMAX - sz, ib->buf + ib->cptr, sz); } if (ifiles->infil == -1) return 0; len = (int)read(ifiles->infil, ib->buf+PBMAX, CPPBUF-PBMAX); if (len == -1) error("read error on file %s", ifiles->orgfn); if (len > 0) { ib->cptr = PBMAX - sz; ib->bsz = PBMAX + len; } return len + sz; } /* * Return a quick-cooked character. * If buffer empty; return 0. */ static int qcchar(void) { struct iobuf *ib = ifiles->ib; int ch; newone: do { if (ib->cptr < ib->bsz) { if (!ISCQ(ch = ib->buf[ib->cptr++])) return ch; break; } } while ((ch = inpbuf(0)) > 0); switch (ch) { case 0: return 0; /* end of file */ case '\r': goto newone; case '\\': if (ib->cptr == ib->bsz) inpbuf(0); switch (ch = ib->buf[ib->cptr]) { case 'u': case 'U': if (incmnt) return '\\'; ib->cptr++; ucn(ch == 'u' ? 4 : 8); break; case '\r': ib->cptr++; if (ib->cptr == ib->bsz) inpbuf(0); /* FALLTHROUGH */ case '\n': ib->cptr++; ifiles->escln++; break; default: return '\\'; } goto newone; case '?': inpbuf(2); if (ib->buf[ib->cptr] == '?') { if ((ch = chktg2(ib->buf[ib->cptr+1])) == 0) return '?'; ib->buf[++ib->cptr] = ch; goto newone; } return '?'; case '/': if (Cflag || incmnt || instr) return '/'; incmnt++; ch = qcchar(); incmnt--; if (ch == '/' || ch == '*') { int n = ifiles->lineno; fastcmnt2(ch); if (n == ifiles->lineno) return ' '; } else { ib->buf[--ib->cptr] = ch; return '/'; } goto newone; } error("ch error"); return 0; /* XXX */ } /* * push a character back to the input stream */ static void unch(int c) { if (c == -1) return; ifiles->ib->cptr--; if (ifiles->ib->cptr < 0) error("pushback buffer full"); ifiles->ib->buf[ifiles->ib->cptr] = (usch)c; } /* * Return trigraph mapping char or 0. */ static int chktg2(int ch) { switch (ch) { case '=': return '#'; case '(': return '['; case ')': return ']'; case '<': return '{'; case '>': return '}'; case '/': return '\\'; case '\'': return '^'; case '!': return '|'; case '-': return '~'; } return 0; } /* * deal with comments in the fast scanner. */ static void fastcmnt2(int ch) { int lastline = ifiles->lineno; incmnt = 1; if (ch == '/') { /* C++ comment */ while ((ch = qcchar()) != '\n') ; unch(ch); } else if (ch == '*') { for (;;) { if ((ch = qcchar()) == 0) break; if (ch == '*') { if ((ch = qcchar()) == '/') { break; } else unch(ch); } else if (ch == '\n') { putch('\n'); ifiles->lineno++; } } } else error("fastcmnt2"); if (ch == 0) error("comment at line %d never ends", lastline); incmnt = 0; } /* * check for universal-character-name on input, and * unput to the pushback buffer encoded as UTF-8. */ static void ucn(int n) { unsigned long cp, m; int ch; if (incmnt) { struct iobuf *ib = ifiles->ib; ib->cptr--; /* [uU] */ ib->buf[--ib->cptr] = '\\'; return; } cp = 0; while (n-- > 0) { if ((ch = qcchar()) == 0 || (spechr[ch] & C_HEX) == 0) { warning("invalid universal character name"); // XXX should actually unput the chars and return 0 unch(ch); // XXX eof break; } cp = cp * 16 + dig2num(ch); } if ((cp < 0xa0 && cp != 0x24 && cp != 0x40 && cp != 0x60) || (cp >= 0xd800 && cp <= 0xdfff)) /* 6.4.3.2 */ error("universal character name cannot be used"); if (cp > 0x7fffffff) error("universal character name out of range"); n = 0; m = 0x7f; while (cp > m) { unch(0x80 | (cp & 0x3f)); cp >>= 6; m >>= (n++ ? 1 : 2); } unch(((m << 1) ^ 0xfe) | cp); } /* * deal with comments when -C is active. * Save comments in expanded macros??? */ void Ccmnt2(struct iobuf *ob, int ch) { if (skpows) cntline(); if (ch == '/') { /* C++ comment */ putob(ob, ch); do { putob(ob, ch); } while ((ch = qcchar()) && ch != '\n'); unch(ch); } else if (ch == '*') { strtobuf((usch *)"/*", ob); for (;;) { ch = qcchar(); putob(ob, ch); if (ch == '*') { if ((ch = qcchar()) == '/') { putob(ob, ch); break; } else unch(ch); } else if (ch == '\n') { ifiles->lineno++; } } } } /* * Traverse over spaces and comments from the input stream, * Returns first non-space character. */ static int fastspc(void) { int ch; while ((ch = qcchar()), ISWS(ch)) ; return ch; } /* * readin chars and store in buf. Warn about too long names. */ usch * bufid(int ch, struct iobuf *ob) { int n = ob->cptr; do { if (ob->cptr - n == MAXIDSZ) warning("identifier exceeds C99 5.2.4.1"); if (ob->cptr < ob->bsz) ob->buf[ob->cptr++] = ch; else putob(ob, ch); } while (spechr[ch = qcchar()] & C_ID); ob->buf[ob->cptr] = 0; /* legal */ unch(ch); return ob->buf+n; } usch idbuf[MAXIDSZ+1]; /* * readin chars and store in buf. Warn about too long names. */ usch * readid(int ch) { int p = 0; do { if (p == MAXIDSZ) warning("identifier exceeds C99 5.2.4.1, truncating"); if (p < MAXIDSZ) idbuf[p] = ch; p++; } while (spechr[ch = qcchar()] & C_ID); idbuf[p] = 0; unch(ch); return idbuf; } /* * get a string or character constant and save it as given by d. */ struct iobuf * faststr(int bc, struct iobuf *ob) { struct iobuf *ib = ifiles->ib; int ch; if (ob == NULL) ob = getobuf(BNORMAL); instr = 1; putob(ob, bc); for (;;) { if (ib->bsz == ib->cptr) ch = qcchar(); else if (ISCQ(ch = ib->buf[ib->cptr])) ch = qcchar(); else ib->cptr++; switch (ch) { case '\\': putob(ob, ch); if (ib->cptr == ib->bsz) inpbuf(0); incmnt = 1; putob(ob, qcchar()); incmnt = 0; continue; case '\n': warning("unterminated literal"); instr = 0; unch(ch); return ob; } putob(ob, ch); if (ch == bc) break; } putob(ob, 0); ob->cptr--; instr = 0; return ob; } /* * get a preprocessing number and save it as given by ob. * returns first non-pp-number char. * We know that this is a valid number already. * * pp-number: digit * . digit * pp-number digit * pp-number identifier-nondigit * pp-number e sign * pp-number E sign * pp-number p sign * pp-number P sign * pp-number . */ int fastnum(int ch, struct iobuf *ob) { int c2; if ((spechr[ch] & C_DIGIT) == 0) { /* not digit, dot */ putob(ob, ch); ch = qcchar(); } for (;;) { putob(ob, ch); if ((ch = qcchar()) == 0) return 0; if ((c2 = (ch & 0337)) == 'E' || c2 == 'P') { if ((c2 = qcchar()) != '-' && c2 != '+') { if (c2 > 0) unch(c2); break; } putob(ob, ch); ch = c2; } else if (ch == '.' || (spechr[ch] & C_ID)) { continue; } else break; } return ch; } /* * Scan quickly the input file searching for: * - '#' directives * - keywords (if not flslvl) * - comments * * Handle strings, numbers and trigraphs with care. * Only data from pp files are scanned here, never any rescans. * This loop is always at trulvl. */ void fastscan(void) { struct iobuf *ob, rbs, *rb = &rbs; extern struct iobuf pb; struct iobuf *ib = ifiles->ib; struct symtab *nl; int ch, c2; usch *dp; #define IDSIZE 128 rb->buf = xmalloc(IDSIZE+1); rb->cptr = 0; rb->bsz = IDSIZE; goto run; for (;;) { /* tight loop to find special chars */ /* should use getchar/putchar here */ for (;;) { if (ib->cptr < ib->bsz) ch = ib->buf[ib->cptr++]; else ch = qcchar(); xloop: if (ch < 0) ch = 0; /* XXX */ if ((spechr[ch] & C_SPEC) != 0) break; putch(ch); } switch (ch) { case 0: free(rb->buf); return; case WARN: case CONC: error("bad char passed"); break; case '/': /* Comments */ incmnt++; ch = qcchar(); incmnt--; if (ch == '/' || ch == '*') { if (Cflag == 0) { int n = ifiles->lineno; fastcmnt2(ch); if (n == ifiles->lineno) putch(' '); /* 5.1.1.2 p3 */ } else Ccmnt2(&pb, ch); } else { putch('/'); goto xloop; } break; case '\n': /* newlines, for pp directives */ /* take care of leftover \n */ while (ifiles->escln > 0) { putch('\n'); ifiles->escln--; ifiles->lineno++; } putch('\n'); ifiles->lineno++; /* search for a # */ run: while ((ch = qcchar()) == '\t' || ch == ' ') putch(ch); if (ch == '%') { if ((c2 = qcchar()) != ':') unch(c2); else ch = '#'; } if (ch == '#') ppdir(); else goto xloop; break; case '?': if (ib->cptr+1 >= ib->bsz) inpbuf(2); if (ib->buf[ib->cptr] == '?') { ib->cptr++; if ((ch = chktg2(ib->buf[ib->cptr++]))) goto xloop; ib->cptr -= 2; } putch('?'); break; case '\'': /* character constant */ if (tflag) { putch(ch); break; /* character constants ignored */ } /* FALLTHROUGH */ case '\"': /* strings */ if (skpows) cntline(); faststr(ch, &pb); break; case '.': /* for pp-number */ if ((spechr[c2 = qcchar()] & C_DIGIT) == 0) { putch('.'); goto xloop; } unch(c2); case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (skpows) cntline(); ch = fastnum(ch, &pb); goto xloop; case 'L': case 'U': case 'u': if (ib->cptr+2 >= ib->bsz) inpbuf(2); if ((c2 = ib->buf[ib->cptr]) == '\"' || c2 == '\'') { putch(ch); break; } else if (c2 == '8' && ch == 'u' && ib->buf[ib->cptr+1] == '\"') { ib->cptr++; putstr((usch *)"u8"); break; } /* FALLTHROUGH */ default: #ifdef PCC_DEBUG if ((spechr[ch] & C_ID) == 0) error("fastscan"); #endif if (flslvl) error("fastscan flslvl"); rb->cptr = 0; dp = bufid(ch, rb); if ((nl = lookup(dp, FIND)) != NULL) { if ((ob = kfind(nl)) != NULL) { if (*ob->buf == '-' || *ob->buf == '+') putch(' '); if (skpows) cntline(); buftobuf(ob, &pb); if (ob->cptr > 0 && (ob->buf[ob->cptr-1] == '-' || ob->buf[ob->cptr-1] == '+')) putch(' '); bufree(ob); } } else { putstr(dp); } break; case '\\': ib->buf[--ib->cptr] = '\\'; if ((ch = qcchar()) != '\\') goto xloop; putch('\\'); break; } } } /* * Store an if/elif line on heap for parsing, evaluate macros and * call yyparse(). */ static usch *yyinp; int inexpr; static int exprline(void) { extern int nbufused; struct iobuf *ob, *rb; struct symtab *nl; int oCflag = Cflag; usch *dp; int c, d, ifdef; rb = getobuf(BNORMAL); nbufused--; Cflag = ifdef = 0; for (;;) { c = qcchar(); xloop: if (c == '\n') break; if (c == '.') { putob(rb, '.'); if ((spechr[c = qcchar()] & C_DIGIT) == 0) goto xloop; } if (ISDIGIT(c)) { c = fastnum(c, rb); goto xloop; } if (c == '\'' || c == '\"') { faststr(c, rb); continue; } if (c == 'L' || c == 'u' || c == 'U') { unch(d = qcchar()); if (d == '\'') /* discard wide designator */ continue; } if (ISID0(c)) { dp = readid(c); nl = lookup(dp, FIND); if (nl && nl->type == DEFLOC) { ifdef = 1; } else if (ifdef) { putob(rb, nl ? '1' : '0'); ifdef = 0; } else if (nl != NULL) { inexpr = 1; if ((ob = kfind(nl))) { ob->buf[ob->cptr] = 0; strtobuf(ob->buf, rb); bufree(ob); } else putob(rb, '0'); inexpr = 0; } else putob(rb, '0'); } else putob(rb, c); } rb->buf[rb->cptr] = 0; unch('\n'); yyinp = rb->buf; c = yyparse(); bufree(rb); nbufused++; Cflag = oCflag; return c; } int yylex(void) { int ch, c2, t; while ((ch = *yyinp++) == ' ' || ch == '\t') ; t = ISDIGIT(ch) ? NUMBER : ch; if (ch < 128 && (spechr[ch] & C_2)) c2 = *yyinp++; else c2 = 0; switch (t) { case 0: return WARN; case '=': if (c2 == '=') return EQ; break; case '!': if (c2 == '=') return NE; break; case '|': if (c2 == '|') return OROR; break; case '&': if (c2 == '&') return ANDAND; break; case '<': if (c2 == '<') return LS; if (c2 == '=') return LE; break; case '>': if (c2 == '>') return RS; if (c2 == '=') return GE; break; case '+': case '-': if (ch == c2) error("invalid preprocessor operator %c%c", ch, c2); break; case '\'': yynode.op = NUMBER; yynode.nd_val = charcon(&yyinp); return NUMBER; case NUMBER: cvtdig(&yyinp); return NUMBER; default: if (ISID0(t)) { yyinp--; while (ISID(*yyinp)) yyinp++; yynode.nd_val = 0; return NUMBER; } return ch; } yyinp--; return ch; } /* * A new file included. * If ifiles == NULL, this is the first file and already opened (stdin). * Return 0 on success, -1 if file to be included is not found. */ int pushfile(const usch *file, const usch *fn, int idx, void *incs) { struct includ ibuf; struct includ *ic; int otrulvl; ic = &ibuf; ic->next = ifiles; if (file != NULL) { if ((ic->infil = open((const char *)file, O_RDONLY)) < 0) return -1; ic->orgfn = ic->fname = file; if (++inclevel > MAX_INCLEVEL) error("limit for nested includes exceeded"); } else { ic->infil = 0; ic->orgfn = ic->fname = (const usch *)""; } #if LIBVMF if (ifiles) { vmmodify(ifiles->vseg); vmunlock(ifiles->vseg); } ic->vseg = vmmapseg(&ibspc, inclevel); vmlock(ic->vseg); #endif ifiles = ic; ic->ib = getobuf(BINBUF); ic->lineno = 1; ic->escln = 0; ic->maxread = ic->curptr; ic->idx = idx; ic->incs = incs; ic->fn = fn; prtline(1); otrulvl = trulvl; fastscan(); if (otrulvl != trulvl || flslvl) error("unterminated conditional"); ifiles = ic->next; inclevel--; #if LIBVMF vmmodify(ic->vseg); vmunlock(ic->vseg); ic->ib->ro = 1; /* XXX no free */ if (ifiles) { ifiles->vseg = vmmapseg(&ibspc, inclevel); vmlock(ifiles->vseg); ifiles->ib->buf = (usch *)ifiles->vseg->s_cinfo; } #endif close(ic->infil); bufree(ic->ib); return 0; } /* * Print current position to output file. */ void prtline(int nl) { struct iobuf *ob; if (Mflag) { if (dMflag) return; /* no output */ if (ifiles->lineno == 1 && (MMDflag == 0 || ifiles->idx != SYSINC)) { ob = bsheap(0, "%s: %s\n", Mfile, ifiles->fname); if (MPflag && strcmp((const char *)ifiles->fname, (char *)MPfile)) bsheap(ob, "%s:\n", ifiles->fname); write(1, ob->buf, ob->cptr); bufree(ob); } } else if (!Pflag) { skpows = 0; bsheap(&pb, "\n# %d \"%s\"", ifiles->lineno, ifiles->fname); if (ifiles->idx == SYSINC) strtobuf((usch *)" 3", &pb); if (nl) strtobuf((usch *)"\n", &pb); } } void cunput(int c) { #ifdef PCC_DEBUG // if (dflag)printf(": '%c'(%d)\n", c > 31 ? c : ' ', c); #endif unch(c); } static int dig2num(int c) { if (c >= 'a') c = c - 'a' + 10; else if (c >= 'A') c = c - 'A' + 10; else c = c - '0'; return c; } /* * Convert string numbers to unsigned long long and check overflow. */ static void cvtdig(usch **yyp) { unsigned long long rv = 0; unsigned long long rv2 = 0; usch *y = *yyp; int rad; y--; rad = *y != '0' ? 10 : y[1] == 'x' || y[1] == 'X' ? 16 : 8; if (rad == 16) y += 2; while ((spechr[*y] & C_HEX)) { rv = rv * rad + dig2num(*y); /* check overflow */ if (rv / rad < rv2) error("constant is out of range"); rv2 = rv; y++; } yynode.op = NUMBER; while (*y == 'l' || *y == 'L' || *y == 'u' || *y == 'U') { if (*y == 'u' || *y == 'U') yynode.op = UNUMBER; y++; } yynode.nd_uval = rv; if ((rad == 8 || rad == 16) && yynode.nd_val < 0) yynode.op = UNUMBER; if (yynode.op == NUMBER && yynode.nd_val < 0) /* too large for signed, see 6.4.4.1 */ error("constant is out of range"); *yyp = y; } static int charcon(usch **yyp) { int val, c; usch *p = *yyp; val = 0; if (*p++ == '\\') { switch (*p++) { case 'a': val = '\a'; break; case 'b': val = '\b'; break; case 'f': val = '\f'; break; case 'n': val = '\n'; break; case 'r': val = '\r'; break; case 't': val = '\t'; break; case 'v': val = '\v'; break; case '\"': val = '\"'; break; case '\'': val = '\''; break; case '\\': val = '\\'; break; case 'x': while ((spechr[c = *p] & C_HEX)) { val = val * 16 + dig2num(c); p++; } break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': p--; while ((spechr[c = *p] & C_DIGIT)) { val = val * 8 + (c - '0'); p++; } break; default: val = p[-1]; } } else val = p[-1]; if (*p != '\'') error("bad charcon"); *yyp = ++p; return val; } static void chknl(int ignore) { void (*f)(const char *, ...); int t; f = ignore ? warning : error; if ((t = fastspc()) != '\n') { if (t) { f("newline expected"); /* ignore rest of line */ while ((t = qcchar()) > 0 && t != '\n') ; } else f("no newline at end of file"); } unch(t); } static void elsestmt(void) { if (flslvl) { if (elflvl > trulvl) ; else if (--flslvl!=0) flslvl++; else trulvl++; } else if (trulvl) { flslvl++; trulvl--; } else error("#else in non-conditional section"); if (elslvl==trulvl+flslvl) error("too many #else"); elslvl=trulvl+flslvl; chknl(1); } static void ifdefstmt(void) { usch *bp; int ch; if (!ISID0(ch = fastspc())) error("bad #ifdef"); bp = readid(ch); if (lookup(bp, FIND) == NULL) flslvl++; else trulvl++; chknl(0); } static void ifndefstmt(void) { usch *bp; int ch; if (!ISID0(ch = fastspc())) error("bad #ifndef"); bp = readid(ch); if (lookup(bp, FIND) != NULL) flslvl++; else trulvl++; chknl(0); } static void endifstmt(void) { if (flslvl) flslvl--; else if (trulvl) trulvl--; else error("#endif in non-conditional section"); if (flslvl == 0) elflvl = 0; elslvl = 0; chknl(1); } static void ifstmt(void) { exprline() ? trulvl++ : flslvl++; } static void elifstmt(void) { if (flslvl == 0) elflvl = trulvl; if (flslvl) { if (elflvl > trulvl) ; else if (--flslvl!=0) flslvl++; else if (exprline()) trulvl++; else flslvl++; } else if (trulvl) { flslvl++; trulvl--; } else error("#elif in non-conditional section"); } /* save line into iobuf */ struct iobuf * savln(void) { struct iobuf *ob = getobuf(BNORMAL); int c; while ((c = qcchar()) != 0) { if (c == '\n') { unch(c); break; } putob(ob, c); } ob->buf[ob->cptr] = 0; return ob; } static void cpperror(void) { struct iobuf *ob = savln(); error("#error%s", ob->buf); bufree(ob); } static void cppwarning(void) { struct iobuf *ob = savln(); warning("#warning%s", ob->buf); bufree(ob); } static void undefstmt(void) { struct symtab *np; usch *bp; int ch; if (!ISID0(ch = fastspc())) error("bad #undef"); bp = readid(ch); if ((np = lookup(bp, FIND)) != NULL) np->valoff = 0; chknl(0); } static void identstmt(void) { struct iobuf *ob = NULL; struct symtab *sp; usch *bp; int ch; if (ISID0(ch = fastspc())) { bp = readid(ch); if ((sp = lookup(bp, FIND))) ob = kfind(sp); if (ob->buf[0] != '\"') goto bad; if (ob) bufree(ob); } else if (ch == '\"') { bufree(faststr(ch, NULL)); } else goto bad; chknl(1); return; bad: error("bad #ident directive"); } static void pragmastmt(void) { int ch; putstr((const usch *)"\n#pragma"); while ((ch = qcchar()) != '\n' && ch > 0) putch(ch); unch(ch); prtline(1); } int cinput(void) { return qcchar(); } #define DIR_FLSLVL 001 #define DIR_FLSINC 002 static struct { const char *name; void (*fun)(void); int flags; } ppd[] = { { "ifndef", ifndefstmt, DIR_FLSINC }, { "ifdef", ifdefstmt, DIR_FLSINC }, { "if", ifstmt, DIR_FLSINC }, { "include", include, 0 }, { "else", elsestmt, DIR_FLSLVL }, { "endif", endifstmt, DIR_FLSLVL }, { "error", cpperror, 0 }, { "warning", cppwarning, 0 }, { "define", define, 0 }, { "undef", undefstmt, 0 }, { "line", line, 0 }, { "pragma", pragmastmt, 0 }, { "elif", elifstmt, DIR_FLSLVL }, { "ident", identstmt, 0 }, #ifdef GCC_COMPAT { "include_next", include_next, 0 }, #endif }; #define NPPD (int)(sizeof(ppd) / sizeof(ppd[0])) static void skpln(void) { int ch; /* just ignore the rest of the line */ while ((ch = qcchar()) != 0) { if (ch == '\n') { unch('\n'); break; } } } /* * do an even faster scan than fastscan while at flslvl. * just search for a new directive. */ static void flscan(void) { int ch; for (;;) { ch = qcchar(); again: switch (ch) { case 0: return; case '\n': putch('\n'); ifiles->lineno++; while ((ch = qcchar()) == ' ' || ch == '\t') ; if (ch == '#') return; if (ch == '%' && (ch = qcchar()) == ':') return; goto again; case '\'': while ((ch = qcchar()) != '\'') { if (ch == '\\') qcchar(); if (ch == '\n') return; } break; case '\"': instr = 1; while ((ch = qcchar()) != '\"') { switch (ch) { case '\\': incmnt = 1; qcchar(); incmnt = 0; break; case '\n': unch(ch); /* FALLTHROUGH */ case 0: instr = 0; return; } } instr = 0; break; case '/': ch = qcchar(); if (ch == '/' || ch == '*') fastcmnt2(ch); goto again; } } } /* * Handle a preprocessor directive. * # is already found. */ void ppdir(void) { int ch, i, oldC; usch *bp; oldC = Cflag; redo: Cflag = 0; if ((ch = fastspc()) == '\n') { /* empty directive */ unch(ch); Cflag = oldC; return; } Cflag = oldC; if ((spechr[ch] & C_ID0) == 0) goto out; bp = readid(ch); /* got some keyword */ for (i = 0; i < NPPD; i++) { if (bp[0] == ppd[i].name[0] && strcmp((char *)bp, ppd[i].name) == 0) { if (flslvl == 0) { (*ppd[i].fun)(); if (flslvl == 0) return; } else { if (ppd[i].flags & DIR_FLSLVL) { (*ppd[i].fun)(); if (flslvl == 0) return; } else if (ppd[i].flags & DIR_FLSINC) flslvl++; } flscan(); goto redo; } } if (flslvl == 0) { if (Aflag) skpln(); return; } flscan(); goto redo; out: if (flslvl == 0 && Aflag == 0) error("invalid preprocessor directive"); unch(ch); skpln(); } pcc-20181216/cc/cpp/tests004075500017500000000000000000001340533064100137205ustar raggewheelpcc-20181216/cc/cpp/tests/CVS004075500017500000000000000000001340533064100143535ustar raggewheelpcc-20181216/cc/cpp/tests/CVS/Root010064400017500000000000000000111340533064100152650ustar raggewheel/cvsroot pcc-20181216/cc/cpp/tests/CVS/Repository010064400017500000000000000000211340533064100165220ustar raggewheelpcc/cc/cpp/tests pcc-20181216/cc/cpp/tests/CVS/Entries010064400017500000000000000030351340533064100157640ustar raggewheel/res1/1.4/Tue Aug 9 17:39:30 2016// /res10/1.1/Sat Dec 18 15:22:13 2010// /res11/1.4/Tue Aug 9 17:39:30 2016// /res12/1.3/Tue Aug 9 17:39:30 2016// /res13/1.2/Tue Aug 9 17:39:30 2016// /res14/1.3/Mon Feb 27 19:34:47 2017// /res15/1.2/Fri May 1 13:39:37 2015// /res15C/1.1/Wed Sep 26 18:30:11 2012// /res16/1.6/Tue Aug 9 17:39:30 2016// /res16C/1.5/Sat Oct 15 09:12:38 2016// /res17/1.3/Tue Aug 9 17:39:30 2016// /res18/1.2/Fri Nov 21 22:49:56 2014// /res2/1.7/Tue Aug 9 17:39:30 2016// /res3/1.7/Sat Oct 15 09:12:38 2016// /res4/1.2/Fri Nov 5 15:54:49 2010// /res5/1.3/Tue Aug 9 17:39:30 2016// /res6/1.3/Fri Jul 27 16:07:31 2012// /res7/1.3/Fri Nov 5 15:54:49 2010// /res8/1.3/Tue Aug 9 17:39:30 2016// /res9/1.2/Fri Nov 5 15:54:49 2010// /test1/1.1/Sun Jul 30 12:12:07 2006// /test10/1.1/Sat Dec 18 15:22:13 2010// /test11/1.1/Sun Jan 9 15:21:34 2011// /test12/1.1/Sun Jan 9 15:21:34 2011// /test13/1.1/Sun Jan 16 11:59:09 2011// /test14/1.2/Mon Feb 27 19:34:47 2017// /test15/1.1/Wed Sep 26 18:30:11 2012// /test16/1.2/Wed Nov 7 09:59:45 2012// /test17/1.2/Wed Aug 19 12:08:08 2015// /test18/1.2/Fri Nov 21 22:49:56 2014// /test19/1.1/Sat Feb 6 09:43:17 2016// /test2/1.1/Sun Jul 30 12:12:07 2006// /test20/1.1/Fri Jun 23 09:59:35 2017// /test21/1.1/Sat Jun 24 16:28:23 2017// /test3/1.1/Sun Jul 30 12:12:07 2006// /test4/1.1/Sun Jul 30 12:12:07 2006// /test5/1.1/Sun Jul 30 12:12:07 2006// /test6/1.1/Sat Oct 7 09:13:04 2006// /test7/1.1/Sat Oct 7 09:13:04 2006// /test8/1.1/Sat Oct 7 09:13:04 2006// /test9/1.1/Tue Jan 2 19:49:02 2007// D pcc-20181216/cc/cpp/tests/res1010064400017500000000000000000521275241252200145710ustar raggewheel # 1 "" char p[] = "x ## y"; pcc-20181216/cc/cpp/tests/res10010064400017500000000000000000721150315064500146510ustar raggewheel # 1 "" int midiopen(int); foo_optarg pcc-20181216/cc/cpp/tests/res11010064400017500000000000000001241275241252200146520ustar raggewheel # 1 "" a a b a b c a b c d __attribute__((__noreturn__)) 1 2 pcc-20181216/cc/cpp/tests/res12010064400017500000000000000064561275241252200146710ustar raggewheel # 1 "" 2 2 2 2 2; # 19 "" (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, (0 + 8) + 0, pcc-20181216/cc/cpp/tests/res13010064400017500000000000000000301275241252200146500ustar raggewheel # 1 "" long pcc-20181216/cc/cpp/tests/res14010064400017500000000000000001121305507752700146630ustar raggewheel # 1 "" AB i1(c) q p B(22,(foof bar kaka)); notable; pcc-20181216/cc/cpp/tests/res15010064400017500000000000000003121252070103100146420ustar raggewheel # 1 "" do { _foo_X (); } while ( 0); do { _foo_Y (); } while ( 0); do { _foo_(); } while ( 0); (111 FIRST 111); (222 SECOND 222); (111 (222 THIRD 222) 111); (222 (111 FOURTH 111) 222); pcc-20181216/cc/cpp/tests/res15C010064400017500000000000000004661203064466300147740ustar raggewheel # 1 "" do { _foo_X (); } while (/* CONSTCOND */0); do { _foo_Y (); } while (/* CONSTCOND */0); do { _foo_(); } while (/* CONSTCOND */0); (111 /*LINTED*/ FIRST 111); (222 SECOND /*LINTED*/ 222); (111 /*LINTED*/ (222 THIRD /*LINTED*/ 222) 111); (222 (111 /*LINTED*/ FOURTH 111) /*LINTED*/ 222); pcc-20181216/cc/cpp/tests/res16010064400017500000000000000015061275241252200146640ustar raggewheel # 1 "" This file is testing line counting in various scenarios involving escaped newlines, including using the trigraph escape sequence --> 4 4 "multi-line string" --> 8 8 'multi-line character constant' --> 12 12 multi-line 012345678 integer constant --> 17 17 multi-line list of tokens --> 24 24 --> 28 28 --> 36 36 --> 40 40 --> 48 48 #pragma multi-line #pragma directive # 49 "" --> 52 52 --> 57 57 multi-line macro embedded --> 59 59 --> 64 64 macro with a leading comment --> 66 66 --> 70 70 macro with leading whitespace and escaped newlines --> 72 72 a token split by escaped newlines --> 77 77 #pragma multi-line #pragma inside if-true block # 84 "" --> 87 87 --> 89 89 #pragma with a preceding comment # 90 "" --> 91 91 --> 97 97 pcc-20181216/cc/cpp/tests/res16C010064400017500000000000000020711300037140600147550ustar raggewheel # 1 "" This file is testing line counting in various scenarios involving escaped newlines, including using the trigraph escape sequence --> 4 4 "multi-line string" --> 8 8 'multi-line character constant' --> 12 12 multi-line 012345678 integer constant --> 17 17 multi-line list of tokens --> 24 24 /* multi-line comment */ --> 28 28 /*/ comment with escaped newlines /* in the markers */ --> 36 36 // multi-line C++ comment --> 40 40 // C++ comment with leading whitespace and escaped newlines --> 48 48 #pragma multi-line #pragma directive # 49 "" --> 52 52 --> 57 57 multi-line macro /* with a comment */ embedded --> 59 59 /* comment before directive */ #define BAR macro with a leading comment --> 64 64 BAR --> 66 66 --> 70 70 macro with leading whitespace and escaped newlines --> 72 72 a token split by escaped newlines --> 77 77 #pragma multi-line #pragma inside if-true block # 84 "" --> 87 87 --> 89 89 /* comment */ # pragma with a preceding comment --> 91 91 --> 97 97 pcc-20181216/cc/cpp/tests/res17010064400017500000000000000002561275241252200146660ustar raggewheel # 1 "" testing that pp-numbers are parsed correctly 123.4e+foo 123.4f+FOO 123.4e+foo 123.4e+foo FOO.123.foo.456+FOO+789.foo 0xfaff 0xfe00 0xfeff pcc-20181216/cc/cpp/tests/res18010064400017500000000000000002031243374062400146620ustar raggewheel # 1 "" "foo" "\"foo\"" "\"foo\\n\"" "\"\\\"foo\\\"\"" "\"foo\\\\\"" "\"\\\\\\\"foo\"" "\"foo\\\\\\\\\"" "foo\n" "foo\\n" pcc-20181216/cc/cpp/tests/res2010064400017500000000000000003231275241252200145730ustar raggewheel # 1 "" # 15 "" f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1); f(2 * (2+(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1)) ^m(0,1); int i[] = { 1, 23, 4, 5, }; char c[2][6] = { "hello", "" }; pcc-20181216/cc/cpp/tests/res3010064400017500000000000000002651300037140600145710ustar raggewheel # 1 "" printf("x" "1" "= %d, x" "2" "= %s", x1, x2); fputs("strncmp(\"abc\\0d\", \"abc\", '\\4') == 0" ": @\n", s); \#include "vers2.h" "hello"; "hello" ", world" pcc-20181216/cc/cpp/tests/res4010064400017500000000000000000261146502431100145700ustar raggewheel # 1 "" (1) pcc-20181216/cc/cpp/tests/res5010064400017500000000000000000751275241252200146020ustar raggewheel # 1 "" int j[] = { 123, 45, 67, 89, 10, 11, 12, }; pcc-20181216/cc/cpp/tests/res6010064400017500000000000000000271200453630300145720ustar raggewheel # 1 "" foo pcc-20181216/cc/cpp/tests/res7010064400017500000000000000000271146502431100145740ustar raggewheel # 1 "" a YES pcc-20181216/cc/cpp/tests/res8010064400017500000000000000000451275241252200146020ustar raggewheel # 1 "" (hej.s_s.s_pos) pcc-20181216/cc/cpp/tests/res9010064400017500000000000000000251146502431100145740ustar raggewheel # 1 "" ao pcc-20181216/cc/cpp/tests/test1010064400017500000000000000002751046312102700147600ustar raggewheel#define hash_hash # ## # #define mkstr(a) # a #define in_between(a) mkstr(a) #define join(c, d) in_between(c hash_hash d) char p[] = join(x, y); // equivalent to // char p[] = "x ## y"; pcc-20181216/cc/cpp/tests/test10010064400017500000000000000006341150315064500150430ustar raggewheel#define __CONCAT(x,y) x ## y #define dev_type_open(n) int n(int) #define dev_decl(n,t) __CONCAT(dev_type_,t)(__CONCAT(n,t)) #define cdev_decl(n) dev_decl(n,open) cdev_decl(midi); # define __GETOPT_PREFIX foo_ # define __GETOPT_CONCAT(x, y) x ## y # define __GETOPT_XCONCAT(x, y) __GETOPT_CONCAT (x, y) # define __GETOPT_ID(y) __GETOPT_XCONCAT (__GETOPT_PREFIX, y) # define optarg __GETOPT_ID (optarg) optarg pcc-20181216/cc/cpp/tests/test11010064400017500000000000000007071151235117600150470ustar raggewheel#define D1(s, ...) s #define D2(s, ...) s D1(__VA_ARGS__) #define D3(s, ...) s D2(__VA_ARGS__) #define D4(s, ...) s D3(__VA_ARGS__) D1(a) D2(a, b) D3(a, b, c) D4(a, b, c, d) #define __sun_attr___noreturn__ __attribute__((__noreturn__)) #define ___sun_attr_inner(__a) __sun_attr_##__a #define __sun_attr__(__a) ___sun_attr_inner __a #define __NORETURN __sun_attr__((__noreturn__)) __NORETURN #define X(...) #define Y(...) 1 __VA_ARGS__ 2 Y(X X() ()) pcc-20181216/cc/cpp/tests/test12010064400017500000000000000010371151235117600150450ustar raggewheel#define y 2 #define fe(p) sfe(p) p #define sfe(p) p #define Y fe(y) y fe(y) Y; # define S2B_QMIN 0 # define S2B_CMIN (S2B_QMIN + 8) #define S2B_1(i) i, #define S2B_2(i) S2B_1(i) S2B_1(i) #define S2B_4(i) S2B_2(i) S2B_2(i) #define S2B_8(i) S2B_4(i) S2B_4(i) #define S2B_16(i) S2B_8(i) S2B_8(i) #define S2B_32(i) S2B_16(i) S2B_16(i) #define S2B_64(i) S2B_32(i) S2B_32(i) #define S2B_128(i) S2B_64(i) S2B_64(i) #define S2B_256(i) S2B_128(i) S2B_128(i) S2B_256(S2B_CMIN + 0) pcc-20181216/cc/cpp/tests/test13010064400017500000000000000001611151455661500150520ustar raggewheel #define UL long, foo #define D(I,F) I #define E(I) D(I) E(UL) #define FOO 1 #if (FOO == 1) #endif /* FOO */ pcc-20181216/cc/cpp/tests/test14010064400017500000000000000003071305507752700150570ustar raggewheel#define A(x) A ## x #define AB A(B) AB #define i1(w) i2(w) p #define i2(x) i1(x) q i1(c) #undef A #define A(x,y) B(x,y) A(22,(foof bar kaka)); #define CONCAT(a, b) a ## b CONCAT(not, able); pcc-20181216/cc/cpp/tests/test15010064400017500000000000000004441203064466300150530ustar raggewheel#define FOO(x) do { _foo_ ## x (); } while (/* CONSTCOND */0) FOO(X); #define BAR FOO(Y) BAR; #define BAZ do { _foo_(); } while (/* CONSTCOND */0) BAZ; #define foo(a) (111 /*LINTED*/ a 111) #define bar(a) (222 a /*LINTED*/ 222) foo(FIRST); bar(SECOND); foo(bar(THIRD)); bar(foo(FOURTH)); pcc-20181216/cc/cpp/tests/test16010064400017500000000000000026221204643042100150440ustar raggewheelThis file is testing line counting in various scenarios involving escaped newlines, including using the trigraph escape sequence --> __LINE__ 4 "multi-\ line ??/ string" --> __LINE__ 8 'multi-\ line ??/ character constant' --> __LINE__ 12 multi-\ line 012\ 345??/ 678 integer constant --> __LINE__ 17 multi-\ line\ li??/ st ??/ of \ tokens --> __LINE__ 24 /* multi-\ line ??/ comment */ --> __LINE__ 28 /\ ??/ */ comment with escaped newlines /* in the markers ??/ *\ / --> __LINE__ 36 // multi-\ line ??/ C++ comment --> __LINE__ 40 \ \ /\ ??/ \ / ??/ C++ comment with leading whitespace and escaped newlines --> __LINE__ 48 #pragma multi-\ line ??/ #pragma directive --> __LINE__ 52 #define FOO multi-\ line macro /* with\ a comment *??/ / embedded --> __LINE__ 57 FOO --> __LINE__ 59 /??/ * comment \ before ??/ directive */ #define BAR macro with a leading comment --> __LINE__ 64 BAR --> __LINE__ 66 \ ??/ #define BAZ macro with leading whitespace and escaped newlines --> __LINE__ 70 BAZ --> __LINE__ 72 #define POTATO a token split by escaped newlines PO\ TA??/ TO --> __LINE__ 77 #if 0 #pragma multi-??/ line \ #pragma inside if-false block --> __LINE__ 82 #else #pragma multi-??/ line \ #pragma inside if-true block --> __LINE__ 87 #endif --> __LINE__ 89 /* comment */ # pragma with a preceding comment --> __LINE__ 91 #if 0 /* multi-\ * line comment at flslvl=1 */ #endif --> __LINE__ 97 pcc-20181216/cc/cpp/tests/test17010064400017500000000000000004051256507065000150540ustar raggewheeltesting that pp-numbers are parsed correctly #define e E #define f F #define foo FOO 123.4e+foo 123.4f+foo 12\ 3.4\ e\ +\ foo 123??/ .4??/ e??/ +??/ foo foo.123.foo.456+foo+789.foo #if 0xfaff 0xfaff #endif #if 0xfe00 0xfe00 #endif #if 0xfeff 0xfeff #endif pcc-20181216/cc/cpp/tests/test18010064400017500000000000000002051243374062400150520ustar raggewheel#define str(a) #a str(foo) str("foo") str("foo\n") str("\"foo\"") str("foo\\") str("\\\"foo") str("foo\\\\") str(foo\n) str(foo\\n) pcc-20181216/cc/cpp/tests/test19010064400017500000000000000006251265534006500150620ustar raggewheel#define S(x) S0(x) #define S0(x) #x #define T(x,y)\ S(x)\ S(y) #define T0(x,y)\ S0(x)\ S0(y) #define U(x)\ S(x)\ S(x) #define U0(x)\ S0(x)\ S0(x) #define V(x)\ V_(x)\ V_(x) #define V_(x)\ S(x) #define V0(x)\ V0_(x)\ V0_(x) #define V0_(x)\ S0(x) __COUNTER__ S(__COUNTER__) S0(__COUNTER__) T(__COUNTER__,__COUNTER__) T0(__COUNTER__,__COUNTER__) U(__COUNTER__) U0(__COUNTER__) V(__COUNTER__) V0(__COUNTER__) pcc-20181216/cc/cpp/tests/test2010064400017500000000000000010771046312102700147620ustar raggewheel#define x 3 #define f(a) f(x * (a)) #undef x #define x 2 #define g f #define z z[0] #define h g(~ #define m(a) a(w) #define w 0,1 #define t(a) a #define p() int #define q(x) x #define r(x,y) x ## y #define str(x) # x f(y+1) + f(f(z)) % t(t(g)(0) + t)(1); g(x+(3,4)-w) | h 5) & m (f)^m(m); p() i[q()] = { q(1), r(2,3), r(4,), r(,5), r(,) }; char c[2][6] = { str(hello), str() }; /* * f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1); * f(2 * (2+(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1); * int i[] = { 1, 23, 4, 5, }; * char c[2][6] = { "hello", "" }; */ pcc-20181216/cc/cpp/tests/test20010064400017500000000000000161651312316320700150500ustar raggewheel#ifndef FOREACH_H #define FOREACH_H #define _CONCAT(a, b) a##b #define CONCAT(a, b) _CONCAT(a, b) #define CONCAT2(a, b) _CONCAT(a, b) #define _CONCAT3(a, b, c) a##b##c #define CONCAT3(a, b, c) _CONCAT3(a, b, c) #define _CONCAT4(a, b, c, d) a##b##c##d #define CONCAT4(a, b, c, d) _CONCAT4(a, b, c, d) #define EXPAND(x) x #define _COUNT_ARGS( _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, _35, _36, _37, _38, _39, _40, \ _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \ _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, \ _61, _62, _63, _64, N, ...) N #define COUNT_ARGS(...) \ _COUNT_ARGS(__VA_ARGS__, 64, 63, 62, 61, 60, \ 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, \ 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, \ 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, \ 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, \ 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, \ 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) #define FOR_EACH_1(func, x) \ func(x) #define FOR_EACH_2(func, x, ...) \ func(x), EXPAND(FOR_EACH_1(func, __VA_ARGS__)) #define FOR_EACH_3(func, x, ...) \ func(x), EXPAND(FOR_EACH_2(func, __VA_ARGS__)) #define FOR_EACH_4(func, x, ...) \ func(x), EXPAND(FOR_EACH_3(func, __VA_ARGS__)) #define FOR_EACH_5(func, x, ...) \ func(x), EXPAND(FOR_EACH_4(func, __VA_ARGS__)) #define FOR_EACH_6(func, x, ...) \ func(x), EXPAND(FOR_EACH_5(func, __VA_ARGS__)) #define FOR_EACH_7(func, x, ...) \ func(x), EXPAND(FOR_EACH_6(func, __VA_ARGS__)) #define FOR_EACH_8(func, x, ...) \ func(x), EXPAND(FOR_EACH_7(func, __VA_ARGS__)) #define FOR_EACH_9(func, x, ...) \ func(x), EXPAND(FOR_EACH_8(func, __VA_ARGS__)) #define FOR_EACH_10(func, x, ...) \ func(x), EXPAND(FOR_EACH_9(func, __VA_ARGS__)) #define FOR_EACH_11(func, x, ...) \ func(x), EXPAND(FOR_EACH_10(func, __VA_ARGS__)) #define FOR_EACH_12(func, x, ...) \ func(x), EXPAND(FOR_EACH_11(func, __VA_ARGS__)) #define FOR_EACH_13(func, x, ...) \ func(x), EXPAND(FOR_EACH_12(func, __VA_ARGS__)) #define FOR_EACH_14(func, x, ...) \ func(x), EXPAND(FOR_EACH_13(func, __VA_ARGS__)) #define FOR_EACH_15(func, x, ...) \ func(x), EXPAND(FOR_EACH_14(func, __VA_ARGS__)) #define FOR_EACH_16(func, x, ...) \ func(x), EXPAND(FOR_EACH_15(func, __VA_ARGS__)) #define FOR_EACH_17(func, x, ...) \ func(x), EXPAND(FOR_EACH_16(func, __VA_ARGS__)) #define FOR_EACH_18(func, x, ...) \ func(x), EXPAND(FOR_EACH_17(func, __VA_ARGS__)) #define FOR_EACH_19(func, x, ...) \ func(x), EXPAND(FOR_EACH_18(func, __VA_ARGS__)) #define FOR_EACH_20(func, x, ...) \ func(x), EXPAND(FOR_EACH_19(func, __VA_ARGS__)) #define FOR_EACH_21(func, x, ...) \ func(x), EXPAND(FOR_EACH_20(func, __VA_ARGS__)) #define FOR_EACH_22(func, x, ...) \ func(x), EXPAND(FOR_EACH_21(func, __VA_ARGS__)) #define FOR_EACH_23(func, x, ...) \ func(x), EXPAND(FOR_EACH_22(func, __VA_ARGS__)) #define FOR_EACH_24(func, x, ...) \ func(x), EXPAND(FOR_EACH_23(func, __VA_ARGS__)) #define FOR_EACH_25(func, x, ...) \ func(x), EXPAND(FOR_EACH_24(func, __VA_ARGS__)) #define FOR_EACH_26(func, x, ...) \ func(x), EXPAND(FOR_EACH_25(func, __VA_ARGS__)) #define FOR_EACH_27(func, x, ...) \ func(x), EXPAND(FOR_EACH_26(func, __VA_ARGS__)) #define FOR_EACH_28(func, x, ...) \ func(x), EXPAND(FOR_EACH_27(func, __VA_ARGS__)) #define FOR_EACH_29(func, x, ...) \ func(x), EXPAND(FOR_EACH_28(func, __VA_ARGS__)) #define FOR_EACH_30(func, x, ...) \ func(x), EXPAND(FOR_EACH_29(func, __VA_ARGS__)) #define FOR_EACH_31(func, x, ...) \ func(x), EXPAND(FOR_EACH_30(func, __VA_ARGS__)) #define FOR_EACH_32(func, x, ...) \ func(x), EXPAND(FOR_EACH_31(func, __VA_ARGS__)) #define FOR_EACH_33(func, x, ...) \ func(x), EXPAND(FOR_EACH_32(func, __VA_ARGS__)) #define FOR_EACH_34(func, x, ...) \ func(x), EXPAND(FOR_EACH_33(func, __VA_ARGS__)) #define FOR_EACH_35(func, x, ...) \ func(x), EXPAND(FOR_EACH_34(func, __VA_ARGS__)) #define FOR_EACH_36(func, x, ...) \ func(x), EXPAND(FOR_EACH_35(func, __VA_ARGS__)) #define FOR_EACH_37(func, x, ...) \ func(x), EXPAND(FOR_EACH_36(func, __VA_ARGS__)) #define FOR_EACH_38(func, x, ...) \ func(x), EXPAND(FOR_EACH_37(func, __VA_ARGS__)) #define FOR_EACH_39(func, x, ...) \ func(x), EXPAND(FOR_EACH_38(func, __VA_ARGS__)) #define FOR_EACH_40(func, x, ...) \ func(x), EXPAND(FOR_EACH_39(func, __VA_ARGS__)) #define FOR_EACH_41(func, x, ...) \ func(x), EXPAND(FOR_EACH_40(func, __VA_ARGS__)) #define FOR_EACH_42(func, x, ...) \ func(x), EXPAND(FOR_EACH_41(func, __VA_ARGS__)) #define FOR_EACH_43(func, x, ...) \ func(x), EXPAND(FOR_EACH_42(func, __VA_ARGS__)) #define FOR_EACH_44(func, x, ...) \ func(x), EXPAND(FOR_EACH_43(func, __VA_ARGS__)) #define FOR_EACH_45(func, x, ...) \ func(x), EXPAND(FOR_EACH_44(func, __VA_ARGS__)) #define FOR_EACH_46(func, x, ...) \ func(x), EXPAND(FOR_EACH_45(func, __VA_ARGS__)) #define FOR_EACH_47(func, x, ...) \ func(x), EXPAND(FOR_EACH_46(func, __VA_ARGS__)) #define FOR_EACH_48(func, x, ...) \ func(x), EXPAND(FOR_EACH_47(func, __VA_ARGS__)) #define FOR_EACH_49(func, x, ...) \ func(x), EXPAND(FOR_EACH_48(func, __VA_ARGS__)) #define FOR_EACH_50(func, x, ...) \ func(x), EXPAND(FOR_EACH_49(func, __VA_ARGS__)) #define FOR_EACH_51(func, x, ...) \ func(x), EXPAND(FOR_EACH_50(func, __VA_ARGS__)) #define FOR_EACH_52(func, x, ...) \ func(x), EXPAND(FOR_EACH_51(func, __VA_ARGS__)) #define FOR_EACH_53(func, x, ...) \ func(x), EXPAND(FOR_EACH_52(func, __VA_ARGS__)) #define FOR_EACH_54(func, x, ...) \ func(x), EXPAND(FOR_EACH_53(func, __VA_ARGS__)) #define FOR_EACH_55(func, x, ...) \ func(x), EXPAND(FOR_EACH_54(func, __VA_ARGS__)) #define FOR_EACH_56(func, x, ...) \ func(x), EXPAND(FOR_EACH_55(func, __VA_ARGS__)) #define FOR_EACH_57(func, x, ...) \ func(x), EXPAND(FOR_EACH_56(func, __VA_ARGS__)) #define FOR_EACH_58(func, x, ...) \ func(x), EXPAND(FOR_EACH_57(func, __VA_ARGS__)) #define FOR_EACH_59(func, x, ...) \ func(x), EXPAND(FOR_EACH_58(func, __VA_ARGS__)) #define FOR_EACH_60(func, x, ...) \ func(x), EXPAND(FOR_EACH_59(func, __VA_ARGS__)) #define FOR_EACH_61(func, x, ...) \ func(x), EXPAND(FOR_EACH_60(func, __VA_ARGS__)) #define FOR_EACH_62(func, x, ...) \ func(x), EXPAND(FOR_EACH_61(func, __VA_ARGS__)) #define FOR_EACH_63(func, x, ...) \ func(x), EXPAND(FOR_EACH_62(func, __VA_ARGS__)) #define FOR_EACH_64(func, x, ...) \ func(x), EXPAND(FOR_EACH_63(func, __VA_ARGS__)) #define FOR_EACH(func, ...) \ EXPAND(CONCAT(FOR_EACH_, COUNT_ARGS(__VA_ARGS__))(func, __VA_ARGS__)) #endif #define SQ(x) (x * x) int squares[] = FOR_EACH(SQ, 1, 2, 3, 4, 5, 6, 7, 8); pcc-20181216/cc/cpp/tests/test21010064400017500000000000000007571312351144700150540ustar raggewheel #define __makestr(x) # x #define __xstr(x) __makestr(x) _PROTOTYPE( void __bad_assertion, (const char *_mess) ); #define assert(expr) ((expr)? (void)0 : \ __bad_assertion("Assertion \"" #expr \ "\" failed, file " __xstr(__FILE__) \ ", line " __xstr(__LINE__) "\n")) assert(sizeof(lists) / sizeof(lists[0]) == sizeof(sysroots) / sizeof(sysroots[0])); pcc-20181216/cc/cpp/tests/test3010064400017500000000000000006341046312102700147610ustar raggewheel#define str(s) # s #define xstr(s) str(s) #define debug(s, t) printf("x" # s "= %d, x" # t "= %s", \ x ## s, x ## t) #define INCFILE(n) vers ## n #define glue(a, b) a ## b #define xglue(a, b) glue(a, b) #define HIGHLOW "hello" #define LOW LOW ", world" debug(1, 2); fputs(str(strncmp("abc\0d", "abc", '\4') // this goes away == 0) str(: @\n), s); \#include xstr(INCFILE(2).h) glue(HIGH, LOW); xglue(HIGH, LOW) pcc-20181216/cc/cpp/tests/test4010064400017500000000000000001041046312102700147520ustar raggewheel#define foobar 1 #define C(x,y) x##y #define D(x) (C(x,bar)) D(foo) pcc-20181216/cc/cpp/tests/test5010064400017500000000000000001631046312102700147600ustar raggewheel#define t(x,y,z) x ## y ## z int j[] = { t(1,2,3), t(,4,5), t(6,,7), t(8,9,), t(10,,), t(,11,), t(,,12), t(,,) }; pcc-20181216/cc/cpp/tests/test6010064400017500000000000000000521051166764000147700ustar raggewheel#define X(a,b, \ c,d) \ foo X(1,2,3,4) pcc-20181216/cc/cpp/tests/test7010064400017500000000000000000501051166764000147670ustar raggewheel#define a() YES #define b() a b() b()() pcc-20181216/cc/cpp/tests/test8010064400017500000000000000001721051166764000147750ustar raggewheel// test macro expansion in arguments #define s_pos s_s.s_pos #define foo(x) (x) //hej.s_pos foo(hej.s_pos) pcc-20181216/cc/cpp/tests/test9010064400017500000000000000001071054653345600150010ustar raggewheel#define C(a,b,c) a##b##c #define N(x,y) C(x,_,y) #define A_O ao N(A,O) pcc-20181216/cc/cxxcom004075500017500000000000000000001340533064100132755ustar raggewheelpcc-20181216/cc/cxxcom/CVS004075500017500000000000000000001340533064100137305ustar raggewheelpcc-20181216/cc/cxxcom/CVS/Root010064400017500000000000000000111340533064100146420ustar raggewheel/cvsroot pcc-20181216/cc/cxxcom/CVS/Repository010064400017500000000000000000161340533064100161030ustar raggewheelpcc/cc/cxxcom pcc-20181216/cc/cxxcom/CVS/Entries010064400017500000000000000013031340533064100153350ustar raggewheel/Makefile.in/1.8/Tue Sep 11 11:24:08 2018// /builtins.c/1.7/Sat Mar 5 15:31:25 2016// /cgram.y/1.11/Tue Oct 11 13:48:24 2016// /cxxcode.c/1.7/Tue Oct 11 13:48:24 2016// /cxxdefs.h/1.2/Wed Jan 4 19:04:08 2012// /gcc_compat.c/1.11/Tue Oct 11 13:48:24 2016// /init.c/1.6/Tue Nov 24 17:30:20 2015// /inline.c/1.7/Mon Sep 26 16:45:43 2016// /main.c/1.7/Thu Mar 16 16:32:51 2017// /optim.c/1.5/Tue Nov 24 17:30:20 2015// /pass1.h/1.20/Sat Mar 5 15:31:25 2016// /pftn.c/1.17/Tue Oct 11 13:48:24 2016// /scan.l/1.10/Tue Oct 11 13:48:24 2016// /softfloat.c/1.1/Sun Jan 1 16:20:55 2012// /stabs.c/1.3/Sun Apr 22 21:07:41 2012// /symtabs.c/1.5/Tue Oct 11 13:48:24 2016// /trees.c/1.23/Mon Sep 26 16:45:43 2016// D pcc-20181216/cc/cxxcom/Makefile.in010064400017500000000000000114231334572273000154260ustar raggewheel# $Id: Makefile.in,v 1.8 2018/09/11 11:24:08 ragge Exp $ # # Makefile.in for cxxcom # VPATH=@srcdir@ srcdir=@srcdir@ top_srcdir=@top_srcdir@ builddir=@builddir@ top_builddir=@top_builddir@ CC = @CC@ EXEEXT = @EXEEXT@ CC_FOR_BUILD = @CC_FOR_BUILD@ CFLAGS = @CFLAGS@ @ADD_CFLAGS@ CPPFLAGS = @CPPFLAGS@ @ADD_CPPFLAGS@ -D_ISOC99_SOURCE -DLANG_CXX \ -Dos_$(TARGOS) -Dmach_$(TARGMACH) \ -I$(srcdir) -I$(builddir) -I$(top_builddir) -I$(MIPDIR) -I$(MDIR) \ -I$(top_srcdir)/os/$(TARGOS) -I$(COMMONDIR) LIBS = @LIBS@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LFLAGS = LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ YACC = @YACC@ YFLAGS = @YFLAGS@ TARGOS = @targos@ TARGOSVER = @targosver@ TARGMACH = @targmach@ TARGMACHDIR = @targmachdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ libexecdir = @libexecdir@ datarootdir = @datarootdir@ mandir = @mandir@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ MDIR=$(top_srcdir)/arch/$(TARGMACHDIR) MIPDIR=$(top_srcdir)/mip COMMONDIR=$(top_srcdir)/common DEST=@BINPREFIX@cxxcom$(EXEEXT) MANPAGE=@BINPREFIX@cxxcom MKEXT=mkext$(EXEEXT) all: $(DEST) OBJS= builtins.o cgram.o code.o common.o compat.o external.o \ gcc_compat.o init.o inline.o local.o local2.o main.o cxxcode.o \ match.o optim.o optim2.o order.o pftn.o reader.o \ regs.o scan.o stabs.o symtabs.o table.o trees.o LOBJS= mkext.lo common.lo table.lo HDRS= $(srcdir)/pass1.h $(MIPDIR)/pass2.h $(MIPDIR)/manifest.h \ $(MDIR)/macdefs.h $(MIPDIR)/node.h $(COMMONDIR)/compat.h # # round 1: generate external.[ch], cgram.[ch] & scan.c # $(LOBJS): $(HDRS) mkext.lo: $(MIPDIR)/mkext.c $(CC_FOR_BUILD) $(CFLAGS) $(CPPFLAGS) -DMKEXT -c -o $@ $(MIPDIR)/mkext.c common.lo: $(MIPDIR)/common.c $(CC_FOR_BUILD) $(CFLAGS) $(CPPFLAGS) -DMKEXT -c -o $@ $(MIPDIR)/common.c table.lo: $(MDIR)/table.c $(CC_FOR_BUILD) $(CFLAGS) $(CPPFLAGS) -DMKEXT -c -o $@ $(MDIR)/table.c $(MKEXT): $(LOBJS) $(CC_FOR_BUILD) $(LDFLAGS) $(LOBJS) -o $@ $(LIBS) external.c: $(MKEXT) $(builddir)/$(MKEXT) cgram.c: $(srcdir)/cgram.y $(YACC) $(YFLAGS) -d $(srcdir)/cgram.y mv -f y.tab.c cgram.c mv -f y.tab.h cgram.h scan.c: $(srcdir)/scan.l $(LEX) $(LFLAGS) $(srcdir)/scan.l mv -f $(LEX_OUTPUT_ROOT).c scan.c # # round 2: compile $(OBJS) # $(OBJS): $(HDRS) external.c cgram.c builtins.o: $(srcdir)/builtins.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/builtins.c cgram.o: cgram.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ cgram.c code.o: $(MDIR)/code.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/code.c common.o: $(MIPDIR)/common.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/common.c compat.o: $(COMMONDIR)/compat.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(COMMONDIR)/compat.c cxxcode.o: $(srcdir)/cxxcode.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/cxxcode.c external.o: external.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ external.c gcc_compat.o: $(srcdir)/gcc_compat.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/gcc_compat.c init.o: $(srcdir)/init.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/init.c inline.o: $(srcdir)/inline.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/inline.c local.o: $(MDIR)/local.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/local.c local2.o: $(MDIR)/local2.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/local2.c main.o: $(srcdir)/main.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/main.c match.o: $(MIPDIR)/match.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/match.c optim.o: $(srcdir)/optim.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/optim.c optim2.o: $(MIPDIR)/optim2.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/optim2.c order.o: $(MDIR)/order.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/order.c pftn.o: $(srcdir)/pftn.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/pftn.c reader.o: $(MIPDIR)/reader.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/reader.c regs.o: $(MIPDIR)/regs.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/regs.c scan.o: scan.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ scan.c stabs.o: $(srcdir)/stabs.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/stabs.c symtabs.o: $(srcdir)/symtabs.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/symtabs.c table.o: $(MDIR)/table.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/table.c trees.o: $(srcdir)/trees.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/trees.c # # round 3: build $(DEST) # $(DEST): $(OBJS) $(CC) $(LDFLAGS) $(OBJS) -o $@ $(LIBS) install: $(DEST) test -z "$(DESTDIR)$(libexecdir)" || mkdir -p "$(DESTDIR)$(libexecdir)" $(INSTALL_PROGRAM) $(DEST) $(DESTDIR)$(libexecdir) test -z "$(DESTDIR)$(mandir)/man1" || mkdir -p "$(DESTDIR)$(mandir)/man1" # $(INSTALL_DATA) $(srcdir)/ccom.1 $(DESTDIR)$(mandir)/man1/$(MANPAGE).1 clean: rm -f $(DEST) $(OBJS) $(MKEXT) $(LOBJS) $(LEX_OUTPUT_ROOT).c \ scan.c y.tab.[ch] cgram.[ch] external.[ch] distclean: clean rm -f Makefile pcc-20181216/cc/cxxcom/builtins.c010064400017500000000000000530331266657571500153770ustar raggewheel/* $Id: builtins.c,v 1.7 2016/03/05 15:31:25 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass1.h" #ifndef MIN #define MIN(a,b) (((a)<(b))?(a):(b)) #endif #ifndef MAX #define MAX(a,b) (((a)>(b))?(a):(b)) #endif #ifndef NO_C_BUILTINS /* * replace an alloca function with direct allocation on stack. * return a destination temp node. */ static NODE * builtin_alloca(const struct bitable *bt, NODE *a) { NODE *t, *u; #ifdef notyet if (xnobuiltins) return NULL; #endif t = tempnode(0, VOID|PTR, 0, 0); u = tempnode(regno(t), VOID|PTR, 0, 0); spalloc(t, a, SZCHAR); return u; } /* * Determine if a value is known to be constant at compile-time and * hence that PCC can perform constant-folding on expressions involving * that value. */ static NODE * builtin_constant_p(const struct bitable *bt, NODE *a) { void putjops(NODE *p, void *arg); NODE *f; int isconst; walkf(a, putjops, 0); for (f = a; f->n_op == COMOP; f = f->n_right) ; isconst = nncon(f); tfree(a); return bcon(isconst); } /* * Hint to the compiler whether this expression will evaluate true or false. * Just ignored for now. */ static NODE * builtin_expect(const struct bitable *bt, NODE *a) { NODE *f; if (a && a->n_op == CM) { tfree(a->n_right); f = a->n_left; nfree(a); a = f; } return a; } /* * Take integer absolute value. * Simply does: ((((x)>>(8*sizeof(x)-1))^(x))-((x)>>(8*sizeof(x)-1))) */ static NODE * builtin_abs(const struct bitable *bt, NODE *a) { NODE *p, *q, *r, *t, *t2, *t3; int tmp1, tmp2, shift; if (a->n_type != INT) a = cast(a, INT, 0); if (a->n_op == ICON) { if (getlval(a) < 0) setlval(a, -getlval(a)); p = a; } else { t = tempnode(0, a->n_type, a->n_df, a->n_ap); tmp1 = regno(t); p = buildtree(ASSIGN, t, a); t = tempnode(tmp1, a->n_type, a->n_df, a->n_ap); shift = (int)tsize(a->n_type, a->n_df, a->n_ap) - 1; q = buildtree(RS, t, bcon(shift)); t2 = tempnode(0, a->n_type, a->n_df, a->n_ap); tmp2 = regno(t2); q = buildtree(ASSIGN, t2, q); t = tempnode(tmp1, a->n_type, a->n_df, a->n_ap); t2 = tempnode(tmp2, a->n_type, a->n_df, a->n_ap); t3 = tempnode(tmp2, a->n_type, a->n_df, a->n_ap); r = buildtree(MINUS, buildtree(ER, t, t2), t3); p = buildtree(COMOP, p, buildtree(COMOP, q, r)); } return p; } #define cmop(x,y) buildtree(COMOP, x, y) #define lblnod(l) nlabel(l) #ifndef TARGET_CXZ /* * Find number of beginning 0's in a word of type t. * t should be deunsigned. */ static NODE * builtin_cxz(NODE *a, TWORD t, int isclz) { NODE *t101, *t102; NODE *rn, *p; int l15, l16, l17; int sz; t = ctype(t); sz = (int)tsize(t, 0, 0); t101 = tempnode(0, INT, 0, 0); t102 = tempnode(0, t, 0, 0); l15 = getlab(); l16 = getlab(); l17 = getlab(); rn = buildtree(ASSIGN, ccopy(t102), a); rn = cmop(rn, buildtree(ASSIGN, ccopy(t101), bcon(0))); rn = cmop(rn, lblnod(l16)); p = buildtree(CBRANCH, buildtree(GE, ccopy(t101), bcon(sz)), bcon(l15)); rn = cmop(rn, p); if (isclz) { p = buildtree(CBRANCH, buildtree(GE, ccopy(t102), bcon(0)), bcon(l17)); } else { p = buildtree(CBRANCH, buildtree(EQ, buildtree(AND, ccopy(t102), bcon(1)), bcon(0)), bcon(l17)); } rn = cmop(rn, p); rn = cmop(rn, block(GOTO, bcon(l15), NIL, INT, 0, 0)); rn = cmop(rn, lblnod(l17)); rn = cmop(rn, buildtree(isclz ? LSEQ : RSEQ , t102, bcon(1))); rn = cmop(rn, buildtree(INCR, ccopy(t101), bcon(1))); rn = cmop(rn, block(GOTO, bcon(l16), NIL, INT, 0, 0)); rn = cmop(rn, lblnod(l15)); return cmop(rn, t101); } static NODE * builtin_clz(const struct bitable *bt, NODE *a) { return builtin_cxz(a, INT, 1); } static NODE * builtin_clzl(const struct bitable *bt, NODE *a) { return builtin_cxz(a, LONG, 1); } static NODE * builtin_clzll(const struct bitable *bt, NODE *a) { return builtin_cxz(a, LONGLONG, 1); } static NODE * builtin_ctz(const struct bitable *bt, NODE *a) { return builtin_cxz(a, INT, 0); } static NODE * builtin_ctzl(const struct bitable *bt, NODE *a) { return builtin_cxz(a, LONG, 0); } static NODE * builtin_ctzll(const struct bitable *bt, NODE *a) { return builtin_cxz(a, LONGLONG, 0); } #endif #ifndef TARGET_FFS /* * Find number of beginning 0's in a word of type t. * t should be deunsigned. */ static NODE * builtin_ff(NODE *a, TWORD t) { NODE *t101, *t102; NODE *rn, *p; int l15, l16, l17; int sz; t = ctype(t); sz = (int)tsize(t, 0, 0)+1; t101 = tempnode(0, INT, 0, 0); t102 = tempnode(0, t, 0, 0); l15 = getlab(); l16 = getlab(); l17 = getlab(); rn = buildtree(ASSIGN, ccopy(t101), bcon(0)); rn = cmop(rn, buildtree(ASSIGN, ccopy(t102), a)); p = buildtree(CBRANCH, buildtree(EQ, ccopy(t102), bcon(0)), bcon(l15)); rn = cmop(rn, p); rn = cmop(rn, buildtree(INCR, ccopy(t101), bcon(1))); rn = cmop(rn, lblnod(l16)); p = buildtree(CBRANCH, buildtree(GE, ccopy(t101), bcon(sz)), bcon(l15)); rn = cmop(rn, p); p = buildtree(CBRANCH, buildtree(EQ, buildtree(AND, ccopy(t102), bcon(1)), bcon(0)), bcon(l17)); rn = cmop(rn, p); rn = cmop(rn, block(GOTO, bcon(l15), NIL, INT, 0, 0)); rn = cmop(rn, lblnod(l17)); rn = cmop(rn, buildtree(RSEQ, t102, bcon(1))); rn = cmop(rn, buildtree(INCR, ccopy(t101), bcon(1))); rn = cmop(rn, block(GOTO, bcon(l16), NIL, INT, 0, 0)); rn = cmop(rn, lblnod(l15)); return cmop(rn, t101); } static NODE * builtin_ffs(const struct bitable *bt, NODE *a) { return builtin_ff(a, INT); } static NODE * builtin_ffsl(const struct bitable *bt, NODE *a) { return builtin_ff(a, LONG); } static NODE * builtin_ffsll(const struct bitable *bt, NODE *a) { return builtin_ff(a, LONGLONG); } #endif /* * Get size of object, if possible. * Currently does nothing, */ static NODE * builtin_object_size(const struct bitable *bt, NODE *a) { CONSZ v = icons(a->n_right); NODE *f; if (v < 0 || v > 3) uerror("arg2 must be between 0 and 3"); f = buildtree(COMOP, a->n_left, xbcon(v < 2 ? -1 : 0, NULL, bt->rt)); nfree(a); return f; } #ifndef TARGET_STDARGS static NODE * builtin_stdarg_start(const struct bitable *bt, NODE *a) { NODE *p, *q; int sz; /* must first deal with argument size; use int size */ p = a->n_right; if (p->n_type < INT) { sz = (int)(SZINT/tsize(p->n_type, p->n_df, p->n_ap)); } else sz = 1; /* do the real job */ p = buildtree(ADDROF, p, NIL); /* address of last arg */ #ifdef BACKAUTO p = optim(buildtree(PLUS, p, bcon(sz))); /* add one to it (next arg) */ #else p = optim(buildtree(MINUS, p, bcon(sz))); /* add one to it (next arg) */ #endif q = block(NAME, NIL, NIL, PTR+VOID, 0, 0); /* create cast node */ q = buildtree(CAST, q, p); /* cast to void * (for assignment) */ p = q->n_right; nfree(q->n_left); nfree(q); p = buildtree(ASSIGN, a->n_left, p); /* assign to ap */ nfree(a); return p; } static NODE * builtin_va_arg(const struct bitable *bt, NODE *a) { NODE *p, *q, *r, *rv; int sz, nodnum; /* create a copy to a temp node of current ap */ p = ccopy(a->n_left); q = tempnode(0, p->n_type, p->n_df, p->n_ap); nodnum = regno(q); rv = buildtree(ASSIGN, q, p); r = a->n_right; sz = (int)tsize(r->n_type, r->n_df, r->n_ap)/SZCHAR; /* add one to ap */ #ifdef BACKAUTO rv = buildtree(COMOP, rv , buildtree(PLUSEQ, a->n_left, bcon(sz))); #else #error fix wrong eval order in builtin_va_arg ecomp(buildtree(MINUSEQ, a->n_left, bcon(sz))); #endif nfree(a->n_right); nfree(a); r = tempnode(nodnum, INCREF(r->n_type), r->n_df, r->n_ap); return buildtree(COMOP, rv, buildtree(UMUL, r, NIL)); } static NODE * builtin_va_end(const struct bitable *bt, NODE *a) { tfree(a); return bcon(0); /* nothing */ } static NODE * builtin_va_copy(const struct bitable *bt, NODE *a) { NODE *f; f = buildtree(ASSIGN, a->n_left, a->n_right); nfree(a); return f; } #endif /* TARGET_STDARGS */ /* * For unimplemented "builtin" functions, try to invoke the * non-builtin name */ static NODE * binhelp(NODE *a, TWORD rt, char *n) { NODE *f = block(NAME, NIL, NIL, INT, 0, 0); f->n_sp = lookup(addname(n), SNORMAL); if (f->n_sp->sclass == SNULL) { f->n_sp->sclass = EXTERN; f->n_sp->stype = INCREF(rt)+(FTN-PTR); } f->n_type = f->n_sp->stype; f = clocal(f); return buildtree(CALL, f, a); } static NODE * builtin_unimp(const struct bitable *bt, NODE *a) { return binhelp(a, bt->rt, &bt->name[10]); } #if 0 static NODE * builtin_unimp_f(NODE *f, NODE *a, TWORD rt) { return binhelp(f, a, rt, f->n_sp->sname); } #endif #ifndef TARGET_PREFETCH static NODE * builtin_prefetch(const struct bitable *bt, NODE *a) { tfree(a); return bcon(0); } #endif #ifndef TARGET_ISMATH /* * Handle the builtin macros for the math functions is* * To get something that is be somewhat generic assume that * isnan() is a real function and that cast of a NaN type * to double will still be a NaN. */ static NODE * mtisnan(NODE *p) { return binhelp(cast(ccopy(p), DOUBLE, 0), INT, "isnan"); } static TWORD mtcheck(NODE *p) { TWORD t1 = p->n_left->n_type, t2 = p->n_right->n_type; if ((t1 >= FLOAT && t1 <= LDOUBLE) || (t2 >= FLOAT && t2 <= LDOUBLE)) return MAX(t1, t2); return 0; } static NODE * builtin_isunordered(const struct bitable *bt, NODE *a) { NODE *p; if (mtcheck(a) == 0) return bcon(0); p = buildtree(OROR, mtisnan(a->n_left), mtisnan(a->n_right)); tfree(a); return p; } static NODE * builtin_isany(NODE *a, TWORD rt, int cmpt) { NODE *p, *q; TWORD t; if ((t = mtcheck(a)) == 0) return bcon(0); p = buildtree(OROR, mtisnan(a->n_left), mtisnan(a->n_right)); p = buildtree(NOT, p, NIL); q = buildtree(cmpt, cast(ccopy(a->n_left), t, 0), cast(ccopy(a->n_right), t, 0)); p = buildtree(ANDAND, p, q); tfree(a); return p; } static NODE * builtin_isgreater(const struct bitable *bt, NODE *a) { return builtin_isany(a, bt->rt, GT); } static NODE * builtin_isgreaterequal(const struct bitable *bt, NODE *a) { return builtin_isany(a, bt->rt, GE); } static NODE * builtin_isless(const struct bitable *bt, NODE *a) { return builtin_isany(a, bt->rt, LT); } static NODE * builtin_islessequal(const struct bitable *bt, NODE *a) { return builtin_isany(a, bt->rt, LE); } static NODE * builtin_islessgreater(const struct bitable *bt, NODE *a) { NODE *p, *q, *r; TWORD t; if ((t = mtcheck(a)) == 0) return bcon(0); p = buildtree(OROR, mtisnan(a->n_left), mtisnan(a->n_right)); p = buildtree(NOT, p, NIL); q = buildtree(GT, cast(ccopy(a->n_left), t, 0), cast(ccopy(a->n_right), t, 0)); r = buildtree(LT, cast(ccopy(a->n_left), t, 0), cast(ccopy(a->n_right), t, 0)); q = buildtree(OROR, q, r); p = buildtree(ANDAND, p, q); tfree(a); return p; } #endif /* * Math-specific builtins that expands to constants. * Versins here is for IEEE FP, vax needs its own versions. */ #if TARGET_ENDIAN == TARGET_LE static const unsigned char vFLOAT[] = { 0, 0, 0x80, 0x7f }; static const unsigned char vDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f }; #ifdef LDBL_128 static const unsigned char vLDOUBLE[] = { 0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0x80, 0xff, 0x7f }; #else /* LDBL_80 */ static const unsigned char vLDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0, 0x80, 0xff, 0x7f }; #endif static const unsigned char nFLOAT[] = { 0, 0, 0xc0, 0x7f }; static const unsigned char nDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0xf8, 0x7f }; #ifdef LDBL_128 static const unsigned char nLDOUBLE[] = { 0,0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0xc0, 0xff, 0x7f }; #else /* LDBL_80 */ static const unsigned char nLDOUBLE[] = { 0, 0, 0, 0, 0, 0, 0, 0xc0, 0xff, 0x7f, 0, 0 }; #endif #else static const unsigned char vFLOAT[] = { 0x7f, 0x80, 0, 0 }; static const unsigned char vDOUBLE[] = { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 }; #ifdef LDBL_128 static const unsigned char vLDOUBLE[] = { 0x7f, 0xff, 0x80, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0 }; #else /* LDBL_80 */ static const unsigned char vLDOUBLE[] = { 0x7f, 0xff, 0x80, 0, 0, 0, 0, 0, 0, 0 }; #endif static const unsigned char nFLOAT[] = { 0x7f, 0xc0, 0, 0 }; static const unsigned char nDOUBLE[] = { 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 }; #ifdef LDBL_128 static const unsigned char nLDOUBLE[] = { 0x7f, 0xff, 0xc0, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0 }; #else /* LDBL_80 */ static const unsigned char nLDOUBLE[] = { 0x7f, 0xff, 0xc0, 0, 0, 0, 0, 0, 0, 0 }; #endif #endif #define VALX(typ,TYP) { \ typ d; \ int x; \ NODE *f; \ x = MIN(sizeof(n ## TYP), sizeof(d)); \ memcpy(&d, v ## TYP, x); \ f = block(FCON, NIL, NIL, TYP, NULL, 0); \ f->n_dcon = fltallo(); \ ((FLT *)f->n_dcon)->fp = d; \ return f; \ } static NODE * builtin_huge_valf(const struct bitable *bt, NODE *a) VALX(float,FLOAT) static NODE * builtin_huge_val(const struct bitable *bt, NODE *a) VALX(double,DOUBLE) static NODE * builtin_huge_vall(const struct bitable *bt, NODE *a) VALX(long double,LDOUBLE) #define builtin_inff builtin_huge_valf #define builtin_inf builtin_huge_val #define builtin_infl builtin_huge_vall /* * Return NANs, if reasonable. */ static NODE * builtin_nanx(const struct bitable *bt, NODE *a) { if (a == NULL || a->n_op == CM) { uerror("%s bad argument", bt->name); a = bcon(0); } else if (a->n_op == STRING && *a->n_name == '\0') { a->n_op = FCON; a->n_type = bt->rt; a->n_dcon = fltallo(); memcpy(&FCAST(a->n_dcon)->fp, nLDOUBLE, sizeof(long double)); } else a = binhelp(eve(a), bt->rt, &bt->name[10]); return a; } /* * Target defines, to implement target versions of the generic builtins */ #ifndef TARGET_MEMCMP #define builtin_memcmp builtin_unimp #endif #ifndef TARGET_MEMCPY #define builtin_memcpy builtin_unimp #endif #ifndef TARGET_MEMPCPY #define builtin_mempcpy builtin_unimp #endif #ifndef TARGET_MEMSET #define builtin_memset builtin_unimp #endif /* Reasonable type of size_t */ #ifndef SIZET #if SZINT == SZSHORT #define SIZET UNSIGNED #elif SZLONG > SZINT #define SIZET ULONG #else #define SIZET UNSIGNED #endif #endif static TWORD memcpyt[] = { VOID|PTR, VOID|PTR, SIZET, INT }; static TWORD memsett[] = { VOID|PTR, INT, SIZET, INT }; static TWORD allocat[] = { SIZET }; static TWORD expectt[] = { LONG, LONG }; static TWORD strcmpt[] = { CHAR|PTR, CHAR|PTR }; static TWORD strcpyt[] = { CHAR|PTR, CHAR|PTR, INT }; static TWORD strncpyt[] = { CHAR|PTR, CHAR|PTR, SIZET, INT }; static TWORD strchrt[] = { CHAR|PTR, INT }; static TWORD strcspnt[] = { CHAR|PTR, CHAR|PTR }; static TWORD strspnt[] = { CHAR|PTR, CHAR|PTR }; static TWORD strpbrkt[] = { CHAR|PTR, CHAR|PTR }; static TWORD nant[] = { CHAR|PTR }; static TWORD bitt[] = { UNSIGNED }; static TWORD bitlt[] = { ULONG }; static TWORD bitllt[] = { ULONGLONG }; static TWORD abst[] = { INT }; static const struct bitable bitable[] = { { "__builtin___memcpy_chk", builtin_unimp, 0, 4, memcpyt, VOID|PTR }, { "__builtin___mempcpy_chk", builtin_unimp, 0, 4, memcpyt, VOID|PTR }, { "__builtin___memmove_chk", builtin_unimp, 0, 4, memcpyt, VOID|PTR }, { "__builtin___memset_chk", builtin_unimp, 0, 4, memsett, VOID|PTR }, { "__builtin___strcat_chk", builtin_unimp, 0, 3, strcpyt, CHAR|PTR }, { "__builtin___strcpy_chk", builtin_unimp, 0, 3, strcpyt, CHAR|PTR }, { "__builtin___strncat_chk", builtin_unimp, 0, 4, strncpyt,CHAR|PTR }, { "__builtin___strncpy_chk", builtin_unimp, 0, 4, strncpyt,CHAR|PTR }, { "__builtin___printf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT }, { "__builtin___fprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT }, { "__builtin___sprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT }, { "__builtin___snprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT }, { "__builtin___vprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT }, { "__builtin___vfprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT }, { "__builtin___vsprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT }, { "__builtin___vsnprintf_chk", builtin_unimp, BTNOPROTO, -1, 0, INT }, { "__builtin_alloca", builtin_alloca, 0, 1, allocat, VOID|PTR }, { "__builtin_abs", builtin_abs, 0, 1, abst, INT }, { "__builtin_clz", builtin_clz, 0, 1, bitt, INT }, { "__builtin_clzl", builtin_clzl, 0, 1, bitlt, INT }, { "__builtin_clzll", builtin_clzll, 0, 1, bitllt, INT }, { "__builtin_ctz", builtin_ctz, 0, 1, bitt, INT }, { "__builtin_ctzl", builtin_ctzl, 0, 1, bitlt, INT }, { "__builtin_ctzll", builtin_ctzll, 0, 1, bitllt, INT }, { "__builtin_ffs", builtin_ffs, 0, 1, bitt, INT }, { "__builtin_ffsl", builtin_ffsl, 0, 1, bitlt, INT }, { "__builtin_ffsll", builtin_ffsll, 0, 1, bitllt, INT }, { "__builtin_popcount", builtin_unimp, 0, 1, bitt, UNSIGNED }, { "__builtin_popcountl", builtin_unimp, 0, 1, bitlt, ULONG }, { "__builtin_popcountll", builtin_unimp, 0, 1, bitllt, ULONGLONG }, { "__builtin_constant_p", builtin_constant_p, 0, 1, 0, INT }, { "__builtin_expect", builtin_expect, 0, 2, expectt, LONG }, { "__builtin_memcmp", builtin_memcmp, 0, 3, memcpyt, INT }, { "__builtin_memcpy", builtin_memcpy, 0, 3, memcpyt, VOID|PTR }, { "__builtin_mempcpy", builtin_mempcpy, 0, 3, memcpyt, VOID|PTR }, { "__builtin_memset", builtin_memset, 0, 3, memsett, VOID|PTR }, { "__builtin_huge_valf", builtin_huge_valf, 0, 0, 0, FLOAT }, { "__builtin_huge_val", builtin_huge_val, 0, 0, 0, DOUBLE }, { "__builtin_huge_vall", builtin_huge_vall, 0, 0, 0, LDOUBLE }, { "__builtin_inff", builtin_inff, 0, 0, 0, FLOAT }, { "__builtin_inf", builtin_inf, 0, 0, 0, DOUBLE }, { "__builtin_infl", builtin_infl, 0, 0, 0, LDOUBLE }, { "__builtin_isgreater", builtin_isgreater, 0, 2, NULL, INT }, { "__builtin_isgreaterequal", builtin_isgreaterequal, 0, 2, NULL, INT }, { "__builtin_isless", builtin_isless, 0, 2, NULL, INT }, { "__builtin_islessequal", builtin_islessequal, 0, 2, NULL, INT }, { "__builtin_islessgreater", builtin_islessgreater, 0, 2, NULL, INT }, { "__builtin_isunordered", builtin_isunordered, 0, 2, NULL, INT }, { "__builtin_nanf", builtin_nanx, BTNOEVE, 1, nant, FLOAT }, { "__builtin_nan", builtin_nanx, BTNOEVE, 1, nant, DOUBLE }, { "__builtin_nanl", builtin_nanx, BTNOEVE, 1, nant, LDOUBLE }, { "__builtin_object_size", builtin_object_size, 0, 2, memsett, SIZET }, { "__builtin_prefetch", builtin_prefetch, 0, 1, memsett, VOID }, { "__builtin_strcmp", builtin_unimp, 0, 2, strcmpt, INT }, { "__builtin_strcpy", builtin_unimp, 0, 2, strcpyt, CHAR|PTR }, { "__builtin_stpcpy", builtin_unimp, 0, 2, strcpyt, CHAR|PTR }, { "__builtin_strchr", builtin_unimp, 0, 2, strchrt, CHAR|PTR }, { "__builtin_strlen", builtin_unimp, 0, 1, strcmpt, SIZET }, { "__builtin_strrchr", builtin_unimp, 0, 2, strchrt, CHAR|PTR }, { "__builtin_strncpy", builtin_unimp, 0, 3, strncpyt, CHAR|PTR }, { "__builtin_strncat", builtin_unimp, 0, 3, strncpyt, CHAR|PTR }, { "__builtin_strcspn", builtin_unimp, 0, 2, strcspnt, SIZET }, { "__builtin_strspn", builtin_unimp, 0, 2, strspnt, SIZET }, { "__builtin_strstr", builtin_unimp, 0, 2, strcmpt, CHAR|PTR }, { "__builtin_strpbrk", builtin_unimp, 0, 2, strpbrkt, CHAR|PTR }, #ifndef TARGET_STDARGS { "__builtin_stdarg_start", builtin_stdarg_start, 0, 2, 0, VOID }, { "__builtin_va_start", builtin_stdarg_start, 0, 2, 0, VOID }, { "__builtin_va_arg", builtin_va_arg, BTNORVAL|BTNOPROTO, 2, 0, 0 }, { "__builtin_va_end", builtin_va_end, 0, 1, 0, VOID }, { "__builtin_va_copy", builtin_va_copy, 0, 2, 0, VOID }, #endif #ifdef TARGET_BUILTINS TARGET_BUILTINS #endif }; /* * Check and cast arguments for builtins. */ static int acnt(NODE *a, int narg, TWORD *tp) { NODE *q; TWORD t; if (a == NIL) return narg; for (; a->n_op == CM; a = a->n_left, narg--) { if (tp == NULL) continue; q = a->n_right; t = ctype(tp[narg-1]); if (q->n_type == t) continue; a->n_right = ccast(q, t, 0, NULL, 0); } /* Last arg is ugly to deal with */ if (narg == 1 && tp != NULL && a->n_type != tp[0]) { q = talloc(); *q = *a; q = ccast(q, ctype(tp[0]), 0, NULL, 0); *a = *q; nfree(q); } return narg != 1; } NODE * builtin_check(struct symtab *sp, NODE *a) { const struct bitable *bt; if (sp->soffset < 0 || sp->soffset >= (int)(sizeof(bitable)/sizeof(bitable[0]))) cerror("builtin_check"); bt = &bitable[sp->soffset]; if ((bt->flags & BTNOEVE) == 0) a = eve(a); if (((bt->flags & BTNOPROTO) == 0) && acnt(a, bt->narg, bt->tp)) { uerror("wrong argument count to %s", bt->name); return bcon(0); } return (*bt->fun)(bt, a); } /* * Put all builtin functions into the global symbol table. */ void builtin_init() { const struct bitable *bt; NODE *p = block(TYPE, 0, 0, 0, 0, 0); struct symtab *sp; int i; for (i = 0; i < (int)(sizeof(bitable)/sizeof(bitable[0])); i++) { bt = &bitable[i]; sp = lookup(addname(bt->name), 0); if (bt->rt == 0 && (bt->flags & BTNORVAL) == 0) cerror("function '%s' has no return type", bt->name); p->n_type = INCREF(bt->rt) + (FTN-PTR); p->n_sp = sp; defid(p, EXTDEF); sp->soffset = i; sp->sflags |= SBUILTIN; } nfree(p); } #endif pcc-20181216/cc/cxxcom/cgram.y010064400017500000000000001564751277716665000147000ustar raggewheel/* $Id: cgram.y,v 1.11 2016/10/11 13:48:24 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code and documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Comments for this grammar file. Ragge 021123 * * ANSI support required rewrite of the function header and declaration * rules almost totally. * * The lex/yacc shared keywords are now split from the keywords used * in the rest of the compiler, to simplify use of other frontends. */ /* * At last count, there were 5 shift/reduce and no reduce/reduce conflicts * Four are accounted for; * One is "dangling else" * Two is in attribute parsing * One is in ({ }) parsing */ /* * Token used in C lex/yacc communications. */ %token C_STRING /* a string constant */ %token C_ICON /* an integer constant */ %token C_FCON /* a floating point constant */ %token C_NAME /* an identifier */ %token C_TYPENAME /* a typedef'd name */ %token C_ANDAND /* && */ %token C_OROR /* || */ %token C_GOTO /* unconditional goto */ %token C_RETURN /* return from function */ %token C_TYPE /* a type */ %token C_CLASS /* a storage class */ %token C_ASOP /* assignment ops */ %token C_RELOP /* <=, <, >=, > */ %token C_EQUOP /* ==, != */ %token C_DIVOP /* /, % */ %token C_SHIFTOP /* <<, >> */ %token C_INCOP /* ++, -- */ %token C_UNOP /* !, ~ */ %token C_STROP /* ., -> */ %token C_STRUCT %token C_IF %token C_ELSE %token C_SWITCH %token C_BREAK %token C_CONTINUE %token C_WHILE %token C_DO %token C_FOR %token C_DEFAULT %token C_CASE %token C_SIZEOF %token C_ALIGNOF %token C_ENUM %token C_ELLIPSIS %token C_QUALIFIER %token C_FUNSPEC %token C_ASM %token NOMATCH %token C_TYPEOF /* COMPAT_GCC */ %token C_ATTRIBUTE /* COMPAT_GCC */ %token PCC_OFFSETOF %token GCC_DESIG %token CXX_NAMESPACE %token CXX_DUALCC %token CXX_TEMPLATE %token CXX_USING %token CXX_TYPENAME %token CXX_CASTS %token CXX_THROW %token CXX_MORENM %token CXX_NEW %token CXX_DELETE %token CXX_CLASS /* * Precedence */ %left ',' %right '=' C_ASOP %right '?' ':' %left C_OROR %left C_ANDAND %left '|' %left '^' %left '&' %left C_EQUOP %left C_RELOP %left C_SHIFTOP %left '+' '-' %left '*' C_DIVOP %right C_UNOP %right C_INCOP C_SIZEOF %left '[' '(' C_STROP %{ # include "pass1.h" # include # include # include int fun_inline; /* Reading an inline function */ int oldstyle; /* Current function being defined */ static struct symtab *xnf; extern int enummer, tvaloff, inattr; extern struct rstack *rpole; static int widestr, alwinl; NODE *cftnod; static int attrwarn = 1; #define NORETYP SNOCREAT /* no return type, save in unused field in symtab */ NODE *bdty(int op, ...); static void fend(struct symtab *); static struct symtab *fundef(NODE *tp, NODE *p); static void olddecl(NODE *p, NODE *a); static struct symtab *init_declarator(NODE *tn, NODE *p, int assign, NODE *a); static void resetbc(int mask); static void swend(void); static void addcase(NODE *p); #ifdef GCC_COMPAT static void gcccase(NODE *p, NODE *); #endif static struct attr *gcc_attr_wrapper(NODE *p); static void adddef(void); static void savebc(void); static void swstart(int, TWORD); static void genswitch(int, TWORD, struct swents **, int); static char *mkpstr(char *str); static struct symtab *clbrace(NODE *); static NODE *cmop(NODE *l, NODE *r); static NODE *xcmop(NODE *out, NODE *in, NODE *str); static void mkxasm(char *str, NODE *p); static NODE *xasmop(char *str, NODE *p); static int maxstlen(char *str); static char *stradd(char *old, char *new); static NODE *biop(int op, NODE *l, NODE *r); static void flend(void); static char * simname(char *s); static NODE *tyof(NODE *); /* COMPAT_GCC */ static NODE *voidcon(void); /* COMPAT_GCC */ static NODE *funargs(NODE *p); static void oldargs(NODE *p); static void uawarn(NODE *p, char *s); static int con_e(NODE *p); static void dainit(NODE *d, NODE *a); static NODE *tymfix(NODE *p); static NODE *namekill(NODE *p, int clr); static NODE *aryfix(NODE *p); #define TYMFIX(inp) { \ NODE *pp = inp; \ inp = tymerge(pp->n_left, pp->n_right); \ nfree(pp->n_left); nfree(pp); } /* * State for saving current switch state (when nested switches). */ struct savbc { struct savbc *next; int brklab; int contlab; int flostat; int swx; } *savbc, *savctx; %} %union { int intval; NODE *nodep; struct symtab *symp; struct rstack *rp; char *strp; } /* define types */ %start edf %type ifelprefix ifprefix whprefix forprefix doprefix switchpart xbegin %type e .e term enum_dcl struct_dcl cast_type declarator elist type_sq cf_spec merge_attribs parameter_declaration abstract_declarator initializer parameter_type_list parameter_list addrlbl declaration_specifiers designation specifier_qualifier_list merge_specifiers identifier_list arg_param_list type_qualifier_list designator_list designator xasm oplist oper cnstr typeof attribute attribute_specifier /* COMPAT_GCC */ attribute_list attr_spec_list attr_var /* COMPAT_GCC */ new_ma new_type_sq new_ds nmrec %type string C_STRING GCC_DESIG nsname CXX_MORENM %type str_head %type xnfdeclarator clbrace enum_head funtype %type C_STRUCT C_RELOP C_DIVOP C_SHIFTOP C_ANDAND C_OROR C_STROP C_INCOP C_UNOP C_ASOP C_EQUOP %type C_TYPE C_QUALIFIER C_ICON C_FCON C_CLASS %type C_NAME C_TYPENAME %% edf: ext_def_list | { ftnend(); } ; ext_def_list: ext_def_list external_def | external_def ; external_def: funtype kr_args compoundstmt { fend($1); } | declaration { blevel = 0; symclear(0); } | namespace | extlink | blockdcl | ';' | error { blevel = 0; } ; funtype: /* no type given */ declarator { $$ = fundef(mkty(INT, 0, 0), $1); cftnsp->sflags |= NORETYP; } | declaration_specifiers declarator { $$ = fundef($1,$2); } ; kr_args: /* empty */ | arg_dcl_list ; blockdcl: simple_decl | asmstatement | ns_alias | using_x ; using_x: CXX_USING tnopt ccopt nested_name_sp ';' { werror("using"); } | CXX_USING CXX_NAMESPACE ccopt nested_name_sp ';' { werror("using2"); } ; tnopt: CXX_TYPENAME { } | { } ; ns_alias: CXX_NAMESPACE C_NAME '=' qual_ns_sp ';' { werror("ns_alias");} ; qual_ns_sp: ccopt nested_name_sp ; nested_name_sp: nmtnm | nmtnm CXX_DUALCC nested_name_sp | nmtnm CXX_DUALCC CXX_TEMPLATE nested_name_sp ; nmtnm: C_NAME | C_TYPENAME ; ccopt: CXX_DUALCC | { } ; simple_decl: ')' NOMATCH { uerror("simple-declaration"); } ; namespace: CXX_NAMESPACE nsname attr_var nsbeg ns_body '}' { POPSYM(); } ; nsname: C_NAME | { $$ = NULL; } ; ns_body: ext_def_list | { } ; nsbeg: '{' { dclns($0, $-1); } ; extlink: C_CLASS C_STRING eb '{' ext_def_list '}' { elnk = LINK_DEF; } | C_CLASS C_STRING eb '{' '}' { elnk = LINK_DEF; } | C_CLASS C_STRING eb declaration { elnk = LINK_DEF; } ; eb: { NODE *p = $-1; char *s = $0; if (p->n_type != EXTERN) uerror("'extern' expected"); if (strcmp(s, "\"C\"") != 0 && strcmp(s, "\"c\"")) uerror("unknown linkage %s", s); nfree(p); elnk = LINK_C; } ; /* * Returns a node pointer or NULL, if no types at all given. * Type trees are checked for correctness and merged into one * type node in typenode(). */ declaration_specifiers: merge_attribs { $$ = typenode($1); } ; merge_attribs: type_sq { $$ = $1; } | type_sq merge_attribs { $$ = cmop($2, $1); } | cf_spec { $$ = $1; } | cf_spec merge_attribs { $$ = cmop($2, $1); } ; type_sq: C_TYPE { $$ = $1; } | C_TYPENAME { struct symtab *sp = lookup($1, 0); if (sp->stype == ENUMTY) { sp->stype = strmemb(sp->sap)->stype; } $$ = mkty(sp->stype, sp->sdf, sp->sap); $$->n_sp = sp; } | struct_dcl { $$ = $1; } | enum_dcl { $$ = $1; } | C_QUALIFIER { $$ = $1; } | attribute_specifier { $$ = biop(ATTRIB, $1, 0); } | typeof { $$ = $1; } ; cf_spec: C_CLASS { $$ = $1; } | C_FUNSPEC { fun_inline = 1; /* XXX - hack */ $$ = block(QUALIFIER, NIL, NIL, 0, 0, 0); } ; typeof: C_TYPEOF '(' e ')' { $$ = tyof(eve($3)); } | C_TYPEOF '(' cast_type ')' { TYMFIX($3); $$ = tyof($3); } ; new_ma: new_type_sq | new_type_sq new_ma { $$ = cmop($2, $1); } | cf_spec { $$ = $1; } | cf_spec new_ma { $$ = cmop($2, $1); } ; new_ds: new_ma { $$ = typenode($1); } ; new_type_sq: C_TYPE { $$ = $1; } | C_TYPENAME { struct symtab *sp = lookup($1, 0); if (sp->stype == ENUMTY) { sp->stype = strmemb(sp->sap)->stype; } $$ = mkty(sp->stype, sp->sdf, sp->sap); $$->n_sp = sp; } | struct_dcl { $$ = $1; } | enum_dcl { $$ = $1; } | C_QUALIFIER { $$ = $1; } ; attribute_specifier : C_ATTRIBUTE '(' '(' attribute_list ')' ')' { $$ = $4; } /*COMPAT_GCC*/ ; attribute_list: attribute | attribute ',' attribute_list { $$ = cmop($3, $1); } ; attribute: { #ifdef GCC_COMPAT $$ = voidcon(); #endif } | C_NAME { $$ = bdty(NAME, $1); } | C_NAME '(' elist ')' { $$ = bdty($3 == NIL ? UCALL : CALL, bdty(NAME, $1), $3); } ; /* * Adds a pointer list to front of the declarators. */ declarator: '*' declarator { $$ = bdty(UMUL, $2); } | '*' type_qualifier_list declarator { $$ = $2; $$->n_left = $3; } | nmrec C_NAME { $$ = biop(NMLIST, $1, bdty(NAME, $2)); } | C_NAME { $$ = bdty(NAME, $1); } | '(' attr_spec_list declarator ')' { $$ = $3; $$->n_ap = attr_add($$->n_ap, gcc_attr_wrapper($2)); } | '(' declarator ')' { $$ = $2; } | declarator '[' e ']' { $$ = biop(LB, $1, $3); } | declarator '[' C_CLASS e ']' { if ($3->n_type != STATIC) uerror("bad class keyword"); tfree($3); /* XXX - handle */ $$ = biop(LB, $1, $4); } | declarator '[' ']' { $$ = biop(LB, $1, bcon(NOOFFSET)); } | declarator '[' '*' ']' { $$ = biop(LB, $1, bcon(NOOFFSET)); } | declarator '(' parameter_type_list ')' { $$ = bdty(CALL, $1, $3); } | declarator '(' identifier_list ')' { $$ = bdty(CALL, $1, $3); oldstyle = 1; } | declarator '(' ')' { $$ = bdty(UCALL, $1); } ; type_qualifier_list: C_QUALIFIER { $$ = $1; $$->n_op = UMUL; } | type_qualifier_list C_QUALIFIER { $$ = $1; $$->n_qual |= $2->n_qual; nfree($2); } | attribute_specifier { $$ = block(UMUL, NIL, NIL, 0, 0, gcc_attr_wrapper($1)); } | type_qualifier_list attribute_specifier { $1->n_ap = attr_add($1->n_ap, gcc_attr_wrapper($2)); } ; identifier_list: C_NAME { $$ = bdty(NAME, $1); oldargs($$); } | identifier_list ',' C_NAME { $$ = cmop($1, bdty(NAME, $3)); oldargs($$->n_right); } ; /* * Returns as parameter_list, but can add an additional ELLIPSIS node. */ parameter_type_list: parameter_list { $$ = $1; } | parameter_list ',' C_ELLIPSIS { $$ = cmop($1, biop(ELLIPSIS, NIL, NIL)); } ; /* * Returns a linked lists of nodes of op CM with parameters on * its right and additional CM nodes of its left pointer. * No CM nodes if only one parameter. */ parameter_list: parameter_declaration { $$ = $1; } | parameter_declaration '&' { $$ = $1; } | parameter_list ',' parameter_declaration { $$ = cmop($1, $3); } ; /* * Returns a node pointer to the declaration. */ parameter_declaration: declaration_specifiers declarator attr_var { if (glval($1) != SNULL && glval($1) != REGISTER) uerror("illegal parameter class"); $$ = block(TYMERGE, $1, $2, INT, 0, gcc_attr_wrapper($3)); } | declaration_specifiers abstract_declarator { $$ = block(TYMERGE, $1, $2, INT, 0, 0); } | declaration_specifiers { $$ = block(TYMERGE, $1, bdty(NAME, NULL), INT, 0, 0); } ; abstract_declarator: '*' { $$ = bdty(UMUL, bdty(NAME, NULL)); } | '*' type_qualifier_list { $$ = $2; $$->n_left = bdty(NAME, NULL); } | '*' abstract_declarator { $$ = bdty(UMUL, $2); } | '*' type_qualifier_list abstract_declarator { $$ = $2; $$->n_left = $3; } | '(' abstract_declarator ')' { $$ = $2; } | '[' ']' attr_var { $$ = block(LB, bdty(NAME, NULL), bcon(NOOFFSET), INT, 0, gcc_attr_wrapper($3)); } | '[' e ']' attr_var { $$ = block(LB, bdty(NAME, NULL), $2, INT, 0, gcc_attr_wrapper($4)); } | abstract_declarator '[' ']' attr_var { $$ = block(LB, $1, bcon(NOOFFSET), INT, 0, gcc_attr_wrapper($4)); } | abstract_declarator '[' e ']' attr_var { $$ = block(LB, $1, $3, INT, 0, gcc_attr_wrapper($5)); } | '(' ')' { $$ = bdty(UCALL, bdty(NAME, NULL)); } | '(' ib2 parameter_type_list ')' { $$ = bdty(CALL, bdty(NAME, NULL), $3); } | abstract_declarator '(' ')' { $$ = bdty(UCALL, $1); } | abstract_declarator '(' ib2 parameter_type_list ')' { $$ = bdty(CALL, $1, $4); } ; ib2: { } ; /* * K&R arg declaration, between ) and { */ arg_dcl_list: arg_declaration | arg_dcl_list arg_declaration ; arg_declaration: declaration_specifiers arg_param_list ';' { nfree($1); } ; arg_param_list: declarator attr_var { olddecl(block(TYMERGE, ccopy($0), $1, INT, 0, 0), $2); } | arg_param_list ',' declarator attr_var { olddecl(block(TYMERGE, ccopy($0), $3, INT, 0, 0), $4); } ; /* * Declarations in beginning of blocks. */ block_item_list: block_item | block_item_list block_item ; block_item: declaration | statement ; /* * Here starts the old YACC code. */ /* * Variables are declared in init_declarator. */ declaration: declaration_specifiers ';' { tfree($1); fun_inline = 0; } | declaration_specifiers init_declarator_list ';' { tfree($1); fun_inline = 0; } ; /* * Normal declaration of variables. curtype contains the current type node. * Returns nothing, variables are declared in init_declarator. */ init_declarator_list: init_declarator { symclear(blevel); } | init_declarator_list ',' attr_var { $$ = $0; } init_declarator { uawarn($3, "init_declarator"); symclear(blevel); } ; enum_dcl: enum_head '{' moe_list optcomma '}' { $$ = enumdcl($1); } | C_ENUM C_NAME { $$ = enumref($2); } ; enum_head: C_ENUM { $$ = enumhd(NULL); } | C_ENUM C_NAME { $$ = enumhd($2); } ; moe_list: moe | moe_list ',' moe ; moe: C_NAME { moedef($1); } | C_TYPENAME { moedef($1); } | C_NAME '=' e { enummer = con_e($3); moedef($1); } | C_TYPENAME '=' e { enummer = con_e($3); moedef($1); } ; struct_dcl: str_head '{' struct_dcl_list '}' { NODE *p; $$ = dclstruct($1); if (pragma_allpacked) { p = bdty(CALL, bdty(NAME, "packed"), bcon(pragma_allpacked)); $$->n_ap = attr_add($$->n_ap,gcc_attr_wrapper(p)); } } | C_STRUCT attr_var C_NAME { $$ = rstruct($3,$1); uawarn($2, "struct_dcl"); } | C_STRUCT attr_var nmrec C_NAME { $$ = cxxrstruct($1,$2,$3,$4); uawarn($2, "struct_dcl"); } /*COMPAT_GCC*/ | str_head '{' '}' { $$ = dclstruct($1); } ; attr_var: { NODE *q, *p; p = pragma_aligned ? bdty(CALL, bdty(NAME, "aligned"), bcon(pragma_aligned)) : NIL; if (pragma_packed) { q = bdty(NAME, "packed"); p = (p == NIL ? q : cmop(p, q)); } pragma_aligned = pragma_packed = 0; $$ = p; } /*COMPAT_GCC*/ | attr_spec_list ; attr_spec_list: attribute_specifier | attr_spec_list attribute_specifier { $$ = cmop($1, $2); } ; str_head: C_STRUCT attr_var { $$ = bstruct(NULL, $1, $2); } | C_STRUCT attr_var C_NAME { $$ = bstruct($3, $1, $2); } ; struct_dcl_list: struct_declaration | struct_dcl_list struct_declaration ; struct_declaration: declaration_specifiers struct_declarator_list optsemi { tfree($1); } | C_NAME ':' { /* cxxaccess($1); */ } ; optsemi: ';' { } | optsemi ';' { werror("extra ; in struct"); } ; specifier_qualifier_list: merge_specifiers { $$ = typenode($1); } ; merge_specifiers: type_sq merge_specifiers { $$ = cmop($2, $1); } | type_sq { $$ = $1; } ; struct_declarator_list: struct_declarator { symclear(blevel); } | struct_declarator_list ',' { $$=$0; } struct_declarator { symclear(blevel); } ; struct_declarator: declarator attr_var { NODE *p; $1 = aryfix($1); p = tymerge($0, tymfix($1)); if ($2) p->n_ap = attr_add(p->n_ap, gcc_attr_wrapper($2)); soumemb(p, (char *)$1->n_sp, glval($0)); tfree(p); } | ':' e { int ie = con_e($2); if (fldchk(ie)) ie = 1; falloc(NULL, ie, $0); } | declarator ':' e { int ie = con_e($3); if (fldchk(ie)) ie = 1; if ($1->n_op == NAME) { /* XXX - tymfix() may alter $1 */ tymerge($0, tymfix($1)); soumemb($1, (char *)$1->n_sp, FIELD | ie); nfree($1); } else uerror("illegal declarator"); } | declarator ':' e attr_spec_list { int ie = con_e($3); if (fldchk(ie)) ie = 1; if ($1->n_op == NAME) { /* XXX - tymfix() may alter $1 */ tymerge($0, tymfix($1)); if ($4) $1->n_ap = attr_add($1->n_ap, gcc_attr_wrapper($4)); soumemb($1, (char *)$1->n_sp, FIELD | ie); nfree($1); } else uerror("illegal declarator"); } | /* unnamed member */ { NODE *p = $0; char *c = permalloc(10); if (p->n_type != STRTY && p->n_type != UNIONTY) uerror("bad unnamed member type"); snprintf(c, 10, "*%dFAKE", getlab()); soumemb(p, c, 0); } ; /* always preceeded by attributes */ xnfdeclarator: declarator attr_var { $$ = xnf = init_declarator($0, $1, 1, $2); } | declarator C_ASM '(' string ')' { pragma_renamed = newstring($4, strlen($4)); $$ = xnf = init_declarator($0, $1, 1, NULL); } ; /* * Handles declarations and assignments. * Returns nothing. */ init_declarator: declarator attr_var { init_declarator($0, $1, 0, $2);} | declarator C_ASM '(' string ')' attr_var { #ifdef GCC_COMPAT pragma_renamed = newstring($4, strlen($4)); init_declarator($0, $1, 0, $6); #else werror("gcc extension"); init_declarator($0, $1, 0, $6); #endif } | xnfdeclarator '=' e { if ($1->sclass == STATIC || $1->sclass == EXTDEF) statinit++; simpleinit($1, eve($3)); if ($1->sclass == STATIC || $1->sclass == EXTDEF) statinit--; xnf = NULL; } | xnfdeclarator '=' begbr init_list optcomma '}' { endinit(0); xnf = NULL; } /*COMPAT_GCC*/ | xnfdeclarator '=' begbr '}' { endinit(0); xnf = NULL; } | xnfdeclarator '=' addrlbl { simpleinit($1, $3); xnf = NULL; } ; begbr: '{' { beginit($-1); } ; initializer: e %prec ',' { $$ = eve($1); } | addrlbl { $$ = $1; } | ibrace init_list optcomma '}' { $$ = NULL; } | ibrace '}' { asginit(bcon(0)); $$ = NULL; } ; init_list: designation initializer { dainit($1, $2); } | init_list ',' designation initializer { dainit($3, $4); } ; designation: designator_list '=' { desinit($1); $$ = NIL; } | GCC_DESIG { desinit(bdty(NAME, $1)); $$ = NIL; } | '[' e C_ELLIPSIS e ']' '=' { $$ = biop(CM, $2, $4); } | { $$ = NIL; } ; designator_list: designator { $$ = $1; } | designator_list designator { $$ = $2; $$->n_left = $1; } ; designator: '[' e ']' { int ie = con_e($2); if (ie < 0) { uerror("designator must be non-negative"); ie = 0; } $$ = biop(LB, NIL, bcon(ie)); } | C_STROP C_TYPENAME { if ($1 != DOT) uerror("invalid designator"); $$ = bdty(NAME, $2); } | C_STROP C_NAME { if ($1 != DOT) uerror("invalid designator"); $$ = bdty(NAME, $2); } ; optcomma : /* VOID */ | ',' ; ibrace: '{' { ilbrace(); } ; /* STATEMENTS */ compoundstmt: begin block_item_list '}' { flend(); } | begin '}' { flend(); } ; begin: '{' { struct savbc *bc = tmpalloc(sizeof(struct savbc)); if (blevel == 1) { #ifdef STABS if (gflag) stabs_line(lineno); #endif dclargs(); } #ifdef STABS if (gflag && blevel > 1) stabs_lbrac(blevel+1); #endif ++blevel; oldstyle = 0; bc->contlab = autooff; bc->next = savctx; savctx = bc; if (!isinlining && sspflag && blevel == 2) sspstart(); } ; statement: e ';' { /* fwalk($1, eprint, 0); */ ecomp(eve($1)); symclear(blevel); } | compoundstmt | ifprefix statement { plabel($1); reached = 1; } | ifelprefix statement { if ($1 != NOLAB) { plabel( $1); reached = 1; } } | whprefix statement { branch(contlab); plabel( brklab ); if( (flostat&FBRK) || !(flostat&FLOOP)) reached = 1; else reached = 0; resetbc(0); } | doprefix statement C_WHILE '(' e ')' ';' { plabel(contlab); if (flostat & FCONT) reached = 1; if (reached) cbranch(buildtree(NE, eve($5), bcon(0)), bcon($1)); else tfree(eve($5)); plabel( brklab); reached = 1; resetbc(0); } | forprefix .e ')' statement { plabel( contlab ); if( flostat&FCONT ) reached = 1; if( $2 ) ecomp( $2 ); branch($1); plabel( brklab ); if( (flostat&FBRK) || !(flostat&FLOOP) ) reached = 1; else reached = 0; resetbc(0); symclear(blevel); /* if declaration inside for() */ } | switchpart statement { if( reached ) branch( brklab ); plabel( $1 ); swend(); plabel( brklab); if( (flostat&FBRK) || !(flostat&FDEF) ) reached = 1; resetbc(FCONT); } | C_BREAK ';' { if (brklab == NOLAB) uerror("illegal break"); else if (reached) branch(brklab); flostat |= FBRK; reached = 0; } | C_CONTINUE ';' { if (contlab == NOLAB) uerror("illegal continue"); else branch(contlab); flostat |= FCONT; goto rch; } | C_RETURN ';' { branch(retlab); if (cftnsp->stype != VOID && (cftnsp->sflags & NORETYP) == 0 && cftnsp->stype != VOID+FTN) uerror("return value required"); rch: if (!reached) warner(Wunreachable_code); reached = 0; } | C_RETURN e ';' { NODE *p, *q; p = nametree(cftnsp); p->n_type = DECREF(p->n_type); q = eve($2); #ifndef NO_COMPLEX if (ANYCX(q) || ANYCX(p)) q = cxret(q, p); #endif p = buildtree(RETURN, p, q); if (p->n_type == VOID) { ecomp(p->n_right); } else { if (cftnod == NIL) cftnod = tempnode(0, p->n_type, p->n_df, p->n_ap); ecomp(buildtree(ASSIGN, ccopy(cftnod), p->n_right)); } tfree(p->n_left); nfree(p); branch(retlab); reached = 0; } | C_GOTO C_NAME ';' { gotolabel($2); goto rch; } | C_GOTO '*' e ';' { ecomp(biop(GOTO, eve($3), NIL)); } | asmstatement ';' | ';' | error ';' | error '}' | label statement ; asmstatement: C_ASM mvol '(' string ')' { send_passt(IP_ASM, mkpstr($4)); } | C_ASM mvol '(' string xasm ')' { mkxasm($4, $5); } ; mvol: /* empty */ | C_QUALIFIER { nfree($1); } ; xasm: ':' oplist { $$ = xcmop($2, NIL, NIL); } | ':' oplist ':' oplist { $$ = xcmop($2, $4, NIL); } | ':' oplist ':' oplist ':' cnstr { $$ = xcmop($2, $4, $6); } ; oplist: /* nothing */ { $$ = NIL; } | oper { $$ = $1; } ; oper: string '(' e ')' { $$ = xasmop($1, eve($3)); } | oper ',' string '(' e ')' { $$ = cmop($1, xasmop($3, eve($5))); } ; cnstr: string { $$ = xasmop($1, bcon(0)); } | cnstr ',' string { $$ = cmop($1, xasmop($3, bcon(0))); } ; label: C_NAME ':' attr_var { deflabel($1, $3); reached = 1; } | C_TYPENAME ':' attr_var { deflabel($1, $3); reached = 1; } | C_CASE e ':' { addcase(eve($2)); reached = 1; } /* COMPAT_GCC */| C_CASE e C_ELLIPSIS e ':' { #ifdef GCC_COMPAT gcccase(eve($2), eve($4)); reached = 1; #endif } | C_DEFAULT ':' { reached = 1; adddef(); flostat |= FDEF; } ; doprefix: C_DO { savebc(); brklab = getlab(); contlab = getlab(); plabel( $$ = getlab()); reached = 1; } ; ifprefix: C_IF '(' e ')' { cbranch(buildtree(NOT, eve($3), NIL), bcon($$ = getlab())); reached = 1; } ; ifelprefix: ifprefix statement C_ELSE { if (reached) branch($$ = getlab()); else $$ = NOLAB; plabel( $1); reached = 1; } ; whprefix: C_WHILE '(' e ')' { savebc(); $3 = eve($3); if ($3->n_op == ICON && glval($3) != 0) flostat = FLOOP; plabel( contlab = getlab()); reached = 1; brklab = getlab(); if (flostat == FLOOP) tfree($3); else cbranch(buildtree(NOT, $3, NIL), bcon(brklab)); } ; forprefix: C_FOR '(' .e ';' .e ';' { if ($3) ecomp($3); savebc(); contlab = getlab(); brklab = getlab(); plabel( $$ = getlab()); reached = 1; if ($5) cbranch(buildtree(NOT, $5, NIL), bcon(brklab)); else flostat |= FLOOP; } | C_FOR '(' { ++blevel; } declaration .e ';' { blevel--; savebc(); contlab = getlab(); brklab = getlab(); plabel( $$ = getlab()); reached = 1; if ($5) cbranch(buildtree(NOT, $5, NIL), bcon(brklab)); else flostat |= FLOOP; } ; switchpart: C_SWITCH '(' e ')' { NODE *p; int num; TWORD t; savebc(); brklab = getlab(); $3 = eve($3); if (!ISINTEGER($3->n_type)) { uerror("switch expression must have integer " "type"); t = INT; } else { $3 = intprom($3); t = $3->n_type; } p = tempnode(0, t, 0, 0); num = regno(p); ecomp(buildtree(ASSIGN, p, $3)); branch( $$ = getlab()); swstart(num, t); reached = 0; } ; /* EXPRESSIONS */ .e: e { $$ = eve($1); } | { $$=0; } ; elist: { $$ = NIL; } | e %prec ',' | elist ',' e { $$ = biop(CM, $1, $3); } | elist ',' cast_type { /* hack for stdarg */ TYMFIX($3); $3->n_op = TYPE; $$ = biop(CM, $1, $3); } ; /* * Precedence order of operators. */ e: e ',' e { $$ = biop(COMOP, $1, $3); } | e '=' e { $$ = biop(ASSIGN, $1, $3); } | e C_ASOP e { $$ = biop($2, $1, $3); } | e '?' e ':' e { $$=biop(QUEST, $1, biop(COLON, $3, $5)); } | e '?' ':' e { NODE *p = tempnode(0, $1->n_type, $1->n_df, $1->n_ap); $$ = biop(COLON, ccopy(p), $4); $$=biop(QUEST, biop(ASSIGN, p, $1), $$); } | e C_OROR e { $$ = biop($2, $1, $3); } | e C_ANDAND e { $$ = biop($2, $1, $3); } | e '|' e { $$ = biop(OR, $1, $3); } | e '^' e { $$ = biop(ER, $1, $3); } | e '&' e { $$ = biop(AND, $1, $3); } | e C_EQUOP e { $$ = biop($2, $1, $3); } | e C_RELOP e { $$ = biop($2, $1, $3); } | e C_SHIFTOP e { $$ = biop($2, $1, $3); } | e '+' e { $$ = biop(PLUS, $1, $3); } | e '-' e { $$ = biop(MINUS, $1, $3); } | e C_DIVOP e { $$ = biop($2, $1, $3); } | e '*' e { $$ = biop(MUL, $1, $3); } | e '=' addrlbl { $$ = biop(ASSIGN, $1, $3); } | term ; xbegin: begin { $$ = getlab(); getlab(); getlab(); branch($$); plabel(($$)+1); } ; addrlbl: C_ANDAND C_NAME { #ifdef GCC_COMPAT struct symtab *s = lookup($2, SLBLNAME); if (s->soffset == 0) s->soffset = -getlab(); $$ = buildtree(ADDROF, nametree(s), NIL); #else uerror("gcc extension"); #endif } ; term: term C_INCOP { $$ = biop($2, $1, bcon(1)); } | '*' term { $$ = biop(UMUL, $2, NIL); } | '&' term { $$ = biop(ADDROF, $2, NIL); } | '-' term { $$ = biop(UMINUS, $2, NIL ); } | '+' term { $$ = biop(PLUS, $2, bcon(0)); } | CXX_CASTS C_RELOP cast_type C_RELOP '(' e ')' { tfree($6); tfree($3); $$ = bcon(0); werror("CXX_CASTS unhandled"); } | C_UNOP term { $$ = biop($1, $2, NIL); } | C_INCOP term { $$ = biop($1 == INCR ? PLUSEQ : MINUSEQ, $2, bcon(1)); } | C_SIZEOF xa term { $$ = biop(SZOF, $3, bcon(0)); inattr = $2; } | '(' cast_type ')' term %prec C_INCOP { TYMFIX($2); $$ = biop(CAST, $2, $4); } | C_SIZEOF xa '(' cast_type ')' %prec C_SIZEOF { $$ = biop(SZOF, $4, bcon(1)); inattr = $2; } | C_ALIGNOF xa '(' cast_type ')' { int al; TYMFIX($4); al = talign($4->n_type, $4->n_ap); $$ = bcon(al/SZCHAR); inattr = $2; tfree($4); } | '(' cast_type ')' clbrace init_list optcomma '}' { endinit(0); $$ = bdty(NAME, $4); $$->n_op = CLOP; } | '(' cast_type ')' clbrace '}' { endinit(0); $$ = bdty(NAME, $4); $$->n_op = CLOP; } | term '[' e ']' { if ($1->n_op == NEWKW) { $1->n_left = biop(LB, $1->n_left, $3); } else $$ = biop(LB, $1, $3); } | C_NAME '(' elist ')' { #if 0 if ($3) tfree($3); $$ = bcon(0); #else $$ = biop($3 ? CALL : UCALL, bdty(NAME, $1), $3); #endif } | term '(' elist ')' { $$ = biop($3 ? CALL : UCALL, $1, $3); } | term C_STROP C_NAME { $$ = biop($2, $1, bdty(NAME, $3)); } | term C_STROP C_TYPENAME { $$ = biop($2, $1, bdty(NAME, $3));} | C_NAME %prec C_SIZEOF /* below ( */{ $$ = bdty(NAME, $1); } | nmrec C_NAME %prec C_SIZEOF { $$ = biop(NMLIST, $1, bdty(NAME, $2)); } | PCC_OFFSETOF '(' cast_type ',' term ')' { TYMFIX($3); $3->n_type = INCREF($3->n_type); $3 = biop(CAST, $3, bcon(0)); if ($5->n_op == NAME) { $$ = biop(STREF, $3, $5); } else { NODE *p = $5; while (p->n_left->n_op != NAME) p = p->n_left; p->n_left = biop(STREF, $3, p->n_left); $$ = $5; } $$ = biop(ADDROF, $$, NIL); $3 = block(NAME, NIL, NIL, ENUNSIGN(INTPTR), 0, 0); $$ = biop(CAST, $3, $$); } | C_ICON { $$ = $1; } | C_FCON { $$ = $1; } | string { $$ = bdty(STRING, $1, widestr); } | '(' e ')' { $$=$2; } | '(' xbegin block_item_list e ';' '}' ')' { /* XXX - check recursive ({ }) statements */ branch(($2)+2); plabel($2); $$ = buildtree(COMOP, biop(GOTO, bcon(($2)+1), NIL), eve($4)); flend(); } | '(' xbegin block_item_list '}' ')' { /* XXX - check recursive ({ }) statements */ branch(($2)+2); plabel($2); $$ = buildtree(COMOP, biop(GOTO, bcon(($2)+1), NIL), voidcon()); flend(); } | CXX_NEW new_ds { $$ = biop(NEWKW, $2, bcon(0)); } | CXX_NEW '(' cast_type ')' { $$ = 0; uerror("new cast"); } | CXX_DELETE term %prec '-' { $$ = biop(DELETE, $2, bcon(NM_DEL)); } | CXX_DELETE '[' ']' term %prec '-' { $$ = biop(DELETE, $4, bcon(NM_DLA)); } ; nmrec: CXX_MORENM { $$ = bdty(NAME, $1); } | CXX_MORENM nmrec { $$ = biop(NMLIST, $2, bdty(NAME, $1)); } ; xa: { $$ = inattr; inattr = 0; } ; clbrace: '{' { NODE *q = $-1; TYMFIX(q); $$ = clbrace(q); } ; string: C_STRING { widestr = 0; $$ = stradd("", $1); } | string C_STRING { $$ = stradd($1, $2); } ; cast_type: specifier_qualifier_list { $$ = biop(TYMERGE, $1, bdty(NAME, NULL)); } | specifier_qualifier_list abstract_declarator { $$ = biop(TYMERGE, $1, aryfix($2)); } ; %% NODE * mkty(TWORD t, union dimfun *d, struct attr *sue) { return block(TYPE, NIL, NIL, t, d, sue); } NODE * bdty(int op, ...) { va_list ap; int val; register NODE *q; va_start(ap, op); q = biop(op, NIL, NIL); switch (op) { case UMUL: case UCALL: q->n_left = va_arg(ap, NODE *); q->n_rval = 0; break; case CALL: q->n_left = va_arg(ap, NODE *); q->n_right = va_arg(ap, NODE *); break; case LB: q->n_left = va_arg(ap, NODE *); if ((val = va_arg(ap, int)) <= 0) { uerror("array size must be positive"); val = 1; } q->n_right = bcon(val); break; case NAME: q->n_sp = va_arg(ap, struct symtab *); /* XXX survive tymerge */ break; case STRING: q->n_name = va_arg(ap, char *); val = va_arg(ap, int); slval(q, val); break; default: cerror("bad bdty"); } va_end(ap); return q; } static void flend(void) { if (!isinlining && sspflag && blevel == 2) sspend(); #ifdef STABS if (gflag && blevel > 2) stabs_rbrac(blevel); #endif --blevel; if( blevel == 1 ) blevel = 0; symclear(blevel); /* Clean ut the symbol table */ if (autooff > maxautooff) maxautooff = autooff; autooff = savctx->contlab; savctx = savctx->next; } static void savebc(void) { struct savbc *bc = tmpalloc(sizeof(struct savbc)); bc->brklab = brklab; bc->contlab = contlab; bc->flostat = flostat; bc->next = savbc; savbc = bc; flostat = 0; } static void resetbc(int mask) { flostat = savbc->flostat | (flostat&mask); contlab = savbc->contlab; brklab = savbc->brklab; savbc = savbc->next; } struct swdef { struct swdef *next; /* Next in list */ int deflbl; /* Label for "default" */ struct swents *ents; /* Linked sorted list of case entries */ int nents; /* # of entries in list */ int num; /* Node value will end up in */ TWORD type; /* Type of switch expression */ } *swpole; /* * add case to switch */ static void addcase(NODE *p) { struct swents **put, *w, *sw = tmpalloc(sizeof(struct swents)); CONSZ val; p = optim(rmpconv(p)); /* change enum to ints */ if (p->n_op != ICON || p->n_sp != NULL) { uerror( "non-constant case expression"); return; } if (swpole == NULL) { uerror("case not in switch"); return; } if (DEUNSIGN(swpole->type) != DEUNSIGN(p->n_type)) { val = glval(p); p = makety(p, swpole->type, 0, 0, 0); if (p->n_op != ICON) cerror("could not cast case value to type of switch " "expression"); if (glval(p) != val) werror("case expression truncated"); } sw->sval = glval(p); tfree(p); put = &swpole->ents; if (ISUNSIGNED(swpole->type)) { for (w = swpole->ents; w != NULL && (U_CONSZ)w->sval < (U_CONSZ)sw->sval; w = w->next) put = &w->next; } else { for (w = swpole->ents; w != NULL && w->sval < sw->sval; w = w->next) put = &w->next; } if (w != NULL && w->sval == sw->sval) { uerror("duplicate case in switch"); return; } plabel(sw->slab = getlab()); *put = sw; sw->next = w; swpole->nents++; } #ifdef GCC_COMPAT void gcccase(NODE *ln, NODE *hn) { CONSZ i, l, h; l = icons(optim(ln)); h = icons(optim(hn)); if (h < l) i = l, l = h, h = i; for (i = l; i <= h; i++) addcase(xbcon(i, NULL, hn->n_type)); } #endif /* * add default case to switch */ static void adddef(void) { if (swpole == NULL) uerror("default not inside switch"); else if (swpole->deflbl != 0) uerror("duplicate default in switch"); else plabel( swpole->deflbl = getlab()); } static void swstart(int num, TWORD type) { struct swdef *sw = tmpalloc(sizeof(struct swdef)); sw->deflbl = sw->nents = 0; sw->ents = NULL; sw->next = swpole; sw->num = num; sw->type = type; swpole = sw; } /* * end a switch block */ static void swend(void) { struct swents *sw, **swp; int i; sw = tmpalloc(sizeof(struct swents)); swp = tmpalloc(sizeof(struct swents *) * (swpole->nents+1)); sw->slab = swpole->deflbl; swp[0] = sw; for (i = 1; i <= swpole->nents; i++) { swp[i] = swpole->ents; swpole->ents = swpole->ents->next; } genswitch(swpole->num, swpole->type, swp, swpole->nents); swpole = swpole->next; } /* * num: tempnode the value of the switch expression is in * type: type of the switch expression * * p points to an array of structures, each consisting * of a constant value and a label. * The first is >=0 if there is a default label; * its value is the label number * The entries p[1] to p[n] are the nontrivial cases * n is the number of case statements (length of list) */ static void genswitch(int num, TWORD type, struct swents **p, int n) { NODE *r, *q; int i; if (mygenswitch(num, type, p, n)) return; /* simple switch code */ for (i = 1; i <= n; ++i) { /* already in 1 */ r = tempnode(num, type, 0, 0); q = xbcon(p[i]->sval, NULL, type); r = buildtree(NE, r, clocal(q)); cbranch(buildtree(NOT, r, NIL), bcon(p[i]->slab)); } if (p[0]->slab > 0) branch(p[0]->slab); } /* * Declare a variable or prototype. */ static struct symtab * init_declarator(NODE *tn, NODE *p, int assign, NODE *a) { int class = (int)glval(tn); struct symtab *sp; p = aryfix(p); if (p->n_op == NMLIST) { tymerge(tn, p->n_right); } else p = tymerge(tn, p); if (a) { struct attr *ap = gcc_attr_wrapper(a); p->n_ap = attr_add(p->n_ap, ap); } sp = cxxdeclvar(p); if (fun_inline && ISFTN(p->n_type)) sp->sflags |= SINLINE; if (!ISFTN(p->n_type)) { if (assign) { defid(p, class); sp = p->n_sp; sp->sflags |= SASG; if (sp->sflags & SDYNARRAY) uerror("can't initialize dynamic arrays"); lcommdel(sp); } else nidcl(p, class); } else { extern NODE *parlink; if (assign) uerror("cannot initialise function"); defid(p, uclass(class)); sp = p->n_sp; if (parlink) { /* dynamic sized arrays in prototypes */ tfree(parlink); /* Free delayed tree */ parlink = NIL; } } tfree(p); return sp; } /* * Declare old-stype function arguments. */ static void oldargs(NODE *p) { blevel++; p->n_op = TYPE; p->n_type = FARG; p->n_sp = lookup((char *)p->n_sp, 0);/* XXX */ defid(p, PARAM); blevel--; } /* * Set NAME nodes to a null name and index of LB nodes to NOOFFSET * unless clr is one, in that case preserve variable name. */ static NODE * namekill(NODE *p, int clr) { NODE *q; int o = p->n_op; switch (coptype(o)) { case LTYPE: if (o == NAME) { if (clr) p->n_sp = NULL; else p->n_sp = lookup((char *)p->n_sp, 0);/* XXX */ } break; case UTYPE: p->n_left = namekill(p->n_left, clr); break; case BITYPE: p->n_left = namekill(p->n_left, clr); if (o == LB) { if (clr) { tfree(p->n_right); p->n_right = bcon(NOOFFSET); } else p->n_right = eve(p->n_right); } else if (o == CALL) p->n_right = namekill(p->n_right, 1); else p->n_right = namekill(p->n_right, clr); if (o == TYMERGE) { q = tymerge(p->n_left, p->n_right); q->n_ap = attr_add(q->n_ap, p->n_ap); tfree(p->n_left); nfree(p); p = q; } break; } return p; } /* * Declare function arguments. */ static NODE * funargs(NODE *p) { extern NODE *arrstk[10]; if (p->n_op == ELLIPSIS) return p; p = namekill(p, 0); if (ISFTN(p->n_type)) p->n_type = INCREF(p->n_type); if (ISARY(p->n_type)) { p->n_type += (PTR-ARY); if (p->n_df->ddim == -1) tfree(arrstk[0]), arrstk[0] = NIL; p->n_df++; } if (p->n_type == VOID && p->n_sp->sname == NULL) return p; /* sanitycheck later */ else if (p->n_sp->sname == NULL) ; /* uerror("argument missing"); */ else defid(p, PARAM); return p; } static NODE * listfw(NODE *p, NODE * (*f)(NODE *)) { if (p->n_op == CM) { p->n_left = listfw(p->n_left, f); p->n_right = (*f)(p->n_right); } else p = (*f)(p); return p; } /* * Declare a function. */ static struct symtab * fundef(NODE *tp, NODE *p) { extern int prolab; struct symtab *s, *nsthis; NODE *q, *typ; int class = (int)glval(tp), oclass, ctval; char *c; /* * We discard all names except for those needed for * parameter declaration. While doing that, also change * non-constant array sizes to unknown. */ ctval = tvaloff; for (q = p; coptype(q->n_op) != LTYPE && q->n_left->n_op != NAME && q->n_left->n_op != NMLIST; q = q->n_left) { if (q->n_op == CALL) q->n_right = namekill(q->n_right, 1); } if (q->n_op != CALL && q->n_op != UCALL) { uerror("invalid function definition"); p = bdty(UCALL, p); } else if (q->n_op == CALL) { blevel = 1; argoff = ARGINIT; if (oldstyle == 0) q->n_right = listfw(q->n_right, funargs); ftnarg(q); blevel = 0; } if (p->n_op == CALL && p->n_left->n_op == NMLIST) { NODE *r = p->n_left; p->n_left = r->n_right; r->n_right = typ = tymerge(tp, p); p = r; } else typ = tymerge(tp, p); #ifdef GCC_COMPAT /* gcc seems to discard __builtin_ when declaring functions */ if (strncmp("__builtin_", (char *)typ->n_sp, 10) == 0) typ->n_sp = (struct symtab *)((char *)typ->n_sp + 10); #endif s = cxxftnfind(p, SNORMAL); nsthis = nscur; nscur = s->sdown; /* XXX fun in fun? */ oclass = s->sclass; if (class == STATIC && oclass == EXTERN) werror("%s was first declared extern, then static", s->sname); if (fun_inline) { /* special syntax for inline functions */ if (! strcmp(s->sname,"main")) uerror("cannot inline main()"); s->sflags |= SINLINE; inline_start(s); if (class == EXTERN) class = EXTDEF; } else if (class == EXTERN) class = SNULL; /* same result */ cftnsp = s; #if 0 defid(p, class); #endif #ifdef GCC_COMPAT if (attr_find(p->n_ap, GCC_ATYP_ALW_INL)) { /* Temporary turn on temps to make always_inline work */ alwinl = 1; if (xtemps == 0) alwinl |= 2; xtemps = 1; } #endif prolab = getlab(); if ((c = cftnsp->soname) == NULL) c = addname(exname(cftnsp->sname)); send_passt(IP_PROLOG, -1, c, cftnsp->stype, cftnsp->sclass == EXTDEF, prolab, ctval); blevel++; #ifdef STABS if (gflag) stabs_func(s); #endif tfree(tp); tfree(p); return nsthis; } static void fend(struct symtab *ns) { if (blevel) cerror("function level error"); ftnend(); fun_inline = 0; if (alwinl & 2) xtemps = 0; alwinl = 0; cftnsp = NULL; nscur = ns; } NODE * structref(NODE *p, int f, char *name) { NODE *r; if (f == DOT) p = buildtree(ADDROF, p, NIL); r = biop(NAME, NIL, NIL); r->n_name = name; r = buildtree(STREF, p, r); return r; } static void olddecl(NODE *p, NODE *a) { struct symtab *s; p = namekill(p, 0); s = p->n_sp; if (s->slevel != 1 || s->stype == UNDEF) uerror("parameter '%s' not defined", s->sname); else if (s->stype != FARG) uerror("parameter '%s' redefined", s->sname); s->stype = p->n_type; s->sdf = p->n_df; s->sap = p->n_ap; if (ISARY(s->stype)) { s->stype += (PTR-ARY); s->sdf++; } else if (s->stype == FLOAT) s->stype = DOUBLE; if (a) attr_add(s->sap, gcc_attr_wrapper(a)); nfree(p); } void branch(int lbl) { int r = reached++; ecomp(biop(GOTO, bcon(lbl), NIL)); reached = r; } /* * Create a printable string based on an encoded string. */ static char * mkpstr(char *str) { char *s, *os; int v, l = (int)strlen(str)+3; /* \t + \n + \0 */ os = s = inlalloc(l); *s++ = '\t'; for (; *str; ) { if (*str++ == '\\') v = esccon(&str); else v = str[-1]; *s++ = v; } *s++ = '\n'; *s = 0; return os; } /* * Estimate the max length a string will have in its internal * representation based on number of \ characters. */ static int maxstlen(char *str) { int i; for (i = 0; *str; str++, i++) if (*str == '\\' || *str < 32 || *str > 0176) i += 3; return i; } static char * voct(char *d, unsigned int v) { v &= (1 << SZCHAR) - 1; *d++ = '\\'; *d++ = v/64 + '0'; v &= 077; *d++ = v/8 + '0'; v &= 7; *d++ = v + '0'; return d; } /* * Convert a string to internal format. The resulting string may be no * more than len characters long. */ static void fixstr(char *d, char *s, int len) { unsigned int v; while (*s) { if (len <= 0) cerror("fixstr"); if (*s == '\\') { s++; v = esccon(&s); d = voct(d, v); len -= 4; } else if (*s < ' ' || *s > 0176) { d = voct(d, *s++); len -= 4; } else *d++ = *s++, len--; } *d = 0; } /* * Add "raw" string new to cleaned string old. */ static char * stradd(char *old, char *new) { char *rv; int len; if (*new == 'L' && new[1] == '\"') widestr = 1, new++; if (*new == '\"') { new++; /* remove first " */ new[strlen(new) - 1] = 0;/* remove last " */ } len = (int)strlen(old) + maxstlen(new) + 1; rv = tmpalloc(len); strlcpy(rv, old, len); fixstr(rv + strlen(old), new, maxstlen(new) + 1); return rv; } /* * Fake a symtab entry for compound literals. */ static struct symtab * clbrace(NODE *p) { struct symtab *sp; sp = getsymtab(simname("cl"), STEMP); sp->stype = p->n_type; sp->squal = p->n_qual; sp->sdf = p->n_df; sp->sap = p->n_ap; tfree(p); if (blevel == 0 && xnf != NULL) { sp->sclass = STATIC; sp->slevel = 2; sp->soffset = getlab(); } else { sp->sclass = blevel ? AUTO : STATIC; if (!ISARY(sp->stype) || sp->sdf->ddim != NOOFFSET) { sp->soffset = NOOFFSET; oalloc(sp, &autooff); } } beginit(sp); return sp; } char * simname(char *s) { int len = (int)strlen(s) + 10 + 1; char *w = tmpalloc(len); snprintf(w, len, "%s%d", s, getlab()); return w; } NODE * biop(int op, NODE *l, NODE *r) { return block(op, l, r, INT, 0, 0); } static NODE * cmop(NODE *l, NODE *r) { return biop(CM, l, r); } static NODE * voidcon(void) { return block(ICON, NIL, NIL, STRTY, 0, 0); } /* Support for extended assembler a' la' gcc style follows below */ static NODE * xmrg(NODE *out, NODE *in) { NODE *p = in; if (p->n_op == XARG) { in = cmop(out, p); } else { while (p->n_left->n_op == CM) p = p->n_left; p->n_left = cmop(out, p->n_left); } return in; } /* * Put together in and out node lists in one list, and balance it with * the constraints on the right side of a CM node. */ static NODE * xcmop(NODE *out, NODE *in, NODE *str) { NODE *p, *q; if (out) { /* D out-list sanity check */ for (p = out; p->n_op == CM; p = p->n_left) { q = p->n_right; if (q->n_name[0] != '=' && q->n_name[0] != '+') uerror("output missing ="); } if (p->n_name[0] != '=' && p->n_name[0] != '+') uerror("output missing ="); if (in == NIL) p = out; else p = xmrg(out, in); } else if (in) { p = in; } else p = voidcon(); if (str == NIL) str = voidcon(); return cmop(p, str); } /* * Generate a XARG node based on a string and an expression. */ static NODE * xasmop(char *str, NODE *p) { p = biop(XARG, p, NIL); p->n_name = isinlining ? newstring(str, strlen(str)) : str; return p; } /* * Generate a XASM node based on a string and an expression. */ static void mkxasm(char *str, NODE *p) { NODE *q; q = biop(XASM, p->n_left, p->n_right); q->n_name = isinlining ? newstring(str, strlen(str)) : str; nfree(p); ecomp(q); } static struct attr * gcc_attr_wrapper(NODE *p) { #ifdef GCC_COMPAT return gcc_attr_parse(p); #else uerror("gcc attribute used"); return NULL; #endif } #ifdef GCC_COMPAT static NODE * tyof(NODE *p) { static struct symtab spp; NODE *q = block(TYPE, NIL, NIL, p->n_type, p->n_df, p->n_ap); q->n_qual = p->n_qual; q->n_sp = &spp; /* for typenode */ tfree(p); return q; } #else static NODE * tyof(NODE *p) { uerror("typeof gcc extension"); return bcon(0); } #endif /* * Rewrite ++/-- to (t=p, p++, t) ops on types that do not act act as usual. */ static NODE * rewincop(NODE *p1, NODE *p2, int op) { NODE *t, *r; t = cstknode(p1->n_type, 0, 0); r = buildtree(ASSIGN, ccopy(t), ccopy(p1)); r = buildtree(COMOP, r, buildtree(op, p1, eve(p2))); return buildtree(COMOP, r, t); } /* * Traverse an unhandled expression tree bottom-up and call buildtree() * or equivalent as needed. */ NODE * eve(NODE *p) { struct symtab *sp; NODE *r, *p1, *p2; int x; p1 = p->n_left; p2 = p->n_right; switch (p->n_op) { case NMLIST: case NAME: sp = cxxlookup(p, SNORMAL|SNOCREAT); if (sp->sflags & SINLINE) inline_ref(sp); r = nametree(sp); if (sp->sflags & SDYNARRAY) r = buildtree(UMUL, r, NIL); #ifdef GCC_COMPAT if (attr_find(sp->sap, GCC_ATYP_DEPRECATED)) warner(Wdeprecated_declarations, sp->sname); #endif break; case DOT: case STREF: r = cxxstructref(eve(p1), p->n_op, (char *)p2->n_sp); nfree(p2); break; case CAST: p1 = buildtree(CAST, p1, eve(p2)); nfree(p1->n_left); r = p1->n_right; nfree(p1); break; case SZOF: x = xinline; xinline = 0; /* XXX hack */ if (glval(p2) == 0) p1 = eve(p1); else TYMFIX(p1); nfree(p2); r = doszof(p1); xinline = x; break; case LB: p1 = eve(p->n_left); r = buildtree(UMUL, buildtree(PLUS, p1, eve(p2)), NIL); break; case COMPL: #ifndef NO_COMPLEX p1 = eve(p1); if (ANYCX(p1)) r = cxconj(p1); else r = buildtree(COMPL, p1, NIL); break; #endif case UMINUS: case NOT: case UMUL: r = buildtree(p->n_op, eve(p->n_left), NIL); break; case ADDROF: r = eve(p1); if (ISFTN(p->n_type)/* || ISARY(p->n_type) */){ #ifdef notdef werror( "& before array or function: ignored" ); #endif } else r = buildtree(ADDROF, r, NIL); break; case CALL: case UCALL: if (p1->n_op == NAME || p1->n_op == NMLIST) { sp = cxxlookup(p1, SNORMAL); #ifndef NO_C_BUILTINS if (sp->sflags & SBUILTIN) { nfree(p1); r = builtin_check(sp, p2); break; } #endif if (sp->stype == UNDEF) { p1->n_type = FTN|INT; p1->n_sp = sp; p1->n_ap = NULL; defid(p1, EXTERN); } nfree(p1); #ifdef GCC_COMPAT if (attr_find(sp->sap, GCC_ATYP_DEPRECATED)) warner(Wdeprecated_declarations, sp->sname); #endif p2 = p->n_op == CALL ? eve(p2) : NIL; r = doacall(sp, nametree(sp), p2, 0); } else if (p1->n_op == DOT || p1->n_op == STREF) { /* * function as member of a struct. * - check args for correct overloaded function * - add hidden arg0 as pointer to this struct */ p2 = p->n_op == CALL ? eve(p2) : NIL; p1->n_left = eve(p1->n_left); /* eval rest */ r = cxxmatchftn(p1, p2); if (p1->n_op == DOT) p1->n_left = buildtree(ADDROF, p1->n_left, NIL); nfree(p1->n_right); p1 = nfree(p1); p2 = cxxaddhidden(p2, p1); r = doacall(NULL, r, p2, 1); } else { p2 = p->n_op == CALL ? eve(p2) : NIL; r = doacall(NULL, eve(p1), p2, 0); } break; #ifndef NO_COMPLEX case XREAL: case XIMAG: p1 = eve(p1); r = cxelem(p->n_op, p1); break; #endif case MUL: case DIV: case PLUS: case MINUS: case ASSIGN: case EQ: case NE: #ifndef NO_COMPLEX p1 = eve(p1); p2 = eve(p2); if (ANYCX(p1) || ANYCX(p2)) { r = cxop(p->n_op, p1, p2); } else if (ISITY(p1->n_type) || ISITY(p2->n_type)) { r = imop(p->n_op, p1, p2); } else r = buildtree(p->n_op, p1, p2); break; #endif case MOD: case CM: case GT: case GE: case LT: case LE: case RS: case LS: case RSEQ: case LSEQ: case AND: case OR: case ER: case OROR: case ANDAND: case EREQ: case OREQ: case ANDEQ: case QUEST: case COLON: p1 = eve(p1); eve2: r = buildtree(p->n_op, p1, eve(p2)); break; case INCR: case DECR: p1 = eve(p1); if (p1->n_type >= FLOAT && p1->n_type <= LDOUBLE) { /* ++/-- on floats isn't ((d+=1)-1) */ /* rewrite to (t=d,d++,t) */ /* XXX - side effects */ r = rewincop(p1, p2, p->n_op); break; } if (p1->n_type != BOOL) goto eve2; /* Hey, fun. ++ will always be 1, and -- will toggle result */ if (p->n_op == INCR) { /* (t=d,d=1,t) */ r = rewincop(p1, p2, ASSIGN); } else { /* (t=d,d^=1,t) */ r = rewincop(p1, p2, EREQ); } break; case MODEQ: case MINUSEQ: case PLUSEQ: case MULEQ: case DIVEQ: p1 = eve(p1); p2 = eve(p2); #ifndef NO_COMPLEX if (ANYCX(p1) || ANYCX(p2)) { r = cxop(UNASG p->n_op, ccopy(p1), p2); r = cxop(ASSIGN, p1, r); break; } else if (ISITY(p1->n_type) || ISITY(p2->n_type)) { r = imop(UNASG p->n_op, ccopy(p1), p2); r = cxop(ASSIGN, p1, r); break; } /* FALLTHROUGH */ #endif if (p1->n_type == BOOL) { r = buildtree(UNASG p->n_op, ccopy(p1), p2); r = buildtree(ASSIGN, p1, r); } else { r = buildtree(p->n_op, p1, p2); } break; case STRING: r = strend(glval(p), p->n_name); break; case COMOP: if (p1->n_op == GOTO) { /* inside ({ }), eve already called */ r = buildtree(p->n_op, p1, p2); } else { p1 = eve(p1); r = buildtree(p->n_op, p1, eve(p2)); } break; case TYPE: case ICON: case FCON: case TEMP: return p; case CLOP: r = nametree(p->n_sp); break; case DELETE: p1 = eve(p1); r = cxx_delete(p1, glval(p2)); nfree(p2); break; case NEWKW: r = cxx_new(p1); nfree(p2); break; default: #ifdef PCC_DEBUG fwalk(p, eprint, 0); #endif cerror("eve"); r = NIL; } nfree(p); return r; } int con_e(NODE *p) { #ifdef WORD_ADDRESSED return (int)icons(optim(eve(p))); #else return (int)icons(optim(rmpconv(eve(p)))); #endif } void uawarn(NODE *p, char *s) { if (p == 0) return; if (attrwarn) werror("unhandled %s attribute", s); tfree(p); } static void dainit(NODE *d, NODE *a) { if (d == NULL) { asginit(a); } else if (d->n_op == CM) { int is = con_e(d->n_left); int ie = con_e(d->n_right); int i; nfree(d); if (ie < is) uerror("negative initializer range"); desinit(biop(LB, NIL, bcon(is))); for (i = is; i < ie; i++) asginit(ccopy(a)); asginit(a); } else { cerror("dainit"); } } /* * Traverse down and tymerge() where appropriate. */ static NODE * tymfix(NODE *p) { NODE *q; int o = coptype(p->n_op); switch (o) { case LTYPE: break; case UTYPE: p->n_left = tymfix(p->n_left); break; case BITYPE: p->n_left = tymfix(p->n_left); p->n_right = tymfix(p->n_right); if (p->n_op == TYMERGE) { q = tymerge(p->n_left, p->n_right); q->n_ap = attr_add(q->n_ap, p->n_ap); tfree(p->n_left); nfree(p); p = q; } break; } return p; } static NODE * aryfix(NODE *p) { NODE *q; for (q = p; q->n_op != NAME; q = q->n_left) { if (q->n_op == LB) { q->n_right = optim(rmpconv(eve(q->n_right))); if ((blevel == 0 || rpole != NULL) && !nncon(q->n_right)) uerror("array size not constant"); /* * Checks according to 6.7.5.2 clause 1: * "...the expression shall have an integer type." * "If the expression is a constant expression, * it shall have a value greater than zero." */ if (!ISINTEGER(q->n_right->n_type)) werror("array size is not an integer"); else if (q->n_right->n_op == ICON && glval(q->n_right) < 0 && glval(q->n_right) != NOOFFSET) { uerror("array size cannot be negative"); slval(q->n_right, 1); } } else if (q->n_op == CALL) q->n_right = namekill(q->n_right, 1); } return p; } pcc-20181216/cc/cxxcom/cxxcode.c010064400017500000000000000441021277716665000151750ustar raggewheel/* $Id: cxxcode.c,v 1.7 2016/10/11 13:48:24 ragge Exp $ */ /* * Copyright (c) 2011 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ # include "pass1.h" struct symtab spole0 = { 0, 0, 0, 0, 0, 0, 0, "base", "base", }; struct symtab *spole = &spole0; struct symtab *nscur = &spole0; int elnk, nsptr; static struct symtab *sfind(char *n, struct symtab *sp); /* * Declare a namespace. */ void dclns(NODE *attr, char *n) { struct symtab *sp; #ifdef GCC_COMPAT struct attr *ap = gcc_attr_parse(attr); #else struct attr *ap = NULL; #endif if (cppdebug)printf("declaring namespace %s\n", n); n = addname(n); sp = sfind(n, nscur->sup); while (sp != NULL) { if (sp->sname == n && sp->sclass == NSPACE) break; sp = sfind(n, sp->snext); } if (sp == NULL) { /* New namespace */ sp = getsymtab(n, 0); sp->sclass = NSPACE; INSSYM(sp); } nscur = sp; if (cppdebug)printf("declaring namespace2 %s\n", nscur->sname); sp->sap = attr_add(sp->sap, ap); /* XXX check attributes */ } /* * Generate a call tree to function named n. */ static NODE * callftn(char *n, ...) { struct symtab *sp = getsymtab(n, 0); NODE *p, *a, *b; va_list ap; sp->stype = (FTN|VOID) | (PTR << TSHIFT); va_start(ap, n); a = va_arg(ap, NODE *); if (a != NULL) { do { b = va_arg(ap, NODE *); if (b != NULL) a = buildtree(CM, a, b); } while (b != NULL); } p = doacall(sp, nametree(sp), a, 0); va_end(ap); return p; } /* * Sanitycheck "new" keyword. */ NODE * cxx_new(NODE *p) { NODE *q = p; NODE *t1 = bcon(1); int nw = NM_NEW; while (p->n_op == LB) { nw = NM_NWA; t1 = buildtree(MUL, t1, eve(p->n_right)); p->n_right = bcon(0); p = p->n_left; } if (p->n_op != TYPE) uerror("new used illegally"); t1 = buildtree(MUL, t1, xbcon(tsize(p->n_type, p->n_df, p->n_ap)/SZCHAR, NULL, INTPTR)); tfree(q); return callftn(decoratename(NULL, nw), t1, NULL); } /* * Handle "delete" keyword. */ NODE * cxx_delete(NODE *p, int del) { return callftn(decoratename(NULL, del), p, NULL); } /* ::= nw # new ::= na # new[] ::= dl # delete ::= da # delete[] ::= ps # + (unary) ::= ng # - (unary) ::= ad # & (unary) ::= de # * (unary) ::= co # ~ ::= pl # + ::= mi # - ::= ml # * ::= dv # / ::= rm # % ::= an # & ::= or # | ::= eo # ^ ::= aS # = ::= pL # += ::= mI # -= ::= mL # *= ::= dV # /= ::= rM # %= ::= aN # &= ::= oR # |= ::= eO # ^= ::= ls # << ::= rs # >> ::= lS # <<= ::= rS # >>= ::= eq # == ::= ne # != ::= lt # < ::= gt # > ::= le # <= ::= ge # >= ::= nt # ! ::= aa # && ::= oo # || ::= pp # ++ (postfix in context) ::= mm # -- (postfix in context) ::= cm # , ::= pm # ->* ::= pt # -> ::= cl # () ::= ix # [] ::= qu # ? ::= st # sizeof (a type) ::= sz # sizeof (an expression) ::= at # alignof (a type) ::= az # alignof (an expression) ::= cv # (cast) ::= v # vendor extended operator */ /* ::= v # void ::= w # wchar_t ::= b # bool ::= c # char ::= a # signed char ::= h # unsigned char ::= s # short ::= t # unsigned short ::= i # int ::= j # unsigned int ::= l # long ::= m # unsigned long ::= x # long long, __int64 ::= y # unsigned long long, __int64 ::= n # __int128 ::= o # unsigned __int128 ::= f # float ::= d # double ::= e # long double, __float80 ::= g # __float128 ::= z # ellipsis ::= Dd # IEEE 754r decimal floating point (64 bits) ::= De # IEEE 754r decimal floating point (128 bits) ::= Df # IEEE 754r decimal floating point (32 bits) ::= Dh # IEEE 754r half-precision floating point (16 bits) ::= Di # char32_t ::= Ds # char16_t ::= Da # auto (in dependent new-expressions) ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) ::= u # vendor extended type */ /* matches type numbering in manifest.h */ static char chmap[] = { 'v', 'b', 'c', 'h', 's', 't', 'i', 'j', 'l', 'm', 'x', 'y', 'f', 'd', 'e' }; static int typch(int typ) { int c = BTYPE(typ); if (c == VOID) c = 0; return chmap[c]; } #define MAXNM 255 /* max length of mangled name */ static char nmblk[MAXNM]; static int nmptr, subptr; /* push character */ static void nmch(int c) { if (nmptr >= MAXNM) cerror("Too long mangled name"); nmblk[nmptr++] = c; } /* Push length and string */ static void pshsln(char *c) { int i, j, ln = (int)strlen(c); #define cnt(v,n) for (v = 0; ln >= n; v++, ln -= n) cnt(i,100); cnt(j,10); if (i) nmch(i+'0'); if (j || i) nmch(j+'0'); nmch(ln+'0'); for (; *c; c++) nmch(*c); } /* Recurse to push namespace names */ static void recnpsh(struct symtab *sp) { if (sp == spole) return; if (sp == sp->sdown) cerror("sp == sp->sdown"); if (sp->sdown) recnpsh(sp->sdown); pshsln(sp->sname); } static void pshargs(union arglist *al) { TWORD t; for (; al->type != TNULL; al++) { t = al->type; if (t == TELLIPSIS) { nmch('z'); continue; } while (t > BTMASK) { if (ISPTR(t)) nmch('P'); else uerror("pshargs2: %lx\n", t); t = DECREF(t); } if (t > LDOUBLE) uerror("pshargs: %lx\n", t); /* XXX - cannot emit const/volatile */ nmch(typch(t)); } } /* * Do name mangling of a symbol table entry. * The resulting name is saved in soname. */ char * decoratename(struct symtab *sp, int type) { char *n; #define QNM(m,s) case m: n = s; break switch (type) { QNM(NM_NEW,"_Znwm"); QNM(NM_NWA,"_Znam"); QNM(NM_DEL,"_ZdlPv"); QNM(NM_DLA,"_ZdaPv"); case NM_NORMAL: /* Defined in defid() */ break; default: uerror("missed mangling %d\n", type); return ""; } if (type != NM_NORMAL) return addname(n); /* special non-mangled cases: * "C" linkage * main() function * variables outside namespaces and classes */ if (elnk == LINK_C || strcmp(sp->sname, "main") == 0 || (sp->sdown == spole && !ISFTN(sp->stype))) { n = exname(sp->sname); return addname(n); } /* Compute the mangled name for other symbols */ nmptr = 0; subptr = 0; nmch('_'); nmch('Z'); if (sp->sdown != NULL) { nmch('N'); recnpsh(sp->sdown); } pshsln(sp->sname); if (sp->sdown != NULL) nmch('E'); if (ISFTN(sp->stype) && sp->sdf->dfun) pshargs(sp->sdf->dfun); nmch(0); return addname(nmblk); } /* * find a symtab entry in the given link. */ static struct symtab * sfind(char *n, struct symtab *sp) { while (sp) { if (cppdebug)printf("sfind: checking %s against %s\n", n, sp->sname); if (sp->sname == n) return sp; sp = sp->snext; } return NULL; } /* class or namespace? */ #define CLORNS(sp) (sp->sclass == STNAME || sp->sclass == CLNAME || \ sp->sclass == UNAME || sp->sclass == NSPACE) /* * find a symtab path entry in the given path. * p is expected to be a link of NMNAMEs. * It is supposed to return a sup value of the last found class. */ static struct symtab * pfind(NODE *p, struct symtab *sp) { char *n; if (cppdebug)printf("pfind: op %d searching %s\n", p->n_op, p->n_op == NAME ? (char *)p->n_sp:(char *)p->n_right->n_sp); if (p->n_op == NAME) { n = (char *)p->n_sp; if ((sp = sfind(n, sp)) == NULL) return NULL; if (cppdebug)printf("pfind: NAME class %d name %s\n", sp->sclass, sp->sname); while (!CLORNS(sp)) { if ((sp = sfind(n, sp->snext)) == NULL) return NULL; } if (cppdebug)printf("pfind: FOUND %s\n", sp->sname); sp = sp->sup; } else { n = (char *)p->n_right->n_sp; if ((sp = sfind(n, sp)) == NULL) return NULL; if (cppdebug)printf("pfind: NMLIST class %d name %s\n", sp->sclass, sp->sname); while (!CLORNS(sp)) { if ((sp = sfind(n, sp->snext)) == NULL) return NULL; } sp = pfind(p->n_left, sp->sup); } return sp; } /* * Declare a variable. */ struct symtab * cxxdeclvar(NODE *p) { struct symtab *sp; if (blevel && p->n_op == NAME) { sp = p->n_sp = lookup((char *)p->n_sp, 0); } else { sp = cxxlookup(p, SNORMAL); } return sp; } /* * class is MOS if variable is member of a CLASS, NORMAL otherwise. * A CLASS as member of a class has symbol type CLASS. */ char *symclass[] = { "NORMAL", "CLASS", "LABEL", "MOS", "STRING" }; /* * Do a name lookup. p can be either just a NAME or NMLIST. * The first symbol instance on its level is returned, which may or * may not be correct. * If no symbol is found, return a new symtab entry. * p should be a NAME after this with n_sp filled in accordingly. * It's the responsibility of the declaration routine to add it to * the symbol table. * nfree() will be called on p after this function. */ struct symtab * cxxlookup(NODE *p, int flags) { struct symtab *sp, *ns; int ftyp = flags & SMASK; NODE *q; char *n, *s; #define SPNAME(p) ((char *)(p->n_op == NAME ? p->n_sp : p->n_right->n_sp)) #ifdef PCC_DEBUG if (cppdebug){ printf("cxxlookup %s\n", SPNAME(p)); symtree(); } #endif q = p; if (p->n_op == NAME) { s = (char *)p->n_sp; if (blevel) { sp = lookup(s, SNOCREAT); /* check if auto var */ if (sp == NULL) { /* check if in classes */ for (ns = nscur; ns != spole; ns = ns->sdown) if ((sp = sfind(s, ns->sup))) break; if (sp == NULL) sp = sfind(s, spole->sup); } if (sp == NULL) sp = lookup(s, 0); /* fallback */ } else { ns = nscur; sp = sfind(s, ns); while (sp != NULL) { if ((sp->sflags & SMASK) == ftyp) break; sp = sfind(s, sp->snext); } if (sp == NULL) { sp = getsymtab(s, ftyp); if ((flags & SNOCREAT) == 0) { #ifdef PCC_DEBUG if (cppdebug)printf("cxxlookup: adding %s %s %s at %s\n", symclass[ftyp], s, sp->soname, nscur ? nscur->sname : "base"); #endif INSSYM(sp); cxxsetname(sp); } } } } else { /* Search through namespaces/classes for it */ n = SPNAME(p); ns = pfind(p->n_left, spole->sup); if (ns == NULL) { uerror("undeclared class in chain"); return getsymtab(n, ftyp); } if ((sp = sfind(n, ns)) == NULL) { sp = getsymtab(n, ftyp); if ((flags & SNOCREAT) == 0) { sp->snext = ns->snext; ns->snext = sp; } } } /* make top node a NAME */ if (q->n_op != NAME) { tfree(q->n_left); p = q->n_right; *q = *q->n_right; nfree(p); } q->n_sp = sp; return sp; } void cxxsetname(struct symtab *sp) { if (elnk == LINK_C) return; /* leave to target */ sp->soname = decoratename(sp, NM_NORMAL); } /* * Create a symbol out of a struct. * We call the symbol "__%THIS" to avoid interference. */ struct symtab * cxxstrvar(struct symtab *so) { struct symtab *sp; NODE *p; sp = lookup("__%THIS", 0); p = block(NAME, 0, 0, INCREF(so->stype), so->sdf, so->sap); p->n_sp = sp; defid(p, PARAM); nfree(p); return sp; } /* * Declare a struct (class) based on its name n. * Assumed that nmcur is correctly pointing to either: * - nothing (class at level 0) * - current namespace * - parent class */ struct symtab * cxxdclstr(char *n) { struct symtab *sp; sp = sfind(n, nscur->sup); while (sp && !CLORNS(sp)) sp = sfind(n, sp->snext); if (sp == 0) sp = getsymtab(n, STAGNAME); // else // uerror("class/namespace redefined"); // INSSYM(sp); // nscur = sp; if (cppdebug)printf("declaring2 struct %s %p nscur %s\n", n, sp, nscur->sname); return sp; } #ifdef PCC_DEBUG static void symwalk(struct symtab *sp, int indent) { int i; while (sp) { for (i = 0; i < indent; i++) printf(" "); printf("%s (%p) %s\n", sp->sname, sp, scnames(sp->sclass)); if (sp->sup) symwalk(sp->sup, indent+1); sp = sp->snext; } } void symtree(void) { symwalk(spole, 0); } #endif /* * Compare a matching prototype for a function. */ static int cxxpcmp(struct symtab *sp, NODE *p) { union arglist *a1, *a2; int i; if (!ISFTN(sp->stype) || p->n_df == NULL || sp->sdf == NULL) return 0; /* no dimfun */ if ((a1 = sp->sdf->dfun) == NULL || (a2 = p->n_df->dfun) == NULL) return 0; /* no argument */ for (i = 0; ; i++) { if (a1[i].type == TNULL && a2[i].type == TNULL) return 1; /* equal prototypes */ if (a1[i].type != a2[i].type) return 1; /* unequal prototypes */ } } struct ckstr { int rv; union arglist *al; }; static void cxxckproto(NODE *p, void *arg) { struct ckstr *cp = arg; if (cp->rv == -1) return; if (cp->al[0].type != p->n_type) goto fail; if (BTYPE(cp->al[0].type) > LDOUBLE) uerror("cxxckproto"); cp->al++; return; fail: cp->rv = -1; } /* * Compare a matching prototype for an argument tree. * Here we can expand to also do inexact matches. * Return 0 if equal, -1 if failed. */ static int cxxptreecmp(struct symtab *sp, NODE *p) { struct ckstr ckstr; union arglist *a1; if (!ISFTN(sp->stype) || sp->sdf == NULL || (a1 = sp->sdf->dfun) == NULL) return 0; /* no dimfun */ if (p == NULL && a1[0].type == TNULL) return 1; /* arg-less */ ckstr.rv = 0; ckstr.al = a1; flist(p, cxxckproto, &ckstr); if (ckstr.al[0].type != TNULL) return -1; /* arg number error */ return ckstr.rv; } /* * Search for (and declare) a function. */ struct symtab * cxxftnfind(NODE *p, int flags) { struct symtab *sp, *ns; char *s; if (p->n_op == NAME) { s = (char *)p->n_sp; /* Search for equally named functions */ sp = sfind(s, nscur->sup); while (sp != NULL) { if (cxxpcmp(sp, p)) { if (sp->sclass != NSPACE || sp->sclass == EXTDEF) { uerror("%s redefined", s); return sp; } else break; } sp = sfind(s, sp->snext); } if (sp == NULL) { sp = getsymtab(s, SNORMAL); sp->stype = p->n_type; sp->squal = p->n_qual; sp->sdf = p->n_df; sp->sap = p->n_ap; INSSYM(sp); if (nscur->sclass != NSPACE && nscur != &spole0) uerror("inside struct"); } sp->sclass = EXTDEF; if (sp->soname == 0) sp->soname = decoratename(sp, NM_NORMAL); } else { /* * declared outside class, tree-style reference * Must have been defined already * This will be an external declaration (not spooled). */ s = SPNAME(p); if ((ns = pfind(p->n_left, spole->sup)) == NULL) { uerror("undeclared class in chain"); goto undecl; } /* Search for an EXTERN or EXTDEF declaration within */ /* EXTDEF causes redeclaration. */ sp = sfind(s, ns); while (sp != NULL) { if (sp->sclass == EXTERN || sp->sclass == EXTDEF) { if (cxxpcmp(sp, p->n_right)) { if (sp->sclass == EXTDEF) uerror("%s redefined", s); break; } } sp = sfind(s, sp->snext); } if (sp == NULL) { uerror("%s undeclared", s); goto undecl; } sp->sclass = EXTDEF; } return sp; undecl: return getsymtab(s, SNORMAL); } /* * Reference to a struct as a :: name. */ NODE * cxxrstruct(int soru, NODE *attr, NODE *t, char *n) { struct symtab *ns, *sp; ns = pfind(t, spole->sup); if (ns == NULL) goto undecl; tfree(t); sp = sfind(n, ns); while (sp != NULL) { if (sp->sclass == soru) return mkty(sp->stype, 0, sp->sap); sp = sfind(n, sp->snext); } undecl: uerror("%s undeclared", n); return mkty(INT, 0, 0); } /* * Search for correct matching function in a struct depending on * argument list a. Return a call node for this function. * Do not touch neither f nor a. * return a name tree suitable for a function call. * We know here that f is a struct reference. */ NODE * cxxmatchftn(NODE *f, NODE *a) { struct attr *ap; struct symtab *sp; char *n = (char *)f->n_right->n_sp; f = f->n_left; if ((ap = attr_find(f->n_ap, ATTR_STRUCT)) == NULL) { uerror("undefined class"); sp = getsymtab(n, 0); } else sp = ap->amlist; sp = sfind(n, sp); while (sp != NULL) { if (ISFTN(sp->stype) && cxxptreecmp(sp, a) == 0) break; sp = sfind(n, sp->snext); } if (sp == NULL) uerror("undefined class member"); return nametree(sp); } /* * Add hidden argument f first in node list a. Return resulting a. */ NODE * cxxaddhidden(NODE *a, NODE *f) { NODE *q; if (a == NULL) return f; if (a->n_op != CM) return block(CM, f, a, INT, 0, 0); for (q = a; q->n_left->n_op == CM; q = q->n_left) ; q->n_left = block(CM, f, q->n_left, INT, 0, 0); return a; } /* * Watch out for references to static members. */ NODE * cxxstructref(NODE *p, int f, char *n) { struct symtab *sp = strmemb(p->n_ap); if (sp == NULL) cerror("ref to unknown struct"); sp = sfind(n, sp); while (sp != NULL) { if (!ISFTN(sp->stype)) { if (sp->sclass == STATIC || sp->sclass == USTATIC) { tfree(p); return nametree(sp); } break; } sp = sfind(n, sp->snext); } return structref(p, f, n); } pcc-20181216/cc/cxxcom/cxxdefs.h010064400017500000000000000026711170112125000151630ustar raggewheel enum { NM_NEW, NM_NWA, NM_DEL, NM_DLA, NM_NORMAL, }; enum { LINK_DEF, LINK_C }; /* linkage definitions */ extern int elnk; #define SCLINK 00020 /* for symtab */ extern int cppdebug; /* spole is symbol at base, nscur is where we are in the stack. */ extern struct symtab *spole, *nscur; /* insert a symbol into this something */ #define INSSYM(sp) (sp->snext = nscur->sup, nscur->sup = sp, sp->sdown = nscur) #define POPSYM() (nscur = nscur->sdown) /* C++-specific node types */ #define CONST_CAST (MAXOP+35) #define DYN_CAST (MAXOP+36) #define REINT_CAST (MAXOP+37) #define STATIC_CAST (MAXOP+38) #define NEWKW (MAXOP+39) #define DELETE (MAXOP+40) #define NMLIST (MAXOP+41) /* C++-specific symtab types */ #define CLNAME (MAXSTCL+1) /* symtab entry is class */ #define NSPACE (MAXSTCL+2) /* symtab entry is namespace */ char *decoratename(struct symtab *sp, int type); NODE *cxx_new(NODE *p); NODE *cxx_delete(NODE *p, int del); void dclns(NODE *attr, char *n); struct symtab *cxxlookup(NODE *p, int declare); void cxxsetname(struct symtab *sp); void cxxmember(struct symtab *sp); struct symtab *cxxstrvar(struct symtab *so); struct symtab *cxxdclstr(char *n); struct symtab *cxxftnfind(NODE *p, int flags); struct symtab *cxxdeclvar(NODE *p); void symtree(void); NODE *cxxrstruct(int soru, NODE *attr, NODE *t, char *tag); NODE *cxxmatchftn(NODE *, NODE *); NODE *cxxaddhidden(NODE *, NODE *); NODE *cxxstructref(NODE *p, int f, char *name); pcc-20181216/cc/cxxcom/gcc_compat.c010064400017500000000000000334051277716665000156430ustar raggewheel/* $Id: gcc_compat.c,v 1.11 2016/10/11 13:48:24 ragge Exp $ */ /* * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Routines to support some of the gcc extensions to C. */ #ifdef GCC_COMPAT #include "pass1.h" #include "cgram.h" #include static struct kw { char *name, *ptr; int rv; } kw[] = { /* * Do NOT change the order of these entries unless you know * what you're doing! */ /* 0 */ { "__asm", NULL, C_ASM }, /* 1 */ { "__signed", NULL, 0 }, /* 2 */ { "__inline", NULL, C_FUNSPEC }, /* 3 */ { "__const", NULL, 0 }, /* 4 */ { "__asm__", NULL, C_ASM }, /* 5 */ { "__inline__", NULL, C_FUNSPEC }, /* 6 */ { "__thread", NULL, 0 }, /* 7 */ { "__FUNCTION__", NULL, 0 }, /* 8 */ { "__volatile", NULL, 0 }, /* 9 */ { "__volatile__", NULL, 0 }, /* 10 */{ "__restrict", NULL, -1 }, /* 11 */{ "__typeof__", NULL, C_TYPEOF }, /* 12 */{ "typeof", NULL, C_TYPEOF }, /* 13 */{ "__extension__", NULL, -1 }, /* 14 */{ "__signed__", NULL, 0 }, /* 15 */{ "__attribute__", NULL, 0 }, /* 16 */{ "__attribute", NULL, 0 }, /* 17 */{ "__real__", NULL, 0 }, /* 18 */{ "__imag__", NULL, 0 }, /* 19 */{ "__builtin_offsetof", NULL, PCC_OFFSETOF }, /* 20 */{ "__PRETTY_FUNCTION__", NULL, 0 }, /* 21 */{ "__alignof__", NULL, C_ALIGNOF }, /* 22 */{ "__typeof", NULL, C_TYPEOF }, /* 23 */{ "__alignof", NULL, C_ALIGNOF }, /* 24 */{ "__restrict__", NULL, -1 }, { NULL, NULL, 0 }, }; /* g77 stuff */ #if SZFLOAT == SZLONG #define G77_INTEGER LONG #define G77_UINTEGER ULONG #elif SZFLOAT == SZINT #define G77_INTEGER INT #define G77_UINTEGER UNSIGNED #else #error fix g77 stuff #endif #if SZFLOAT*2 == SZLONG #define G77_LONGINT LONG #define G77_ULONGINT ULONG #elif SZFLOAT*2 == SZLONGLONG #define G77_LONGINT LONGLONG #define G77_ULONGINT ULONGLONG #else #error fix g77 long stuff #endif static TWORD g77t[] = { G77_INTEGER, G77_UINTEGER, G77_LONGINT, G77_ULONGINT }; static char *g77n[] = { "__g77_integer", "__g77_uinteger", "__g77_longint", "__g77_ulongint" }; void gcc_init(void) { struct kw *kwp; NODE *p; TWORD t; int i; for (kwp = kw; kwp->name; kwp++) kwp->ptr = addname(kwp->name); for (i = 0; i < 4; i++) { struct symtab *sp; t = ctype(g77t[i]); p = block(NAME, NIL, NIL, t, NULL, 0); sp = lookup(addname(g77n[i]), 0); p->n_sp = sp; defid(p, TYPEDEF); nfree(p); } } #define TS "\n#pragma tls\n# %d\n" #define TLLEN sizeof(TS)+10 /* * See if a string matches a gcc keyword. */ int gcc_keyword(char *str, NODE **n) { extern int inattr, parlvl, parbal; YYSTYPE *yyl = (YYSTYPE *)n; /* XXX should pass yylval */ char tlbuf[TLLEN], *tw; struct kw *kwp; int i; /* XXX hack, should pass everything in expressions */ if (str == kw[21].ptr) return kw[21].rv; if (inattr) return 0; for (i = 0, kwp = kw; kwp->name; kwp++, i++) if (str == kwp->ptr) break; if (kwp->name == NULL) return 0; if (kwp->rv) return kwp->rv; switch (i) { case 1: /* __signed */ case 14: /* __signed__ */ *n = mkty((TWORD)SIGNED, 0, 0); return C_TYPE; case 3: /* __const */ *n = block(QUALIFIER, NIL, NIL, CON, 0, 0); (*n)->n_qual = CON; return C_QUALIFIER; case 6: /* __thread */ snprintf(tlbuf, TLLEN, TS, lineno); tw = &tlbuf[strlen(tlbuf)]; while (tw > tlbuf) cunput(*--tw); return -1; case 7: /* __FUNCTION__ */ case 20: /* __PRETTY_FUNCTION__ */ if (cftnsp == NULL) { uerror("%s outside function", kwp->name); yylval.strp = ""; } else yylval.strp = cftnsp->sname; /* XXX - not C99 */ return C_STRING; case 8: /* __volatile */ case 9: /* __volatile__ */ *n = block(QUALIFIER, NIL, NIL, VOL, 0, 0); (*n)->n_qual = VOL; return C_QUALIFIER; case 15: /* __attribute__ */ case 16: /* __attribute */ inattr = 1; parlvl = parbal; return C_ATTRIBUTE; case 17: /* __real__ */ yyl->intval = XREAL; return C_UNOP; case 18: /* __imag__ */ yyl->intval = XIMAG; return C_UNOP; } cerror("gcc_keyword"); return 0; } #ifndef TARGET_ATTR #define TARGET_ATTR(p, sue) 0 #endif #ifndef ALMAX #define ALMAX (ALLDOUBLE > ALLONGLONG ? ALLDOUBLE : ALLONGLONG) #endif /* allowed number of args */ #define A_0ARG 0x01 #define A_1ARG 0x02 #define A_2ARG 0x04 #define A_3ARG 0x08 /* arg # is a name */ #define A1_NAME 0x10 #define A2_NAME 0x20 #define A3_NAME 0x40 #define A_MANY 0x80 /* arg # is "string" */ #define A1_STR 0x100 #define A2_STR 0x200 #define A3_STR 0x400 #ifdef __MSC__ #define CS(x) #else #define CS(x) [x] = #endif struct atax { int typ; char *name; } atax[GCC_ATYP_MAX] = { CS(ATTR_NONE) { 0, NULL }, CS(ATTR_COMPLEX) { 0, NULL }, CS(xxxATTR_BASETYP) { 0, NULL }, CS(ATTR_QUALTYP) { 0, NULL }, CS(ATTR_STRUCT) { 0, NULL }, CS(ATTR_ALIGNED) { A_0ARG|A_1ARG, "aligned" }, CS(GCC_ATYP_PACKED) { A_0ARG|A_1ARG, "packed" }, CS(GCC_ATYP_SECTION) { A_1ARG|A1_STR, "section" }, CS(GCC_ATYP_TRANSP_UNION) { A_0ARG, "transparent_union" }, CS(GCC_ATYP_UNUSED) { A_0ARG, "unused" }, CS(GCC_ATYP_DEPRECATED) { A_0ARG, "deprecated" }, CS(GCC_ATYP_MAYALIAS) { A_0ARG, "may_alias" }, CS(GCC_ATYP_MODE) { A_1ARG|A1_NAME, "mode" }, CS(GCC_ATYP_NORETURN) { A_0ARG, "noreturn" }, CS(GCC_ATYP_FORMAT) { A_3ARG|A1_NAME, "format" }, CS(GCC_ATYP_NONNULL) { A_MANY, "nonnull" }, CS(GCC_ATYP_SENTINEL) { A_0ARG|A_1ARG, "sentinel" }, CS(GCC_ATYP_WEAK) { A_0ARG, "weak" }, CS(GCC_ATYP_FORMATARG) { A_1ARG, "format_arg" }, CS(GCC_ATYP_GNU_INLINE) { A_0ARG, "gnu_inline" }, CS(GCC_ATYP_MALLOC) { A_0ARG, "malloc" }, CS(GCC_ATYP_NOTHROW) { A_0ARG, "nothrow" }, CS(GCC_ATYP_CONST) { A_0ARG, "const" }, CS(GCC_ATYP_PURE) { A_0ARG, "pure" }, CS(GCC_ATYP_CONSTRUCTOR) { A_0ARG, "constructor" }, CS(GCC_ATYP_DESTRUCTOR) { A_0ARG, "destructor" }, CS(GCC_ATYP_VISIBILITY) { A_1ARG|A1_STR, "visibility" }, CS(GCC_ATYP_STDCALL) { A_0ARG, "stdcall" }, CS(GCC_ATYP_CDECL) { A_0ARG, "cdecl" }, CS(GCC_ATYP_WARN_UNUSED_RESULT) { A_0ARG, "warn_unused_result" }, CS(GCC_ATYP_USED) { A_0ARG, "used" }, CS(GCC_ATYP_NO_INSTR_FUN) { A_0ARG, "no_instrument_function" }, CS(GCC_ATYP_NOINLINE) { A_0ARG, "noinline" }, CS(GCC_ATYP_ALIAS) { A_1ARG|A1_STR, "alias" }, CS(GCC_ATYP_WEAKREF) { A_0ARG|A_1ARG|A1_STR, "weakref" }, CS(GCC_ATYP_ALLOCSZ) { A_1ARG|A_2ARG, "alloc_size" }, CS(GCC_ATYP_ALW_INL) { A_0ARG, "always_inline" }, CS(GCC_ATYP_TLSMODEL) { A_1ARG|A1_STR, "tls_model" }, CS(GCC_ATYP_ALIASWEAK) { A_1ARG|A1_STR, "aliasweak" }, CS(GCC_ATYP_REGPARM) { A_1ARG, "regparm" }, CS(GCC_ATYP_FASTCALL) { A_0ARG, "fastcall" }, CS(GCC_ATYP_BOUNDED) { A_3ARG|A_MANY|A1_NAME, "bounded" }, }; #if SZPOINT(CHAR) == SZLONGLONG #define GPT LONGLONG #else #define GPT INT #endif struct atax mods[] = { { 0, NULL }, { INT, "SI" }, { INT, "word" }, { GPT, "pointer" }, { CHAR, "byte" }, { CHAR, "QI" }, { SHORT, "HI" }, { LONGLONG, "DI" }, { FLOAT, "SF" }, { DOUBLE, "DF" }, { LDOUBLE, "XF" }, { FCOMPLEX, "SC" }, { COMPLEX, "DC" }, { LCOMPLEX, "XC" }, #ifdef TARGET_MODS TARGET_MODS #endif }; #define ATSZ (sizeof(mods)/sizeof(mods[0])) static int amatch(char *s, struct atax *at, int mx) { int i, len; if (s[0] == '_' && s[1] == '_') s += 2; len = (int)strlen(s); if (len > 2 && s[len-1] == '_' && s[len-2] == '_') len -= 2; for (i = 0; i < mx; i++) { char *t = at[i].name; if (t != NULL && strncmp(s, t, len) == 0 && t[len] == 0) return i; } return 0; } static void setaarg(int str, union aarg *aa, NODE *p) { if (str) { if (((str & (A1_STR|A2_STR|A3_STR)) && p->n_op != STRING) || ((str & (A1_NAME|A2_NAME|A3_NAME)) && p->n_op != NAME)) uerror("bad arg to attribute"); if (p->n_op == STRING) { aa->sarg = newstring(p->n_name, strlen(p->n_name)); } else aa->sarg = (char *)p->n_sp; nfree(p); } else aa->iarg = (int)icons(eve(p)); } /* * Parse attributes from an argument list. */ static struct attr * gcc_attribs(NODE *p) { NODE *q, *r; struct attr *ap; char *name = NULL, *c; int cw, attr, narg, i; if (p->n_op == NAME) { name = (char *)p->n_sp; } else if (p->n_op == CALL || p->n_op == UCALL) { name = (char *)p->n_left->n_sp; } else if (p->n_op == ICON && p->n_type == STRTY) { return NULL; } else cerror("bad variable attribute"); if ((attr = amatch(name, atax, GCC_ATYP_MAX)) == 0) { warner(Wattributes, name); ap = NULL; goto out; } narg = 0; if (p->n_op == CALL) for (narg = 1, q = p->n_right; q->n_op == CM; q = q->n_left) narg++; cw = atax[attr].typ; if (!(cw & A_MANY) && ((narg > 3) || ((cw & (1 << narg)) == 0))) { uerror("wrong attribute arg count"); return NULL; } ap = attr_new(attr, 3); /* XXX should be narg */ q = p->n_right; switch (narg) { default: /* XXX */ while (narg-- > 3) { r = q; q = q->n_left; tfree(r->n_right); nfree(r); } /* FALLTHROUGH */ case 3: setaarg(cw & (A3_NAME|A3_STR), &ap->aa[2], q->n_right); r = q; q = q->n_left; nfree(r); /* FALLTHROUGH */ case 2: setaarg(cw & (A2_NAME|A2_STR), &ap->aa[1], q->n_right); r = q; q = q->n_left; nfree(r); /* FALLTHROUGH */ case 1: setaarg(cw & (A1_NAME|A1_STR), &ap->aa[0], q); p->n_op = UCALL; /* FALLTHROUGH */ case 0: break; } /* some attributes must be massaged special */ switch (attr) { case ATTR_ALIGNED: if (narg == 0) ap->aa[0].iarg = ALMAX; else ap->aa[0].iarg *= SZCHAR; break; case GCC_ATYP_PACKED: if (narg == 0) ap->aa[0].iarg = 1; /* bitwise align */ else ap->aa[0].iarg *= SZCHAR; break; case GCC_ATYP_MODE: if ((i = amatch(ap->aa[0].sarg, mods, ATSZ)) == 0) werror("unknown mode arg %s", ap->aa[0].sarg); ap->aa[0].iarg = ctype(mods[i].typ); break; case GCC_ATYP_VISIBILITY: c = ap->aa[0].sarg; if (strcmp(c, "default") && strcmp(c, "hidden") && strcmp(c, "internal") && strcmp(c, "protected")) werror("unknown visibility %s", c); break; case GCC_ATYP_TLSMODEL: c = ap->aa[0].sarg; if (strcmp(c, "global-dynamic") && strcmp(c, "local-dynamic") && strcmp(c, "initial-exec") && strcmp(c, "local-exec")) werror("unknown tls model %s", c); break; default: break; } out: return ap; } /* * Extract attributes from a node tree and return attribute entries * based on its contents. */ struct attr * gcc_attr_parse(NODE *p) { struct attr *b, *c; if (p == NIL) return NULL; if (p->n_op != CM) { b = gcc_attribs(p); tfree(p); } else { b = gcc_attr_parse(p->n_left); c = gcc_attr_parse(p->n_right); nfree(p); b = b ? attr_add(b, c) : c; } return b; } /* * Fixup struct/unions depending on attributes. */ void gcc_tcattrfix(NODE *p) { struct symtab *sp; struct attr *ap; int sz, coff, csz, al, oal, mxal; if ((ap = attr_find(p->n_ap, GCC_ATYP_PACKED)) == NULL) return; /* nothing to fix */ al = ap->iarg(0); mxal = 0; /* Must repack struct */ coff = csz = 0; for (sp = strmemb(ap); sp; sp = sp->snext) { oal = talign(sp->stype, sp->sap); if (oal > al) oal = al; if (mxal < oal) mxal = oal; if (sp->sclass & FIELD) sz = sp->sclass&FLDSIZ; else sz = (int)tsize(sp->stype, sp->sdf, sp->sap); sp->soffset = upoff(sz, oal, &coff); if (coff > csz) csz = coff; if (p->n_type == UNIONTY) coff = 0; } if (mxal < ALCHAR) mxal = ALCHAR; /* for bitfields */ SETOFF(csz, mxal); /* Roundup to whatever */ ap = attr_find(p->n_ap, ATTR_STRUCT); ap->amsize = csz; ap = attr_find(p->n_ap, ATTR_ALIGNED); ap->iarg(0) = mxal; } /* * gcc-specific pragmas. */ int pragmas_gcc(char *t) { char u; extern char *pragstore; if (strcmp((t = pragtok(NULL)), "diagnostic") == 0) { int warn, err; if (strcmp((t = pragtok(NULL)), "ignored") == 0) warn = 0, err = 0; else if (strcmp(t, "warning") == 0) warn = 1, err = 0; else if (strcmp(t, "error") == 0) warn = 1, err = 1; else return 1; if (eat('\"') || eat('-')) return 1; for (t = pragstore; *t && *t != '\"'; t++) ; u = *t; *t = 0; Wset(pragstore + 1, warn, err); *t = u; } else if (strcmp(t, "poison") == 0) { /* currently ignore */; } else if (strcmp(t, "visibility") == 0) { /* currently ignore */; } else if (strcmp(t, "system_header") == 0) { /* currently ignore */; } else werror("gcc pragma unsupported"); return 0; } #ifdef PCC_DEBUG void dump_attr(struct attr *ap) { printf("attributes; "); for (; ap; ap = ap->next) { if (ap->atype >= GCC_ATYP_MAX) { printf("bad type %d, ", ap->atype); } else if (atax[ap->atype].name == 0) { char *c = ap->atype == ATTR_COMPLEX ? "complex" : ap->atype == ATTR_STRUCT ? "struct" : "badtype"; printf("%s, ", c); } else { printf("%s: ", atax[ap->atype].name); printf("%d %d %d, ", ap->iarg(0), ap->iarg(1), ap->iarg(2)); } } printf("\n"); } #endif #endif pcc-20181216/cc/cxxcom/init.c010064400017500000000000000660641262511725400145020ustar raggewheel/* $Id: init.c,v 1.6 2015/11/24 17:30:20 ragge Exp $ */ /* * Copyright (c) 2004, 2007 Anders Magnusson (ragge@ludd.ltu.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code and documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "pass1.h" #include /* * The following machine-dependent routines may be called during * initialization: * * zbits(OFFSZ, int) - sets int bits of zero at position OFFSZ. * infld(CONSZ off, int fsz, CONSZ val) * - sets the bitfield val starting at off and size fsz. * ninval(CONSZ off, int fsz, NODE *) * - prints an integer constant which may have * a label associated with it, located at off and * size fsz. * * Initialization may be of different kind: * - Initialization at compile-time, all values are constants and laid * out in memory. Static or extern variables outside functions. * - Initialization at run-time, written to their values as code. * * Currently run-time-initialized variables are only initialized by using * move instructions. An optimization might be to detect that it is * initialized with constants and therefore copied from readonly memory. */ /* * The base element(s) of an initialized variable is kept in a linked * list, allocated while initialized. * * When a scalar is found, entries are popped of the instk until it's * possible to find an entry for a new scalar; then onstk() is called * to get the correct type and size of that scalar. * * If a right brace is found, pop the stack until a matching left brace * were found while filling the elements with zeros. This left brace is * also marking where the current level is for designated initializations. * * Position entries are increased when traversing back down into the stack. */ /* * Good-to-know entries from symtab: * soffset - # of bits from beginning of this structure. */ /* * TO FIX: * - Alignment of structs on like i386 char members. */ /* * Struct used in array initialisation. */ static struct instk { struct instk *in_prev; /* linked list */ struct symtab *in_lnk; /* member in structure initializations */ struct symtab *in_sym; /* symtab index */ union dimfun *in_df; /* dimenston of array */ TWORD in_t; /* type for this level */ int in_n; /* number of arrays seen so far */ int in_fl; /* flag which says if this level is controlled by {} */ } *pstk, pbase; int doing_init, statinit; static struct symtab *csym; #ifdef PCC_DEBUG static void prtstk(struct instk *in); #endif /* * Linked lists for initializations. */ struct ilist { struct ilist *next; CONSZ off; /* bit offset of this entry */ int fsz; /* bit size of this entry */ NODE *n; /* node containing this data info */ }; struct llist { SLIST_ENTRY(llist) next; CONSZ begsz; /* bit offset of this entry */ struct ilist *il; }; static SLIST_HEAD(llh, llist) lpole; static CONSZ basesz; static int numents; /* # of array entries allocated */ static struct initctx { struct initctx *prev; struct instk *pstk; struct symtab *psym; struct llh lpole; CONSZ basesz; int numents; } *inilnk; static struct ilist * getil(struct ilist *next, CONSZ b, int sz, NODE *n) { struct ilist *il = tmpalloc(sizeof(struct ilist)); il->off = b; il->fsz = sz; il->n = n; il->next = next; return il; } /* * Allocate a new struct defining a block of initializers appended to the * end of the llist. Return that entry. */ static struct llist * getll(void) { struct llist *ll; ll = tmpalloc(sizeof(struct llist)); ll->begsz = numents * basesz; ll->il = NULL; SLIST_INSERT_LAST(&lpole, ll, next); numents++; return ll; } /* * Return structure containing off bitnumber. * Allocate more entries, if needed. */ static struct llist * setll(OFFSZ off) { struct llist *ll = NULL; /* Ensure that we have enough entries */ while (off >= basesz * numents) ll = getll(); if (ll != NULL && ll->begsz <= off && ll->begsz + basesz > off) return ll; SLIST_FOREACH(ll, &lpole, next) if (ll->begsz <= off && ll->begsz + basesz > off) break; return ll; /* ``cannot fail'' */ } char *astypnames[] = { 0, 0, "\t.byte", "\t.byte", "\t.short", "\t.short", "\t.word", "\t.word", "\t.long", "\t.long", "\t.quad", "\t.quad", "ERR", "ERR", "ERR", }; void inval(CONSZ off, int fsz, NODE *p) { struct symtab *sp; CONSZ val; TWORD t; if (p->n_op != ICON && p->n_op != FCON) { uerror("constant required"); return; } if (p->n_type == BOOL) { if ((U_CONSZ)glval(p) > 1) slval(p, 1); p->n_type = BOOL_TYPE; } if (ninval(off, fsz, p)) return; /* dealt with in local.c */ t = p->n_type; if (t > BTMASK) t = INTPTR; val = (CONSZ)(glval(p) & SZMASK(sztable[t])); if (t <= ULONGLONG) { sp = p->n_sp; printf("%s ",astypnames[t]); if (val || sp == NULL) printf(CONFMT, val); if (val && sp != NULL) printf("+"); if (sp != NULL) { if ((sp->sclass == STATIC && sp->slevel > 0)) { printf(LABFMT, sp->soffset); } else printf("%s", sp->soname ? sp->soname : exname(sp->sname)); } printf("\n"); } else cerror("inval: unhandled type %d", (int)t); } #ifndef MYBFINIT static int inbits; static CONSZ xinval; /* * Initialize a bitfield. * XXX - use U_CONSZ? */ void infld(CONSZ off, int fsz, CONSZ val) { #ifdef PCC_DEBUG if (idebug) printf("infld off " CONFMT ", fsz %d, val " CONFMT " inbits %d\n", off, fsz, val, inbits); #endif val &= SZMASK(fsz); #if TARGET_ENDIAN == TARGET_BE while (fsz + inbits >= SZCHAR) { int shsz = SZCHAR-inbits; xinval = (xinval << shsz) | (val >> (fsz - shsz)); printf("%s " CONFMT "\n", astypnames[CHAR], (CONSZ)(xinval & SZMASK(SZCHAR))); fsz -= shsz; val &= SZMASK(fsz); xinval = inbits = 0; } if (fsz) { xinval = (xinval << fsz) | val; inbits += fsz; } #else while (fsz + inbits >= SZCHAR) { int shsz = SZCHAR-inbits; xinval |= (val << inbits); printf("%s " CONFMT "\n", astypnames[CHAR], (CONSZ)(xinval & SZMASK(SZCHAR))); fsz -= shsz; val >>= shsz; xinval = inbits = 0; } if (fsz) { xinval |= (val << inbits); inbits += fsz; } #endif } char *asspace = "\t.space"; /* * set fsz bits in sequence to zero. */ void zbits(OFFSZ off, int fsz) { int m; #ifdef PCC_DEBUG if (idebug) printf("zbits off " CONFMT ", fsz %d inbits %d\n", off, fsz, inbits); #endif #if TARGET_ENDIAN == TARGET_BE if ((m = (inbits % SZCHAR))) { m = SZCHAR - m; if (fsz < m) { inbits += fsz; xinval <<= fsz; return; } else { fsz -= m; xinval <<= m; printf("%s " CONFMT "\n", astypnames[CHAR], xinval & SZMASK(SZCHAR)); xinval = inbits = 0; } } #else if ((m = (inbits % SZCHAR))) { m = SZCHAR - m; if (fsz < m) { inbits += fsz; return; } else { fsz -= m; printf("%s " CONFMT "\n", astypnames[CHAR], (CONSZ)(xinval & SZMASK(SZCHAR))); xinval = inbits = 0; } } #endif if (fsz >= SZCHAR) { printf("%s %d\n", asspace, fsz/SZCHAR); fsz -= (fsz/SZCHAR) * SZCHAR; } if (fsz) { xinval = 0; inbits = fsz; } } #endif /* * beginning of initialization; allocate space to store initialized data. * remember storage class for writeout in endinit(). * p is the newly declarated type. */ void beginit(struct symtab *sp) { struct initctx *ict; struct instk *is = &pbase; #ifdef PCC_DEBUG if (idebug) printf("beginit(%p), sclass %s\n", sp, scnames(sp->sclass)); #endif if (pstk) { #ifdef PCC_DEBUG if (idebug) printf("beginit: saving ctx pstk %p\n", pstk); #endif /* save old context */ ict = tmpalloc(sizeof(struct initctx)); ict->prev = inilnk; inilnk = ict; ict->pstk = pstk; ict->psym = csym; ict->lpole = lpole; ict->basesz = basesz; ict->numents = numents; is = tmpalloc(sizeof(struct instk)); } csym = sp; numents = 0; /* no entries in array list */ if (ISARY(sp->stype)) { basesz = tsize(DECREF(sp->stype), sp->sdf+1, sp->sap); if (basesz == 0) { uerror("array has incomplete type"); basesz = SZINT; } } else basesz = tsize(sp->stype, sp->sdf, sp->sap); SLIST_INIT(&lpole); /* first element */ if (ISSOU(sp->stype)) { is->in_lnk = strmemb(sp->sap); } else is->in_lnk = NULL; is->in_n = 0; is->in_t = sp->stype; is->in_sym = sp; is->in_df = sp->sdf; is->in_fl = 0; is->in_prev = NULL; pstk = is; doing_init++; if (sp->sclass == STATIC || sp->sclass == EXTDEF) statinit++; } /* * Push a new entry on the initializer stack. * The new entry will be "decremented" to the new sub-type of the previous * entry when called. * Popping of entries is done elsewhere. */ static void stkpush(void) { struct instk *is; struct symtab *sq, *sp; TWORD t; if (pstk == NULL) { sp = csym; t = 0; } else { t = pstk->in_t; sp = pstk->in_sym; } #ifdef PCC_DEBUG if (idebug) { printf("stkpush: '%s' %s ", sp->sname, scnames(sp->sclass)); tprint(t, 0); } #endif /* * Figure out what the next initializer will be, and push it on * the stack. If this is an array, just decrement type, if it * is a struct or union, extract the next element. */ is = tmpalloc(sizeof(struct instk)); is->in_fl = 0; is->in_n = 0; if (pstk == NULL) { /* stack empty */ is->in_lnk = ISSOU(sp->stype) ? strmemb(sp->sap) : NULL; is->in_t = sp->stype; is->in_sym = sp; is->in_df = sp->sdf; } else if (ISSOU(t)) { sq = pstk->in_lnk; if (sq == NULL) { uerror("excess of initializing elements"); } else { is->in_lnk = ISSOU(sq->stype) ? strmemb(sq->sap) : NULL; is->in_t = sq->stype; is->in_sym = sq; is->in_df = sq->sdf; } } else if (ISARY(t)) { is->in_lnk = ISSOU(DECREF(t)) ? strmemb(pstk->in_sym->sap) : 0; is->in_t = DECREF(t); is->in_sym = sp; if (pstk->in_df->ddim != NOOFFSET && pstk->in_df->ddim && pstk->in_n >= pstk->in_df->ddim) { werror("excess of initializing elements"); pstk->in_n--; } is->in_df = pstk->in_df+1; } else uerror("too many left braces"); is->in_prev = pstk; pstk = is; #ifdef PCC_DEBUG if (idebug) { printf(" newtype "); tprint(is->in_t, 0); printf("\n"); } #endif } /* * pop down to either next level that can handle a new initializer or * to the next braced level. */ static void stkpop(void) { #ifdef PCC_DEBUG if (idebug) printf("stkpop\n"); #endif for (; pstk; pstk = pstk->in_prev) { if (pstk->in_t == STRTY && pstk->in_lnk != NULL) { pstk->in_lnk = pstk->in_lnk->snext; if (pstk->in_lnk != NULL) break; } if (ISSOU(pstk->in_t) && pstk->in_fl) break; /* need } */ if (ISARY(pstk->in_t)) { pstk->in_n++; if (pstk->in_fl) break; if (pstk->in_df->ddim == NOOFFSET || pstk->in_n < pstk->in_df->ddim) break; /* ger more elements */ } } #ifdef PCC_DEBUG if (idebug > 1) prtstk(pstk); #endif } /* * Count how many elements an array may consist of. */ static int acalc(struct instk *is, int n) { if (is == NULL || !ISARY(is->in_t)) return 0; return acalc(is->in_prev, n * is->in_df->ddim) + n * is->in_n; } /* * Find current bit offset of the top element on the stack from * the beginning of the aggregate. */ static CONSZ findoff(void) { struct instk *is; OFFSZ off; #ifdef PCC_DEBUG if (ISARY(pstk->in_t)) cerror("findoff on bad type %x", pstk->in_t); #endif /* * Offset calculations. If: * - previous type is STRTY, soffset has in-struct offset. * - this type is ARY, offset is ninit*stsize. */ for (off = 0, is = pstk; is; is = is->in_prev) { if (is->in_prev && is->in_prev->in_t == STRTY) off += is->in_sym->soffset; if (ISARY(is->in_t)) { /* suesize is the basic type, so adjust */ TWORD t = is->in_t; OFFSZ o; while (ISARY(t)) t = DECREF(t); if (ISPTR(t)) { o = SZPOINT(t); /* XXX use tsize() */ } else { o = tsize(t, is->in_sym->sdf, is->in_sym->sap); } off += o * acalc(is, 1); while (is->in_prev && ISARY(is->in_prev->in_t)) { if (is->in_prev->in_prev && is->in_prev->in_prev->in_t == STRTY) off += is->in_sym->soffset; is = is->in_prev; } } } #ifdef PCC_DEBUG if (idebug>1) { printf("findoff: off " CONFMT "\n", off); prtstk(pstk); } #endif return off; } /* * Insert the node p with size fsz at position off. * Bit fields are already dealt with, so a node of correct type * with correct alignment and correct bit offset is given. */ static void nsetval(CONSZ off, int fsz, NODE *p) { struct llist *ll; struct ilist *il; if (idebug>1) printf("setval: off " CONFMT " fsz %d p %p\n", off, fsz, p); if (fsz == 0) return; ll = setll(off); off -= ll->begsz; if (ll->il == NULL) { ll->il = getil(NULL, off, fsz, p); } else { il = ll->il; if (il->off > off) { ll->il = getil(ll->il, off, fsz, p); } else { for (il = ll->il; il->next; il = il->next) if (il->off <= off && il->next->off > off) break; if (il->off == off) { /* replace */ nfree(il->n); il->n = p; } else il->next = getil(il->next, off, fsz, p); } } } /* * take care of generating a value for the initializer p * inoff has the current offset (last bit written) * in the current word being generated * Returns the offset. */ CONSZ scalinit(NODE *p) { CONSZ woff; NODE *q; int fsz; #ifdef PCC_DEBUG if (idebug > 2) { printf("scalinit(%p)\n", p); fwalk(p, eprint, 0); prtstk(pstk); } #endif if (nerrors) return 0; p = optim(p); #ifdef notdef /* leave to the target to decide if useable */ if (csym->sclass != AUTO && p->n_op != ICON && p->n_op != FCON && p->n_op != NAME) cerror("scalinit not leaf"); #endif /* Out of elements? */ if (pstk == NULL) { uerror("excess of initializing elements"); return 0; } /* * Get to the simple type if needed. */ while (ISSOU(pstk->in_t) || ISARY(pstk->in_t)) { stkpush(); /* If we are doing auto struct init */ if (ISSOU(pstk->in_t) && ISSOU(p->n_type) && suemeq(pstk->in_sym->sap, p->n_ap)) break; } if (ISSOU(pstk->in_t) == 0) { /* let buildtree do typechecking (and casting) */ q = block(NAME, NIL,NIL, pstk->in_t, pstk->in_df, pstk->in_sym->sap); p = buildtree(ASSIGN, q, p); nfree(p->n_left); q = p->n_right; nfree(p); } else q = p; #ifndef WORD_ADDRESSED if (csym->sclass != AUTO) q = rmpconv(optim(rmpconv(q))); #endif q = optim(q); woff = findoff(); /* bitfield sizes are special */ if (pstk->in_sym->sclass & FIELD) fsz = -(pstk->in_sym->sclass & FLDSIZ); else fsz = (int)tsize(pstk->in_t, pstk->in_sym->sdf, pstk->in_sym->sap); nsetval(woff, fsz, q); stkpop(); #ifdef PCC_DEBUG if (idebug > 2) { printf("scalinit e(%p)\n", q); } #endif return woff; } /* * Generate code to insert a value into a bitfield. */ static void insbf(OFFSZ off, int fsz, int val) { struct symtab sym; NODE *p, *r; TWORD typ; #ifdef PCC_DEBUG if (idebug > 1) printf("insbf: off " CONFMT " fsz %d val %d\n", off, fsz, val); #endif if (fsz == 0) return; /* small opt: do char instead of bf asg */ if ((off & (ALCHAR-1)) == 0 && fsz == SZCHAR) typ = CHAR; else typ = INT; /* Fake a struct reference */ p = buildtree(ADDROF, nametree(csym), NIL); sym.stype = typ; sym.squal = 0; sym.sdf = 0; sym.sap = NULL; sym.soffset = (int)off; sym.sclass = (char)(typ == INT ? FIELD | fsz : MOU); r = xbcon(0, &sym, typ); p = block(STREF, p, r, INT, 0, 0); ecomp(buildtree(ASSIGN, stref(p), bcon(val))); } /* * Clear a bitfield, starting at off and size fsz. */ static void clearbf(OFFSZ off, OFFSZ fsz) { /* Pad up to the next even initializer */ if ((off & (ALCHAR-1)) || (fsz < SZCHAR)) { int ba = (int)(((off + (SZCHAR-1)) & ~(SZCHAR-1)) - off); if (ba > fsz) ba = (int)fsz; insbf(off, ba, 0); off += ba; fsz -= ba; } while (fsz >= SZCHAR) { insbf(off, SZCHAR, 0); off += SZCHAR; fsz -= SZCHAR; } if (fsz) insbf(off, fsz, 0); } /* * final step of initialization. * print out init nodes and generate copy code (if needed). */ void endinit(int seg) { struct llist *ll; struct ilist *il; int fsz; OFFSZ lastoff, tbit; #ifdef PCC_DEBUG if (idebug) printf("endinit()\n"); #endif /* Calculate total block size */ if (ISARY(csym->stype) && csym->sdf->ddim == NOOFFSET) { tbit = numents*basesz; /* open-ended arrays */ csym->sdf->ddim = numents; if (csym->sclass == AUTO) { /* Get stack space */ csym->soffset = NOOFFSET; oalloc(csym, &autooff); } } else tbit = tsize(csym->stype, csym->sdf, csym->sap); /* Setup symbols */ if (csym->sclass != AUTO) { locctr(seg ? UDATA : DATA, csym); defloc(csym); } /* Traverse all entries and print'em out */ lastoff = 0; SLIST_FOREACH(ll, &lpole, next) { for (il = ll->il; il; il = il->next) { #ifdef PCC_DEBUG if (idebug > 1) { printf("off " CONFMT " size %d val " CONFMT " type ", ll->begsz+il->off, il->fsz, glval(il->n)); tprint(il->n->n_type, 0); printf("\n"); } #endif fsz = il->fsz; if (csym->sclass == AUTO) { struct symtab sym; NODE *p, *r, *n; if (ll->begsz + il->off > lastoff) clearbf(lastoff, (ll->begsz + il->off) - lastoff); /* Fake a struct reference */ p = buildtree(ADDROF, nametree(csym), NIL); n = il->n; sym.stype = n->n_type; sym.squal = n->n_qual; sym.sdf = n->n_df; sym.sap = n->n_ap; sym.soffset = (int)(ll->begsz + il->off); sym.sclass = (char)(fsz < 0 ? FIELD | -fsz : 0); r = xbcon(0, &sym, INT); p = block(STREF, p, r, INT, 0, 0); ecomp(buildtree(ASSIGN, stref(p), il->n)); if (fsz < 0) fsz = -fsz; } else { if (ll->begsz + il->off > lastoff) zbits(lastoff, (ll->begsz + il->off) - lastoff); if (fsz < 0) { fsz = -fsz; infld(il->off, fsz, glval(il->n)); } else inval(il->off, fsz, il->n); tfree(il->n); } lastoff = ll->begsz + il->off + fsz; } } if (csym->sclass == AUTO) { clearbf(lastoff, tbit-lastoff); } else zbits(lastoff, tbit-lastoff); doing_init--; if (csym->sclass == STATIC || csym->sclass == EXTDEF) statinit--; endictx(); } void endictx(void) { struct initctx *ict = inilnk; if (ict == NULL) return; pstk = ict->pstk; csym = ict->psym; lpole = ict->lpole; basesz = ict->basesz; numents = ict->numents; inilnk = inilnk->prev; #ifdef PCC_DEBUG if (idebug) printf("endinit: restoring ctx pstk %p\n", pstk); #endif } /* * process an initializer's left brace */ void ilbrace(void) { #ifdef PCC_DEBUG if (idebug) printf("ilbrace()\n"); #endif if (pstk == NULL) return; stkpush(); pstk->in_fl = 1; /* mark lbrace */ #ifdef PCC_DEBUG if (idebug > 1) prtstk(pstk); #endif } /* * called when a '}' is seen */ void irbrace(void) { #ifdef PCC_DEBUG if (idebug) printf("irbrace()\n"); if (idebug > 2) prtstk(pstk); #endif if (pstk == NULL) return; /* Got right brace, search for corresponding in the stack */ for (; pstk->in_prev != NULL; pstk = pstk->in_prev) { if(!pstk->in_fl) continue; /* we have one now */ pstk->in_fl = 0; /* cancel { */ if (ISARY(pstk->in_t)) pstk->in_n = pstk->in_df->ddim; else if (pstk->in_t == STRTY) { while (pstk->in_lnk != NULL && pstk->in_lnk->snext != NULL) pstk->in_lnk = pstk->in_lnk->snext; } stkpop(); return; } } /* * Create a new init stack based on given elements. */ static void mkstack(NODE *p) { #ifdef PCC_DEBUG if (idebug) { printf("mkstack: %p\n", p); if (idebug > 1 && p) fwalk(p, eprint, 0); } #endif if (p == NULL) return; mkstack(p->n_left); switch (p->n_op) { case LB: /* Array index */ if (p->n_right->n_op != ICON) cerror("mkstack"); if (!ISARY(pstk->in_t)) uerror("array indexing non-array"); pstk->in_n = (int)glval(p->n_right); nfree(p->n_right); break; case NAME: if (pstk->in_lnk) { for (; pstk->in_lnk; pstk->in_lnk = pstk->in_lnk->snext) if (pstk->in_lnk->sname == (char *)p->n_sp) break; if (pstk->in_lnk == NULL) uerror("member missing"); } else { uerror("not a struct/union"); } break; default: cerror("mkstack2"); } nfree(p); stkpush(); } /* * Initialize a specific element, as per C99. */ void desinit(NODE *p) { int op = p->n_op; if (pstk == NULL) stkpush(); /* passed end of array */ while (pstk->in_prev && pstk->in_fl == 0) pstk = pstk->in_prev; /* Empty stack */ if (ISSOU(pstk->in_t)) pstk->in_lnk = strmemb(pstk->in_sym->sap); mkstack(p); /* Setup for assignment */ /* pop one step if SOU, ilbrace will push */ if (op == NAME || op == LB) pstk = pstk->in_prev; #ifdef PCC_DEBUG if (idebug > 1) { printf("desinit e\n"); prtstk(pstk); } #endif } /* * Convert a string to an array of char/wchar for asginit. */ static void strcvt(NODE *p) { NODE *q = p; char *s; int i; #ifdef mach_arm /* XXX */ if (p->n_op == UMUL && p->n_left->n_op == ADDROF) p = p->n_left->n_left; #endif for (s = p->n_sp->sname; *s != 0; ) { if (*s++ == '\\') { i = esccon(&s); } else i = (unsigned char)s[-1]; asginit(bcon(i)); } tfree(q); } /* * Do an assignment to a struct element. */ void asginit(NODE *p) { int g; #ifdef PCC_DEBUG if (idebug) printf("asginit %p\n", p); if (idebug > 1 && p) fwalk(p, eprint, 0); #endif /* convert string to array of char/wchar */ if (p && (DEUNSIGN(p->n_type) == ARY+CHAR || p->n_type == ARY+WCHAR_TYPE)) { struct instk *is; TWORD t; t = p->n_type == ARY+WCHAR_TYPE ? ARY+WCHAR_TYPE : ARY+CHAR; /* * ...but only if next element is ARY+CHAR, otherwise * just fall through. */ /* HACKHACKHACK */ is = pstk; if (pstk == NULL) stkpush(); while (ISSOU(pstk->in_t) || ISARY(pstk->in_t)) stkpush(); if (pstk->in_prev && (DEUNSIGN(pstk->in_prev->in_t) == t || pstk->in_prev->in_t == t)) { pstk = pstk->in_prev; if ((g = pstk->in_fl) == 0) pstk->in_fl = 1; /* simulate ilbrace */ strcvt(p); if (g == 0) irbrace(); /* will fill with zeroes */ return; } else pstk = is; /* no array of char */ /* END HACKHACKHACK */ } if (p == NULL) { /* only end of compound stmt */ irbrace(); } else /* assign next element */ scalinit(p); } #ifdef PCC_DEBUG void prtstk(struct instk *in) { int i, o = 0; printf("init stack:\n"); for (; in != NULL; in = in->in_prev) { for (i = 0; i < o; i++) printf(" "); printf("%p) '%s' ", in, in->in_sym->sname); tprint(in->in_t, 0); printf(" %s ", scnames(in->in_sym->sclass)); if (in->in_df /* && in->in_df->ddim */) printf("arydim=%d ", in->in_df->ddim); printf("ninit=%d ", in->in_n); if (BTYPE(in->in_t) == STRTY || ISARY(in->in_t)) printf("stsize=%d ", (int)tsize(in->in_t, in->in_df, in->in_sym->sap)); if (in->in_fl) printf("{ "); printf("soff=%d ", in->in_sym->soffset); if (in->in_t == STRTY) { if (in->in_lnk) printf("curel %s ", in->in_lnk->sname); else printf("END struct"); } printf("\n"); o++; } } #endif /* * Do a simple initialization. * At block 0, just print out the value, at higher levels generate * appropriate code. */ void simpleinit(struct symtab *sp, NODE *p) { NODE *q, *r, *nt; TWORD t; int sz; /* May be an initialization of an array of char by a string */ if ((DEUNSIGN(p->n_type) == ARY+CHAR && DEUNSIGN(sp->stype) == ARY+CHAR) || (DEUNSIGN(p->n_type) == DEUNSIGN(ARY+WCHAR_TYPE) && DEUNSIGN(sp->stype) == DEUNSIGN(ARY+WCHAR_TYPE))) { /* Handle "aaa" as { 'a', 'a', 'a' } */ beginit(sp); strcvt(p); if (csym->sdf->ddim == NOOFFSET) scalinit(bcon(0)); /* Null-term arrays */ endinit(0); return; } nt = nametree(sp); switch (sp->sclass) { case STATIC: case EXTDEF: q = nt; locctr(DATA, sp); defloc(sp); #ifndef NO_COMPLEX if (ANYCX(q) || ANYCX(p)) { r = cxop(ASSIGN, q, p); /* XXX must unwind the code generated here */ /* We can rely on correct code generated */ p = r->n_left->n_right->n_left; r->n_left->n_right->n_left = bcon(0); tfree(r); r = p->n_left->n_right; sz = (int)tsize(r->n_type, r->n_df, r->n_ap); inval(0, sz, r); inval(0, sz, p->n_right->n_right); tfree(p); break; } #endif p = optim(buildtree(ASSIGN, nt, p)); #ifndef WORD_ADDRESSED p = optim(rmpconv(p)); #endif q = p->n_right; t = q->n_type; sz = (int)tsize(t, q->n_df, q->n_ap); inval(0, sz, q); tfree(p); break; case AUTO: case REGISTER: if (ISARY(sp->stype)) cerror("no array init"); q = nt; #ifndef NO_COMPLEX if (ANYCX(q) || ANYCX(p)) r = cxop(ASSIGN, q, p); else #endif r = buildtree(ASSIGN, q, p); ecomp(r); break; default: uerror("illegal initialization"); } } pcc-20181216/cc/cxxcom/inline.c010064400017500000000000000331741277225026700150160ustar raggewheel/* $Id: inline.c,v 1.7 2016/09/26 16:45:43 ragge Exp $ */ /* * Copyright (c) 2003, 2008 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "pass1.h" #include /* * Simple description of how the inlining works: * A function found with the keyword "inline" is always saved. * If it also has the keyword "extern" it is written out thereafter. * If it has the keyword "static" it will be written out if it is referenced. * inlining will only be done if -xinline is given, and only if it is * possible to inline the function. */ static void printip(struct interpass *pole); struct ntds { int temp; TWORD type; union dimfun *df; struct attr *attr; }; /* * ilink from ipole points to the next struct in the list of functions. */ static struct istat { SLIST_ENTRY(istat) link; struct symtab *sp; int flags; #define CANINL 1 /* function is possible to inline */ #define WRITTEN 2 /* function is written out */ #define REFD 4 /* Referenced but not yet written out */ struct ntds *nt;/* Array of arg temp type data */ int nargs; /* number of args in array */ int retval; /* number of return temporary, if any */ struct interpass shead; } *cifun; static SLIST_HEAD(, istat) ipole = { NULL, &ipole.q_forw }; static int nlabs; #define IP_REF (MAXIP+1) #ifdef PCC_DEBUG #define SDEBUG(x) if (sdebug) printf x #else #define SDEBUG(x) #endif int isinlining; int inlnodecnt, inlstatcnt; #define SZSI sizeof(struct istat) #define ialloc() memset(permalloc(SZSI), 0, SZSI); inlstatcnt++ static void tcnt(NODE *p, void *arg) { inlnodecnt++; if (nlabs > 1 && (p->n_op == REG || p->n_op == OREG) && regno(p) == FPREG) SLIST_FIRST(&ipole)->flags &= ~CANINL; /* no stack refs */ if (p->n_op == NAME || p->n_op == ICON) p->n_sp = NULL; /* let symtabs be freed for inline funcs */ if (ndebug) printf("locking node %p\n", p); } static struct istat * findfun(struct symtab *sp) { struct istat *is; SLIST_FOREACH(is, &ipole, link) if (is->sp == sp) return is; return NULL; } static void refnode(struct symtab *sp) { struct interpass *ip; SDEBUG(("refnode(%s)\n", sp->sname)); ip = permalloc(sizeof(*ip)); ip->type = IP_REF; ip->ip_name = (char *)sp; inline_addarg(ip); } void inline_addarg(struct interpass *ip) { extern NODE *cftnod; SDEBUG(("inline_addarg(%p)\n", ip)); DLIST_INSERT_BEFORE(&cifun->shead, ip, qelem); if (ip->type == IP_DEFLAB) nlabs++; if (ip->type == IP_NODE) walkf(ip->ip_node, tcnt, 0); /* Count as saved */ if (cftnod) cifun->retval = regno(cftnod); } /* * Called to setup for inlining of a new function. */ void inline_start(struct symtab *sp) { struct istat *is; SDEBUG(("inline_start(\"%s\")\n", sp->sname)); if (isinlining) cerror("already inlining function"); if ((is = findfun(sp)) != 0) { if (!DLIST_ISEMPTY(&is->shead, qelem)) uerror("inline function already defined"); } else { is = ialloc(); is->sp = sp; SLIST_INSERT_FIRST(&ipole, is, link); DLIST_INIT(&is->shead, qelem); } cifun = is; nlabs = 0; isinlining++; } /* * End of an inline function. In C99 an inline function declared "extern" * should also have external linkage and are therefore printed out. * * Gcc inline syntax is a mess, see matrix below on emitting functions: * without extern * -std= - gnu89 gnu99 * gcc 3.3.5: ja ja ja * gcc 4.1.3: ja ja ja * gcc 4.3.1 ja ja nej * * with extern * gcc 3.3.5: nej nej nej * gcc 4.1.3: nej nej nej * gcc 4.3.1 nej nej ja * * The attribute gnu_inline sets gnu89 behaviour. * Since pcc mimics gcc 4.3.1 that is the behaviour we emulate. */ void inline_end(void) { struct symtab *sp = cifun->sp; SDEBUG(("inline_end()\n")); if (sdebug)printip(&cifun->shead); isinlining = 0; #ifdef GCC_COMPAT if (sp->sclass != STATIC && (attr_find(sp->sap, GCC_ATYP_GNU_INLINE) || xgnu89)) { if (sp->sclass == EXTDEF) sp->sclass = 0; else sp->sclass = EXTDEF; } #endif if (sp->sclass == EXTDEF) { cifun->flags |= REFD; inline_prtout(); } } /* * Called when an inline function is found, to be sure that it will * be written out. * The function may not be defined when inline_ref() is called. */ void inline_ref(struct symtab *sp) { struct istat *w; SDEBUG(("inline_ref(\"%s\")\n", sp->sname)); if (sp->sclass == SNULL) return; /* only inline, no references */ if (isinlining) { refnode(sp); } else { SLIST_FOREACH(w,&ipole, link) { if (w->sp != sp) continue; w->flags |= REFD; return; } /* function not yet defined, print out when found */ w = ialloc(); w->sp = sp; w->flags |= REFD; SLIST_INSERT_FIRST(&ipole, w, link); DLIST_INIT(&w->shead, qelem); } } static void puto(struct istat *w) { struct interpass_prolog *ipp, *epp, *pp; struct interpass *ip, *nip; extern int crslab; int lbloff = 0; /* Copy the saved function and print it out */ ipp = 0; /* XXX data flow analysis */ DLIST_FOREACH(ip, &w->shead, qelem) { switch (ip->type) { case IP_EPILOG: case IP_PROLOG: if (ip->type == IP_PROLOG) { ipp = (struct interpass_prolog *)ip; /* fix label offsets */ lbloff = crslab - ipp->ip_lblnum; } else { epp = (struct interpass_prolog *)ip; crslab += (epp->ip_lblnum - ipp->ip_lblnum); } pp = tmpalloc(sizeof(struct interpass_prolog)); memcpy(pp, ip, sizeof(struct interpass_prolog)); pp->ip_lblnum += lbloff; #ifdef PCC_DEBUG if (ip->type == IP_EPILOG && crslab != pp->ip_lblnum) cerror("puto: %d != %d", crslab, pp->ip_lblnum); #endif pass2_compile((struct interpass *)pp); break; case IP_REF: inline_ref((struct symtab *)ip->ip_name); break; default: nip = tmpalloc(sizeof(struct interpass)); *nip = *ip; if (nip->type == IP_NODE) { NODE *p; p = nip->ip_node = ccopy(nip->ip_node); if (p->n_op == GOTO) glval(p->n_left) += lbloff; else if (p->n_op == CBRANCH) glval(p->n_right) += lbloff; } else if (nip->type == IP_DEFLAB) nip->ip_lbl += lbloff; pass2_compile(nip); break; } } w->flags |= WRITTEN; } /* * printout functions that are referenced. */ void inline_prtout(void) { struct istat *w; int gotone = 0; SLIST_FOREACH(w, &ipole, link) { if ((w->flags & (REFD|WRITTEN)) == REFD && !DLIST_ISEMPTY(&w->shead, qelem)) { locctr(PROG, w->sp); defloc(w->sp); puto(w); w->flags |= WRITTEN; gotone++; } } if (gotone) inline_prtout(); } #if 1 static void printip(struct interpass *pole) { static char *foo[] = { 0, "NODE", "PROLOG", "STKOFF", "EPILOG", "DEFLAB", "DEFNAM", "ASM" }; struct interpass *ip; struct interpass_prolog *ipplg, *epplg; DLIST_FOREACH(ip, pole, qelem) { if (ip->type > MAXIP) printf("IP(%d) (%p): ", ip->type, ip); else printf("%s (%p): ", foo[ip->type], ip); switch (ip->type) { case IP_NODE: printf("\n"); #ifdef PCC_DEBUG fwalk(ip->ip_node, eprint, 0); break; #endif case IP_PROLOG: ipplg = (struct interpass_prolog *)ip; printf("%s %s autos %d mintemp %d minlbl %d\n", ipplg->ipp_name, ipplg->ipp_vis ? "(local)" : "", ipplg->ipp_autos, ipplg->ip_tmpnum, ipplg->ip_lblnum); break; case IP_EPILOG: epplg = (struct interpass_prolog *)ip; printf("%s %s autos %d mintemp %d minlbl %d\n", epplg->ipp_name, epplg->ipp_vis ? "(local)" : "", epplg->ipp_autos, epplg->ip_tmpnum, epplg->ip_lblnum); break; case IP_DEFLAB: printf(LABFMT "\n", ip->ip_lbl); break; case IP_DEFNAM: printf("\n"); break; case IP_ASM: printf("%s", ip->ip_asm); break; default: break; } } } #endif static int toff; static NODE * mnode(struct ntds *nt, NODE *p) { NODE *q; int num = nt->temp + toff; if (p->n_op == CM) { q = p->n_right; q = tempnode(num, nt->type, nt->df, nt->attr); nt--; p->n_right = buildtree(ASSIGN, q, p->n_right); p->n_left = mnode(nt, p->n_left); p->n_op = COMOP; } else { p = pconvert(p); q = tempnode(num, nt->type, nt->df, nt->attr); p = buildtree(ASSIGN, q, p); } return p; } static void rtmps(NODE *p, void *arg) { if (p->n_op == TEMP) regno(p) += toff; } /* * Inline a function. Returns the return value. * There are two major things that must be converted when * inlining a function: * - Label numbers must be updated with an offset. * - The stack block must be relocated (add to REG or OREG). * - Temporaries should be updated (but no must) */ NODE * inlinetree(struct symtab *sp, NODE *f, NODE *ap) { extern int crslab, tvaloff; struct istat *is = findfun(sp); struct interpass *ip, *ipf, *ipl; int lmin, l0, l1, l2, gainl; NODE *p, *rp; if (is == NULL || nerrors) { inline_ref(sp); /* prototype of not yet declared inline ftn */ return NIL; } SDEBUG(("inlinetree(%p,%p) OK %d\n", f, ap, is->flags & CANINL)); #ifdef GCC_COMPAT gainl = attr_find(sp->sap, GCC_ATYP_ALW_INL) != NULL; #else gainl = 0; #endif if ((is->flags & CANINL) == 0 && gainl) werror("cannot inline but always_inline"); if ((is->flags & CANINL) == 0 || (xinline == 0 && gainl == 0)) { if (is->sp->sclass == STATIC || is->sp->sclass == USTATIC) inline_ref(sp); return NIL; } if (isinlining && cifun->sp == sp) { /* Do not try to inline ourselves */ inline_ref(sp); return NIL; } #ifdef mach_i386 if (kflag) { is->flags |= REFD; /* if static inline, emit */ return NIL; /* XXX cannot handle hidden ebx arg */ } #endif /* emit jumps to surround inline function */ branch(l0 = getlab()); plabel(l1 = getlab()); l2 = getlab(); SDEBUG(("branch labels %d,%d,%d\n", l0, l1, l2)); ipf = DLIST_NEXT(&is->shead, qelem); /* prolog */ ipl = DLIST_PREV(&is->shead, qelem); /* epilog */ /* Fix label & temp offsets */ #define IPP(x) ((struct interpass_prolog *)x) SDEBUG(("pre-offsets crslab %d tvaloff %d\n", crslab, tvaloff)); lmin = crslab - IPP(ipf)->ip_lblnum; crslab += (IPP(ipl)->ip_lblnum - IPP(ipf)->ip_lblnum) + 1; toff = tvaloff - IPP(ipf)->ip_tmpnum; tvaloff += (IPP(ipl)->ip_tmpnum - IPP(ipf)->ip_tmpnum) + 1; SDEBUG(("offsets crslab %d lmin %d tvaloff %d toff %d\n", crslab, lmin, tvaloff, toff)); /* traverse until first real label */ ipf = DLIST_NEXT(ipf, qelem); do ipf = DLIST_NEXT(ipf, qelem); while (ipf->type != IP_DEFLAB); /* traverse backwards to last label */ do ipl = DLIST_PREV(ipl, qelem); while (ipl->type != IP_DEFLAB); /* So, walk over all statements and emit them */ for (ip = ipf; ip != ipl; ip = DLIST_NEXT(ip, qelem)) { switch (ip->type) { case IP_NODE: p = ccopy(ip->ip_node); if (p->n_op == GOTO) glval(p->n_left) += lmin; else if (p->n_op == CBRANCH) glval(p->n_right) += lmin; walkf(p, rtmps, 0); #ifdef PCC_DEBUG if (sdebug) { printf("converted node\n"); fwalk(ip->ip_node, eprint, 0); fwalk(p, eprint, 0); } #endif send_passt(IP_NODE, p); break; case IP_DEFLAB: SDEBUG(("converted label %d to %d\n", ip->ip_lbl, ip->ip_lbl + lmin)); send_passt(IP_DEFLAB, ip->ip_lbl + lmin); break; case IP_ASM: send_passt(IP_ASM, ip->ip_asm); break; case IP_REF: inline_ref((struct symtab *)ip->ip_name); break; default: cerror("bad inline stmt %d", ip->type); } } SDEBUG(("last label %d to %d\n", ip->ip_lbl, ip->ip_lbl + lmin)); send_passt(IP_DEFLAB, ip->ip_lbl + lmin); branch(l2); plabel(l0); rp = block(GOTO, bcon(l1), NIL, INT, 0, 0); if (is->retval) p = tempnode(is->retval + toff, DECREF(sp->stype), sp->sdf, sp->sap); else p = bcon(0); rp = buildtree(COMOP, rp, p); if (is->nargs) { p = mnode(&is->nt[is->nargs-1], ap); rp = buildtree(COMOP, p, rp); } tfree(f); return rp; } void inline_args(struct symtab **sp, int nargs) { union arglist *al; struct istat *cf; TWORD t; int i; SDEBUG(("inline_args\n")); cf = cifun; /* * First handle arguments. We currently do not inline anything if: * - function has varargs * - function args are volatile, checked if no temp node is asg'd. */ /* XXX - this is ugly, invent something better */ if (cf->sp->sdf->dfun == NULL) return; /* no prototype */ for (al = cf->sp->sdf->dfun; al->type != TNULL; al++) { t = al->type; if (t == TELLIPSIS) return; /* cannot inline */ if (ISSOU(BTYPE(t))) al++; for (; t > BTMASK; t = DECREF(t)) if (ISARY(t) || ISFTN(t)) al++; } if (nargs) { for (i = 0; i < nargs; i++) if ((sp[i]->sflags & STNODE) == 0) return; /* not temporary */ cf->nt = permalloc(sizeof(struct ntds)*nargs); for (i = 0; i < nargs; i++) { cf->nt[i].temp = sp[i]->soffset; cf->nt[i].type = sp[i]->stype; cf->nt[i].df = sp[i]->sdf; cf->nt[i].attr = sp[i]->sap; } } cf->nargs = nargs; cf->flags |= CANINL; } pcc-20181216/cc/cxxcom/main.c010064400017500000000000000206061306253706300144530ustar raggewheel/* $Id: main.c,v 1.7 2017/03/16 16:32:51 ragge Exp $ */ /* * Copyright (c) 2002 Anders Magnusson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #ifdef HAVE_UNISTD_H #include #endif #include #include #include #include "pass1.h" #include "pass2.h" int bdebug, ddebug, edebug, idebug, ndebug; int odebug, pdebug, sdebug, tdebug, xdebug, cppdebug, wdebug; int b2debug, c2debug, e2debug, f2debug, g2debug, o2debug; int r2debug, s2debug, t2debug, u2debug, x2debug; int gflag, kflag, pflag, sflag; int sspflag; int xscp, xssa, xtailcall, xtemps, xdeljumps, xdce, xinline, xccp, xgnu89, xgnu99; int xuchar; int freestanding; char *prgname; static void prtstats(void); static void usage(void) { (void)fprintf(stderr, "usage: %s [option] [infile] [outfile]...\n", prgname); exit(1); } static void segvcatch(int a) { char buf[1024]; snprintf(buf, sizeof buf, "%sinternal compiler error: %s, line %d\n", nerrors ? "" : "major ", ftitle, lineno); (void)write(STDERR_FILENO, buf, strlen(buf)); _exit(1); } static void xopt(char *str) { if (strcmp(str, "ssa") == 0) xssa++; else if (strcmp(str, "tailcall") == 0) xtailcall++; else if (strcmp(str, "temps") == 0) xtemps++; else if (strcmp(str, "deljumps") == 0) xdeljumps++; else if (strcmp(str, "dce") == 0) xdce++; else if (strcmp(str, "inline") == 0) xinline++; else if (strcmp(str, "ccp") == 0) xccp++; else if (strcmp(str, "gnu89") == 0) xgnu89++; else if (strcmp(str, "gnu99") == 0) xgnu99++; else if (strcmp(str, "uchar") == 0) xuchar++; else { fprintf(stderr, "unknown -x option '%s'\n", str); usage(); } } static void fflags(char *str) { int flagval = 1; if (strncmp("no-", str, 3) == 0) { str += 3; flagval = 0; } if (strcmp(str, "stack-protector") == 0) sspflag = flagval; else if (strcmp(str, "stack-protector-all") == 0) sspflag = flagval; else if (strncmp(str, "pack-struct", 11) == 0) pragma_allpacked = (strlen(str) > 12 ? atoi(str+12) : 1); else if (strcmp(str, "freestanding") == 0) freestanding = flagval; else { fprintf(stderr, "unknown -f option '%s'\n", str); usage(); } } /* control multiple files */ int main(int argc, char *argv[]) { int ch; #ifdef TIMING struct timeval t1, t2; (void)gettimeofday(&t1, NULL); #endif prgname = argv[0]; while ((ch = getopt(argc, argv, "OT:VW:X:Z:f:gkm:psvwx:")) != -1) { switch (ch) { #if !defined(MULTIPASS) || defined(PASS1) case 'X': /* pass1 debugging */ while (*optarg) switch (*optarg++) { case 'b': ++bdebug; break; /* buildtree */ case 'd': ++ddebug; break; /* declarations */ case 'e': ++edebug; break; /* pass1 exit */ case 'i': ++idebug; break; /* initializations */ case 'n': ++ndebug; break; /* node allocation */ case 'o': ++odebug; break; /* optim */ case 'p': ++pdebug; break; /* prototype */ case 's': ++sdebug; break; /* inline */ case 't': ++tdebug; break; /* type match */ case 'x': ++xdebug; break; /* MD code */ case '+': ++cppdebug; break; /* C++ */ default: fprintf(stderr, "unknown -X flag '%c'\n", optarg[-1]); exit(1); } break; #endif #if !defined(MULTIPASS) || defined(PASS2) case 'Z': /* pass2 debugging */ while (*optarg) switch (*optarg++) { case 'b': /* basic block and SSA building */ ++b2debug; break; case 'c': /* code printout */ ++c2debug; break; case 'e': /* print tree upon pass2 enter */ ++e2debug; break; case 'f': /* instruction matching */ ++f2debug; break; case 'g': /* print flow graphs */ ++g2debug; break; case 'n': /* node allocation */ ++ndebug; break; case 'o': /* instruction generator */ ++o2debug; break; case 'r': /* register alloc/graph coloring */ ++r2debug; break; case 's': /* shape matching */ ++s2debug; break; case 't': /* type matching */ ++t2debug; break; case 'u': /* Sethi-Ullman debugging */ ++u2debug; break; case 'x': /* target specific */ ++x2debug; break; default: fprintf(stderr, "unknown -Z flag '%c'\n", optarg[-1]); exit(1); } break; #endif case 'f': /* Language */ fflags(optarg); break; case 'g': /* Debugging */ gflag = 1; break; case 'k': /* PIC code */ ++kflag; break; case 'm': /* Target-specific */ mflags(optarg); break; case 'p': /* Profiling */ pflag = 1; break; case 's': /* Statistics */ ++sflag; break; case 'W': /* Enable different warnings */ Wflags(optarg); break; case 'x': /* Different settings */ xopt(optarg); break; case 'v': printf("ccom: %s\n", VERSSTR); break; case '?': default: usage(); } } argc -= optind; argv += optind; if (argc > 0 && strcmp(argv[0], "-") != 0) { if (freopen(argv[0], "r", stdin) == NULL) { fprintf(stderr, "open input file '%s':", argv[0]); perror(NULL); exit(1); } } if (argc > 1 && strcmp(argv[1], "-") != 0) { if (freopen(argv[1], "w", stdout) == NULL) { fprintf(stderr, "open output file '%s':", argv[1]); perror(NULL); exit(1); } } mkdope(); signal(SIGSEGV, segvcatch); #ifdef SIGBUS signal(SIGBUS, segvcatch); #endif fregs = FREGS; /* number of free registers */ lineno = 1; #ifdef GCC_COMPAT gcc_init(); #endif /* starts past any of the above */ reached = 1; bjobcode(); #ifndef TARGET_VALIST { NODE *p = block(NAME, NIL, NIL, PTR|CHAR, NULL, 0); struct symtab *sp = lookup(addname("__builtin_va_list"), 0); p->n_sp = sp; defid(p, TYPEDEF); nfree(p); } #endif complinit(); #ifdef STABS if (gflag) { stabs_file(argc ? argv[0] : ""); stabs_init(); } #endif if (sspflag) sspinit(); (void) yyparse(); yyaccpt(); if (!nerrors) lcommprint(); #ifdef STABS if (gflag) stabs_efile(argc ? argv[0] : ""); #endif ejobcode( nerrors ? 1 : 0 ); #ifdef TIMING (void)gettimeofday(&t2, NULL); t2.tv_sec -= t1.tv_sec; t2.tv_usec -= t1.tv_usec; if (t2.tv_usec < 0) { t2.tv_usec += 1000000; t2.tv_sec -= 1; } fprintf(stderr, "ccom total time: %ld s %ld us\n", t2.tv_sec, t2.tv_usec); #endif if (sflag) prtstats(); return(nerrors?1:0); } void prtstats(void) { extern int nametabs, namestrlen, tmpallocsize, permallocsize; extern int lostmem, arglistcnt, dimfuncnt, inlnodecnt, inlstatcnt; extern int symtabcnt, suedefcnt; fprintf(stderr, "Name table entries: %d pcs\n", nametabs); fprintf(stderr, "Name string size: %d B\n", namestrlen); fprintf(stderr, "Permanent allocated memory: %d B\n", permallocsize); fprintf(stderr, "Temporary allocated memory: %d B\n", tmpallocsize); fprintf(stderr, "Lost memory: %d B\n", lostmem); fprintf(stderr, "Argument list unions: %d pcs\n", arglistcnt); fprintf(stderr, "Dimension/function unions: %d pcs\n", dimfuncnt); fprintf(stderr, "Struct/union/enum blocks: %d pcs\n", suedefcnt); fprintf(stderr, "Inline node count: %d pcs\n", inlnodecnt); fprintf(stderr, "Inline control blocks: %d pcs\n", inlstatcnt); fprintf(stderr, "Permanent symtab entries: %d pcs\n", symtabcnt); } pcc-20181216/cc/cxxcom/optim.c010064400017500000000000000236551262511725400146660ustar raggewheel/* $Id: optim.c,v 1.5 2015/11/24 17:30:20 ragge Exp $ */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code and documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditionsand the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ # include "pass1.h" # define SWAP(p,q) {sp=p; p=q; q=sp;} # define RCON(p) (p->n_right->n_op==ICON) # define RO(p) p->n_right->n_op # define RV(p) glval(p->n_right) # define LCON(p) (p->n_left->n_op==ICON) # define LO(p) p->n_left->n_op # define LV(p) glval(p->n_left) /* remove left node */ static NODE * zapleft(NODE *p) { NODE *q; q = p->n_left; nfree(p->n_right); nfree(p); return q; } /* * fortran function arguments */ static NODE * fortarg(NODE *p) { if( p->n_op == CM ){ p->n_left = fortarg( p->n_left ); p->n_right = fortarg( p->n_right ); return(p); } while( ISPTR(p->n_type) ){ p = buildtree( UMUL, p, NIL ); } return( optim(p) ); } /* mapping relationals when the sides are reversed */ short revrel[] ={ EQ, NE, GE, GT, LE, LT, UGE, UGT, ULE, ULT }; /* * local optimizations, most of which are probably * machine independent */ NODE * optim(NODE *p) { int o, ty; NODE *sp, *q; OFFSZ sz; int i; if (odebug) return(p); ty = coptype(p->n_op); if( ty == LTYPE ) return(p); if( ty == BITYPE ) p->n_right = optim(p->n_right); p->n_left = optim(p->n_left); /* collect constants */ again: o = p->n_op; switch(o){ case SCONV: if (concast(p->n_left, p->n_type)) { q = p->n_left; nfree(p); p = q; break; } /* FALLTHROUGH */ case PCONV: if (p->n_type != VOID) p = clocal(p); break; case FORTCALL: p->n_right = fortarg( p->n_right ); break; case ADDROF: if (LO(p) == TEMP) break; if( LO(p) != NAME ) cerror( "& error" ); if( !andable(p->n_left) && !statinit) break; LO(p) = ICON; setuleft: /* paint over the type of the left hand side with the type of the top */ p->n_left->n_type = p->n_type; p->n_left->n_df = p->n_df; p->n_left->n_ap = p->n_ap; q = p->n_left; nfree(p); p = q; break; case NOT: case UMINUS: case COMPL: if (LCON(p) && conval(p->n_left, o, p->n_left)) p = nfree(p); break; case UMUL: /* Do not discard ADDROF TEMP's */ if (LO(p) == ADDROF && LO(p->n_left) != TEMP) { q = p->n_left->n_left; nfree(p->n_left); nfree(p); p = q; break; } if( LO(p) != ICON ) break; LO(p) = NAME; goto setuleft; case RS: if (LCON(p) && RCON(p) && conval(p->n_left, o, p->n_right)) goto zapright; sz = tsize(p->n_type, p->n_df, p->n_ap); if (LO(p) == RS && RCON(p->n_left) && RCON(p) && (RV(p) + RV(p->n_left)) < sz) { /* two right-shift by constants */ RV(p) += RV(p->n_left); p->n_left = zapleft(p->n_left); } #if 0 else if (LO(p) == LS && RCON(p->n_left) && RCON(p)) { RV(p) -= RV(p->n_left); if (RV(p) < 0) o = p->n_op = LS, RV(p) = -RV(p); p->n_left = zapleft(p->n_left); } #endif if (RO(p) == ICON) { if (RV(p) < 0) { RV(p) = -RV(p); p->n_op = LS; goto again; } #ifdef notyet /* must check for side effects, --a >> 32; */ if (RV(p) >= tsize(p->n_type, p->n_df, p->n_sue) && ISUNSIGNED(p->n_type)) { /* ignore signed shifts */ /* too many shifts */ tfree(p->n_left); nfree(p->n_right); p->n_op = ICON; glval(p) = 0; p->n_sp = NULL; } else #endif /* avoid larger shifts than type size */ if (RV(p) >= sz) { RV(p) = RV(p) % sz; werror("shift larger than type"); } if (RV(p) == 0) p = zapleft(p); } break; case LS: if (LCON(p) && RCON(p) && conval(p->n_left, o, p->n_right)) goto zapright; sz = tsize(p->n_type, p->n_df, p->n_ap); if (LO(p) == LS && RCON(p->n_left) && RCON(p)) { /* two left-shift by constants */ RV(p) += RV(p->n_left); p->n_left = zapleft(p->n_left); } #if 0 else if (LO(p) == RS && RCON(p->n_left) && RCON(p)) { RV(p) -= RV(p->n_left); p->n_left = zapleft(p->n_left); } #endif if (RO(p) == ICON) { if (RV(p) < 0) { RV(p) = -RV(p); p->n_op = RS; goto again; } #ifdef notyet /* must check for side effects */ if (RV(p) >= tsize(p->n_type, p->n_df, p->n_sue)) { /* too many shifts */ tfree(p->n_left); nfree(p->n_right); p->n_op = ICON; glval(p) = 0; p->n_sp = NULL; } else #endif /* avoid larger shifts than type size */ if (RV(p) >= sz) { RV(p) = RV(p) % sz; werror("shift larger than type"); } if (RV(p) == 0) p = zapleft(p); } break; case MINUS: if (LCON(p) && RCON(p) && p->n_left->n_sp == p->n_right->n_sp) { /* link-time constants, but both are the same */ /* solve it now by forgetting the symbols */ p->n_left->n_sp = p->n_right->n_sp = NULL; } if( !nncon(p->n_right) ) break; RV(p) = -RV(p); o = p->n_op = PLUS; case MUL: /* * Check for u=(x-y)+z; where all vars are pointers to * the same struct. This has two advantages: * 1: avoid a mul+div * 2: even if not allowed, people may get surprised if this * calculation do not give correct result if using * unaligned structs. */ if (p->n_type == INTPTR && RCON(p) && LO(p) == DIV && RCON(p->n_left) && RV(p) == RV(p->n_left) && LO(p->n_left) == MINUS) { q = p->n_left->n_left; if (q->n_left->n_type == PTR+STRTY && q->n_right->n_type == PTR+STRTY && strmemb(q->n_left->n_ap) == strmemb(q->n_right->n_ap)) { p = zapleft(p); p = zapleft(p); } } /* FALLTHROUGH */ case PLUS: case AND: case OR: case ER: /* commutative ops; for now, just collect constants */ /* someday, do it right */ if( nncon(p->n_left) || ( LCON(p) && !RCON(p) ) ) SWAP( p->n_left, p->n_right ); /* make ops tower to the left, not the right */ if( RO(p) == o ){ NODE *t1, *t2, *t3; t1 = p->n_left; sp = p->n_right; t2 = sp->n_left; t3 = sp->n_right; /* now, put together again */ p->n_left = sp; sp->n_left = t1; sp->n_right = t2; sp->n_type = p->n_type; p->n_right = t3; } if(o == PLUS && LO(p) == MINUS && RCON(p) && RCON(p->n_left) && conval(p->n_right, MINUS, p->n_left->n_right)){ zapleft: q = p->n_left->n_left; nfree(p->n_left->n_right); nfree(p->n_left); p->n_left = q; } if( RCON(p) && LO(p)==o && RCON(p->n_left) && conval( p->n_right, o, p->n_left->n_right ) ){ goto zapleft; } else if( LCON(p) && RCON(p) && conval( p->n_left, o, p->n_right ) ){ zapright: nfree(p->n_right); q = makety(p->n_left, p->n_type, p->n_qual, p->n_df, p->n_ap); nfree(p); p = clocal(q); break; } /* change muls to shifts */ if( o == MUL && nncon(p->n_right) && (i=ispow2(RV(p)))>=0){ if( i == 0 ) { /* multiplication by 1 */ goto zapright; } o = p->n_op = LS; p->n_right->n_type = INT; p->n_right->n_df = NULL; RV(p) = i; } /* change +'s of negative consts back to - */ if( o==PLUS && nncon(p->n_right) && RV(p)<0 ){ RV(p) = -RV(p); o = p->n_op = MINUS; } /* remove ops with RHS 0 */ if ((o == PLUS || o == MINUS || o == OR || o == ER) && nncon(p->n_right) && RV(p) == 0) { goto zapright; } break; case DIV: if( nncon( p->n_right ) && glval(p->n_right) == 1 ) goto zapright; if (LCON(p) && RCON(p) && conval(p->n_left, DIV, p->n_right)) goto zapright; if (RCON(p) && ISUNSIGNED(p->n_type) && (i=ispow2(RV(p))) > 0) { p->n_op = RS; RV(p) = i; q = p->n_right; if(tsize(q->n_type, q->n_df, q->n_ap) > SZINT) p->n_right = makety(q, INT, 0, 0, 0); break; } break; case MOD: if (RCON(p) && ISUNSIGNED(p->n_type) && ispow2(RV(p)) > 0) { p->n_op = AND; RV(p) = RV(p) -1; break; } break; case EQ: case NE: case LT: case LE: case GT: case GE: case ULT: case ULE: case UGT: case UGE: if( !LCON(p) ) break; /* exchange operands */ sp = p->n_left; p->n_left = p->n_right; p->n_right = sp; p->n_op = revrel[p->n_op - EQ ]; break; #ifdef notyet case ASSIGN: /* Simple test to avoid two branches */ if (RO(p) != NE) break; q = p->n_right; if (RCON(q) && RV(q) == 0 && LO(q) == AND && RCON(q->n_left) && (i = ispow2(RV(q->n_left))) && q->n_left->n_type == INT) { q->n_op = RS; RV(q) = i; } break; #endif } return(p); } int ispow2(CONSZ c) { int i; if( c <= 0 || (c&(c-1)) ) return(-1); for( i=0; c>1; ++i) c >>= 1; return(i); } int nncon(NODE *p) { /* is p a constant without a name */ return( p->n_op == ICON && p->n_sp == NULL ); } pcc-20181216/cc/cxxcom/pass1.h010064400017500000000000000431171266657571500146040ustar raggewheel/* $Id: pass1.h,v 1.20 2016/03/05 15:31:25 ragge Exp $ */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code and documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditionsand the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include #include #include #ifdef HAVE_STDINT_H #include #endif #include #ifndef MKEXT #include "external.h" #else typedef unsigned int bittype; /* XXX - for basicblock */ #endif #include "manifest.h" #include "softfloat.h" /* * Storage classes */ #define SNULL 0 #define AUTO 1 #define EXTERN 2 #define STATIC 3 #define REGISTER 4 #define EXTDEF 5 /* #define LABEL 6*/ /* #define ULABEL 7*/ #define MOS 8 #define PARAM 9 #define STNAME 10 #define MOU 11 #define UNAME 12 #define TYPEDEF 13 /* #define FORTRAN 14 */ #define ENAME 15 #define MOE 16 /* #define UFORTRAN 17 */ #define USTATIC 18 #define MAXSTCL 20 /* field size is ORed in */ #define FIELD 0200 #define FLDSIZ 0177 extern char *scnames(int); /* * Symbol table flags */ #define SNORMAL 0 #define STAGNAME 01 #define SLBLNAME 02 #define SMOSNAME 03 #define SSTRING 04 #define NSTYPES 05 #define SMASK 07 #define STLS 00010 /* Thread Local Support variable */ /* #define SREF 00020 */ #define SNOCREAT 00040 /* don't create a symbol in lookup() */ #define STEMP 00100 /* Allocate symtab from temp or perm mem */ #define SDYNARRAY 00200 /* symbol is dynamic array on stack */ #define SINLINE 00400 /* function is of type inline */ #define STNODE 01000 /* symbol shall be a temporary node */ #define SBUILTIN 02000 /* this is a builtin function */ #define SASG 04000 /* symbol is assigned to already */ #define SLOCAL1 010000 #define SLOCAL2 020000 #define SLOCAL3 040000 /* alignment of initialized quantities */ #ifndef AL_INIT #define AL_INIT ALINT #endif struct rstack; struct symtab; union arglist; #ifdef GCC_COMPAT struct gcc_attr_pack; #endif struct namespace; /* * Dimension/prototype information. * ddim > 0 holds the dimension of an array. * ddim < 0 is a dynamic array and refers to a tempnode. * ...unless: * ddim == NOOFFSET, an array without dimenston, "[]" * ddim == -1, dynamic array while building before defid. */ union dimfun { int ddim; /* Dimension of an array */ union arglist *dfun; /* Prototype index */ }; /* * Argument list member info when storing prototypes. */ union arglist { TWORD type; union dimfun *df; struct attr *sap; }; #define TNULL INCREF(FARG) /* pointer to FARG -- impossible type */ #define TELLIPSIS INCREF(INCREF(FARG)) /* * Symbol table definition. */ struct symtab { struct symtab *snext; /* link to other symbols in the same scope */ struct symtab *sdown; /* link to parent class */ struct symtab *sup; /* link to child class */ int soffset; /* offset or value */ char sclass; /* storage class */ char slevel; /* scope level */ short sflags; /* flags, see below */ char *sname; /* Symbol name */ char *soname; /* Written-out name */ TWORD stype; /* type word */ TWORD squal; /* qualifier word */ union dimfun *sdf; /* ptr to the dimension/prototype array */ struct attr *sap; /* the base type attribute list */ }; #define ISSOU(ty) ((ty) == STRTY || (ty) == UNIONTY) /* * External definitions */ struct swents { /* switch table */ struct swents *next; /* Next struct in linked list */ CONSZ sval; /* case value */ int slab; /* associated label */ }; int mygenswitch(int, TWORD, struct swents **, int); extern int blevel; extern int oldstyle; extern int lineno, nerrors; extern char *ftitle; extern struct symtab *cftnsp; extern int autooff, maxautooff, argoff; extern OFFSZ inoff; extern int reached; extern int isinlining; extern int xinline, xgnu89, xgnu99; extern int bdebug, ddebug, edebug, idebug, ndebug; extern int odebug, pdebug, sdebug, tdebug, xdebug; /* various labels */ extern int brklab; extern int contlab; extern int flostat; extern int retlab; extern int doing_init, statinit; extern short sztable[]; extern char *astypnames[]; /* pragma globals */ extern int pragma_allpacked, pragma_packed, pragma_aligned; extern char *pragma_renamed; /* * Flags used in the (elementary) flow analysis ... */ #define FBRK 02 #define FCONT 04 #define FDEF 010 #define FLOOP 020 /* * Location counters */ #define NOSEG -1 #define PROG 0 /* (ro) program segment */ #define DATA 1 /* (rw) data segment */ #define RDATA 2 /* (ro) data segment */ #define LDATA 3 /* (rw) local data */ #define UDATA 4 /* (rw) uninitialized data */ #define STRNG 5 /* (ro) string segment */ #define PICDATA 6 /* (rw) relocatable data segment */ #define PICRDATA 7 /* (ro) relocatable data segment */ #define PICLDATA 8 /* (rw) local relocatable data */ #define TLSDATA 9 /* (rw) TLS data segment */ #define TLSUDATA 10 /* (rw) TLS uninitialized segment */ #define CTORS 11 /* constructor */ #define DTORS 12 /* destructor */ #define NMSEG 13 /* other (named) segment */ extern int lastloc; void locctr(int type, struct symtab *sp); void setseg(int type, char *name); void defalign(int al); void symdirec(struct symtab *sp); /* mark an offset which is undefined */ #define NOOFFSET (-10201) /* declarations of various functions */ extern NODE *buildtree(int, NODE *, NODE *r), *mkty(unsigned, union dimfun *, struct attr *), *rstruct(char *, int), *dclstruct(struct rstack *), *strend(int gtype, char *), *tymerge(NODE *, NODE *), *stref(NODE *), #ifdef WORD_ADDRESSED *offcon(OFFSZ, TWORD, union dimfun *, struct attr *), #endif *bcon(int), *xbcon(CONSZ, struct symtab *, TWORD), *bpsize(NODE *), *convert(NODE *, int), *pconvert(NODE *), *oconvert(NODE *), *ptmatch(NODE *), *makety(NODE *, TWORD, TWORD, union dimfun *, struct attr *), *block(int, NODE *, NODE *, TWORD, union dimfun *, struct attr *), *doszof(NODE *), *talloc(void), *optim(NODE *), *clocal(NODE *), *ccopy(NODE *), *tempnode(int, TWORD, union dimfun *, struct attr *), *eve(NODE *), *doacall(struct symtab *, NODE *, NODE *, int); NODE *intprom(NODE *); OFFSZ tsize(TWORD, union dimfun *, struct attr *), psize(NODE *); NODE * typenode(NODE *new); void spalloc(NODE *, NODE *, OFFSZ); char *exname(char *); NODE *floatcon(char *); NODE *fhexcon(char *); NODE *bdty(int op, ...); extern struct rstack *rpole; int oalloc(struct symtab *, int *); void deflabel(char *, NODE *); void gotolabel(char *); unsigned int esccon(char **); void inline_start(struct symtab *); void inline_end(void); void inline_addarg(struct interpass *); void inline_ref(struct symtab *); void inline_prtout(void); void inline_args(struct symtab **, int); NODE *inlinetree(struct symtab *, NODE *, NODE *); void ftnarg(NODE *); struct rstack *bstruct(char *, int, NODE *); void moedef(char *); void beginit(struct symtab *); void simpleinit(struct symtab *, NODE *); struct symtab *lookup(char *, int); struct symtab *getsymtab(char *, int); char *addstring(char *); char *addname(char *); void symclear(int); struct symtab *hide(struct symtab *); void soumemb(NODE *, char *, int); int talign(unsigned int, struct attr *); void bfcode(struct symtab **, int); int chkftn(union arglist *, union arglist *); void branch(int); void cbranch(NODE *, NODE *); void extdec(struct symtab *); void defzero(struct symtab *); int falloc(struct symtab *, int, NODE *); TWORD ctype(TWORD); void inval(CONSZ, int, NODE *); int ninval(CONSZ, int, NODE *); void infld(CONSZ, int, CONSZ); void zbits(CONSZ, int); void instring(struct symtab *); void inwstring(struct symtab *); void plabel(int); void bjobcode(void); void ejobcode(int); void calldec(NODE *, NODE *); int cisreg(TWORD); void asginit(NODE *); void desinit(NODE *); void endinit(int); void endictx(void); void sspinit(void); void sspstart(void); void sspend(void); void ilbrace(void); void irbrace(void); CONSZ scalinit(NODE *); void p1print(char *, ...); char *copst(int); int cdope(int); void myp2tree(NODE *); void lcommprint(void); void lcommdel(struct symtab *); NODE *funcode(NODE *); struct symtab *enumhd(char *); NODE *enumdcl(struct symtab *); NODE *enumref(char *); CONSZ icons(NODE *); CONSZ valcast(CONSZ v, TWORD t); int mypragma(char *); char *pragtok(char *); int eat(int); void fixdef(struct symtab *); int cqual(TWORD, TWORD); void defloc(struct symtab *); int fldchk(int); int nncon(NODE *); void cunput(char); NODE *nametree(struct symtab *sp); void *inlalloc(int size); void *blkalloc(int size); void pass1_lastchance(struct interpass *); void fldty(struct symtab *p); int getlab(void); struct suedef *sueget(struct suedef *p); void complinit(void); NODE *structref(NODE *p, int f, char *name); NODE *cxop(int op, NODE *l, NODE *r); NODE *imop(int op, NODE *l, NODE *r); NODE *cxelem(int op, NODE *p); NODE *cxconj(NODE *p); NODE *cxret(NODE *p, NODE *q); NODE *cast(NODE *p, TWORD t, TWORD q); NODE *ccast(NODE *p, TWORD t, TWORD u, union dimfun *df, struct attr *sue); int andable(NODE *); int conval(NODE *, int, NODE *); int ispow2(CONSZ); void defid(NODE *q, int class); void efcode(void); void ecomp(NODE *p); int upoff(int size, int alignment, int *poff); void nidcl(NODE *p, int class); void eprint(NODE *, int, int *, int *); int uclass(int class); int notlval(NODE *); void ecode(NODE *p); void ftnend(void); void dclargs(void); int suemeq(struct attr *s1, struct attr *s2); struct symtab *strmemb(struct attr *ap); int yylex(void); void yyerror(char *); int pragmas_gcc(char *t); NODE *cstknode(TWORD t, union dimfun *df, struct attr *ap); int concast(NODE *p, TWORD t); #ifdef WORD_ADDRESSED #define rmpconv(p) (p) #else NODE *rmpconv(NODE *); #endif NODE *nlabel(int label); int isbuiltin(char *n); char *getexname(struct symtab *); enum { ATTR_FIRST = ATTR_MI_MAX + 1, /* PCC used attributes */ ATTR_COMPLEX, /* Internal definition of complex */ xxxATTR_BASETYP, /* Internal; see below */ ATTR_QUALTYP, /* Internal; const/volatile, see below */ ATTR_ALIGNED, ATTR_STRUCT, /* Internal; element list */ #define ATTR_MAX ATTR_STRUCT ATTR_SONAME, #ifdef GCC_COMPAT /* type attributes */ GCC_ATYP_PACKED, GCC_ATYP_SECTION, GCC_ATYP_TRANSP_UNION, GCC_ATYP_UNUSED, GCC_ATYP_DEPRECATED, GCC_ATYP_MAYALIAS, /* variable attributes */ GCC_ATYP_MODE, /* function attributes */ GCC_ATYP_NORETURN, GCC_ATYP_FORMAT, GCC_ATYP_NONNULL, GCC_ATYP_SENTINEL, GCC_ATYP_WEAK, GCC_ATYP_FORMATARG, GCC_ATYP_GNU_INLINE, GCC_ATYP_MALLOC, GCC_ATYP_NOTHROW, GCC_ATYP_CONST, GCC_ATYP_PURE, GCC_ATYP_CONSTRUCTOR, GCC_ATYP_DESTRUCTOR, GCC_ATYP_VISIBILITY, GCC_ATYP_WARN_UNUSED_RESULT, GCC_ATYP_USED, GCC_ATYP_NO_INSTR_FUN, GCC_ATYP_NOINLINE, GCC_ATYP_ALIAS, GCC_ATYP_WEAKREF, GCC_ATYP_ALLOCSZ, GCC_ATYP_ALW_INL, GCC_ATYP_TLSMODEL, GCC_ATYP_ALIASWEAK, GCC_ATYP_REGPARM, GCC_ATYP_FASTCALL, /* other stuff */ GCC_ATYP_BOUNDED, /* OpenBSD extra boundary checks */ GCC_ATYP_MAX, #endif #ifdef ATTR_P1_TARGET ATTR_P1_TARGET, #endif ATTR_P1_MAX }; struct flt { long double fp; }; typedef struct flt FLT; extern FLT flt_zero; #define fltallo() tmpalloc(sizeof(FLT)) #define FCAST(x) ((FLT *)x) #define FLOAT_ZERO (&flt_zero) #define FLOAT_PLUS(p1,p2) (FCAST((p1)->n_dcon)->fp += FCAST((p2)->n_dcon)->fp) #define FLOAT_MINUS(p1,p2) (FCAST((p1)->n_dcon)->fp -= FCAST((p2)->n_dcon)->fp) #define FLOAT_MUL(p1,p2) (FCAST((p1)->n_dcon)->fp *= FCAST((p2)->n_dcon)->fp) #define FLOAT_DIV(p1,p2) (FCAST((p1)->n_dcon)->fp /= FCAST((p2)->n_dcon)->fp) #define FLOAT_ISZERO(p) ((p)->fp == 0.0) #define FLOAT_FP2FP(f,t) (f->fp = (t == FLOAT ? (float)f->fp : \ t == DOUBLE ? (double)f->fp : f->fp)) #define FLOAT_INT2FP(d,p,v) (ISUNSIGNED(v) ? \ (d->fp = (long double)(U_CONSZ)(p)) : (d->fp = (long double)(CONSZ)(p))) #define FLOAT_FP2INT(i,d,t) (ISUNSIGNED(t) ? \ (i = (U_CONSZ)(d->fp)) : (i = d->fp)) #define FLOAT_EQ(d1,d2) (d1->fp == d2->fp) #define FLOAT_NE(d1,d2) (d1->fp != d2->fp) #define FLOAT_GE(d1,d2) (d1->fp >= d2->fp) #define FLOAT_GT(d1,d2) (d1->fp > d2->fp) #define FLOAT_LE(d1,d2) (d1->fp <= d2->fp) #define FLOAT_LT(d1,d2) (d1->fp < d2->fp) #define FLOAT_NEG(p) (p->fp = -p->fp) #define FLOAT_SETZERO(d) (d)->fp = FLOAT_ZERO /* #ifdef notdef * ATTR_BASETYP has the following layout: * aa[0].iarg has size * aa[1].iarg has alignment #endif * ATTR_QUALTYP has the following layout: * aa[0].iarg has CON/VOL + FUN/ARY/PTR * Not defined yet... * aa[3].iarg is dimension for arrays (XXX future) * aa[3].varg is function defs for functions. */ #ifdef notdef #define atypsz aa[0].iarg #define aalign aa[1].iarg #endif /* * ATTR_STRUCT member list. */ #define amlist aa[0].varg #define amsize aa[1].iarg #define strattr(x) (attr_find(x, ATTR_STRUCT)) #define iarg(x) aa[x].iarg #define sarg(x) aa[x].sarg #define varg(x) aa[x].varg void gcc_init(void); int gcc_keyword(char *, NODE **); struct attr *gcc_attr_parse(NODE *); void gcc_tcattrfix(NODE *); struct gcc_attrib *gcc_get_attr(struct suedef *, int); void dump_attr(struct attr *gap); #ifndef NO_C_BUILTINS struct bitable { char *name; NODE *(*fun)(const struct bitable *, NODE *a); short flags; #define BTNOPROTO 001 #define BTNORVAL 002 #define BTNOEVE 004 short narg; TWORD *tp; TWORD rt; }; NODE *builtin_check(struct symtab *, NODE *a); void builtin_init(void); /* Some builtins targets need to implement */ NODE *builtin_frame_address(const struct bitable *bt, NODE *a); NODE *builtin_return_address(const struct bitable *bt, NODE *a); NODE *builtin_cfa(const struct bitable *bt, NODE *a); #endif #ifdef STABS void stabs_init(void); void stabs_file(char *); void stabs_efile(char *); void stabs_line(int); void stabs_rbrac(int); void stabs_lbrac(int); void stabs_func(struct symtab *); void stabs_newsym(struct symtab *); void stabs_chgsym(struct symtab *); void stabs_struct(struct symtab *, struct attr *); #endif #ifndef CHARCAST /* to make character constants into character connstants */ /* this is a macro to defend against cross-compilers, etc. */ #define CHARCAST(x) (char)(x) #endif /* sometimes int is smaller than pointers */ #if SZPOINT(CHAR) <= SZINT #define INTPTR INT #elif SZPOINT(CHAR) <= SZLONG #define INTPTR LONG #elif SZPOINT(CHAR) <= SZLONGLONG #define INTPTR LONGLONG #else #error int size unknown #endif #ifdef TWOPASS #define PRTPREF "* " #else #define PRTPREF "" #endif /* Generate a bitmask from a given type size */ #define SZMASK(y) ((((1LL << ((y)-1))-1) << 1) | 1) /* * C compiler first pass extra defines. */ #define QUALIFIER (MAXOP+1) #define CLASS (MAXOP+2) #define RB (MAXOP+3) #define DOT (MAXOP+4) #define ELLIPSIS (MAXOP+5) #define TYPE (MAXOP+6) #define LB (MAXOP+7) #define COMOP (MAXOP+8) #define QUEST (MAXOP+9) #define COLON (MAXOP+10) #define ANDAND (MAXOP+11) #define OROR (MAXOP+12) #define NOT (MAXOP+13) #define CAST (MAXOP+14) #define STRING (MAXOP+15) /* The following must be in the same order as their NOASG counterparts */ #define PLUSEQ (MAXOP+16) #define MINUSEQ (MAXOP+17) #define DIVEQ (MAXOP+18) #define MODEQ (MAXOP+19) #define MULEQ (MAXOP+20) #define ANDEQ (MAXOP+21) #define OREQ (MAXOP+22) #define EREQ (MAXOP+23) #define LSEQ (MAXOP+24) #define RSEQ (MAXOP+25) #define UNASG (-(PLUSEQ-PLUS))+ #define INCR (MAXOP+26) #define DECR (MAXOP+27) #define SZOF (MAXOP+28) #define CLOP (MAXOP+29) #define ATTRIB (MAXOP+30) #define XREAL (MAXOP+31) #define XIMAG (MAXOP+32) #define TYMERGE (MAXOP+33) #define LABEL (MAXOP+34) #define STREF (MAXOP+35) /* * The following types are only used in pass1. */ #define SIGNED (MAXTYPES+1) #define FARG (MAXTYPES+2) #define FIMAG (MAXTYPES+3) #define IMAG (MAXTYPES+4) #define LIMAG (MAXTYPES+5) #define FCOMPLEX (MAXTYPES+6) #define COMPLEX (MAXTYPES+7) #define LCOMPLEX (MAXTYPES+8) #define ENUMTY (MAXTYPES+9) #define ISFTY(x) ((x) >= FLOAT && (x) <= LDOUBLE) #define ISCTY(x) ((x) >= FCOMPLEX && (x) <= LCOMPLEX) #define ISITY(x) ((x) >= FIMAG && (x) <= LIMAG) #define ANYCX(p) (p->n_type == STRTY && attr_find(p->n_ap, ATTR_COMPLEX)) #define coptype(o) (cdope(o)&TYFLG) #define clogop(o) (cdope(o)&LOGFLG) #define casgop(o) (cdope(o)&ASGFLG) #define slval setlval #define glval getlval #include pcc-20181216/cc/cxxcom/pftn.c010064400017500000000000002105701277716665000145130ustar raggewheel/* $Id: pftn.c,v 1.17 2016/10/11 13:48:24 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code and documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditionsand the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Many changes from the 32V sources, among them: * - New symbol table manager (moved to another file). * - Prototype saving/checks. */ # include "pass1.h" #include "cgram.h" struct symtab *cftnsp; int arglistcnt, dimfuncnt; /* statistics */ int symtabcnt, suedefcnt; /* statistics */ int autooff, /* the next unused automatic offset */ maxautooff, /* highest used automatic offset in function */ argoff; /* the next unused argument offset */ int retlab = NOLAB; /* return label for subroutine */ int brklab; int contlab; int flostat; int blevel; int reached, prolab; struct params; #define MKTY(p, t, d, s) r = talloc(); *r = *p; \ r = argcast(r, t, d, s); *p = *r; nfree(r); /* * Linked list stack while reading in structs. */ struct rstack { struct rstack *rnext; int rsou; int rstr; struct symtab *rsym; // struct symtab *rb; struct attr *ap; int flags; #define LASTELM 1 } *rpole; /* * Linked list for parameter (and struct elements) declaration. */ static struct params { struct params *prev; struct symtab *sym; } *lparam; static int nparams; /* defines used for getting things off of the initialization stack */ NODE *arrstk[10]; int arrstkp; static int intcompare; NODE *parlink; void fixtype(NODE *p, int class); int fixclass(int class, TWORD type); static void dynalloc(struct symtab *p, int *poff); static void evalidx(struct symtab *p); int isdyn(struct symtab *p); void inforce(OFFSZ n); void vfdalign(int n); static void ssave(struct symtab *); #ifdef PCC_DEBUG static void alprint(union arglist *al, int in); #endif static void lcommadd(struct symtab *sp); static NODE *mkcmplx(NODE *p, TWORD dt); extern int fun_inline; FLT flt_zero = { .fp = 0.0, }; /* * Declaration of an identifier. Handles redeclarations, hiding, * incomplete types and forward declarations. * * q is a TYPE node setup after parsing with n_type, n_df and n_ap. * n_sp is a pointer to the not-yet initalized symbol table entry * unless it's a redeclaration or supposed to hide a variable. */ void defid(NODE *q, int class) { struct attr *ap; struct symtab *p; TWORD type, qual; TWORD stp, stq; int scl; union dimfun *dsym, *ddef; int slev, temp, changed; if (q == NIL) return; /* an error was detected */ p = q->n_sp; if (p->sname == NULL) cerror("defining null identifier"); #ifdef PCC_DEBUG if (ddebug) { printf("defid(%s (%p), ", p->sname, p); tprint(q->n_type, q->n_qual); printf(", %s, (%p)), level %d\n\t", scnames(class), q->n_df, blevel); #ifdef GCC_COMPAT dump_attr(q->n_ap); #endif } #endif fixtype(q, class); type = q->n_type; qual = q->n_qual; class = fixclass(class, type); stp = p->stype; stq = p->squal; slev = p->slevel; #ifdef PCC_DEBUG if (ddebug) { printf(" modified to "); tprint(type, qual); printf(", %s\n", scnames(class)); printf(" previous def'n: "); tprint(stp, stq); printf(", %s, (%p,%p)), level %d\n", scnames(p->sclass), p->sdf, p->sap, slev); } #endif if (blevel == 1) { switch (class) { default: if (!(class&FIELD) && !ISFTN(type)) uerror("declared argument %s missing", p->sname ); case MOS: case MOU: cerror("field5"); case TYPEDEF: case PARAM: ; } } if (stp == UNDEF) goto enter; /* New symbol */ if (type != stp) goto mismatch; if (blevel > slev && (class == AUTO || class == REGISTER)) /* new scope */ goto mismatch; /* * test (and possibly adjust) dimensions. * also check that prototypes are correct. */ dsym = p->sdf; ddef = q->n_df; changed = 0; for (temp = type; temp & TMASK; temp = DECREF(temp)) { if (ISARY(temp)) { if (dsym->ddim == NOOFFSET) { dsym->ddim = ddef->ddim; changed = 1; } else if (ddef->ddim != NOOFFSET && dsym->ddim!=ddef->ddim) { goto mismatch; } ++dsym; ++ddef; } else if (ISFTN(temp)) { /* add a late-defined prototype here */ if (cftnsp == NULL && dsym->dfun == NULL) dsym->dfun = ddef->dfun; if (!oldstyle && ddef->dfun != NULL && chkftn(dsym->dfun, ddef->dfun)) uerror("declaration doesn't match prototype"); dsym++, ddef++; } } #ifdef STABS if (changed && gflag) stabs_chgsym(p); /* symbol changed */ #endif /* check that redeclarations are to the same structure */ if (temp == STRTY || temp == UNIONTY) { if (strmemb(p->sap) != strmemb(q->n_ap)) goto mismatch; } scl = p->sclass; #ifdef PCC_DEBUG if (ddebug) printf(" previous class: %s\n", scnames(scl)); #endif /* * Its allowed to add attributes to existing declarations. * Be careful though not to trash existing attributes. * XXX - code below is probably not correct. */ if (p->sap && p->sap->atype <= ATTR_MAX) { /* nothing special, just overwrite */ p->sap = q->n_ap; } else { if (p->slevel == blevel) { for (ap = q->n_ap; ap; ap = ap->next) { if (ap->atype > ATTR_MAX) p->sap = attr_add(p->sap, attr_dup(ap)); } } else p->sap = q->n_ap; } if (class & FIELD) cerror("field1"); switch(class) { case EXTERN: if (pragma_renamed) p->soname = pragma_renamed; pragma_renamed = NULL; switch( scl ){ case STATIC: case USTATIC: if( slev==0 ) goto done; break; case EXTDEF: case EXTERN: goto done; case SNULL: if (p->sflags & SINLINE) { p->sclass = EXTDEF; inline_ref(p); goto done; } break; } break; case STATIC: if (scl==USTATIC || (scl==EXTERN && blevel==0)) { p->sclass = STATIC; goto done; } if (changed || (scl == STATIC && blevel == slev)) goto done; /* identical redeclaration */ break; case USTATIC: if (scl==STATIC || scl==USTATIC) goto done; break; case TYPEDEF: if (scl == class) goto done; break; case MOU: case MOS: cerror("field6"); case EXTDEF: switch (scl) { case EXTERN: p->sclass = EXTDEF; goto done; case USTATIC: p->sclass = STATIC; goto done; case SNULL: /* * Handle redeclarations of inlined functions. * This is allowed if the previous declaration is of * type gnu_inline. */ #ifdef GCC_COMPAT if (attr_find(p->sap, GCC_ATYP_GNU_INLINE)) goto done; #endif break; } break; case AUTO: case REGISTER: break; /* mismatch.. */ case SNULL: if (fun_inline && ISFTN(type)) goto done; break; } mismatch: /* * Only allowed for automatic variables. */ if (blevel <= slev || class == EXTERN) { uerror("redeclaration of %s", p->sname); return; } q->n_sp = p = hide(p); enter: /* make a new entry */ #ifdef PCC_DEBUG if(ddebug) printf(" new entry made\n"); #endif #ifdef GCC_COMPAT if (type < BTMASK && (ap = attr_find(q->n_ap, GCC_ATYP_MODE))) { type = ENUNSIGN(ap->iarg(0)); if (type == XTYPE) uerror("fix XTYPE basetyp"); } #endif p->stype = type; p->squal = qual; p->sclass = (char)class; p->slevel = (char)blevel; p->soffset = NOOFFSET; #if 0 if (class != TYPEDEF && blevel == 0) p->soname = decoratename(p, NM_NORMAL); #endif if (q->n_ap) p->sap = attr_add(q->n_ap, p->sap); /* copy dimensions */ p->sdf = q->n_df; /* Do not save param info for old-style functions */ if (ISFTN(type) && oldstyle) p->sdf->dfun = NULL; if (arrstkp) evalidx(p); /* allocate offsets */ if (class&FIELD) { cerror("field2"); /* new entry */ } else switch (class) { case REGISTER: cerror("register var"); case AUTO: if (isdyn(p)) { p->sflags |= SDYNARRAY; dynalloc(p, &autooff); } else oalloc(p, &autooff); break; case PARAM: if (q->n_type != FARG) oalloc(p, &argoff); break; case STATIC: case EXTDEF: case EXTERN: p->soffset = getlab(); if (pragma_renamed) p->soname = pragma_renamed; pragma_renamed = NULL; break; case MOU: case MOS: cerror("field7"); case SNULL: #ifdef notdef if (fun_inline) { p->slevel = 1; p->soffset = getlab(); } #endif break; } #ifdef STABS if (gflag && p->stype != FARG) stabs_newsym(p); #endif done: cxxsetname(p); fixdef(p); /* Leave last word to target */ #ifndef HAVE_WEAKREF { struct attr *at; /* Refer renamed function */ if ((at = attr_find(p->sap, GCC_ATYP_WEAKREF))) p->soname = at->sarg(0); } #endif #ifdef PCC_DEBUG if (ddebug) { printf( " sdf, offset: %p, %d\n\t", p->sdf, p->soffset); #ifdef GCC_COMPAT dump_attr(p->sap); #endif } #endif } void ssave(struct symtab *sym) { struct params *p; p = tmpalloc(sizeof(struct params)); p->prev = lparam; p->sym = sym; lparam = p; } /* * end of function */ void ftnend(void) { #ifdef GCC_COMPAT struct attr *gc, *gd; #endif extern NODE *cftnod; extern struct savbc *savbc; extern struct swdef *swpole; extern int tvaloff; char *c; if (retlab != NOLAB && nerrors == 0) { /* inside a real function */ plabel(retlab); if (cftnod) ecomp(buildtree(FORCE, cftnod, NIL)); efcode(); /* struct return handled here */ if ((c = cftnsp->soname) == NULL) c = addname(exname(cftnsp->sname)); SETOFF(maxautooff, ALCHAR); send_passt(IP_EPILOG, maxautooff/SZCHAR, c, cftnsp->stype, cftnsp->sclass == EXTDEF, retlab, tvaloff); } cftnod = NIL; tcheck(); brklab = contlab = retlab = NOLAB; flostat = 0; if (nerrors == 0) { if (savbc != NULL) cerror("bcsave error"); if (lparam != NULL) cerror("parameter reset error"); if (swpole != NULL) cerror("switch error"); } #ifdef GCC_COMPAT if (cftnsp) { gc = attr_find(cftnsp->sap, GCC_ATYP_CONSTRUCTOR); gd = attr_find(cftnsp->sap, GCC_ATYP_DESTRUCTOR); if (gc || gd) { struct symtab sts = *cftnsp; NODE *p; sts.stype = INCREF(sts.stype); p = nametree(&sts); p->n_op = ICON; if (gc) { locctr(CTORS, &sts); inval(0, SZPOINT(0), p); } if (gd) { locctr(DTORS, &sts); inval(0, SZPOINT(0), p); } tfree(p); } } #endif savbc = NULL; lparam = NULL; cftnsp = NULL; maxautooff = autooff = AUTOINIT; reached = 1; if (isinlining) inline_end(); inline_prtout(); tmpfree(); /* Release memory resources */ } static struct symtab nulsym = { NULL, NULL, NULL, 0, 0, 0, 0, "null", "null", INT, 0, NULL, NULL }; void dclargs(void) { union dimfun *df; union arglist *al, *al2, *alb; struct params *a; struct symtab *p, **parr = NULL; /* XXX gcc */ int i; /* * Deal with fun(void) properly. */ if (nparams == 1 && lparam->sym && lparam->sym->stype == VOID) goto done; if (cftnsp->sdown && cftnsp->sdown->sclass != NSPACE) { /* first arg is a pointer to the "sprev" class */ p = cxxstrvar(cftnsp->sdown); ssave(p); nparams++; } /* * Generate a list for bfcode(). * Parameters were pushed in reverse order. */ if (nparams != 0) parr = tmpalloc(sizeof(struct symtab *) * nparams); if (nparams) for (a = lparam, i = 0; a != NULL; a = a->prev) { p = a->sym; parr[i++] = p; if (p == NULL) { uerror("parameter %d name missing", i); p = &nulsym; /* empty symtab */ } if (p->stype == FARG) p->stype = INT; if (ISARY(p->stype)) { p->stype += (PTR-ARY); p->sdf++; } else if (ISFTN(p->stype)) { werror("function declared as argument"); p->stype = INCREF(p->stype); } #ifdef STABS if (gflag) stabs_newsym(p); #endif } if (oldstyle && (df = cftnsp->sdf) && (al = df->dfun)) { /* * Check against prototype of oldstyle function. */ alb = al2 = tmpalloc(sizeof(union arglist) * nparams * 3 + 1); for (i = 0; i < nparams; i++) { TWORD type = parr[i]->stype; (al2++)->type = type; if (ISSOU(BTYPE(type))) (al2++)->sap = parr[i]->sap; while (!ISFTN(type) && !ISARY(type) && type > BTMASK) type = DECREF(type); if (type > BTMASK) (al2++)->df = parr[i]->sdf; } al2->type = TNULL; intcompare = 1; if (chkftn(al, alb)) uerror("function doesn't match prototype"); intcompare = 0; } if (oldstyle && nparams) { /* Must recalculate offset for oldstyle args here */ argoff = ARGINIT; for (i = 0; i < nparams; i++) { parr[i]->soffset = NOOFFSET; oalloc(parr[i], &argoff); } } done: autooff = AUTOINIT; plabel(prolab); /* after prolog, used in optimization */ retlab = getlab(); bfcode(parr, nparams); if (fun_inline && (xinline #ifdef GCC_COMPAT || attr_find(cftnsp->sap, GCC_ATYP_ALW_INL) #endif )) inline_args(parr, nparams); plabel(getlab()); /* used when spilling */ if (parlink) ecomp(parlink); parlink = NIL; lparam = NULL; nparams = 0; symclear(1); /* In case of function pointer args */ } /* * basic attributes for structs and enums */ static struct attr * seattr(void) { return attr_add(attr_new(ATTR_ALIGNED, 4), attr_new(ATTR_STRUCT, 2)); } /* * Struct/union/enum symtab construction. */ static void defstr(struct symtab *sp, int class) { sp->sclass = (char)class; if (class == STNAME || class == CLNAME) sp->stype = STRTY; else if (class == UNAME) sp->stype = UNIONTY; else if (class == ENAME) sp->stype = ENUMTY; } /* * Declare a struct/union/enum tag. * If not found, create a new tag with UNDEF type. */ static struct symtab * deftag(char *name, int class) { struct symtab *sp; if ((sp = cxxdclstr(name))->sap == NULL) { /* New tag */ defstr(sp, class); } else if (sp->sclass != class) uerror("tag %s redeclared", name); return sp; } /* * reference to a structure or union, with no definition */ NODE * rstruct(char *tag, int soru) { struct symtab *sp; sp = deftag(tag, soru); if (sp->sap == NULL) sp->sap = seattr(); return mkty(sp->stype, 0, sp->sap); } static int enumlow, enumhigh; int enummer; /* * Declare a member of enum. */ void moedef(char *name) { struct symtab *sp; sp = lookup(name, SNORMAL); if (sp->stype == UNDEF || (sp->slevel < blevel)) { if (sp->stype != UNDEF) sp = hide(sp); sp->stype = INT; /* always */ sp->sclass = MOE; sp->soffset = enummer; } else uerror("%s redeclared", name); if (enummer < enumlow) enumlow = enummer; if (enummer > enumhigh) enumhigh = enummer; enummer++; } /* * Declare an enum tag. Complain if already defined. */ struct symtab * enumhd(char *name) { struct attr *ap; struct symtab *sp; enummer = enumlow = enumhigh = 0; if (name == NULL) return NULL; sp = deftag(name, ENAME); if (sp->stype != ENUMTY) { if (sp->slevel == blevel) uerror("%s redeclared", name); sp = hide(sp); defstr(sp, ENAME); } if (sp->sap == NULL) ap = sp->sap = attr_new(ATTR_STRUCT, 4); else ap = attr_find(sp->sap, ATTR_STRUCT); ap->amlist = sp; return sp; } /* * finish declaration of an enum */ NODE * enumdcl(struct symtab *sp) { NODE *p; TWORD t; #ifdef ENUMSIZE t = ENUMSIZE(enumhigh, enumlow); #else t = ctype(enumlow < 0 ? INT : UNSIGNED); #ifdef notdef if (enumhigh <= MAX_CHAR && enumlow >= MIN_CHAR) t = ctype(CHAR); else if (enumhigh <= MAX_SHORT && enumlow >= MIN_SHORT) t = ctype(SHORT); else t = ctype(INT); #endif #endif if (sp) sp->stype = t; p = mkty(t, 0, 0); p->n_sp = sp; return p; } /* * Handle reference to an enum */ NODE * enumref(char *name) { struct symtab *sp; NODE *p; sp = lookup(name, STAGNAME); #ifdef notdef /* * 6.7.2.3 Clause 2: * "A type specifier of the form 'enum identifier' without an * enumerator list shall only appear after the type it specifies * is complete." */ if (sp->sclass != ENAME) uerror("enum %s undeclared", name); #endif if (sp->sclass == SNULL) { /* declare existence of enum */ sp = enumhd(name); sp->stype = ENUMTY; } p = mkty(sp->stype, 0, sp->sap); p->n_sp = sp; return p; } /* * begining of structure or union declaration * It's an error if this routine is called twice with the same struct. */ struct rstack * bstruct(char *name, int soru, NODE *gp) { struct rstack *r; struct symtab *sp; struct attr *ap, *gap; char nbuf[20]; #ifdef GCC_COMPAT gap = gp ? gcc_attr_parse(gp) : NULL; #else gap = NULL; #endif if (name == NULL) { static int ancnt; snprintf(nbuf, sizeof(nbuf), "__%%ANON%d", ancnt++); name = addname(nbuf); } if (name != NULL) { sp = deftag(name, soru); if (sp->sap == NULL) sp->sap = seattr(); ap = attr_find(sp->sap, ATTR_ALIGNED); if (ap->iarg(0) != 0) { if (sp->slevel < blevel) { sp = hide(sp); defstr(sp, soru); sp->sap = seattr(); } else uerror("%s redeclared", name); } INSSYM(sp); nscur = sp; gap = sp->sap = attr_add(sp->sap, gap); } else { gap = attr_add(seattr(), gap); sp = getsymtab("__%", SNORMAL); } r = tmpcalloc(sizeof(struct rstack)); r->rsou = soru; r->rsym = sp; // r->rb = NULL; r->ap = gap; r->rnext = rpole; rpole = r; return r; } /* * Called after a struct is declared to restore the environment. * - If ALSTRUCT is defined, this will be the struct alignment and the * struct size will be a multiple of ALSTRUCT, otherwise it will use * the alignment of the largest struct member. */ NODE * dclstruct(struct rstack *r) { NODE *n; struct attr *aps, *apb; struct symtab *sp; int al, sa, sz; apb = attr_find(r->ap, ATTR_ALIGNED); aps = attr_find(r->ap, ATTR_STRUCT); // aps->amlist = r->rb; aps->amlist = nscur->sup; #ifdef ALSTRUCT al = ALSTRUCT; #else al = ALCHAR; #endif /* * extract size and alignment, calculate offsets */ for (sp = /* r->rb */nscur->sup; sp; sp = sp->snext) { sp->sdown = r->rsym; if (ISFTN(sp->stype)) continue; sa = talign(sp->stype, sp->sap); if (sp->sclass & FIELD) sz = sp->sclass&FLDSIZ; else sz = (int)tsize(sp->stype, sp->sdf, sp->sap); if (sz > rpole->rstr) rpole->rstr = sz; /* for use with unions */ /* * set al, the alignment, to the lcm of the alignments * of the members. */ SETOFF(al, sa); } SETOFF(rpole->rstr, al); aps->amsize = rpole->rstr; apb->iarg(0) = al; #ifdef PCC_DEBUG if (ddebug) { printf("dclstruct(%s): size=%d, align=%d\n", r->rsym ? r->rsym->sname : "??", aps->amsize, apb->iarg(0)); } if (ddebug>1) { printf("\tsize %d align %d link %p\n", aps->amsize, apb->iarg(0), aps->amlist); for (sp = aps->amlist; sp != NULL; sp = sp->snext) { printf("\tmember %s(%p)\n", sp->sname, sp); } } #endif #ifdef STABS if (gflag) stabs_struct(r->rsym, r->ap); #endif rpole = r->rnext; n = mkty(r->rsou == STNAME ? STRTY : UNIONTY, 0, r->ap); n->n_sp = r->rsym; POPSYM(); n->n_qual |= 1; /* definition place XXX used by attributes */ return n; } /* * Add a new member to the current struct or union being declared. */ void soumemb(NODE *n, char *name, int class) { struct symtab *sp, *lsp; int incomp, tsz, al; TWORD t; if (rpole == NULL) cerror("soumemb"); /* check if tag name exists */ lsp = NULL; for (sp = /* rpole->rb */ nscur->sup; sp != NULL; lsp = sp, sp = sp->snext) if (*name != '*' && sp->sname == name && class == sp->sclass) uerror("redeclaration of %s", name); sp = getsymtab(name, SMOSNAME); #if 0 if (rpole->rb == NULL) rpole->rb = sp; else lsp->snext = sp; #endif if (nscur->sup == NULL) nscur->sup = sp; else lsp->snext = sp; n->n_sp = sp; sp->stype = n->n_type; sp->squal = n->n_qual; sp->slevel = blevel; sp->sap = n->n_ap; sp->sdf = n->n_df; sp->sdown = rpole->rsym; if (class & FIELD) { sp->sclass = (char)class; falloc(sp, class&FLDSIZ, NIL); } else if (class == STATIC) { sp->sclass = USTATIC; cxxsetname(sp); } else if (ISFTN(sp->stype)) { sp->sclass = EXTERN; cxxsetname(sp); } else if (rpole->rsou == STNAME || rpole->rsou == UNAME) { sp->sclass = rpole->rsou == STNAME ? MOS : MOU; if (sp->sclass == MOU) rpole->rstr = 0; al = talign(sp->stype, sp->sap); tsz = (int)tsize(sp->stype, sp->sdf, sp->sap); sp->soffset = upoff(tsz, al, &rpole->rstr); } /* * 6.7.2.1 clause 16: * "...the last member of a structure with more than one * named member may have incomplete array type;" */ if (ISARY(sp->stype) && sp->sdf->ddim == NOOFFSET) incomp = 1; else incomp = 0; if ((rpole->flags & LASTELM) || (/* rpole->rb */ nscur->sup == sp && incomp == 1)) uerror("incomplete array in struct"); if (incomp == 1) rpole->flags |= LASTELM; /* * 6.7.2.1 clause 2: * "...such a structure shall not be a member of a structure * or an element of an array." */ t = sp->stype; if (rpole->rsou != STNAME || BTYPE(t) != STRTY) return; /* not for unions */ while (ISARY(t)) t = DECREF(t); if (ISPTR(t)) return; if ((lsp = strmemb(sp->sap)) != NULL) { for (; lsp->snext; lsp = lsp->snext) ; if (ISARY(lsp->stype) && lsp->snext && lsp->sdf->ddim == NOOFFSET) uerror("incomplete struct in struct"); } } /* * error printing routine in parser */ void yyerror(char *s) { uerror(s); } void yyaccpt(void); void yyaccpt(void) { ftnend(); } /* * p is top of type list given to tymerge later. * Find correct CALL node and declare parameters from there. */ void ftnarg(NODE *p) { NODE *q; #ifdef PCC_DEBUG if (ddebug > 2) printf("ftnarg(%p)\n", p); #endif /* * Push argument symtab entries onto param stack in reverse order, * due to the nature of the stack it will be reclaimed correct. */ for (; p->n_op != NAME; p = p->n_left) { if (p->n_op == UCALL && p->n_left->n_op == NAME) return; /* Nothing to enter */ if (p->n_op == CALL && (p->n_left->n_op == NAME || p->n_left->n_op == NMLIST)) break; } p = p->n_right; while (p->n_op == CM) { q = p->n_right; if (q->n_op != ELLIPSIS) { ssave(q->n_sp); nparams++; #ifdef PCC_DEBUG if (ddebug > 2) printf(" saving sym %s (%p) from (%p)\n", q->n_sp->sname, q->n_sp, q); #endif } p = p->n_left; } ssave(p->n_sp); if (p->n_type != VOID) nparams++; #ifdef PCC_DEBUG if (ddebug > 2) printf(" saving sym %s (%p) from (%p)\n", nparams ? p->n_sp->sname : "", p->n_sp, p); #endif } /* * compute the alignment of an object with type ty, sizeoff index s */ int talign(unsigned int ty, struct attr *apl) { struct attr *al; int a; for (; ty > BTMASK; ty = DECREF(ty)) { switch (ty & TMASK) { case PTR: return(ALPOINT); case ARY: continue; case FTN: cerror("compiler takes alignment of function"); } } /* check for alignment attribute */ if ((al = attr_find(apl, ATTR_ALIGNED))) { if ((a = al->iarg(0)) == 0) { uerror("no alignment"); a = ALINT; } return a; } ty = BTYPE(ty); if (ty >= CHAR && ty <= ULONGLONG && ISUNSIGNED(ty)) ty = DEUNSIGN(ty); switch (ty) { case BOOL: a = ALBOOL; break; case CHAR: a = ALCHAR; break; case SHORT: a = ALSHORT; break; case INT: a = ALINT; break; case LONG: a = ALLONG; break; case LONGLONG: a = ALLONGLONG; break; case FLOAT: a = ALFLOAT; break; case DOUBLE: a = ALDOUBLE; break; case LDOUBLE: a = ALLDOUBLE; break; default: uerror("no alignment"); a = ALINT; } return a; } short sztable[] = { 0, SZBOOL, SZCHAR, SZCHAR, SZSHORT, SZSHORT, SZINT, SZINT, SZLONG, SZLONG, SZLONGLONG, SZLONGLONG, SZFLOAT, SZDOUBLE, SZLDOUBLE }; /* compute the size associated with type ty, * dimoff d, and sizoff s */ /* BETTER NOT BE CALLED WHEN t, d, and s REFER TO A BIT FIELD... */ OFFSZ tsize(TWORD ty, union dimfun *d, struct attr *apl) { struct attr *ap, *ap2; OFFSZ mult, sz; mult = 1; for (; ty > BTMASK; ty = DECREF(ty)) { switch (ty & TMASK) { case FTN: uerror( "cannot take size of function"); case PTR: return( SZPOINT(ty) * mult ); case ARY: if (d->ddim == NOOFFSET) return 0; if (d->ddim < 0) cerror("tsize: dynarray"); mult *= d->ddim; d++; } } if (ty == VOID) ty = CHAR; if (ty <= LDOUBLE) sz = sztable[ty]; else if (ISSOU(ty)) { if ((ap = strattr(apl)) == NULL || (ap2 = attr_find(apl, ATTR_ALIGNED)) == NULL || (ap2->iarg(0) == 0)) { uerror("unknown structure/union/enum"); sz = SZINT; } else sz = ap->amsize; } else { uerror("unknown type"); sz = SZINT; } return((unsigned int)sz * mult); } /* * Save string (and print it out). If wide then wide string. */ NODE * strend(int wide, char *str) { struct symtab *sp; NODE *p; /* If an identical string is already emitted, just forget this one */ if (wide) { /* Do not save wide strings, at least not now */ sp = getsymtab(str, SSTRING|STEMP); } else { str = addstring(str); /* enter string in string table */ sp = lookup(str, SSTRING); /* check for existence */ } if (sp->soffset == 0) { /* No string */ char *wr; int i; sp->sclass = STATIC; sp->slevel = 1; sp->soffset = getlab(); sp->squal = (CON >> TSHIFT); sp->sdf = permalloc(sizeof(union dimfun)); if (wide) { sp->stype = WCHAR_TYPE+ARY; } else { if (xuchar) { sp->stype = UCHAR+ARY; } else { sp->stype = CHAR+ARY; } } for (wr = sp->sname, i = 1; *wr; i++) if (*wr++ == '\\') (void)esccon(&wr); sp->sdf->ddim = i; if (wide) inwstring(sp); else instring(sp); } p = block(NAME, NIL, NIL, sp->stype, sp->sdf, sp->sap); p->n_sp = sp; return(clocal(p)); } /* * Print out a wide string by calling ninval(). */ void inwstring(struct symtab *sp) { char *s = sp->sname; NODE *p; locctr(STRNG, sp); defloc(sp); p = xbcon(0, NULL, WCHAR_TYPE); do { if (*s++ == '\\') glval(p) = esccon(&s); else glval(p) = (unsigned char)s[-1]; inval(0, tsize(WCHAR_TYPE, NULL, NULL), p); } while (s[-1] != 0); nfree(p); } #ifndef MYINSTRING /* * Print out a string of characters. * Assume that the assembler understands C-style escape * sequences. */ void instring(struct symtab *sp) { char *s, *str; locctr(STRNG, sp); defloc(sp); str = sp->sname; /* be kind to assemblers and avoid long strings */ printf("\t.ascii \""); for (s = str; *s != 0; ) { if (*s++ == '\\') { (void)esccon(&s); } if (s - str > 60) { fwrite(str, 1, s - str, stdout); printf("\"\n\t.ascii \""); str = s; } } fwrite(str, 1, s - str, stdout); printf("\\0\"\n"); } #endif /* * update the offset pointed to by poff; return the * offset of a value of size `size', alignment `alignment', * given that off is increasing */ int upoff(int size, int alignment, int *poff) { int off; off = *poff; SETOFF(off, alignment); if (off < 0) cerror("structure or stack overgrown"); /* wrapped */ *poff = off+size; return (off); } /* * allocate p with offset *poff, and update *poff */ int oalloc(struct symtab *p, int *poff ) { int al, off, tsz; int noff; /* * Only generate tempnodes if we are optimizing, * and only for integers, floats or pointers, * and not if the type on this level is volatile. */ if (xtemps && ((p->sclass == AUTO) || (p->sclass == REGISTER)) && (p->stype < STRTY || ISPTR(p->stype)) && !(cqual(p->stype, p->squal) & VOL) && cisreg(p->stype)) { NODE *tn = tempnode(0, p->stype, p->sdf, p->sap); p->soffset = regno(tn); p->sflags |= STNODE; nfree(tn); return 0; } al = talign(p->stype, p->sap); noff = off = *poff; tsz = (int)tsize(p->stype, p->sdf, p->sap); #ifdef BACKAUTO if (p->sclass == AUTO) { noff = off + tsz; if (noff < 0) cerror("stack overflow"); SETOFF(noff, al); off = -noff; } else #endif if (p->sclass == PARAM && (p->stype == CHAR || p->stype == UCHAR || p->stype == SHORT || p->stype == USHORT || p->stype == BOOL)) { off = upoff(SZINT, ALINT, &noff); #if TARGET_ENDIAN == TARGET_BE off = noff - tsz; #endif } else { off = upoff(tsz, al, &noff); } if (p->sclass != REGISTER) { /* in case we are allocating stack space for register arguments */ if (p->soffset == NOOFFSET) p->soffset = off; else if(off != p->soffset) return(1); } *poff = noff; return(0); } /* * Delay emission of code generated in argument headers. */ static void edelay(NODE *p) { if (blevel == 1) { /* Delay until after declarations */ if (parlink == NULL) parlink = p; else parlink = block(COMOP, parlink, p, 0, 0, 0); } else ecomp(p); } /* * Traverse through the array args, evaluate them and put the * resulting temp numbers in the dim fields. */ static void evalidx(struct symtab *sp) { union dimfun *df; NODE *p; TWORD t; int astkp = 0; if (arrstk[0] == NIL) astkp++; /* for parameter arrays */ if (isdyn(sp)) sp->sflags |= SDYNARRAY; df = sp->sdf; for (t = sp->stype; t > BTMASK; t = DECREF(t)) { if (!ISARY(t)) continue; if (df->ddim == -1) { p = tempnode(0, INT, 0, 0); df->ddim = -regno(p); edelay(buildtree(ASSIGN, p, arrstk[astkp++])); } df++; } arrstkp = 0; } /* * Return 1 if dynamic array, 0 otherwise. */ int isdyn(struct symtab *sp) { union dimfun *df = sp->sdf; TWORD t; for (t = sp->stype; t > BTMASK; t = DECREF(t)) { if (!ISARY(t)) return 0; if (df->ddim < 0 && df->ddim != NOOFFSET) return 1; df++; } return 0; } /* * Allocate space on the stack for dynamic arrays (or at least keep track * of the index). * Strategy is as follows: * - first entry is a pointer to the dynamic datatype. * - if it's a one-dimensional array this will be the only entry used. * - if it's a multi-dimensional array the following (numdim-1) integers * will contain the sizes to multiply the indexes with. * - code to write the dimension sizes this will be generated here. * - code to allocate space on the stack will be generated here. */ static void dynalloc(struct symtab *p, int *poff) { union dimfun *df; NODE *n, *tn, *pol; TWORD t; /* * The pointer to the array is not necessarily stored in a * TEMP node, but if it is, its number is in the soffset field; */ t = p->stype; p->sflags |= STNODE; p->stype = INCREF(p->stype); /* Make this an indirect pointer */ tn = tempnode(0, p->stype, p->sdf, p->sap); p->soffset = regno(tn); df = p->sdf; pol = bcon(1); for (; t > BTMASK; t = DECREF(t)) { if (!ISARY(t)) break; if (df->ddim < 0) n = tempnode(-df->ddim, INT, 0, 0); else n = bcon(df->ddim); pol = buildtree(MUL, pol, n); df++; } /* Create stack gap */ spalloc(tn, pol, tsize(t, 0, p->sap)); } /* * allocate a field of width w * new is 0 if new entry, 1 if redefinition, -1 if alignment */ int falloc(struct symtab *p, int w, NODE *pty) { TWORD otype, type; int al,sz; otype = type = p ? p->stype : pty->n_type; if (type == BOOL) type = BOOL_TYPE; if (!ISINTEGER(type)) { uerror("illegal field type"); type = INT; } al = talign(type, NULL); sz = (int)tsize(type, NULL, NULL); if (w > sz) { uerror("field too big"); w = sz; } if (w == 0) { /* align only */ SETOFF(rpole->rstr, al); if (p != NULL) uerror("zero size field"); return(0); } if (rpole->rstr%al + w > sz) SETOFF(rpole->rstr, al); if (p == NULL) { rpole->rstr += w; /* we know it will fit */ return(0); } /* establish the field */ p->soffset = rpole->rstr; rpole->rstr += w; p->stype = otype; fldty(p); return(0); } /* * Check if this symbol should be a common or must be handled in data seg. */ static void commchk(struct symtab *sp) { if ((sp->sflags & STLS) #ifdef GCC_COMPAT || attr_find(sp->sap, GCC_ATYP_SECTION) #endif ) { /* TLS handled in data segment */ if (sp->sclass == EXTERN) sp->sclass = EXTDEF; beginit(sp); endinit(1); } else { symdirec(sp); defzero(sp); } } /* * handle unitialized declarations assumed to be not functions: * int a; * extern int a; * static int a; */ void nidcl(NODE *p, int class) { struct symtab *sp; int commflag = 0; /* compute class */ if (class == SNULL) { if (blevel > 1) class = AUTO; else if (blevel != 0 || rpole) cerror( "nidcl error" ); else /* blevel = 0 */ commflag = 1, class = EXTERN; } defid(p, class); sp = p->n_sp; /* check if forward decl */ if (ISARY(sp->stype) && sp->sdf->ddim == NOOFFSET) return; if (sp->sflags & SASG) return; /* already initialized */ switch (class) { case EXTDEF: /* simulate initialization by 0 */ simpleinit(p->n_sp, bcon(0)); break; case EXTERN: if (commflag) lcommadd(p->n_sp); else extdec(p->n_sp); break; case STATIC: if (blevel == 0) lcommadd(p->n_sp); else commchk(p->n_sp); break; } } struct lcd { SLIST_ENTRY(lcd) next; struct symtab *sp; }; static SLIST_HEAD(, lcd) lhead = { NULL, &lhead.q_forw}; /* * Add a local common statement to the printout list. */ void lcommadd(struct symtab *sp) { struct lcd *lc, *lcp; lcp = NULL; SLIST_FOREACH(lc, &lhead, next) { if (lc->sp == sp) return; /* already exists */ if (lc->sp == NULL && lcp == NULL) lcp = lc; } if (lcp == NULL) { lc = permalloc(sizeof(struct lcd)); lc->sp = sp; SLIST_INSERT_LAST(&lhead, lc, next); } else lcp->sp = sp; } /* * Delete a local common statement. */ void lcommdel(struct symtab *sp) { struct lcd *lc; SLIST_FOREACH(lc, &lhead, next) { if (lc->sp == sp) { lc->sp = NULL; return; } } } /* * Print out the remaining common statements. */ void lcommprint(void) { struct lcd *lc; SLIST_FOREACH(lc, &lhead, next) { if (lc->sp != NULL) commchk(lc->sp); } } /* * Merge given types to a single node. * Any type can end up here. * p is the old node, q is the old (if any). * CLASS is AUTO, EXTERN, REGISTER, STATIC or TYPEDEF. * QUALIFIER is VOL or CON * TYPE is CHAR, SHORT, INT, LONG, SIGNED, UNSIGNED, VOID, BOOL, FLOAT, * DOUBLE, STRTY, UNIONTY. */ struct typctx { int class, qual, sig, uns, cmplx, imag, err; TWORD type; NODE *saved; struct attr *pre, *post; }; static void typwalk(NODE *p, void *arg) { struct typctx *tc = arg; #define cmop(x,y) block(CM, x, y, INT, 0, 0) switch (p->n_op) { case ATTRIB: #ifdef GCC_COMPAT if (tc->saved && (tc->saved->n_qual & 1)) { tc->post = attr_add(tc->post,gcc_attr_parse(p->n_left)); } else { tc->pre = attr_add(tc->pre, gcc_attr_parse(p->n_left)); } p->n_left = bcon(0); /* For tfree() */ #endif break; case CLASS: if (tc->class) tc->err = 1; /* max 1 class */ tc->class = p->n_type; break; case QUALIFIER: #if 0 if (p->n_qual == 0) uerror("invalid use of 'restrict'"); #endif tc->qual |= p->n_qual >> TSHIFT; break; case TYPE: if (p->n_sp != NULL || ISSOU(p->n_type)) { /* typedef, enum or struct/union */ if (tc->saved || tc->type) tc->err = 1; #ifdef GCC_COMPAT if (ISSOU(p->n_type) && p->n_left) { if (tc->post) cerror("typwalk"); tc->post = gcc_attr_parse(p->n_left); } #endif tc->saved = ccopy(p); break; } switch (p->n_type) { case BOOL: case CHAR: case FLOAT: case VOID: if (tc->type) tc->err = 1; tc->type = p->n_type; break; case DOUBLE: if (tc->type == 0) tc->type = DOUBLE; else if (tc->type == LONG) tc->type = LDOUBLE; else tc->err = 1; break; case SHORT: if (tc->type == 0 || tc->type == INT) tc->type = SHORT; else tc->err = 1; break; case INT: if (tc->type == SHORT || tc->type == LONG || tc->type == LONGLONG) break; else if (tc->type == 0) tc->type = INT; else tc->err = 1; break; case LONG: if (tc->type == 0) tc->type = LONG; else if (tc->type == INT) break; else if (tc->type == LONG) tc->type = LONGLONG; else if (tc->type == DOUBLE) tc->type = LDOUBLE; else tc->err = 1; break; case SIGNED: if (tc->sig || tc->uns) tc->err = 1; tc->sig = 1; break; case UNSIGNED: if (tc->sig || tc->uns) tc->err = 1; tc->uns = 1; break; case COMPLEX: tc->cmplx = 1; break; case IMAG: tc->imag = 1; break; default: cerror("typwalk"); } } } NODE * typenode(NODE *p) { struct symtab *sp; struct typctx tc; NODE *q; char *c; memset(&tc, 0, sizeof(struct typctx)); flist(p, typwalk, &tc); tfree(p); if (tc.err) goto bad; if (tc.cmplx || tc.imag) { if (tc.type == 0) tc.type = DOUBLE; if ((tc.cmplx && tc.imag) || tc.sig || tc.uns || !ISFTY(tc.type)) goto bad; if (tc.cmplx) { c = tc.type == DOUBLE ? "0d" : tc.type == FLOAT ? "0f" : "0l"; sp = lookup(addname(c), 0); tc.type = STRTY; tc.saved = mkty(tc.type, sp->sdf, sp->sap); tc.saved->n_sp = sp; tc.type = 0; } else tc.type += (FIMAG-FLOAT); } if (tc.saved && tc.type) goto bad; if (tc.sig || tc.uns) { if (tc.type == 0) tc.type = tc.sig ? INT : UNSIGNED; if (tc.type > ULONGLONG) goto bad; if (tc.uns) tc.type = ENUNSIGN(tc.type); } if (xuchar && tc.type == CHAR && tc.sig == 0) tc.type = UCHAR; #ifdef GCC_COMPAT if (pragma_packed) { q = bdty(CALL, bdty(NAME, "packed"), bcon(pragma_packed)); tc.post = attr_add(tc.post, gcc_attr_parse(q)); } if (pragma_aligned) { /* Deal with relevant pragmas */ q = bdty(CALL, bdty(NAME, "aligned"), bcon(pragma_aligned)); tc.post = attr_add(tc.post, gcc_attr_parse(q)); } pragma_aligned = pragma_packed = 0; #endif if ((q = tc.saved) == NULL) { TWORD t; if ((t = BTYPE(tc.type)) > LDOUBLE && t != VOID && t != BOOL && !(t >= FIMAG && t <= LIMAG)) cerror("typenode2 t %x", tc.type); if (t == UNDEF) { t = INT; MODTYPE(tc.type, INT); } q = mkty(tc.type, 0, 0); } q->n_ap = attr_add(q->n_ap, tc.post); q->n_qual = tc.qual; glval(q) = tc.class; #ifdef GCC_COMPAT if (tc.post) { /* Can only occur for TYPEDEF, STRUCT or UNION */ if (tc.saved == NULL) cerror("typenode"); if (tc.saved->n_sp) /* trailer attributes for structs */ tc.saved->n_sp->sap = q->n_ap; } if (tc.pre) q->n_ap = attr_add(q->n_ap, tc.pre); gcc_tcattrfix(q); #endif return q; bad: uerror("illegal type combination"); return mkty(INT, 0, 0); } struct tylnk { struct tylnk *next; union dimfun df; }; /* * Retrieve all CM-separated argument types, sizes and dimensions and * put them in an array. * XXX - can only check first type level, side effects? */ static union arglist * arglist(NODE *n) { union arglist *al; NODE *w = n, **ap; int num, cnt, i, j, k; TWORD ty; #ifdef PCC_DEBUG if (pdebug) { printf("arglist %p\n", n); fwalk(n, eprint, 0); } #endif /* First: how much to allocate */ for (num = cnt = 0, w = n; w->n_op == CM; w = w->n_left) { cnt++; /* Number of levels */ num++; /* At least one per step */ if (w->n_right->n_op == ELLIPSIS) continue; ty = w->n_right->n_type; if (BTYPE(ty) == STRTY || BTYPE(ty) == UNIONTY) num++; while (!ISFTN(ty) && !ISARY(ty) && ty > BTMASK) ty = DECREF(ty); if (ty > BTMASK) num++; } cnt++; ty = w->n_type; if (BTYPE(ty) == STRTY || BTYPE(ty) == UNIONTY) num++; while (!ISFTN(ty) && !ISARY(ty) && ty > BTMASK) ty = DECREF(ty); if (ty > BTMASK) num++; num += 2; /* TEND + last arg type */ /* Second: Create list to work on */ ap = tmpalloc(sizeof(NODE *) * cnt); al = permalloc(sizeof(union arglist) * num); arglistcnt += num; for (w = n, i = 0; w->n_op == CM; w = w->n_left) ap[i++] = w->n_right; ap[i] = w; /* Third: Create actual arg list */ for (k = 0, j = i; j >= 0; j--) { if (ap[j]->n_op == ELLIPSIS) { al[k++].type = TELLIPSIS; ap[j]->n_op = ICON; /* for tfree() */ continue; } /* Convert arrays to pointers */ if (ISARY(ap[j]->n_type)) { ap[j]->n_type += (PTR-ARY); ap[j]->n_df++; } /* Convert (silently) functions to pointers */ if (ISFTN(ap[j]->n_type)) ap[j]->n_type = INCREF(ap[j]->n_type); ty = ap[j]->n_type; #ifdef GCC_COMPAT if (ty == UNIONTY && attr_find(ap[j]->n_ap, GCC_ATYP_TRANSP_UNION)){ /* transparent unions must have compatible types * shortcut here: if pointers, set void *, * otherwise btype. */ struct symtab *sp = strmemb(ap[j]->n_ap); ty = ISPTR(sp->stype) ? PTR|VOID : sp->stype; } #endif al[k++].type = ty; if (BTYPE(ty) == STRTY || BTYPE(ty) == UNIONTY) al[k++].sap = ap[j]->n_ap; while (!ISFTN(ty) && !ISARY(ty) && ty > BTMASK) ty = DECREF(ty); if (ty > BTMASK) al[k++].df = ap[j]->n_df; } al[k++].type = TNULL; if (k > num) cerror("arglist: k%d > num%d", k, num); tfree(n); #ifdef PCC_DEBUG if (pdebug) alprint(al, 0); #endif return al; } static void tylkadd(union dimfun dim, struct tylnk **tylkp, int *ntdim) { (*tylkp)->next = tmpalloc(sizeof(struct tylnk)); *tylkp = (*tylkp)->next; (*tylkp)->next = NULL; (*tylkp)->df = dim; (*ntdim)++; } /* * build a type, and stash away dimensions, * from a parse tree of the declaration * the type is build top down, the dimensions bottom up */ static void tyreduce(NODE *p, struct tylnk **tylkp, int *ntdim) { union dimfun dim; NODE *r = NULL; int o; TWORD t, q; o = p->n_op; if (o == NAME) { p->n_qual = DECQAL(p->n_qual); return; } t = INCREF(p->n_type); q = p->n_qual; switch (o) { case CALL: t += (FTN-PTR); dim.dfun = arglist(p->n_right); break; case UCALL: t += (FTN-PTR); dim.dfun = NULL; break; case LB: t += (ARY-PTR); if (p->n_right->n_op != ICON) { r = p->n_right; o = RB; } else { dim.ddim = (int)glval(p->n_right); nfree(p->n_right); #ifdef notdef /* XXX - check dimensions at usage time */ if (dim.ddim == NOOFFSET && p->n_left->n_op == LB) uerror("null dimension"); #endif } break; } p->n_left->n_type = t; p->n_left->n_qual = INCQAL(q) | p->n_left->n_qual; tyreduce(p->n_left, tylkp, ntdim); if (o == LB || o == UCALL || o == CALL) tylkadd(dim, tylkp, ntdim); if (o == RB) { dim.ddim = -1; tylkadd(dim, tylkp, ntdim); arrstk[arrstkp++] = r; } p->n_sp = p->n_left->n_sp; p->n_type = p->n_left->n_type; p->n_qual = p->n_left->n_qual; } /* * merge type typ with identifier idp. * idp is returned as a NAME node with correct types, * typ is untouched since multiple declarations uses it. * typ has type attributes, idp can never carry such attributes * so on return just a pointer to the typ attributes is returned. */ NODE * tymerge(NODE *typ, NODE *idp) { TWORD t; NODE *p; union dimfun *j; struct tylnk *base, tylnk, *tylkp; struct attr *bap; int ntdim, i; #ifdef PCC_DEBUG if (ddebug > 2) { printf("tymerge(%p,%p)\n", typ, idp); fwalk(typ, eprint, 0); fwalk(idp, eprint, 0); } #endif if (typ->n_op != TYPE) cerror("tymerge: arg 1"); bap = typ->n_ap; idp->n_type = typ->n_type; idp->n_qual |= typ->n_qual; tylkp = &tylnk; tylkp->next = NULL; ntdim = 0; tyreduce(idp, &tylkp, &ntdim); for (t = typ->n_type, j = typ->n_df; t&TMASK; t = DECREF(t)) if (ISARY(t) || ISFTN(t)) tylkadd(*j++, &tylkp, &ntdim); if (ntdim) { union dimfun *a = permalloc(sizeof(union dimfun) * ntdim); dimfuncnt += ntdim; for (i = 0, base = tylnk.next; base; base = base->next, i++) a[i] = base->df; idp->n_df = a; } else idp->n_df = NULL; /* now idp is a single node: fix up type */ if ((t = ctype(idp->n_type)) != idp->n_type) idp->n_type = t; if (idp->n_op != NAME) { for (p = idp->n_left; p->n_op != NAME; p = p->n_left) nfree(p); nfree(p); idp->n_op = NAME; } idp->n_ap = bap; return(idp); } static NODE * argcast(NODE *p, TWORD t, union dimfun *d, struct attr *ap) { NODE *u, *r = talloc(); r->n_op = NAME; r->n_type = t; r->n_qual = 0; /* XXX */ r->n_df = d; r->n_ap = ap; u = buildtree(CAST, r, p); nfree(u->n_left); r = u->n_right; nfree(u); return r; } #ifdef PCC_DEBUG /* * Print a prototype. */ static void alprint(union arglist *al, int in) { TWORD t; int i = 0, j; for (; al->type != TNULL; al++) { for (j = in; j > 0; j--) printf(" "); printf("arg %d: ", i++); t = al->type; tprint(t, 0); while (t > BTMASK) { if (ISARY(t)) { al++; printf(" dim %d ", al->df->ddim); } else if (ISFTN(t)) { al++; alprint(al->df->dfun, in+1); } t = DECREF(t); } if (ISSOU(t)) { al++; printf(" (size %d align %d)", (int)tsize(t, 0, al->sap), (int)talign(t, al->sap)); } printf("\n"); } if (in == 0) printf("end arglist\n"); } #endif int suemeq(struct attr *s1, struct attr *s2) { return (strmemb(s1) == strmemb(s2)); } /* * Sanity-check old-style args. */ static NODE * oldarg(NODE *p) { if (p->n_op == TYPE) uerror("type is not an argument"); if (p->n_type == FLOAT) return cast(p, DOUBLE, p->n_qual); return p; } /* * Do prototype checking and add conversions before calling a function. * Argument f is function and a is a CM-separated list of arguments. * Returns a merged node (via buildtree() of function and arguments. */ NODE * doacall(struct symtab *sp, NODE *f, NODE *a, int hidden) { NODE *w, *r; union arglist *al; struct ap { struct ap *next; NODE *node; } *at, *apole = NULL; int argidx/* , hasarray = 0*/; TWORD type, arrt; #ifdef PCC_DEBUG if (ddebug) { printf("doacall.\n"); fwalk(f, eprint, 0); if (a) fwalk(a, eprint, 0); } #endif /* First let MD code do something */ calldec(f, a); /* XXX XXX hack */ if ((f->n_op == CALL) && f->n_left->n_op == ADDROF && f->n_left->n_left->n_op == NAME && (f->n_left->n_left->n_type & 0x7e0) == 0x4c0) goto build; /* XXX XXX hack */ /* Check for undefined or late defined enums */ if (BTYPE(f->n_type) == ENUMTY) { /* not-yet check if declared enum */ struct symtab *sq = strmemb(f->n_ap); if (sq->stype != ENUMTY) MODTYPE(f->n_type, sq->stype); if (BTYPE(f->n_type) == ENUMTY) uerror("enum %s not declared", sq->sname); } /* * Do some basic checks. */ if (f->n_df == NULL || (al = f->n_df[0].dfun) == NULL) { /* * Handle non-prototype declarations. */ if (f->n_op == NAME && f->n_sp != NULL) { if (strncmp(f->n_sp->sname, "__builtin", 9) != 0) warner(Wmissing_prototypes, f->n_sp->sname); } else warner(Wmissing_prototypes, ""); /* floats must be cast to double */ if (a == NULL) goto build; if (a->n_op != CM) { a = oldarg(a); } else { for (w = a; w->n_left->n_op == CM; w = w->n_left) w->n_right = oldarg(w->n_right); w->n_left = oldarg(w->n_left); w->n_right = oldarg(w->n_right); } goto build; } if (al->type == VOID) { if (a != NULL) uerror("function takes no arguments"); goto build; /* void function */ } else { if (a == NULL) { uerror("function needs arguments"); goto build; } } #ifdef PCC_DEBUG if (pdebug) { printf("arglist for %s\n", f->n_sp != NULL ? f->n_sp->sname : "function pointer"); alprint(al, 0); } #endif /* * Create a list of pointers to the nodes given as arg. */ for (w = a; w->n_op == CM; w = w->n_left) { at = tmpalloc(sizeof(struct ap)); at->node = w->n_right; at->next = apole; apole = at; } if (hidden == 0) { at = tmpalloc(sizeof(struct ap)); at->node = w; at->next = apole; apole = at; } /* * Do the typechecking by walking up the list. */ argidx = 1; while (al->type != TNULL) { if (al->type == TELLIPSIS) { /* convert the rest of float to double */ for (; apole; apole = apole->next) { if (apole->node->n_type != FLOAT) continue; MKTY(apole->node, DOUBLE, 0, 0); } goto build; } if (apole == NULL) { uerror("too few arguments to function"); goto build; } /* al = prototyp, apole = argument till ftn */ /* type = argumentets typ, arrt = prototypens typ */ type = apole->node->n_type; arrt = al->type; #if 0 if ((hasarray = ISARY(arrt))) arrt += (PTR-ARY); #endif /* Taking addresses of arrays are meaningless in expressions */ /* but people tend to do that and also use in prototypes */ /* this is mostly a problem with typedefs */ if (ISARY(type)) { if (ISPTR(arrt) && ISARY(DECREF(arrt))) type = INCREF(type); else type += (PTR-ARY); } else if (ISPTR(type) && !ISARY(DECREF(type)) && ISPTR(arrt) && ISARY(DECREF(arrt))) { type += (ARY-PTR); type = INCREF(type); } /* Check structs */ if (type <= BTMASK && arrt <= BTMASK) { if (type != arrt) { if (ISSOU(BTYPE(type)) || ISSOU(BTYPE(arrt))) { incomp: uerror("incompatible types for arg %d", argidx); } else { MKTY(apole->node, arrt, 0, 0) } #ifndef NO_COMPLEX } else if (type == STRTY && attr_find(apole->node->n_ap, ATTR_COMPLEX) && attr_find(al[1].sap, ATTR_COMPLEX)) { /* Both are complex */ if (strmemb(apole->node->n_ap)->stype != strmemb(al[1].sap)->stype) { /* must convert to correct type */ w = talloc(); *w = *apole->node; w = mkcmplx(w, strmemb(al[1].sap)->stype); *apole->node = *w; nfree(w); } goto out; #endif } else if (ISSOU(BTYPE(type))) { if (!suemeq(apole->node->n_ap, al[1].sap)) goto incomp; } goto out; } /* XXX should (recusively) check return type and arg list of func ptr arg XXX */ if (ISFTN(DECREF(arrt)) && ISFTN(type)) type = INCREF(type); /* Hereafter its only pointers (or arrays) left */ /* Check for struct/union intermixing with other types */ if (((type <= BTMASK) && ISSOU(BTYPE(type))) || ((arrt <= BTMASK) && ISSOU(BTYPE(arrt)))) goto incomp; /* Check for struct/union compatibility */ if (type == arrt) { if (ISSOU(BTYPE(type))) { if (suemeq(apole->node->n_ap, al[1].sap)) goto out; } else goto out; } if (BTYPE(arrt) == VOID && type > BTMASK) goto skip; /* void *f = some pointer */ if (arrt > BTMASK && BTYPE(type) == VOID) goto skip; /* some *f = void pointer */ if (apole->node->n_op == ICON && glval(apole->node) == 0) goto skip; /* Anything assigned a zero */ if ((type & ~BTMASK) == (arrt & ~BTMASK)) { /* do not complain for pointers with signedness */ if ((DEUNSIGN(BTYPE(type)) == DEUNSIGN(BTYPE(arrt))) && (BTYPE(type) != BTYPE(arrt))) { warner(Wpointer_sign); goto skip; } } werror("implicit conversion of argument %d due to prototype", argidx); skip: if (ISSOU(BTYPE(arrt))) { MKTY(apole->node, arrt, 0, al[1].sap) } else { MKTY(apole->node, arrt, 0, 0) } out: al++; if (ISSOU(BTYPE(arrt))) al++; #if 0 while (arrt > BTMASK && !ISFTN(arrt)) arrt = DECREF(arrt); if (ISFTN(arrt) || hasarray) al++; #else while (arrt > BTMASK) { if (ISARY(arrt) || ISFTN(arrt)) { al++; break; } arrt = DECREF(arrt); } #endif apole = apole->next; argidx++; } if (apole != NULL) uerror("too many arguments to function"); build: if (sp != NULL && (sp->sflags & SINLINE) && (w = inlinetree(sp, f, a))) return w; return buildtree(a == NIL ? UCALL : CALL, f, a); } static int chk2(TWORD type, union dimfun *dsym, union dimfun *ddef) { while (type > BTMASK) { switch (type & TMASK) { case ARY: /* may be declared without dimension */ if (dsym->ddim == NOOFFSET) dsym->ddim = ddef->ddim; if (dsym->ddim < 0 && ddef->ddim < 0) ; /* dynamic arrays as arguments */ else if (ddef->ddim > 0 && dsym->ddim != ddef->ddim) return 1; dsym++, ddef++; break; case FTN: /* old-style function headers with function pointers * will most likely not have a prototype. * This is not considered an error. */ if (ddef->dfun == NULL) { #ifdef notyet werror("declaration not a prototype"); #endif } else if (chkftn(dsym->dfun, ddef->dfun)) return 1; dsym++, ddef++; break; } type = DECREF(type); } return 0; } /* * Compare two function argument lists to see if they match. */ int chkftn(union arglist *usym, union arglist *udef) { TWORD t2; int ty, tyn; if (usym == NULL) return 0; if (cftnsp != NULL && udef == NULL && usym->type == VOID) return 0; /* foo() { function with foo(void); prototype */ if (udef == NULL && usym->type != TNULL) return 1; while (usym->type != TNULL) { if (usym->type == udef->type) goto done; /* * If an old-style declaration, then all types smaller than * int are given as int parameters. */ if (intcompare) { ty = BTYPE(usym->type); tyn = BTYPE(udef->type); if (ty == tyn || ty != INT) return 1; if (tyn == CHAR || tyn == UCHAR || tyn == SHORT || tyn == USHORT) goto done; return 1; } else return 1; done: ty = BTYPE(usym->type); t2 = usym->type; if (ISSOU(ty)) { usym++, udef++; if (suemeq(usym->sap, udef->sap) == 0) return 1; } while (!ISFTN(t2) && !ISARY(t2) && t2 > BTMASK) t2 = DECREF(t2); if (t2 > BTMASK) { usym++, udef++; if (chk2(t2, usym->df, udef->df)) return 1; } usym++, udef++; } if (usym->type != udef->type) return 1; return 0; } void fixtype(NODE *p, int class) { unsigned int t, type; int mod1, mod2; /* fix up the types, and check for legality */ /* forward declared enums */ if (BTYPE(p->n_sp->stype) == ENUMTY) { MODTYPE(p->n_sp->stype, strmemb(p->n_sp->sap)->stype); } if( (type = p->n_type) == UNDEF ) return; if ((mod2 = (type&TMASK))) { t = DECREF(type); while( mod1=mod2, mod2 = (t&TMASK) ){ if( mod1 == ARY && mod2 == FTN ){ uerror( "array of functions is illegal" ); type = 0; } else if( mod1 == FTN && ( mod2 == ARY || mod2 == FTN ) ){ uerror( "function returns illegal type" ); type = 0; } t = DECREF(t); } } /* detect function arguments, watching out for structure declarations */ if (rpole && ISFTN(type)) { uerror("function illegal in structure or union"); type = INCREF(type); } p->n_type = type; } /* * give undefined version of class */ int uclass(int class) { if (class == SNULL) return(EXTERN); else if (class == STATIC) return(USTATIC); else return(class); } int fixclass(int class, TWORD type) { extern int fun_inline; /* first, fix null class */ if (class == SNULL) { if (fun_inline && ISFTN(type)) return SNULL; if (rpole) cerror("field8"); else if (blevel == 0) class = EXTDEF; else class = AUTO; } /* now, do general checking */ if( ISFTN( type ) ){ switch( class ) { default: uerror( "function has illegal storage class" ); case AUTO: class = EXTERN; case EXTERN: case EXTDEF: case TYPEDEF: case STATIC: case USTATIC: ; } } if (class & FIELD) { cerror("field3"); } switch (class) { case MOS: case MOU: cerror("field4"); case REGISTER: if (blevel == 0) uerror("illegal register declaration"); if (blevel == 1) return(PARAM); else return(AUTO); case AUTO: if( blevel < 2 ) uerror( "illegal ULABEL class" ); return( class ); case EXTERN: case STATIC: case EXTDEF: case TYPEDEF: case USTATIC: case PARAM: return( class ); default: cerror( "illegal class: %d", class ); /* NOTREACHED */ } return 0; /* XXX */ } /* * Generates a goto statement; sets up label number etc. */ void gotolabel(char *name) { struct symtab *s = lookup(name, SLBLNAME); if (s->soffset == 0) s->soffset = -getlab(); branch(s->soffset < 0 ? -s->soffset : s->soffset); } /* * Sets a label for gotos. */ void deflabel(char *name, NODE *p) { struct symtab *s = lookup(name, SLBLNAME); #ifdef GCC_COMPAT s->sap = gcc_attr_parse(p); #endif if (s->soffset > 0) uerror("label '%s' redefined", name); if (s->soffset == 0) s->soffset = getlab(); if (s->soffset < 0) s->soffset = -s->soffset; plabel( s->soffset); } struct symtab * getsymtab(char *name, int flags) { struct symtab *s; if (flags & STEMP) { s = tmpalloc(sizeof(struct symtab)); } else { s = permalloc(sizeof(struct symtab)); symtabcnt++; } s->sname = name; s->soname = NULL; s->sup = s->sdown = s->snext = NULL; s->stype = UNDEF; s->squal = 0; s->sclass = SNULL; s->sflags = (short)(flags & SMASK); s->soffset = 0; s->slevel = (char)blevel; s->sdf = NULL; s->sap = NULL; return s; } int fldchk(int sz) { if (rpole->rsou != STNAME && rpole->rsou != UNAME) uerror("field outside of structure"); if (sz < 0 || sz >= FIELD) { uerror("illegal field size"); return 1; } return 0; } #ifdef PCC_DEBUG static char * ccnames[] = { /* names of storage classes */ "SNULL", "AUTO", "EXTERN", "STATIC", "REGISTER", "EXTDEF", "LABEL", "ULABEL", "MOS", "PARAM", "STNAME", "MOU", "UNAME", "TYPEDEF", "FORTRAN", "ENAME", "MOE", "UFORTRAN", "USTATIC", "?????", "?????", "CLNAME", "NSPACE", }; char * scnames(int c) { /* return the name for storage class c */ static char buf[12]; if( c&FIELD ){ snprintf( buf, sizeof(buf), "FIELD[%d]", c&FLDSIZ ); return( buf ); } return( ccnames[c] ); } #endif #ifdef os_openbsd static char *stack_chk_fail = "__stack_smash_handler"; static char *stack_chk_guard = "__guard"; #else static char *stack_chk_fail = "__stack_chk_fail"; static char *stack_chk_guard = "__stack_chk_guard"; #endif static char *stack_chk_canary = "__stack_chk_canary"; void sspinit(void) { NODE *p; p = block(NAME, NIL, NIL, FTN+VOID, 0, 0); p->n_sp = lookup(stack_chk_fail, SNORMAL); defid(p, EXTERN); nfree(p); p = block(NAME, NIL, NIL, INT, 0, 0); p->n_sp = lookup(stack_chk_guard, SNORMAL); defid(p, EXTERN); nfree(p); } void sspstart(void) { NODE *p, *q; q = block(NAME, NIL, NIL, INT, 0, 0); q->n_sp = lookup(stack_chk_guard, SNORMAL); q = clocal(q); p = block(REG, NIL, NIL, INT, 0, 0); glval(p) = 0; p->n_rval = FPREG; q = block(ER, p, q, INT, 0, 0); q = clocal(q); p = block(NAME, NIL, NIL, INT, 0, 0); p->n_qual = VOL >> TSHIFT; p->n_sp = lookup(stack_chk_canary, SNORMAL); defid(p, AUTO); p = clocal(p); ecomp(buildtree(ASSIGN, p, q)); } void sspend(void) { NODE *p, *q; TWORD t; int lab; if (retlab != NOLAB) { plabel(retlab); retlab = getlab(); } t = DECREF(cftnsp->stype); if (t == BOOL) t = BOOL_TYPE; p = block(NAME, NIL, NIL, INT, 0, 0); p->n_sp = lookup(stack_chk_canary, SNORMAL); p = clocal(p); q = block(REG, NIL, NIL, INT, 0, 0); glval(q) = 0; q->n_rval = FPREG; q = block(ER, p, q, INT, 0, 0); p = block(NAME, NIL, NIL, INT, 0, 0); p->n_sp = lookup(stack_chk_guard, SNORMAL); p = clocal(p); lab = getlab(); cbranch(buildtree(EQ, p, q), bcon(lab)); p = block(NAME, NIL, NIL, FTN+VOID, 0, 0); p->n_sp = lookup(stack_chk_fail, SNORMAL); p = clocal(p); q = eve(bdty(STRING, cftnsp->sname, 0)); ecomp(buildtree(CALL, p, q)); plabel(lab); } /* * Allocate on the permanent heap for inlines, otherwise temporary heap. */ void * blkalloc(int size) { return isinlining || blevel < 2 ? permalloc(size) : tmpalloc(size); } /* * Allocate on the permanent heap for inlines, otherwise temporary heap. */ void * inlalloc(int size) { return isinlining ? permalloc(size) : tmpalloc(size); } /* * Fetch pointer to first member in a struct list. */ struct symtab * strmemb(struct attr *ap) { if ((ap = attr_find(ap, ATTR_STRUCT)) == NULL) cerror("strmemb"); return ap->amlist; } #ifndef NO_COMPLEX static char *real, *imag; static struct symtab *cxsp[3]; /* * As complex numbers internally are handled as structs, create * these by hand-crafting them. */ void complinit(void) { struct attr *ap; struct rstack *rp; NODE *p, *q; char *n[] = { "0f", "0d", "0l" }; int i, d_debug; d_debug = ddebug; ddebug = 0; real = addname("__real"); imag = addname("__imag"); p = block(NAME, NIL, NIL, FLOAT, 0, 0); for (i = 0; i < 3; i++) { p->n_type = FLOAT+i; rpole = rp = bstruct(NULL, STNAME, NULL); soumemb(p, real, 0); soumemb(p, imag, 0); q = dclstruct(rp); cxsp[i] = q->n_sp = lookup(addname(n[i]), 0); defid(q, TYPEDEF); ap = attr_new(ATTR_COMPLEX, 0); q->n_sp->sap = attr_add(q->n_sp->sap, ap); nfree(q); } nfree(p); ddebug = d_debug; } /* * Return the highest real floating point type. * Known that at least one type is complex or imaginary. */ static TWORD maxtyp(NODE *l, NODE *r) { TWORD tl, tr, t; tl = ANYCX(l) ? strmemb(l->n_ap)->stype : l->n_type; tr = ANYCX(r) ? strmemb(r->n_ap)->stype : r->n_type; if (ISITY(tl)) tl -= (FIMAG - FLOAT); if (ISITY(tr)) tr -= (FIMAG - FLOAT); t = tl > tr ? tl : tr; if (!ISFTY(t)) cerror("maxtyp"); return t; } /* * Fetch space on stack for complex struct. */ static NODE * cxstore(TWORD t) { struct symtab s; s = *cxsp[t - FLOAT]; s.sclass = AUTO; s.soffset = NOOFFSET; oalloc(&s, &autooff); return nametree(&s); } #define comop(x,y) buildtree(COMOP, x, y) static NODE * mkcmplx(NODE *p, TWORD dt) { NODE *q, *r, *i, *t; if (!ANYCX(p)) { /* Not complex, convert to complex on stack */ q = cxstore(dt); if (ISITY(p->n_type)) { p->n_type = p->n_type - FIMAG + FLOAT; r = bcon(0); i = p; } else { r = p; i = bcon(0); } p = buildtree(ASSIGN, structref(ccopy(q), DOT, real), r); p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, imag), i)); p = comop(p, q); } else { if (strmemb(p->n_ap)->stype != dt) { q = cxstore(dt); p = buildtree(ADDROF, p, NIL); t = tempnode(0, p->n_type, p->n_df, p->n_ap); p = buildtree(ASSIGN, ccopy(t), p); p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, real), structref(ccopy(t), STREF, real))); p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, imag), structref(t, STREF, imag))); p = comop(p, q); } } return p; } static NODE * cxasg(NODE *l, NODE *r) { TWORD tl, tr; tl = strattr(l->n_ap) ? strmemb(l->n_ap)->stype : 0; tr = strattr(r->n_ap) ? strmemb(r->n_ap)->stype : 0; if (ANYCX(l) && ANYCX(r) && tl != tr) { /* different types in structs */ r = mkcmplx(r, tl); } else if (!ANYCX(l)) r = structref(r, DOT, ISITY(l->n_type) ? imag : real); else if (!ANYCX(r)) r = mkcmplx(r, tl); return buildtree(ASSIGN, l, r); } /* * Fixup complex operations. * At least one operand is complex. */ NODE * cxop(int op, NODE *l, NODE *r) { TWORD mxtyp; NODE *p, *q; NODE *ltemp, *rtemp; NODE *real_l, *imag_l; NODE *real_r, *imag_r; if (op == ASSIGN) return cxasg(l, r); mxtyp = maxtyp(l, r); l = mkcmplx(l, mxtyp); r = mkcmplx(r, mxtyp); /* put a pointer to left and right elements in a TEMP */ l = buildtree(ADDROF, l, NIL); ltemp = tempnode(0, l->n_type, l->n_df, l->n_ap); l = buildtree(ASSIGN, ccopy(ltemp), l); r = buildtree(ADDROF, r, NIL); rtemp = tempnode(0, r->n_type, r->n_df, r->n_ap); r = buildtree(ASSIGN, ccopy(rtemp), r); p = comop(l, r); /* create the four trees needed for calculation */ real_l = structref(ccopy(ltemp), STREF, real); real_r = structref(ccopy(rtemp), STREF, real); imag_l = structref(ltemp, STREF, imag); imag_r = structref(rtemp, STREF, imag); /* get storage on stack for the result */ q = cxstore(mxtyp); switch (op) { case NE: case EQ: tfree(q); p = buildtree(op, comop(p, real_l), real_r); q = buildtree(op, imag_l, imag_r); p = buildtree(op == EQ ? ANDAND : OROR, p, q); return p; case PLUS: case MINUS: p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, real), buildtree(op, real_l, real_r))); p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, imag), buildtree(op, imag_l, imag_r))); break; case MUL: /* Complex mul is "complex" */ /* (u+iv)*(x+iy)=((u*x)-(v*y))+i(v*x+y*u) */ p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, real), buildtree(MINUS, buildtree(MUL, ccopy(real_r), ccopy(real_l)), buildtree(MUL, ccopy(imag_r), ccopy(imag_l))))); p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, imag), buildtree(PLUS, buildtree(MUL, real_r, imag_l), buildtree(MUL, imag_r, real_l)))); break; case DIV: /* Complex div is even more "complex" */ /* (u+iv)/(x+iy)=(u*x+v*y)/(x*x+y*y)+i((v*x-u*y)/(x*x+y*y)) */ p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, real), buildtree(DIV, buildtree(PLUS, buildtree(MUL, ccopy(real_r), ccopy(real_l)), buildtree(MUL, ccopy(imag_r), ccopy(imag_l))), buildtree(PLUS, buildtree(MUL, ccopy(real_r), ccopy(real_r)), buildtree(MUL, ccopy(imag_r), ccopy(imag_r)))))); p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, real), buildtree(DIV, buildtree(MINUS, buildtree(MUL, ccopy(imag_l), ccopy(real_r)), buildtree(MUL, ccopy(real_l), ccopy(imag_r))), buildtree(PLUS, buildtree(MUL, ccopy(real_r), ccopy(real_r)), buildtree(MUL, ccopy(imag_r), ccopy(imag_r)))))); tfree(real_r); tfree(real_l); tfree(imag_r); tfree(imag_l); break; default: uerror("illegal operator %s", copst(op)); } return comop(p, q); } /* * Fixup imaginary operations. * At least one operand is imaginary, none is complex. */ NODE * imop(int op, NODE *l, NODE *r) { NODE *p, *q; TWORD mxtyp; int li, ri; li = ri = 0; if (ISITY(l->n_type)) li = 1, l->n_type = l->n_type - (FIMAG-FLOAT); if (ISITY(r->n_type)) ri = 1, r->n_type = r->n_type - (FIMAG-FLOAT); mxtyp = maxtyp(l, r); switch (op) { case ASSIGN: /* if both are imag, store value, otherwise store 0.0 */ if (!(li && ri)) { tfree(r); r = bcon(0); } p = buildtree(ASSIGN, l, r); p->n_type += (FIMAG-FLOAT); break; case PLUS: if (li && ri) { p = buildtree(PLUS, l, r); p->n_type += (FIMAG-FLOAT); } else { /* If one is imaginary and one is real, make complex */ if (li) q = l, l = r, r = q; /* switch */ q = cxstore(mxtyp); p = buildtree(ASSIGN, structref(ccopy(q), DOT, real), l); p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, imag), r)); p = comop(p, q); } break; case MINUS: if (li && ri) { p = buildtree(MINUS, l, r); p->n_type += (FIMAG-FLOAT); } else if (li) { q = cxstore(mxtyp); p = buildtree(ASSIGN, structref(ccopy(q), DOT, real), buildtree(UMINUS, r, NIL)); p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, imag), l)); p = comop(p, q); } else /* if (ri) */ { q = cxstore(mxtyp); p = buildtree(ASSIGN, structref(ccopy(q), DOT, real), l); p = comop(p, buildtree(ASSIGN, structref(ccopy(q), DOT, imag), buildtree(UMINUS, r, NIL))); p = comop(p, q); } break; case MUL: p = buildtree(MUL, l, r); if (li && ri) p = buildtree(UMINUS, p, NIL); if (li ^ ri) p->n_type += (FIMAG-FLOAT); break; case DIV: p = buildtree(DIV, l, r); if (ri && !li) p = buildtree(UMINUS, p, NIL); if (li ^ ri) p->n_type += (FIMAG-FLOAT); break; default: cerror("imop"); p = NULL; } return p; } NODE * cxelem(int op, NODE *p) { if (ANYCX(p)) { p = structref(p, DOT, op == XREAL ? real : imag); } else if (op == XIMAG) { /* XXX sanitycheck? */ tfree(p); p = bcon(0); } return p; } NODE * cxconj(NODE *p) { NODE *q, *r; /* XXX side effects? */ q = cxstore(strmemb(p->n_ap)->stype); r = buildtree(ASSIGN, structref(ccopy(q), DOT, real), structref(ccopy(p), DOT, real)); r = comop(r, buildtree(ASSIGN, structref(ccopy(q), DOT, imag), buildtree(UMINUS, structref(p, DOT, imag), NIL))); return comop(r, q); } /* * Prepare for return. * There may be implicit casts to other types. */ NODE * cxret(NODE *p, NODE *q) { //printf("cxret\n"); //fwalk(p, eprint, 0); if (ANYCX(q)) { /* Return complex type */ p = mkcmplx(p, strmemb(q->n_ap)->stype); } else if (ISFTY(q->n_type) || ISITY(q->n_type)) { /* real or imag */ p = structref(p, DOT, ISFTY(q->n_type) ? real : imag); if (p->n_type != q->n_type) p = cast(p, q->n_type, 0); } else cerror("cxred failing type"); return p; } #endif pcc-20181216/cc/cxxcom/scan.l010064400017500000000000000451451277716665000145050ustar raggewheel%{ /* $Id: scan.l,v 1.10 2016/10/11 13:48:24 ragge Exp $ */ /* * Copyright (c) 2002 Anders Magnusson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ %} D [0-9] L [a-zA-Z_] H [a-fA-F0-9] E [Ee][+-]?{D}+ P [Pp][+-]?{D}+ FS (f|F|l|L)?i? IS (u|U|l|L)* UL ({L}|\\u{H}{H}{H}{H}|\\U{H}{H}{H}{H}{H}{H}{H}{H}) %{ #include #include #include #include #include #include "pass1.h" #include "cgram.h" #define bdebug flexbdebug static NODE *cvtdig(int radix); static NODE *charcon(void); static NODE *wcharcon(void); static void control(int); static void pragma(void); int notype, parbal, inattr, parlvl, nodinit, inoso; static int dotfile; static int resw(TWORD, int); static int namechk(void); #define CPP_IDENT 2 #define CPP_LINE 3 #define CPP_HASH 4 #ifdef STABS #define STABS_LINE(x) if (gflag && cftnsp) stabs_line(x) #else #define STABS_LINE(x) #endif #if defined(FLEX_SCANNER) && YY_FLEX_SUBMINOR_VERSION == 31 /* Hack to avoid unnecessary warnings */ FILE *yyget_in (void); FILE *yyget_out (void); int yyget_leng (void); char *yyget_text (void); void yyset_in (FILE *); void yyset_out (FILE *); int yyget_debug (void); void yyset_debug (int); int yylex_destroy (void); extern int yyget_lineno (void); extern void yyset_lineno (int); #endif %} %% "__func__" { if (cftnsp == NULL) uerror("__func__ outside function"); yylval.strp = cftnsp->sname; /* XXX - not C99 */ return(C_STRING); } "asm" { return(C_ASM); } "auto" { return resw(AUTO, C_CLASS); } "_Bool" { return resw(BOOL, C_TYPE); } "break" { return(C_BREAK); } "case" { return(C_CASE); } "char" { return resw(CHAR, C_TYPE); } "class" { yylval.intval = CLNAME; notype=1; return(C_STRUCT); } "_Complex" { return resw(COMPLEX, C_TYPE); } "const" { return resw(CON, C_QUALIFIER); } "const_cast" { yylval.intval = CONST_CAST; return(CXX_CASTS); } "continue" { return(C_CONTINUE); } "default" { return(C_DEFAULT); } "delete" { return(CXX_DELETE); } "do" { return(C_DO); } "double" { return resw(DOUBLE, C_TYPE); } "dynamic_cast" { yylval.intval = DYN_CAST; return(CXX_CASTS); } "else" { return(C_ELSE); } "enum" { notype=1; return(C_ENUM); } "extern" { return resw(EXTERN, C_CLASS); } "float" { return resw(FLOAT, C_TYPE); } "for" { return(C_FOR); } "goto" { notype=1; return(C_GOTO); } "if" { return(C_IF); } "_Imaginary" { return resw(IMAG, C_TYPE); } "inline" { return(C_FUNSPEC); } "int" { return resw(INT, C_TYPE); } "long" { return resw(LONG, C_TYPE); } "namespace" { return(CXX_NAMESPACE); } "new" { notype = 0; return(CXX_NEW); } "register" { return resw(REGISTER, C_CLASS); } "reinterpret_cast" { yylval.intval = REINT_CAST; return(CXX_CASTS); } "restrict" { ; /* just ignore */ } "return" { return(C_RETURN); } "short" { return resw(SHORT, C_TYPE); } "signed" { return resw(SIGNED, C_TYPE); } "sizeof" { return(C_SIZEOF); } "static" { return resw(STATIC, C_CLASS); } "static_cast" { yylval.intval = STATIC_CAST; return(CXX_CASTS); } "struct" { yylval.intval = STNAME; notype=1; return(C_STRUCT); } "switch" { return(C_SWITCH); } "template" { return(CXX_TEMPLATE); } "typedef" { return resw(TYPEDEF, C_CLASS); } "typename" { return(CXX_TYPENAME); } "union" { yylval.intval = UNAME; notype=1; return(C_STRUCT); } "unsigned" { return resw(UNSIGNED, C_TYPE); } "using" { return(CXX_USING); } "void" { return resw(VOID, C_TYPE); } "volatile" { return resw(VOL, C_QUALIFIER); } "while" { return(C_WHILE); } {UL}({UL}|{D})* { return namechk(); } 0[xX]{H}+{IS}? { yylval.nodep = cvtdig(16); return(C_ICON); } 0{D}+{IS}? { yylval.nodep = cvtdig(8); return(C_ICON); } {D}+{IS}? { yylval.nodep = cvtdig(10); return(C_ICON); } L'(\\.|[^\\'])*' { yylval.nodep = wcharcon(); return(C_ICON); } '(\\.|[^\\'])*' { yylval.nodep = charcon(); return(C_ICON); } {D}+{E}{FS}? { yylval.nodep = floatcon(yytext); return(C_FCON); } {D}*"."{D}+({E})?{FS}? { yylval.nodep = floatcon(yytext); return(C_FCON); } {D}+"."{D}*({E})?{FS}? { yylval.nodep = floatcon(yytext); return(C_FCON); } 0[xX]{H}*"."{H}+{P}{FS}? { yylval.nodep = fhexcon(yytext); return(C_FCON); } 0[xX]{H}+"."{P}{FS}? { yylval.nodep = fhexcon(yytext); return(C_FCON); } 0[xX]{H}+{P}{FS}? { yylval.nodep = fhexcon(yytext); return(C_FCON); } L?\"(\\.|[^\\"])*\" { yylval.strp = yytext; return C_STRING; } "..." { return(C_ELLIPSIS); } ">>=" { yylval.intval = RSEQ; return(C_ASOP); } "<<=" { yylval.intval = LSEQ; return(C_ASOP); } "+=" { yylval.intval = PLUSEQ; return(C_ASOP); } "-=" { yylval.intval = MINUSEQ; return(C_ASOP); } "*=" { yylval.intval = MULEQ; return(C_ASOP); } "/=" { yylval.intval = DIVEQ; return(C_ASOP); } "%=" { yylval.intval = MODEQ; return(C_ASOP); } "&=" { yylval.intval = ANDEQ; return(C_ASOP); } "^=" { yylval.intval = EREQ; return(C_ASOP); } "|=" { yylval.intval = OREQ; return(C_ASOP); } ">>" { yylval.intval = RS; return(C_SHIFTOP); } "<<" { yylval.intval = LS; return(C_SHIFTOP); } "++" { yylval.intval = INCR; return(C_INCOP); } "--" { yylval.intval = DECR; return(C_INCOP); } "->" { yylval.intval = STREF; return(C_STROP); } "&&" { yylval.intval = ANDAND; return(C_ANDAND); } "||" { yylval.intval = OROR; return(C_OROR); } "<=" { yylval.intval = LE; return(C_RELOP); } ">=" { yylval.intval = GE; return(C_RELOP); } "==" { yylval.intval = EQ; return(C_EQUOP); } "!=" { yylval.intval = NE; return(C_EQUOP); } "::" { return(CXX_DUALCC); } ";" { notype = 0; return(';'); } ("{"|"<%") { notype = 0; return('{'); } ("}"|"%>") { if (rpole) notype = 1; return('}'); } "," { if (parbal && !inoso) notype = 0; return(','); } ":" { if (doing_init) nodinit--; return(':'); } "=" { return('='); } "(" { parbal++; notype = 0; return('('); } ")" { parbal--; inoso = 0; if (parbal==0) { notype = 0; } if (inattr && parlvl == parbal) inattr = 0; return(')'); } ("["|"<:") { return('['); } ("]"|":>") { return(']'); } "." { yylval.intval = DOT; return(C_STROP); } "&" { return('&'); } "!" { yylval.intval = NOT; return(C_UNOP); } "~" { yylval.intval = COMPL; return(C_UNOP); } "-" { return('-'); } "+" { return('+'); } "*" { if (parbal && notype == 0) notype = 1; return('*'); } "/" { yylval.intval = DIV; return(C_DIVOP); } "%" { yylval.intval = MOD; return(C_DIVOP); } "<" { yylval.intval = LT; return(C_RELOP); } ">" { yylval.intval = GT; return(C_RELOP); } "^" { return('^'); } "|" { return('|'); } "?" { if (doing_init) nodinit++; return('?'); } ^#pragma[ \t].* { pragma(); } ^#ident[ \t].* { control(CPP_IDENT); } ^#line[ \t].* { control(CPP_LINE); } ^#.* { control(CPP_HASH); } [ \t\v\f] { } "\n" { ++lineno; STABS_LINE(lineno); } . { /* ignore bad characters */ } %% int lineno, issyshdr; char *ftitle = ""; static int namechk(void) { struct symtab *s; int i; yylval.strp = addname(yytext); while ((i = input()) == ' ' || i == '\t') ; if (i == ':') { if ((i = input()) == ':') return CXX_MORENM; unput(i); if (doing_init && nodinit == 0) return(GCC_DESIG); i = ':'; } unput(i); #ifdef GCC_COMPAT if ((i = gcc_keyword(yylval.strp, &yylval.nodep)) > 0) return i; #endif if (notype) return(C_NAME); s = lookup(yylval.strp, SNOCREAT); return s && s->sclass == TYPEDEF ? notype=1, C_TYPENAME : C_NAME; } int yywrap(void) { if (0) unput(0); /* quiet gcc */ return(1); } int resw(TWORD t, int rv) { if (inattr) { yylval.strp = addname(yytext); return C_NAME; } switch (rv) { case C_CLASS: yylval.nodep = block(CLASS, NIL, NIL, t, 0, 0); return rv; case C_QUALIFIER: yylval.nodep = block(QUALIFIER, NIL, NIL, 0, 0, 0); yylval.nodep->n_qual = t; return rv; case C_TYPE: yylval.nodep = mkty(t, 0, 0); notype=1; return(rv); default: cerror("resw"); } return 0; } #ifndef SOFTFLOAT static long double typround(long double dc, char *e, TWORD *tw) { int im = 0; *tw = DOUBLE; for (; *e; e++) { switch (*e) { case 'f': case 'F': *tw = FLOAT; dc = (float)dc; break; case 'l': case 'L': *tw = LDOUBLE; break; case 'i': case 'I': im = 1; break; } } if (*tw == DOUBLE) dc = (double)dc; #ifndef NO_COMPLEX if (im) *tw += (FIMAG-FLOAT); #endif return dc; } /* * XXX floatcon() and fhexcon() should be in support libraries for * the target floating point. */ static NODE * f2(char *str) { TWORD tw; NODE *p; long double dc; char *eptr; #ifdef HAVE_STRTOLD dc = strtold(str, &eptr); /* XXX - avoid strtod() */ #else dc = strtod(str, &eptr); /* XXX - avoid strtod() */ #endif dc = typround(dc, eptr, &tw); p = block(FCON, NIL, NIL, tw, 0, 0); p->n_dcon = fltallo(); FCAST(p->n_dcon)->fp = dc; return p; } NODE * floatcon(char *s) { return f2(s); } static int h2n(int ch) { if (ch >= '0' && ch <= '9') return ch - '0'; if (ch >= 'a' && ch <= 'f') return ch - 'a' + 10; return ch - 'A' + 10; } NODE * fhexcon(char *c) { TWORD tw; char *ep; long double d; int i, ed; NODE *p; d = 0.0; ed = 0; c+= 2; /* skip 0x */ #define FSET(n) { d *= 2; if (i & n) d += 1.0; } for (; *c != '.' && *c != 'p' && *c != 'P'; c++) { i = h2n(*c); FSET(8); FSET(4); FSET(2); FSET(1); } if (*c != '.' && *c != 'p' && *c != 'P') cerror("fhexcon"); if (*c == '.') { c++; for (; *c != 'p' && *c != 'P'; c++) { i = h2n(*c); FSET(8); FSET(4); FSET(2); FSET(1); ed -= 4; } } if (*c != 'P' && *c != 'p') cerror("fhexcon2"); c++; ed += (int)strtol(c, &ep, 10); /* avoid looping in vain. Idea from Fred J. Tydeman */ if (ed > 32769) ed = 32769; if (ed < -32769) ed = -32769; while (ed > 0) d *= 2, ed--; while (ed < 0) d /= 2, ed++; d = typround(d, ep, &tw); p = block(FCON, NIL, NIL, tw, 0, 0); p->n_dcon = fltallo(); FCAST(p->n_dcon)->fp = d; return p; } #endif unsigned int esccon(char **sptr) { char *wr = *sptr; char *owr; char c; unsigned int val; int wsz = 4, esccon_warn = 1; switch (*wr++) { case 'a': val = '\a'; break; case 'b': val = '\b'; break; case 'f': val = '\f'; break; case 'n': val = '\n'; break; case 'r': val = '\r'; break; case 't': val = '\t'; break; case 'v': val = '\v'; break; case '\"': val = '\"'; break; case 'x': val = (int)strtoul(wr, &wr, 16); break; /* ISO/IEC 9099:1999 (E) 6.4.3 */ case 'U'|(char)0x80: esccon_warn = 0; /* FALLTHROUGH */ case 'U': wsz = 8; /* FALLTHROUGH */ case 'u': owr = wr; while (wr < (owr + wsz)) if (*wr == '\0') break; else ++wr; if (wr != (owr + wsz)) { /* incomplete */ val = (int)strtoul(owr, &wr, 16); } else { c = owr[wsz]; owr[wsz] = '\0'; /* prevent it from reading too much */ val = (int)strtoul(owr, &wr, 16); owr[wsz] = c; } if (wr != (owr + wsz)) werror("incomplete universal character name"); if (wsz == 4) val &= 0xFFFF; if (esccon_warn && ((val >= 0xD800 && val <= 0xDFFF) || (val < 0xA0 && val != 0x24 && val != 0x40 && val != 0x60))) werror("invalid universal character name %04X", val); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': val = wr[-1] - '0'; if (*wr >= '0' && *wr <= '7') { val = (val << 3) + (*wr++ - '0'); if (*wr >= '0' && *wr <= '7') val = (val << 3) + (*wr++ - '0'); } break; default: val = wr[-1]; } *sptr = wr; return val; } NODE * cvtdig(int radix) { NODE *p; TWORD otype, ntype; unsigned long long v; char *ch = yytext; int n, numl, numu; if (radix == 16) ch += 2; /* Skip 0x */ v = 0; while ((*ch >= '0' && *ch <= '9') || (*ch >= 'a' && *ch <= 'f') || (*ch >= 'A' && *ch <= 'F')) { v *= radix; n = *ch; n = (n <= '9' ? n - '0' : (n > 'F' ? n - 'a' : n - 'A') + 10); ch++; v += n; } /* Parse trailing chars */ ntype = INT; numl = numu = 0; for (n = 0; n < 3; n++) { if (*ch == 0) break; if ((*ch == 'l' || *ch == 'L') && numl < 2) ntype+=2, numl++; else if ((*ch == 'u' || *ch == 'U') && numu < 1) ntype = ENUNSIGN(ntype), numu++; else break; ch++; } if (*ch) uerror("constant has too many '%c'", *ch); otype = ntype; switch (ntype) { case INT: case LONG: case LONGLONG: if (radix == 10) { if (otype == LONGLONG) break; if (v > MAX_LONG) { ntype = LONGLONG; if (otype == LONG) break; } else if (v > MAX_INT) ntype = LONG; } else { if (v > MAX_LONGLONG) { ntype = ULONGLONG; if (otype == LONGLONG) break; } else if (v > MAX_ULONG) { ntype = LONGLONG; } else if (v > MAX_LONG) { ntype = ULONG; if (otype == LONG) break; } else if (v > MAX_UNSIGNED) { ntype = LONG; } else if (v > MAX_INT) ntype = UNSIGNED; } break; case UNSIGNED: case ULONG: if (v > MAX_ULONG) { ntype = ULONGLONG; if (otype == ULONG) break; } else if (v > MAX_UNSIGNED) ntype = ULONG; break; } ntype = ctype(ntype); p = xbcon(v, NULL, ntype); ASGLVAL(p->n_slval, v); return p; } /* * Convert a character constant to an integer. */ NODE * charcon(void) { int lastcon = 0; int val, i = 0; char *pp = yytext; pp++; /* skip ' */ while (*pp != '\'') { if (*pp++ == '\\') { val = esccon(&pp); } else val = pp[-1]; makecc(val, i); i++; } if (i == 0) uerror("empty character constant"); else if (i > (SZINT/SZCHAR) || (i>1)) werror("too many characters in character constant"); return bcon(lastcon); } NODE * wcharcon(void) { unsigned int lastcon = 0; unsigned int val, i = 0; char *pp = yytext; pp++; /* skip L */ pp++; /* skip ' */ while (*pp != '\'') { if (*pp++ == '\\') { val = esccon(&pp); } else val = pp[-1]; #if WCHAR_SIZE == 2 lastcon = (lastcon << 16) | (val & 0xFFFF); #else lastcon = val; #endif i++; } if (i == 0) uerror("empty wide-character constant"); else if (i > 1) werror("too many characters in wide-character constant"); return xbcon(lastcon, NULL, ctype(UNSIGNED)); } #ifndef MYDOTFILE /* * Get basename and print it as '.file "basename.c"' */ static void printdotfile(char *file) { char *p; if ((p = strrchr(file, '/')) == NULL) p = file; else p++; printf(PRTPREF "\t.file \"%s\"\n", p); } #endif void control(int t) { char *wr = yytext; char *eptr; int val; wr++; /* Skip initial '#' */ switch (t) { case CPP_IDENT: return; /* Just skip these for now. */ case CPP_LINE: wr += 4; /* FALLTHROUGH */ case CPP_HASH: val = (int)strtol(wr, &eptr, 10); if (wr == eptr) /* Illegal string */ goto bad; wr = eptr; lineno = val - 1; while (*wr && *wr != '\"') wr++; if (*wr == 0) return; if (*wr++ != '\"') goto bad; eptr = wr; while (*wr && *wr != '\"') wr++; if (*wr != '\"') goto bad; *wr = 0; ftitle = addstring(eptr); #ifdef STABS if (gflag) stabs_file(ftitle); #endif if (dotfile == 0) { dotfile++; printdotfile(ftitle); } } return; bad: werror("%s: illegal control", yytext); } int pragma_allpacked; int pragma_packed, pragma_aligned; char *pragma_renamed; static int pragmas_weak(char *str) { struct symtab *sp; char *s1, *s2; if ((s1 = pragtok(NULL)) == NULL) return 1; if ((s2 = pragtok(NULL)) == NULL) { sp = lookup(addname(s1), SNORMAL); #ifdef GCC_COMPAT sp->sap = attr_add(sp->sap, gcc_attr_parse(bdty(NAME, "weak"))); #else sp->sap = 0; #endif } else if (*s2 == '=') { if ((s2 = pragtok(NULL)) == NULL) return 1; sp = lookup(addname(s2), SNORMAL); #ifdef GCC_COMPAT sp->sap = attr_add(sp->sap, gcc_attr_parse(bdty(CALL, bdty(NAME, "aliasweak"), bdty(STRING, s1, 0)))); #else sp->sap = NULL; #endif } else return 1; return 0; } char *pragstore; /* trivial tokenizer for pragmas */ #define ps pragstore char * pragtok(char *sin) { static char ss[2]; char *rv; if (sin) ps = sin; for (; isspace((int)*ps); ps++) ; if (*ps == 0) return NULL; for (rv = ps; isalpha((int)*ps) || isdigit((int)*ps) || *ps == '_'; ps++) ; ss[0] = *ps; if (rv == ps) { rv = ss, ps++; } else { *ps = 0; rv = tmpstrdup(rv); *ps = ss[0]; } return rv; } /* return 1 on error */ int eat(int ch) { char *s = pragtok(0); return (s == 0 || *s != ch); } static int pragmas_alpack(char *t) { char *s; int ap; ap = (s = pragtok(0)) ? atoi(s) : 1; if (strcmp(t, "packed") == 0) pragma_packed = ap; else pragma_aligned = ap; return 0; } /* * Packing control. * still missing push/pop. */ static int pragmas_pack(char *t) { char *s; if (eat('(')) return 1; s = pragtok(0); if (*s == ')') return pragma_allpacked = 0; if (*s < '0' || *s > '9') /* no number */ return 1; pragma_allpacked = atoi(s); return eat(')'); } static int pragmas_renamed(char *t) { char *f = pragtok(0); if (f == 0) return 1; pragma_renamed = newstring(f, strlen(f)); return 0; } static int pragmas_stdc(char *t) { return 0; /* Just ignore */ } struct pragmas { char *name; int (*fun)(char *); } pragmas[] = { { "pack", pragmas_pack }, { "packed", pragmas_alpack }, { "aligned", pragmas_alpack }, { "rename", pragmas_renamed }, #ifdef GCC_COMPAT { "GCC", pragmas_gcc }, #endif { "STDC", pragmas_stdc }, { "weak", pragmas_weak }, { "ident", NULL }, { 0 }, }; /* * got a full pragma line. Split it up here. */ static void pragma(void) { struct pragmas *p; char *t, *pt; if ((t = pragtok(&yytext[7])) != NULL) { pt = ps; for (p = pragmas; p->name; p++) { if (strcmp(t, p->name) == 0) { if (p->fun && (*p->fun)(t)) uerror("bad argument to #pragma"); return; } } ps = pt; if (mypragma(t)) return; } warner(Wunknown_pragmas, t, ps); } void cunput(char c) { unput(c); } pcc-20181216/cc/cxxcom/softfloat.c010064400017500000000000000154311170010374700155230ustar raggewheel/* $Id: softfloat.c,v 1.1 2012/01/01 16:20:55 ragge Exp $ */ /* * Copyright (c) 2008 Anders Magnusson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifdef SOFTFLOAT #include "pass1.h" /* * Floating point emulation to be used when cross-compiling. * Currently only supports F- and D-float, used in DEC machines. * Should be trivial to add other emulations. * * XXX - assumes that: * - long long is (at least) 64 bits * - int is at least 32 bits. * - short is 16 bits. */ #ifdef FDFLOAT /* * Useful macros to manipulate the float. */ #define DSIGN(w) (((w).fd1 >> 15) & 1) #define DSIGNSET(w,s) ((w).fd1 = (s << 15) | ((w).fd1 & 077777)) #define DEXP(w) (((w).fd1 >> 7) & 0377) #define DEXPSET(w,e) ((w).fd1 = (((e) & 0377) << 7) | ((w).fd1 & 0100177)) #define DMANTH(w) ((w).fd1 & 0177) #define DMANTHSET(w,m) ((w).fd1 = ((m) & 0177) | ((w).fd1 & 0177600)) typedef unsigned int lword; typedef unsigned long long dword; #define MAXMANT 0x100000000000000LL /* * Returns a zero dfloat. */ static SF nulldf(void) { SF rv; rv.fd1 = rv.fd2 = rv.fd3 = rv.fd4 = 0; return rv; } /* * Convert a (u)longlong to dfloat. * XXX - fails on too large (> 55 bits) numbers. */ SF soft_cast(CONSZ ll, TWORD t) { int i; SF rv; rv = nulldf(); if (ll == 0) return rv; /* fp is zero */ if (ll < 0) DSIGNSET(rv,1), ll = -ll; for (i = 0; ll > 0; i++, ll <<= 1) ; DEXPSET(rv, 192-i); DMANTHSET(rv, ll >> 56); rv.fd2 = ll >> 40; rv.fd3 = ll >> 24; rv.fd4 = ll >> 8; return rv; } /* * multiply two dfloat. Use chop, not round. */ SF soft_mul(SF p1, SF p2) { SF rv; lword a1[2], a2[2], res[4]; dword sum; res[0] = res[1] = res[2] = res[3] = 0; /* move mantissa into lwords */ a1[0] = p1.fd4 | (p1.fd3 << 16); a1[1] = p1.fd2 | DMANTH(p1) << 16 | 0x800000; a2[0] = p2.fd4 | (p2.fd3 << 16); a2[1] = p2.fd2 | DMANTH(p2) << 16 | 0x800000; #define MULONE(x,y,r) sum += (dword)a1[x] * (dword)a2[y]; sum += res[r]; \ res[r] = sum; sum >>= 32; sum = 0; MULONE(0, 0, 0); MULONE(1, 0, 1); res[2] = sum; sum = 0; MULONE(0, 1, 1); MULONE(1, 1, 2); res[3] = sum; rv.fd1 = 0; DSIGNSET(rv, DSIGN(p1) ^ DSIGN(p2)); DEXPSET(rv, DEXP(p1) + DEXP(p2) - 128); if (res[3] & 0x8000) { res[3] = (res[3] << 8) | (res[2] >> 24); res[2] = (res[2] << 8) | (res[1] >> 24); } else { DEXPSET(rv, DEXP(rv) - 1); res[3] = (res[3] << 9) | (res[2] >> 23); res[2] = (res[2] << 9) | (res[1] >> 23); } DMANTHSET(rv, res[3] >> 16); rv.fd2 = res[3]; rv.fd3 = res[2] >> 16; rv.fd4 = res[2]; return rv; } SF soft_div(SF t, SF n) { SF rv; dword T, N, K; int c; #define SHL(x,b) ((dword)(x) << b) T = SHL(1,55) | SHL(DMANTH(t), 48) | SHL(t.fd2, 32) | SHL(t.fd3, 16) | t.fd4; N = SHL(1,55) | SHL(DMANTH(n), 48) | SHL(n.fd2, 32) | SHL(n.fd3, 16) | n.fd4; c = T > N; for (K = 0; (K & 0x80000000000000ULL) == 0; ) { if (T >= N) { T -= N; K |= 1; } T <<= 1; K <<= 1; } rv.fd1 = 0; DSIGNSET(rv, DSIGN(t) ^ DSIGN(n)); DEXPSET(rv, DEXP(t) - DEXP(n) + 128 + c); DMANTHSET(rv, K >> 48); rv.fd2 = K >> 32; rv.fd3 = K >> 16; rv.fd4 = K; return rv; } /* * Negate a float number. Easy. */ SF soft_neg(SF sf) { int sign = DSIGN(sf) == 0; DSIGNSET(sf, sign); return sf; } /* * Return true if fp number is zero. */ int soft_isz(SF sf) { return (DEXP(sf) == 0); } int soft_cmp_eq(SF x1, SF x2) { cerror("soft_cmp_eq"); return 0; } int soft_cmp_ne(SF x1, SF x2) { cerror("soft_cmp_ne"); return 0; } int soft_cmp_le(SF x1, SF x2) { cerror("soft_cmp_le"); return 0; } int soft_cmp_lt(SF x1, SF x2) { cerror("soft_cmp_lt"); return 0; } int soft_cmp_ge(SF x1, SF x2) { cerror("soft_cmp_ge"); return 0; } int soft_cmp_gt(SF x1, SF x2) { cerror("soft_cmp_gt"); return 0; } /* * Convert a fp number to a CONSZ. */ CONSZ soft_val(SF sf) { CONSZ mant; int exp = DEXP(sf) - 128; mant = SHL(1,55) | SHL(DMANTH(sf), 48) | SHL(sf.fd2, 32) | SHL(sf.fd3, 16) | sf.fd4; while (exp < 0) mant >>= 1, exp++; while (exp > 0) mant <<= 1, exp--; return mant; } SF soft_plus(SF x1, SF x2) { cerror("soft_plus"); return x1; } SF soft_minus(SF x1, SF x2) { cerror("soft_minus"); return x1; } /* * Convert a hex constant to floating point number. */ NODE * fhexcon(char *s) { cerror("fhexcon"); return NULL; } /* * Convert a floating-point constant to D-float and store it in a NODE. */ NODE * floatcon(char *s) { NODE *p; dword mant; SF fl, flexp, exp5; int exp, negexp, bexp; exp = 0; mant = 0; #define ADDTO(sum, val) sum = sum * 10 + val - '0' for (; *s >= '0' && *s <= '9'; s++) { if (mant= '0' && *s <= '9'; s++) { if (mant= '0' && *s <= '9'; s++) ADDTO(eexp, *s); if (sign) eexp = -eexp; exp = exp + eexp; } negexp = 1; if (exp<0) { negexp = -1; exp = -exp; } flexp = soft_cast(1, INT); exp5 = soft_cast(5, INT); bexp = exp; fl = soft_cast(mant, INT); for (; exp; exp >>= 1) { if (exp&01) flexp = soft_mul(flexp, exp5); exp5 = soft_mul(exp5, exp5); } if (negexp<0) fl = soft_div(fl, flexp); else fl = soft_mul(fl, flexp); DEXPSET(fl, DEXP(fl) + negexp*bexp); p = block(FCON, NIL, NIL, DOUBLE, 0, MKSUE(DOUBLE)); /* XXX type */ p->n_dcon = fl; return p; } #else #error missing softfloat definition #endif #endif pcc-20181216/cc/cxxcom/stabs.c010064400017500000000000000274721174507143500146550ustar raggewheel/* $Id: stabs.c,v 1.3 2012/04/22 21:07:41 plunky Exp $ */ /* * Copyright (c) 2004 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Simple implementation of the "stabs" debugging format. * Not complete but at least makes it possible to set breakpoints, * examine simple variables and do stack traces. * Based on the stabs documentation that follows gdb. */ #include "pass1.h" #ifdef STABS #include #include #include #define STABHASH 256 #define INTNUM 1 /* internal number of type "int" */ #undef BIT2BYTE /* from external.h */ #define BIT2BYTE(x) ((x)/SZCHAR) #ifndef STABLBL #error macdefs.h must define STABLBL #endif /* defines taken from BSD */ #define N_GSYM 0x20 /* global symbol */ #define N_FUN 0x24 /* procedure name */ #define N_LCSYM 0x28 /* bss segment variable */ #define N_RSYM 0x40 /* register variable */ #define N_SLINE 0x44 /* text segment line number */ #define N_SO 0x64 /* main source file name */ #define N_LSYM 0x80 /* stack variable */ #define N_SOL 0x84 /* included source file name */ #define N_PSYM 0xa0 /* parameter variable */ #define N_LBRAC 0xc0 /* left bracket */ #define N_RBRAC 0xe0 /* right bracket */ /* * Local type mapping * Types are defined as a typeword, a dimension pointer (in the case * of arrays) and struct/union/enum declarations. * Function prototypes are ignored. */ static struct stabtype { struct stabtype *next; /* linked list */ TWORD type; /* pcc type number */ union dimfun *df; /* dimension of arrays */ struct attr *ap; /* struct/union/enum declarations */ int num; /* local type number */ } *stabhash[STABHASH]; static int ntypes; static char *curfun; static int stablbl = 10; extern int inftn; void ptype(char *name, int num, int inhnum, long long min, long long max); struct stabtype *addtype(TWORD, union dimfun *, struct attr *); struct stabtype *findtype(TWORD t, union dimfun *df, struct attr *sue); void printtype(struct symtab *s, char *str, int len); void cprint(int p2, char *fmt, ...); #define MAXPSTR 100 extern int isinlining; /* * Output type definitions for the stab debugging format. * Note that "int" is always internal number 1. */ void stabs_init(void) { struct stabtype *st; #define ADDTYPE(y) addtype(y, NULL, 0) ptype("int", ADDTYPE(INT)->num, INTNUM, MIN_INT, MAX_INT); st = ADDTYPE(CHAR); ptype("char", st->num, st->num, 0, MAX_CHAR); ptype("short", ADDTYPE(SHORT)->num, INTNUM, MIN_SHORT, MAX_SHORT); ptype("long", ADDTYPE(LONG)->num, INTNUM, MIN_LONG, MAX_LONG); ptype("long long", ADDTYPE(LONGLONG)->num, INTNUM, MIN_LONGLONG, MAX_LONGLONG); ptype("unsigned char", ADDTYPE(UCHAR)->num, INTNUM, 0, MAX_UCHAR); ptype("unsigned short", ADDTYPE(USHORT)->num, INTNUM, 0, MAX_USHORT); ptype("unsigned int", ADDTYPE(UNSIGNED)->num, INTNUM, 0, MAX_UNSIGNED); ptype("unsigned long", ADDTYPE(ULONG)->num, INTNUM, 0, MAX_ULONG); ptype("unsigned long long", ADDTYPE(ULONGLONG)->num, INTNUM, 0, MAX_ULONGLONG); ptype("float", ADDTYPE(FLOAT)->num, INTNUM, 4, 0); ptype("double", ADDTYPE(DOUBLE)->num, INTNUM, 8, 0); ptype("long double", ADDTYPE(LDOUBLE)->num, INTNUM, 12, 0); st = ADDTYPE(VOID); cprint(0, "\t.stabs \"void:t%d=r%d\",%d,0,0,0\n", st->num, st->num, N_LSYM); } /* * Print a type in stabs format */ void ptype(char *name, int num, int inhnum, long long min, long long max) { cprint(0, "\t.stabs \"%s:t%d=r%d;%lld;%lld;\",%d,0,0,0\n", name, num, inhnum, min, max, N_LSYM); } /* * Add a new local type to the hash table. * The search key is the (type, df, sue) triple. */ struct stabtype * addtype(TWORD t, union dimfun *df, struct attr *ap) { struct stabtype *st; st = permalloc(sizeof(struct stabtype)); st->type = t; st->df = df; st->ap = ap; st->num = ++ntypes; st->next = stabhash[t & (STABHASH-1)]; stabhash[t & (STABHASH-1)] = st; return st; } /* * Search for a given type and return a type pointer (or NULL). */ struct stabtype * findtype(TWORD t, union dimfun *df, struct attr *ap) { struct stabtype *st; union dimfun *dw, *dx; TWORD tw; st = stabhash[t & (STABHASH-1)]; for (; st; st = st->next) { if (t != st->type || ap != st->ap) continue; /* Ok, type and sue matches, check dimensions */ if (st->df == NULL) return st; /* no arrays, got match */ dw = st->df; dx = df; tw = t; for (; tw > BTMASK; tw = DECREF(tw)) { if (ISARY(tw)) { if (dw->ddim == dx->ddim) dw++, dx++; else break; } } if (tw <= BTMASK) return st; } return NULL; } /* * Print current line number. */ void stabs_line(int line) { if (inftn == 0) return; /* ignore */ #ifdef STAB_LINE_ABSOLUTE cprint(1, "\t.stabn %d,0,%d," STABLBL "\n" STABLBL ":\n", N_SLINE, line, stablbl, stablbl); #else cprint(1, "\t.stabn %d,0,%d," STABLBL "-%s\n" STABLBL ":\n", N_SLINE, line, stablbl, curfun, stablbl); #endif stablbl++; } /* * Start of block. */ void stabs_lbrac(int blklvl) { #ifdef STAB_LINE_ABSOLUTE cprint(1, "\t.stabn %d,0,%d," STABLBL "\n" STABLBL ":\n", N_LBRAC, blklvl, stablbl, stablbl); #else cprint(1, "\t.stabn %d,0,%d," STABLBL "-%s\n" STABLBL ":\n", N_LBRAC, blklvl, stablbl, curfun, stablbl); #endif stablbl++; } /* * End of block. */ void stabs_rbrac(int blklvl) { #ifdef STAB_LINE_ABSOLUTE cprint(1, "\t.stabn %d,0,%d," STABLBL "\n" STABLBL ":\n", N_RBRAC, blklvl, stablbl, stablbl); #else cprint(1, "\t.stabn %d,0,%d," STABLBL "-%s\n" STABLBL ":\n", N_RBRAC, blklvl, stablbl, curfun, stablbl); #endif stablbl++; } static char *mainfile; /* * Print current file and set mark. */ void stabs_file(char *fname) { if (mainfile == NULL) mainfile = fname; /* first call */ cprint(inftn, "\t.stabs \"%s\",%d,0,0," STABLBL "\n" STABLBL ":\n", fname, fname == mainfile ? N_SO : N_SOL, stablbl, stablbl); stablbl++; } /* * Print end mark */ void stabs_efile(char *fname) { cprint(inftn, "\t.stabs \"\",%d,0,0," STABLBL "\n" STABLBL ":\n", fname == mainfile ? N_SO : N_SOL, stablbl, stablbl); stablbl++; } /* * Print beginning of function. */ void stabs_func(struct symtab *s) { char str[MAXPSTR]; if ((curfun = s->soname) == NULL) curfun = addname(exname(s->sname)); printtype(s, str, sizeof(str)); cprint(1, "\t.stabs \"%s:%c%s\",%d,0,%d,%s\n", curfun, s->sclass == STATIC ? 'f' : 'F', str, N_FUN, 0, curfun); } /* * Print a (complex) type. * Will also create subtypes. * Printed string is like "20=*21=*1". */ void printtype(struct symtab *s, char *ostr, int len) { struct stabtype *st; union dimfun *df = s->sdf; struct attr *ap = s->sap; TWORD t = s->stype; int op = 0; /* Print out not-yet-found types */ if (ISFTN(t)) t = DECREF(t); st = findtype(t, df, ap); while (st == NULL && t > BTMASK) { st = addtype(t, df, ap); op+=snprintf(ostr+op, len - op, "%d=", st->num); if (ISFTN(t)) ostr[op++] = 'f'; else if (ISPTR(t)) ostr[op++] = '*'; else if (ISARY(t)) { op+=snprintf(ostr+op, len - op, "ar%d;0;%d;", INTNUM, df->ddim-1); } else cerror("printtype: notype"); if (ISARY(t)) df++; t = DECREF(t); st = findtype(t, df, ap); if (op > MAXPSTR-10) cerror("printtype: too difficult expression"); } /* print out basic type. may have to be entered in case of sue */ snprintf(ostr+op, len - op, "%d", st == NULL ? 1 : st->num); /* snprintf here null-terminated the string */ } void stabs_newsym(struct symtab *s) { extern int fun_inline; char *sname; char ostr[MAXPSTR]; OFFSZ suesize, sz; if (ISFTN(s->stype)) return; /* functions are handled separate */ if (s->sclass == STNAME || s->sclass == UNAME || s->sclass == MOS || s->sclass == ENAME || s->sclass == MOU || s->sclass == MOE || s->sclass == TYPEDEF || (s->sclass & FIELD) || ISSOU(s->stype)) return; /* XXX - fix structs */ if ((sname = s->soname) == NULL) sname = exname(s->sname); sz = tsize(s->stype, s->sdf, s->sap); suesize = BIT2BYTE(sz); if (suesize > 32767) suesize = 32767; else if (suesize < -32768) suesize = -32768; printtype(s, ostr, sizeof(ostr)); switch (s->sclass) { case PARAM: cprint(0, "\t.stabs \"%s:p%s\",%d,0," CONFMT ",%d\n", sname, ostr, N_PSYM, (CONSZ)suesize, BIT2BYTE(s->soffset)); break; case AUTO: cprint(0, "\t.stabs \"%s:%s\",%d,0," CONFMT ",%d\n", sname, ostr, N_LSYM, (CONSZ)suesize, BIT2BYTE(s->soffset)); break; case STATIC: if (blevel) cprint(0, "\t.stabs \"%s:V%s\",%d,0," CONFMT "," LABFMT "\n", sname, ostr, N_LCSYM, (CONSZ)suesize, s->soffset); else cprint(0, "\t.stabs \"%s:S%s\",%d,0," CONFMT ",%s\n", sname, ostr, N_LCSYM, (CONSZ)suesize, sname); break; case EXTERN: case EXTDEF: cprint(0, "\t.stabs \"%s:G%s\",%d,0," CONFMT ",0\n", sname, ostr, N_GSYM, (CONSZ)suesize); break; case REGISTER: cprint(0, "\t.stabs \"%s:r%s\",%d,0,%d,%d\n", sname, ostr, N_RSYM, 1, s->soffset); break; case SNULL: if (fun_inline) break; /* FALLTHROUGH */ default: cerror("fix stab_newsym; class %d", s->sclass); } } void stabs_chgsym(struct symtab *s) { } /* * define a struct. */ void stabs_struct(struct symtab *p, struct attr *ap) { } struct stabsv { SLIST_ENTRY(stabsv) next; char *str; } ; static SLIST_HEAD(, stabsv) stpole = { NULL, &stpole.q_forw }; /* * Global variable debug info is printed out directly. * For functions and their declarations, both the labels and * the debug info is put into ASM nodes and follows their statements * into pass2. * Due to the possible unsync between pass1 and 2 and where the * stabs info for text is sent over the following syncing is used: * curfun == 0 * print out everything; only data will be. * curfun != 0 && inftn == 0 * save in linked list * curfun != 0 && inftn != 0 * print linked list first, empty it, then arg. */ void cprint(int p2, char *fmt, ...) { #define CPBSZ 200 char buf[CPBSZ]; struct stabsv *w; va_list ap; char *str; if (isinlining) return; /* XXX do not save any inline functions currently */ va_start(ap, fmt); if (p2) { if (vsnprintf(buf, CPBSZ, fmt, ap) >= CPBSZ) werror("stab symbol line too long, truncating"); str = tmpstrdup(buf); if (inftn == 0) { w = tmpalloc(sizeof(struct stabsv)); w->str = str; SLIST_INSERT_LAST(&stpole, w, next); } else { if (stpole.q_last != &stpole.q_forw) { SLIST_FOREACH(w, &stpole, next) { send_passt(IP_ASM, w->str); } SLIST_INIT(&stpole); } send_passt(IP_ASM, str); } } else vprintf(fmt, ap); va_end(ap); } #endif pcc-20181216/cc/cxxcom/symtabs.c010064400017500000000000000245371277716665000152340ustar raggewheel/* $Id: symtabs.c,v 1.5 2016/10/11 13:48:24 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "pass1.h" /* * These definitions are used in the patricia tree that stores * the strings. */ #define LEFT_IS_LEAF 0x80000000 #define RIGHT_IS_LEAF 0x40000000 #define IS_LEFT_LEAF(x) (((x) & LEFT_IS_LEAF) != 0) #define IS_RIGHT_LEAF(x) (((x) & RIGHT_IS_LEAF) != 0) #define BITNO(x) ((x) & ~(LEFT_IS_LEAF|RIGHT_IS_LEAF)) #define CHECKBITS 8 struct tree { int bitno; struct tree *lr[2]; }; static struct tree *firstname; int nametabs, namestrlen; static struct tree *firststr; int strtabs, strstrlen; static char *symtab_add(char *key, struct tree **, int *, int *); int lastloc = NOSEG; #define P_BIT(key, bit) (key[bit >> 3] >> (bit & 7)) & 1 #define getree() permalloc(sizeof(struct tree)) char * addname(char *key) { return symtab_add(key, &firstname, &nametabs, &namestrlen); } char * addstring(char *key) { return symtab_add(key, &firststr, &strtabs, &strstrlen); } /* * Add a name to the name stack (if its non-existing), * return its address. * This is a simple patricia implementation. */ static char * symtab_add(char *key, struct tree **first, int *tabs, int *stlen) { struct tree *w, *new, *last; int cix, bit, fbit, svbit, ix, bitno, len; char *m, *k, *sm; /* Count full string length */ for (k = key, len = 0; *k; k++, len++) ; switch (*tabs) { case 0: *first = (struct tree *)newstring(key, len); *stlen += (len + 1); (*tabs)++; return (char *)*first; case 1: m = (char *)*first; svbit = 0; /* XXX why? */ break; default: w = *first; bitno = len * CHECKBITS; for (;;) { bit = BITNO(w->bitno); fbit = bit > bitno ? 0 : P_BIT(key, bit); svbit = fbit ? IS_RIGHT_LEAF(w->bitno) : IS_LEFT_LEAF(w->bitno); w = w->lr[fbit]; if (svbit) { m = (char *)w; break; } } } sm = m; k = key; /* Check for correct string and return */ for (cix = 0; *m && *k && *m == *k; m++, k++, cix += CHECKBITS) ; if (*m == 0 && *k == 0) return sm; ix = *m ^ *k; while ((ix & 1) == 0) ix >>= 1, cix++; /* Create new node */ new = getree(); bit = P_BIT(key, cix); new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF); new->lr[bit] = (struct tree *)newstring(key, len); *stlen += (len + 1); if ((*tabs)++ == 1) { new->lr[!bit] = *first; new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF); *first = new; return (char *)new->lr[bit]; } w = *first; last = NULL; for (;;) { fbit = w->bitno; bitno = BITNO(w->bitno); if (bitno == cix) cerror("bitno == cix"); if (bitno > cix) break; svbit = P_BIT(key, bitno); last = w; w = w->lr[svbit]; if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF)) break; } new->lr[!bit] = w; if (last == NULL) { *first = new; } else { last->lr[svbit] = new; last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF); } if (bitno < cix) new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF); return (char *)new->lr[bit]; } static struct tree *sympole[NSTYPES]; static struct symtab *tmpsyms[NSTYPES]; int numsyms[NSTYPES]; /* * Inserts a symbol into the symbol tree. * Returns a struct symtab. */ struct symtab * lookup(char *key, int stype) { struct symtab *sym; struct tree *w, *new, *last; int cix, bit, fbit, svbit, bitno; int type, uselvl; intptr_t ix, match, code = (intptr_t)key; type = stype & SMASK; uselvl = (blevel > 0 && type != SSTRING); /* * The local symbols are kept in a simple linked list. * Check this list first. */ if (blevel > 0) for (sym = tmpsyms[type]; sym; sym = sym->snext) if (sym->sname == key) return sym; switch (numsyms[type]) { case 0: if (stype & SNOCREAT) return NULL; if (uselvl) { sym = getsymtab(key, stype|STEMP); sym->snext = tmpsyms[type]; tmpsyms[type] = sym; return sym; } sympole[type] = (struct tree *)getsymtab(key, stype); numsyms[type]++; return (struct symtab *)sympole[type]; case 1: w = (struct tree *)sympole[type]; svbit = 0; /* XXX why? */ break; default: w = sympole[type]; for (;;) { bit = BITNO(w->bitno); fbit = (int)(code >> bit) & 1; svbit = fbit ? IS_RIGHT_LEAF(w->bitno) : IS_LEFT_LEAF(w->bitno); w = w->lr[fbit]; if (svbit) break; } } sym = (struct symtab *)w; match = (intptr_t)sym->sname; ix = code ^ match; if (ix == 0) return sym; else if (stype & SNOCREAT) return NULL; #ifdef PCC_DEBUG if (ddebug) printf(" adding %s as %s at level %d\n", key, uselvl ? "temp" : "perm", blevel); #endif /* * Insert into the linked list, if feasible. */ if (uselvl) { sym = getsymtab(key, stype|STEMP); sym->snext = tmpsyms[type]; tmpsyms[type] = sym; return sym; } /* * Need a new node. If type is SNORMAL and inside a function * the node must be allocated as permanent anyway. * This could be optimized by adding a remove routine, but it * may be more trouble than it is worth. */ if (stype == (STEMP|SNORMAL)) stype = SNORMAL; for (cix = 0; (ix & 1) == 0; ix >>= 1, cix++) ; new = stype & STEMP ? tmpalloc(sizeof(struct tree)) : permalloc(sizeof(struct tree)); bit = (int)(code >> cix) & 1; new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF); new->lr[bit] = (struct tree *)getsymtab(key, stype); if (numsyms[type]++ == 1) { new->lr[!bit] = sympole[type]; new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF); sympole[type] = new; return (struct symtab *)new->lr[bit]; } w = sympole[type]; last = NULL; for (;;) { fbit = w->bitno; bitno = BITNO(w->bitno); if (bitno == cix) cerror("bitno == cix"); if (bitno > cix) break; svbit = (int)(code >> bitno) & 1; last = w; w = w->lr[svbit]; if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF)) break; } new->lr[!bit] = w; if (last == NULL) { sympole[type] = new; } else { last->lr[svbit] = new; last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF); } if (bitno < cix) new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF); return (struct symtab *)new->lr[bit]; } void symclear(int level) { struct symtab *s; int i; #ifdef PCC_DEBUG if (ddebug) printf("symclear(%d)\n", level); #endif if (level < 1) { for (i = 0; i < NSTYPES; i++) { s = tmpsyms[i]; tmpsyms[i] = 0; if (i != SLBLNAME) continue; while (s != NULL) { if (s->soffset < 0) uerror("label '%s' undefined",s->sname); s = s->snext; } } } else { for (i = 0; i < NSTYPES; i++) { if (i == SLBLNAME) continue; /* function scope */ while (tmpsyms[i] != NULL && tmpsyms[i]->slevel > level) { tmpsyms[i] = tmpsyms[i]->snext; } } } } struct symtab * hide(struct symtab *sym) { struct symtab *new; int typ = sym->sflags & SMASK; new = getsymtab(sym->sname, typ|STEMP); new->snext = tmpsyms[typ]; tmpsyms[typ] = new; warner(Wshadow, sym->sname, sym->slevel ? "local" : "global"); #ifdef PCC_DEBUG if (ddebug) printf("\t%s hidden at level %d (%p -> %p)\n", sym->sname, blevel, sym, new); #endif return new; } /* * Extract correct segment for the specified symbol and call * target routines to print it out. * If symtab entry is specified, output alignment as well. */ void locctr(int seg, struct symtab *sp) { #ifdef GCC_COMPAT struct attr *ga; #endif if (seg == NOSEG) { ; } else if (sp == NULL) { if (lastloc != seg) setseg(seg, NULL); #ifdef GCC_COMPAT } else if ((ga = attr_find(sp->sap, GCC_ATYP_SECTION)) != NULL) { setseg(NMSEG, ga->sarg(0)); seg = NOSEG; #endif } else { if (seg == DATA) { if (ISCON(cqual(sp->stype, sp->squal))) seg = RDATA; else if (sp->sclass == STATIC) seg = LDATA; } if (sp->sflags & STLS) { if (seg == DATA || seg == LDATA) seg = TLSDATA; if (seg == UDATA) seg = TLSUDATA; } else if (kflag) { if (seg == DATA) seg = PICDATA; if (seg == RDATA) seg = PICRDATA; if (seg == LDATA) seg = PICLDATA; } if (lastloc != seg) setseg(seg, NULL); } lastloc = seg; /* setup alignment */ #ifndef ALFTN #define ALFTN ALINT #endif if (sp) { int al; if (ISFTN(sp->stype)) { al = ALFTN; } else al = talign(sp->stype, sp->sap); defalign(al); symdirec(sp); } } #ifndef MYALIGN void defalign(int al) { #ifdef HASP2ALIGN #define P2ALIGN(x) ispow2(x) #else #define P2ALIGN(x) (x) #endif if (al != ALCHAR) printf("\t.align %d\n", P2ALIGN(al/ALCHAR)); } #endif #ifndef MYDIREC /* * Directives given as attributes to symbols. */ void symdirec(struct symtab *sp) { #ifdef GCC_COMPAT struct attr *ga; char *name; if ((name = sp->soname) == NULL) name = exname(sp->sname); if ((ga = attr_find(sp->sap, GCC_ATYP_WEAK)) != NULL) printf("\t.weak %s\n", name); if ((ga = attr_find(sp->sap, GCC_ATYP_VISIBILITY)) && strcmp(ga->sarg(0), "default")) printf("\t.%s %s\n", ga->sarg(0), name); if ((ga = attr_find(sp->sap, GCC_ATYP_ALIASWEAK))) { printf("\t.weak %s\n", ga->sarg(0)); printf("\t.set %s,%s\n", ga->sarg(0), name); } #endif } #endif char * getexname(struct symtab *sp) { char *s; if ((s = sp->soname) == NULL) s = addname(exname(sp->sname)); return s; } pcc-20181216/cc/cxxcom/trees.c010064400017500000000000002055111277225026700146560ustar raggewheel/* $Id: trees.c,v 1.23 2016/09/26 16:45:43 ragge Exp $ */ /* * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code and documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditionsand the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * Some of the changes from 32V include: * - Understand "void" as type. * - Handle enums as ints everywhere. * - Convert some C-specific ops into branches. */ # include "pass1.h" # include "pass2.h" # include # include static void chkpun(NODE *p); static int opact(NODE *p); static int moditype(TWORD); static NODE *strargs(NODE *); static void rmcops(NODE *p); static NODE *tymatch(NODE *p); void putjops(NODE *, void *); static void p2tree(NODE *); static struct symtab *findmember(struct symtab *, char *); int inftn; /* currently between epilog/prolog */ static char *tnames[] = { "undef", "farg", "char", "unsigned char", "short", "unsigned short", "int", "unsigned int", "long", "unsigned long", "long long", "unsigned long long", "float", "double", "long double", "strty", "unionty", "enumty", "moety", "void", "signed", /* pass1 */ "bool", /* pass1 */ "fimag", /* pass1 */ "dimag", /* pass1 */ "limag", /* pass1 */ "fcomplex", /* pass1 */ "dcomplex", /* pass1 */ "lcomplex", /* pass1 */ "enumty", /* pass1 */ "?", "?" }; /* some special actions, used in finding the type of nodes */ # define NCVT 01 # define PUN 02 # define TYPL 04 # define TYPR 010 # define TYMATCH 040 # define LVAL 0100 # define CVTO 0200 # define CVTL 0400 # define CVTR 01000 # define PTMATCH 02000 # define OTHER 04000 # define NCVTR 010000 # define PROML 020000 /* promote left operand */ /* node conventions: NAME: rval>0 is stab index for external rval<0 is -inlabel number lval is offset in bits ICON: lval has the value rval has the STAB index, or - label number, if a name whose address is in the constant rval = NONAME means no name REG: rval is reg. identification cookie */ extern int negrel[]; /* Have some defaults for most common targets */ #ifndef WORD_ADDRESSED #define offcon(o,t,d,ap) xbcon((o/SZCHAR), NULL, INTPTR) #define VBLOCK(p,b,t,d,a) buildtree(DIV, p, b) #define MBLOCK(p,b,t,d,a) buildtree(MUL, p, b) #else #define VBLOCK(p,b,t,d,a) block(PVCONV, p, b, t, d, a) #define MBLOCK(p,b,t,d,a) block(PMCONV, p, b, t, d, a) #endif NODE * buildtree(int o, NODE *l, NODE *r) { NODE *p, *q; int actions; int opty, n; struct symtab *sp = NULL; /* XXX gcc */ NODE *lr, *ll; #ifdef PCC_DEBUG if (bdebug) { printf("buildtree(%s, %p, %p)\n", copst(o), l, r); if (l) fwalk(l, eprint, 0); if (r) fwalk(r, eprint, 0); } #endif opty = coptype(o); /* check for constants */ if (o == ANDAND || o == OROR || o == NOT) { if (l->n_op == FCON) { p = bcon(!FLOAT_ISZERO(FCAST(l->n_dcon))); nfree(l); l = p; } if (o != NOT && r->n_op == FCON) { p = bcon(!FLOAT_ISZERO(FCAST(r->n_dcon))); nfree(r); r = p; } } if( opty == UTYPE && l->n_op == ICON ){ switch( o ){ case NOT: case UMINUS: case COMPL: if( conval( l, o, l ) ) return(l); break; } } else if (o == NOT && l->n_op == FCON) { l = clocal(block(SCONV, l, NIL, INT, 0, 0)); } else if( o == UMINUS && l->n_op == FCON ){ FLOAT_NEG(FCAST(l->n_dcon)); return(l); } else if( o==QUEST && (l->n_op==ICON || (l->n_op==NAME && ISARY(l->n_type)))) { CONSZ c = glval(l); if (l->n_op==NAME) c = 1; /* will become constant later */ nfree(l); if (c) { walkf(r->n_right, putjops, 0); tfree(r->n_right); l = r->n_left; } else { walkf(r->n_left, putjops, 0); tfree(r->n_left); l = r->n_right; } nfree(r); return(l); } else if( opty == BITYPE && l->n_op == ICON && r->n_op == ICON ){ switch( o ){ case PLUS: case MINUS: case MUL: case DIV: case MOD: /* * Do type propagation for simple types here. * The constant value is correct anyway. * Maybe this op shortcut should be removed? */ if (l->n_sp == NULL && r->n_sp == NULL && l->n_type < BTMASK && r->n_type < BTMASK) { if (l->n_type > r->n_type) r->n_type = l->n_type; else l->n_type = r->n_type; } /* FALLTHROUGH */ case ULT: case UGT: case ULE: case UGE: case LT: case GT: case LE: case GE: case EQ: case NE: case ANDAND: case OROR: case AND: case OR: case ER: case LS: case RS: if (!ISPTR(l->n_type) && !ISPTR(r->n_type)) { if( conval( l, o, r ) ) { nfree(r); return(l); } } break; } } else if (opty == BITYPE && (l->n_op == FCON || l->n_op == ICON) && (r->n_op == FCON || r->n_op == ICON) && (o == PLUS || o == MINUS || o == MUL || o == DIV || (o >= EQ && o <= GT) )) { #define D(x) ((FLT *)x) #ifndef CC_DIV_0 if (o == DIV && ((r->n_op == ICON && glval(r) == 0) || (r->n_op == FCON && FLOAT_EQ(D(r->n_dcon), FLOAT_ZERO)))) goto runtime; /* HW dependent */ #endif if (l->n_op == ICON) { if (!concast(l, r->n_type)) cerror("fail cast const"); } else if (r->n_op == ICON) { if (!concast(r, l->n_type)) cerror("fail cast const"); } switch(o){ case PLUS: case MINUS: case MUL: case DIV: switch (o) { case PLUS: FLOAT_PLUS(l, r); break; case MINUS: FLOAT_MINUS(l, r); break; case MUL: FLOAT_MUL(l, r); break; case DIV: FLOAT_DIV(l, r); break; } nfree(r); return(l); case EQ: case NE: case LE: case LT: case GE: case GT: switch (o) { case EQ: n = FLOAT_EQ(D(l->n_dcon), D(r->n_dcon)); break; case NE: n = FLOAT_NE(D(l->n_dcon), D(r->n_dcon)); break; case LE: n = FLOAT_LE(D(l->n_dcon), D(r->n_dcon)); break; case LT: n = FLOAT_LT(D(l->n_dcon), D(r->n_dcon)); break; case GE: n = FLOAT_GE(D(l->n_dcon), D(r->n_dcon)); break; case GT: n = FLOAT_GT(D(l->n_dcon), D(r->n_dcon)); break; default: n = 0; /* XXX flow analysis */ } nfree(r); nfree(l); return bcon(n); } } #ifndef CC_DIV_0 runtime: #endif /* its real; we must make a new node */ p = block(o, l, r, INT, 0, 0); actions = opact(p); if (actions & PROML) p->n_left = intprom(p->n_left); if (actions & LVAL) { /* check left descendent */ if (notlval(p->n_left)) { uerror("lvalue required"); nfree(p); return l; #ifdef notyet } else { if ((l->n_type > BTMASK && ISCON(l->n_qual)) || (l->n_type <= BTMASK && ISCON(l->n_qual << TSHIFT))) if (blevel > 0) uerror("lvalue is declared const"); #endif } } if( actions & NCVTR ){ p->n_left = pconvert( p->n_left ); } else if( !(actions & NCVT ) ){ switch( opty ){ case BITYPE: p->n_right = pconvert( p->n_right ); /* FALLTHROUGH */ case UTYPE: p->n_left = pconvert( p->n_left ); } } if ((actions&PUN) && (o!=CAST)) chkpun(p); if( actions & (TYPL|TYPR) ){ q = (actions&TYPL) ? p->n_left : p->n_right; p->n_type = q->n_type; p->n_qual = q->n_qual; p->n_df = q->n_df; p->n_ap = q->n_ap; } if( actions & CVTL ) p = convert( p, CVTL ); if( actions & CVTR ) p = convert( p, CVTR ); if( actions & TYMATCH ) p = tymatch(p); if( actions & PTMATCH ) p = ptmatch(p); if( actions & OTHER ){ struct symtab *sp1; l = p->n_left; r = p->n_right; switch(o){ case NAME: cerror("buildtree NAME"); case STREF: /* p->x turned into *(p+offset) */ /* rhs must be a name; check correctness */ /* Find member symbol struct */ if (l->n_type != PTR+STRTY && l->n_type != PTR+UNIONTY){ uerror("struct or union required"); break; } if ((sp1 = strmemb(l->n_ap)) == NULL) { uerror("undefined struct or union"); break; } if ((sp = findmember(sp1, r->n_name)) == NULL) { uerror("member '%s' not declared", r->n_name); break; } r->n_sp = sp; p = stref(p); break; case UMUL: if (l->n_op == ADDROF) { nfree(p); p = nfree(l); } if( !ISPTR(l->n_type))uerror("illegal indirection"); p->n_type = DECREF(l->n_type); p->n_qual = DECREF(l->n_qual); p->n_df = l->n_df; p->n_ap = l->n_ap; break; case ADDROF: switch( l->n_op ){ case UMUL: nfree(p); p = nfree(l); /* FALLTHROUGH */ case TEMP: case NAME: p->n_type = INCREF(l->n_type); p->n_qual = INCQAL(l->n_qual); p->n_df = l->n_df; p->n_ap = l->n_ap; break; case COMOP: nfree(p); lr = buildtree(ADDROF, l->n_right, NIL); p = buildtree( COMOP, l->n_left, lr ); nfree(l); break; case QUEST: lr = buildtree( ADDROF, l->n_right->n_right, NIL ); ll = buildtree( ADDROF, l->n_right->n_left, NIL ); nfree(p); nfree(l->n_right); p = buildtree( QUEST, l->n_left, buildtree( COLON, ll, lr ) ); nfree(l); break; default: uerror("unacceptable operand of &: %d", l->n_op ); break; } break; case LS: case RS: /* must make type size at least int... */ if (p->n_type == CHAR || p->n_type == SHORT) { p->n_left = makety(l, INT, 0, 0, 0); } else if (p->n_type == UCHAR || p->n_type == USHORT) { p->n_left = makety(l, UNSIGNED, 0, 0, 0); } l = p->n_left; p->n_type = l->n_type; p->n_qual = l->n_qual; p->n_df = l->n_df; p->n_ap = l->n_ap; /* FALLTHROUGH */ case LSEQ: case RSEQ: /* ...but not for assigned types */ if(tsize(r->n_type, r->n_df, r->n_ap) > SZINT) p->n_right = makety(r, INT, 0, 0, 0); break; case RETURN: case ASSIGN: case CAST: /* structure assignment */ /* take the addresses of the two sides; then make an * operator using STASG and * the addresses of left and right */ if (strmemb(l->n_ap) != strmemb(r->n_ap)) uerror("assignment of different structures"); r = buildtree(ADDROF, r, NIL); l = block(STASG, l, r, r->n_type, r->n_df, r->n_ap); l = clocal(l); if( o == RETURN ){ nfree(p); p = l; break; } p->n_op = UMUL; p->n_left = l; p->n_right = NIL; break; case QUEST: /* fixup types of : */ if (r->n_left->n_type != p->n_type) r->n_left = makety(r->n_left, p->n_type, p->n_qual, p->n_df, p->n_ap); if (r->n_right->n_type != p->n_type) r->n_right = makety(r->n_right, p->n_type, p->n_qual, p->n_df, p->n_ap); break; case COLON: /* structure colon */ if (strmemb(l->n_ap) != strmemb(r->n_ap)) uerror( "type clash in conditional" ); break; case CALL: p->n_right = r = strargs(p->n_right); p = funcode(p); /* FALLTHROUGH */ case UCALL: if (!ISPTR(l->n_type)) uerror("illegal function"); p->n_type = DECREF(l->n_type); if (!ISFTN(p->n_type)) uerror("illegal function"); p->n_type = DECREF(p->n_type); p->n_df = l->n_df+1; /* add one for prototypes */ p->n_ap = l->n_ap; if (p->n_type == STRTY || p->n_type == UNIONTY) { /* function returning structure */ /* make function really return ptr to str., with * */ p->n_op += STCALL-CALL; p->n_type = INCREF(p->n_type); p = clocal(p); /* before recursing */ p = buildtree(UMUL, p, NIL); } break; default: cerror( "other code %d", o ); } } /* * Allow (void)0 casts. * XXX - anything on the right side must be possible to cast. * XXX - remove void types further on. */ if (p->n_op == CAST && p->n_type == VOID && p->n_right->n_op == ICON) p->n_right->n_type = VOID; if (actions & CVTO) p = oconvert(p); p = clocal(p); #ifdef PCC_DEBUG if (bdebug) { printf("End of buildtree:\n"); fwalk(p, eprint, 0); } #endif return(p); } /* Find a member in a struct or union. May be an unnamed member */ static struct symtab * findmember(struct symtab *sp, char *s) { struct symtab *sp2, *sp3; for (; sp != NULL; sp = sp->snext) { if (sp->sname[0] == '*') { /* unnamed member, recurse down */ if ((sp2 = findmember(strmemb(sp->sap), s))) { sp3 = tmpalloc(sizeof (struct symtab)); *sp3 = *sp2; sp3->soffset += sp->soffset; return sp3; } } else if (sp->sname == s) return sp; } return NULL; } /* * Check if there will be a lost label destination inside of a ?: * It cannot be reached so just print it out. */ void putjops(NODE *p, void *arg) { if (p->n_op == COMOP && p->n_left->n_op == GOTO) plabel((int)glval(p->n_left->n_left)+1); } /* * Build a name node based on a symtab entry. * broken out from buildtree(). */ NODE * nametree(struct symtab *sp) { NODE *p; p = block(NAME, NIL, NIL, sp->stype, sp->sdf, sp->sap); p->n_qual = sp->squal; p->n_sp = sp; #ifndef NO_C_BUILTINS if (sp->sname[0] == '_' && strncmp(sp->sname, "__builtin_", 10) == 0) return p; /* do not touch builtins here */ #endif if (sp->sflags & STNODE) { /* Generated for optimizer */ p->n_op = TEMP; p->n_rval = sp->soffset; } #ifdef GCC_COMPAT /* Get a label name */ if (sp->sflags == SLBLNAME) { p->n_type = VOID; } #endif if (sp->stype == UNDEF) { uerror("%s undefined", sp->sname); /* make p look reasonable */ p->n_type = INT; p->n_df = NULL; defid(p, SNULL); } if (sp->sclass == MOE) { p->n_op = ICON; glval(p) = sp->soffset; p->n_df = NULL; p->n_sp = NULL; } return clocal(p); } /* * Cast a node to another type by inserting a cast. * Just a nicer interface to buildtree. * Returns the new tree. */ NODE * cast(NODE *p, TWORD t, TWORD u) { NODE *q; q = block(NAME, NIL, NIL, t, 0, 0); q->n_qual = u; q = buildtree(CAST, q, p); p = q->n_right; nfree(q->n_left); nfree(q); return p; } /* * Cast and complain if necessary by not inserining a cast. */ NODE * ccast(NODE *p, TWORD t, TWORD u, union dimfun *df, struct attr *ap) { NODE *q; /* let buildtree do typechecking (and casting) */ q = block(NAME, NIL, NIL, t, df, ap); p = buildtree(ASSIGN, q, p); nfree(p->n_left); q = optim(p->n_right); nfree(p); return q; } /* * Do an actual cast of a constant (if possible). * Routine assumes 2-complement (is there anything else today?) * Returns 1 if handled, 0 otherwise. */ int concast(NODE *p, TWORD t) { extern short sztable[]; CONSZ val; if (p->n_op != ICON && p->n_op != FCON) /* only constants */ return 0; if (p->n_op == ICON && p->n_sp != NULL) { /* no addresses */ if (t == BOOL) { glval(p) = 1, p->n_type = BOOL, p->n_sp = NULL; return 1; } return 0; } if ((p->n_type & TMASK) || (t & TMASK)) /* no cast of pointers */ return 0; //printf("concast till %d\n", t); //fwalk(p, eprint, 0); #define TYPMSK(y) ((((1LL << (y-1))-1) << 1) | 1) if (p->n_op == ICON) { val = glval(p); if (t == BOOL) { if (val) glval(p) = 1; } else if (t <= ULONGLONG) { glval(p) = val & TYPMSK(sztable[t]); if (!ISUNSIGNED(t)) { if (val & (1LL << (sztable[t]-1))) glval(p) |= ~TYPMSK(sztable[t]); } } else if (t <= LDOUBLE) { p->n_op = FCON; FLOAT_INT2FP(D(p->n_dcon), val, p->n_type); } } else { /* p->n_op == FCON */ if (t == BOOL) { p->n_op = ICON; glval(p) = FLOAT_NE(D(p->n_dcon),FLOAT_ZERO); p->n_sp = NULL; } else if (t <= ULONGLONG) { p->n_op = ICON; glval(p) = ISUNSIGNED(t) ? /* XXX FIXME */ ((U_CONSZ)D(p->n_dcon)->fp) : D(p->n_dcon)->fp; p->n_sp = NULL; } else { D(p->n_dcon)->fp = t == FLOAT ? (float)D(p->n_dcon)->fp : t == DOUBLE ? (double)D(p->n_dcon)->fp : D(p->n_dcon)->fp; } } p->n_type = t; //fwalk(p, eprint, 0); return 1; } /* * Do a conditional branch. */ void cbranch(NODE *p, NODE *q) { p = buildtree(CBRANCH, p, q); if (p->n_left->n_op == ICON) { if (glval(p->n_left) != 0) { branch((int)glval(q)); /* branch always */ reached = 0; } tfree(p); tfree(q); return; } ecomp(p); } NODE * strargs(register NODE *p) { /* rewrite structure flavored arguments */ if( p->n_op == CM ){ p->n_left = strargs( p->n_left ); p->n_right = strargs( p->n_right ); return( p ); } if( p->n_type == STRTY || p->n_type == UNIONTY ){ p = block(STARG, p, NIL, p->n_type, p->n_df, p->n_ap); p->n_left = buildtree( ADDROF, p->n_left, NIL ); p = clocal(p); } return( p ); } /* * apply the op o to the lval part of p; if binary, rhs is val */ int conval(NODE *p, int o, NODE *q) { TWORD tl = p->n_type, tr = q->n_type, td; int i, u; CONSZ val; U_CONSZ v1, v2; val = glval(q); /* make both sides same type */ if (tl < BTMASK && tr < BTMASK) { td = tl > tr ? tl : tr; if (td < INT) td = INT; u = ISUNSIGNED(td); if (tl != td) p = makety(p, td, 0, 0, 0); if (tr != td) q = makety(q, td, 0, 0, 0); } else u = ISUNSIGNED(tl) || ISUNSIGNED(tr); if( u && (o==LE||o==LT||o==GE||o==GT)) o += (UGE-GE); if (p->n_sp != NULL && q->n_sp != NULL) return(0); if (q->n_sp != NULL && o != PLUS) return(0); if (p->n_sp != NULL && o != PLUS && o != MINUS) return(0); v1 = glval(p); v2 = glval(q); if (v2 == 0 && (cdope(o) & DIVFLG)) return 0; /* leave division by zero to runtime */ switch( o ){ case PLUS: glval(p) += val; if (p->n_sp == NULL) { p->n_right = q->n_right; p->n_type = q->n_type; } break; case MINUS: glval(p) -= val; break; case MUL: glval(p) *= val; break; case DIV: if (u) { v1 /= v2; glval(p) = v1; } else glval(p) /= val; break; case MOD: if (u) { v1 %= v2; glval(p) = v1; } else glval(p) %= val; break; case AND: glval(p) &= val; break; case OR: glval(p) |= val; break; case ER: glval(p) ^= val; break; case LS: i = (int)val; glval(p) = glval(p) << i; break; case RS: i = (int)val; if (u) { v1 = v1 >> i; glval(p) = v1; } else glval(p) = glval(p) >> i; break; case UMINUS: glval(p) = - glval(p); break; case COMPL: glval(p) = ~glval(p); break; case NOT: glval(p) = !glval(p); break; case LT: glval(p) = glval(p) < val; break; case LE: glval(p) = glval(p) <= val; break; case GT: glval(p) = glval(p) > val; break; case GE: glval(p) = glval(p) >= val; break; case ULT: glval(p) = v1 < v2; break; case ULE: glval(p) = v1 <= v2; break; case UGT: glval(p) = v1 > v2; break; case UGE: glval(p) = v1 >= v2; break; case EQ: glval(p) = glval(p) == val; break; case NE: glval(p) = glval(p) != val; break; case ANDAND: glval(p) = glval(p) && val; break; case OROR: glval(p) = glval(p) || val; break; default: return(0); } /* Do the best in making everything type correct after calc */ if (p->n_sp == NULL && q->n_sp == NULL) glval(p) = valcast(glval(p), p->n_type); return(1); } /* * Ensure that v matches the type t; sign- or zero-extended * as suitable to CONSZ. * Only to be used for integer types. */ CONSZ valcast(CONSZ v, TWORD t) { CONSZ r; int sz; if (t < CHAR || t > ULONGLONG) return v; /* cannot cast */ if (t >= LONGLONG) return v; /* already largest */ #define M(x) ((((1ULL << ((x)-1)) - 1) << 1) + 1) #define NOTM(x) (~M(x)) #define SBIT(x) (1ULL << ((x)-1)) sz = (int)tsize(t, NULL, NULL); r = v & M(sz); if (!ISUNSIGNED(t) && (SBIT(sz) & r)) r = r | NOTM(sz); return r; } /* * Checks p for the existence of a pun. This is called when the op of p * is ASSIGN, RETURN, CAST, COLON, or relational. * One case is when enumerations are used: this applies only to lint. * In the other case, one operand is a pointer, the other integer type * we check that this integer is in fact a constant zero... * in the case of ASSIGN, any assignment of pointer to integer is illegal * this falls out, because the LHS is never 0. * XXX - check for COMOPs in assignment RHS? */ void chkpun(NODE *p) { union dimfun *d1, *d2; NODE *q; int t1, t2; t1 = p->n_left->n_type; t2 = p->n_right->n_type; switch (p->n_op) { case RETURN: /* return of void allowed but nothing else */ if (t1 == VOID && t2 == VOID) return; if (t1 == VOID) { werror("returning value from void function"); return; } if (t2 == VOID) { uerror("using void value"); return; } break; case COLON: if (t1 == VOID && t2 == VOID) return; break; default: if ((t1 == VOID && t2 != VOID) || (t1 != VOID && t2 == VOID)) { uerror("value of void expression used"); return; } break; } /* allow void pointer assignments in any direction */ if (BTYPE(t1) == VOID && (t2 & TMASK)) return; if (BTYPE(t2) == VOID && (t1 & TMASK)) return; /* boolean have special syntax */ if (t1 == BOOL) { if (!ISARY(t2)) /* Anything scalar */ return; } if (ISPTR(t1) || ISARY(t1)) q = p->n_right; else q = p->n_left; if (!ISPTR(q->n_type) && !ISARY(q->n_type)) { if (q->n_op != ICON || glval(q) != 0) werror("illegal combination of pointer and integer"); } else { if (t1 == t2) { if (ISSOU(BTYPE(t1)) && !suemeq(p->n_left->n_ap, p->n_right->n_ap)) werror("illegal structure pointer combination"); return; } d1 = p->n_left->n_df; d2 = p->n_right->n_df; for (;;) { if (ISARY(t1) || ISPTR(t1)) { if (!ISARY(t2) && !ISPTR(t2)) break; if (ISARY(t1) && ISARY(t2) && d1->ddim != d2->ddim) { werror("illegal array size combination"); return; } if (ISARY(t1)) ++d1; if (ISARY(t2)) ++d2; } else if (ISFTN(t1)) { if (chkftn(d1->dfun, d2->dfun)) { werror("illegal function " "pointer combination"); return; } ++d1; ++d2; } else break; t1 = DECREF(t1); t2 = DECREF(t2); } if (DEUNSIGN(t1) != DEUNSIGN(t2)) warner(Wpointer_sign); } } static NODE * offplus(NODE *p, int off, TWORD t, TWORD q, union dimfun *d, struct attr *ap) { if (off != 0) { p = block(PLUS, p, offcon(off, t, d, ap), t, d, ap); p->n_qual = q; p = optim(p); } return buildtree(UMUL, p, NIL); } NODE * stref(NODE *p) { NODE *r; struct attr *ap, *xap, *yap; union dimfun *d; TWORD t, q; int dsc; OFFSZ off; struct symtab *s; /* make p->x */ /* this is also used to reference automatic variables */ s = p->n_right->n_sp; nfree(p->n_right); r = nfree(p); #ifdef GCC_COMPAT xap = attr_find(r->n_ap, GCC_ATYP_PACKED); #endif p = pconvert(r); /* make p look like ptr to x */ if (!ISPTR(p->n_type)) p->n_type = PTR+UNIONTY; t = INCREF(s->stype); q = INCQAL(s->squal); d = s->sdf; ap = s->sap; #ifdef GCC_COMPAT if ((yap = attr_find(ap, GCC_ATYP_PACKED)) != NULL) xap = yap; else if (xap != NULL) ap = attr_add(ap, attr_dup(xap)); #else xap = yap = NULL; #endif /* xap set if packed struct */ p = makety(p, t, q, d, ap); if (ISFTN(s->stype)) { /* direct class call */ p = block(NMLIST, p, nametree(s), INT, 0, 0); return p; } /* compute the offset to be added */ off = s->soffset; dsc = s->sclass; if (dsc & FIELD) { TWORD ftyp = s->stype; int fal = talign(ftyp, ap); off = (off/fal)*fal; p = offplus(p, off, t, q, d, ap); p = block(FLD, p, NIL, ftyp, 0, ap); p->n_qual = q; p->n_rval = PKFIELD(dsc&FLDSIZ, s->soffset%fal); } else { p = offplus(p, off, t, q, d, ap); #ifndef CAN_UNALIGN /* if target cannot handle unaligned addresses, fix here */ #endif } p = clocal(p); return p; } int notlval(register NODE *p) { /* return 0 if p an lvalue, 1 otherwise */ again: switch( p->n_op ){ case FLD: p = p->n_left; goto again; case NAME: case OREG: case UMUL: if( ISARY(p->n_type) || ISFTN(p->n_type) ) return(1); case TEMP: case REG: return(0); default: return(1); } } /* make a constant node with value i */ NODE * bcon(int i) { return xbcon(i, NULL, INT); } NODE * xbcon(CONSZ val, struct symtab *sp, TWORD type) { NODE *p; p = block(ICON, NIL, NIL, type, 0, 0); glval(p) = val; p->n_sp = sp; return clocal(p); } NODE * bpsize(NODE *p) { int isdyn(struct symtab *sp); struct symtab s; NODE *q, *r; TWORD t; int sz; s.stype = DECREF(p->n_type); s.sdf = p->n_df; if (isdyn(&s)) { q = bcon(1); for (t = s.stype; t > BTMASK; t = DECREF(t)) { if (ISPTR(t)) return buildtree(MUL, q, bcon(SZPOINT(t))); if (ISARY(t)) { if (s.sdf->ddim < 0) r = tempnode(-s.sdf->ddim, INT, 0, 0); else r = bcon(s.sdf->ddim/SZCHAR); q = buildtree(MUL, q, r); s.sdf++; } } sz = (int)tsize(p->n_type, p->n_df, p->n_ap); p = buildtree(MUL, q, bcon(sz/SZCHAR)); } else p = (offcon(psize(p), p->n_type, p->n_df, p->n_ap)); return p; } /* * p is a node of type pointer; psize returns the * size of the thing pointed to */ OFFSZ psize(NODE *p) { if (!ISPTR(p->n_type)) { uerror("pointer required"); return(SZINT); } /* note: no pointers to fields */ return(tsize(DECREF(p->n_type), p->n_df, p->n_ap)); } /* * convert an operand of p * f is either CVTL or CVTR * operand has type int, and is converted by the size of the other side * convert is called when an integer is to be added to a pointer, for * example in arrays or structures. */ NODE * convert(NODE *p, int f) { union dimfun *df; TWORD ty, ty2; NODE *q, *r, *s, *rv; if (f == CVTL) { q = p->n_left; s = p->n_right; } else { q = p->n_right; s = p->n_left; } ty2 = ty = DECREF(s->n_type); while (ISARY(ty)) ty = DECREF(ty); r = offcon(tsize(ty, s->n_df, s->n_ap), s->n_type, s->n_df, s->n_ap); ty = ty2; rv = bcon(1); df = s->n_df; while (ISARY(ty)) { rv = buildtree(MUL, rv, df->ddim >= 0 ? bcon(df->ddim) : tempnode(-df->ddim, INT, 0, 0)); df++; ty = DECREF(ty); } rv = clocal(MBLOCK(rv, r, INT, 0, 0)); rv = optim(rv); r = MBLOCK(q, rv, INT, 0, 0); r = clocal(r); /* * Indexing is only allowed with integer arguments, so insert * SCONV here if arg is not an integer. * XXX - complain? */ if (r->n_type != INTPTR) r = clocal(makety(r, INTPTR, 0, 0, 0)); if (f == CVTL) p->n_left = r; else p->n_right = r; return(p); } NODE * pconvert(register NODE *p) { /* if p should be changed into a pointer, do so */ if( ISARY( p->n_type) ){ p->n_type = DECREF( p->n_type ); ++p->n_df; return( buildtree( ADDROF, p, NIL ) ); } if( ISFTN( p->n_type) ) return( buildtree( ADDROF, p, NIL ) ); return( p ); } NODE * oconvert(register NODE *p) { /* convert the result itself: used for pointer and unsigned */ switch(p->n_op) { case LE: case LT: case GE: case GT: if(ISUNSIGNED(p->n_left->n_type) || ISUNSIGNED(p->n_right->n_type) || ISPTR(p->n_left->n_type) || ISPTR(p->n_right->n_type)) p->n_op += (ULE-LE); /* FALLTHROUGH */ case EQ: case NE: return( p ); case MINUS: p->n_type = INTPTR; p->n_ap = NULL; return(clocal(VBLOCK(p, bpsize(p->n_left), INT, 0, 0))); } cerror( "illegal oconvert: %d", p->n_op ); return(p); } /* * makes the operands of p agree; they are * either pointers or integers, by this time * with MINUS, the sizes must be the same * with COLON, the types must be the same */ NODE * ptmatch(NODE *p) { struct attr *ap, *ap2; union dimfun *d, *d2; TWORD t1, t2, t, q1, q2, q; int o; o = p->n_op; t = t1 = p->n_left->n_type; q = q1 = p->n_left->n_qual; t2 = p->n_right->n_type; q2 = p->n_right->n_qual; d = p->n_left->n_df; d2 = p->n_right->n_df; ap = p->n_left->n_ap; ap2 = p->n_right->n_ap; switch( o ){ case ASSIGN: case RETURN: { break; } case CAST: if (t == VOID) { /* just paint over */ p->n_right = block(SCONV, p->n_right, NIL, VOID, 0, 0); return p; } break; case MINUS: { int isdyn(struct symtab *sp); struct symtab s1, s2; s1.stype = DECREF(t); s1.sdf = d; s2.stype = DECREF(t2); s2.sdf = d2; if (isdyn(&s1) || isdyn(&s2)) ; /* We don't know */ else if (psize(p->n_left) != psize(p->n_right)) uerror("illegal pointer subtraction"); break; } case COLON: if (t1 != t2) { /* * Check for void pointer types. They are allowed * to cast to/from any pointers. */ if (ISPTR(t1) && ISPTR(t2) && (BTYPE(t1) == VOID || BTYPE(t2) == VOID)) break; uerror("illegal types in :"); } break; default: /* must work harder: relationals or comparisons */ if( !ISPTR(t1) ){ t = t2; q = q2; d = d2; ap = ap2; break; } if( !ISPTR(t2) ){ break; } /* both are pointers */ if( talign(t2,ap2) < talign(t,ap) ){ t = t2; q = q2; ap = ap2; } break; } p->n_left = makety( p->n_left, t, q, d, ap ); p->n_right = makety( p->n_right, t, q, d, ap ); if( o!=MINUS && !clogop(o) ){ p->n_type = t; p->n_qual = q; p->n_df = d; p->n_ap = ap; } return(clocal(p)); } /* * Satisfy the types of various arithmetic binary ops. * * rules are: * if assignment, type of LHS * if any doubles, make double * else if any float make float * else if any longlongs, make long long * else if any longs, make long * else etcetc. * * If the op with the highest rank is unsigned, this is the resulting type. * See: 6.3.1.1 rank order equal of signed and unsigned types * 6.3.1.8 Usual arithmetic conversions */ static NODE * tymatch(NODE *p) { TWORD tl, tr, t; NODE *l, *r; int o; o = p->n_op; r = p->n_right; l = p->n_left; tl = l->n_type; tr = r->n_type; if (tl == BOOL) tl = BOOL_TYPE; if (tr == BOOL) tr = BOOL_TYPE; if (casgop(o)) { if (r->n_op != ICON && tl < FLOAT && tr < FLOAT && DEUNSIGN(tl) < DEUNSIGN(tr) && o != CAST) warner(Wtruncate, tnames[tr], tnames[tl]); p->n_right = makety(p->n_right, l->n_type, 0, 0, 0); t = p->n_type = l->n_type; p->n_ap = l->n_ap; } else { t = tl > tr ? tl : tr; /* MAX */ /* This depends on ctype() called early */ if (o != COLON && t < INT) t = INT; if (tl != t) p->n_left = makety(p->n_left, t, 0, 0, 0); if (tr != t) p->n_right = makety(p->n_right, t, 0, 0, 0); if (o == COLON && l->n_type == BOOL && r->n_type == BOOL) t = p->n_type = BOOL; else if (!clogop(o)) p->n_type = t; } #ifdef PCC_DEBUG if (tdebug) { printf("tymatch(%p): ", p); tprint(tl, 0); printf(" %s ", copst(o)); tprint(tr, 0); printf(" => "); tprint(t, 0); printf("\n"); fwalk(p, eprint, 0); } #endif return p; } /* * make p into type t by inserting a conversion */ NODE * makety(NODE *p, TWORD t, TWORD q, union dimfun *d, struct attr *ap) { if (t == p->n_type) { p->n_df = d; p->n_ap = ap; p->n_qual = q; return(p); } if (ISITY(t) || ISCTY(t) || ISITY(p->n_type) || ISCTY(p->n_type)) cerror("makety"); if (concast(p, t)) return clocal(p); p = block(t & TMASK ? PCONV : SCONV, p, NIL, t, d, ap); p->n_qual = q; return clocal(p); } NODE * block(int o, NODE *l, NODE *r, TWORD t, union dimfun *d, struct attr *ap) { register NODE *p; p = talloc(); p->n_rval = 0; p->n_op = o; glval(p) = 0; /* Protect against large lval */ p->n_left = l; p->n_right = r; p->n_type = t; p->n_qual = 0; p->n_df = d; p->n_ap = ap; #if !defined(MULTIPASS) /* p->n_reg = */p->n_su = 0; p->n_regw = 0; #endif return(p); } /* * Return the constant value from an ICON. */ CONSZ icons(NODE *p) { /* if p is an integer constant, return its value */ CONSZ val; if (p->n_op != ICON || p->n_sp != NULL) { uerror( "constant expected"); val = 1; } else val = glval(p); tfree(p); return(val); } /* * the intent of this table is to examine the * operators, and to check them for * correctness. * * The table is searched for the op and the * modified type (where this is one of the * types INT (includes char and short), LONG, * DOUBLE (includes FLOAT), and POINTER * * The default action is to make the node type integer * * The actions taken include: * PUN check for puns * CVTL convert the left operand * CVTR convert the right operand * TYPL the type is determined by the left operand * TYPR the type is determined by the right operand * TYMATCH force type of left and right to match,by inserting conversions * PTMATCH like TYMATCH, but for pointers * LVAL left operand must be lval * CVTO convert the op * NCVT do not convert the operands * OTHER handled by code * NCVTR convert the left operand, not the right... * */ # define MINT 01 /* integer */ # define MDBI 02 /* integer or double */ # define MSTR 04 /* structure */ # define MPTR 010 /* pointer */ # define MPTI 020 /* pointer or integer */ int opact(NODE *p) { int mt12, mt1, mt2, o; mt1 = mt2 = mt12 = 0; switch (coptype(o = p->n_op)) { case BITYPE: mt12=mt2 = moditype(p->n_right->n_type); /* FALLTHROUGH */ case UTYPE: mt12 &= (mt1 = moditype(p->n_left->n_type)); break; } switch( o ){ case NAME : case ICON : case FCON : case CALL : case UCALL: case UMUL: { return( OTHER ); } case UMINUS: if( mt1 & MDBI ) return( TYPL+PROML ); break; case COMPL: if( mt1 & MINT ) return( TYPL+PROML ); break; case ADDROF: return( NCVT+OTHER ); case NOT: return( PROML ); /* case INIT: */ case CM: case CBRANCH: case ANDAND: case OROR: return( 0 ); case MUL: case DIV: if( mt12 & MDBI ) return( TYMATCH ); break; case MOD: case AND: case OR: case ER: if( mt12 & MINT ) return( TYMATCH ); break; case LS: case RS: if( mt12 & MINT ) return( TYPL+OTHER ); break; case EQ: case NE: case LT: case LE: case GT: case GE: if( mt12 & MDBI ) return( TYMATCH+CVTO ); else if( mt12 & MPTR ) return( PTMATCH+PUN+CVTO ); else if( mt12 & MPTI ) return( PTMATCH+PUN ); else break; case QUEST: return( TYPR+OTHER ); case COMOP: return( TYPR ); case STREF: return( NCVTR+OTHER ); case FORCE: return( TYPL ); case COLON: if( mt12 & MDBI ) return( TYMATCH ); else if( mt12 & MPTR ) return( TYPL+PTMATCH+PUN ); else if( (mt1&MINT) && (mt2&MPTR) ) return( TYPR+PUN ); else if( (mt1&MPTR) && (mt2&MINT) ) return( TYPL+PUN ); else if( mt12 & MSTR ) return( NCVT+TYPL+OTHER ); break; case ASSIGN: case RETURN: if( mt12 & MSTR ) return( LVAL+NCVT+TYPL+OTHER ); case CAST: if( mt12 & MDBI ) return( TYPL+LVAL+TYMATCH ); else if( mt1 & MPTR) return( LVAL+PTMATCH+PUN ); else if( mt12 & MPTI ) return( TYPL+LVAL+TYMATCH+PUN ); break; case LSEQ: case RSEQ: if( mt12 & MINT ) return( TYPL+LVAL+OTHER ); break; case MULEQ: case DIVEQ: if( mt12 & MDBI ) return( LVAL+TYMATCH ); break; case MODEQ: case ANDEQ: case OREQ: case EREQ: if (mt12 & MINT) return(LVAL+TYMATCH); break; case PLUSEQ: case MINUSEQ: case INCR: case DECR: if (mt12 & MDBI) return(TYMATCH+LVAL); else if ((mt1&MPTR) && (mt2&MINT)) return(TYPL+LVAL+CVTR); break; case MINUS: if (mt12 & MPTR) return(CVTO+PTMATCH+PUN); if (mt2 & MPTR) break; /* FALLTHROUGH */ case PLUS: if (mt12 & MDBI) return(TYMATCH); else if ((mt1&MPTR) && (mt2&MINT)) return(TYPL+CVTR); else if ((mt1&MINT) && (mt2&MPTR)) return(TYPR+CVTL); } uerror("operands of %s have incompatible types", copst(o)); return(NCVT); } int moditype(TWORD ty) { switch (ty) { case STRTY: case UNIONTY: return( MSTR ); case BOOL: case CHAR: case SHORT: case UCHAR: case USHORT: case UNSIGNED: case ULONG: case ULONGLONG: case INT: case LONG: case LONGLONG: return( MINT|MDBI|MPTI ); case FLOAT: case DOUBLE: case LDOUBLE: #ifndef NO_COMPLEX case FCOMPLEX: case COMPLEX: case LCOMPLEX: case FIMAG: case IMAG: case LIMAG: #endif return( MDBI ); default: return( MPTR|MPTI ); } } int tvaloff = MAXREGS+NPERMREG > 100 ? MAXREGS+NPERMREG + 100 : 100; /* * Returns a TEMP node with temp number nr. * If nr == 0, return a node with a new number. */ NODE * tempnode(int nr, TWORD type, union dimfun *df, struct attr *ap) { NODE *r; if (tvaloff == -NOOFFSET) tvaloff++; /* Skip this for array indexing */ r = block(TEMP, NIL, NIL, type, df, ap); regno(r) = nr ? nr : tvaloff; tvaloff += szty(type); return r; } /* * Do sizeof on p. */ NODE * doszof(NODE *p) { extern NODE *arrstk[10]; extern int arrstkp; union dimfun *df; TWORD ty; NODE *rv, *q; int astkp; if (p->n_op == FLD) uerror("can't apply sizeof to bit-field"); /* * Arrays may be dynamic, may need to make computations. */ rv = bcon(1); df = p->n_df; ty = p->n_type; astkp = 0; while (ISARY(ty)) { if (df->ddim == NOOFFSET) uerror("sizeof of incomplete type"); if (df->ddim < 0) { if (arrstkp) q = arrstk[astkp++]; else q = tempnode(-df->ddim, INT, 0, 0); } else q = bcon(df->ddim); rv = buildtree(MUL, rv, q); df++; ty = DECREF(ty); } rv = buildtree(MUL, rv, xbcon(tsize(ty, p->n_df, p->n_ap)/SZCHAR, NULL, INTPTR)); tfree(p); arrstkp = 0; /* XXX - may this fail? */ return rv; } #ifdef PCC_DEBUG void eprint(NODE *p, int down, int *a, int *b) { int ty; *a = *b = down+1; while( down > 1 ){ printf( "\t" ); down -= 2; } if( down ) printf( " " ); ty = coptype( p->n_op ); printf("%p) %s, ", p, copst(p->n_op)); if (p->n_op == XARG || p->n_op == XASM) printf("id '%s', ", p->n_name); if (ty == LTYPE) { printf(CONFMT, glval(p)); if (p->n_op == NAME || p->n_op == ICON) printf(", %p, ", p->n_sp); else printf(", %d, ", p->n_rval); } tprint(p->n_type, p->n_qual); printf( ", %p, ", p->n_df); #ifdef GCC_COMPAT dump_attr(p->n_ap); #endif } # endif /* * Emit everything that should be emitted on the left side * of a comma operator, and remove the operator. * Do not traverse through QUEST, ANDAND and OROR. * Enable this for all targets when stable enough. */ static void comops(NODE *p) { int o; NODE *q; while (p->n_op == COMOP) { /* XXX hack for GCC ({ }) ops */ if (p->n_left->n_op == GOTO) { int v = (int)glval(p->n_left->n_left); ecomp(p->n_left); plabel(v+1); } else ecomp(p->n_left); /* will recurse if more COMOPs */ q = p->n_right; *p = *q; nfree(q); } o = coptype(p->n_op); if (p->n_op == QUEST || p->n_op == ANDAND || p->n_op == OROR) o = UTYPE; if (o != LTYPE) comops(p->n_left); if (o == BITYPE) comops(p->n_right); } /* * Walk up through the tree from the leaves, * removing constant operators. */ static void logwalk(NODE *p) { int o = coptype(p->n_op); NODE *l, *r; l = p->n_left; r = p->n_right; switch (o) { case LTYPE: return; case BITYPE: logwalk(r); /* FALLTHROUGH */ case UTYPE: logwalk(l); } if (!clogop(p->n_op)) return; if (p->n_op == NOT && l->n_op == ICON) { glval(p) = glval(l) == 0; nfree(l); p->n_op = ICON; } if (l->n_op == ICON && r->n_op == ICON) { if (conval(l, p->n_op, r) == 0) { /* * people sometimes tend to do really odd compares, * like "if ("abc" == "def")" etc. * do it runtime instead. */ } else { glval(p) = glval(l); p->n_op = ICON; nfree(l); nfree(r); } } } /* * Removes redundant logical operators for branch conditions. */ static void fixbranch(NODE *p, int label) { logwalk(p); if (p->n_op == ICON) { if (glval(p) != 0) branch(label); nfree(p); } else { if (!clogop(p->n_op)) /* Always conditional */ p = buildtree(NE, p, bcon(0)); ecode(buildtree(CBRANCH, p, bcon(label))); } } /* * Write out logical expressions as branches. */ static void andorbr(NODE *p, int true, int false) { NODE *q; int o, lab; lab = -1; switch (o = p->n_op) { case EQ: case NE: /* * Remove redundant EQ/NE nodes. */ while (((o = p->n_left->n_op) == EQ || o == NE) && p->n_right->n_op == ICON) { o = p->n_op; q = p->n_left; if (glval(p->n_right) == 0) { nfree(p->n_right); *p = *q; nfree(q); if (o == EQ) p->n_op = negrel[p->n_op - EQ]; #if 0 p->n_op = NE; /* toggla */ #endif } else if (glval(p->n_right) == 1) { nfree(p->n_right); *p = *q; nfree(q); if (o == NE) p->n_op = negrel[p->n_op - EQ]; #if 0 p->n_op = EQ; /* toggla */ #endif } else break; /* XXX - should always be false */ } /* FALLTHROUGH */ case LE: case LT: case GE: case GT: calc: if (true < 0) { p->n_op = negrel[p->n_op - EQ]; true = false; false = -1; } rmcops(p->n_left); rmcops(p->n_right); fixbranch(p, true); if (false >= 0) branch(false); break; case ULE: case UGT: /* Convert to friendlier ops */ if (nncon(p->n_right) && glval(p->n_right) == 0) p->n_op = o == ULE ? EQ : NE; goto calc; case UGE: case ULT: /* Already true/false by definition */ if (nncon(p->n_right) && glval(p->n_right) == 0) { if (true < 0) { o = o == ULT ? UGE : ULT; true = false; } rmcops(p->n_left); ecode(p->n_left); rmcops(p->n_right); ecode(p->n_right); nfree(p); if (o == UGE) /* true */ branch(true); break; } goto calc; case ANDAND: lab = false<0 ? getlab() : false ; andorbr(p->n_left, -1, lab); comops(p->n_right); andorbr(p->n_right, true, false); if (false < 0) plabel( lab); nfree(p); break; case OROR: lab = true<0 ? getlab() : true; andorbr(p->n_left, lab, -1); comops(p->n_right); andorbr(p->n_right, true, false); if (true < 0) plabel( lab); nfree(p); break; case NOT: andorbr(p->n_left, false, true); nfree(p); break; default: rmcops(p); if (true >= 0) fixbranch(p, true); if (false >= 0) { if (true >= 0) branch(false); else fixbranch(buildtree(EQ, p, bcon(0)), false); } } } /* * Create a node for either TEMP or on-stack storage. */ NODE * cstknode(TWORD t, union dimfun *df, struct attr *ap) { struct symtab *sp; /* create a symtab entry suitable for this type */ sp = getsymtab("0hej", STEMP); sp->stype = t; sp->sdf = df; sp->sap = ap; sp->sclass = AUTO; sp->soffset = NOOFFSET; oalloc(sp, &autooff); return nametree(sp); } /* * Massage the output trees to remove C-specific nodes: * COMOPs are split into separate statements. * QUEST/COLON are rewritten to branches. * ANDAND/OROR/NOT are rewritten to branches for lazy-evaluation. * CBRANCH conditions are rewritten for lazy-evaluation. */ static void rmcops(NODE *p) { TWORD type; NODE *q, *r, *tval; int o, ty, lbl, lbl2; tval = NIL; o = p->n_op; ty = coptype(o); if (BTYPE(p->n_type) == ENUMTY) { /* fixup enum */ struct symtab *sp = strmemb(p->n_ap); MODTYPE(p->n_type, sp->stype); /* * XXX may fail if these are true: * - variable-sized enums * - non-byte-addressed targets. */ if (BTYPE(p->n_type) == ENUMTY && ISPTR(p->n_type)) MODTYPE(p->n_type, INT); /* INT ok? */ } switch (o) { case QUEST: /* * Create a branch node from ?: * || and && must be taken special care of. */ type = p->n_type; andorbr(p->n_left, -1, lbl = getlab()); /* Make ASSIGN node */ /* Only if type is not void */ q = p->n_right->n_left; comops(q); if (type != VOID) { tval = cstknode(q->n_type, q->n_df, q->n_ap); q = buildtree(ASSIGN, ccopy(tval), q); } rmcops(q); ecode(q); /* Done with assign */ branch(lbl2 = getlab()); plabel( lbl); q = p->n_right->n_right; comops(q); if (type != VOID) { q = buildtree(ASSIGN, ccopy(tval), q); } rmcops(q); ecode(q); /* Done with assign */ plabel( lbl2); nfree(p->n_right); if (p->n_type != VOID) { *p = *tval; nfree(tval); } else { p->n_op = ICON; glval(p) = 0; p->n_sp = NULL; } break; case ULE: case ULT: case UGE: case UGT: case EQ: case NE: case LE: case LT: case GE: case GT: case ANDAND: case OROR: case NOT: #ifdef SPECIAL_CCODES #error fix for private CCODES handling #else r = talloc(); *r = *p; andorbr(r, -1, lbl = getlab()); tval = cstknode(p->n_type, p->n_df, p->n_ap); ecode(buildtree(ASSIGN, ccopy(tval), bcon(1))); branch(lbl2 = getlab()); plabel( lbl); ecode(buildtree(ASSIGN, ccopy(tval), bcon(0))); plabel( lbl2); *p = *tval; nfree(tval); #endif break; case CBRANCH: andorbr(p->n_left, glval(p->n_right), -1); nfree(p->n_right); p->n_op = ICON; p->n_type = VOID; break; case COMOP: cerror("COMOP error"); default: if (ty == LTYPE) return; rmcops(p->n_left); if (ty == BITYPE) rmcops(p->n_right); } } /* * Return 1 if an assignment is found. */ static int has_se(NODE *p) { if (cdope(p->n_op) & ASGFLG) return 1; if (coptype(p->n_op) == LTYPE) return 0; if (has_se(p->n_left)) return 1; if (coptype(p->n_op) == BITYPE) return has_se(p->n_right); return 0; } /* * Find and convert asgop's to separate statements. * Be careful about side effects. * assign tells whether ASSIGN should be considered giving * side effects or not. */ static NODE * delasgop(NODE *p) { NODE *q, *r; int tval; if (p->n_op == INCR || p->n_op == DECR) { /* * Rewrite x++ to (x += 1) -1; and deal with it further down. * Pass2 will remove -1 if unnecessary. */ q = ccopy(p); tfree(p->n_left); q->n_op = (p->n_op==INCR)?PLUSEQ:MINUSEQ; p->n_op = (p->n_op==INCR)?MINUS:PLUS; p->n_left = delasgop(q); } else if ((cdope(p->n_op)&ASGOPFLG) && p->n_op != RETURN && p->n_op != CAST) { NODE *l = p->n_left; NODE *ll = l->n_left; if (has_se(l)) { q = tempnode(0, ll->n_type, ll->n_df, ll->n_ap); tval = regno(q); r = tempnode(tval, ll->n_type, ll->n_df,ll->n_ap); l->n_left = q; /* Now the left side of node p has no side effects. */ /* side effects on the right side must be obeyed */ p = delasgop(p); r = buildtree(ASSIGN, r, ll); r = delasgop(r); ecode(r); } else { #if 0 /* Cannot call buildtree() here, it would invoke double add shifts */ p->n_right = buildtree(UNASG p->n_op, ccopy(l), p->n_right); #else p->n_right = block(UNASG p->n_op, ccopy(l), p->n_right, p->n_type, p->n_df, p->n_ap); #endif p->n_op = ASSIGN; p->n_right = delasgop(p->n_right); p->n_right = clocal(p->n_right); } } else { if (coptype(p->n_op) == LTYPE) return p; p->n_left = delasgop(p->n_left); if (coptype(p->n_op) == BITYPE) p->n_right = delasgop(p->n_right); } return p; } #ifndef FIELDOPS /* avoid promotion to int */ #define TYPMOD(o, p, n, t) clocal(block(o, p, n, t, 0, 0)) #define TYPLS(p, n, t) TYPMOD(LS, p, n, t) #define TYPRS(p, n, t) TYPMOD(RS, p, n, t) #define TYPOR(p, q, t) TYPMOD(OR, p, q, t) #define TYPAND(p, q, t) TYPMOD(AND, p, q, t) /* * Read an unaligned bitfield from position pointed to by p starting at * off and size fsz and return a tree of type t with resulting data. */ static NODE * rdualfld(NODE *p, TWORD t, TWORD ct, int off, int fsz) { int t2f, inbits, tsz, ctsz; NODE *q, *r; ct = ENUNSIGN(ct); ctsz = (int)tsize(ct, 0, 0); /* traverse until first data byte */ for (t2f = 0; off > ctsz; t2f++, off -= ctsz) ; #ifdef UNALIGNED_ACCESS /* try to squeeze it into an int */ if (off + fsz > ctsz && off + fsz <= SZINT) { ct = UNSIGNED; ctsz = SZINT; } #endif p = makety(p, PTR|ct, 0, 0, 0); if (off + fsz <= ctsz) { /* only one operation needed */ q = buildtree(UMUL, buildtree(PLUS, p, bcon(t2f)), 0); if (!ISUNSIGNED(t)) { ct = DEUNSIGN(ct); q = makety(q, ct, 0, 0, 0); } q = TYPLS(q, bcon(ctsz-fsz-off), ct); q = TYPRS(q, bcon(ctsz-fsz), ct); q = makety(q, t, 0, 0, 0); } else { q = buildtree(UMUL, buildtree(PLUS, ccopy(p), bcon(t2f)), 0); q = makety(TYPRS(q, bcon(off), ct), t, 0, 0, 0); inbits = ctsz - off; t2f++; while (fsz > inbits) { r = buildtree(UMUL, buildtree(PLUS, ccopy(p), bcon(t2f)), 0); r = makety(r, t, 0, 0, 0); r = TYPLS(r, bcon(inbits), t); q = TYPOR(q, r, t); inbits += ctsz; t2f++; } /* sign/zero extend XXX - RS must sign extend */ tsz = (int)tsize(t, 0, 0); if (!ISUNSIGNED(t)) { t = DEUNSIGN(t); q = makety(q, t, 0, 0, 0); } q = TYPLS(q, bcon(tsz-fsz), t); q = TYPRS(q, bcon(tsz-fsz), t); tfree(p); } return q; } /* * Write val to a (unaligned) bitfield with length fsz positioned off bits * from d. Bitfield type is t, and type to use when writing is ct. * neither f nor d should have any side effects if copied. * Multiples of ct are supposed to be written without problems. * Both val and d are free'd after use. */ static NODE * wrualfld(NODE *val, NODE *d, TWORD t, TWORD ct, int off, int fsz) { NODE *p, *q, *r, *rn, *s; int ctsz, t2f, inbits; ctsz = (int)tsize(ct, 0, 0); ct = ENUNSIGN(ct); d = makety(d, PTR|ct, 0, 0, 0); for (t2f = 0; off > ctsz; t2f++, off -= ctsz) ; if (off + fsz <= ctsz) { r = tempnode(0, ct, 0, 0); /* only one operation needed */ d = buildtree(UMUL, buildtree(PLUS, d, bcon(t2f)), 0); p = ccopy(d); p = TYPAND(p, xbcon(~(SZMASK(fsz) << off), 0, ct), ct); val = makety(val, ct, 0, 0, 0); q = TYPAND(val, xbcon(SZMASK(fsz), 0, ct), ct); q = buildtree(ASSIGN, ccopy(r), q); q = TYPLS(q, bcon(off), ct); p = TYPOR(p, q, ct); p = makety(p, t, 0, 0, 0); rn = buildtree(ASSIGN, d, p); rn = buildtree(COMOP, rn, makety(r, t, 0, 0, 0)); } else { s = makety(ccopy(val), t, 0, 0, 0); s = TYPAND(s, xbcon(SZMASK(fsz), 0, t), t); r = buildtree(UMUL, buildtree(PLUS, ccopy(d), bcon(t2f)), 0); p = ccopy(r); p = TYPAND(p, xbcon(SZMASK(off), 0, ct), ct); q = ccopy(val); q = TYPLS(q, bcon(off), t); q = makety(q, ct, 0, 0, 0); p = TYPOR(p, q, ct); rn = buildtree(ASSIGN, r, p); inbits = ctsz - off; t2f++; while (fsz > inbits+ctsz) { r = buildtree(UMUL, buildtree(PLUS, ccopy(d), bcon(t2f)), 0); q = ccopy(val); q = TYPRS(q, bcon(inbits), t); q = makety(q, ct, 0, 0, 0); rn = buildtree(COMOP, rn, buildtree(ASSIGN, r, q)); t2f++; inbits += ctsz; } r = buildtree(UMUL, buildtree(PLUS, d, bcon(t2f)), 0); p = ccopy(r); p = TYPAND(p, makety(xbcon(~SZMASK(fsz-inbits), 0, ct), ct, 0, 0, 0), ct); q = TYPRS(val, bcon(inbits), t); q = TYPAND(q, xbcon(SZMASK(fsz-inbits), 0, t), t); q = makety(q, ct, 0, 0, 0); p = TYPOR(p, q, ct); rn = buildtree(COMOP, rn, buildtree(ASSIGN, r, p)); rn = buildtree(COMOP, rn, s); } return rn; } /* * Rewrite bitfield operations to shifts. */ static NODE * rmfldops(NODE *p) { TWORD t, ct; NODE *q, *r, *t1, *t2, *bt, *t3, *t4; int fsz, foff; if (p->n_op == FLD) { /* Rewrite a field read operation */ fsz = UPKFSZ(p->n_rval); foff = UPKFOFF(p->n_rval); q = buildtree(ADDROF, p->n_left, NIL); ct = t = p->n_type; #ifdef GCC_COMPAT if (attr_find(p->n_ap, GCC_ATYP_PACKED) && coptype(q->n_op) != LTYPE) { t1 = tempnode(0, q->n_type, 0, 0); bt = buildtree(ASSIGN, ccopy(t1), q); q = t1; #ifndef UNALIGNED_ACCESS ct = UCHAR; #endif } else #endif bt = bcon(0); q = rdualfld(q, t, ct, foff, fsz); p->n_left = bt; p->n_right = q; p->n_op = COMOP; } else if (((cdope(p->n_op)&ASGOPFLG) || p->n_op == ASSIGN || p->n_op == INCR || p->n_op == DECR) && p->n_left->n_op == FLD) { /* * Rewrite a field write operation * More difficult than a read op since we must care * about side effects. */ q = p->n_left; fsz = UPKFSZ(q->n_rval); foff = UPKFOFF(q->n_rval); t = q->n_left->n_type; #if TARGET_ENDIAN == TARGET_BE foff = (int)tsize(t, 0, 0) - fsz - foff; #endif bt = NULL; if (p->n_right->n_op != ICON && p->n_right->n_op != NAME) { t2 = tempnode(0, p->n_right->n_type, 0, 0); bt = buildtree(ASSIGN, ccopy(t2), p->n_right); } else t2 = p->n_right; ct = t; #ifdef GCC_COMPAT #ifndef UNALIGNED_ACCESS if (attr_find(q->n_ap, GCC_ATYP_PACKED)) ct = UCHAR; #endif #endif /* t2 is what we have to write (RHS of ASSIGN) */ /* bt is (eventually) something that must be written */ if (q->n_left->n_op == UMUL) { /* LHS of assignment may have side effects */ q = q->n_left; t1 = tempnode(0, q->n_left->n_type, 0, 0); r = buildtree(ASSIGN, ccopy(t1), q->n_left); bt = bt ? block(COMOP, bt, r, INT, 0, 0) : r; q->n_left = t1; } t1 = buildtree(ADDROF, p->n_left->n_left, 0); /* t1 is lval where to write (and read) */ if (p->n_op == ASSIGN) { q = wrualfld(t2, t1, t, ct, foff, fsz); if (bt) q = block(COMOP, bt, q, t, 0, 0); nfree(p->n_left); p->n_left = bcon(0); p->n_right = q; p->n_op = COMOP; } else if ((cdope(p->n_op)&ASGOPFLG)) { /* And here is the asgop-specific code */ t3 = tempnode(0, t, 0, 0); q = rdualfld(ccopy(t1), t, ct, foff, fsz); q = buildtree(UNASG p->n_op, q, t2); q = buildtree(ASSIGN, ccopy(t3), q); r = wrualfld(ccopy(t3), t1, t, ct, foff, fsz); q = buildtree(COMOP, q, r); q = buildtree(COMOP, q, t3); nfree(p->n_left); p->n_left = bt ? bt : bcon(0); p->n_right = q; p->n_op = COMOP; } else { t3 = tempnode(0, t, 0, 0); t4 = tempnode(0, t, 0, 0); q = rdualfld(ccopy(t1), t, ct, foff, fsz); q = buildtree(ASSIGN, ccopy(t3), q); r = buildtree(p->n_op==INCR?PLUS:MINUS, ccopy(t3), t2); r = buildtree(ASSIGN, ccopy(t4), r); q = buildtree(COMOP, q, r); r = wrualfld(t4, t1, t, ct, foff, fsz); q = buildtree(COMOP, q, r); if (bt) q = block(COMOP, bt, q, t, 0, 0); nfree(p->n_left); p->n_left = q; p->n_right = t3; p->n_op = COMOP; } } if (coptype(p->n_op) != LTYPE) p->n_left = rmfldops(p->n_left); if (coptype(p->n_op) == BITYPE) p->n_right = rmfldops(p->n_right); return p; } #endif void ecomp(NODE *p) { #ifdef PCC_DEBUG if (edebug) fwalk(p, eprint, 0); #endif if (!reached) { warner(Wunreachable_code); reached = 1; } p = optim(p); #ifndef FIELDOPS p = rmfldops(p); #endif comops(p); rmcops(p); p = delasgop(p); if (p->n_op == ICON && p->n_type == VOID) tfree(p); else ecode(p); } #if defined(MULTIPASS) void p2tree(NODE *p) { struct symtab *q; int ty; myp2tree(p); /* local action can be taken here */ ty = coptype(p->n_op); printf("%d\t", p->n_op); if (ty == LTYPE) { printf(CONFMT, glval(p)); printf("\t"); } if (ty != BITYPE) { if (p->n_op == NAME || p->n_op == ICON) printf("0\t"); else printf("%d\t", p->n_rval); } printf("%o\t", p->n_type); /* handle special cases */ switch (p->n_op) { case NAME: case ICON: /* print external name */ if ((q = p->n_sp) != NULL) { if ((q->sclass == STATIC && q->slevel > 0)) { printf(LABFMT, q->soffset); } else printf("%s\n", q->soname ? q->soname : exname(q->sname)); } else printf("\n"); break; case STARG: case STASG: case STCALL: case USTCALL: /* print out size */ /* use lhs size, in order to avoid hassles * with the structure `.' operator */ /* note: p->left not a field... */ printf(CONFMT, (CONSZ)tsize(STRTY, p->n_left->n_df, p->n_left->n_ap)); printf("\t%d\t\n", talign(STRTY, p->n_left->n_ap)); break; case XARG: case XASM: break; default: printf( "\n" ); } if (ty != LTYPE) p2tree(p->n_left); if (ty == BITYPE) p2tree(p->n_right); } #else static char * sptostr(struct symtab *sp) { char *cp = inlalloc(32); int n = sp->soffset; if (n < 0) n = -n; snprintf(cp, 32, LABFMT, n); return cp; } void p2tree(NODE *p) { struct attr *oap, *ap; struct symtab *q; int ty; myp2tree(p); /* local action can be taken here */ /* Fix left imaginary types */ if (ISITY(BTYPE(p->n_type))) MODTYPE(p->n_type, p->n_type - (FIMAG-FLOAT)); /* cleanup attributes. * copy those that are supposed to go into pass2 */ oap = p->n_ap; p->n_ap = NULL; for (ap = oap; ap; ap = ap->next) if (ap->atype < ATTR_MI_MAX) p->n_ap = attr_add(p->n_ap, attr_dup(ap)); /* XXX store size of attr in itself */ ty = coptype(p->n_op); switch( p->n_op ){ case NAME: case ICON: if ((q = p->n_sp) != NULL) { if ((q->sclass == STATIC && q->slevel > 0) #ifdef GCC_COMPAT || q->sflags == SLBLNAME #endif ) { p->n_name = sptostr(q); } else { if ((p->n_name = q->soname) == NULL) p->n_name = addname(exname(q->sname)); } } else p->n_name = ""; break; case STASG: case STARG: case STCALL: case USTCALL: /* STASG used for stack array init */ if (p->n_op == STASG && ISARY(p->n_type)) { int size1 = (int)tsize(p->n_type, p->n_left->n_df, p->n_left->n_ap)/SZCHAR; ap->iarg(0) = (int)tsize(p->n_type, p->n_right->n_df, p->n_right->n_ap)/SZCHAR; if (size1 < ap->iarg(0)) ap->iarg(0) = size1; ap->iarg(1) = talign(p->n_type, p->n_left->n_ap)/SZCHAR; break; } /* set up size parameters */ ap->iarg(0) = (int)((tsize(STRTY, p->n_left->n_df, p->n_left->n_ap)+SZCHAR-1)/SZCHAR); ap->iarg(1) = talign(STRTY,p->n_left->n_ap)/SZCHAR; if (ap->iarg(1) == 0) ap->iarg(1) = 1; /* At least char for packed structs */ break; case XARG: case XASM: break; default: p->n_name = ""; } if( ty != LTYPE ) p2tree( p->n_left ); if( ty == BITYPE ) p2tree( p->n_right ); } #endif /* * Change void data types into char. */ static void delvoid(NODE *p, void *arg) { /* Convert "PTR undef" (void *) to "PTR uchar" */ if (BTYPE(p->n_type) == VOID) p->n_type = (p->n_type & ~BTMASK) | UCHAR; if (BTYPE(p->n_type) == BOOL) { if (p->n_op == SCONV && p->n_type == BOOL) { /* create a jump and a set */ NODE *r; int l, l2; r = tempnode(0, BOOL_TYPE, NULL, 0); cbranch(buildtree(EQ, p->n_left, bcon(0)), bcon(l = getlab())); *p = *r; ecode(buildtree(ASSIGN, tcopy(r), bcon(1))); branch(l2 = getlab()); plabel(l); ecode(buildtree(ASSIGN, r, bcon(0))); plabel(l2); } else p->n_type = (p->n_type & ~BTMASK) | BOOL_TYPE; } } /* * Change calls inside calls to separate statement. */ static NODE * deldcall(NODE *p, int split) { NODE *q, *r; int o = p->n_op; if (cdope(o) & CALLFLG) { if (split) { q = cstknode(p->n_type, p->n_df, p->n_ap); r = ccopy(q); q = block(ASSIGN, q, p, p->n_type, p->n_df, p->n_ap); ecode(q); return r; } split++; } if (coptype(o) == BITYPE) p->n_right = deldcall(p->n_right, split); if (coptype(o) != LTYPE) p->n_left = deldcall(p->n_left, split); return p; } #ifndef WORD_ADDRESSED static NODE * pprop(NODE *p, TWORD t, struct attr *ap) { int o = p->n_op; TWORD t2; #ifdef PCC_DEBUG if (p->n_op == TEMP && p->n_type != t && !(ISPTR(p->n_type) && ISPTR(t))) { cerror("TEMP type change: %x -> %x", p->n_type, t); } #endif p->n_type = t; p->n_ap = ap; switch (o) { case UMUL: t = INCREF(t); break; case ADDROF: t2 = p->n_left->n_type; if (p->n_left->n_op == TEMP) { /* Will be converted to memory in pass2 */ if (!ISPTR(t2) && DECREF(t) != t2) ; /* XXX cannot convert this */ else p->n_left->n_type = DECREF(t); return p; } if (ISPTR(t2) && !ISPTR(DECREF(t))) break; /* not quite correct */ t = DECREF(t); break; case PCONV: return p; case PLUSEQ: case PLUS: case INCR: case DECR: if (!ISPTR(p->n_left->n_type)) { if (!ISPTR(p->n_right->n_type)) cerror("no * in PLUS"); p->n_right = pprop(p->n_right, t, ap); } else p->n_left = pprop(p->n_left, t, ap); return p; case MINUSEQ: case MINUS: if (ISPTR(p->n_left->n_type)) { if (ISPTR(p->n_right->n_type)) break; /* change both */ p->n_left = pprop(p->n_left, t, ap); } else p->n_right = pprop(p->n_right, t, ap); return p; case CALL: case UCALL: case STCALL: /* may end up here if struct passed in regs */ case USTCALL: return p; case STASG: /* if struct is cast to pointer */ return p; case ASSIGN: break; default: if (coptype(o) == LTYPE) break; #ifdef PCC_DEBUG fwalk(p, eprint, 0); #endif cerror("pprop op error %d\n", o); } if (coptype(o) == BITYPE) p->n_right = pprop(p->n_right, t, ap); if (coptype(o) != LTYPE) p->n_left = pprop(p->n_left, t, ap); return p; } /* * Search for PCONV's that can be removed while still keeping * the type correctness. */ NODE * rmpconv(NODE *p) { struct symtab *sp; int o = p->n_op; int ot = coptype(o); NODE *q, *l; if (ot != LTYPE) p->n_left = rmpconv(p->n_left); if (ot == BITYPE) p->n_right = rmpconv(p->n_right); if (o != PCONV) return p; l = p->n_left; if (nncon(l) || (cdope(l->n_op) & CALLFLG)) ; /* Let any nonamed constant be cast to pointer directly */ else if (l->n_type >= INTPTR && l->n_op == ICON) { /* named constants only if >= pointer size */ /* create INTPTR type */ sp = l->n_sp; l->n_sp = NULL; concast(l, INTPTR); l->n_sp = sp; } else if (!ISPTR(l->n_type)) return p; q = pprop(p->n_left, p->n_type, p->n_ap); nfree(p); return q; } #endif void ecode(NODE *p) { /* walk the tree and write out the nodes.. */ if (nerrors) return; #ifdef GCC_COMPAT { NODE *q = p; if (q->n_op == UMUL) q = p->n_left; if (cdope(q->n_op)&CALLFLG && attr_find(q->n_ap, GCC_ATYP_WARN_UNUSED_RESULT)) werror("return value ignored"); } #endif #ifndef WORD_ADDRESSED p = rmpconv(p); #endif p = optim(p); p = delasgop(p); p = deldcall(p, 0); walkf(p, delvoid, 0); #ifdef PCC_DEBUG if (xdebug) { printf("Fulltree:\n"); fwalk(p, eprint, 0); } #endif p2tree(p); #if !defined(MULTIPASS) send_passt(IP_NODE, p); #endif } /* * Send something further on to the next pass. */ void send_passt(int type, ...) { struct interpass *ip; struct interpass_prolog *ipp; extern int crslab; va_list ap; int sz; va_start(ap, type); if (cftnsp == NULL && type != IP_ASM) { #ifdef notyet cerror("no function"); #endif if (type == IP_NODE) tfree(va_arg(ap, NODE *)); return; } if (type == IP_PROLOG || type == IP_EPILOG) sz = sizeof(struct interpass_prolog); else sz = sizeof(struct interpass); ip = inlalloc(sz); ip->type = type; ip->lineno = lineno; switch (type) { case IP_NODE: ip->ip_node = va_arg(ap, NODE *); if (ip->ip_node->n_op == LABEL) { NODE *p = ip->ip_node; ip->ip_lbl = (int)glval(p->n_left); ip->type = IP_DEFLAB; nfree(nfree(p)); } break; case IP_EPILOG: if (!isinlining) { locctr(PROG, cftnsp); defloc(cftnsp); } /* FALLTHROUGH */ case IP_PROLOG: inftn = type == IP_PROLOG ? 1 : 0; ipp = (struct interpass_prolog *)ip; ipp->ipp_autos = va_arg(ap, int); ipp->ipp_name = va_arg(ap, char *); ipp->ipp_type = va_arg(ap, TWORD); ipp->ipp_vis = va_arg(ap, int); ip->ip_lbl = va_arg(ap, int); ipp->ip_tmpnum = va_arg(ap, int); ipp->ip_lblnum = crslab; if (type == IP_PROLOG) ipp->ip_lblnum--; break; case IP_DEFLAB: ip->ip_lbl = va_arg(ap, int); break; case IP_ASM: if (blevel == 0) { /* outside function */ printf("%s", va_arg(ap, char *)); va_end(ap); locctr(NOSEG, NULL); return; } ip->ip_asm = va_arg(ap, char *); break; default: cerror("bad send_passt type %d", type); } va_end(ap); pass1_lastchance(ip); /* target-specific info */ if (isinlining) inline_addarg(ip); else pass2_compile(ip); } char * copst(int op) { if (op <= MAXOP) return opst[op]; #define SNAM(x,y) case x: return #y; switch (op) { SNAM(QUALIFIER,QUALIFIER) SNAM(CLASS,CLASS) SNAM(RB,]) SNAM(DOT,.) SNAM(ELLIPSIS,...) SNAM(LB,[) SNAM(TYPE,TYPE) SNAM(COMOP,COMOP) SNAM(QUEST,?) SNAM(COLON,:) SNAM(ANDAND,&&) SNAM(OROR,||) SNAM(NOT,!) SNAM(CAST,CAST) SNAM(PLUSEQ,+=) SNAM(MINUSEQ,-=) SNAM(MULEQ,*=) SNAM(DIVEQ,/=) SNAM(MODEQ,%=) SNAM(ANDEQ,&=) SNAM(OREQ,|=) SNAM(EREQ,^=) SNAM(LSEQ,<<=) SNAM(RSEQ,>>=) SNAM(INCR,++) SNAM(DECR,--) SNAM(STRING,STRING) SNAM(SZOF,SIZEOF) SNAM(ATTRIB,ATTRIBUTE) SNAM(TYMERGE,TYMERGE) SNAM(LABEL,LABEL) SNAM(NEWKW,NEW) SNAM(NMLIST,::) #ifdef GCC_COMPAT SNAM(XREAL,__real__) SNAM(XIMAG,__imag__) #endif default: cerror("bad copst %d", op); } return 0; /* XXX gcc */ } int cdope(int op) { if (op <= MAXOP) return dope[op]; switch (op) { case CLOP: case STRING: case QUALIFIER: case CLASS: case RB: case ELLIPSIS: case TYPE: return LTYPE; case DOT: case SZOF: case COMOP: case QUEST: case COLON: case LB: case TYMERGE: case NEWKW: case NMLIST: return BITYPE; case XIMAG: case XREAL: case ATTRIB: case LABEL: return UTYPE; case ANDAND: case OROR: return BITYPE|LOGFLG; case NOT: return UTYPE|LOGFLG; case CAST: return BITYPE|ASGFLG|ASGOPFLG; case PLUSEQ: return BITYPE|ASGFLG|ASGOPFLG|FLOFLG|SIMPFLG|COMMFLG; case MINUSEQ: return BITYPE|FLOFLG|SIMPFLG|ASGFLG|ASGOPFLG; case MULEQ: return BITYPE|FLOFLG|MULFLG|ASGFLG|ASGOPFLG; case OREQ: case EREQ: case ANDEQ: return BITYPE|SIMPFLG|COMMFLG|ASGFLG|ASGOPFLG; case DIVEQ: return BITYPE|FLOFLG|MULFLG|DIVFLG|ASGFLG|ASGOPFLG; case MODEQ: return BITYPE|DIVFLG|ASGFLG|ASGOPFLG; case LSEQ: case RSEQ: return BITYPE|SHFFLG|ASGFLG|ASGOPFLG; case INCR: case DECR: return BITYPE|ASGFLG; } cerror("cdope missing op %d", op); return 0; /* XXX gcc */ } /* * make a fresh copy of p */ NODE * ccopy(NODE *p) { NODE *q; q = talloc(); *q = *p; switch (coptype(q->n_op)) { case BITYPE: q->n_right = ccopy(p->n_right); case UTYPE: q->n_left = ccopy(p->n_left); } return(q); } NODE * nlabel(int label) { return block(LABEL, bcon(label), NIL, 0, 0, 0); } /* * set PROG-seg label. */ void plabel(int label) { reached = 1; /* Will this always be correct? */ send_passt(IP_NODE, nlabel(label)); } /* * Perform integer promotion on node n. */ NODE * intprom(NODE *n) { if ((n->n_type >= CHAR && n->n_type < INT) || n->n_type == BOOL) { if ((n->n_type == UCHAR && MAX_UCHAR > MAX_INT) || (n->n_type == USHORT && MAX_USHORT > MAX_INT)) return makety(n, UNSIGNED, 0, 0, 0); return makety(n, INT, 0, 0, 0); } return n; } /* * Return CON/VOL/0, whichever are active for the current type. */ int cqual(TWORD t, TWORD q) { while (ISARY(t)) t = DECREF(t), q = DECQAL(q); if (t <= BTMASK) q <<= TSHIFT; return q & (CON|VOL); } int crslab = 10; /* * Return a number for internal labels. */ int getlab(void) { return crslab++; } pcc-20181216/cc/driver004075500017500000000000000000001340533064100132675ustar raggewheelpcc-20181216/cc/driver/CVS004075500017500000000000000000001340533064100137225ustar raggewheelpcc-20181216/cc/driver/CVS/Root010064400017500000000000000000111340533064100146340ustar raggewheel/cvsroot pcc-20181216/cc/driver/CVS/Repository010064400017500000000000000000161340533064100160750ustar raggewheelpcc/cc/driver pcc-20181216/cc/driver/CVS/Entries010064400017500000000000000005211340533064100153300ustar raggewheel/Makefile.in/1.9/Tue Sep 25 11:17:17 2012// /driver.c/1.7/Fri Jun 3 15:34:01 2011// /driver.h/1.2/Thu May 26 16:48:40 2011// /platform.c/1.5/Thu Aug 9 11:41:28 2012// /strlist.c/1.4/Fri Dec 14 17:41:32 2018// /strlist.h/1.4/Fri Dec 14 17:41:32 2018// /xalloc.c/1.2/Thu May 26 16:48:40 2011// /xalloc.h/1.2/Thu May 26 16:48:40 2011// D pcc-20181216/cc/driver/Makefile.in010064400017500000000000000030351203031127500154040ustar raggewheel# $Id: Makefile.in,v 1.9 2012/09/25 11:17:17 plunky Exp $ # # Makefile.in for the cc driver part of pcc. # VPATH=@srcdir@ srcdir=@srcdir@ top_srcdir=@top_srcdir@ top_builddir=@top_builddir@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ libdir = @libdir@ libexecdir = @libexecdir@ includedir = @includedir@ datarootdir = @datarootdir@ mandir = @mandir@ CC = @CC@ EXEEXT = @EXEEXT@ TARGOS = @targos@ TARGOSVER = @targosver@ TARGMACH = @targmach@ TARGET = @target@ VERSION = @PACKAGE_VERSION@ PCCLIBDIR = $(libdir)/pcc/$(TARGET)/$(VERSION)/lib PCCINCDIR = $(libdir)/pcc/$(TARGET)/$(VERSION)/include CFLAGS = @CFLAGS@ @ADD_CFLAGS@ CPPFLAGS = @CPPFLAGS@ -DLIBEXECDIR=\"$(libexecdir)/\" \ @ADD_CPPFLAGS@ -DINCLUDEDIR=\"$(includedir)/\" \ -DPCCINCDIR=\"$(PCCINCDIR)/\" -DPCCLIBDIR=\"$(PCCLIBDIR)/\" \ -DTARGOS=\"$(TARGOS)\" -DTARGOSVER=$(TARGOSVER) -Dos_$(TARGOS) \ -DTARGMACH=\"$(TARGMACH)\" -Dmach_$(TARGMACH) \ -I$(top_builddir) -I$(top_srcdir)/os/$(TARGOS) -I$(MIPDIR) -I$(MDIR) LIBS = @LIBS@ LDFLAGS = @LDFLAGS@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ OBJS=driver.o platform.o strlist.o xalloc.o DEST=@BINPREFIX@pcc$(EXEEXT) MIPDIR=$(top_srcdir)/mip MDIR=$(top_srcdir)/arch/$(TARGMACH) all: $(DEST) $(DEST): $(OBJS) $(CC) $(LDFLAGS) $(OBJS) -o $@ $(LIBS) .c.o: $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< install: test -z "$(DESTDIR)$(bindir)" || mkdir -p "$(DESTDIR)$(bindir)" $(INSTALL_PROGRAM) $(DEST) $(DESTDIR)$(bindir) clean: rm -f $(OBJS) $(DEST) distclean: clean rm -f Makefile pcc-20181216/cc/driver/driver.c010064400017500000000000000474431157217735100150300ustar raggewheel/* $Id: driver.c,v 1.7 2011/06/03 15:34:01 plunky Exp $ */ /*- * Copyright (c) 2011 Joerg Sonnenberger . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include "driver.h" #include "xalloc.h" #include "config.h" static volatile sig_atomic_t exit_now; static volatile sig_atomic_t child; static void sigterm_handler(int signum) { exit_now = 1; if (child) kill(child, SIGTERM); } static const char versionstr[] = VERSSTR; enum phases { DEFAULT, PREPROCESS, COMPILE, ASSEMBLE, LINK } last_phase = DEFAULT; const char *isysroot = NULL; const char *sysroot = ""; const char *preprocessor; const char *compiler; const char *assembler; const char *linker; struct strlist crtdirs; static struct strlist user_sysincdirs; struct strlist sysincdirs; struct strlist includes; struct strlist incdirs; struct strlist libdirs; struct strlist progdirs; struct strlist preprocessor_flags; struct strlist compiler_flags; struct strlist assembler_flags; struct strlist early_linker_flags; struct strlist middle_linker_flags; struct strlist late_linker_flags; struct strlist stdlib_flags; struct strlist early_program_csu_files; struct strlist late_program_csu_files; struct strlist early_dso_csu_files; struct strlist late_dso_csu_files; struct strlist temp_outputs; const char *final_output; static char *temp_directory; static struct strlist inputs; int pic_mode; /* 0: no PIC, 1: -fpic, 2: -fPIC */ int save_temps; int debug_mode; int profile_mode; int nostdinc; int nostdlib; int nostartfiles; int static_mode; int shared_mode; int use_pthread; int verbose_mode; void error(const char *fmt, ...) { va_list arg; va_start(arg, fmt); vfprintf(stderr, fmt, arg); putc('\n', stderr); va_end(arg); exit(1); } static void warning(const char *fmt, ...) { va_list arg; va_start(arg, fmt); vfprintf(stderr, fmt, arg); putc('\n', stderr); va_end(arg); } static void set_last_phase(enum phases phase) { assert(phase != DEFAULT); if (last_phase != DEFAULT && phase != last_phase) error("conflicting compiler options specified"); last_phase = phase; } static void expand_sysroot(void) { struct string *s; struct strlist *lists[] = { &crtdirs, &sysincdirs, &incdirs, &user_sysincdirs, &libdirs, &progdirs, NULL }; const char *sysroots[] = { sysroot, isysroot, isysroot, isysroot, sysroot, sysroot, NULL }; size_t i, sysroot_len, value_len; char *path; assert(sizeof(lists) / sizeof(lists[0]) == sizeof(sysroots) / sizeof(sysroots[0])); for (i = 0; lists[i] != NULL; ++i) { STRLIST_FOREACH(s, lists[i]) { if (s->value[0] != '=') continue; sysroot_len = strlen(sysroots[i]); /* Skipped '=' compensates additional space for '\0' */ value_len = strlen(s->value); path = xmalloc(sysroot_len + value_len); memcpy(path, sysroots[i], sysroot_len); memcpy(path + sysroot_len, s->value + 1, value_len); free(s->value); s->value = path; } } } static void missing_argument(const char *argp) { error("Option `%s' required an argument", argp); } static void split_and_append(struct strlist *l, char *arg) { char *next; for (; arg != NULL; arg = NULL) { next = strchr(arg, ','); if (next != NULL) *next++ = '\0'; strlist_append(l, arg); } } static int strlist_exec(struct strlist *l) { char **argv; size_t argc; int result; strlist_make_array(l, &argv, &argc); if (verbose_mode) { printf("Calling "); strlist_print(l, stdout); printf("\n"); } if (exit_now) return 1; switch ((child = fork())) { case 0: execvp(argv[0], argv); result = write(STDERR_FILENO, "Exec of ", 8); result = write(STDERR_FILENO, argv[0], strlen(argv[0])); result = write(STDERR_FILENO, "failed\n", 7); (void)result; _exit(127); case -1: error("fork failed"); default: while (waitpid(child, &result, 0) == -1 && errno == EINTR) /* nothing */(void)0; result = WEXITSTATUS(result); if (result) error("%s terminated with status %d", argv[0], result); while (argc-- > 0) free(argv[argc]); free(argv); break; } return exit_now; } static char * find_file(const char *file, struct strlist *path, int mode) { struct string *s; char *f; size_t lf, lp; int need_sep; lf = strlen(file); STRLIST_FOREACH(s, path) { lp = strlen(s->value); need_sep = (lp && s->value[lp - 1] != '/') ? 1 : 0; f = xmalloc(lp + lf + need_sep + 1); memcpy(f, s->value, lp); if (need_sep) f[lp] = '/'; memcpy(f + lp + need_sep, file, lf + 1); if (access(f, mode) == 0) return f; free(f); } return xstrdup(file); } static char * output_name(const char *file, const char *new_suffix, int counter, int last) { const char *old_suffix; char *name; size_t lf, ls, len; int counter_len; if (last && final_output) return xstrdup(final_output); old_suffix = strrchr(file, '.'); if (old_suffix != NULL && strchr(old_suffix, '/') != NULL) old_suffix = NULL; if (old_suffix == NULL) old_suffix = file + strlen(file); ls = strlen(new_suffix); if (save_temps || last) { lf = old_suffix - file; name = xmalloc(lf + ls + 1); memcpy(name, file, lf); memcpy(name + lf, new_suffix, ls + 1); return name; } if (temp_directory == NULL) { const char *template; char *path; size_t template_len; int need_sep; template = getenv("TMPDIR"); if (template == NULL) template = "/tmp"; template_len = strlen(template); if (template_len && template[template_len - 1] == '/') need_sep = 0; else need_sep = 1; path = xmalloc(template_len + need_sep + 6 + 1); memcpy(path, template, template_len); if (need_sep) path[template_len] = '/'; memcpy(path + template_len + need_sep, "pcc-XXXXXX", 11); if (mkdtemp(path) == NULL) error("mkdtemp failed: %s", strerror(errno)); temp_directory = path; } lf = strlen(temp_directory); counter_len = snprintf(NULL, 0, "%d", counter); if (counter_len < 1) error("snprintf failure"); len = lf + 1 + (size_t)counter_len + ls + 1; name = xmalloc(len); snprintf(name, len, "%s/%d%s", temp_directory, counter, new_suffix); strlist_append(&temp_outputs, name); return name; } static int preprocess_input(const char *file, char *input, char **output, const char *suffix, int counter) { struct strlist args; struct string *s; char *out; int retval; strlist_init(&args); strlist_append_list(&args, &preprocessor_flags); STRLIST_FOREACH(s, &includes) { strlist_append(&args, "-i"); strlist_append(&args, s->value); } STRLIST_FOREACH(s, &incdirs) { strlist_append(&args, "-I"); strlist_append(&args, s->value); } STRLIST_FOREACH(s, &user_sysincdirs) { strlist_append(&args, "-S"); strlist_append(&args, s->value); } if (!nostdinc) { STRLIST_FOREACH(s, &sysincdirs) { strlist_append(&args, "-S"); strlist_append(&args, s->value); } } strlist_append(&args, input); if (last_phase == PREPROCESS && final_output == NULL) out = xstrdup("-"); else out = output_name(file, suffix, counter, last_phase == PREPROCESS); if (strcmp(out, "-")) strlist_append(&args, out); strlist_prepend(&args, find_file(preprocessor, &progdirs, X_OK)); *output = out; retval = strlist_exec(&args); strlist_free(&args); return retval; } static int compile_input(const char *file, char *input, char **output, const char *suffix, int counter) { struct strlist args; char *out; int retval; strlist_init(&args); strlist_append_list(&args, &compiler_flags); if (debug_mode) strlist_append(&args, "-g"); if (pic_mode) strlist_append(&args, "-k"); if (profile_mode) warning("-pg is currently ignored"); strlist_append(&args, input); out = output_name(file, suffix, counter, last_phase == ASSEMBLE); strlist_append(&args, out); strlist_prepend(&args, find_file(compiler, &progdirs, X_OK)); *output = out; retval = strlist_exec(&args); strlist_free(&args); return retval; } static int assemble_input(const char *file, char *input, char **output, const char *suffix, int counter) { struct strlist args; char *out; int retval; strlist_init(&args); strlist_append_list(&args, &assembler_flags); strlist_append(&args, input); out = output_name(file, ".o", counter, last_phase == COMPILE); strlist_append(&args, "-o"); strlist_append(&args, out); strlist_prepend(&args, find_file(assembler, &progdirs, X_OK)); *output = out; retval = strlist_exec(&args); strlist_free(&args); return retval; } static int handle_input(const char *file) { static int counter; const char *suffix; char *src; int handled, retval; ++counter; if (strcmp(file, "-") == 0) { /* XXX see -x option */ suffix = ".c"; } else { suffix = strrchr(file, '.'); if (suffix != NULL && strchr(suffix, '/') != NULL) suffix = NULL; if (suffix == NULL) suffix = ""; } src = xstrdup(file); if (strcmp(suffix, ".c") == 0) { suffix = ".i"; retval = preprocess_input(file, src, &src, suffix, counter); if (retval) return retval; handled = 1; } else if (strcmp(suffix, ".S") == 0) { suffix = ".s"; retval = preprocess_input(file, src, &src, suffix, counter); if (retval) return retval; handled = 1; } if (last_phase == PREPROCESS) goto done; if (strcmp(suffix, ".i") == 0) { suffix = ".s"; retval = compile_input(file, src, &src, suffix, counter); if (retval) return retval; handled = 1; } if (last_phase == ASSEMBLE) goto done; if (strcmp(suffix, ".s") == 0) { suffix = ".o"; retval = assemble_input(file, src, &src, suffix, counter); if (retval) return retval; handled = 1; } if (last_phase == COMPILE) goto done; if (strcmp(suffix, ".o") == 0) handled = 1; strlist_append(&middle_linker_flags, src); done: if (handled) return 0; if (last_phase == LINK) warning("unknown suffix %s, passing file down to linker", suffix); else warning("unknown suffix %s, skipped", suffix); free(src); return 0; } static int run_linker(void) { struct strlist linker_flags; struct strlist *early_csu, *late_csu; struct string *s; int retval; if (final_output) { strlist_prepend(&early_linker_flags, final_output); strlist_prepend(&early_linker_flags, "-o"); } if (!nostdlib) strlist_append_list(&late_linker_flags, &stdlib_flags); if (!nostartfiles) { if (shared_mode) { early_csu = &early_dso_csu_files; late_csu = &late_dso_csu_files; } else { early_csu = &early_program_csu_files; late_csu = &late_program_csu_files; } STRLIST_FOREACH(s, early_csu) strlist_append_nocopy(&middle_linker_flags, find_file(s->value, &crtdirs, R_OK)); STRLIST_FOREACH(s, late_csu) strlist_append_nocopy(&late_linker_flags, find_file(s->value, &crtdirs, R_OK)); } strlist_init(&linker_flags); strlist_append_list(&linker_flags, &early_linker_flags); strlist_append_list(&linker_flags, &middle_linker_flags); strlist_append_list(&linker_flags, &late_linker_flags); strlist_prepend(&linker_flags, find_file(linker, &progdirs, X_OK)); retval = strlist_exec(&linker_flags); strlist_free(&linker_flags); return retval; } static void cleanup(void) { struct string *file; STRLIST_FOREACH(file, &temp_outputs) { if (unlink(file->value) == -1) warning("removal of ``%s'' failed: %s", file->value, strerror(errno)); } if (temp_directory && rmdir(temp_directory) == -1) warning("removal of ``%s'' failed: %s", temp_directory, strerror(errno)); } int main(int argc, char **argv) { struct string *input; char *argp; int retval; strlist_init(&crtdirs); strlist_init(&user_sysincdirs); strlist_init(&sysincdirs); strlist_init(&incdirs); strlist_init(&includes); strlist_init(&libdirs); strlist_init(&progdirs); strlist_init(&inputs); strlist_init(&preprocessor_flags); strlist_init(&compiler_flags); strlist_init(&assembler_flags); strlist_init(&early_linker_flags); strlist_init(&middle_linker_flags); strlist_init(&late_linker_flags); strlist_init(&stdlib_flags); strlist_init(&early_program_csu_files); strlist_init(&late_program_csu_files); strlist_init(&early_dso_csu_files); strlist_init(&late_dso_csu_files); strlist_init(&temp_outputs); init_platform_specific(TARGOS, TARGMACH); while (--argc) { ++argv; argp = *argv; if (*argp != '-' || strcmp(argp, "-") == 0) { strlist_append(&inputs, argp); continue; } switch (argp[1]) { case '-': if (strcmp(argp, "--param") == 0) { if (argc == 0) missing_argument(argp); --argc; ++argv; /* Unused */ continue; } if (strncmp(argp, "--sysroot=", 10) == 0) { sysroot = argp + 10; continue; } if (strcmp(argp, "--version") == 0) { printf("%s\n", versionstr); exit(0); } break; case 'B': strlist_append(&crtdirs, argp); strlist_append(&libdirs, argp); strlist_append(&progdirs, argp); continue; case 'C': if (argp[2] == '\0') { strlist_append(&preprocessor_flags, argp); continue; } break; case 'c': if (argp[2] == '\0') { set_last_phase(COMPILE); continue; } break; case 'D': strlist_append(&preprocessor_flags, argp); if (argp[2] == '\0') { if (argc == 0) missing_argument(argp); --argc; ++argv; strlist_append(&preprocessor_flags, argp); } continue; case 'E': if (argp[2] == '\0') { set_last_phase(PREPROCESS); continue; } break; case 'f': if (strcmp(argp, "-fpic") == 0) { pic_mode = 1; continue; } if (strcmp(argp, "-fPIC") == 0) { pic_mode = 2; continue; } /* XXX GCC options */ break; case 'g': if (argp[2] == '\0') { debug_mode = 1; continue; } /* XXX allow variants like -g1? */ break; case 'I': if (argp[2] == '\0') { if (argc == 0) missing_argument(argp); --argc; ++argv; strlist_append(&incdirs, argp); continue; } strlist_append(&incdirs, argp + 2); continue; case 'i': if (strcmp(argp, "-isystem") == 0) { if (argc == 0) missing_argument(argp); --argc; ++argv; strlist_append(&user_sysincdirs, argp); continue; } if (strcmp(argp, "-include") == 0) { if (argc == 0) missing_argument(argp); --argc; ++argv; strlist_append(&includes, argp); continue; } if (strcmp(argp, "-isysroot") == 0) { if (argc == 0) missing_argument(argp); --argc; ++argv; isysroot = argp; continue; } /* XXX -idirafter */ /* XXX -iquote */ break; case 'k': if (argp[2] == '\0') { pic_mode = 1; continue; } break; case 'M': if (argp[2] == '\0') { strlist_append(&preprocessor_flags, argp); continue; } break; case 'm': /* XXX implement me */ break; case 'n': if (strcmp(argp, "-nostdinc") == 0) { nostdinc = 1; continue; } if (strcmp(argp, "-nostdinc++") == 0) continue; if (strcmp(argp, "-nostdlib") == 0) { nostdlib = 1; nostartfiles = 1; continue; } if (strcmp(argp, "-nostartfiles") == 0) { nostartfiles = 1; continue; } break; case 'O': if (argp[2] != '\0' && argp[3] != '\0') break; switch(argp[2]) { case '2': case '1': case '\0': strlist_append(&compiler_flags, "-xtemps"); strlist_append(&compiler_flags, "-xdeljumps"); strlist_append(&compiler_flags, "-xinline"); case '0': continue; } break; case 'o': if (argp[2] == '\0') { if (argc == 0) missing_argument(argp); --argc; ++argv; if (final_output) error("Only one `-o' option allowed"); final_output = *argv; continue; } break; case 'p': if (argp[2] == '\0' || strcmp(argp, "-pg") == 0) { profile_mode = 1; continue; } if (strcmp(argp, "-pedantic") == 0) continue; if (strcmp(argp, "-pipe") == 0) continue; /* XXX implement me */ if (strcmp(argp, "-pthread") == 0) { use_pthread = 1; continue; } /* XXX -print-prog-name=XXX */ /* XXX -print-multi-os-directory */ break; case 'r': if (argp[2] == '\0') { strlist_append(&middle_linker_flags, argp); continue; } break; case 'S': if (argp[2] == '\0') { set_last_phase(ASSEMBLE); continue; } break; case 's': if (strcmp(argp, "-save-temps") == 0) { save_temps = 1; continue; } if (strcmp(argp, "-shared") == 0) { shared_mode = 1; continue; } if (strcmp(argp, "-static") == 0) { static_mode = 1; continue; } if (strncmp(argp, "-std=", 5) == 0) continue; /* XXX sanitize me */ break; case 't': if (argp[2] == '\0') { strlist_append(&preprocessor_flags, argp); continue; } case 'U': strlist_append(&preprocessor_flags, argp); if (argp[2] == '\0') { if (argc == 0) missing_argument(argp); --argc; ++argv; strlist_append(&preprocessor_flags, argp); } continue; case 'v': if (argp[2] == '\0') { verbose_mode = 1; continue; } break; case 'W': if (strncmp(argp, "-Wa,", 4) == 0) { split_and_append(&assembler_flags, argp + 4); continue; } if (strncmp(argp, "-Wl,", 4) == 0) { split_and_append(&middle_linker_flags, argp + 4); continue; } if (strncmp(argp, "-Wp,", 4) == 0) { split_and_append(&preprocessor_flags, argp + 4); continue; } /* XXX warning flags */ break; case 'x': /* XXX -x c */ /* XXX -c assembler-with-cpp */ break; } error("unknown flag `%s'", argp); } if (last_phase == DEFAULT) last_phase = LINK; if (verbose_mode) printf("%s\n", versionstr); if (isysroot == NULL) isysroot = sysroot; expand_sysroot(); if (last_phase != LINK && final_output && !STRLIST_EMPTY(&inputs) && !STRLIST_NEXT(STRLIST_FIRST(&inputs))) error("-o specified with more than one input"); if (last_phase == PREPROCESS && final_output == NULL) final_output = "-"; if (STRLIST_EMPTY(&inputs)) error("No input specificed"); retval = 0; signal(SIGTERM, sigterm_handler); STRLIST_FOREACH(input, &inputs) { if (handle_input(input->value)) retval = 1; } if (!retval && last_phase == LINK) { if (run_linker()) retval = 1; } if (exit_now) warning("Received signal, terminating"); cleanup(); strlist_free(&crtdirs); strlist_free(&user_sysincdirs); strlist_free(&sysincdirs); strlist_free(&incdirs); strlist_free(&includes); strlist_free(&libdirs); strlist_free(&progdirs); strlist_free(&inputs); strlist_free(&preprocessor_flags); strlist_free(&compiler_flags); strlist_free(&assembler_flags); strlist_free(&early_linker_flags); strlist_free(&middle_linker_flags); strlist_free(&late_linker_flags); strlist_free(&stdlib_flags); strlist_free(&early_program_csu_files); strlist_free(&late_program_csu_files); strlist_free(&early_dso_csu_files); strlist_free(&late_dso_csu_files); strlist_free(&temp_outputs); return retval; } pcc-20181216/cc/driver/driver.h010064400017500000000000000045531156750215000150210ustar raggewheel/* $Id: driver.h,v 1.2 2011/05/26 16:48:40 plunky Exp $ */ /*- * Copyright (c) 2011 Joerg Sonnenberger . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef DRIVER_H #define DRIVER_H #include "strlist.h" extern const char *isysroot; extern const char *sysroot; extern const char *preprocessor; extern const char *compiler; extern const char *assembler; extern const char *linker; extern struct strlist crtdirs; extern struct strlist sysincdirs; extern struct strlist libdirs; extern struct strlist progdirs; extern struct strlist preprocessor_flags; extern struct strlist compiler_flags; extern struct strlist assembler_flags; extern struct strlist early_linker_flags; extern struct strlist middle_linker_flags; extern struct strlist late_linker_flags; extern struct strlist stdlib_flags; extern struct strlist early_program_csu_files; extern struct strlist late_program_csu_files; extern struct strlist early_dso_csu_files; extern struct strlist late_dso_csu_files; void error(const char *fmt, ...); void init_platform_specific(const char *, const char *); #endif /* DRIVER_H */ pcc-20181216/cc/driver/platform.c010064400017500000000000000220701201072075000153270ustar raggewheel/* $Id: platform.c,v 1.5 2012/08/09 11:41:28 ragge Exp $ */ /*- * Copyright (c) 2011 Joerg Sonnenberger . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include "driver.h" #include "config.h" #include "ccconfig.h" #ifndef NEW_DRIVER_CFG #define USE_OLD_DRIVER_CFG #endif #define _MKS(x) #x #define MKS(x) _MKS(x) #ifndef PREPROCESSOR #define PREPROCESSOR "cpp" #endif #ifndef COMPILER #define COMPILER "ccom" #endif #ifndef ASSEMBLER #define ASSEMBLER "as" #endif #ifndef LINKER #define LINKER "ld" #endif enum architecture { ARCH_ANY, ARCH_I386, ARCH_X86_64 }; static const struct { enum architecture arch; const char *name; } arch_mapping[] = { #ifdef USE_OLD_DRIVER_CFG { ARCH_ANY, TARGMACH }, #else { ARCH_I386, "i386" }, { ARCH_X86_64, "x86_64" } , #endif }; enum os { OS_ANY, OS_NETBSD, OS_LINUX }; static const struct { enum os os; const char *name; } os_mapping[] = { #ifdef USE_OLD_DRIVER_CFG { OS_ANY, TARGOS }, #else { OS_NETBSD, "netbsd" }, { OS_LINUX, "linux" }, #endif }; struct platform_specific { enum architecture arch; enum os os; const char * const *values; }; #ifndef USE_OLD_DRIVER_CFG static const char * const early_program_csu_values0[] = { "crt0.o", NULL }; static const char * const early_program_csu_values1[] = { "crt1.o", NULL }; #else static const char * const early_program_csu_values2[] = { CRT0FILE, NULL }; #endif static const struct platform_specific early_program_csu[] = { #ifdef USE_OLD_DRIVER_CFG { ARCH_ANY, OS_ANY, early_program_csu_values2 }, #else { ARCH_ANY, OS_NETBSD, early_program_csu_values0 }, { ARCH_ANY, OS_LINUX, early_program_csu_values1 }, #endif }; static const char * const late_program_csu_values0[] = { "crtend.o", "crtn.o", NULL }; static const struct platform_specific late_program_csu[] = { { ARCH_ANY, OS_ANY, late_program_csu_values0 }, }; static const char * const early_dso_csu_values0[] = { "crtio", "crtbeginS.o", NULL }; static const struct platform_specific early_dso_csu[] = { { ARCH_ANY, OS_ANY, early_dso_csu_values0 }, }; static const char * const late_dso_csu_values0[] = { "crtendS.o", "crtn.o", NULL }; static const struct platform_specific late_dso_csu[] = { { ARCH_ANY, OS_ANY, late_dso_csu_values0 }, }; static const char * const predefined_macros_values0[] = { "-D__x86_64__", "-D__x86_64", "-D__amd64__", "-D__amd64", NULL }; static const char * const predefined_macros_values1[] = { "-D__NetBSD__", "-D__ELF__", NULL }; static const char * const predefined_macros_values2[] = { "-D__linux__", "-D__ELF__", NULL }; static const char * const predefined_macros_values3[] = { "-D__i386__", NULL }; static const char * const predefined_macros_values4[] = { "-D__PCC__=" MKS(PCC_MAJOR), "-D__PCC_MINOR__=" MKS(PCC_MINOR), "-D__PCC_MINORMINOR__=" MKS(PCC_MINORMINOR), "-D__VERSION__=" MKS(VERSSTR), "-D__STDC_ISO_10646__=200009L", NULL }; static const char * const predefined_macros_values5[] = { "-D__GNUC__=4", "-D__GNUC_MINOR__=3", "-D__GNUC_PATCHLEVEL__=1", "-D__GNUC_STDC_INLINE__=1", NULL }; static const struct platform_specific predefined_macros[] = { { ARCH_X86_64, OS_ANY, predefined_macros_values0 }, { ARCH_ANY, OS_NETBSD, predefined_macros_values1 }, { ARCH_ANY, OS_LINUX, predefined_macros_values2 }, { ARCH_I386, OS_ANY, predefined_macros_values3 }, { ARCH_ANY, OS_ANY, predefined_macros_values4 }, { ARCH_ANY, OS_ANY, predefined_macros_values5 }, }; static const char * const early_linker_values0[] = { "-dynamic-linker", "/libexec/ld.elf_so", NULL }; static const char * const early_linker_values1[] = { "-m", "elf_i386", NULL }; static const char * const early_linker_values2[] = { "-m", "elf_x86_64", NULL }; static const char * const early_linker_values3[] = { "-dynamic-linker", "/lib64/ld-linux-x86-64.so.2", NULL }; static const char * const early_linker_values4[] = { "-m", "elf_i386", NULL }; static const char * const early_linker_values5[] = { "-m", "elf_x86_64", NULL }; static const struct platform_specific early_linker[] = { { ARCH_ANY, OS_NETBSD, early_linker_values0 }, { ARCH_I386, OS_NETBSD, early_linker_values1 }, { ARCH_X86_64, OS_NETBSD, early_linker_values2 }, { ARCH_ANY, OS_LINUX, early_linker_values3 }, { ARCH_I386, OS_LINUX, early_linker_values4 }, { ARCH_X86_64, OS_LINUX, early_linker_values5 }, }; static const char * const sysincdir_list_values0[] = { "=/usr/include", NULL }; static const char * const sysincdir_list_values1[] = { /* XXX fix up for libpcc? */ "=/usr/lib/gcc/x86_64-linux-gnu/4.4/include", NULL }; static const struct platform_specific sysincdir_list[] = { { ARCH_ANY, OS_ANY, sysincdir_list_values0 }, { ARCH_X86_64, OS_LINUX, sysincdir_list_values1 }, }; static const char * const crtdir_list_values0[] = { "=/usr/lib/i386", "=/usr/lib", NULL }; static const char * const crtdir_list_values1[] = { "=/usr/lib", NULL }; static const char * const crtdir_list_values2[] = { "=/usr/lib64", "=/usr/lib/gcc/x86_64-linux-gnu/4.4", NULL }; static const struct platform_specific crtdir_list[] = { { ARCH_I386, OS_NETBSD, crtdir_list_values0 }, { ARCH_X86_64, OS_NETBSD, crtdir_list_values1 }, { ARCH_X86_64, OS_LINUX, crtdir_list_values2 }, }; static const char * const stdlib_list_values0[] = { "-L/usr/lib/gcc/x86_64-linux-gnu/4.4", NULL }; static const char * const stdlib_list_values1[] = { "-lgcc", "--as-needed", "-lgcc_s", "--no-as-needed", "-lc", "-lgcc", "--as-needed", "-lgcc_s", "--no-as-needed", NULL }; static const struct platform_specific stdlib_list[] = { { ARCH_X86_64, OS_LINUX, stdlib_list_values0 }, { ARCH_ANY, OS_ANY, stdlib_list_values1 }, }; static const char * const program_dirs_values0[] = { LIBEXECDIR, NULL }; static const struct platform_specific program_dirs[] = { { ARCH_ANY, OS_ANY, program_dirs_values0 }, }; #define ARRAYLEN(a) (sizeof(a) / sizeof((a)[0])) #define ARRAYPAIR(a) a, ARRAYLEN(a) static const struct { const struct platform_specific *initializer; size_t len; struct strlist *list; } platform_specific_inits[] = { { ARRAYPAIR(early_program_csu), &early_program_csu_files }, { ARRAYPAIR(late_program_csu), &late_program_csu_files }, { ARRAYPAIR(early_dso_csu), &early_dso_csu_files }, { ARRAYPAIR(late_dso_csu), &late_dso_csu_files }, { ARRAYPAIR(predefined_macros), &preprocessor_flags }, { ARRAYPAIR(early_linker), &early_linker_flags }, { ARRAYPAIR(sysincdir_list), &sysincdirs }, { ARRAYPAIR(crtdir_list), &crtdirs }, { ARRAYPAIR(stdlib_list), &stdlib_flags }, { ARRAYPAIR(program_dirs), &progdirs }, }; void init_platform_specific(const char *os_name, const char *arch_name) { enum os os; enum architecture arch; size_t i, j, len; const struct platform_specific *initializer; struct strlist *l; os = OS_ANY; for (i = 0; i < ARRAYLEN(os_mapping); ++i) { if (strcmp(os_mapping[i].name, os_name) == 0) { os = os_mapping[i].os; break; } } if (os == OS_ANY) error("unknown Operating System: %s", os_name); arch = ARCH_ANY; for (i = 0; i < ARRAYLEN(arch_mapping); ++i) { if (strcmp(arch_mapping[i].name, arch_name) == 0) { arch = arch_mapping[i].arch; break; } } if (arch == ARCH_ANY) error("unknown architecture: %s", arch_name); for (i = 0; i < ARRAYLEN(platform_specific_inits); ++i) { initializer = platform_specific_inits[i].initializer; len = platform_specific_inits[i].len; l = platform_specific_inits[i].list; for (j = 0; j < len; ++j) { if (initializer[j].arch != arch && initializer[j].arch != ARCH_ANY) continue; if (initializer[j].os != os && initializer[j].os != OS_ANY) continue; strlist_append_array(l, initializer[j].values); } } preprocessor = PREPROCESSOR; compiler = COMPILER; assembler = ASSEMBLER; linker = LINKER; } pcc-20181216/cc/driver/strlist.c010064400017500000000000000100321340476551400152210ustar raggewheel/* $Id: strlist.c,v 1.4 2018/12/14 17:41:32 plunky Exp $ */ /*- * Copyright (c) 2011 Joerg Sonnenberger . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include "strlist.h" #include "xalloc.h" void strlist_init(struct strlist *l) { l->first = l->last = NULL; } void strlist_free(struct strlist *l) { struct string *s1, *s2; STRLIST_FOREACH_MUTABLE(s1, l, s2) { free(s1->value); free(s1); } l->first = l->last = NULL; } void strlist_make_array(const struct strlist *l, char ***a, size_t *len) { const struct string *s; char **i; *len = 0; STRLIST_FOREACH(s, l) ++*len; *a = xcalloc(*len + 1, sizeof(*i)); i = *a; STRLIST_FOREACH(s, l) *i++ = xstrdup(s->value); *i = NULL; } void strlist_print(const struct strlist *l, FILE *f, int esc, const char *sep) { const struct string *s; int quote, first = 1; const char *p; STRLIST_FOREACH(s, l) { if (!first) fputs(sep, f); quote = 0; if (esc) { for (p = s->value; *p; p++) { if ((*p >= '0' && *p <= '9') || (*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || *p == '.' || *p == '/' || *p == '-' || *p == '_') continue; quote = 1; break; } } if (quote) putc('"', f); for (p = s->value; *p; p++) { if (quote && (*p == '"' || *p == '$' || *p == '\\' || *p == '`')) putc('\\', f); putc(*p, f); } if (quote) putc('"', f); first = 0; } } void strlist_append_nocopy(struct strlist *l, char *val) { struct string *s; s = xmalloc(sizeof(*s)); s->next = NULL; s->value = val; if (l->last != NULL) { l->last->next = s; l->last = s; } else { l->last = s; l->first = s; } } void strlist_append(struct strlist *l, const char *val) { strlist_append_nocopy(l, xstrdup(val)); } void strlist_append_list(struct strlist *l, const struct strlist *l2) { struct string *s; STRLIST_FOREACH(s, l2) strlist_append(l, s->value); } void strlist_append_array(struct strlist *l, const char * const *strings) { for (; *strings != NULL; ++strings) strlist_append(l, *strings); } void strlist_prepend_nocopy(struct strlist *l, char *val) { struct string *s; s = xmalloc(sizeof(*s)); s->next = l->first; s->value = val; l->first = s; if (l->last == NULL) { l->last = s; } } void strlist_prepend(struct strlist *l, const char *val) { strlist_prepend_nocopy(l, xstrdup(val)); } void strlist_prepend_list(struct strlist *l, const struct strlist *l2) { struct string *s, *s2, *s3, *s4; if (STRLIST_EMPTY(l2)) return; if (STRLIST_EMPTY(l)) { strlist_append_list(l, l2); return; } s2 = NULL; s4 = l->first; STRLIST_FOREACH(s, l2) { s3 = xmalloc(sizeof(*s3)); s3->value = xstrdup(s->value); s3->next = s4; if (s2 == NULL) l->first = s3; else s2->next = s3; } } pcc-20181216/cc/driver/strlist.h010064400017500000000000000053301340476551400152330ustar raggewheel/* $Id: strlist.h,v 1.4 2018/12/14 17:41:32 plunky Exp $ */ /*- * Copyright (c) 2011 Joerg Sonnenberger . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef STRLIST_H #define STRLIST_H #include #include struct string { struct string *next; char *value; }; struct strlist { struct string *first; struct string *last; }; void strlist_init(struct strlist *); void strlist_free(struct strlist *); void strlist_make_array(const struct strlist *, char ***, size_t *); void strlist_print(const struct strlist *, FILE *, int, const char *); void strlist_prepend(struct strlist *, const char *); void strlist_prepend_nocopy(struct strlist *, char *); void strlist_prepend_list(struct strlist *, const struct strlist *); void strlist_append(struct strlist *, const char *); void strlist_append_nocopy(struct strlist *, char *); void strlist_append_list(struct strlist *, const struct strlist *); void strlist_append_array(struct strlist *, const char * const *); #define STRLIST_FIRST(head) ((head)->first) #define STRLIST_NEXT(elem) ((elem)->next) #define STRLIST_FOREACH(var, head) \ for ((var) = STRLIST_FIRST(head); \ (var) != NULL; \ (var) = STRLIST_NEXT(var)) #define STRLIST_FOREACH_MUTABLE(var, head, var2) \ for ((var) = STRLIST_FIRST(head); \ (var) != NULL && ((var2) = STRLIST_NEXT(var), 1); \ (var) = (var2)) #define STRLIST_EMPTY(head) (STRLIST_FIRST(head) == NULL) #endif /* STRLIST_H */ pcc-20181216/cc/driver/xalloc.c010064400017500000000000000041461156750215000150010ustar raggewheel/* $Id: xalloc.c,v 1.2 2011/05/26 16:48:40 plunky Exp $ */ /*- * Copyright (c) 2011 Joerg Sonnenberger . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include "xalloc.h" static void error(const char *str) { fprintf(stderr, "%s\n", str); exit(1); } void * xcalloc(size_t elem, size_t len) { void *ptr; if ((ptr = calloc(elem, len)) == NULL) error("calloc failed"); return ptr; } void * xmalloc(size_t len) { void *ptr; if ((ptr = malloc(len)) == NULL) error("malloc failed"); return ptr; } void * xrealloc(void *buf, size_t len) { void *ptr; if ((ptr = realloc(buf, len)) == NULL) error("realloc failed"); return ptr; } char * xstrdup(const char *str) { char *buf; if ((buf = strdup(str)) == NULL) error("strdup failed"); return buf; } pcc-20181216/cc/driver/xalloc.h010064400017500000000000000032041156750215000150000ustar raggewheel/* $Id: xalloc.h,v 1.2 2011/05/26 16:48:40 plunky Exp $ */ /*- * Copyright (c) 2011 Joerg Sonnenberger . * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef XALLOC_H #define XALLOC_H #include void *xcalloc(size_t, size_t); void *xmalloc(size_t); void *xrealloc(void *, size_t); char *xstrdup(const char *); #endif /* XALLOC_H */ pcc-20181216/common004075500017500000000000000000001340533064100126775ustar raggewheelpcc-20181216/common/CVS004075500017500000000000000000001340533064100133325ustar raggewheelpcc-20181216/common/CVS/Root010064400017500000000000000000111340533064100142440ustar raggewheel/cvsroot pcc-20181216/common/CVS/Repository010064400017500000000000000000131340533064100155020ustar raggewheelpcc/common pcc-20181216/common/CVS/Entries010064400017500000000000000004561340533064100147470ustar raggewheel/compat.c/1.13/Fri Jul 24 08:26:05 2015// /compat.h/1.6/Fri Jul 24 08:26:05 2015// /softfloat.c/1.26/Sun Dec 9 09:18:26 2018// /softfloat.h/1.15/Sun Dec 2 16:37:53 2018// /strtodg.c/1.2/Mon Aug 6 20:19:33 2018// /unicode.c/1.10/Tue Oct 11 13:48:24 2016// /unicode.h/1.5/Sun Jul 19 13:20:37 2015// D pcc-20181216/common/compat.c010064400017500000000000000502171255437323500144210ustar raggewheel/* * Copyright (c) 1998 Todd C. Miller * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $Id: compat.c,v 1.13 2015/07/24 08:26:05 ragge Exp $ */ /* * Copyright (c) 1987, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $NetBSD: gettemp.c,v 1.13 2003/12/05 00:57:36 uebayasi Exp $ */ #include #include "config.h" #include "compat.h" #ifndef HAVE_STRLCAT /* * Appends src to string dst of size siz (unlike strncat, siz is the * full size of dst, not space left). At most siz-1 characters * will be copied. Always NUL terminates (unless siz <= strlen(dst)). * Returns strlen(initial dst) + strlen(src); if retval >= siz, * truncation occurred. */ size_t strlcat(char *dst, const char *src, size_t siz) { char *d = dst; const char *s = src; size_t n = siz; size_t dlen; /* Find the end of dst and adjust bytes left but don't go past end */ while (n-- != 0 && *d != '\0') d++; dlen = d - dst; n = siz - dlen; if (n == 0) return(dlen + strlen(s)); while (*s != '\0') { if (n != 1) { *d++ = *s; n--; } s++; } *d = '\0'; return(dlen + (s - src)); /* count does not include NUL */ } #endif #ifndef HAVE_STRLCPY /* * Copy src to string dst of size siz. At most siz-1 characters * will be copied. Always NUL terminates (unless siz == 0). * Returns strlen(src); if retval >= siz, truncation occurred. */ size_t strlcpy(char *dst, const char *src, size_t siz) { char *d = dst; const char *s = src; size_t n = siz; /* Copy as many bytes as will fit */ if (n != 0 && --n != 0) { do { if ((*d++ = *s++) == 0) break; } while (--n != 0); } /* Not enough room in dst, add NUL and traverse rest of src */ if (n == 0) { if (siz != 0) *d = '\0'; /* NUL-terminate dst */ while (*s++) ; } return(s - src - 1); /* count does not include NUL */ } #endif #ifndef HAVE_GETOPT char *optarg; int optind = 1; int getopt(int argc, char * const argv[], const char *args) { int n; int nlen = strlen(args); char cmd; char rv; if (argv[optind] && *argv[optind] == '-') { cmd = *(argv[optind] + 1); for (n = 0; n < nlen; n++) { if (args[n] == ':') continue; if (args[n] == cmd) { rv = *(argv[optind] + 1); if (args[n+1] == ':') { if (*(argv[optind] + 2) != '\0') { optarg = argv[optind] + 2; optind += 1; } else { optarg = argv[optind + 1]; optind += 2; } if (!optarg) optarg=""; return rv; } else { optarg = NULL; optind += 1; return rv; } } } } return -1; } #endif #if !defined(HAVE_MKSTEMP) && !defined(_WIN32) #include /* open() */ #include /* getpid() */ int mkstemp(char *path) { char *trv; unsigned int pid; /* To guarantee multiple calls generate unique names even if the file is not created. 676 different possibilities with 7 or more X's, 26 with 6 or less. */ static char xtra[2] = "aa"; int xcnt = 0; pid = getpid(); /* Move to end of path and count trailing X's. */ for (trv = path; *trv; ++trv) if (*trv == 'X') xcnt++; else xcnt = 0; /* Use at least one from xtra. Use 2 if more than 6 X's. */ if (*(trv - 1) == 'X') *--trv = xtra[0]; if (xcnt > 6 && *(trv - 1) == 'X') *--trv = xtra[1]; /* Set remaining X's to pid digits with 0's to the left. */ while (*--trv == 'X') { *trv = (pid % 10) + '0'; pid /= 10; } /* update xtra for next call. */ if (xtra[0] != 'z') xtra[0]++; else { xtra[0] = 'a'; if (xtra[1] != 'z') xtra[1]++; else xtra[1] = 'a'; } return open(path, O_CREAT | O_EXCL | O_RDWR, 0600); } #endif #ifndef HAVE_FFS int ffs(int x) { int r = 1; if (!x) return 0; if (!(x & 0xffff)) { x >>= 16; r += 16; } if (!(x & 0xff)) { x >>= 8; r += 8; } if (!(x & 0xf)) { x >>= 4; r += 4; } if (!(x & 3)) { x >>= 2; r += 2; } if (!(x & 1)) { x >>= 1; r += 1; } return r; } #endif /* * Copyright Patrick Powell 1995 * This code is based on code written by Patrick Powell (papowell@astart.com) * It may be used for any purpose as long as this notice remains intact * on all source code distributions */ #if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) #include /* isdigit() */ static void dopr(char *buffer, size_t maxlen, const char *format, va_list args); static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value, int flags, int min, int max); static void fmtint(char *buffer, size_t *currlen, size_t maxlen, long value, int base, int min, int max, int flags); static void fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, int min, int max, int flags); static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c); /* * dopr(): poor man's version of doprintf */ /* format read states */ #define DP_S_DEFAULT 0 #define DP_S_FLAGS 1 #define DP_S_MIN 2 #define DP_S_DOT 3 #define DP_S_MAX 4 #define DP_S_MOD 5 #define DP_S_CONV 6 #define DP_S_DONE 7 /* format flags - Bits */ #define DP_F_MINUS (1 << 0) #define DP_F_PLUS (1 << 1) #define DP_F_SPACE (1 << 2) #define DP_F_NUM (1 << 3) #define DP_F_ZERO (1 << 4) #define DP_F_UP (1 << 5) #define DP_F_UNSIGNED (1 << 6) /* Conversion Flags */ #define DP_C_SHORT 1 #define DP_C_LONG 2 #define DP_C_LDOUBLE 3 #define DP_C_LONG_LONG 4 #define char_to_int(p) (p - '0') #define abs_val(p) (p < 0 ? -p : p) static void dopr(char *buffer, size_t maxlen, const char *format, va_list args) { char *strvalue, ch; long value; long double fvalue; int min = 0, max = -1, state = DP_S_DEFAULT, flags = 0, cflags = 0; size_t currlen = 0; ch = *format++; while (state != DP_S_DONE) { if ((ch == '\0') || (currlen >= maxlen)) state = DP_S_DONE; switch(state) { case DP_S_DEFAULT: if (ch == '%') state = DP_S_FLAGS; else dopr_outch(buffer, &currlen, maxlen, ch); ch = *format++; break; case DP_S_FLAGS: switch (ch) { case '-': flags |= DP_F_MINUS; ch = *format++; break; case '+': flags |= DP_F_PLUS; ch = *format++; break; case ' ': flags |= DP_F_SPACE; ch = *format++; break; case '#': flags |= DP_F_NUM; ch = *format++; break; case '0': flags |= DP_F_ZERO; ch = *format++; break; default: state = DP_S_MIN; break; } break; case DP_S_MIN: if (isdigit((unsigned char)ch)) { min = 10 * min + char_to_int (ch); ch = *format++; } else if (ch == '*') { min = va_arg (args, int); ch = *format++; state = DP_S_DOT; } else state = DP_S_DOT; break; case DP_S_DOT: if (ch == '.') { state = DP_S_MAX; ch = *format++; } else state = DP_S_MOD; break; case DP_S_MAX: if (isdigit((unsigned char)ch)) { if (max < 0) max = 0; max = 10 * max + char_to_int(ch); ch = *format++; } else if (ch == '*') { max = va_arg (args, int); ch = *format++; state = DP_S_MOD; } else state = DP_S_MOD; break; case DP_S_MOD: switch (ch) { case 'h': cflags = DP_C_SHORT; ch = *format++; break; case 'l': cflags = DP_C_LONG; ch = *format++; if (ch == 'l') { cflags = DP_C_LONG_LONG; ch = *format++; } break; case 'q': cflags = DP_C_LONG_LONG; ch = *format++; break; case 'L': cflags = DP_C_LDOUBLE; ch = *format++; break; default: break; } state = DP_S_CONV; break; case DP_S_CONV: switch (ch) { case 'd': case 'i': if (cflags == DP_C_SHORT) value = va_arg(args, int); else if (cflags == DP_C_LONG) value = va_arg(args, long int); else if (cflags == DP_C_LONG_LONG) value = va_arg (args, long long); else value = va_arg (args, int); fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags); break; case 'o': flags |= DP_F_UNSIGNED; if (cflags == DP_C_SHORT) value = va_arg(args, unsigned int); else if (cflags == DP_C_LONG) value = va_arg(args, unsigned long int); else if (cflags == DP_C_LONG_LONG) value = va_arg(args, unsigned long long); else value = va_arg(args, unsigned int); fmtint(buffer, &currlen, maxlen, value, 8, min, max, flags); break; case 'u': flags |= DP_F_UNSIGNED; if (cflags == DP_C_SHORT) value = va_arg(args, unsigned int); else if (cflags == DP_C_LONG) value = va_arg(args, unsigned long int); else if (cflags == DP_C_LONG_LONG) value = va_arg(args, unsigned long long); else value = va_arg(args, unsigned int); fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags); break; case 'X': flags |= DP_F_UP; case 'x': flags |= DP_F_UNSIGNED; if (cflags == DP_C_SHORT) value = va_arg(args, unsigned int); else if (cflags == DP_C_LONG) value = va_arg(args, unsigned long int); else if (cflags == DP_C_LONG_LONG) value = va_arg(args, unsigned long long); else value = va_arg(args, unsigned int); fmtint(buffer, &currlen, maxlen, value, 16, min, max, flags); break; case 'f': if (cflags == DP_C_LDOUBLE) fvalue = va_arg(args, long double); else fvalue = va_arg(args, double); /* um, floating point? */ fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags); break; case 'E': flags |= DP_F_UP; case 'e': if (cflags == DP_C_LDOUBLE) fvalue = va_arg(args, long double); else fvalue = va_arg(args, double); break; case 'G': flags |= DP_F_UP; case 'g': if (cflags == DP_C_LDOUBLE) fvalue = va_arg(args, long double); else fvalue = va_arg(args, double); break; case 'c': dopr_outch(buffer, &currlen, maxlen, va_arg(args, int)); break; case 's': strvalue = va_arg(args, char *); if (max < 0) max = maxlen; /* ie, no max */ fmtstr(buffer, &currlen, maxlen, strvalue, flags, min, max); break; case 'p': strvalue = va_arg(args, void *); fmtint(buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags); break; case 'n': if (cflags == DP_C_SHORT) { short int *num; num = va_arg(args, short int *); *num = currlen; } else if (cflags == DP_C_LONG) { long int *num; num = va_arg(args, long int *); *num = currlen; } else if (cflags == DP_C_LONG_LONG) { long long *num; num = va_arg(args, long long *); *num = currlen; } else { int *num; num = va_arg(args, int *); *num = currlen; } break; case '%': dopr_outch(buffer, &currlen, maxlen, ch); break; case 'w': /* not supported yet, treat as next char */ ch = *format++; break; default: /* Unknown, skip */ break; } ch = *format++; state = DP_S_DEFAULT; flags = cflags = min = 0; max = -1; break; case DP_S_DONE: break; default: /* hmm? */ break; /* some picky compilers need this */ } } if (currlen < maxlen - 1) buffer[currlen] = '\0'; else buffer[maxlen - 1] = '\0'; } static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value, int flags, int min, int max) { int cnt = 0, padlen, strln; /* amount to pad */ if (value == 0) value = ""; for (strln = 0; value[strln]; ++strln); /* strlen */ padlen = min - strln; if (padlen < 0) padlen = 0; if (flags & DP_F_MINUS) padlen = -padlen; /* Left Justify */ while ((padlen > 0) && (cnt < max)) { dopr_outch(buffer, currlen, maxlen, ' '); --padlen; ++cnt; } while (*value && (cnt < max)) { dopr_outch(buffer, currlen, maxlen, *value++); ++cnt; } while ((padlen < 0) && (cnt < max)) { dopr_outch(buffer, currlen, maxlen, ' '); ++padlen; ++cnt; } } /* Have to handle DP_F_NUM (ie 0x and 0 alternates) */ static void fmtint(char *buffer, size_t *currlen, size_t maxlen, long value, int base, int min, int max, int flags) { unsigned long uvalue; char convert[20]; int signvalue = 0, place = 0, caps = 0; int spadlen = 0; /* amount to space pad */ int zpadlen = 0; /* amount to zero pad */ #define PADMAX(x,y) ((x) > (y) ? (x) : (y)) if (max < 0) max = 0; uvalue = value; if (!(flags & DP_F_UNSIGNED)) { if (value < 0) { signvalue = '-'; uvalue = -value; } else if (flags & DP_F_PLUS) /* Do a sign (+/i) */ signvalue = '+'; else if (flags & DP_F_SPACE) signvalue = ' '; } if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */ do { convert[place++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef") [uvalue % (unsigned)base]; uvalue = (uvalue / (unsigned)base ); } while (uvalue && (place < 20)); if (place == 20) place--; convert[place] = 0; zpadlen = max - place; spadlen = min - PADMAX(max, place) - (signvalue ? 1 : 0); if (zpadlen < 0) zpadlen = 0; if (spadlen < 0) spadlen = 0; if (flags & DP_F_ZERO) { zpadlen = PADMAX(zpadlen, spadlen); spadlen = 0; } if (flags & DP_F_MINUS) spadlen = -spadlen; /* Left Justifty */ /* Spaces */ while (spadlen > 0) { dopr_outch(buffer, currlen, maxlen, ' '); --spadlen; } /* Sign */ if (signvalue) dopr_outch(buffer, currlen, maxlen, signvalue); /* Zeros */ if (zpadlen > 0) { while (zpadlen > 0) { dopr_outch(buffer, currlen, maxlen, '0'); --zpadlen; } } /* Digits */ while (place > 0) dopr_outch(buffer, currlen, maxlen, convert[--place]); /* Left Justified spaces */ while (spadlen < 0) { dopr_outch (buffer, currlen, maxlen, ' '); ++spadlen; } } static long double ldpow10(int exp) { long double result = 1; while (exp) { result *= 10; exp--; } return result; } static long lroundl(long double value) { long intpart = value; value -= intpart; if (value >= 0.5) intpart++; return intpart; } static void fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, int min, int max, int flags) { char iconvert[20], fconvert[20]; int signvalue = 0, iplace = 0, fplace = 0; int padlen = 0; /* amount to pad */ int zpadlen = 0, caps = 0; long intpart, fracpart; long double ufvalue; /* * AIX manpage says the default is 0, but Solaris says the default * is 6, and sprintf on AIX defaults to 6 */ if (max < 0) max = 6; ufvalue = abs_val(fvalue); if (fvalue < 0) signvalue = '-'; else if (flags & DP_F_PLUS) /* Do a sign (+/i) */ signvalue = '+'; else if (flags & DP_F_SPACE) signvalue = ' '; intpart = ufvalue; /* * Sorry, we only support 9 digits past the decimal because of our * conversion method */ if (max > 9) max = 9; /* We "cheat" by converting the fractional part to integer by * multiplying by a factor of 10 */ fracpart = lroundl((ldpow10 (max)) * (ufvalue - intpart)); if (fracpart >= ldpow10 (max)) { intpart++; fracpart -= ldpow10 (max); } /* Convert integer part */ do { iconvert[iplace++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef") [intpart % 10]; intpart = (intpart / 10); } while(intpart && (iplace < 20)); if (iplace == 20) iplace--; iconvert[iplace] = 0; /* Convert fractional part */ do { fconvert[fplace++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef") [fracpart % 10]; fracpart = (fracpart / 10); } while(fracpart && (fplace < 20)); if (fplace == 20) fplace--; fconvert[fplace] = 0; /* -1 for decimal point, another -1 if we are printing a sign */ padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); zpadlen = max - fplace; if (zpadlen < 0) zpadlen = 0; if (padlen < 0) padlen = 0; if (flags & DP_F_MINUS) padlen = -padlen; /* Left Justifty */ if ((flags & DP_F_ZERO) && (padlen > 0)) { if (signvalue) { dopr_outch(buffer, currlen, maxlen, signvalue); --padlen; signvalue = 0; } while (padlen > 0) { dopr_outch(buffer, currlen, maxlen, '0'); --padlen; } } while (padlen > 0) { dopr_outch(buffer, currlen, maxlen, ' '); --padlen; } if (signvalue) dopr_outch(buffer, currlen, maxlen, signvalue); while (iplace > 0) dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]); /* * Decimal point. This should probably use locale to find the * correct char to print out. */ dopr_outch(buffer, currlen, maxlen, '.'); while (fplace > 0) dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]); while (zpadlen > 0) { dopr_outch(buffer, currlen, maxlen, '0'); --zpadlen; } while (padlen < 0) { dopr_outch(buffer, currlen, maxlen, ' '); ++padlen; } } static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c) { if (*currlen < maxlen) buffer[(*currlen)++] = c; } #endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */ #ifndef HAVE_VSNPRINTF int vsnprintf(char *str, size_t count, const char *fmt, va_list args) { str[0] = 0; dopr(str, count, fmt, args); return(strlen(str)); } #endif /* !HAVE_VSNPRINTF */ #ifndef HAVE_SNPRINTF int snprintf(char *str,size_t count,const char *fmt,...) { va_list ap; va_start(ap, fmt); (void) vsnprintf(str, count, fmt, ap); va_end(ap); return(strlen(str)); } #endif /* !HAVE_SNPRINTF */ pcc-20181216/common/compat.h010064400017500000000000000016101255437323500144170ustar raggewheel/* $Id: compat.h,v 1.6 2015/07/24 08:26:05 ragge Exp $ */ /* * Just compatibility function prototypes. * Public domain. */ #ifndef COMPAT_H #define COMPAT_H #ifndef HAVE_STRLCPY #include /* size_t */ size_t strlcpy(char *dst, const char *src, size_t siz); #endif #ifndef HAVE_STRLCAT #include /* size_t */ size_t strlcat(char *dst, const char *src, size_t siz); #endif #ifndef HAVE_GETOPT extern char *optarg; extern int optind; int getopt(int, char * const [], const char *); #endif #ifndef HAVE_MKSTEMP int mkstemp(char *); #endif #ifndef HAVE_FFS int ffs(int); #endif #ifndef HAVE_SNPRINTF #include /* size_t */ int snprintf(char *str, size_t count, const char *fmt, ...); #endif #ifndef HAVE_VSNPRINTF #include /* size_t */ #include /* va_list */ int vsnprintf(char *str, size_t count, const char *fmt, va_list args); #endif #endif pcc-20181216/common/softfloat.c010064400017500000000000001222531340315674200151330ustar raggewheel/* $Id: softfloat.c,v 1.26 2018/12/09 09:18:26 ragge Exp $ */ /* * Copyright (c) 2008 Anders Magnusson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "manifest.h" #include "softfloat.h" #include #include #ifndef PCC_DEBUG #define assert(e) ((void)0) #else #define assert(e) (!(e)?cerror("assertion failed " #e " at softfloat:%d",__LINE__):(void)0) #endif /* * Floating point emulation, to not depend on the characteristics (and bugs) * of the host floating-point implementation when compiling. * * Assumes that: * - long long is (at least) 64 bits * - long is at least 32 bits. * - short is at least 16 bits. */ #ifdef FDFLOAT /* * Supports F- and D-float, used in DEC machines. * * XXX - assumes that: * - long long is (at least) 64 bits * - int is at least 32 bits. * - short is 16 bits. */ /* * Useful macros to manipulate the float. */ #define DSIGN(w) (((w).fd1 >> 15) & 1) #define DSIGNSET(w,s) ((w).fd1 = (s << 15) | ((w).fd1 & 077777)) #define DEXP(w) (((w).fd1 >> 7) & 0377) #define DEXPSET(w,e) ((w).fd1 = (((e) & 0377) << 7) | ((w).fd1 & 0100177)) #define DMANTH(w) ((w).fd1 & 0177) #define DMANTHSET(w,m) ((w).fd1 = ((m) & 0177) | ((w).fd1 & 0177600)) typedef unsigned int lword; typedef unsigned long long dword; #define MAXMANT 0x100000000000000LL /* * Returns a zero dfloat. */ static SF nulldf(void) { SF rv; rv.fd1 = rv.fd2 = rv.fd3 = rv.fd4 = 0; return rv; } /* * Convert a (u)longlong to dfloat. * XXX - fails on too large (> 55 bits) numbers. */ SF soft_cast(CONSZ ll, TWORD t) { int i; SF rv; rv = nulldf(); if (ll == 0) return rv; /* fp is zero */ if (ll < 0) DSIGNSET(rv,1), ll = -ll; for (i = 0; ll > 0; i++, ll <<= 1) ; DEXPSET(rv, 192-i); DMANTHSET(rv, ll >> 56); rv.fd2 = ll >> 40; rv.fd3 = ll >> 24; rv.fd4 = ll >> 8; return rv; } /* * multiply two dfloat. Use chop, not round. */ SF soft_mul(SF p1, SF p2) { SF rv; lword a1[2], a2[2], res[4]; dword sum; res[0] = res[1] = res[2] = res[3] = 0; /* move mantissa into lwords */ a1[0] = p1.fd4 | (p1.fd3 << 16); a1[1] = p1.fd2 | DMANTH(p1) << 16 | 0x800000; a2[0] = p2.fd4 | (p2.fd3 << 16); a2[1] = p2.fd2 | DMANTH(p2) << 16 | 0x800000; #define MULONE(x,y,r) sum += (dword)a1[x] * (dword)a2[y]; sum += res[r]; \ res[r] = sum; sum >>= 32; sum = 0; MULONE(0, 0, 0); MULONE(1, 0, 1); res[2] = sum; sum = 0; MULONE(0, 1, 1); MULONE(1, 1, 2); res[3] = sum; rv.fd1 = 0; DSIGNSET(rv, DSIGN(p1) ^ DSIGN(p2)); DEXPSET(rv, DEXP(p1) + DEXP(p2) - 128); if (res[3] & 0x8000) { res[3] = (res[3] << 8) | (res[2] >> 24); res[2] = (res[2] << 8) | (res[1] >> 24); } else { DEXPSET(rv, DEXP(rv) - 1); res[3] = (res[3] << 9) | (res[2] >> 23); res[2] = (res[2] << 9) | (res[1] >> 23); } DMANTHSET(rv, res[3] >> 16); rv.fd2 = res[3]; rv.fd3 = res[2] >> 16; rv.fd4 = res[2]; return rv; } SF soft_div(SF t, SF n) { SF rv; dword T, N, K; int c; #define SHL(x,b) ((dword)(x) << b) T = SHL(1,55) | SHL(DMANTH(t), 48) | SHL(t.fd2, 32) | SHL(t.fd3, 16) | t.fd4; N = SHL(1,55) | SHL(DMANTH(n), 48) | SHL(n.fd2, 32) | SHL(n.fd3, 16) | n.fd4; c = T > N; for (K = 0; (K & 0x80000000000000ULL) == 0; ) { if (T >= N) { T -= N; K |= 1; } T <<= 1; K <<= 1; } rv.fd1 = 0; DSIGNSET(rv, DSIGN(t) ^ DSIGN(n)); DEXPSET(rv, DEXP(t) - DEXP(n) + 128 + c); DMANTHSET(rv, K >> 48); rv.fd2 = K >> 32; rv.fd3 = K >> 16; rv.fd4 = K; return rv; } /* * Negate a float number. Easy. */ SF soft_neg(SF sf) { int sign = DSIGN(sf) == 0; DSIGNSET(sf, sign); return sf; } /* * Return true if fp number is zero. */ int soft_isz(SF sf) { return (DEXP(sf) == 0); } int soft_cmp_eq(SF x1, SF x2) { cerror("soft_cmp_eq"); return 0; } int soft_cmp_ne(SF x1, SF x2) { cerror("soft_cmp_ne"); return 0; } int soft_cmp_le(SF x1, SF x2) { cerror("soft_cmp_le"); return 0; } int soft_cmp_lt(SF x1, SF x2) { cerror("soft_cmp_lt"); return 0; } int soft_cmp_ge(SF x1, SF x2) { cerror("soft_cmp_ge"); return 0; } int soft_cmp_gt(SF x1, SF x2) { cerror("soft_cmp_gt"); return 0; } /* * Convert a fp number to a CONSZ. */ CONSZ soft_val(SF sf) { CONSZ mant; int exp = DEXP(sf) - 128; mant = SHL(1,55) | SHL(DMANTH(sf), 48) | SHL(sf.fd2, 32) | SHL(sf.fd3, 16) | sf.fd4; while (exp < 0) mant >>= 1, exp++; while (exp > 0) mant <<= 1, exp--; return mant; } SF soft_plus(SF x1, SF x2) { cerror("soft_plus"); return x1; } SF soft_minus(SF x1, SF x2) { cerror("soft_minus"); return x1; } /* * Convert a hex constant to floating point number. */ NODE * fhexcon(char *s) { cerror("fhexcon"); return NULL; } /* * Convert a floating-point constant to D-float and store it in a NODE. */ NODE * floatcon(char *s) { NODE *p; dword mant; SF fl, flexp, exp5; int exp, negexp, bexp; exp = 0; mant = 0; #define ADDTO(sum, val) sum = sum * 10 + val - '0' for (; *s >= '0' && *s <= '9'; s++) { if (mant= '0' && *s <= '9'; s++) { if (mant= '0' && *s <= '9'; s++) ADDTO(eexp, *s); if (sign) eexp = -eexp; exp = exp + eexp; } negexp = 1; if (exp<0) { negexp = -1; exp = -exp; } flexp = soft_cast(1, INT); exp5 = soft_cast(5, INT); bexp = exp; fl = soft_cast(mant, INT); for (; exp; exp >>= 1) { if (exp&01) flexp = soft_mul(flexp, exp5); exp5 = soft_mul(exp5, exp5); } if (negexp<0) fl = soft_div(fl, flexp); else fl = soft_mul(fl, flexp); DEXPSET(fl, DEXP(fl) + negexp*bexp); p = block(FCON, NIL, NIL, DOUBLE, 0, 0); /* XXX type */ p->n_dcon = fl; return p; } #else /* * Use parametric floating-point representation, as used in the package gdtoa * published by David M. Gay and generally available as gdtoa.tgz at * http://www.netlib.org/fp/ ; see also strtodg.c introduction. * * Arithmetic characteristics are described in struct FPI (explained below); * the actual numbers are represented (stored) in struct SF. * Floating-point numbers have fpi->nbits bits. * These numbers are regarded as integers multiplied by 2^e * (i.e., 2 to the power of the exponent e), where e is stored in * *exp by strtodg. The minimum and maximum exponent values fpi->emin * and fpi->emax for normalized floating-point numbers reflect this * arrangement. For example, the IEEE 754 standard for binary arithmetic * specifies doubles (also known as binary64) as having 53 bits, with * normalized values of the form 1.xxxxx... times 2^(b-1023), with 52 bits * (the x's) and the biased exponent b represented explicitly; * b is an unsigned integer in the range 1 <= b <= 2046 for normalized * finite doubles, b = 0 for denormals, and b = 2047 for Infinities and NaNs. * To turn an IEEE double into the representation used here, we multiply * 1.xxxx... by 2^52 (to make it an integer) and reduce the exponent * e = (b-1023) by 52: * fpi->emin = 1 - 1023 - 52 * fpi->emax = 1046 - 1023 - 52 * For fpi_binary64 initialization, we actually write -53+1 rather than -52, * to emphasize that there are 53 bits including one implicit bit at the * left of the binary point. * Field fpi->rounding indicates the desired rounding direction, with * possible values * FPI_Round_zero = toward 0, * FPI_Round_near = unbiased rounding -- the IEEE default, * FPI_Round_up = toward +Infinity, and * FPI_Round_down = toward -Infinity * FPI_Round_near_from0 = to nearest, ties always away from 0 * given in pass1.h. * * Field fpi->sudden_underflow indicates whether computations should return * denormals or flush them to zero. Normal floating-point numbers have * bit fpi->nbits in the significand on. Denormals have it off, with * exponent = fpi->emin. * * Fields fpi->explicit_one, fpi->storage, and fpi->exp_bias are only * relevant when the numbers are finally packed into interchange format. * If bit 1 is the lowest in the significand, bit fpi->storage has the sign. * * Some architectures do not use IEEE arithmetic but can nevertheless use * the same parametrization. They should provide their own FPI objects. * Fields fpi->has_inf_nan and fpi->has_neg_zero cover the non-IEEE cases * of lacking respectively the use of infinities and NaN, and negative zero. * Field fpi->has_radix_16 is for architectures (IBM, DG Nova) with base 16. * * In this implementation, the bits are stored in one large integer * (unsigned long long); this limits the number of bits to 64. * Because of the storage representation (but not the implementation), * exponents are restricted to 15 bits. * * Furthermore, this implementation assumes that: * - integers are (obviously) stored as 2's complement * - long long is (at least) 64 bits * - CONSZ is (at least) 64 bits * There are possible issues if int is 16 bits, with divisions. * * As a result, this is also a slightly restricted software implementation of * IEEE 754:1985 standard. Missing parts, useless in a compiler, are: * - no soft_unpack(), to convert from external binary{32,64} formats * - no precision control (not required, dropped in :2008) * - no soft_sqrt() operation * - no soft_remainder() operation * - no soft_rint(), _ceil, or _floor rounding operations * - no binary-to-decimal conversion (can use D. Gay's dgtoa.c) * - signaling NaNs (SF_NoNumber; should cause SFEXCP_Invalid on every op) * - XXX fenv-support is pending * - no soft_scalb(), _logb, or _nextafter optional functions * It should be easy to expand it into a complete implementation. * * The operations are rounded according to the indicated type. * If because of FLT_EVAL_METHOD, the precision has to be greater, * this should be handled by the calling code. */ /* * API restrictions: * - type information should be between FLOAT and LDOUBLE */ #ifndef Long #define Long int #endif #ifndef ULong typedef unsigned Long ULong; #endif #ifndef ULLong typedef unsigned long long ULLong; #endif static uint64_t sfrshift(uint64_t mant, int bits); extern int strtodg (const char*, char**, FPI*, Long*, ULong*); /* IEEE binary formats, and their interchange format encodings */ #ifdef notdef FPI fpi_binary16 = { 11, 1-15-11+1, 30-15-11+1, 1, 0, 0, 1, 1, 0, 16, 15+11-1 }; #endif #ifndef notyet FPI fpi_binary128 = { 113, 1-16383-113+1, 32766-16383-113+1, 1, 0, 0, 1, 1, 0, 128, 16383+113-1 }; #endif #ifdef USE_IEEEFP_32 #define IEEEFP_32_FPI fpi_binary32 FPI fpi_binary32 = { 24, 1-127-24+1, 254-127-24+1, 1, 0, 0, 1, 1, 0, 32, 127+24-1 }; #define IEEEFP_32_ZERO(x,s) ((x)->fp[0] = (s << 31)) #define IEEEFP_32_NAN(x,sign) ((x)->fp[0] = 0x7fc00000 | (sign << 31)) #define IEEEFP_32_INF(x,sign) ((x)->fp[0] = 0x7f800000 | (sign << 31)) #define IEEEFP_32_ISINF(x) (((x)->fp[0] & 0x7fffffff) == 0x7f800000) #define IEEEFP_32_ISZERO(x) (((x)->fp[0] & 0x7fffffff) == 0) #define IEEEFP_32_ISNAN(x) (((x)->fp[0] & 0x7fffffff) == 0x7fc00000) #define IEEEFP_32_BIAS 127 #define IEEEFP_32_TOOLARGE(exp, mant) ieeefp_32_toolarge(exp, mant) #define IEEEFP_32_TOOSMALL(exp, mant) ieeefp_32_toosmall(exp, mant) #define IEEEFP_32_MAKE(x, sign, exp, mant) \ ((x)->fp[0] = (sign << 31) | (((exp & 0xff) << 23) + sfrshift(mant, 41))) static int ieeefp_32_toolarge(int exp, uint64_t mant) { if (exp >= IEEEFP_32_MAX_EXP + IEEEFP_32_BIAS) return 1; if ((exp == IEEEFP_32_MAX_EXP + IEEEFP_32_BIAS - 1) && (sfrshift(mant, 41) > 0x7fffff)) return 1; return 0; } static int ieeefp_32_toosmall(int exp, uint64_t mant) { if ( exp >= 0 ) return 0; mant = sfrshift(mant, -exp); mant |= (mant & 0xffffffffff ? 0x10000000000 : 0); if (mant & 0xfffffe0000000000) return 1; return 0; } #else #error need float definition #endif #ifdef USE_IEEEFP_64 #define IEEEFP_64_FPI fpi_binary64 FPI fpi_binary64 = { 53, 1-1023-53+1, 2046-1023-53+1, 1, 0, 0, 1, 1, 0, 64, 1023+53-1 }; //static SF ieee64_zero = { { { 0, 0, 0 } } }; #define IEEEFP_64_ZERO(x,s) ((x)->fp[0] = 0, (x)->fp[1] = (s << 31)) #define IEEEFP_64_NAN(x,sign) \ ((x)->fp[0] = 0, (x)->fp[1] = 0x7ff80000 | (sign << 31)) #define IEEEFP_64_INF(x,sign) \ ((x)->fp[0] = 0, (x)->fp[1] = 0x7ff00000 | (sign << 31)) #define IEEEFP_64_NEG(x) (x)->fp[1] ^= 0x80000000 #define IEEEFP_64_ISINF(x) ((((x)->fp[1] & 0x7fffffff) == 0x7ff00000) && \ (x)->fp[0] == 0) #define IEEEFP_64_ISINFNAN(x) (((x)->fp[1] & 0x7ff00000) == 0x7ff00000) #define IEEEFP_64_ISZERO(x) ((((x)->fp[1] & 0x7fffffff) == 0) && (x)->fp[0] == 0) #define IEEEFP_64_ISNAN(x) ((((x)->fp[1] & 0x7fffffff) == 0x7ff80000) && \ (x)->fp[0] == 0) #define IEEEFP_64_BIAS 1023 #define IEEEFP_64_TOOLARGE(exp, mant) ieeefp_64_toolarge(exp, mant) #define IEEEFP_64_MAXMINT 2048+64+16 /* exponent + subnormal + guard */ #define IEEEFP_64_MAKE(x, sign, exp, mant) \ { uint64_t xmant = sfrshift(mant, 12); \ ((x)->fp[0] = xmant, (x)->fp[1] = ((sign << 31) | \ ((exp & 0x7ff) << 20)) + (xmant >> 32)); } static int ieeefp_64_toolarge(int exp, uint64_t mant) { if (exp >= IEEEFP_64_MAX_EXP + IEEEFP_64_BIAS) return 1; if ((exp == IEEEFP_64_MAX_EXP + IEEEFP_64_BIAS - 1) && (sfrshift(mant, 12) > 0xfffffffffffff)) return 1; return 0; } #else #error need double definition #endif #ifdef USE_IEEEFP_X80 #define IEEEFP_X80_FPI fpi_binaryx80 /* IEEE double extended in its usual form, for example Intel 387 */ FPI fpi_binaryx80 = { 64, 1-16383-64+1, 32766-16383-64+1, 1, 0, 1, 1, 1, 0, 80, 16383+64-1 }; #define IEEEFP_X80_NAN(x,s) \ ((x)->fp[0] = 0, (x)->fp[1] = 0xc0000000, (x)->fp[2] = 0x7fff | ((s) << 15)) #define IEEEFP_X80_INF(x,s) \ ((x)->fp[0] = 0, (x)->fp[1] = 0x80000000, (x)->fp[2] = 0x7fff | ((s) << 15)) #define IEEEFP_X80_ZERO(x,s) \ ((x)->fp[0] = (x)->fp[1] = 0, (x)->fp[2] = (s << 15)) #define IEEEFP_X80_NEG(x) (x)->fp[2] ^= 0x8000 #define IEEEFP_X80_ISINF(x) ((((x)->fp[2] & 0x7fff) == 0x7fff) && \ ((x)->fp[1] == 0x80000000) && (x)->fp[0] == 0) #define IEEEFP_X80_ISINFNAN(x) (((x)->fp[2] & 0x7fff) == 0x7fff) #define IEEEFP_X80_ISZERO(x) ((((x)->fp[2] & 0x7fff) == 0) && \ ((x)->fp[1] | (x)->fp[0]) == 0) #define IEEEFP_X80_ISNAN(x) ((((x)->fp[2] & 0x7fff) == 0x7fff) && \ (((x)->fp[1] != 0x80000000) || (x)->fp[0] == 0)) #define IEEEFP_X80_BIAS 16383 #define IEEEFP_X80_MAXMINT 32768+64+16 /* exponent + subnormal + guard */ #define IEEEFP_X80_MAKE(x, sign, exp, mant) \ ((x)->fp[0] = mant >> 1, (x)->fp[1] = (mant >> 33) | \ (exp ? (1 << 31) : 0), \ (x)->fp[2] = (exp & 0x7fff) | (sign << 15)) #endif #ifdef USE_IEEEFP_X80 #define SZLD 10 /* less than SZLDOUBLE, avoid cmp junk */ #else #define SZLD sizeof(long double) #endif #define SOFT_INFINITE 1 #define SOFT_NAN 2 #define SOFT_ZERO 3 #define SOFT_NORMAL 4 #define SOFT_SUBNORMAL 5 int soft_classify(SFP sf, TWORD type); #define FPI_FLOAT C(FLT_PREFIX,_FPI) #define FPI_DOUBLE C(DBL_PREFIX,_FPI) #define FPI_LDOUBLE C(LDBL_PREFIX,_FPI) #define LDOUBLE_NAN C(LDBL_PREFIX,_NAN) #define LDOUBLE_INF C(LDBL_PREFIX,_INF) #define LDOUBLE_ZERO C(LDBL_PREFIX,_ZERO) #define LDOUBLE_NEG C(LDBL_PREFIX,_NEG) #define LDOUBLE_ISINF C(LDBL_PREFIX,_ISINF) #define LDOUBLE_ISNAN C(LDBL_PREFIX,_ISNAN) #define LDOUBLE_ISINFNAN C(LDBL_PREFIX,_ISINFNAN) #define LDOUBLE_ISZERO C(LDBL_PREFIX,_ISZERO) #define LDOUBLE_BIAS C(LDBL_PREFIX,_BIAS) #define LDOUBLE_MAKE C(LDBL_PREFIX,_MAKE) #define LDOUBLE_MAXMINT C(LDBL_PREFIX,_MAXMINT) #define LDOUBLE_SIGN C(LDBL_PREFIX,_SIGN) #define DOUBLE_NAN C(DBL_PREFIX,_NAN) #define DOUBLE_INF C(DBL_PREFIX,_INF) #define DOUBLE_ZERO C(DBL_PREFIX,_ZERO) #define DOUBLE_NEG C(DBL_PREFIX,_NEG) #define DOUBLE_ISINF C(DBL_PREFIX,_ISINF) #define DOUBLE_ISNAN C(DBL_PREFIX,_ISNAN) #define DOUBLE_ISZERO C(DBL_PREFIX,_ISZERO) #define DOUBLE_BIAS C(DBL_PREFIX,_BIAS) #define DOUBLE_TOOLARGE C(DBL_PREFIX,_TOOLARGE) #define DOUBLE_TOOSMALL C(DBL_PREFIX,_TOOSMALL) #define DOUBLE_MAKE C(DBL_PREFIX,_MAKE) #define DOUBLE_MAXMINT C(DBL_PREFIX,_MAXMINT) #define FLOAT_NAN C(FLT_PREFIX,_NAN) #define FLOAT_INF C(FLT_PREFIX,_INF) #define FLOAT_ZERO C(FLT_PREFIX,_ZERO) #define FLOAT_NEG C(FLT_PREFIX,_NEG) #define FLOAT_ISINF C(FLT_PREFIX,_ISINF) #define FLOAT_ISNAN C(FLT_PREFIX,_ISNAN) #define FLOAT_ISZERO C(FLT_PREFIX,_ISZERO) #define FLOAT_BIAS C(FLT_PREFIX,_BIAS) #define FLOAT_TOOLARGE C(FLT_PREFIX,_TOOLARGE) #define FLOAT_TOOSMALL C(FLT_PREFIX,_TOOSMALL) #define FLOAT_MAKE C(FLT_PREFIX,_MAKE) FPI * fpis[3] = { &FPI_FLOAT, &FPI_DOUBLE, &FPI_LDOUBLE }; #define MAXMINT (LDOUBLE_MAXMINT/16) /* nbits per uint16 */ /* MP package */ typedef struct mint { unsigned int len:15, sign:1; /* sign 1 if minus */ uint16_t val[MAXMINT]; } MINT; void madd(MINT *a, MINT *b, MINT *c); void msub(MINT *a, MINT *b, MINT *c); void mult(MINT *a, MINT *b, MINT *c); void mdiv(MINT *a, MINT *b, MINT *c, MINT *r); void minit(MINT *m); void mshl(MINT *m, int nbits); static void chomp(MINT *a); void mdump(char *c, MINT *a); /* * IEEE specials: * Zero: Exponent 0, mantissa 0 * Denormal: Exponent 0, mantissa != 0 * Infinity: Exponent all 1, mantissa 0 * QNAN: Exponent all 1, mantissa MSB 1 (indeterminate) * SNAN: Exponent all 1, mantissa MSB 0 (invalid) */ #define LX(x,n) ((uint64_t)(x)->fp[n] << n*32) #ifdef USE_IEEEFP_X80 /* * Get long double mantissa without hidden bit. * Hidden bit is expected to be at position 65. */ static uint64_t ldouble_mant(SFP sfp) { uint64_t rv; rv = (LX(sfp,0) | LX(sfp,1)) << 1; /* XXX */ return rv; } #define ldouble_exp(x) ((x)->fp[2] & 0x7FFF) #define ldouble_sign(x) (((x)->fp[2] >> 15) & 1) #elif defined(USE_IEEEFP_64) #define ldouble_mant double_mant #define ldouble_exp double_exp #define ldouble_sign double_sign #endif #define double_mant(x) (((uint64_t)(x)->fp[1] << 44) | ((uint64_t)(x)->fp[0] << 12)) #define double_exp(x) (((x)->fp[1] >> 20) & 0x7fff) #define double_sign(x) (((x)->fp[1] >> 31) & 1) #define float_mant(x) ((uint64_t)((x)->fp[0] & 0x7fffff) << 41) #define float_exp(x) (((x)->fp[0] >> 23) & 0xff) #define float_sign(x) (((x)->fp[0] >> 31) & 1) static void mant2mint(MINT *a, SFP sfp) { uint64_t rv = (LX(sfp,0) | LX(sfp,1)); minit(a); a->val[0] = rv; a->val[1] = rv >> 16; a->val[2] = rv >> 32; a->val[3] = rv >> 48; a->len = 4; } /* * convert a long double to MINT. * Known here to only be valid numbers. */ static void ldbl2mint(MINT *a, SFP sfp) { int exp = ldouble_exp(sfp); mant2mint(a, sfp); mshl(a, exp + 16); /* 16 == guard bits, 64 bit mant is in len */ a->sign = ldouble_sign(sfp); } static int topbit(MINT *a) { uint16_t val; int res; chomp(a); res = (a->len-1) * 16; val = a->val[a->len-1]; val >>= 1; while (val) val >>= 1, res++; return res; } static int getbit(MINT *a, int h) { if (h < 0 || h/16 >= a->len) return 0; return (a->val[h/16] & (1 << (h%16))) != 0; } static void mcopy(MINT *b, MINT *a) { int i; a->len = b->len; a->sign = b->sign; for (i = 0; i < a->len; i++) a->val[i] = b->val[i]; } /* * Round the MINT number. */ static void grsround(MINT *a) { int h = topbit(a); int doadd, i; h -= 63; /* points to lsb */ /* if guard AND either lsb, round or sticky set, add to lsb */ //printf("grs: h %d a %x\n", h, a->val[1]); doadd = 0; if (getbit(a, h-1)) { /* guard bit set */ //printf("grs: getbit!\n"); if (getbit(a, h) || getbit(a, h-2) || getbit(a, h-3)) { doadd = 1; } else { /* find out whether sticky should be set */ for (i = (h/16)-1; i >= 0; i--) { if (a->val[i]) { doadd = 1; break; } } if (doadd == 0) { for (i = 0; i < (h%16)-2; i++) { if (getbit(a, i)) { doadd = 1; break; } } } } } if (doadd && h >= 0) { MINT d, e; minit(&d); mcopy(a, &e); d.len = (h/16)+1; d.val[(h/16)] = 1 << (h % 16); madd(&d, &e, a); } //printf("grs2: h %d a %x\n", h, a->val[1]); } /* * fillin SF with the mantissa. Expect to already be rounded. * return number of times a is left-shifted. */ static int mint2mant(MINT *a, uint64_t *r) { int e = 0; uint64_t mant; int len = a->len-1; while ((a->val[len] & 0x8000) == 0) mshl(a, 1), e++; mant = (uint64_t)a->val[len] << 48; if (len > 0) mant |= (uint64_t)a->val[len-1] << 32; if (len > 1) mant |= (uint64_t)a->val[len-2] << 16; if (len > 2) mant |= (uint64_t)a->val[len-3]; *r = mant; return e; } static void mint2ldbl(SFP sfp, MINT *a) { uint64_t mant; int exp; chomp(a); grsround(a); exp = -mint2mant(a, &mant); exp += (a->len-1) * 16; exp -= 64; /* bits in mantissa */ mant <<= 1; LDOUBLE_MAKE(sfp, a->sign, exp, mant); } /* * Convert a extended float (x80) number to float (32-bit). * Store as float. */ static void floatx80_to_float32(SFP a) { int exp, sign; uint64_t mant; mant = ldouble_mant(a); exp = ldouble_exp(a); sign = ldouble_sign(a); //printf("x80: sign %d exp %x mant %llx\n", sign, exp, mant); //printf("x80s: 0 %x 1 %x 2 %x\n", a.fp[0], a.fp[1], a.fp[2]); if (LDOUBLE_ISINF(a)) { FLOAT_INF(a, sign); //printf("1\n"); } else if (LDOUBLE_ISNAN(a)) { FLOAT_NAN(a, sign); a->fp[0] |= mant >> 41; //printf("2\n"); } else if (LDOUBLE_ISZERO(a)) { //printf("3\n"); FLOAT_ZERO(a, sign); } else { //printf("4\n"); exp = exp - LDOUBLE_BIAS + FLOAT_BIAS; //printf("4: ecp %x\n", exp); if (FLOAT_TOOLARGE(exp, mant)) { FLOAT_INF(a, sign); } else if (FLOAT_TOOSMALL(exp, mant)) { FLOAT_ZERO(a, sign); } else { FLOAT_MAKE(a, sign, exp, mant); } } } /* * Convert a extended float (x80) number to double (64-bit). * Store as double. */ static void floatx80_to_float64(SFP a) { SF rv; int exp, sign; uint64_t mant; mant = ldouble_mant(a); exp = ldouble_exp(a); sign = ldouble_sign(a); //printf("x80: sign %d exp %x mant %llx\n", sign, exp, mant); //printf("x80s: 0 %x 1 %x 2 %x\n", a.fp[0], a.fp[1], a.fp[2]); if (LDOUBLE_ISINF(a)) { DOUBLE_INF(&rv, sign); //printf("1\n"); } else if (LDOUBLE_ISNAN(a)) { DOUBLE_NAN(&rv, sign); rv.fp[1] |= (mant >> 44); rv.fp[0] = mant >> 12; //printf("2\n"); } else if (LDOUBLE_ISZERO(a)) { //printf("3\n"); DOUBLE_ZERO(&rv, sign); } else { //printf("4\n"); exp = exp - LDOUBLE_BIAS + DOUBLE_BIAS; //printf("4: exp %d mant %llx sign %d\n", exp, mant, sign); if (DOUBLE_TOOLARGE(exp, mant)) { DOUBLE_INF(&rv, sign); } else { if (exp < 0) { //printf("done1: sign %d exp %d mant %llx\n", sign, exp, mant); mant = (mant >> 1) | (1ULL << 63) | (mant & 1); //printf("done2: sign %d exp %d mant %llx\n", sign, exp, mant); if (exp < 0) mant = sfrshift(mant, -exp); //printf("done3: sign %d exp %d mant %llx\n", sign, exp, mant); exp = 0; } //printf("done: sign %d exp %d mant %llx\n", sign, exp, mant); DOUBLE_MAKE(&rv, sign, exp, mant); } //printf("X: %x %x %x\n", rv.fp[0], rv.fp[1], rv.fp[2]); } #ifdef DEBUGFP { double d = a->debugfp; //printf("d: %llx\n", *(long long *)&d); if (memcmp(&rv, &d, sizeof(double))) fpwarn("floatx80_to_float64", (long double)*(double*)&rv.debugfp, (long double)d); } #endif *a = rv; } /* * Opposite to above; move a 64-bit float into an 80-bit value. */ static void float64_to_floatx80(SFP a) { SF rv; int exp, sign; uint64_t mant; sign = double_sign(a); switch (soft_classify(a, DOUBLE)) { case SOFT_ZERO: LDOUBLE_ZERO(&rv, sign); break; case SOFT_INFINITE: LDOUBLE_INF(&rv, sign); break; case SOFT_NAN: LDOUBLE_NAN(&rv, sign); break; default: mant = double_mant(a); exp = double_exp(a); exp = exp - DOUBLE_BIAS + LDOUBLE_BIAS; LDOUBLE_MAKE(&rv, sign, exp, mant); break; } *a = rv; } /* * Opposite to above; move a 32-bit float into an 80-bit value. */ static void float32_to_floatx80(SFP a) { int exp, sign; uint64_t mant; sign = float_sign(a); //printf("float32_to_floatx80: classify %d\n", soft_classify(&a, FLOAT)); switch (soft_classify(a, FLOAT)) { case SOFT_ZERO: LDOUBLE_ZERO(a, sign); break; case SOFT_INFINITE: LDOUBLE_INF(a, sign); break; case SOFT_NAN: LDOUBLE_NAN(a, sign); break; default: mant = float_mant(a); exp = float_exp(a); //printf("exp %x\n", exp); exp = exp - FLOAT_BIAS + LDOUBLE_BIAS; //printf("exp %x sign %d mant %llx\n", exp, sign, mant); LDOUBLE_MAKE(a, sign, exp, mant); break; } } /* * Constant rounding control mode (cf. TS 18661 clause 11). * Default is to have no effect. Set through #pragma STDC FENV_ROUND */ int sf_constrounding = FPI_RoundNotSet; /* * Exceptions raised by functions which do not return a SF; behave like errno */ int sf_exceptions = 0; /* * Shift right, rounding to even. */ static uint64_t sfrshift(uint64_t b, int count) { uint64_t z; z = b >> (count - 3); if (b & ((1 << (count - 3)) - 1)) z |= 1; /* sticky */ if (z & 4) { if ((z & 3) || (z & 8)) z += 8; } return z >> 3; } /* * Conversions. */ /* * Convert from integer type f to floating-point type t. * Rounds correctly to the target type. */ void soft_int2fp(SFP rv, CONSZ l, TWORD f, TWORD t) { int64_t ll = l; uint64_t mant; int sign = 0, exp; if (!ISUNSIGNED(f) && ll < 0) { ll = -ll; sign = 1; } if (ll == 0) { LDOUBLE_ZERO(rv, 0); } else { exp = LDOUBLE_BIAS + 64; while (ll > 0) ll <<= 1, exp--; ll <<= 1, exp--; mant = ll; LDOUBLE_MAKE(rv, sign, exp, mant); if (t == FLOAT || t == DOUBLE) soft_fp2fp(rv, t); } #ifdef DEBUGFP { long double dl; dl = ISUNSIGNED(f) ? (long double)(U_CONSZ)(l) : (long double)(CONSZ)(l); dl = t == FLOAT ? (float)dl : t == DOUBLE ? (double)dl : dl; if (dl != rv->debugfp) fpwarn("soft_int2fp", rv->debugfp, dl); } #endif } /* * Explicit cast into some floating-point format. */ void soft_fp2fp(SFP sfp, TWORD t) { #ifdef DEBUGFP // SF rvsave = *sfp; #endif SF rv; if (t == DOUBLE) { rv = *sfp; floatx80_to_float64(&rv); float64_to_floatx80(&rv); } else if (t == FLOAT) { rv = *sfp; floatx80_to_float32(&rv); //printf("soft_fp2fp: %f\n", (double)*(float *)&rv.debugfp); float32_to_floatx80(&rv); //printf("soft_fp2fpX: %Lf\n", rv.debugfp); } else rv = *sfp; //printf("soft_fp2fp: t %d\n", t); #ifdef DEBUGFP { long double l = (t == DOUBLE ? (double)sfp->debugfp : (t == FLOAT ? (float)sfp->debugfp : sfp->debugfp)); if (memcmp(&l, &rv.debugfp, SZLD)) fpwarn("soft_fp2fp", rv.debugfp, l); } #endif *sfp = rv; } /* * Convert a fp number to a CONSZ. Always chop toward zero. */ CONSZ soft_fp2int(SFP sfp, TWORD t) { uint64_t mant; int exp; if (soft_classify(sfp, LDOUBLE) != SOFT_NORMAL) return 0; exp = ldouble_exp(sfp) - LDOUBLE_BIAS - 64 + 1; mant = ldouble_mant(sfp); mant = (mant >> 1) | (1LL << 63); while (exp > 0) mant <<= 1, exp--; while (exp < 0) mant >>= 1, exp++; if (ldouble_sign(sfp)) mant = -(int64_t)mant; #ifdef DEBUGFP { uint64_t u = (uint64_t)sfp->debugfp; int64_t s = (int64_t)sfp->debugfp; if (ISUNSIGNED(t)) { if (u != mant) fpwarn("soft_fp2int:u", 0.0, sfp->debugfp); } else { if (s != (int64_t)mant) fpwarn("soft_fp2int:s", 0.0, sfp->debugfp); } } #endif return mant; } /* * Operations. */ /* * Negate a softfloat. */ void soft_neg(SFP sfp) { LDOUBLE_NEG(sfp); } void soft_plus(SFP x1p, SFP x2p, TWORD t) { MINT a, b, c; SF rv; if (LDOUBLE_ISINF(x1p) && LDOUBLE_ISINF(x2p)) { if (ldouble_sign(x1p) == ldouble_sign(x2p)) return; LDOUBLE_NAN(x1p,0); return; } if (LDOUBLE_ISNAN(x1p) || LDOUBLE_ISINF(x1p)) return; if (LDOUBLE_ISNAN(x2p) || LDOUBLE_ISNAN(x2p)) { *x1p = *x2p; return; } ldbl2mint(&a, x1p); ldbl2mint(&b, x2p); madd(&a, &b, &c); mint2ldbl(&rv, &c); #ifdef DEBUGFP if (x1p->debugfp + x2p->debugfp != rv.debugfp) fpwarn("soft_plus", rv.debugfp, x1p->debugfp + x2p->debugfp); #endif *x1p = rv; } void soft_minus(SFP x1, SFP x2, TWORD t) { LDOUBLE_NEG(x2); return soft_plus(x1, x2, t); } /* * Multiply two softfloats. */ void soft_mul(SFP x1p, SFP x2p, TWORD t) { MINT a, b, c; uint64_t mant; int exp1, exp2, sign, sh; int s1 = ldouble_sign(x1p); int s2 = ldouble_sign(x2p); SF rv; if (LDOUBLE_ISINFNAN(x1p) || LDOUBLE_ISINFNAN(x2p)) { if (LDOUBLE_ISNAN(x1p) || LDOUBLE_ISNAN(x2p)) { LDOUBLE_NAN(x1p, 0); } else if (LDOUBLE_ISINF(x1p) && LDOUBLE_ISINF(x2p)) { LDOUBLE_INF(x1p, s1 == s2); } else if (LDOUBLE_ISINF(x1p) && LDOUBLE_ISZERO(x2p)) { LDOUBLE_NAN(x1p, 0); } else if (LDOUBLE_ISINF(x2p) && LDOUBLE_ISZERO(x1p)) { LDOUBLE_NAN(x1p, 0); } else /* if (LDOUBLE_ISINF(x1p) || LDOUBLE_ISINF(x2p)) */ { LDOUBLE_INF(x1p, s1 == s2); } return; } mant2mint(&a, x1p); mant2mint(&b, x2p); //mdump("x1: ", &a); //mdump("x2: ", &b); mult(&a, &b, &c); //mdump("res: ", &c); grsround(&c); sh = 1 - mint2mant(&c, &mant); exp1 = ldouble_exp(x1p) - LDOUBLE_BIAS; exp2 = ldouble_exp(x2p) - LDOUBLE_BIAS; //printf("exp1 %d exp2 %d\n", exp1, exp2); sign = s1 != s2; LDOUBLE_MAKE(&rv, sign, (exp1 + exp2 + sh + LDOUBLE_BIAS), (mant << 1)); #ifdef DEBUGFP if (x1p->debugfp * x2p->debugfp != rv.debugfp) fpwarn("soft_mul", rv.debugfp, x1p->debugfp * x2p->debugfp); #endif *x1p = rv; } void soft_div(SFP x1p, SFP x2p, TWORD t) { MINT a, b, c, d, e, f; uint64_t mant; int exp1, exp2, sign, sh; int s1 = ldouble_sign(x1p); int s2 = ldouble_sign(x2p); SF rv; if (LDOUBLE_ISINFNAN(x1p) || LDOUBLE_ISINFNAN(x2p)) { if (LDOUBLE_ISNAN(x1p) || LDOUBLE_ISNAN(x2p)) { LDOUBLE_NAN(&rv, 1); } else if (LDOUBLE_ISINF(x1p) && LDOUBLE_ISINF(x2p)) { LDOUBLE_NAN(&rv, 0); } else if (LDOUBLE_ISINF(x1p) && LDOUBLE_ISZERO(x2p)) { LDOUBLE_NAN(&rv, 0); } else if (LDOUBLE_ISINF(x2p)) { LDOUBLE_ZERO(&rv, 0); } else if (LDOUBLE_ISZERO(x2p)) { LDOUBLE_INF(&rv, 0); } else /* if (LDOUBLE_ISINF(x1p)) */ { LDOUBLE_INF(&rv, s1); } } else if (LDOUBLE_ISZERO(x2p)) { if (LDOUBLE_ISZERO(x1p)) { LDOUBLE_NAN(&rv, s1 == s2); } else { LDOUBLE_INF(&rv, s1 != s2); } } else { /* get quot and remainder of divided mantissa */ mant2mint(&a, x1p); mshl(&a, 64); mant2mint(&b, x2p); mdiv(&a, &b, &c, &d); sh = topbit(&c) - 64; /* MANT_BITS */ /* divide remainder as well, for use in rounding */ mshl(&d, 64); mant2mint(&b, x2p); mdiv(&d, &b, &e, &f); /* create 128-bit number of the two quotients */ mshl(&c, 64); madd(&c, &e, &f); /* do correct rounding */ grsround(&f); mint2mant(&f, &mant); exp1 = ldouble_exp(x1p) - LDOUBLE_BIAS; exp2 = ldouble_exp(x2p) - LDOUBLE_BIAS; sign = s1 != s2; LDOUBLE_MAKE(&rv, sign, (exp1 - exp2 + sh + LDOUBLE_BIAS), (mant << 1)); } #ifdef DEBUGFP { long double ldd = x1p->debugfp / x2p->debugfp; if (memcmp(&ldd, &rv.debugfp, SZLD)) fpwarn("soft_div", rv.debugfp, ldd); } #endif //long double ldou = x1p->debugfp / x2p->debugfp; //printf("x1: %llx %x\n", *(long long *)&x1.debugfp, ((int *)&x1.debugfp)[2]); //printf("x2: %llx %x\n", *(long long *)&x2.debugfp, ((int *)&x2.debugfp)[2]); //printf("rv: %llx %x\n", *(long long *)&rv.debugfp, ((int *)&rv.debugfp)[2]); //printf("rv: %llx %x\n", *(long long *)&ldou, ((int *)&ldou)[2]); *x1p = rv; } /* * Classifications and comparisons. */ /* * Return true if fp number is zero. Easy. */ int soft_isz(SFP sfp) { int r = LDOUBLE_ISZERO(sfp); #ifdef DEBUGFP if ((sfp->debugfp == 0.0 && r == 0) || (sfp->debugfp != 0.0 && r == 1)) fpwarn("soft_isz", sfp->debugfp, (long double)r); #endif return r; } /* * Do classification as in C99 7.12.3, for internal use. * No subnormal yet. */ int soft_classify(SFP sfp, TWORD t) { int rv; switch (t) { case FLOAT: if (FLOAT_ISINF(sfp)) rv = SOFT_INFINITE; else if (FLOAT_ISNAN(sfp)) rv = SOFT_NAN; else if (FLOAT_ISZERO(sfp)) rv = SOFT_ZERO; else rv = SOFT_NORMAL; break; case DOUBLE: if (DOUBLE_ISINF(sfp)) rv = SOFT_INFINITE; else if (DOUBLE_ISNAN(sfp)) rv = SOFT_NAN; else if (DOUBLE_ISZERO(sfp)) rv = SOFT_ZERO; else rv = SOFT_NORMAL; break; case LDOUBLE: if (LDOUBLE_ISINF(sfp)) rv = SOFT_INFINITE; else if (LDOUBLE_ISNAN(sfp)) rv = SOFT_NAN; else if (LDOUBLE_ISZERO(sfp)) rv = SOFT_ZERO; else rv = SOFT_NORMAL; break; } return rv; } static int soft_cmp_eq(SFP x1, SFP x2) { int s1, s2, e1, e2; uint64_t m1, m2; s1 = ldouble_sign(x1); s2 = ldouble_sign(x2); e1 = ldouble_exp(x1); e2 = ldouble_exp(x2); m1 = ldouble_mant(x1); m2 = ldouble_mant(x2); if (e1 == 0 && e2 == 0 && m1 == 0 && m2 == 0) return 1; /* special case: +0 == -0 (discard sign) */ if (s1 != s2) return 0; if (e1 == e2 && m1 == m2) return 1; return 0; } /* * Is x1 greater/less than x2? */ static int soft_cmp_gl(SFP x1, SFP x2, int isless) { uint64_t mant1, mant2; int s2, rv; /* Both zero -> not greater */ if (LDOUBLE_ISZERO(x1) && LDOUBLE_ISZERO(x2)) return 0; /* one negative -> return x2 sign */ if (ldouble_sign(x1) + (s2 = ldouble_sign(x2)) == 1) return isless ? !s2 : s2; /* check exponent */ if (ldouble_exp(x1) > ldouble_exp(x2)) { rv = isless ? 0 : 1; } else if (ldouble_exp(x1) < ldouble_exp(x2)) { rv = isless ? 1 : 0; } else { /* exponent equal, check mantissa */ mant1 = ldouble_mant(x1); mant2 = ldouble_mant(x2); if (mant1 == mant2) return 0; /* same number */ if (mant1 > mant2) { rv = isless ? 0 : 1; } else /* if (mant1 < mant2) */ rv = isless ? 1 : 0; } /* if both negative, invert rv */ if (s2) rv ^= 1; return rv; } int soft_cmp(SFP v1p, SFP v2p, int v) { int rv = 0; if (LDOUBLE_ISNAN(v1p) || LDOUBLE_ISNAN(v2p)) return 0; /* never equal */ switch (v) { case GT: case LT: rv = soft_cmp_gl(v1p, v2p, v == LT); break; case GE: case LE: if ((rv = soft_cmp_eq(v1p, v2p))) break; rv = soft_cmp_gl(v1p, v2p, v == LE); break; case EQ: rv = soft_cmp_eq(v1p, v2p); break; case NE: rv = !soft_cmp_eq(v1p, v2p); break; } return rv; } #endif /* FDFLOAT */ static void vals2fp(SF *sf, int k, int exp, uint32_t *mant) { int sign = (k & SF_Neg) != 0; uint64_t m; switch (k & SF_kmask) { case SF_Zero: LDOUBLE_ZERO(sf, sign); break; /* already 0 */ case SF_Normal: m = (((uint64_t)mant[1] << 32) | mant[0]) << 1; //printf("vals2fp m %llx\n", m); exp += FPI_LDOUBLE.exp_bias; LDOUBLE_MAKE(sf, sign, exp, m); //printf("vals2fp: %llx %llx\n", *(long long *)&sf->debugfp, m); #ifdef DEBUGFP if (mant[0] != sf->fp[0] || mant[1] != sf->fp[1]) fpwarn("vals2fp", sf->debugfp, sf->debugfp); #endif break; case SF_Denormal: m = (((uint64_t)mant[1] << 32) | mant[0]) << 1; LDOUBLE_MAKE(sf, sign, 0, m); break; default: fprintf(stderr, "vals2fp: unhandled %x\n", k); break; } if (k & (SFEXCP_ALLmask & ~(SFEXCP_Inexlo|SFEXCP_Inexhi))) fprintf(stderr, "vals2fp: unhandled2 %x\n", k); } /* * Conversions from decimal and hexadecimal strings. * Rounds correctly to the target type (subject to FLT_EVAL_METHOD.) * dt is resulting type. */ void strtosf(SFP sfp, char *str, TWORD tw) { char *eptr; ULong bits[2] = { 0, 0 }; Long expt; int k; k = strtodg(str, &eptr, &FPI_LDOUBLE, &expt, bits); if (k & SFEXCP_Overflow) werror("Overflow in floating-point constant"); if (k & SFEXCP_Inexact && (str[1] == 'x' || str[1] == 'X')) werror("Hexadecimal floating-point constant not exactly"); vals2fp(sfp, k, expt, bits); //printf("strtosf: %llx\n", *(long long *)&sf.debugfp); #ifdef DEBUGFP { long double ld = strtold(str, NULL); if (ld != sfp->debugfp) fpwarn("strtosf", sfp->debugfp, ld); } #endif } /* * return INF/NAN. */ void soft_huge_val(SFP sfp) { LDOUBLE_INF(sfp, 0); #ifdef DEBUGFP if (sfp->debugfp != __builtin_huge_vall()) fpwarn("soft_huge_val", sfp->debugfp, __builtin_huge_vall()); #endif } void soft_nan(SFP sfp, char *c) { LDOUBLE_NAN(sfp, 0); } /* * Convert internally stored floating point to fp type in TWORD. * Save as a static array of uint32_t. */ uint32_t * soft_toush(SFP sfp, TWORD t, int *nbits) { static SF sf; //printf("soft_toush: osf %Lf %La t %d\n", osf.debugfp, osf.debugfp, t); //printf("soft_toushLD: %x %x %x\n", osf.fp[2], osf.fp[1], osf.fp[0]); //float d = osf.debugfp; printf("soft_toush-D: d %x %x\n", *(((int *)&d)+1), *(int *)&d); memset(&sf, 0, sizeof(SF)); if (t == LDOUBLE) { sf = *sfp; } else if (t == DOUBLE) { sf = *sfp; floatx80_to_float64(&sf); //printf("soft_toushD: sf %f\n", *(double *)&sf.debugfp); //printf("soft_toushD2: %x %x\n", sf.fp[1], sf.fp[0]); } else /* if (t == FLOAT) */ { sf = *sfp; floatx80_to_float32(&sf); //printf("soft_toushD: sf %f\n", (double)*(float *)&sf.debugfp); //printf("soft_toushD2: %x\n", sf.fp[0]); } #ifdef DEBUGFP { float ldf; double ldd; long double ldt; ldt = (t == FLOAT ? (float)sfp->debugfp : t == DOUBLE ? (double)sfp->debugfp : (long double)sfp->debugfp); ldf = ldt; ldd = ldt; if (t == FLOAT && memcmp(&ldf, &sf.debugfp, sizeof(float))) fpwarn("soft_toush2", (long double)*(float*)&sf.debugfp, ldt); if (t == DOUBLE && memcmp(&ldd, &sf.debugfp, sizeof(double))) fpwarn("soft_toush3", (long double)*(double*)&sf.debugfp, ldt); if (t == LDOUBLE && memcmp(&ldt, &sf.debugfp, SZLD)) fpwarn("soft_toush4", (long double)sf.debugfp, ldt); } #endif *nbits = fpis[t-FLOAT]->storage; return sf.fp; } #ifdef DEBUGFP void fpwarn(const char *s, long double soft, long double hard) { extern int nerrors; union { long double ld; int i[3]; } X; fprintf(stderr, "WARNING: In function %s: soft=%La hard=%La\n", s, soft, hard); fprintf(stderr, "WARNING: soft=%Lf hard=%Lf\n", soft, hard); X.ld=soft; fprintf(stderr, "WARNING: s[0]=%x s[1]=%x s[2]=%x ", X.i[0], X.i[1], X.i[2]); X.ld=hard; fprintf(stderr, "h[0]=%x h[1]=%x h[2]=%x\n", X.i[0], X.i[1], X.i[2]); nerrors++; } #endif /* * Veeeeery simple arbitrary precision code. * Interface similar to old libmp package. */ void minit(MINT *m) { m->sign = 0; m->len = 0; memset(m->val, 0, MAXMINT); } static void chomp(MINT *a) { while (a->len > 0 && a->val[a->len-1] == 0) a->len--; } static void neg2com(MINT *a) { uint32_t sum; int i; sum = 1; for (i = 0; i < a->len; i++) { a->val[i] = ~a->val[i]; sum = a->val[i] + sum; a->val[i] = sum; sum >>= 16; } } void mshl(MINT *a, int nbits) { int i, j; /* XXXXXXX must improve speed significantly */ for (j = 0; j < nbits; j++) { if (a->val[a->len-1] & 0x8000) { #ifdef DEBUGFP if (a->len >= MAXMINT) fpwarn("mshl: shifting out", 0, 0); #endif a->val[a->len++] = 0; } for (i = a->len-1; i > 0; i--) a->val[i] = (a->val[i] << 1) | (a->val[i-1] >> 15); a->val[i] = (a->val[i] << 1); } } void mdump(char *c, MINT *a) { int i; printf("%s: ", c); printf("len %d sign %d:\n", a->len, (unsigned)a->sign); for (i = 0; i < a->len; i++) printf("%05d: %04x\n", i, a->val[i]); } /* * add (and sub) uses 2-complement (for simplicity). */ void madd(MINT *a, MINT *b, MINT *c) { int32_t sum; int mx, i; chomp(a); chomp(b); /* ensure both numbers are the same size + 1 (for two-complement) */ mx = (b->len > a->len ? b->len : a->len) + 1; for (i = a->len; i < mx; i++) a->val[i] = 0; for (i = b->len; i < mx; i++) b->val[i] = 0; a->len = b->len = mx; if (a->sign) neg2com(a); if (b->sign) neg2com(b); sum = 0; for (i = 0; i < a->len; i++) { sum = a->val[i] + b->val[i] + sum; c->val[i] = sum; sum >>= 16; } c->len = a->len; if (c->val[c->len-1] & 0x8000) { neg2com(c); c->sign = 1; } else c->sign = 0; chomp(c); } void msub(MINT *a, MINT *b, MINT *c) { b->sign = !b->sign; madd(a, b, c); } void mult(MINT *a, MINT *b, MINT *c) { MINT *sw; uint32_t sum; int i, j; c->len = a->len + b->len; for (i = 0; i < c->len; i++) c->val[i] = 0; if (b->len > a->len) sw = a, a = b, b = sw; for(i = 0; i < b->len; i++) { sum = 0; for(j = 0; j < a->len; j++) { sum = c->val[j+i] + (uint32_t)a->val[j] * b->val[i] + sum; c->val[j+i] = sum; sum >>= 16; } c->val[j+i] = sum; } c->sign = (a->sign == b->sign) == 0; } static int geq(MINT *l, MINT *r) { int i; if (l->len > r->len) return 1; if (l->len < r->len) return 0; for (i = l->len-1; i >= 0; i--) { if (r->val[i] > l->val[i]) return 0; if (r->val[i] < l->val[i]) return 1; } return 1; } void mdiv(MINT *n, MINT *d, MINT *q, MINT *r) { MINT a, b; int i; minit(q); minit(r); chomp(n); chomp(d); for (i = 0; i < n->len; i++) q->val[i] = 0; q->len = n->len; for (i = n->len * 16 - 1; i >= 0; i--) { mshl(r, 1); if (r->len == 0) r->val[r->len++] = 0; r->val[0] |= (n->val[i/16] >> (i % 16)) & 1; if (geq(r, d)) { mcopy(d, &b); msub(r, &b, &a); mcopy(&a, r); q->val[i/16] |= (1 << (i % 16)); } } chomp(q); } pcc-20181216/common/softfloat.h010064400017500000000000000125441340100514100151210ustar raggewheel/* $Id: softfloat.h,v 1.15 2018/12/02 16:37:53 ragge Exp $ */ /* * Copyright (c) 2015 Anders Magnusson. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include /* * Definitions for softfloat routines. * * Floating point numbers will always be stored as the largest supported * float type (long double). This in turn will be stuffed bitwise into * an array of uint32_t for addressing. */ #ifndef CROSS_COMPILING #define DEBUGFP /* compare everything with native fp */ #endif typedef struct softfloat { union { uint32_t fp[(SZLDOUBLE+31)/32]; #ifdef DEBUGFP long double debugfp; #endif }; } SF; typedef SF *SFP; #define C(x,y) C2(x,y) #define C2(x,y) x##y #ifdef USE_IEEEFP_32 #define IEEEFP_32_RADIX 2 #define IEEEFP_32_DIG 6 #define IEEEFP_32_EPSILON 1.19209290E-07F #define IEEEFP_32_MAX_10_EXP +38 #define IEEEFP_32_MAX_EXP +128 #define IEEEFP_32_MAX 3.40282347E+38F #define IEEEFP_32_MIN_10_EXP -37 #define IEEEFP_32_MIN_EXP -125 #define IEEEFP_32_MIN 1.17549435E-38F #define IEEEFP_32_MANT_DIG 24 #define IEEEFP_32_HAS_SUBNORM 1 #endif #ifdef USE_IEEEFP_64 #define IEEEFP_64_DIG 15 #define IEEEFP_64_EPSILON 2.22044604925031308085e-16 #define IEEEFP_64_MAX_10_EXP 308 #define IEEEFP_64_MAX_EXP 1024 #define IEEEFP_64_MAX 1.79769313486231570815e+308 #define IEEEFP_64_MIN_10_EXP (-307) #define IEEEFP_64_MIN_EXP (-1021) #define IEEEFP_64_MIN 2.22507385850720138309e-308 #define IEEEFP_64_MANT_DIG 53 #endif #ifdef USE_IEEEFP_X80 #define IEEEFP_X80_DIG 18 #define IEEEFP_X80_EPSILON 1.08420217248550443401e-19L #define IEEEFP_X80_MAX_10_EXP 4932 #define IEEEFP_X80_MAX_EXP 16384 #define IEEEFP_X80_MAX 1.18973149535723176502e+4932L #define IEEEFP_X80_MIN_10_EXP (-4931) #define IEEEFP_X80_MIN_EXP (-16381) #define IEEEFP_X80_MIN 3.36210314311209350626e-4932L #define IEEEFP_X80_MANT_DIG 64 #endif #ifdef IEEEFP_128 #endif #define TARGET_FLT_RADIX C(FLT_FP,_RADIX) /* * Description of a floating point format, based what is in gdtoa package. * The first members are the same as in gdtoa, the rest are pcc specific. */ typedef struct FPI { int nbits; int emin; int emax; int rounding; int sudden_underflow:1; int explicit_one:1; /* if MSB is explicitely stored */ int has_inf_nan:1; /* highest exponent means INF and NaN */ int has_neg_zero:1; int has_radix_16:1; int storage; int exp_bias; } FPI; /* SF.kind values; same as STRTODG_* values */ enum { SF_Zero = 0, SF_Normal = 1, SF_Denormal = 2, SF_Infinite = 3, SF_NaN = 4, /* default quiet NaN */ SF_NaNbits = 5, /* (not used) */ SF_NoNumber = 6, /* signaling NaN */ SF_kmask = 7, /* The following may be or-ed into one of the above values. */ SF_Neg = 0x80, /* does not affect SFEXCP_Inex(lo|hi) */ SFEXCP_Inexlo = 0x100, /* returned result rounded toward zero */ SFEXCP_Inexhi = 0x200, /* returned result rounded away from zero */ SFEXCP_Inexact = 0x300, SFEXCP_Underflow= 0x400, SFEXCP_Overflow = 0x800, SFEXCP_DivByZero= 0x1000, SFEXCP_Invalid = 0x2000, SFEXCP_Aborted = 0x8000, /* Not IEEE; operation not performed */ SFEXCP_ALLmask = 0xFF00 /* All exceptions (mask) */ }; /* FPI.rounding values: same as FLT_ROUNDS */ enum { FPI_Round_zero = 0, /* same meaning as FE_TOWARDZERO */ FPI_Round_near = 1, /* same meaning as FE_TONEAREST */ FPI_Round_up = 2, /* same meaning as FE_UPWARD */ FPI_Round_down = 3, /* same meaning as FE_DOWNWARD */ /* Warning: if adding new modes, keep same meaning for 2 low bits. */ FPI_Round_near_from0 = 5, /* to nearest but ties up (Vax) */ FPI_RoundNotSet = -4, /* to implement dynamic rounding */ }; extern FPI * fpis[3]; /* FLOAT, DOUBLE, LDOUBLE, respectively */ #ifndef CC_DRIVER void soft_neg(SF *); void soft_int2fp(SFP, CONSZ p, TWORD f, TWORD v); CONSZ soft_fp2int(SF *p, TWORD v); void soft_fp2fp(SFP p, TWORD v); void soft_plus(SFP, SFP, TWORD); void soft_minus(SFP, SFP, TWORD); void soft_mul(SFP, SFP, TWORD); void soft_div(SFP, SFP, TWORD); int soft_cmp(SF*, SF*, int); int soft_isz(SF*); void strtosf(SFP, char *, TWORD); CONSZ soft_signbit(SF sf); int soft_isnan(SF sf); void soft_huge_val(SFP); void soft_nan(SFP, char *); uint32_t *soft_toush(SFP, TWORD, int *); #ifdef DEBUGFP void fpwarn(const char *s, long double soft, long double hard); #endif #endif pcc-20181216/common/strtodg.c010064400017500000000000002055101333212652500146130ustar raggewheel/* $Id: strtodg.c,v 1.2 2018/08/06 20:19:33 ragge Exp $ */ #define STRTODG_FOR_PCC #ifdef STRTODG_FOR_PCC /* * This is a derivation of (part of) the package gdtoa published by * David M. Gay and generally available as gdtoa.tgz at * http://www.netlib.org/fp/ * This package is a generalization of the strtod routine described in * David M. Gay, "Correctly Rounded Binary-Decimal and * Decimal-Binary Conversions", Numerical Analysis Manuscript * No. 90-10, Bell Labs, Murray Hill, 1990; * http://cm.bell-labs.com/cm/cs/what/ampl/REFS/rounding.ps.gz * * We used only the decimal->binary "generic" conversion, which is * exposed through the strtodg() function, along with all the support * routines it needs. We have concatenated the files * gdtoaimp.h * misc.c * gmisc.c * smisc.c * sum.c * hd_init.c * gethex.c * strtodg.c * removing the duplicated notices (first 32 lines.) * Then we have introduced small changes, mostly to silence compiler * warnings or to disable features we do not use. * Our functional changes are surrounded with STRTODG_FOR_PCC. * We stick to the naming and style conventions used in the original * package, to improve the "diffability" with it. * The reference version could thus be retrieved with sed -e "32q" gdtoaimp.h > strtodg.ref for f in gdtoaimp.h misc.c gmisc.c smisc.c sum.c hd_init.c gethex.c strtodg.c do sed -e "1,32d" $f >>strtodg.ref done * * Notes: * . An important distinction to do is between the target architecture, * which is generally described through the FPI structure; and the host * double floating-point, which is highly relied upon; variances * between the host implementations (IEEE or VAX, little- or big-endian) * should be detected at compile time, and are discrimated through the * source with the use of the macros IEEE_xxx or VAX (or IBM, untested.) * * Known issue: some compilers are reporting warnings about "shadowing * variables", because of the use of 'exp' as a variable name. */ /* Tailoring for PCC */ #define NO_INFNAN_CHECK #undef NO_HEX_FP #define No_Hex_NaN #define NO_ERRNO #undef USE_LOCALE #ifndef __MATH_H__ #define __MATH_H__ /* skip unnecessary math.h, and avoid troubles */ #endif #include "config.h" #if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) == 0 /* Try to guess the host floating-point implementation */ # if defined(vax) || defined(__vax__) #define VAX # elif defined(HOST_LITTLE_ENDIAN) #define IEEE_8087 # elif defined(HOST_BIG_ENDIAN) #define IEEE_MC68k # endif #endif #endif /* gdtoaimp.h */ /**************************************************************** The author of this software is David M. Gay. Copyright (C) 1998-2000 by Lucent Technologies All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that the copyright notice and this permission notice and warranty disclaimer appear in supporting documentation, and that the name of Lucent or any of its entities not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ****************************************************************/ /* This is a variation on dtoa.c that converts arbitary binary floating-point formats to and from decimal notation. It uses double-precision arithmetic internally, so there are still various #ifdefs that adapt the calculations to the native double-precision arithmetic (any of IEEE, VAX D_floating, or IBM mainframe arithmetic). Please send bug reports to David M. Gay (dmg at acm dot org, with " at " changed at "@" and " dot " changed to "."). */ #ifdef STRTODG_FOR_PCC /* (Irrelevant comment removed, to avoid being misled.) */ #endif /* strtod for IEEE-, VAX-, and IBM-arithmetic machines. * * This strtod returns a nearest machine number to the input decimal * string (or sets errno to ERANGE). With IEEE arithmetic, ties are * broken by the IEEE round-even rule. Otherwise ties are broken by * biased rounding (add half and chop). * * Inspired loosely by William D. Clinger's paper "How to Read Floating * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 112-126]. * * Modifications: * * 1. We only require IEEE, IBM, or VAX double-precision * arithmetic (not IEEE double-extended). * 2. We get by with floating-point arithmetic in a case that * Clinger missed -- when we're computing d * 10^n * for a small integer d and the integer n is not too * much larger than 22 (the maximum integer k for which * we can represent 10^k exactly), we may be able to * compute (d*10^k) * 10^(e-k) with just one roundoff. * 3. Rather than a bit-at-a-time adjustment of the binary * result in the hard case, we use floating-point * arithmetic to determine the adjustment to within * one bit; only in really hard cases do we need to * compute a second residual. * 4. Because of 3., we don't need a large table of powers of 10 * for ten-to-e (just some small tables, e.g. of 10^k * for 0 <= k <= 22). */ /* * #define IEEE_8087 for IEEE-arithmetic machines where the least * significant byte has the lowest address. * #define IEEE_MC68k for IEEE-arithmetic machines where the most * significant byte has the lowest address. * #define Long int on machines with 32-bit ints and 64-bit longs. * #define Sudden_Underflow for IEEE-format machines without gradual * underflow (i.e., that flush to zero on underflow). * #define IBM for IBM mainframe-style floating-point arithmetic. * #define VAX for VAX-style floating-point arithmetic (D_floating). * #define No_leftright to omit left-right logic in fast floating-point * computation of dtoa and gdtoa. This will cause modes 4 and 5 to be * treated the same as modes 2 and 3 for some inputs. * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3. * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines * that use extended-precision instructions to compute rounded * products and quotients) with IBM. * #define ROUND_BIASED for IEEE-format with biased rounding and arithmetic * that rounds toward +Infinity. * #define ROUND_BIASED_without_Round_Up for IEEE-format with biased * rounding when the underlying floating-point arithmetic uses * unbiased rounding. This prevent using ordinary floating-point * arithmetic when the result could be computed with one rounding error. * #define Inaccurate_Divide for IEEE-format with correctly rounded * products but inaccurate quotients, e.g., for Intel i860. * #define NO_LONG_LONG on machines that do not have a "long long" * integer type (of >= 64 bits). On such machines, you can * #define Just_16 to store 16 bits per 32-bit Long when doing * high-precision integer arithmetic. Whether this speeds things * up or slows things down depends on the machine and the number * being converted. If long long is available and the name is * something other than "long long", #define Llong to be the name, * and if "unsigned Llong" does not work as an unsigned version of * Llong, #define #ULLong to be the corresponding unsigned type. * #define KR_headers for old-style C function headers. * #define Bad_float_h if your system lacks a float.h or if it does not * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP, * FLT_RADIX, FLT_ROUNDS, and DBL_MAX. * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n) * if memory is available and otherwise does something you deem * appropriate. If MALLOC is undefined, malloc will be invoked * directly -- and assumed always to succeed. Similarly, if you * want something other than the system's free() to be called to * recycle memory acquired from MALLOC, #define FREE to be the * name of the alternate routine. (FREE or free is only called in * pathological cases, e.g., in a gdtoa call after a gdtoa return in * mode 3 with thousands of digits requested.) * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making * memory allocations from a private pool of memory when possible. * When used, the private pool is PRIVATE_MEM bytes long: 2304 bytes, * unless #defined to be a different length. This default length * suffices to get rid of MALLOC calls except for unusual cases, * such as decimal-to-binary conversion of a very long string of * digits. When converting IEEE double precision values, the * longest string gdtoa can return is about 751 bytes long. For * conversions by strtod of strings of 800 digits and all gdtoa * conversions of IEEE doubles in single-threaded executions with * 8-byte pointers, PRIVATE_MEM >= 7400 appears to suffice; with * 4-byte pointers, PRIVATE_MEM >= 7112 appears adequate. * #define NO_INFNAN_CHECK if you do not wish to have INFNAN_CHECK * #defined automatically on IEEE systems. On such systems, * when INFNAN_CHECK is #defined, strtod checks * for Infinity and NaN (case insensitively). * When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined, * strtodg also accepts (case insensitively) strings of the form * NaN(x), where x is a string of hexadecimal digits (optionally * preceded by 0x or 0X) and spaces; if there is only one string * of hexadecimal digits, it is taken for the fraction bits of the * resulting NaN; if there are two or more strings of hexadecimal * digits, each string is assigned to the next available sequence * of 32-bit words of fractions bits (starting with the most * significant), right-aligned in each sequence. * Unless GDTOA_NON_PEDANTIC_NANCHECK is #defined, input "NaN(...)" * is consumed even when ... has the wrong form (in which case the * "(...)" is consumed but ignored). * #define MULTIPLE_THREADS if the system offers preemptively scheduled * multiple threads. In this case, you must provide (or suitably * #define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed * by FREE_DTOA_LOCK(n) for n = 0 or 1. (The second lock, accessed * in pow5mult, ensures lazy evaluation of only one copy of high * powers of 5; omitting this lock would introduce a small * probability of wasting memory, but would otherwise be harmless.) * You must also invoke freedtoa(s) to free the value s returned by * dtoa. You may do so whether or not MULTIPLE_THREADS is #defined. * #define IMPRECISE_INEXACT if you do not care about the setting of * the STRTOG_Inexact bits in the special case of doing IEEE double * precision conversions (which could also be done by the strtod in * dtoa.c). * #define NO_HEX_FP to disable recognition of C9x's hexadecimal * floating-point constants. * #define -DNO_ERRNO to suppress setting errno (in strtod.c and * strtodg.c). * #define NO_STRING_H to use private versions of memcpy. * On some K&R systems, it may also be necessary to * #define DECLARE_SIZE_T in this case. * #define USE_LOCALE to use the current locale's decimal_point value. */ #ifndef GDTOAIMP_H_INCLUDED #define GDTOAIMP_H_INCLUDED #ifndef STRTODG_FOR_PCC #include "gdtoa.h" #include "gd_qnan.h" #else /* The public part has been moved to PCC headers */ #include "pass1.h" #undef FREE /* Do not mix apples with oranges... */ #define MALLOC(sz) tmpalloc(sz) #define FREE(p) /*nothing to do*/ /* Just provide the "ANSI C" wrappers, to improve "diffability" */ #define ANSI(x) x #define Void void #define CONST const #ifndef Long #define Long int /* Better support than int32_t or int_fast32_t. */ #endif #ifndef ULong typedef unsigned Long ULong; #endif #ifndef UShort typedef unsigned short UShort; #endif enum { /* return values from strtodg */ STRTOG_Zero = SF_Zero, /* required to be =0 */ STRTOG_Normal = SF_Normal, STRTOG_Denormal = SF_Denormal, STRTOG_Infinite = SF_Infinite, STRTOG_NaN = SF_NaN, STRTOG_NaNbits = SF_NaNbits, STRTOG_NoNumber = SF_NoNumber, STRTOG_Retmask = SF_kmask, /* The following may be or-ed into one of the above values. */ STRTOG_Neg = SF_Neg, /* does not affect STRTOG_Inexlo or STRTOG_Inexhi */ STRTOG_Inexlo = SFEXCP_Inexlo, /* returned result rounded toward zero */ STRTOG_Inexhi = SFEXCP_Inexhi, /* returned result rounded away from zero */ STRTOG_Inexact = SFEXCP_Inexact, STRTOG_Underflow= SFEXCP_Underflow, STRTOG_Overflow = SFEXCP_Overflow }; int strtodg (const char*, char**, FPI*, Long*, ULong*); #endif /* STRTODG_FOR_PCC */ #ifdef Honor_FLT_ROUNDS #include #endif #ifdef DEBUG #include "stdio.h" #define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);} #endif #include "stdlib.h" #include "string.h" #ifdef KR_headers #define Char char #else #define Char void #endif #ifdef MALLOC extern Char *MALLOC ANSI((size_t)); #else #define MALLOC malloc #endif #undef IEEE_Arith #undef Avoid_Underflow #ifdef IEEE_MC68k #define IEEE_Arith #endif #ifdef IEEE_8087 #define IEEE_Arith #endif #include "errno.h" #ifdef Bad_float_h #ifdef IEEE_Arith #define DBL_DIG 15 #define DBL_MAX_10_EXP 308 #define DBL_MAX_EXP 1024 #define FLT_RADIX 2 #define DBL_MAX 1.7976931348623157e+308 #endif #ifdef IBM #define DBL_DIG 16 #define DBL_MAX_10_EXP 75 #define DBL_MAX_EXP 63 #define FLT_RADIX 16 #define DBL_MAX 7.2370055773322621e+75 #endif #ifdef VAX #define DBL_DIG 16 #define DBL_MAX_10_EXP 38 #define DBL_MAX_EXP 127 #define FLT_RADIX 2 #define DBL_MAX 1.7014118346046923e+38 #define n_bigtens 2 #endif #ifndef LONG_MAX #define LONG_MAX 2147483647 #endif #else /* ifndef Bad_float_h */ #include "float.h" #endif /* Bad_float_h */ #ifdef IEEE_Arith #define Scale_Bit 0x10 #define n_bigtens 5 #endif #ifdef IBM #define n_bigtens 3 #endif #ifdef VAX #define n_bigtens 2 #endif #ifndef __MATH_H__ #include "math.h" #endif #ifdef __cplusplus extern "C" { #endif #if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) != 1 Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined. #endif typedef union { double d; ULong L[2]; } U; #ifdef IEEE_8087 #define word0(x) (x)->L[1] #define word1(x) (x)->L[0] #else #define word0(x) (x)->L[0] #define word1(x) (x)->L[1] #endif #define dval(x) (x)->d /* The following definition of Storeinc is appropriate for MIPS processors. * An alternative that might be better on some machines is * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff) */ #if defined(IEEE_8087) + defined(VAX) #define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \ ((unsigned short *)a)[0] = (unsigned short)c, a++) #else #define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \ ((unsigned short *)a)[1] = (unsigned short)c, a++) #endif /* #define P DBL_MANT_DIG */ /* Ten_pmax = floor(P*log(2)/log(5)) */ /* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */ /* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */ /* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */ #ifdef IEEE_Arith #define Exp_shift 20 #define Exp_shift1 20 #define Exp_msk1 0x100000 #define Exp_msk11 0x100000 #define Exp_mask 0x7ff00000 #define P 53 #define Bias 1023 #define Emin (-1022) #define Exp_1 0x3ff00000 #define Exp_11 0x3ff00000 #define Ebits 11 #define Frac_mask 0xfffff #define Frac_mask1 0xfffff #define Ten_pmax 22 #define Bletch 0x10 #define Bndry_mask 0xfffff #define Bndry_mask1 0xfffff #define LSB 1 #define Sign_bit 0x80000000 #define Log2P 1 #define Tiny0 0 #define Tiny1 1 #define Quick_max 14 #define Int_max 14 #ifndef Flt_Rounds #ifdef FLT_ROUNDS #define Flt_Rounds FLT_ROUNDS #else #define Flt_Rounds 1 #endif #endif /*Flt_Rounds*/ #else /* ifndef IEEE_Arith */ #undef Sudden_Underflow #define Sudden_Underflow #ifdef IBM #undef Flt_Rounds #define Flt_Rounds 0 #define Exp_shift 24 #define Exp_shift1 24 #define Exp_msk1 0x1000000 #define Exp_msk11 0x1000000 #define Exp_mask 0x7f000000 #define P 14 #define Bias 65 #define Exp_1 0x41000000 #define Exp_11 0x41000000 #define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */ #define Frac_mask 0xffffff #define Frac_mask1 0xffffff #define Bletch 4 #define Ten_pmax 22 #define Bndry_mask 0xefffff #define Bndry_mask1 0xffffff #define LSB 1 #define Sign_bit 0x80000000 #define Log2P 4 #define Tiny0 0x100000 #define Tiny1 0 #define Quick_max 14 #define Int_max 15 #else /* VAX */ #undef Flt_Rounds #define Flt_Rounds 1 #define Exp_shift 23 #define Exp_shift1 7 #define Exp_msk1 0x80 #define Exp_msk11 0x800000 #define Exp_mask 0x7f80 #define P 56 #define Bias 129 #define Exp_1 0x40800000 #define Exp_11 0x4080 #define Ebits 8 #define Frac_mask 0x7fffff #define Frac_mask1 0xffff007f #define Ten_pmax 24 #define Bletch 2 #define Bndry_mask 0xffff007f #define Bndry_mask1 0xffff007f #define LSB 0x10000 #define Sign_bit 0x8000 #define Log2P 1 #define Tiny0 0x80 #define Tiny1 0 #define Quick_max 15 #define Int_max 15 #endif /* IBM, VAX */ #endif /* IEEE_Arith */ #ifndef IEEE_Arith #define ROUND_BIASED #else #ifdef ROUND_BIASED_without_Round_Up #undef ROUND_BIASED #define ROUND_BIASED #endif #endif #ifdef RND_PRODQUOT #define rounded_product(a,b) a = rnd_prod(a, b) #define rounded_quotient(a,b) a = rnd_quot(a, b) #ifdef KR_headers extern double rnd_prod(), rnd_quot(); #else extern double rnd_prod(double, double), rnd_quot(double, double); #endif #else #define rounded_product(a,b) a *= b #define rounded_quotient(a,b) a /= b #endif #define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1)) #define Big1 0xffffffff #undef Pack_16 #ifndef Pack_32 #define Pack_32 #endif #ifdef NO_LONG_LONG #undef ULLong #ifdef Just_16 #undef Pack_32 #define Pack_16 /* When Pack_32 is not defined, we store 16 bits per 32-bit Long. * This makes some inner loops simpler and sometimes saves work * during multiplications, but it often seems to make things slightly * slower. Hence the default is now to store 32 bits per Long. */ #endif #else /* long long available */ #ifndef Llong #define Llong long long #endif #ifndef ULLong #define ULLong unsigned Llong #endif #endif /* NO_LONG_LONG */ #ifdef Pack_32 #define ULbits 32 #define kshift 5 #define kmask 31 #define ALL_ON 0xffffffff #else #define ULbits 16 #define kshift 4 #define kmask 15 #define ALL_ON 0xffff #endif #ifndef MULTIPLE_THREADS #define ACQUIRE_DTOA_LOCK(n) /*nothing*/ #define FREE_DTOA_LOCK(n) /*nothing*/ #endif #define Kmax 9 struct Bigint { struct Bigint *next; int k, maxwds, sign, wds; ULong x[1]; }; typedef struct Bigint Bigint; #ifdef NO_STRING_H #ifdef DECLARE_SIZE_T typedef unsigned int size_t; #endif extern void memcpy_D2A ANSI((void*, const void*, size_t)); #define Bcopy(x,y) memcpy_D2A(&x->sign,&y->sign,y->wds*sizeof(ULong) + 2*sizeof(int)) #else /* !NO_STRING_H */ #define Bcopy(x,y) memcpy(&x->sign,&y->sign,y->wds*sizeof(ULong) + 2*sizeof(int)) #endif /* NO_STRING_H */ #define Balloc Balloc_D2A #define Bfree Bfree_D2A #define InfName InfName_D2A #define NanName NanName_D2A #define ULtoQ ULtoQ_D2A #define ULtof ULtof_D2A #define ULtod ULtod_D2A #define ULtodd ULtodd_D2A #define ULtox ULtox_D2A #define ULtoxL ULtoxL_D2A #define add_nanbits add_nanbits_D2A #define any_on any_on_D2A #define b2d b2d_D2A #define bigtens bigtens_D2A #define cmp cmp_D2A #define copybits copybits_D2A #define d2b d2b_D2A #define decrement decrement_D2A #define diff diff_D2A #define dtoa_result dtoa_result_D2A #define g__fmt g__fmt_D2A #define gethex gethex_D2A #define hexdig hexdig_D2A #define hexnan hexnan_D2A #define hi0bits(x) hi0bits_D2A((ULong)(x)) #define i2b i2b_D2A #define increment increment_D2A #define lo0bits lo0bits_D2A #define lshift lshift_D2A #define match match_D2A #define mult mult_D2A #define multadd multadd_D2A #define nrv_alloc nrv_alloc_D2A #define pow5mult pow5mult_D2A #define quorem quorem_D2A #define ratio ratio_D2A #define rshift rshift_D2A #define rv_alloc rv_alloc_D2A #define s2b s2b_D2A #define set_ones set_ones_D2A #define strcp strcp_D2A #define strtoIg strtoIg_D2A #define sum sum_D2A #define tens tens_D2A #define tinytens tinytens_D2A #define tinytens tinytens_D2A #define trailz trailz_D2A #define ulp ulp_D2A extern char *add_nanbits ANSI((char*, size_t, ULong*, int)); extern char *dtoa_result; #ifndef STRTODG_FOR_PCC extern CONST double bigtens[], tens[], tinytens[]; extern unsigned char hexdig[]; #endif extern const char *InfName[6], *NanName[3]; extern Bigint *Balloc ANSI((int)); extern void Bfree ANSI((Bigint*)); extern void ULtof ANSI((ULong*, ULong*, Long, int)); extern void ULtod ANSI((ULong*, ULong*, Long, int)); extern void ULtodd ANSI((ULong*, ULong*, Long, int)); extern void ULtoQ ANSI((ULong*, ULong*, Long, int)); extern void ULtox ANSI((UShort*, ULong*, Long, int)); extern void ULtoxL ANSI((ULong*, ULong*, Long, int)); extern ULong any_on ANSI((Bigint*, int)); extern double b2d ANSI((Bigint*, int*)); extern int cmp ANSI((Bigint*, Bigint*)); extern void copybits ANSI((ULong*, int, Bigint*)); extern Bigint *d2b ANSI((double, int*, int*)); extern void decrement ANSI((Bigint*)); extern Bigint *diff ANSI((Bigint*, Bigint*)); extern char *dtoa ANSI((double d, int mode, int ndigits, int *decpt, int *sign, char **rve)); extern char *g__fmt ANSI((char*, char*, char*, int, ULong, size_t)); extern int gethex ANSI((CONST char**, FPI*, Long*, Bigint**, int)); extern void hexdig_init_D2A(Void); extern int hexnan ANSI((CONST char**, FPI*, ULong*)); extern int hi0bits_D2A ANSI((ULong)); extern Bigint *i2b ANSI((int)); extern Bigint *increment ANSI((Bigint*)); extern int lo0bits ANSI((ULong*)); extern Bigint *lshift ANSI((Bigint*, int)); extern int match ANSI((CONST char**, char*)); extern Bigint *mult ANSI((Bigint*, Bigint*)); extern Bigint *multadd ANSI((Bigint*, int, int)); extern char *nrv_alloc ANSI((char*, char **, int)); extern Bigint *pow5mult ANSI((Bigint*, int)); extern int quorem ANSI((Bigint*, Bigint*)); extern double ratio ANSI((Bigint*, Bigint*)); extern void rshift ANSI((Bigint*, int)); extern char *rv_alloc ANSI((int)); extern Bigint *s2b ANSI((CONST char*, int, int, ULong, int)); extern Bigint *set_ones ANSI((Bigint*, int)); extern char *strcp ANSI((char*, const char*)); #ifndef STRTODG_FOR_PCC extern int strtoIg ANSI((CONST char*, char**, FPI*, Long*, Bigint**, int*)); extern double strtod ANSI((const char *s00, char **se)); #endif extern Bigint *sum ANSI((Bigint*, Bigint*)); extern int trailz ANSI((Bigint*)); extern double ulp ANSI((U*)); #ifdef __cplusplus } #endif #ifndef STRTODG_FOR_PCC /* No NaN stuff here */ /* * NAN_WORD0 and NAN_WORD1 are only referenced in strtod.c. Prior to * 20050115, they used to be hard-wired here (to 0x7ff80000 and 0, * respectively), but now are determined by compiling and running * qnan.c to generate gd_qnan.h, which specifies d_QNAN0 and d_QNAN1. * Formerly gdtoaimp.h recommended supplying suitable -DNAN_WORD0=... * and -DNAN_WORD1=... values if necessary. This should still work. * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.) */ #ifdef IEEE_Arith #ifndef NO_INFNAN_CHECK #undef INFNAN_CHECK #define INFNAN_CHECK #endif #ifdef IEEE_MC68k #define _0 0 #define _1 1 #ifndef NAN_WORD0 #define NAN_WORD0 d_QNAN0 #endif #ifndef NAN_WORD1 #define NAN_WORD1 d_QNAN1 #endif #else #define _0 1 #define _1 0 #ifndef NAN_WORD0 #define NAN_WORD0 d_QNAN1 #endif #ifndef NAN_WORD1 #define NAN_WORD1 d_QNAN0 #endif #endif #else #undef INFNAN_CHECK #endif #endif #undef SI #ifdef Sudden_Underflow #define SI 1 #else #define SI 0 #endif #endif /* GDTOAIMP_H_INCLUDED */ /* misc.c */ static Bigint *freelist[Kmax+1]; #ifndef Omit_Private_Memory #ifndef PRIVATE_MEM #define PRIVATE_MEM 2304 #endif #define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double)) static double private_mem[PRIVATE_mem], *pmem_next = private_mem; #endif Bigint * Balloc #ifdef KR_headers (k) int k; #else (int k) #endif { int x; Bigint *rv; #ifndef Omit_Private_Memory unsigned int len; #endif ACQUIRE_DTOA_LOCK(0); /* The k > Kmax case does not need ACQUIRE_DTOA_LOCK(0), */ /* but this case seems very unlikely. */ if (k <= Kmax && (rv = freelist[k]) !=0) { freelist[k] = rv->next; } else { x = 1 << k; #ifdef Omit_Private_Memory rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); #else len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) /sizeof(double); if (k <= Kmax && pmem_next - private_mem + len <= PRIVATE_mem) { rv = (Bigint*)pmem_next; pmem_next += len; } else rv = (Bigint*)MALLOC(len*sizeof(double)); #endif rv->k = k; rv->maxwds = x; } FREE_DTOA_LOCK(0); rv->sign = rv->wds = 0; return rv; } void Bfree #ifdef KR_headers (v) Bigint *v; #else (Bigint *v) #endif { if (v) { if (v->k > Kmax) #ifdef FREE FREE((void*)v); #else free((void*)v); #endif else { ACQUIRE_DTOA_LOCK(0); v->next = freelist[v->k]; freelist[v->k] = v; FREE_DTOA_LOCK(0); } } } int lo0bits #ifdef KR_headers (y) ULong *y; #else (ULong *y) #endif { int k; ULong x = *y; if (x & 7) { if (x & 1) return 0; if (x & 2) { *y = x >> 1; return 1; } *y = x >> 2; return 2; } k = 0; if (!(x & 0xffff)) { k = 16; x >>= 16; } if (!(x & 0xff)) { k += 8; x >>= 8; } if (!(x & 0xf)) { k += 4; x >>= 4; } if (!(x & 0x3)) { k += 2; x >>= 2; } if (!(x & 1)) { k++; x >>= 1; if (!x) return 32; } *y = x; return k; } Bigint * multadd #ifdef KR_headers (b, m, a) Bigint *b; int m, a; #else (Bigint *b, int m, int a) /* multiply by m and add a */ #endif { int i, wds; #ifdef ULLong ULong *x; ULLong carry, y; #else ULong carry, *x, y; #ifdef Pack_32 ULong xi, z; #endif #endif Bigint *b1; wds = b->wds; x = b->x; i = 0; carry = a; do { #ifdef ULLong y = *x * (ULLong)m + carry; carry = y >> 32; *x++ = (ULong)y & 0xffffffffUL; #else #ifdef Pack_32 xi = *x; y = (xi & 0xffff) * m + carry; z = (xi >> 16) * m + (y >> 16); carry = z >> 16; *x++ = (z << 16) + (y & 0xffff); #else y = *x * m + carry; carry = y >> 16; *x++ = y & 0xffff; #endif #endif } while(++i < wds); if (carry) { if (wds >= b->maxwds) { b1 = Balloc(b->k+1); Bcopy(b1, b); Bfree(b); b = b1; } b->x[wds++] = (ULong)carry; b->wds = wds; } return b; } int hi0bits_D2A #ifdef KR_headers (x) ULong x; #else (ULong x) #endif { int k = 0; if (!(x & 0xffff0000)) { k = 16; x <<= 16; } if (!(x & 0xff000000)) { k += 8; x <<= 8; } if (!(x & 0xf0000000)) { k += 4; x <<= 4; } if (!(x & 0xc0000000)) { k += 2; x <<= 2; } if (!(x & 0x80000000)) { k++; if (!(x & 0x40000000)) return 32; } return k; } Bigint * i2b #ifdef KR_headers (i) int i; #else (int i) #endif { Bigint *b; b = Balloc(1); b->x[0] = i; b->wds = 1; return b; } Bigint * mult #ifdef KR_headers (a, b) Bigint *a, *b; #else (Bigint *a, Bigint *b) #endif { Bigint *c; int k, wa, wb, wc; ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0; ULong y; #ifdef ULLong ULLong carry, z; #else ULong carry, z; #ifdef Pack_32 ULong z2; #endif #endif if (a->wds < b->wds) { c = a; a = b; b = c; } k = a->k; wa = a->wds; wb = b->wds; wc = wa + wb; if (wc > a->maxwds) k++; c = Balloc(k); for(x = c->x, xa = x + wc; x < xa; x++) *x = 0; xa = a->x; xae = xa + wa; xb = b->x; xbe = xb + wb; xc0 = c->x; #ifdef ULLong for(; xb < xbe; xc0++) { if ( (y = *xb++) !=0) { x = xa; xc = xc0; carry = 0; do { z = *x++ * (ULLong)y + *xc + carry; carry = z >> 32; *xc++ = z & 0xffffffffUL; } while(x < xae); *xc = carry; } } #else #ifdef Pack_32 for(; xb < xbe; xb++, xc0++) { if ( (y = *xb & 0xffff) !=0) { x = xa; xc = xc0; carry = 0; do { z = (*x & 0xffff) * y + (*xc & 0xffff) + carry; carry = z >> 16; z2 = (*x++ >> 16) * y + (*xc >> 16) + carry; carry = z2 >> 16; Storeinc(xc, z2, z); } while(x < xae); *xc = carry; } if ( (y = *xb >> 16) !=0) { x = xa; xc = xc0; carry = 0; z2 = *xc; do { z = (*x & 0xffff) * y + (*xc >> 16) + carry; carry = z >> 16; Storeinc(xc, z, z2); z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry; carry = z2 >> 16; } while(x < xae); *xc = z2; } } #else for(; xb < xbe; xc0++) { if ( (y = *xb++) !=0) { x = xa; xc = xc0; carry = 0; do { z = *x++ * y + *xc + carry; carry = z >> 16; *xc++ = z & 0xffff; } while(x < xae); *xc = carry; } } #endif #endif for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ; c->wds = wc; return c; } static Bigint *p5s; Bigint * pow5mult #ifdef KR_headers (b, k) Bigint *b; int k; #else (Bigint *b, int k) #endif { Bigint *b1, *p5, *p51; int i; static int p05[3] = { 5, 25, 125 }; if ( (i = k & 3) !=0) b = multadd(b, p05[i-1], 0); if (!(k >>= 2)) return b; if ((p5 = p5s) == 0) { /* first time */ #ifdef MULTIPLE_THREADS ACQUIRE_DTOA_LOCK(1); if (!(p5 = p5s)) { p5 = p5s = i2b(625); p5->next = 0; } FREE_DTOA_LOCK(1); #else p5 = p5s = i2b(625); p5->next = 0; #endif } for(;;) { if (k & 1) { b1 = mult(b, p5); Bfree(b); b = b1; } if (!(k >>= 1)) break; if ((p51 = p5->next) == 0) { #ifdef MULTIPLE_THREADS ACQUIRE_DTOA_LOCK(1); if (!(p51 = p5->next)) { p51 = p5->next = mult(p5,p5); p51->next = 0; } FREE_DTOA_LOCK(1); #else p51 = p5->next = mult(p5,p5); p51->next = 0; #endif } p5 = p51; } return b; } Bigint * lshift #ifdef KR_headers (b, k) Bigint *b; int k; #else (Bigint *b, int k) #endif { int i, k1, n, n1; Bigint *b1; ULong *x, *x1, *xe, z; n = k >> kshift; k1 = b->k; n1 = n + b->wds + 1; for(i = b->maxwds; n1 > i; i <<= 1) k1++; b1 = Balloc(k1); x1 = b1->x; for(i = 0; i < n; i++) *x1++ = 0; x = b->x; xe = x + b->wds; if (k &= kmask) { #ifdef Pack_32 k1 = 32 - k; z = 0; do { *x1++ = *x << k | z; z = *x++ >> k1; } while(x < xe); if ((*x1 = z) !=0) ++n1; #else k1 = 16 - k; z = 0; do { *x1++ = *x << k & 0xffff | z; z = *x++ >> k1; } while(x < xe); if (*x1 = z) ++n1; #endif } else do *x1++ = *x++; while(x < xe); b1->wds = n1 - 1; Bfree(b); return b1; } int cmp #ifdef KR_headers (a, b) Bigint *a, *b; #else (Bigint *a, Bigint *b) #endif { ULong *xa, *xa0, *xb, *xb0; int i, j; i = a->wds; j = b->wds; #ifdef DEBUG if (i > 1 && !a->x[i-1]) Bug("cmp called with a->x[a->wds-1] == 0"); if (j > 1 && !b->x[j-1]) Bug("cmp called with b->x[b->wds-1] == 0"); #endif if (i -= j) return i; xa0 = a->x; xa = xa0 + j; xb0 = b->x; xb = xb0 + j; for(;;) { if (*--xa != *--xb) return *xa < *xb ? -1 : 1; if (xa <= xa0) break; } return 0; } Bigint * diff #ifdef KR_headers (a, b) Bigint *a, *b; #else (Bigint *a, Bigint *b) #endif { Bigint *c; int i, wa, wb; ULong *xa, *xae, *xb, *xbe, *xc; #ifdef ULLong ULLong borrow, y; #else ULong borrow, y; #ifdef Pack_32 ULong z; #endif #endif i = cmp(a,b); if (!i) { c = Balloc(0); c->wds = 1; c->x[0] = 0; return c; } if (i < 0) { c = a; a = b; b = c; i = 1; } else i = 0; c = Balloc(a->k); c->sign = i; wa = a->wds; xa = a->x; xae = xa + wa; wb = b->wds; xb = b->x; xbe = xb + wb; xc = c->x; borrow = 0; #ifdef ULLong do { y = (ULLong)*xa++ - *xb++ - borrow; borrow = y >> 32 & 1UL; *xc++ = y & 0xffffffffUL; } while(xb < xbe); while(xa < xae) { y = *xa++ - borrow; borrow = y >> 32 & 1UL; *xc++ = y & 0xffffffffUL; } #else #ifdef Pack_32 do { y = (*xa & 0xffff) - (*xb & 0xffff) - borrow; borrow = (y & 0x10000) >> 16; z = (*xa++ >> 16) - (*xb++ >> 16) - borrow; borrow = (z & 0x10000) >> 16; Storeinc(xc, z, y); } while(xb < xbe); while(xa < xae) { y = (*xa & 0xffff) - borrow; borrow = (y & 0x10000) >> 16; z = (*xa++ >> 16) - borrow; borrow = (z & 0x10000) >> 16; Storeinc(xc, z, y); } #else do { y = *xa++ - *xb++ - borrow; borrow = (y & 0x10000) >> 16; *xc++ = y & 0xffff; } while(xb < xbe); while(xa < xae) { y = *xa++ - borrow; borrow = (y & 0x10000) >> 16; *xc++ = y & 0xffff; } #endif #endif while(!*--xc) wa--; c->wds = wa; return c; } double b2d #ifdef KR_headers (a, e) Bigint *a; int *e; #else (Bigint *a, int *e) #endif { ULong *xa, *xa0, w, y, z; int k; U d; #ifdef VAX ULong d0, d1; #else #define d0 word0(&d) #define d1 word1(&d) #endif xa0 = a->x; xa = xa0 + a->wds; y = *--xa; #ifdef DEBUG if (!y) Bug("zero y in b2d"); #endif k = hi0bits(y); *e = 32 - k; #ifdef Pack_32 if (k < Ebits) { d0 = Exp_1 | y >> (Ebits - k); w = xa > xa0 ? *--xa : 0; d1 = y << ((32-Ebits) + k) | w >> (Ebits - k); goto ret_d; } z = xa > xa0 ? *--xa : 0; if (k -= Ebits) { d0 = Exp_1 | y << k | z >> (32 - k); y = xa > xa0 ? *--xa : 0; d1 = z << k | y >> (32 - k); } else { d0 = Exp_1 | y; d1 = z; } #else if (k < Ebits + 16) { z = xa > xa0 ? *--xa : 0; d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k; w = xa > xa0 ? *--xa : 0; y = xa > xa0 ? *--xa : 0; d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k; goto ret_d; } z = xa > xa0 ? *--xa : 0; w = xa > xa0 ? *--xa : 0; k -= Ebits + 16; d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k; y = xa > xa0 ? *--xa : 0; d1 = w << k + 16 | y << k; #endif ret_d: #ifdef VAX word0(&d) = d0 >> 16 | d0 << 16; word1(&d) = d1 >> 16 | d1 << 16; #endif return dval(&d); } #undef d0 #undef d1 Bigint * d2b #ifdef KR_headers (dd, e, bits) double dd; int *e, *bits; #else (double dd, int *e, int *bits) #endif { Bigint *b; U d; #ifndef Sudden_Underflow int i; #endif int de, k; ULong *x, y, z; #ifdef VAX ULong d0, d1; #else #define d0 word0(&d) #define d1 word1(&d) #endif d.d = dd; #ifdef VAX d0 = word0(&d) >> 16 | word0(&d) << 16; d1 = word1(&d) >> 16 | word1(&d) << 16; #endif #ifdef Pack_32 b = Balloc(1); #else b = Balloc(2); #endif x = b->x; z = d0 & Frac_mask; d0 &= 0x7fffffff; /* clear sign bit, which we ignore */ #ifdef Sudden_Underflow de = (int)(d0 >> Exp_shift); #ifndef IBM z |= Exp_msk11; #endif #else if ( (de = (int)(d0 >> Exp_shift)) !=0) z |= Exp_msk1; #endif #ifdef Pack_32 if ( (y = d1) !=0) { if ( (k = lo0bits(&y)) !=0) { x[0] = y | z << (32 - k); z >>= k; } else x[0] = y; #ifndef Sudden_Underflow i = #endif b->wds = (x[1] = z) !=0 ? 2 : 1; } else { k = lo0bits(&z); x[0] = z; #ifndef Sudden_Underflow i = #endif b->wds = 1; k += 32; } #else if ( (y = d1) !=0) { if ( (k = lo0bits(&y)) !=0) if (k >= 16) { x[0] = y | z << 32 - k & 0xffff; x[1] = z >> k - 16 & 0xffff; x[2] = z >> k; i = 2; } else { x[0] = y & 0xffff; x[1] = y >> 16 | z << 16 - k & 0xffff; x[2] = z >> k & 0xffff; x[3] = z >> k+16; i = 3; } else { x[0] = y & 0xffff; x[1] = y >> 16; x[2] = z & 0xffff; x[3] = z >> 16; i = 3; } } else { #ifdef DEBUG if (!z) Bug("Zero passed to d2b"); #endif k = lo0bits(&z); if (k >= 16) { x[0] = z; i = 0; } else { x[0] = z & 0xffff; x[1] = z >> 16; i = 1; } k += 32; } while(!x[i]) --i; b->wds = i + 1; #endif #ifndef Sudden_Underflow if (de) { #endif #ifdef IBM *e = (de - Bias - (P-1) << 2) + k; *bits = 4*P + 8 - k - hi0bits(word0(&d) & Frac_mask); #else *e = de - Bias - (P-1) + k; *bits = P - k; #endif #ifndef Sudden_Underflow } else { *e = de - Bias - (P-1) + 1 + k; #ifdef Pack_32 *bits = 32*i - hi0bits(x[i-1]); #else *bits = (i+2)*16 - hi0bits(x[i]); #endif } #endif return b; } #undef d0 #undef d1 CONST double #ifdef IEEE_Arith bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 }; CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, 1e-256 }; #else #ifdef IBM bigtens[] = { 1e16, 1e32, 1e64 }; CONST double tinytens[] = { 1e-16, 1e-32, 1e-64 }; #else bigtens[] = { 1e16, 1e32 }; CONST double tinytens[] = { 1e-16, 1e-32 }; #endif #endif CONST double tens[] = { 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22 #ifdef VAX , 1e23, 1e24 #endif }; char * #ifdef KR_headers strcp_D2A(a, b) char *a; char *b; #else strcp_D2A(char *a, CONST char *b) #endif { while((*a = *b++)) a++; return a; } #ifdef NO_STRING_H Char * #ifdef KR_headers memcpy_D2A(a, b, len) Char *a; Char *b; size_t len; #else memcpy_D2A(void *a1, void *b1, size_t len) #endif { char *a = (char*)a1, *ae = a + len; char *b = (char*)b1, *a0 = a; while(a < ae) *a++ = *b++; return a0; } #endif /* NO_STRING_H */ /* gmisc.c */ void #ifdef KR_headers rshift(b, k) Bigint *b; int k; #else rshift(Bigint *b, int k) #endif { ULong *x, *x1, *xe, y; int n; x = x1 = b->x; n = k >> kshift; if (n < b->wds) { xe = x + b->wds; x += n; if (k &= kmask) { n = ULbits - k; y = *x++ >> k; while(x < xe) { *x1++ = (y | (*x << n)) & ALL_ON; y = *x++ >> k; } if ((*x1 = y) !=0) x1++; } else while(x < xe) *x1++ = *x++; } if ((b->wds = x1 - b->x) == 0) b->x[0] = 0; } int #ifdef KR_headers trailz(b) Bigint *b; #else trailz(Bigint *b) #endif { ULong L, *x, *xe; int n = 0; x = b->x; xe = x + b->wds; for(n = 0; x < xe && !*x; x++) n += ULbits; if (x < xe) { L = *x; n += lo0bits(&L); } return n; } /* smisc.c */ Bigint * s2b #ifdef KR_headers (s, nd0, nd, y9, dplen) CONST char *s; int dplen, nd0, nd; ULong y9; #else (CONST char *s, int nd0, int nd, ULong y9, int dplen) #endif { Bigint *b; int i, k; Long x, y; x = (nd + 8) / 9; for(k = 0, y = 1; x > y; y <<= 1, k++) ; #ifdef Pack_32 b = Balloc(k); b->x[0] = y9; b->wds = 1; #else b = Balloc(k+1); b->x[0] = y9 & 0xffff; b->wds = (b->x[1] = y9 >> 16) ? 2 : 1; #endif i = 9; if (9 < nd0) { s += 9; do b = multadd(b, 10, *s++ - '0'); while(++i < nd0); s += dplen; } else s += dplen + 9; for(; i < nd; i++) b = multadd(b, 10, *s++ - '0'); return b; } double ratio #ifdef KR_headers (a, b) Bigint *a, *b; #else (Bigint *a, Bigint *b) #endif { U da, db; int k, ka, kb; dval(&da) = b2d(a, &ka); dval(&db) = b2d(b, &kb); k = ka - kb + ULbits*(a->wds - b->wds); #ifdef IBM if (k > 0) { word0(&da) += (k >> 2)*Exp_msk1; if (k &= 3) dval(&da) *= 1 << k; } else { k = -k; word0(&db) += (k >> 2)*Exp_msk1; if (k &= 3) dval(&db) *= 1 << k; } #else if (k > 0) word0(&da) += k*Exp_msk1; else { k = -k; word0(&db) += k*Exp_msk1; } #endif return dval(&da) / dval(&db); } #ifdef INFNAN_CHECK int match #ifdef KR_headers (sp, t) char **sp, *t; #else (CONST char **sp, char *t) #endif { int c, d; CONST char *s = *sp; while( (d = *t++) !=0) { if ((c = *++s) >= 'A' && c <= 'Z') c += 'a' - 'A'; if (c != d) return 0; } *sp = s + 1; return 1; } #endif /* INFNAN_CHECK */ void #ifdef KR_headers copybits(c, n, b) ULong *c; int n; Bigint *b; #else copybits(ULong *c, int n, Bigint *b) #endif { ULong *ce, *x, *xe; #ifdef Pack_16 int nw, nw1; #endif ce = c + ((n-1) >> kshift) + 1; x = b->x; #ifdef Pack_32 xe = x + b->wds; while(x < xe) *c++ = *x++; #else nw = b->wds; nw1 = nw & 1; for(xe = x + (nw - nw1); x < xe; x += 2) Storeinc(c, x[1], x[0]); if (nw1) *c++ = *x; #endif while(c < ce) *c++ = 0; } ULong #ifdef KR_headers any_on(b, k) Bigint *b; int k; #else any_on(Bigint *b, int k) #endif { int n, nwds; ULong *x, *x0, x1, x2; x = b->x; nwds = b->wds; n = k >> kshift; if (n > nwds) n = nwds; else if (n < nwds && (k &= kmask)) { x1 = x2 = x[n]; x1 >>= k; x1 <<= k; if (x1 != x2) return 1; } x0 = x; x += n; while(x > x0) if (*--x) return 1; return 0; } /* sum.c */ Bigint * #ifdef KR_headers sum(a, b) Bigint *a; Bigint *b; #else sum(Bigint *a, Bigint *b) #endif { Bigint *c; ULong carry, *xc, *xa, *xb, *xe, y; #ifdef Pack_32 ULong z; #endif if (a->wds < b->wds) { c = b; b = a; a = c; } c = Balloc(a->k); c->wds = a->wds; carry = 0; xa = a->x; xb = b->x; xc = c->x; xe = xc + b->wds; #ifdef Pack_32 do { y = (*xa & 0xffff) + (*xb & 0xffff) + carry; carry = (y & 0x10000) >> 16; z = (*xa++ >> 16) + (*xb++ >> 16) + carry; carry = (z & 0x10000) >> 16; Storeinc(xc, z, y); } while(xc < xe); xe += a->wds - b->wds; while(xc < xe) { y = (*xa & 0xffff) + carry; carry = (y & 0x10000) >> 16; z = (*xa++ >> 16) + carry; carry = (z & 0x10000) >> 16; Storeinc(xc, z, y); } #else do { y = *xa++ + *xb++ + carry; carry = (y & 0x10000) >> 16; *xc++ = y & 0xffff; } while(xc < xe); xe += a->wds - b->wds; while(xc < xe) { y = *xa++ + carry; carry = (y & 0x10000) >> 16; *xc++ = y & 0xffff; } #endif if (carry) { if (c->wds == c->maxwds) { b = Balloc(c->k + 1); Bcopy(b, c); Bfree(c); c = b; } c->x[c->wds++] = 1; } return c; } /* hd_init.c */ #if 0 unsigned char hexdig[256]; static void #ifdef KR_headers htinit(h, s, inc) unsigned char *h; unsigned char *s; int inc; #else htinit(unsigned char *h, unsigned char *s, int inc) #endif { int i, j; for(i = 0; (j = s[i]) !=0; i++) h[j] = i + inc; } void hexdig_init_D2A(Void) /* Use of hexdig_init omitted 20121220 to avoid a */ /* race condition when multiple threads are used. */ { #define USC (unsigned char *) htinit(hexdig, USC "0123456789", 0x10); htinit(hexdig, USC "abcdef", 0x10 + 10); htinit(hexdig, USC "ABCDEF", 0x10 + 10); } #else unsigned char hexdig[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 16,17,18,19,20,21,22,23,24,25,0,0,0,0,0,0, 0,26,27,28,29,30,31,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,26,27,28,29,30,31,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; #endif /* gethex.c */ #ifdef USE_LOCALE #include "locale.h" #endif int #ifdef KR_headers gethex(sp, fpi, exp, bp, sign) CONST char **sp; FPI *fpi; Long *exp; Bigint **bp; int sign; #else gethex( CONST char **sp, FPI *fpi, Long *exp, Bigint **bp, int sign) #endif { Bigint *b; CONST unsigned char *decpt, *s0, *s, *s1; int big, esign, havedig, irv, j, k, n, n0, nbits, up, zret; ULong L, lostbits, *x; Long e, e1; #ifdef USE_LOCALE int i; #ifdef NO_LOCALE_CACHE const unsigned char *decimalpoint = (unsigned char*)localeconv()->decimal_point; #else const unsigned char *decimalpoint; static unsigned char *decimalpoint_cache; if (!(s0 = decimalpoint_cache)) { s0 = (unsigned char*)localeconv()->decimal_point; if ((decimalpoint_cache = (char*)MALLOC(strlen(s0) + 1))) { strcpy(decimalpoint_cache, s0); s0 = decimalpoint_cache; } } decimalpoint = s0; #endif #endif /**** if (!hexdig['0']) hexdig_init_D2A(); ****/ *bp = 0; havedig = 0; s0 = *(CONST unsigned char **)sp + 2; while(s0[havedig] == '0') havedig++; s0 += havedig; s = s0; decpt = 0; zret = 0; e = 0; if (hexdig[*s]) havedig++; else { zret = 1; #ifdef USE_LOCALE for(i = 0; decimalpoint[i]; ++i) { if (s[i] != decimalpoint[i]) goto pcheck; } decpt = s += i; #else if (*s != '.') goto pcheck; decpt = ++s; #endif if (!hexdig[*s]) goto pcheck; while(*s == '0') s++; if (hexdig[*s]) zret = 0; havedig = 1; s0 = s; } while(hexdig[*s]) s++; #ifdef USE_LOCALE if (*s == *decimalpoint && !decpt) { for(i = 1; decimalpoint[i]; ++i) { if (s[i] != decimalpoint[i]) goto pcheck; } decpt = s += i; #else if (*s == '.' && !decpt) { decpt = ++s; #endif while(hexdig[*s]) s++; }/*}*/ if (decpt) e = -(((Long)(s-decpt)) << 2); pcheck: s1 = s; big = esign = 0; switch(*s) { case 'p': case 'P': switch(*++s) { case '-': esign = 1; /* no break */ case '+': s++; } if ((n = hexdig[*s]) == 0 || n > 0x19) { s = s1; break; } e1 = n - 0x10; while((n = hexdig[*++s]) !=0 && n <= 0x19) { if (e1 & 0xf8000000) big = 1; e1 = 10*e1 + n - 0x10; } if (esign) e1 = -e1; e += e1; } *sp = (char*)s; if (!havedig) *sp = (char*)s0 - 1; if (zret) return STRTOG_Zero; if (big) { if (esign) { #ifdef STRTODG_FOR_PCC if (! fpi->sudden_underflow) #endif switch(fpi->rounding) { case FPI_Round_up: if (sign) break; goto ret_tiny; case FPI_Round_down: if (!sign) break; goto ret_tiny; } goto retz; ret_tiny: b = Balloc(0); b->wds = 1; b->x[0] = 1; goto dret; } switch(fpi->rounding) { case FPI_Round_near: goto ovfl1; case FPI_Round_up: if (!sign) goto ovfl1; goto ret_big; case FPI_Round_down: if (sign) goto ovfl1; goto ret_big; } ret_big: nbits = fpi->nbits; n0 = n = nbits >> kshift; if (nbits & kmask) ++n; for(j = n, k = 0; j >>= 1; ++k); *bp = b = Balloc(k); b->wds = n; for(j = 0; j < n0; ++j) b->x[j] = ALL_ON; if (n > n0) b->x[j] = ULbits >> (ULbits - (nbits & kmask)); *exp = fpi->emin; return STRTOG_Normal | STRTOG_Inexlo; } n = s1 - s0 - 1; for(k = 0; n > (1 << (kshift-2)) - 1; n >>= 1) k++; b = Balloc(k); x = b->x; n = 0; L = 0; #ifdef USE_LOCALE for(i = 0; decimalpoint[i+1]; ++i); #endif while(s1 > s0) { #ifdef USE_LOCALE if (*--s1 == decimalpoint[i]) { s1 -= i; continue; } #else if (*--s1 == '.') continue; #endif if (n == ULbits) { *x++ = L; L = 0; n = 0; } L |= (hexdig[*s1] & 0x0f) << n; n += 4; } *x++ = L; b->wds = n = x - b->x; n = ULbits*n - hi0bits(L); nbits = fpi->nbits; lostbits = 0; x = b->x; if (n > nbits) { n -= nbits; if (any_on(b,n)) { lostbits = 1; k = n - 1; if (x[k>>kshift] & 1 << (k & kmask)) { lostbits = 2; if (k > 0 && any_on(b,k)) lostbits = 3; } } rshift(b, n); e += n; } else if (n < nbits) { n = nbits - n; b = lshift(b, n); e -= n; x = b->x; } if (e > fpi->emax) { ovfl: Bfree(b); ovfl1: #ifndef NO_ERRNO errno = ERANGE; #endif #ifdef STRTODG_FOR_PCC *exp = fpi->emax + 1; #endif return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi; } irv = STRTOG_Normal; if (e < fpi->emin) { #ifdef STRTODG_FOR_PCC if (fpi->sudden_underflow) { Bfree(b); goto retz; } #endif irv = STRTOG_Denormal; n = fpi->emin - e; if (n >= nbits) { switch (fpi->rounding) { case FPI_Round_near: if (n == nbits && (n < 2 || any_on(b,n-1))) goto one_bit; break; case FPI_Round_up: if (!sign) goto one_bit; break; case FPI_Round_down: if (sign) { one_bit: x[0] = b->wds = 1; dret: *bp = b; *exp = fpi->emin; #ifndef NO_ERRNO errno = ERANGE; #endif return STRTOG_Denormal | STRTOG_Inexhi | STRTOG_Underflow; } } Bfree(b); retz: #ifndef NO_ERRNO errno = ERANGE; #endif return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow; } k = n - 1; if (lostbits) lostbits = 1; else if (k > 0) lostbits = any_on(b,k); if (x[k>>kshift] & 1 << (k & kmask)) lostbits |= 2; nbits -= n; rshift(b,n); e = fpi->emin; } if (lostbits) { up = 0; switch(fpi->rounding) { case FPI_Round_zero: break; case FPI_Round_near: if (lostbits & 2 && (lostbits | x[0]) & 1) up = 1; break; case FPI_Round_up: up = 1 - sign; break; case FPI_Round_down: up = sign; } if (up) { k = b->wds; b = increment(b); x = b->x; if (irv == STRTOG_Denormal) { if (nbits == fpi->nbits - 1 && x[nbits >> kshift] & 1 << (nbits & kmask)) irv = STRTOG_Normal; } else if (b->wds > k || ((n = nbits & kmask) !=0 && hi0bits(x[k-1]) < 32-n)) { rshift(b,1); if (++e > fpi->emax) goto ovfl; } irv |= STRTOG_Inexhi; } else irv |= STRTOG_Inexlo; } *bp = b; *exp = e; return irv; } /* strtodg.c */ #ifdef USE_LOCALE #include "locale.h" #endif static CONST int fivesbits[] = { 0, 3, 5, 7, 10, 12, 14, 17, 19, 21, 24, 26, 28, 31, 33, 35, 38, 40, 42, 45, 47, 49, 52 #ifdef VAX , 54, 56 #endif }; Bigint * #ifdef KR_headers increment(b) Bigint *b; #else increment(Bigint *b) #endif { ULong *x, *xe; Bigint *b1; #ifdef Pack_16 ULong carry = 1, y; #endif x = b->x; xe = x + b->wds; #ifdef Pack_32 do { if (*x < (ULong)0xffffffffL) { ++*x; return b; } *x++ = 0; } while(x < xe); #else do { y = *x + carry; carry = y >> 16; *x++ = y & 0xffff; if (!carry) return b; } while(x < xe); if (carry) #endif { if (b->wds >= b->maxwds) { b1 = Balloc(b->k+1); Bcopy(b1,b); Bfree(b); b = b1; } b->x[b->wds++] = 1; } return b; } void #ifdef KR_headers decrement(b) Bigint *b; #else decrement(Bigint *b) #endif { ULong *x, *xe; #ifdef Pack_16 ULong borrow = 1, y; #endif x = b->x; xe = x + b->wds; #ifdef Pack_32 do { if (*x) { --*x; break; } *x++ = 0xffffffffL; } while(x < xe); #else do { y = *x - borrow; borrow = (y & 0x10000) >> 16; *x++ = y & 0xffff; } while(borrow && x < xe); #endif } static int #ifdef KR_headers all_on(b, n) Bigint *b; int n; #else all_on(Bigint *b, int n) #endif { ULong *x, *xe; x = b->x; xe = x + (n >> kshift); while(x < xe) if ((*x++ & ALL_ON) != ALL_ON) return 0; if (n &= kmask) return ((*x | (ALL_ON << n)) & ALL_ON) == ALL_ON; return 1; } Bigint * #ifdef KR_headers set_ones(b, n) Bigint *b; int n; #else set_ones(Bigint *b, int n) #endif { int k; ULong *x, *xe; k = (n + ((1 << kshift) - 1)) >> kshift; if (b->k < k) { Bfree(b); b = Balloc(k); } k = n >> kshift; if (n &= kmask) k++; b->wds = k; x = b->x; xe = x + k; while(x < xe) *x++ = ALL_ON; if (n) x[-1] >>= ULbits - n; return b; } static int rvOK #ifdef KR_headers (d, fpi, exp, bits, exact, rd, irv) U *d; FPI *fpi; Long *exp; ULong *bits; int exact, rd, *irv; #else (U *d, FPI *fpi, Long *exp, ULong *bits, int exact, int rd, int *irv) #endif { Bigint *b; ULong carry, inex, lostbits; int bdif, e, j, k, k1, nb, rv; carry = rv = 0; b = d2b(dval(d), &e, &bdif); bdif -= nb = fpi->nbits; e += bdif; if (bdif <= 0) { if (exact) goto trunc; goto ret; } if (P == nb) { if ( #ifndef IMPRECISE_INEXACT exact && #endif fpi->rounding == #ifdef RND_PRODQUOT FPI_Round_near #else Flt_Rounds #endif ) goto trunc; goto ret; } switch(rd) { case 1: /* round down (toward -Infinity) */ goto trunc; case 2: /* round up (toward +Infinity) */ break; default: /* round near */ k = bdif - 1; if (k < 0) goto trunc; if (!k) { if (!exact) goto ret; if (b->x[0] & 2) break; goto trunc; } if (b->x[k>>kshift] & ((ULong)1 << (k & kmask))) break; goto trunc; } /* "break" cases: round up 1 bit, then truncate; bdif > 0 */ carry = 1; trunc: inex = lostbits = 0; if (bdif > 0) { if ( (lostbits = any_on(b, bdif)) !=0) inex = STRTOG_Inexlo; rshift(b, bdif); if (carry) { inex = STRTOG_Inexhi; b = increment(b); if ( (j = nb & kmask) !=0) j = ULbits - j; if (hi0bits(b->x[b->wds - 1]) != j) { if (!lostbits) lostbits = b->x[0] & 1; rshift(b, 1); e++; } } } else if (bdif < 0) b = lshift(b, -bdif); if (e < fpi->emin) { k = fpi->emin - e; e = fpi->emin; if (k > nb || fpi->sudden_underflow) { b->wds = inex = 0; *irv = STRTOG_Underflow | STRTOG_Inexlo; } else { k1 = k - 1; if (k1 > 0 && !lostbits) lostbits = any_on(b, k1); if (!lostbits && !exact) goto ret; lostbits |= carry = b->x[k1>>kshift] & (1 << (k1 & kmask)); rshift(b, k); *irv = STRTOG_Denormal; if (carry) { b = increment(b); inex = STRTOG_Inexhi | STRTOG_Underflow; } else if (lostbits) inex = STRTOG_Inexlo | STRTOG_Underflow; } } else if (e > fpi->emax) { e = fpi->emax + 1; *irv = STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi; #ifndef NO_ERRNO errno = ERANGE; #endif b->wds = inex = 0; } *exp = e; copybits(bits, nb, b); *irv |= inex; rv = 1; ret: Bfree(b); return rv; } static int #ifdef KR_headers mantbits(d) U *d; #else mantbits(U *d) #endif { ULong L; #ifdef VAX L = word1(d) << 16 | word1(d) >> 16; if (L) #else if ( (L = word1(d)) !=0) #endif return P - lo0bits(&L); #ifdef VAX L = word0(d) << 16 | word0(d) >> 16 | Exp_msk11; #else L = word0(d) | Exp_msk1; #endif return P - 32 - lo0bits(&L); } int strtodg #ifdef KR_headers (s00, se, fpi, exp, bits) CONST char *s00; char **se; FPI *fpi; Long *exp; ULong *bits; #else (CONST char *s00, char **se, FPI *fpi, Long *exp, ULong *bits) #endif { int abe, abits, asub; int bb0, bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, decpt, denorm; int dsign, e, e1, e2, emin, esign, finished, i, inex, irv; int j, k, nbits, nd, nd0, nf, nz, nz0, rd, rvbits, rve, rve1, sign; int sudden_underflow = 0; /* silence compilers */ CONST char *s, *s0, *s1; double adj0, tol; Long L; U adj, rv; ULong *b, *be, y, z; Bigint *ab, *bb, *bb1, *bd, *bd0, *bs, *delta, *rvb, *rvb0; #ifdef USE_LOCALE /*{{*/ #ifdef NO_LOCALE_CACHE char *decimalpoint = localeconv()->decimal_point; int dplen = strlen(decimalpoint); #else char *decimalpoint; static char *decimalpoint_cache; static int dplen; if (!(s0 = decimalpoint_cache)) { s0 = localeconv()->decimal_point; if ((decimalpoint_cache = (char*)MALLOC(strlen(s0) + 1))) { strcpy(decimalpoint_cache, s0); s0 = decimalpoint_cache; } dplen = strlen(s0); } decimalpoint = (char*)s0; #endif /*NO_LOCALE_CACHE*/ #else /*USE_LOCALE}{*/ #define dplen 1 #endif /*USE_LOCALE}}*/ irv = STRTOG_Zero; denorm = sign = nz0 = nz = 0; dval(&rv) = 0.; rvb = 0; nbits = fpi->nbits; for(s = s00;;s++) switch(*s) { case '-': sign = 1; /* no break */ case '+': if (*++s) goto break2; /* no break */ case 0: sign = 0; irv = STRTOG_NoNumber; s = s00; goto ret; case '\t': case '\n': case '\v': case '\f': case '\r': case ' ': continue; default: goto break2; } break2: if (*s == '0') { #ifndef NO_HEX_FP switch(s[1]) { case 'x': case 'X': irv = gethex(&s, fpi, exp, &rvb, sign); if (irv == STRTOG_NoNumber) { s = s00; sign = 0; } goto ret; } #endif nz0 = 1; while(*++s == '0') ; if (!*s) goto ret; } sudden_underflow = fpi->sudden_underflow; s0 = s; y = z = 0; for(decpt = nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) if (nd < 9) y = 10*y + c - '0'; else if (nd < DBL_DIG + 2) z = 10*z + c - '0'; nd0 = nd; #ifdef USE_LOCALE if (c == *decimalpoint) { for(i = 1; decimalpoint[i]; ++i) if (s[i] != decimalpoint[i]) goto dig_done; s += i; c = *s; #else if (c == '.') { c = *++s; #endif decpt = 1; if (!nd) { for(; c == '0'; c = *++s) nz++; if (c > '0' && c <= '9') { s0 = s; nf += nz; nz = 0; goto have_dig; } goto dig_done; } for(; c >= '0' && c <= '9'; c = *++s) { have_dig: nz++; if (c -= '0') { nf += nz; for(i = 1; i < nz; i++) if (nd++ < 9) y *= 10; else if (nd <= DBL_DIG + 2) z *= 10; if (nd++ < 9) y = 10*y + c; else if (nd <= DBL_DIG + 2) z = 10*z + c; nz = 0; } } }/*}*/ dig_done: e = 0; if (c == 'e' || c == 'E') { if (!nd && !nz && !nz0) { irv = STRTOG_NoNumber; s = s00; goto ret; } s00 = s; esign = 0; switch(c = *++s) { case '-': esign = 1; case '+': c = *++s; } if (c >= '0' && c <= '9') { while(c == '0') c = *++s; if (c > '0' && c <= '9') { L = c - '0'; s1 = s; while((c = *++s) >= '0' && c <= '9') L = 10*L + c - '0'; if (s - s1 > 8 || L > 19999) /* Avoid confusion from exponents * so large that e might overflow. */ e = 19999; /* safe for 16 bit ints */ else e = (int)L; if (esign) e = -e; } else e = 0; } else s = s00; } if (!nd) { if (!nz && !nz0) { #ifdef INFNAN_CHECK /* Check for Nan and Infinity */ if (!decpt) switch(c) { case 'i': case 'I': if (match(&s,"nf")) { --s; if (!match(&s,"inity")) ++s; irv = STRTOG_Infinite; goto infnanexp; } break; case 'n': case 'N': if (match(&s, "an")) { irv = STRTOG_NaN; *exp = fpi->emax + 1; #ifndef No_Hex_NaN if (*s == '(') /*)*/ irv = hexnan(&s, fpi, bits); #endif goto infnanexp; } } #else (void)decpt; /* shut up compiler! */ #endif /* INFNAN_CHECK */ irv = STRTOG_NoNumber; s = s00; } goto ret; } irv = STRTOG_Normal; e1 = e -= nf; rd = 0; switch(fpi->rounding & 3) { case FPI_Round_up: rd = 2 - sign; break; case FPI_Round_zero: rd = 1; break; case FPI_Round_down: rd = 1 + sign; } /* Now we have nd0 digits, starting at s0, followed by a * decimal point, followed by nd-nd0 digits. The number we're * after is the integer represented by those digits times * 10**e */ if (!nd0) nd0 = nd; k = nd < DBL_DIG + 2 ? nd : DBL_DIG + 2; dval(&rv) = y; if (k > 9) dval(&rv) = tens[k - 9] * dval(&rv) + z; bd0 = 0; if (nbits <= P && nd <= DBL_DIG) { if (!e) { if (rvOK(&rv, fpi, exp, bits, 1, rd, &irv)) goto ret; } else if (e > 0) { if (e <= Ten_pmax) { #ifdef VAX goto vax_ovfl_check; #else i = fivesbits[e] + mantbits(&rv) <= P; /* rv = */ rounded_product(dval(&rv), tens[e]); if (rvOK(&rv, fpi, exp, bits, i, rd, &irv)) goto ret; e1 -= e; goto rv_notOK; #endif } i = DBL_DIG - nd; if (e <= Ten_pmax + i) { /* A fancier test would sometimes let us do * this for larger i values. */ e2 = e - i; e1 -= i; dval(&rv) *= tens[i]; #ifdef VAX /* VAX exponent range is so narrow we must * worry about overflow here... */ vax_ovfl_check: dval(&adj) = dval(&rv); word0(&adj) -= P*Exp_msk1; /* adj = */ rounded_product(dval(&adj), tens[e2]); if ((word0(&adj) & Exp_mask) > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) goto rv_notOK; word0(&adj) += P*Exp_msk1; dval(&rv) = dval(&adj); #else /* rv = */ rounded_product(dval(&rv), tens[e2]); #endif if (rvOK(&rv, fpi, exp, bits, 0, rd, &irv)) goto ret; e1 -= e2; } } #ifndef Inaccurate_Divide else if (e >= -Ten_pmax) { /* rv = */ rounded_quotient(dval(&rv), tens[-e]); if (rvOK(&rv, fpi, exp, bits, 0, rd, &irv)) goto ret; e1 -= e; } #endif } rv_notOK: e1 += nd - k; /* Get starting approximation = rv * 10**e1 */ e2 = 0; if (e1 > 0) { if ( (i = e1 & 15) !=0) dval(&rv) *= tens[i]; if (e1 &= ~15) { e1 >>= 4; while(e1 >= (1 << (n_bigtens-1))) { e2 += ((word0(&rv) & Exp_mask) >> Exp_shift1) - Bias; word0(&rv) &= ~Exp_mask; word0(&rv) |= Bias << Exp_shift1; dval(&rv) *= bigtens[n_bigtens-1]; e1 -= 1 << (n_bigtens-1); } e2 += ((word0(&rv) & Exp_mask) >> Exp_shift1) - Bias; word0(&rv) &= ~Exp_mask; word0(&rv) |= Bias << Exp_shift1; for(j = 0; e1 > 0; j++, e1 >>= 1) if (e1 & 1) dval(&rv) *= bigtens[j]; } } else if (e1 < 0) { e1 = -e1; if ( (i = e1 & 15) !=0) dval(&rv) /= tens[i]; if (e1 &= ~15) { e1 >>= 4; while(e1 >= (1 << (n_bigtens-1))) { e2 += ((word0(&rv) & Exp_mask) >> Exp_shift1) - Bias; word0(&rv) &= ~Exp_mask; word0(&rv) |= Bias << Exp_shift1; dval(&rv) *= tinytens[n_bigtens-1]; e1 -= 1 << (n_bigtens-1); } e2 += ((word0(&rv) & Exp_mask) >> Exp_shift1) - Bias; word0(&rv) &= ~Exp_mask; word0(&rv) |= Bias << Exp_shift1; for(j = 0; e1 > 0; j++, e1 >>= 1) if (e1 & 1) dval(&rv) *= tinytens[j]; } } #ifdef IBM /* e2 is a correction to the (base 2) exponent of the return * value, reflecting adjustments above to avoid overflow in the * native arithmetic. For native IBM (base 16) arithmetic, we * must multiply e2 by 4 to change from base 16 to 2. */ e2 <<= 2; #endif rvb = d2b(dval(&rv), &rve, &rvbits); /* rv = rvb * 2^rve */ rve += e2; if ((j = rvbits - nbits) > 0) { rshift(rvb, j); rvbits = nbits; rve += j; } bb0 = 0; /* trailing zero bits in rvb */ e2 = rve + rvbits - nbits; if (e2 > fpi->emax + 1) goto huge; rve1 = rve + rvbits - nbits; if (e2 < (emin = fpi->emin)) { denorm = 1; j = rve - emin; if (j > 0) { rvb = lshift(rvb, j); rvbits += j; } else if (j < 0) { rvbits += j; if (rvbits <= 0) { if (rvbits < -1) { ufl: rvb->wds = 0; rvb->x[0] = 0; *exp = emin; irv = STRTOG_Underflow | STRTOG_Inexlo; goto ret; } rvb->x[0] = rvb->wds = rvbits = 1; } else rshift(rvb, -j); } rve = rve1 = emin; if (sudden_underflow && e2 + 1 < emin) goto ufl; } /* Now the hard part -- adjusting rv to the correct value.*/ /* Put digits into bd: true value = bd * 10^e */ bd0 = s2b(s0, nd0, nd, y, dplen); for(;;) { bd = Balloc(bd0->k); Bcopy(bd, bd0); bb = Balloc(rvb->k); Bcopy(bb, rvb); bbbits = rvbits - bb0; bbe = rve + bb0; bs = i2b(1); if (e >= 0) { bb2 = bb5 = 0; bd2 = bd5 = e; } else { bb2 = bb5 = -e; bd2 = bd5 = 0; } if (bbe >= 0) bb2 += bbe; else bd2 -= bbe; bs2 = bb2; j = nbits + 1 - bbbits; i = bbe + bbbits - nbits; if (i < emin) /* denormal */ j += i - emin; bb2 += j; bd2 += j; i = bb2 < bd2 ? bb2 : bd2; if (i > bs2) i = bs2; if (i > 0) { bb2 -= i; bd2 -= i; bs2 -= i; } if (bb5 > 0) { bs = pow5mult(bs, bb5); bb1 = mult(bs, bb); Bfree(bb); bb = bb1; } bb2 -= bb0; if (bb2 > 0) bb = lshift(bb, bb2); else if (bb2 < 0) rshift(bb, -bb2); if (bd5 > 0) bd = pow5mult(bd, bd5); if (bd2 > 0) bd = lshift(bd, bd2); if (bs2 > 0) bs = lshift(bs, bs2); asub = 1; inex = STRTOG_Inexhi; delta = diff(bb, bd); if (delta->wds <= 1 && !delta->x[0]) break; dsign = delta->sign; delta->sign = finished = 0; L = 0; i = cmp(delta, bs); if (rd && i <= 0) { irv = STRTOG_Normal; if ( (finished = dsign ^ (rd&1)) !=0) { if (dsign != 0) { irv |= STRTOG_Inexhi; goto adj1; } irv |= STRTOG_Inexlo; if (rve1 == emin) goto adj1; for(i = 0, j = nbits; j >= ULbits; i++, j -= ULbits) { if (rvb->x[i] & ALL_ON) goto adj1; } if (j > 1 && lo0bits(rvb->x + i) < j - 1) goto adj1; rve = rve1 - 1; rvb = set_ones(rvb, rvbits = nbits); break; } irv |= dsign ? STRTOG_Inexlo : STRTOG_Inexhi; break; } if (i < 0) { /* Error is less than half an ulp -- check for * special case of mantissa a power of two. */ irv = dsign ? STRTOG_Normal | STRTOG_Inexlo : STRTOG_Normal | STRTOG_Inexhi; if (dsign || bbbits > 1 || denorm || rve1 == emin) break; delta = lshift(delta,1); if (cmp(delta, bs) > 0) { irv = STRTOG_Normal | STRTOG_Inexlo; goto drop_down; } break; } if (i == 0) { /* exactly half-way between */ if (dsign) { if (denorm && all_on(rvb, rvbits)) { /*boundary case -- increment exponent*/ rvb->wds = 1; rvb->x[0] = 1; rve = emin + nbits - (rvbits = 1); irv = STRTOG_Normal | STRTOG_Inexhi; denorm = 0; break; } irv = STRTOG_Normal | STRTOG_Inexlo; } else if (bbbits == 1) { irv = STRTOG_Normal; drop_down: /* boundary case -- decrement exponent */ if (rve1 == emin) { irv = STRTOG_Normal | STRTOG_Inexhi; if (rvb->wds == 1 && rvb->x[0] == 1) sudden_underflow = 1; break; } rve -= nbits; rvb = set_ones(rvb, rvbits = nbits); break; } else irv = STRTOG_Normal | STRTOG_Inexhi; if ((bbbits < nbits && !denorm) || !(rvb->x[0] & 1)) break; if (dsign) { rvb = increment(rvb); j = kmask & (ULbits - (rvbits & kmask)); if (hi0bits(rvb->x[rvb->wds - 1]) != j) rvbits++; irv = STRTOG_Normal | STRTOG_Inexhi; } else { if (bbbits == 1) goto undfl; decrement(rvb); irv = STRTOG_Normal | STRTOG_Inexlo; } break; } if ((dval(&adj) = ratio(delta, bs)) <= 2.) { adj1: inex = STRTOG_Inexlo; if (dsign) { asub = 0; inex = STRTOG_Inexhi; } else if (denorm && bbbits <= 1) { undfl: rvb->wds = 0; rve = emin; irv = STRTOG_Underflow | STRTOG_Inexlo; break; } adj0 = dval(&adj) = 1.; } else { adj0 = dval(&adj) *= 0.5; if (dsign) { asub = 0; inex = STRTOG_Inexlo; } if (dval(&adj) < 2147483647.) { L = adj0; adj0 -= L; switch(rd) { case 0: if (adj0 >= .5) goto inc_L; break; case 1: if (asub && adj0 > 0.) goto inc_L; break; case 2: if (!asub && adj0 > 0.) { inc_L: L++; inex = STRTOG_Inexact - inex; } } dval(&adj) = L; } } y = rve + rvbits; /* adj *= ulp(dval(&rv)); */ /* if (asub) rv -= adj; else rv += adj; */ if (!denorm && rvbits < nbits) { rvb = lshift(rvb, j = nbits - rvbits); rve -= j; rvbits = nbits; } ab = d2b(dval(&adj), &abe, &abits); if (abe < 0) rshift(ab, -abe); else if (abe > 0) ab = lshift(ab, abe); rvb0 = rvb; if (asub) { /* rv -= adj; */ j = hi0bits(rvb->x[rvb->wds-1]); rvb = diff(rvb, ab); k = rvb0->wds - 1; if (denorm) /* do nothing */; else if (rvb->wds <= k || hi0bits( rvb->x[k]) > hi0bits(rvb0->x[k])) { /* unlikely; can only have lost 1 high bit */ if (rve1 == emin) { --rvbits; denorm = 1; } else { rvb = lshift(rvb, 1); --rve; --rve1; L = finished = 0; } } } else { rvb = sum(rvb, ab); k = rvb->wds - 1; if (k >= rvb0->wds || hi0bits(rvb->x[k]) < hi0bits(rvb0->x[k])) { if (denorm) { if (++rvbits == nbits) denorm = 0; } else { rshift(rvb, 1); rve++; rve1++; L = 0; } } } Bfree(ab); Bfree(rvb0); if (finished) break; z = rve + rvbits; if (y == z && L) { /* Can we stop now? */ tol = dval(&adj) * 5e-16; /* > max rel error */ dval(&adj) = adj0 - .5; if (dval(&adj) < -tol) { if (adj0 > tol) { irv |= inex; break; } } else if (dval(&adj) > tol && adj0 < 1. - tol) { irv |= inex; break; } } bb0 = denorm ? 0 : trailz(rvb); Bfree(bb); Bfree(bd); Bfree(bs); Bfree(delta); } if (!denorm && (j = nbits - rvbits) != 0) { if (j > 0) rvb = lshift(rvb, j); else rshift(rvb, -j); rve -= j; } *exp = rve; Bfree(bb); Bfree(bd); Bfree(bs); Bfree(bd0); Bfree(delta); if (rve > fpi->emax) { switch(fpi->rounding & 3) { case FPI_Round_near: goto huge; case FPI_Round_up: if (!sign) goto huge; break; case FPI_Round_down: if (sign) goto huge; } /* Round to largest representable magnitude */ Bfree(rvb); rvb = 0; irv = STRTOG_Normal | STRTOG_Inexlo; *exp = fpi->emax; b = bits; be = b + ((fpi->nbits + 31) >> 5); while(b < be) *b++ = (ULong)(-1); if ((j = fpi->nbits & 0x1f) != 0) *--be >>= (32 - j); goto ret; huge: rvb->wds = 0; irv = STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi; #ifndef NO_ERRNO errno = ERANGE; #endif #ifdef INFNAN_CHECK infnanexp: #endif *exp = fpi->emax + 1; } ret: if (denorm) { if (sudden_underflow) { rvb->wds = 0; irv = STRTOG_Underflow | STRTOG_Inexlo; #ifndef NO_ERRNO errno = ERANGE; #endif } else { irv = (irv & ~STRTOG_Retmask) | (rvb->wds > 0 ? STRTOG_Denormal : STRTOG_Zero); if (irv & STRTOG_Inexact) { irv |= STRTOG_Underflow; #ifndef NO_ERRNO errno = ERANGE; #endif } } } if (se) *se = (char *)s; if (sign) irv |= STRTOG_Neg; if (rvb) { copybits(bits, nbits, rvb); Bfree(rvb); } return irv; } pcc-20181216/common/unicode.c010064400017500000000000000057301277716665000145740ustar raggewheel/* $Id: unicode.c,v 1.10 2016/10/11 13:48:24 ragge Exp $ */ /* * Copyright (c) 2014 Eric Olson * Some rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include "pass1.h" #include "manifest.h" #include "unicode.h" /* * decode 32-bit code point from UTF-8 * move pointer */ long u82cp(char **q) { unsigned char *t = (unsigned char *)*q; unsigned long c, r; int i, sz; if (*t == '\\') c = esccon((char **)&t); else c = *t++; /* always eat the first value */ *q = (char *)t; if (c > 0x7F) { if ((c & 0xE0) == 0xC0) { sz = 2; r = c & 0x1F; } else if ((c & 0xF0) == 0xE0) { sz = 3; r = c & 0x0F; } else if ((c & 0xF8) == 0xF0) { sz = 4; r = c & 0x07; } else if ((c & 0xFC) == 0xF8) { sz = 5; r = c & 0x03; } else if ((c & 0xFE) == 0xFC) { sz = 6; r = c & 0x01; } else { u8error("invalid utf-8 prefix"); return 0xFFFFUL; } for (i = 1; i < sz; i++) { if (*t == '\\') c = esccon((char **)&t); else c = *t++; if ((c & 0xC0) == 0x80) { r = (r << 6) + (c & 0x3F); } else { u8error("utf-8 encoding %d bytes too short", sz - i); return 0xFFFFUL; } } *q = (char *)t; } else { r = c; } return r; } /* * Create UTF-16 from unicode number. * Expects s to point to two words. */ void cp2u16(long num, unsigned short *s) { s[0] = s[1] = 0; if (num <= 0xd7ff || (num >= 0xe000 && num <= 0xffffL)) { *s = (unsigned short)num; } else if (num >= 0x010000L && num <= 0x10ffffL) { num -= 0x010000L; s[0] = (unsigned short)((num >> 10) + 0xd800); s[1] = (unsigned short)((num & 0x3ff) + 0xdc00); } else if (num > 0x10ffffL) werror("illegal UTF-16 value"); } pcc-20181216/common/unicode.h010064400017500000000000000003441255272204500145600ustar raggewheel/* $Id: unicode.h,v 1.5 2015/07/19 13:20:37 ragge Exp $ */ #ifndef _UNICODE_H #define _UNICODE_H extern long u82cp(char **q); extern void u8error(const char *fmt, ...); extern void cp2u16(long num, unsigned short *s); #endif pcc-20181216/doc004075500017500000000000000000001340533064100121545ustar raggewheelpcc-20181216/doc/CVS004075500017500000000000000000001340533064100126075ustar raggewheelpcc-20181216/doc/CVS/Root010064400017500000000000000000111340533064100135210ustar raggewheel/cvsroot pcc-20181216/doc/CVS/Repository010064400017500000000000000000101340533064100147540ustar raggewheelpcc/doc pcc-20181216/doc/CVS/Entries010064400017500000000000000000021340533064100142070ustar raggewheelD pcc-20181216/f77004075500017500000000000000000001340533064100120125ustar raggewheelpcc-20181216/f77/CVS004075500017500000000000000000001340533064100124455ustar raggewheelpcc-20181216/f77/CVS/Root010064400017500000000000000000111340533064100133570ustar raggewheel/cvsroot pcc-20181216/f77/CVS/Repository010064400017500000000000000000101340533064100146120ustar raggewheelpcc/f77 pcc-20181216/f77/CVS/Entries010064400017500000000000000001031340533064100140470ustar raggewheel/Makefile.in/1.7/Tue Jun 7 13:56:05 2011// D/f77//// D/fcom//// D pcc-20181216/f77/Makefile.in010064400017500000000000000013401157342676500141520ustar raggewheel# $Id: Makefile.in,v 1.7 2011/06/07 13:56:05 plunky Exp $ # # Makefile.in for top-level of pcc. # @SET_MAKE@ ALL_SUBDIRS= f77 fcom DIST_SUBDIRS= $(ALL_SUBDIRS) all install clean: @for subdir in $(ALL_SUBDIRS); do \ _nextdir_=$${_thisdir_+$$_thisdir_/}$$subdir; \ echo "===> $$_nextdir_"; \ (_thisdir_=$$_nextdir_; export _thisdir_; cd $$subdir && \ exec $(MAKE) $(MFLAGS) $@) || exit $$?; \ echo "<=== $$_nextdir_"; \ done distclean: @for subdir in $(DIST_SUBDIRS); do \ _nextdir_=$${_thisdir_+$$_thisdir_/}$$subdir; \ echo "===> $$_nextdir_"; \ (_thisdir_=$$_nextdir_; export _thisdir_; cd $$subdir && \ exec $(MAKE) $(MFLAGS) $@) || exit $$?; \ echo "<=== $$_nextdir_"; \ done rm -f Makefile pcc-20181216/f77/f77004075500017500000000000000000001340533064100124155ustar raggewheelpcc-20181216/f77/f77/CVS004075500017500000000000000000001340533064100130505ustar raggewheelpcc-20181216/f77/f77/CVS/Root010064400017500000000000000000111340533064100137620ustar raggewheel/cvsroot pcc-20181216/f77/f77/CVS/Repository010064400017500000000000000000141340533064100152210ustar raggewheelpcc/f77/f77 pcc-20181216/f77/f77/CVS/Entries010064400017500000000000000001741340533064100144620ustar raggewheel/Makefile.in/1.22/Tue Sep 25 11:17:17 2012// /f77.1/1.2/Wed Dec 24 17:40:41 2008// /f77.c/1.22/Thu Aug 4 08:32:32 2011// D pcc-20181216/f77/f77/Makefile.in010064400017500000000000000025451203031127500145370ustar raggewheel# $Id: Makefile.in,v 1.22 2012/09/25 11:17:17 plunky Exp $ # # Makefile.in for the f77 frontend of pcc. # VPATH=@srcdir@ top_srcdir=@top_srcdir@ top_builddir=@top_builddir@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ libdir = @libdir@ libexecdir = @libexecdir@ includedir = @includedir@ CC = @CC@ TARGOS = @targos@ TARGOSVER = @targosver@ TARGMACH = @targmach@ TARGET = @target@ VERSION = @PACKAGE_VERSION@ PCCLIBDIR = $(libdir)/pcc/$(TARGET)/$(VERSION)/lib PCCINCDIR = $(libdir)/pcc/$(TARGET)/$(VERSION)/include F77LIBDIR=-L$(prefix)/lib CFLAGS = @CFLAGS@ @ADD_CFLAGS@ CPPFLAGS = @CPPFLAGS@ @ADD_CPPFLAGS@ -DLANG_F77 \ -DLIBEXECDIR=\"$(libexecdir)\" -DINCLUDEDIR=\"$(includedir)\" \ -DPCCINCDIR=\"$(PCCINCDIR)/\" -DPCCLIBDIR=\"$(PCCLIBDIR)/\" \ -DLIBDIR=\"$(F77LIBDIR)\" -Dmach_$(TARGMACH) -Dos_$(TARGOS) \ -I$(FCOMDIR) -I$(top_builddir) -I$(top_srcdir)/os/$(TARGOS) -I$(MDIR) LIBS = @LIBS@ LDFLAGS = @LDFLAGS@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ OBJS=f77.o DEST=@BINPREFIX@f77 MIPDIR=$(top_srcdir)/mip MDIR=$(top_srcdir)/arch/$(TARGMACH) FCOMDIR=$(top_srcdir)/f77/fcom all: $(DEST) $(DEST): $(OBJS) $(CC) $(LDFLAGS) $(OBJS) -o $@ $(LIBS) .c.o: $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< install: $(INSTALL_PROGRAM) $(DEST) $(bindir) clean: rm -f $(OBJS) $(DEST) distclean: clean rm -f Makefile pcc-20181216/f77/f77/f77.1010064400017500000000000000124131112447203100131530ustar raggewheel.\" $Id: f77.1,v 1.2 2008/12/24 17:40:41 sgk Exp $ .\" .\" Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" .\" Redistributions of source code and documentation must retain the above .\" copyright notice, this list of conditions and the following disclaimer. .\" Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditionsand the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" All advertising materials mentioning features or use of this software .\" must display the following acknowledgement: .\" This product includes software developed or owned by Caldera .\" International, Inc. .\" Neither the name of Caldera International, Inc. nor the names of other .\" contributors may be used to endorse or promote products derived from .\" this software without specific prior written permission. .\" .\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA .\" INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE .\" DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE .\" FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, .\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING .\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" .TH F77 1 .SH NAME f77 \- Fortran 77 compiler .SH SYNOPSIS .B f77 [ option ] ... file ... .SH DESCRIPTION .I F77 is the UNIX Fortran 77 compiler. It accepts several types of arguments: .PP Arguments whose names end with `.f' are taken to be Fortran 77 source programs; they are compiled, and each object program is left on the file in the current directory whose name is that of the source with `.o' substituted for '.f'. .PP Arguments whose names end with `.r' or `.e' are taken to be Ratfor or EFL source programs, respectively; these are first transformed by the appropriate preprocessor, then compiled by f77. .PP In the same way, arguments whose names end with `.c' or `.s' are taken to be C or assembly source programs and are compiled or assembled, producing a `.o' file. .PP The following options have the same meaning as in .IR cc (1). See .IR ld (1) for load-time options. .TP .B \-c Suppress loading and produce `.o' files for each source file. .TP .B \-p Prepare object files for profiling, see .IR prof (1). .TP .SM .B \-O Invoke an object-code optimizer. .TP .SM .B \-S Compile the named programs, and leave the assembler-language output on corresponding files suffixed `.s'. (No `.o' is created.). .TP .B \-f Use a floating point interpreter (for PDP11's that lack 11/70-style floating point). .TP .BR \-o " output" Name the final output file .I output instead of `a.out'. .PP The following options are peculiar to .IR f77 . .TP .SM .BR \-onetrip Compile DO loops that are performed at least once if reached. (Fortran 77 DO loops are not performed at all if the upper limit is smaller than the lower limit.) .TP .BR \-u Make the default type of a variable `undefined' rather than using the default Fortran rules. .TP .BR \-q Suppress printing of procedure names during compilation. .TP .BR \-C Compile code to check that subscripts are within declared array bounds. .TP .BR \-w Suppress all warning messages. If the option is `\-w66', only Fortran 66 compatibility warnings are suppressed. .TP .BR \-F Apply EFL and Ratfor preprocessor to relevant files, put the result in the file with the suffix changed to `.f', but do not compile. .TP .BR \-m Apply the M4 preprocessor to each `.r' or `.e' file before transforming it with the Ratfor or EFL preprocessor. .TP .TP .BI \-E x Use the string .I x as an EFL option in processing `.e' files. .TP .BI \-R x Use the string .I x as a Ratfor option in processing `.r' files. .PP Other arguments are taken to be either loader option arguments, or F77-compatible object programs, typically produced by an earlier run, or perhaps libraries of F77-compatible routines. These programs, together with the results of any compilations specified, are loaded (in the order given) to produce an executable program with name `a.out'. .SH FILES .nf .ta \w'/usr/lib/libF77.a 'u file.[fresc] input file file.o object file a.out loaded output ./fort[pid].? temporary /usr/lib/f77pass1 compiler /lib/f1 pass 2 /lib/c2 optional optimizer /usr/lib/libF77.a intrinsic function library /usr/lib/libI77.a Fortran I/O library /lib/libc.a C library, see section 3 .fi .SH "SEE ALSO" S. I. Feldman, P. J. Weinberger, .I A Portable Fortran 77 Compiler .br prof(1), cc(1), ld(1) .SH DIAGNOSTICS The diagnostics produced by .I f77 itself are intended to be self-explanatory. Occasional messages may be produced by the loader. .SH BUGS The Fortran 66 subset of the language has been exercised extensively; the newer features have not. pcc-20181216/f77/f77/f77.c010064400017500000000000000343041161645444000132520ustar raggewheel/* $Id: f77.c,v 1.22 2011/08/04 08:32:32 mickey Exp $ */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code and documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditionsand the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ char xxxvers[] = "FORTRAN 77 DRIVER, VERSION 1.11, 28 JULY 1978\n"; #include #include #include #include #include #include #include #include #include #include "ccconfig.h" typedef FILE *FILEP; typedef int flag; #define YES 1 #define NO 0 FILEP diagfile; static int pid; static int sigivalue = 0; static int sigqvalue = 0; #ifndef FCOM #define FCOM "fcom" #endif #ifndef ASSEMBLER #define ASSEMBLER "as" #endif #ifndef LINKER #define LINKER "ld" #endif static char *fcom = LIBEXECDIR "/" FCOM ; static char *asmname = ASSEMBLER ; static char *ldname = LINKER ; static char *startfiles[] = STARTFILES; static char *endfiles[] = ENDFILES; static char *dynlinker[] = DYNLINKER; static char *crt0file = CRT0FILE; static char *macroname = "m4"; static char *shellname = "/bin/sh"; static char *aoutname = "a.out" ; static char *libdir = LIBDIR ; static char *liblist[] = F77LIBLIST; static char *infname; static char asmfname[15]; static char prepfname[15]; #define MAXARGS 100 int ffmax; static char *ffary[MAXARGS]; static char eflags[30] = ""; static char rflags[30] = ""; static char lflag[3] = "-x"; static char *eflagp = eflags; static char *rflagp = rflags; static char **loadargs; static char **loadp; static int oflag; static flag loadflag = YES; static flag saveasmflag = NO; static flag profileflag = NO; static flag optimflag = NO; static flag debugflag = NO; static flag verbose = NO; static flag fortonly = NO; static flag macroflag = NO; static char *setdoto(char *), *lastchar(char *), *lastfield(char *); static void intrupt(int); static void enbint(void (*)(int)); static void crfnames(void); static void fatal1(char *, ...); static void done(int), texec(char *, char **); static char *copyn(int, char *); static int dotchar(char *), unreadable(char *), sys(char *), dofort(char *); static int nodup(char *); static int await(int); static void rmf(char *), doload(char *[], char *[]), doasm(char *); static int callsys(char *, char **); static void errorx(char *, ...); static void addarg(char **ary, int *num, char *arg) { ary[(*num)++] = arg; if ((*num) == MAXARGS) { fprintf(stderr, "argument array too small\n"); exit(1); } } int main(int argc, char **argv) { int i, c, status; char *s; char fortfile[20], *t; char buff[100]; diagfile = stderr; sigivalue = (int) signal(SIGINT, SIG_IGN) & 01; sigqvalue = (int) signal(SIGQUIT, SIG_IGN) & 01; enbint(intrupt); pid = getpid(); crfnames(); loadargs = (char **)calloc(1, (argc + 20) * sizeof(*loadargs)); if (!loadargs) fatal1("out of memory"); loadp = loadargs; --argc; ++argv; while(argc>0 && argv[0][0]=='-' && argv[0][1]!='\0') { for(s = argv[0]+1 ; *s ; ++s) switch(*s) { case 'T': /* use special passes */ switch(*++s) { case '1': fcom = s+1; goto endfor; case 'a': asmname = s+1; goto endfor; case 'l': ldname = s+1; goto endfor; case 'm': macroname = s+1; goto endfor; default: fatal1("bad option -T%c", *s); } break; case 'w': /* F66 warn or no warn */ addarg(ffary, &ffmax, s-1); break; case 'q': /* * Suppress printing of procedure names during * compilation. */ addarg(ffary, &ffmax, s-1); break; copyfflag: case 'u': case 'U': case 'M': case '1': case 'C': addarg(ffary, &ffmax, s-1); break; case 'O': optimflag = YES; addarg(ffary, &ffmax, s-1); break; case 'm': if(s[1] == '4') ++s; macroflag = YES; break; case 'S': saveasmflag = YES; case 'c': loadflag = NO; break; case 'v': verbose = YES; break; case 'd': debugflag = YES; goto copyfflag; case 'p': profileflag = YES; goto copyfflag; case 'o': if(!strcmp(s, "onetrip")) { addarg(ffary, &ffmax, s-1); goto endfor; } oflag = 1; aoutname = *++argv; --argc; break; case 'F': fortonly = YES; loadflag = NO; break; case 'I': if(s[1]=='2' || s[1]=='4' || s[1]=='s') goto copyfflag; fprintf(diagfile, "invalid flag -I%c\n", s[1]); done(1); case 'l': /* letter ell--library */ s[-1] = '-'; *loadp++ = s-1; goto endfor; case 'E': /* EFL flag argument */ while(( *eflagp++ = *++s)) ; *eflagp++ = ' '; goto endfor; case 'R': while(( *rflagp++ = *++s )) ; *rflagp++ = ' '; goto endfor; default: lflag[1] = *s; *loadp++ = copyn(strlen(lflag), lflag); break; } endfor: --argc; ++argv; } if (verbose) fprintf(stderr, xxxvers); if (argc == 0) errorx("No input files"); #ifdef mach_pdp11 if(nofloating) *loadp++ = (profileflag ? NOFLPROF : NOFLFOOT); else #endif for(i = 0 ; i%s", macroname, infname, prepfname); if(sys(buff)) { rmf(prepfname); break; } infname = prepfname; } if(c == 'e') snprintf(buff, sizeof(buff), "efl %s %s >%s", eflags, infname, fortfile); else snprintf(buff, sizeof(buff), "ratfor %s %s >%s", rflags, infname, fortfile); status = sys(buff); if(macroflag) rmf(infname); if(status) { loadflag = NO; rmf(fortfile); break; } if( ! fortonly ) { infname = argv[i] = lastfield(argv[i]); *lastchar(infname) = 'f'; if( dofort(argv[i]) ) loadflag = NO; else { if( nodup(t = setdoto(argv[i])) ) *loadp++ = t; rmf(fortfile); } } break; case 'f': /* Fortran file */ case 'F': if( unreadable(argv[i]) ) break; if( dofort(argv[i]) ) loadflag = NO; else if( nodup(t=setdoto(argv[i])) ) *loadp++ = t; break; case 'c': /* C file */ case 's': /* Assembler file */ if( unreadable(argv[i]) ) break; fprintf(diagfile, "%s:\n", argv[i]); snprintf(buff, sizeof(buff), "cc -c %s", argv[i]); if( sys(buff) ) loadflag = NO; else if( nodup(t = setdoto(argv[i])) ) *loadp++ = t; break; case 'o': if( nodup(argv[i]) ) *loadp++ = argv[i]; break; default: if( ! strcmp(argv[i], "-o") ) aoutname = argv[++i]; else *loadp++ = argv[i]; break; } if(loadflag) doload(loadargs, loadp); done(0); return 0; } #define ADD(x) addarg(params, &nparms, (x)) static int dofort(char *s) { int nparms, i; char *params[MAXARGS]; nparms = 0; ADD(FCOM); for (i = 0; i < ffmax; i++) ADD(ffary[i]); ADD(s); ADD(asmfname); ADD(NULL); infname = s; if (callsys(fcom, params)) errorx("Error. No assembly."); doasm(s); if (saveasmflag == NO) rmf(asmfname); return(0); } static void doasm(char *s) { char *obj; char *params[MAXARGS]; int nparms; if (oflag && loadflag == NO) obj = aoutname; else obj = setdoto(s); nparms = 0; ADD(asmname); ADD("-o"); ADD(obj); ADD(asmfname); ADD(NULL); if (callsys(asmname, params)) fatal1("assembler error"); if(verbose) fprintf(diagfile, "\n"); } static void doload(char *v0[], char *v[]) { int nparms, i; char *params[MAXARGS]; char **p; nparms = 0; ADD(ldname); ADD("-X"); ADD("-d"); for (i = 0; dynlinker[i]; i++) ADD(dynlinker[i]); ADD("-o"); ADD(aoutname); ADD(crt0file); for (i = 0; startfiles[i]; i++) ADD(startfiles[i]); *v = NULL; for(p = v0; *p ; p++) ADD(*p); if (libdir) ADD(libdir); for(p = liblist ; *p ; p++) ADD(*p); for (i = 0; endfiles[i]; i++) ADD(endfiles[i]); ADD(NULL); if (callsys(ldname, params)) fatal1("couldn't load %s", ldname); if(verbose) fprintf(diagfile, "\n"); } /* Process control and Shell-simulating routines */ /* * Execute f[] with parameter array v[]. * Copied from cc. */ static int callsys(char f[], char *v[]) { int t, status = 0; pid_t p; char *s; if (debugflag || verbose) { fprintf(stderr, "%s ", f); for (t = 1; v[t]; t++) fprintf(stderr, "%s ", v[t]); fprintf(stderr, "\n"); } if ((p = fork()) == 0) { #ifdef notyet if (Bflag) { size_t len = strlen(Bflag) + 8; char *a = malloc(len); if (a == NULL) { error("callsys: malloc failed"); exit(1); } if ((s = strrchr(f, '/'))) { strlcpy(a, Bflag, len); strlcat(a, s, len); execv(a, v); } } #endif execvp(f, v); if ((s = strrchr(f, '/'))) execvp(s+1, v); fprintf(stderr, "Can't find %s\n", f); _exit(100); } else { if (p == -1) { printf("Try again\n"); return(100); } } while (waitpid(p, &status, 0) == -1 && errno == EINTR) ; if (WIFEXITED(status)) return (WEXITSTATUS(status)); if (WIFSIGNALED(status)) done(1); fatal1("Fatal error in %s", f); return 0; /* XXX */ } static int sys(char *str) { char *s, *t; char *argv[100], path[100]; char *inname, *outname; int append = 0; int wait_pid; int argc; if(debugflag) fprintf(diagfile, "%s\n", str); inname = NULL; outname = NULL; argv[0] = shellname; argc = 1; t = str; while( isspace((int)*t) ) ++t; while(*t) { if(*t == '<') inname = t+1; else if(*t == '>') { if(t[1] == '>') { append = YES; outname = t+2; } else { append = NO; outname = t+1; } } else argv[argc++] = t; while( !isspace((int)*t) && *t!='\0' ) ++t; if(*t) { *t++ = '\0'; while( isspace((int)*t) ) ++t; } } if(argc == 1) /* no command */ return(-1); argv[argc] = 0; s = path; t = "/usr/bin/"; while(*t) *s++ = *t++; for(t = argv[1] ; (*s++ = *t++) ; ) ; if((wait_pid = fork()) == 0) { if(inname) freopen(inname, "r", stdin); if(outname) freopen(outname, (append ? "a" : "w"), stdout); enbint(SIG_DFL); texec(path+9, argv); /* command */ texec(path+4, argv); /* /bin/command */ texec(path , argv); /* /usr/bin/command */ fatal1("Cannot load %s",path+9); } return( await(wait_pid) ); } /* modified version from the Shell */ static void texec(char *f, char **av) { execv(f, av+1); if (errno==ENOEXEC) { av[1] = f; execv(shellname, av); fatal1("No shell!"); } if (errno==ENOMEM) fatal1("%s: too large", f); } /* * Cleanup and exit with value k. */ static void done(int k) { static int recurs = NO; if(recurs == NO) { recurs = YES; if (saveasmflag == NO) rmf(asmfname); } exit(k); } static void enbint(void (*k)(int)) { if(sigivalue == 0) signal(SIGINT,k); if(sigqvalue == 0) signal(SIGQUIT,k); } static void intrupt(int a) { done(2); } static int await(int wait_pid) { int w, status; enbint(SIG_IGN); while ( (w = wait(&status)) != wait_pid) if(w == -1) fatal1("bad wait code"); enbint(intrupt); if(status & 0377) { if(status != SIGINT) fprintf(diagfile, "Termination code %d", status); done(3); } return(status>>8); } /* File Name and File Manipulation Routines */ static int unreadable(char *s) { FILE *fp; if((fp = fopen(s, "r"))) { fclose(fp); return(NO); } else { fprintf(diagfile, "Error: Cannot read file %s\n", s); loadflag = NO; return(YES); } } static void crfnames(void) { snprintf(asmfname, sizeof(asmfname), "fort%d.%s", pid, "s"); snprintf(prepfname, sizeof(prepfname), "fort%d.%s", pid, "p"); } static void rmf(char *fn) { if(!debugflag && fn!=NULL && *fn!='\0') unlink(fn); } static int dotchar(char *s) { for( ; *s ; ++s) if(s[0]=='.' && s[1]!='\0' && s[2]=='\0') return( s[1] ); return(NO); } static char * lastfield(char *s) { char *t; for(t = s; *s ; ++s) if(*s == '/') t = s+1; return(t); } static char * lastchar(char *s) { while(*s) ++s; return(s-1); } static char * setdoto(char *s) { *lastchar(s) = 'o'; return( lastfield(s) ); } static char * copyn(int n, char *s) { char *p, *q; p = q = (char *)calloc(1, (unsigned) n + 1); if (!p) fatal1("out of memory"); while(n-- > 0) *q++ = *s++; return (p); } static int nodup(char *s) { char **p; for(p = loadargs ; p < loadp ; ++p) if( !strcmp(*p, s) ) return(NO); return(YES); } static void errorx(char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(diagfile, fmt, ap); fprintf(diagfile, "\n"); va_end(ap); if (debugflag) abort(); done(1); } static void fatal1(char *fmt, ...) { va_list ap; va_start(ap, fmt); fprintf(diagfile, "Compiler error in file %s: ", infname); vfprintf(diagfile, fmt, ap); fprintf(diagfile, "\n"); va_end(ap); if (debugflag) abort(); done(1); } pcc-20181216/f77/fcom004075500017500000000000000000001340533064100127365ustar raggewheelpcc-20181216/f77/fcom/CVS004075500017500000000000000000001340533064100133715ustar raggewheelpcc-20181216/f77/fcom/CVS/Root010064400017500000000000000000111340533064100143030ustar raggewheel/cvsroot pcc-20181216/f77/fcom/CVS/Repository010064400017500000000000000000151340533064100155430ustar raggewheelpcc/f77/fcom pcc-20181216/f77/fcom/CVS/Entries010064400017500000000000000017721340533064100150100ustar raggewheel/Makefile.in/1.23/Tue Sep 25 11:17:17 2012// /data.c/1.15/Sun May 11 15:28:03 2008// /defines.h/1.15/Sat May 10 07:53:41 2008// /defs.h/1.23/Mon Dec 12 09:18:25 2011// /equiv.c/1.11/Sun May 11 15:28:03 2008// /error.c/1.8/Sat May 10 07:53:41 2008// /exec.c/1.14/Sun May 11 15:28:03 2008// /expr.c/1.20/Sun May 11 15:28:03 2008// /ftypes.h/1.5/Fri Dec 19 08:08:48 2008// /gram.dcl/1.7/Sat May 10 08:44:17 2008// /gram.exec/1.4/Sat May 10 08:39:27 2008// /gram.expr/1.4/Sun May 4 09:51:57 2008// /gram.head/1.9/Sat May 10 07:53:41 2008// /gram.io/1.1/Sun Apr 17 13:54:38 2005// /init.c/1.16/Wed Dec 24 17:40:41 2008// /intr.c/1.13/Sun May 11 15:28:03 2008// /io.c/1.15/Fri Dec 19 08:08:48 2008// /lex.c/1.12/Sun May 11 15:28:03 2008// /main.c/1.17/Thu Mar 22 18:51:40 2012// /misc.c/1.17/Wed Feb 11 15:58:55 2009// /proc.c/1.14/Wed Dec 24 17:40:41 2008// /put.c/1.17/Sun May 11 15:28:03 2008// /putscj.c/1.18/Fri Dec 19 08:08:48 2008// /scjdefs.h/1.9/Sun Mar 23 09:17:44 2008// /tokens/1.2/Wed Mar 5 18:50:33 2008// D pcc-20181216/f77/fcom/Makefile.in010064400017500000000000000111501203031127500150500ustar raggewheel# $Id: Makefile.in,v 1.23 2012/09/25 11:17:17 plunky Exp $ # # Makefile for the Fortran 77 compiler # srcdir=@srcdir@ top_srcdir=@top_srcdir@ builddir=@builddir@ top_builddir=@top_builddir@ CC = @CC@ CC_FOR_BUILD = @CC_FOR_BUILD@ CFLAGS = @CFLAGS@ @ADD_CFLAGS@ CPPFLAGS = @CPPFLAGS@ @ADD_CPPFLAGS@ -DFCOM -DLANG_F77 \ -Dos_$(TARGOS) -Dmach_$(TARGMACH) \ -I$(srcdir) -I$(builddir) -I$(top_builddir) \ -I$(MIPDIR) -I$(MDIR) -I$(top_srcdir)/os/$(TARGOS) LIBS = @LIBS@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LFLAGS = LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ YACC = @YACC@ YFLAGS = @YFLAGS@ TARGOS = @targos@ TARGOSVER = @targosver@ TARGMACH = @targmach@ prefix = @prefix@ exec_prefix = @exec_prefix@ libexecdir = @libexecdir@ datarootdir = @datarootdir@ mandir = @mandir@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ MDIR=$(top_srcdir)/arch/$(TARGMACH) MIPDIR=$(top_srcdir)/mip DEST=@BINPREFIX@fcom$(EXEEXT) MKEXT=mkext$(EXEEXT) OBJS= common.o compat.o data.o equiv.o error.o exec.o expr.o \ external.o flocal.o gram.o init.o intr.o io.o lex.o \ local2.o main.o match.o misc.o optim2.o order.o proc.o \ put.o putscj.o reader.o regs.o table.o LOBJS= common.lo mkext.lo table.lo HDRS= $(srcdir)/defs.h $(srcdir)/defines.h $(srcdir)/ftypes.h \ $(MIPDIR)/pass2.h $(MIPDIR)/manifest.h $(MIPDIR)/node.h \ $(MDIR)/macdefs.h GSRC= $(srcdir)/gram.head $(srcdir)/gram.dcl $(srcdir)/gram.expr \ $(srcdir)/gram.exec $(srcdir)/gram.io all: $(DEST) # # round 1: generate external.[ch] & gram.[ch] # $(LOBJS): $(HDRS) common.lo: $(MIPDIR)/common.c $(CC_FOR_BUILD) $(CFLAGS) $(CPPFLAGS) -DMKEXT -c -o $@ $(MIPDIR)/common.c mkext.lo: $(MIPDIR)/mkext.c $(CC_FOR_BUILD) $(CFLAGS) $(CPPFLAGS) -DMKEXT -c -o $@ $(MIPDIR)/mkext.c table.lo: $(MDIR)/table.c $(CC_FOR_BUILD) $(CFLAGS) $(CPPFLAGS) -DMKEXT -c -o $@ $(MDIR)/table.c $(MKEXT): $(LOBJS) $(CC_FOR_BUILD) $(LDFLAGS) $(LOBJS) -o $@ $(LIBS) external.c: $(MKEXT) $(builddir)/$(MKEXT) gram.c: $(GSRC) $(srcdir)/tokens ( grep -n . < $(srcdir)/tokens | sed "s/\([^:]*\):\(.*\)/%token \2 \1/"; \ cat $(GSRC) ) > gram.y $(YACC) $(YFLAGS) -d gram.y mv -f y.tab.c gram.c mv -f y.tab.h gram.h # # round 2: compile $(OBJS) # $(OBJS): $(HDRS) external.c gram.c common.o: $(MIPDIR)/common.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/common.c compat.o: $(MIPDIR)/compat.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/compat.c data.o: $(srcdir)/data.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/data.c equiv.o: $(srcdir)/equiv.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/equiv.c error.o: $(srcdir)/error.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/error.c exec.o: $(srcdir)/exec.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/exec.c expr.o: $(srcdir)/expr.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/expr.c external.o: external.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ external.c flocal.o: $(MDIR)/flocal.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/flocal.c gram.o: gram.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ gram.c init.o: $(srcdir)/init.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/init.c intr.o: $(srcdir)/intr.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/intr.c io.o: $(srcdir)/io.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/io.c lex.o: $(srcdir)/lex.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/lex.c local2.o: $(MDIR)/local2.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/local2.c main.o: $(srcdir)/main.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/main.c match.o: $(MIPDIR)/match.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/match.c misc.o: $(srcdir)/misc.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/misc.c optim2.o: $(MIPDIR)/optim2.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/optim2.c order.o: $(MDIR)/order.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/order.c proc.o: $(srcdir)/proc.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/proc.c put.o: $(srcdir)/put.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/put.c putscj.o: $(srcdir)/putscj.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(srcdir)/putscj.c reader.o: $(MIPDIR)/reader.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/reader.c regs.o: $(MIPDIR)/regs.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MIPDIR)/regs.c table.o: $(MDIR)/table.c $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $(MDIR)/table.c # # round 3: build $(DEST) # $(DEST): $(OBJS) $(CC) $(LDFLAGS) $(OBJS) -o $@ $(LIBS) install: $(DEST) test -z "$(DESTDIR)$(libexecdir)" || mkdir -p "$(DESTDIR)$(libexecdir)" $(INSTALL_PROGRAM) $(DEST) $(DESTDIR)$(libexecdir) clean: rm -f $(DEST) $(OBJS) $(MKEXT) $(LOBJS) \ y.tab.[ch] gram.[ych] external.[ch] distclean: clean rm -f Makefile pcc-20181216/f77/fcom/data.c010064400017500000000000000202051101161020300140500ustar raggewheel/* $Id: data.c,v 1.15 2008/05/11 15:28:03 ragge Exp $ */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code and documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditionsand the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "defines.h" #include "defs.h" #if 1 /* RAGGE */ extern FILE *initfile; #endif /* ROUTINES CALLED DURING DATA STATEMENT PROCESSING */ LOCAL void setdata(struct bigblock *, struct bigblock *, ftnint, ftnint); static char datafmt[] = "%s\t%05ld\t%05ld\t%d" ; /* another initializer, called from parser */ void dataval(repp, valp) register struct bigblock *repp, *valp; { int i, nrep; ftnint elen, vlen; register struct bigblock *p; if(repp == NULL) nrep = 1; else if (ISICON(repp) && repp->b_const.fconst.ci >= 0) nrep = repp->b_const.fconst.ci; else { err("invalid repetition count in DATA statement"); frexpr(repp); goto ret; } frexpr(repp); if( ! ISCONST(valp) ) { err("non-constant initializer"); goto ret; } if(toomanyinit) goto ret; for(i = 0 ; i < nrep ; ++i) { p = nextdata(&elen, &vlen); if(p == NULL) { err("too many initializers"); toomanyinit = YES; goto ret; } setdata(p, valp, elen, vlen); frexpr(p); } ret: frexpr(valp); } struct bigblock *nextdata(elenp, vlenp) ftnint *elenp, *vlenp; { register struct bigblock *ip; struct bigblock *pp; register struct bigblock *np; register chainp rp; bigptr p; bigptr neltp; register bigptr q; int skip; ftnint off; while(curdtp) { p = curdtp->chain.datap; if(p->tag == TIMPLDO) { ip = p; if(ip->b_impldo.implb==NULL || ip->b_impldo.impub==NULL || ip->b_impldo.varnp==NULL) fatal1("bad impldoblock 0%o", ip); if(ip->isactive) ip->b_impldo.varvp->b_const.fconst.ci += ip->b_impldo.impdiff; else { q = fixtype(cpexpr(ip->b_impldo.implb)); if( ! ISICON(q) ) goto doerr; ip->b_impldo.varvp = q; if(ip->b_impldo.impstep) { q = fixtype(cpexpr(ip->b_impldo.impstep)); if( ! ISICON(q) ) goto doerr; ip->b_impldo.impdiff = q->b_const.fconst.ci; frexpr(q); } else ip->b_impldo.impdiff = 1; q = fixtype(cpexpr(ip->b_impldo.impub)); if(! ISICON(q)) goto doerr; ip->b_impldo.implim = q->b_const.fconst.ci; frexpr(q); ip->isactive = YES; rp = ALLOC(rplblock); rp->rplblock.nextp = rpllist; rpllist = rp; rp->rplblock.rplnp = ip->b_impldo.varnp; rp->rplblock.rplvp = ip->b_impldo.varvp; rp->rplblock.rpltag = TCONST; } if( (ip->b_impldo.impdiff>0 && (ip->b_impldo.varvp->b_const.fconst.ci <= ip->b_impldo.implim)) || (ip->b_impldo.impdiff<0 && (ip->b_impldo.varvp->b_const.fconst.ci >= ip->b_impldo.implim))) { /* start new loop */ curdtp = ip->b_impldo.datalist; goto next; } /* clean up loop */ popstack(&rpllist); frexpr(ip->b_impldo.varvp); ip->isactive = NO; curdtp = curdtp->chain.nextp; goto next; } pp = p; np = pp->b_prim.namep; skip = YES; if(p->b_prim.argsp==NULL && np->b_name.vdim!=NULL) { /* array initialization */ q = mkaddr(np); off = typesize[np->vtype] * curdtelt; if(np->vtype == TYCHAR) off *= np->vleng->b_const.fconst.ci; q->b_addr.memoffset = mkexpr(OPPLUS, q->b_addr.memoffset, mkintcon(off) ); if( (neltp = np->b_name.vdim->nelt) && ISCONST(neltp)) { if(++curdtelt < neltp->b_const.fconst.ci) skip = NO; } else err("attempt to initialize adjustable array"); } else q = mklhs( cpexpr(pp) ); if(skip) { curdtp = curdtp->chain.nextp; curdtelt = 0; } if(q->vtype == TYCHAR) if(ISICON(q->vleng)) *elenp = q->vleng->b_const.fconst.ci; else { err("initialization of string of nonconstant length"); continue; } else *elenp = typesize[q->vtype]; if(np->vstg == STGCOMMON) *vlenp = extsymtab[np->b_name.vardesc.varno].maxleng; else if(np->vstg == STGEQUIV) *vlenp = eqvclass[np->b_name.vardesc.varno].eqvleng; else { *vlenp = (np->vtype==TYCHAR ? np->vleng->b_const.fconst.ci : typesize[np->vtype]); if(np->b_name.vdim) *vlenp *= np->b_name.vdim->nelt->b_const.fconst.ci; } return(q); doerr: err("nonconstant implied DO parameter"); frexpr(q); curdtp = curdtp->chain.nextp; next: curdtelt = 0; } return(NULL); } LOCAL void setdata(varp, valp, elen, vlen) struct bigblock *varp; ftnint elen, vlen; struct bigblock *valp; { union constant con; int i, k; int stg, type, valtype; ftnint offset; register char *s, *t; static char varname[XL+2]; /* output form of name is padded with blanks and preceded with a storage class digit */ stg = varp->vstg; varname[0] = (stg==STGCOMMON ? '2' : (stg==STGEQUIV ? '1' : '0') ); s = memname(stg, varp->b_addr.memno); for(t = varname+1 ; *s ; ) *t++ = *s++; while(t < varname+XL+1) *t++ = ' '; varname[XL+1] = '\0'; offset = varp->b_addr.memoffset->b_const.fconst.ci; type = varp->vtype; valtype = valp->vtype; if(type!=TYCHAR && valtype==TYCHAR) { if(! ftn66flag) warn("non-character datum initialized with character string"); varp->vleng = MKICON(typesize[type]); varp->vtype = type = TYCHAR; } else if( (type==TYCHAR && valtype!=TYCHAR) || (cktype(OPASSIGN,type,valtype) == TYERROR) ) { err("incompatible types in initialization"); return; } if(type != TYCHAR) { if(valtype == TYUNKNOWN) con.ci = valp->b_const.fconst.ci; else consconv(type, &con, valtype, &valp->b_const.fconst); } k = 1; switch(type) { case TYLOGICAL: type = tylogical; case TYSHORT: case TYLONG: fprintf(initfile, datafmt, varname, offset, vlen, type); prconi(initfile, type, con.ci); break; case TYCOMPLEX: k = 2; type = TYREAL; case TYREAL: goto flpt; case TYDCOMPLEX: k = 2; type = TYDREAL; case TYDREAL: flpt: for(i = 0 ; i < k ; ++i) { fprintf(initfile, datafmt, varname, offset, vlen, type); prconr(initfile, type, con.cd[i]); offset += typesize[type]; } break; case TYCHAR: k = valp->vleng->b_const.fconst.ci; if(elen < k) k = elen; for(i = 0 ; i < k ; ++i) { fprintf(initfile, datafmt, varname, offset++, vlen, TYCHAR); fprintf(initfile, "\t%d\n", valp->b_const.fconst.ccp[i]); } k = elen - valp->vleng->b_const.fconst.ci; while( k-- > 0) { fprintf(initfile, datafmt, varname, offset++, vlen, TYCHAR); fprintf(initfile, "\t%d\n", ' '); } break; default: fatal1("setdata: impossible type %d", type); } } void frdata(p0) chainp p0; { register chainp p; register bigptr q; for(p = p0 ; p ; p = p->chain.nextp) { q = p->chain.datap; if(q->tag == TIMPLDO) { if(q->isbusy) return; /* circular chain completed */ q->isbusy = YES; frdata(q->b_impldo.datalist); ckfree(q); } else frexpr(q); } frchain( &p0); } pcc-20181216/f77/fcom/defines.h010064400017500000000000000135321101125220500145720ustar raggewheel/* $Id: defines.h,v 1.15 2008/05/10 07:53:41 ragge Exp $ */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code and documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditionsand the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #ifdef FCOM #include "pass2.h" #endif #include "ftypes.h" #define INTERDATA 2 #define GCOS 3 #define PDP11 4 #define IBM 5 #define CMACH 6 #define VAX 7 #define DMR 2 #define SCJ 3 #define BINARY 2 #define ASCII 3 #define PREFIX 2 #define POSTFIX 3 #define M(x) (1<tag==TCONST && ISINT(z->vtype)) #define ISCHAR(z) (z->vtype==TYCHAR) #define ISINT(z) ONEOF(z, MSKINT) #define ISCONST(z) (z->tag==TCONST) #define ISERROR(z) (z->tag==TERROR) #define ISPLUSOP(z) (z->tag==TEXPR && z->b_expr.opcode==OPPLUS) #define ISSTAROP(z) (z->tag==TEXPR && z->b_expr.opcode==OPSTAR) #define ISONE(z) (ISICON(z) && z->b_const.fconst.ci==1) /* #define INT(z) ONEOF(z, MSKINT|MSKCHAR) */ #define MKICON(z) mkintcon( (ftnint)(z) ) #define CHCON(z) mkstrcon(strlen(z), z) /* round a up to a multiple of b */ #define roundup(a,b) ( b * ( (a+b-1)/b) ) /* prototypes for cpu-specific functions */ void prchars(int *); pcc-20181216/f77/fcom/defs.h010064400017500000000000000323061167134334100141140ustar raggewheel/* $Id: defs.h,v 1.23 2011/12/12 09:18:25 plunky Exp $ */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code and documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditionsand the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include /* Copied from ../../cc/ccom/pass1.h. */ #define DATA 1 #define RDATA 2 #define UDATA 4 #define VL 6 #define XL 8 #define MAXINCLUDES 10 #define MAXLITERALS 20 #define MAXCTL 20 #define MAXHASH 401 #define MAXSTNO 1000 #define MAXEXT 200 #define MAXEQUIV 150 #define MAXLABLIST 100 typedef struct bigblock *bigptr; typedef union chainedblock *chainp; extern FILE *infile; extern FILE *diagfile; extern long int headoffset; extern char token [ ]; extern int toklen; extern int lineno; extern char *infname; extern int needkwd; extern struct labelblock *thislabel; extern int mflag, tflag; extern flag profileflag; extern flag optimflag; extern flag quietflag; extern flag nowarnflag; extern flag ftn66flag; extern flag shiftcase; extern flag undeftype; extern flag shortsubs; extern flag onetripflag; extern flag checksubs; extern flag debugflag; extern int nerr; extern int nwarn; extern int ndata; extern int parstate; extern flag headerdone; extern int blklevel; extern flag saveall; extern flag substars; extern int impltype[ ]; extern int implleng[ ]; extern int implstg[ ]; extern int tyint; extern int tylogical; extern ftnint typesize[]; extern int typealign[]; extern int procno; extern int proctype; extern char * procname; extern int rtvlabel[ ]; extern int fudgelabel; /* to confuse the pdp11 optimizer */ extern struct bigblock *typeaddr; extern struct bigblock *retslot; extern int cxslot; extern int chslot; extern int chlgslot; extern int procclass; extern ftnint procleng; extern int nentry; extern flag multitype; extern int blklevel; extern int lastlabno; extern int lastvarno; extern int lastargslot; extern int argloc; extern ftnint autoleng; extern ftnint bssleng; extern int retlabel; extern int ret0label; extern int dorange; extern int regnum[ ]; extern bigptr regnamep[ ]; extern int maxregvar; extern int highregvar; extern chainp templist; extern chainp holdtemps; extern chainp entries; extern chainp rpllist; extern chainp curdtp; extern ftnint curdtelt; extern flag toomanyinit; extern flag inioctl; extern int iostmt; extern struct bigblock *ioblkp; extern int nioctl; extern int nequiv; extern int nintnames; extern int nextnames; struct chain { chainp nextp; bigptr datap; }; extern chainp chains; struct ctlframe { unsigned ctltype:8; unsigned dostepsign:8; int ctlabels[4]; int dolabel; struct bigblock *donamep; bigptr domax; bigptr dostep; }; #define endlabel ctlabels[0] #define elselabel ctlabels[1] #define dobodylabel ctlabels[1] #define doposlabel ctlabels[2] #define doneglabel ctlabels[3] extern struct ctlframe ctls[ ]; extern struct ctlframe *ctlstack; extern struct ctlframe *lastctl; struct extsym { char extname[XL]; unsigned extstg:4; unsigned extsave:1; unsigned extinit:1; chainp extp; ftnint extleng; ftnint maxleng; }; extern struct extsym extsymtab[ ]; extern struct extsym *nextext; extern struct extsym *lastext; struct labelblock { int labelno; unsigned blklevel:8; unsigned labused:1; unsigned labinacc:1; unsigned labdefined:1; unsigned labtype:2; ftnint stateno; }; extern struct labelblock labeltab[ ]; extern struct labelblock *labtabend; extern struct labelblock *highlabtab; struct entrypoint { chainp nextp; struct extsym *entryname; chainp arglist; int entrylabel; int typelabel; ptr enamep; }; struct primblock { struct bigblock *namep; struct bigblock *argsp; bigptr fcharp; bigptr lcharp; }; struct hashentry { int hashval; struct bigblock *varp; }; extern struct hashentry hashtab[ ]; extern struct hashentry *lasthash; struct intrpacked /* bits for intrinsic function description */ { unsigned f1:3; unsigned f2:4; unsigned f3:7; }; struct nameblock { char varname[VL]; unsigned vdovar:1; unsigned vdcldone:1; unsigned vadjdim:1; unsigned vsave:1; unsigned vprocclass:3; unsigned vregno:4; union { int varno; chainp vstfdesc; /* points to (formals, expr) pair */ struct intrpacked intrdesc; /* bits for intrinsic function */ } vardesc; struct dimblock *vdim; int voffset; }; struct paramblock { char varname[VL]; bigptr paramval; } ; struct exprblock { unsigned opcode:6; bigptr leftp; bigptr rightp; }; struct dcomplex { double dreal, dimag; }; union constant { char *ccp; ftnint ci; double cd[2]; struct dcomplex dc; }; struct constblock { union constant fconst; }; struct listblock { chainp listp; }; struct addrblock { int memno; bigptr memoffset; unsigned istemp:1; unsigned ntempelt:10; }; struct errorblock { int pad; }; struct dimblock { int ndim; bigptr nelt; bigptr baseoffset; bigptr basexpr; struct { bigptr dimsize; bigptr dimexpr; } dims[1]; }; struct impldoblock /* XXXX */ { #define isactive vtype #define isbusy vclass struct bigblock *varnp; struct bigblock *varvp; bigptr implb; bigptr impub; bigptr impstep; ftnint impdiff; ftnint implim; chainp datalist; }; struct rplblock /* name replacement block */ { chainp nextp; struct bigblock *rplnp; ptr rplvp; struct bigblock *rplxp; int rpltag; }; struct equivblock { ptr equivs; unsigned eqvinit:1; long int eqvtop; long int eqvbottom; } ; #define eqvleng eqvtop extern struct equivblock eqvclass[ ]; struct eqvchain { chainp nextp; ptr eqvitem; long int eqvoffset; } ; union chainedblock { struct chain chain; struct entrypoint entrypoint; struct rplblock rplblock; struct eqvchain eqvchain; }; struct bigblock { unsigned tag:4; unsigned vtype:4; unsigned vclass:4; unsigned vstg:4; bigptr vleng; union { struct exprblock _expr; struct addrblock _addr; struct constblock _const; struct errorblock _error; struct listblock _list; struct primblock _prim; struct nameblock _name; struct paramblock _param; struct impldoblock _impldo; } _u; #define b_expr _u._expr #define b_addr _u._addr #define b_const _u._const #define b_error _u._error #define b_list _u._list #define b_prim _u._prim #define b_name _u._name #define b_param _u._param #define b_impldo _u._impldo }; struct literal { short littype; short litnum; union { ftnint litival; double litdval; struct { char litclen; /* small integer */ char litcstr[XL]; } litcval; } litval; }; extern struct literal litpool[ ]; extern int nliterals; /* popular functions with non integer return values */ #define expptr bigptr #define tagptr bigptr ptr cpblock(int ,void *); ptr ckalloc(int); char *varstr(int, char *), *nounder(int, char *), *varunder(int, char *); char *copyn(int, char *), *copys(char *); chainp hookup(chainp, chainp), mkchain(bigptr, chainp); ftnint convci(int, char *), iarrlen(struct bigblock *q); ftnint lmin(ftnint, ftnint), lmax(ftnint, ftnint); ftnint simoffset(expptr *); char *memname(int, int), *convic(ftnint), *setdoto(char *); double convcd(int, char *); struct extsym *mkext(char *), *newentry(struct bigblock *), *comblock(int, char *s); struct bigblock *mkname(int, char *); struct labelblock *mklabel(ftnint); struct bigblock *addrof(expptr), *call1(int, char *, expptr), *call2(int, char *, expptr, expptr), *call3(int, char *, expptr, expptr, expptr), *call4(int, char *, expptr, expptr, expptr, expptr); struct bigblock *call0(int, char *), *mkexpr(int, bigptr, bigptr); struct bigblock *callk(int, char *, bigptr); struct bigblock *builtin(int, char *), *fmktemp(int, bigptr), *mktmpn(int, int, bigptr), *nextdata(ftnint *, ftnint *), *autovar(int, int, bigptr), *mklhs(struct bigblock *), *mkaddr(struct bigblock *), *putconst(struct bigblock *), *memversion(struct bigblock *); struct bigblock *mkscalar(struct bigblock *np); struct bigblock *realpart(struct bigblock *p); struct bigblock *imagpart(struct bigblock *p); struct bigblock *mkintcon(ftnint), *mkbitcon(int, int, char *), *mklogcon(int), *mkaddcon(int), *mkrealcon(int, double), *mkstrcon(int, char *), *mkcxcon(bigptr,bigptr); bigptr mkconst(int t); bigptr mklist(chainp p); bigptr mkiodo(chainp, chainp); bigptr mkconv(int, bigptr), mkfunct(struct bigblock *), fixexpr(struct bigblock *), fixtype(bigptr); bigptr cpexpr(bigptr), mkprim(bigptr, struct bigblock *, bigptr, bigptr); struct bigblock *mkarg(int, int); struct bigblock *errnode(void); void initkey(void), prtail(void), puteof(void), done(int); void fileinit(void), procinit(void), endproc(void), doext(void), preven(int); int inilex(char *), yyparse(void), newlabel(void), lengtype(int, int); void err(char *, ...), warn(char *, ...), fatal(char *, ...), enddcl(void); void p2pass(char *s), frexpr(bigptr), execerr(char *, ...); void setimpl(int, ftnint, int, int), setlog(void), newproc(void); void prdbginfo(void), impldcl(struct bigblock *p); void putbracket(void), enddcl(void), doequiv(void); void puthead(char *), startproc(struct extsym *, int); void dclerr(char *s, struct bigblock *v), putforce(int, bigptr); void entrypt(int, int, ftnint, struct extsym *, chainp); void settype(struct bigblock *, int, int), putlabel(int); void putbranch(struct bigblock *p), goret(int), putrbrack(int); void prolog(struct entrypoint *, struct bigblock *), prendproc(void); void prlocvar(char *, ftnint), prext(char *, ftnint, int); void vardcl(struct bigblock *v), frchain(chainp *p); void frtemp(struct bigblock *p), incomm(struct extsym *, struct bigblock *); void setintr(struct bigblock * v), setext(struct bigblock * v); struct uux { expptr lb, ub; }; void setbound(struct bigblock *, int, struct uux []); void setfmt(struct labelblock *lp), frdata(chainp), frrpl(void), dataval(struct bigblock *, struct bigblock *), consnegop(struct bigblock *p), exdo(int, chainp), exelse(void), exendif(void), exif(bigptr), exelif(bigptr), exequals(struct bigblock *, bigptr), exassign(struct bigblock *, struct labelblock *), exarif(bigptr, struct labelblock *, struct labelblock *, struct labelblock *); int intrfunct(char s[VL]), eqn(int, char *, char *); int fmtstmt(struct labelblock *lp); int cktype(int, int, int); int yylex(void), inregister(struct bigblock *); int inilex(char *), iocname(void); int maxtype(int, int), flog2(ftnint), hextoi(int); int cmpstr(char *, char *, ftnint, ftnint); int enregister(struct bigblock *np); int conssgn(bigptr p); int fixargs(int, struct bigblock *); int addressable(bigptr p); void prlabel(int); void prconi(FILE *, int, ftnint); void prcona(ftnint); void prconr(FILE *, int, double); void prarif(bigptr, int, int, int); void putstr(char *, ftnint); NODE *putex1(bigptr p); void puteq(bigptr, bigptr); void popstack(chainp *p); void consconv(int, union constant *, int, union constant *); void yyerror(char *s); void enddo(int); void doinclude(char *); void flline(void); void startioctl(void); void endioctl(void), endio(void), ioclause(int, bigptr), doio(chainp); void excall(struct bigblock *, struct bigblock *, int, struct labelblock *[]); void exreturn(expptr p); void exstop(int, expptr); void exgoto(struct labelblock *); void exasgoto(bigptr); void putcmgo(expptr, int, struct labelblock *[]); void putexpr(expptr p); void putif(expptr, int); void putgoto(int); void deregister(struct bigblock *np); NODE *putx(expptr p); void cpn(int, char *, char *); void prcmgoto(expptr, int, int, int); char *lexline(ftnint *n); bigptr suboffset(struct bigblock *p); struct bigblock *intraddr(struct bigblock *np); struct bigblock *intrcall(bigptr, bigptr, int); void setloc(int); void prnloc(char *name); void fprint(bigptr p, int indx); void ckfree(void *p); #undef expptr #undef tagptr #define err1 err #define err2 err #define warn1 warn #define fatal1 fatal pcc-20181216/f77/fcom/equiv.c010064400017500000000000000165631101161020300143040ustar raggewheel/* $Id: equiv.c,v 1.11 2008/05/11 15:28:03 ragge Exp $ */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code and documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditionsand the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "defines.h" #include "defs.h" /* ROUTINES RELATED TO EQUIVALENCE CLASS PROCESSING */ LOCAL void eqvcommon(struct equivblock *, int, ftnint); LOCAL void eqveqv(int, int, ftnint); LOCAL void freqchain(struct equivblock *p); LOCAL int nsubs(struct bigblock *p); /* called at end of declarations section to process chains created by EQUIVALENCE statements */ void doequiv() { register int i; int inequiv, comno, ovarno; ftnint comoffset, offset, leng; register struct equivblock *p; register chainp q; struct bigblock *itemp; register struct bigblock *np; bigptr offp; int ns; chainp cp; ovarno = comoffset = offset = 0; /* XXX gcc */ for(i = 0 ; i < nequiv ; ++i) { p = &eqvclass[i]; p->eqvbottom = p->eqvtop = 0; comno = -1; for(q = p->equivs ; q ; q = q->eqvchain.nextp) { itemp = q->eqvchain.eqvitem; vardcl(np = itemp->b_prim.namep); if(itemp->b_prim.argsp || itemp->b_prim.fcharp) { if(np->b_name.vdim!=NULL && np->b_name.vdim->ndim>1 && nsubs(itemp->b_prim.argsp)==1 ) { if(! ftn66flag) warn("1-dim subscript in EQUIVALENCE"); cp = NULL; ns = np->b_name.vdim->ndim; while(--ns > 0) cp = mkchain( MKICON(1), cp); itemp->b_prim.argsp->b_list.listp->chain.nextp = cp; } offp = suboffset(itemp); } else offp = MKICON(0); if(ISICON(offp)) offset = q->eqvchain.eqvoffset = offp->b_const.fconst.ci; else { dclerr("nonconstant subscript in equivalence ", np); np = NULL; goto endit; } if( (leng = iarrlen(np)) < 0) { dclerr("adjustable in equivalence", np); np = NULL; goto endit; } p->eqvbottom = lmin(p->eqvbottom, -offset); p->eqvtop = lmax(p->eqvtop, leng-offset); switch(np->vstg) { case STGUNKNOWN: case STGBSS: case STGEQUIV: break; case STGCOMMON: comno = np->b_name.vardesc.varno; comoffset = np->b_name.voffset + offset; break; default: dclerr("bad storage class in equivalence", np); np = NULL; goto endit; } endit: frexpr(offp); q->eqvchain.eqvitem = np; } if(comno >= 0) eqvcommon(p, comno, comoffset); else for(q = p->equivs ; q ; q = q->eqvchain.nextp) { if((np = q->eqvchain.eqvitem)) { inequiv = NO; if(np->vstg==STGEQUIV) { if( (ovarno = np->b_name.vardesc.varno) == i) { if(np->b_name.voffset + q->eqvchain.eqvoffset != 0) dclerr("inconsistent equivalence", np); } else { offset = np->b_name.voffset; inequiv = YES; } } np->vstg = STGEQUIV; np->b_name.vardesc.varno = i; np->b_name.voffset = - q->eqvchain.eqvoffset; if(inequiv) eqveqv(i, ovarno, q->eqvchain.eqvoffset + offset); } } } for(i = 0 ; i < nequiv ; ++i) { p = & eqvclass[i]; if(p->eqvbottom!=0 || p->eqvtop!=0) { for(q = p->equivs ; q; q = q->eqvchain.nextp) { np = q->eqvchain.eqvitem; np->b_name.voffset -= p->eqvbottom; if(np->b_name.voffset % typealign[np->vtype] != 0) dclerr("bad alignment forced by equivalence", np); } p->eqvtop -= p->eqvbottom; p->eqvbottom = 0; } freqchain(p); } } /* put equivalence chain p at common block comno + comoffset */ LOCAL void eqvcommon(p, comno, comoffset) struct equivblock *p; int comno; ftnint comoffset; { int ovarno; ftnint k, offq; register struct bigblock *np; register chainp q; if(comoffset + p->eqvbottom < 0) { err1("attempt to extend common %s backward", nounder(XL, extsymtab[comno].extname) ); freqchain(p); return; } if( (k = comoffset + p->eqvtop) > extsymtab[comno].extleng) extsymtab[comno].extleng = k; for(q = p->equivs ; q ; q = q->eqvchain.nextp) if((np = q->eqvchain.eqvitem)) { switch(np->vstg) { case STGUNKNOWN: case STGBSS: np->vstg = STGCOMMON; np->b_name.vardesc.varno = comno; np->b_name.voffset = comoffset - q->eqvchain.eqvoffset; break; case STGEQUIV: ovarno = np->b_name.vardesc.varno; offq = comoffset - q->eqvchain.eqvoffset - np->b_name.voffset; np->vstg = STGCOMMON; np->b_name.vardesc.varno = comno; np->b_name.voffset = comoffset - q->eqvchain.eqvoffset; if(ovarno != (p - eqvclass)) eqvcommon(&eqvclass[ovarno], comno, offq); break; case STGCOMMON: if(comno != np->b_name.vardesc.varno || comoffset != np->b_name.voffset+q->eqvchain.eqvoffset) dclerr("inconsistent common usage", np); break; default: fatal1("eqvcommon: impossible vstg %d", np->vstg); } } freqchain(p); p->eqvbottom = p->eqvtop = 0; } /* put all items on ovarno chain on front of nvarno chain * adjust offsets of ovarno elements and top and bottom of nvarno chain */ LOCAL void eqveqv(nvarno, ovarno, delta) int ovarno, nvarno; ftnint delta; { register struct equivblock *p0, *p; register struct nameblock *np; chainp q, q1; p0 = eqvclass + nvarno; p = eqvclass + ovarno; p0->eqvbottom = lmin(p0->eqvbottom, p->eqvbottom - delta); p0->eqvtop = lmax(p0->eqvtop, p->eqvtop - delta); p->eqvbottom = p->eqvtop = 0; for(q = p->equivs ; q ; q = q1) { q1 = q->eqvchain.nextp; if( (np = q->eqvchain.eqvitem) && np->vardesc.varno==ovarno) { q->eqvchain.nextp = p0->equivs; p0->equivs = q; q->eqvchain.eqvoffset -= delta; np->vardesc.varno = nvarno; np->voffset -= delta; } else ckfree(q); } p->equivs = NULL; } LOCAL void freqchain(p) register struct equivblock *p; { register chainp q, oq; for(q = p->equivs ; q ; q = oq) { oq = q->eqvchain.nextp; ckfree(q); } p->equivs = NULL; } LOCAL int nsubs(p) register struct bigblock *p; { register int n; register chainp q; n = 0; if(p) for(q = p->b_list.listp ; q ; q = q->chain.nextp) ++n; return(n); } pcc-20181216/f77/fcom/error.c010064400017500000000000000060661101125220500143050ustar raggewheel/* $Id: error.c,v 1.8 2008/05/10 07:53:41 ragge Exp $ */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code and documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "defines.h" #include "defs.h" void warn(char *s, ...) { va_list ap; if(nowarnflag) return; va_start(ap, s); fprintf(diagfile, "Warning on line %d of %s: ", lineno, infname); vfprintf(diagfile, s, ap); fprintf(diagfile, "\n"); va_end(ap); ++nwarn; } void err(char *s, ...) { va_list ap; va_start(ap, s); fprintf(diagfile, "Error on line %d of %s: ", lineno, infname); vfprintf(diagfile, s, ap); fprintf(diagfile, "\n"); va_end(ap); ++nerr; } void yyerror(s) char *s; { err(s); } void dclerr(s, v) char *s; struct bigblock *v; { char buff[100]; if(v) { sprintf(buff, "Declaration error for %s: %s", varstr(VL, v->b_name.varname), s); err( buff); } else err1("Declaration error %s", s); } void execerr(char *s, ...) { va_list ap; va_start(ap, s); fprintf(diagfile, "Error on line %d of %s: Execution error ", lineno, infname); vfprintf(diagfile, s, ap); fprintf(diagfile, "\n"); va_end(ap); ++nerr; } void fatal(char *s, ...) { va_list ap; va_start(ap, s); fprintf(diagfile, "Compiler error line %d of %s: ", lineno, infname); vfprintf(diagfile, s, ap); fprintf(diagfile, "\n"); va_end(ap); if(debugflag) abort(); done(3); exit(3); } pcc-20181216/f77/fcom/exec.c010064400017500000000000000275301101161020300140730ustar raggewheel/* $Id: exec.c,v 1.14 2008/05/11 15:28:03 ragge Exp $ */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code and documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "defines.h" #include "defs.h" /* Logical IF codes */ LOCAL void exar2(int, bigptr, int, int); LOCAL void pushctl(int code); LOCAL void popctl(void); LOCAL void poplab(void); LOCAL void mkstfunct(struct bigblock *, bigptr); void exif(p) bigptr p; { pushctl(CTLIF); ctlstack->elselabel = newlabel(); putif(p, ctlstack->elselabel); } void exelif(p) bigptr p; { if(ctlstack->ctltype == CTLIF) { if(ctlstack->endlabel == 0) ctlstack->endlabel = newlabel(); putgoto(ctlstack->endlabel); putlabel(ctlstack->elselabel); ctlstack->elselabel = newlabel(); putif(p, ctlstack->elselabel); } else execerr("elseif out of place", 0); } void exelse() { if(ctlstack->ctltype==CTLIF) { if(ctlstack->endlabel == 0) ctlstack->endlabel = newlabel(); putgoto( ctlstack->endlabel ); putlabel(ctlstack->elselabel); ctlstack->ctltype = CTLELSE; } else execerr("else out of place", 0); } void exendif() { if(ctlstack->ctltype == CTLIF) { putlabel(ctlstack->elselabel); if(ctlstack->endlabel) putlabel(ctlstack->endlabel); popctl(); } else if(ctlstack->ctltype == CTLELSE) { putlabel(ctlstack->endlabel); popctl(); } else execerr("endif out of place", 0); } LOCAL void pushctl(code) int code; { register int i; if(++ctlstack >= lastctl) fatal("nesting too deep"); ctlstack->ctltype = code; for(i = 0 ; i < 4 ; ++i) ctlstack->ctlabels[i] = 0; ++blklevel; } LOCAL void popctl() { if( ctlstack-- < ctls ) fatal("control stack empty"); --blklevel; poplab(); } LOCAL void poplab() { register struct labelblock *lp; for(lp = labeltab ; lp < highlabtab ; ++lp) if(lp->labdefined) { /* mark all labels in inner blocks unreachable */ if(lp->blklevel > blklevel) lp->labinacc = YES; } else if(lp->blklevel > blklevel) { /* move all labels referred to in inner blocks out a level */ lp->blklevel = blklevel; } } /* BRANCHING CODE */ void exgoto(lab) struct labelblock *lab; { putgoto(lab->labelno); } /* * Found an assignment expression. */ void exequals(struct bigblock *lp, bigptr rp) { if(lp->tag != TPRIM) { err("assignment to a non-variable"); frexpr(lp); frexpr(rp); } else if(lp->b_prim.namep->vclass!=CLVAR && lp->b_prim.argsp) { if(parstate >= INEXEC) err("statement function amid executables"); else mkstfunct(lp, rp); } else { if(parstate < INDATA) enddcl(); puteq(mklhs(lp), rp); } } /* * Create a statement function; e.g. like "f(i)=i*i" */ void mkstfunct(struct bigblock *lp, bigptr rp) { struct bigblock *p; struct bigblock *np; chainp args; np = lp->b_prim.namep; if(np->vclass == CLUNKNOWN) np->vclass = CLPROC; else { dclerr("redeclaration of statement function", np); return; } np->b_name.vprocclass = PSTFUNCT; np->vstg = STGSTFUNCT; impldcl(np); args = (lp->b_prim.argsp ? lp->b_prim.argsp->b_list.listp : NULL); np->b_name.vardesc.vstfdesc = mkchain((void *)args, (void *)rp); for( ; args ; args = args->chain.nextp) if( (p = args->chain.datap)->tag!=TPRIM || p->b_prim.argsp || p->b_prim.fcharp || p->b_prim.lcharp) err("non-variable argument in statement function definition"); else { vardcl(args->chain.datap = p->b_prim.namep); ckfree(p); } } void excall(name, args, nstars, labels) struct bigblock *name; struct bigblock *args; int nstars; struct labelblock *labels[ ]; { register bigptr p; settype(name, TYSUBR, 0); p = mkfunct( mkprim(name, args, NULL, NULL) ); p->vtype = p->b_expr.leftp->vtype = TYINT; if(nstars > 0) putcmgo(p, nstars, labels); else putexpr(p); } void exstop(stop, p) int stop; register bigptr p; { char *q; int n; if(p) { if( ! ISCONST(p) ) { execerr("pause/stop argument must be constant", 0); frexpr(p); p = mkstrcon(0, 0); } else if( ISINT(p->vtype) ) { q = convic(p->b_const.fconst.ci); n = strlen(q); if(n > 0) { p->b_const.fconst.ccp = copyn(n, q); p->vtype = TYCHAR; p->vleng = MKICON(n); } else p = mkstrcon(0, 0); } else if(p->vtype != TYCHAR) { execerr("pause/stop argument must be integer or string", 0); p = mkstrcon(0, 0); } } else p = mkstrcon(0, 0); putexpr( call1(TYSUBR, (stop ? "s_stop" : "s_paus"), p) ); } /* DO LOOP CODE */ #define DOINIT par[0] #define DOLIMIT par[1] #define DOINCR par[2] #define VARSTEP 0 #define POSSTEP 1 #define NEGSTEP 2 void exdo(range, spec) int range; chainp spec; { register bigptr p, q; bigptr q1; register struct bigblock *np; chainp cp; register int i; int dotype, incsign = 0; /* XXX gcc */ struct bigblock *dovarp, *dostgp; bigptr par[3]; pushctl(CTLDO); dorange = ctlstack->dolabel = range; np = spec->chain.datap; ctlstack->donamep = NULL; if(np->b_name.vdovar) { err1("nested loops with variable %s", varstr(VL,np->b_name.varname)); ctlstack->donamep = NULL; return; } dovarp = mklhs( mkprim(np, 0,0,0) ); if( ! ONEOF(dovarp->vtype, MSKINT|MSKREAL) ) { err("bad type on do variable"); return; } ctlstack->donamep = np; np->b_name.vdovar = YES; if( enregister(np) ) { /* stgp points to a storage version, varp to a register version */ dostgp = dovarp; dovarp = mklhs( mkprim(np, 0,0,0) ); } else dostgp = NULL; dotype = dovarp->vtype; for(i=0 , cp = spec->chain.nextp ; cp!=NULL && i<3 ; cp = cp->chain.nextp) { p = par[i++] = fixtype(cp->chain.datap); if( ! ONEOF(p->vtype, MSKINT|MSKREAL) ) { err("bad type on DO parameter"); return; } } frchain(&spec); switch(i) { case 0: case 1: err("too few DO parameters"); return; default: err("too many DO parameters"); return; case 2: DOINCR = MKICON(1); case 3: break; } ctlstack->endlabel = newlabel(); ctlstack->dobodylabel = newlabel(); if( ISCONST(DOLIMIT) ) ctlstack->domax = mkconv(dotype, DOLIMIT); else ctlstack->domax = fmktemp(dotype, NULL); if( ISCONST(DOINCR) ) { ctlstack->dostep = mkconv(dotype, DOINCR); if( (incsign = conssgn(ctlstack->dostep)) == 0) err("zero DO increment"); ctlstack->dostepsign = (incsign > 0 ? POSSTEP : NEGSTEP); } else { ctlstack->dostep = fmktemp(dotype, NULL); ctlstack->dostepsign = VARSTEP; ctlstack->doposlabel = newlabel(); ctlstack->doneglabel = newlabel(); } if( ISCONST(ctlstack->domax) && ISCONST(DOINIT) && ctlstack->dostepsign!=VARSTEP) { puteq(cpexpr(dovarp), cpexpr(DOINIT)); if( onetripflag ) frexpr(DOINIT); else { q = mkexpr(OPPLUS, MKICON(1), mkexpr(OPMINUS, cpexpr(ctlstack->domax), cpexpr(DOINIT)) ); if(incsign != conssgn(q)) { warn("DO range never executed"); putgoto(ctlstack->endlabel); } frexpr(q); } } else if(ctlstack->dostepsign!=VARSTEP && !onetripflag) { if( ISCONST(ctlstack->domax) ) q = cpexpr(ctlstack->domax); else q = mkexpr(OPASSIGN, cpexpr(ctlstack->domax), DOLIMIT); q1 = mkexpr(OPASSIGN, cpexpr(dovarp), DOINIT); q = mkexpr( (ctlstack->dostepsign==POSSTEP ? OPLE : OPGE), q1, q); putif(q, ctlstack->endlabel); } else { if(! ISCONST(ctlstack->domax) ) puteq( cpexpr(ctlstack->domax), DOLIMIT); q = DOINIT; if( ! onetripflag ) q = mkexpr(OPMINUS, q, mkexpr(OPASSIGN, cpexpr(ctlstack->dostep), DOINCR) ); puteq( cpexpr(dovarp), q); if(onetripflag && ctlstack->dostepsign==VARSTEP) puteq( cpexpr(ctlstack->dostep), DOINCR); } if(ctlstack->dostepsign == VARSTEP) { if(onetripflag) putgoto(ctlstack->dobodylabel); else putif( mkexpr(OPGE, cpexpr(ctlstack->dostep), MKICON(0)), ctlstack->doneglabel ); putlabel(ctlstack->doposlabel); p = cpexpr(dovarp); putif( mkexpr(OPLE, mkexpr(OPASSIGN, p, mkexpr(OPPLUS, cpexpr(dovarp), cpexpr(ctlstack->dostep))), cpexpr(ctlstack->domax)), ctlstack->endlabel); } putlabel(ctlstack->dobodylabel); if(dostgp) puteq(dostgp, cpexpr(dovarp)); frexpr(dovarp); } /* * Reached the end of a DO statement. */ void enddo(int here) { register struct ctlframe *q; register bigptr t; struct bigblock *np; struct bigblock *ap; register int i; while(here == dorange) { if((np = ctlstack->donamep)) { t = mklhs(mkprim(ctlstack->donamep, 0,0 ,0)); t = mkexpr(OPASSIGN, cpexpr(t), mkexpr(OPPLUS, t, cpexpr(ctlstack->dostep))); if(ctlstack->dostepsign == VARSTEP) { putif( mkexpr(OPLE, cpexpr(ctlstack->dostep), MKICON(0)), ctlstack->doposlabel); putlabel(ctlstack->doneglabel); putif( mkexpr(OPLT, t, ctlstack->domax), ctlstack->dobodylabel); } else putif( mkexpr( (ctlstack->dostepsign==POSSTEP ? OPGT : OPLT), t, ctlstack->domax), ctlstack->dobodylabel); putlabel(ctlstack->endlabel); if((ap = memversion(np))) puteq(ap, mklhs( mkprim(np,0,0,0)) ); for(i = 0 ; i < 4 ; ++i) ctlstack->ctlabels[i] = 0; deregister(ctlstack->donamep); ctlstack->donamep->b_name.vdovar = NO; frexpr(ctlstack->dostep); } popctl(); dorange = 0; for(q = ctlstack ; q>=ctls ; --q) if(q->ctltype == CTLDO) { dorange = q->dolabel; break; } } } void exassign(vname, labelval) struct bigblock *vname; struct labelblock *labelval; { struct bigblock *p; p = mklhs(mkprim(vname,0,0,0)); if( ! ONEOF(p->vtype, MSKINT|MSKADDR) ) err("noninteger assign variable"); else puteq(p, mkaddcon(labelval->labelno) ); } void exarif(expr, neglab, zerlab, poslab) bigptr expr; struct labelblock *neglab, *zerlab, *poslab; { register int lm, lz, lp; lm = neglab->labelno; lz = zerlab->labelno; lp = poslab->labelno; expr = fixtype(expr); if( ! ONEOF(expr->vtype, MSKINT|MSKREAL) ) { err("invalid type of arithmetic if expression"); frexpr(expr); } else { if(lm == lz) exar2(OPLE, expr, lm, lp); else if(lm == lp) exar2(OPNE, expr, lm, lz); else if(lz == lp) exar2(OPGE, expr, lz, lm); else prarif(expr, lm, lz, lp); } } LOCAL void exar2(op, e, l1, l2) int op; bigptr e; int l1, l2; { putif( mkexpr(op, e, MKICON(0)), l2); putgoto(l1); } void exreturn(p) register bigptr p; { if(p && (proctype!=TYSUBR || procclass!=CLPROC) ) { err("alternate return in nonsubroutine"); p = 0; } if(p) { putforce(TYINT, p); putgoto(retlabel); } else putgoto(procclass==TYSUBR ? ret0label : retlabel); } void exasgoto(labvar) bigptr labvar; { register struct bigblock *p; p = mklhs( mkprim(labvar,0,0,0) ); if( ! ISINT(p->vtype) ) err("assigned goto variable must be integer"); else putbranch(p); } pcc-20181216/f77/fcom/expr.c010064400017500000000000001160621101161020300141240ustar raggewheel/* $Id: expr.c,v 1.20 2008/05/11 15:28:03 ragge Exp $ */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code and documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditionsand the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include "defines.h" #include "defs.h" /* little routines to create constant blocks */ LOCAL int letter(int c); LOCAL void conspower(union constant *, struct bigblock *, ftnint); LOCAL void consbinop(int, int, union constant *, union constant *, union constant *); LOCAL void zdiv(struct dcomplex *, struct dcomplex *, struct dcomplex *); LOCAL struct bigblock *stfcall(struct bigblock *, struct bigblock *); LOCAL bigptr mkpower(struct bigblock *p); LOCAL bigptr fold(struct bigblock *e); LOCAL bigptr subcheck(struct bigblock *, bigptr); struct bigblock *mkconst(t) register int t; { register struct bigblock *p; p = BALLO(); p->tag = TCONST; p->vtype = t; return(p); } struct bigblock *mklogcon(l) register int l; { register struct bigblock * p; p = mkconst(TYLOGICAL); p->b_const.fconst.ci = l; return(p); } struct bigblock *mkintcon(l) ftnint l; { register struct bigblock *p; p = mkconst(TYLONG); p->b_const.fconst.ci = l; #ifdef MAXSHORT if(l >= -MAXSHORT && l <= MAXSHORT) p->vtype = TYSHORT; #endif return(p); } struct bigblock *mkaddcon(l) register int l; { register struct bigblock *p; p = mkconst(TYADDR); p->b_const.fconst.ci = l; return(p); } struct bigblock *mkrealcon(t, d) register int t; double d; { register struct bigblock *p; p = mkconst(t); p->b_const.fconst.cd[0] = d; return(p); } struct bigblock *mkbitcon(shift, leng, s) int shift; int leng; char *s; { register struct bigblock *p; p = mkconst(TYUNKNOWN); p->b_const.fconst.ci = 0; while(--leng >= 0) if(*s != ' ') p->b_const.fconst.ci = (p->b_const.fconst.ci << shift) | hextoi(*s++); return(p); } struct bigblock *mkstrcon(l,v) int l; register char *v; { register struct bigblock *p; register char *s; p = mkconst(TYCHAR); p->vleng = MKICON(l); p->b_const.fconst.ccp = s = (char *) ckalloc(l); while(--l >= 0) *s++ = *v++; return(p); } struct bigblock *mkcxcon(realp,imagp) register bigptr realp, imagp; { int rtype, itype; register struct bigblock *p; rtype = realp->vtype; itype = imagp->vtype; if( ISCONST(realp) && ISNUMERIC(rtype) && ISCONST(imagp) && ISNUMERIC(itype) ) { p = mkconst( (rtype==TYDREAL||itype==TYDREAL) ? TYDCOMPLEX : TYCOMPLEX ); if( ISINT(rtype) ) p->b_const.fconst.cd[0] = realp->b_const.fconst.ci; else p->b_const.fconst.cd[0] = realp->b_const.fconst.cd[0]; if( ISINT(itype) ) p->b_const.fconst.cd[1] = imagp->b_const.fconst.ci; else p->b_const.fconst.cd[1] = imagp->b_const.fconst.cd[0]; } else { err("invalid complex constant"); p = errnode(); } frexpr(realp); frexpr(imagp); return(p); } struct bigblock *errnode() { struct bigblock *p; p = BALLO(); p->tag = TERROR; p->vtype = TYERROR; return(p); } bigptr mkconv(t, p) register int t; register bigptr p; { register bigptr q; if(t==TYUNKNOWN || t==TYERROR) fatal1("mkconv of impossible type %d", t); if(t == p->vtype) return(p); else if( ISCONST(p) && p->vtype!=TYADDR) { q = mkconst(t); consconv(t, &(q->b_const.fconst), p->vtype, &(p->b_const.fconst)); frexpr(p); } else { q = mkexpr(OPCONV, p, 0); q->vtype = t; } return(q); } struct bigblock *addrof(p) bigptr p; { return( mkexpr(OPADDR, p, NULL) ); } bigptr cpexpr(p) register bigptr p; { register bigptr e; int tag; register chainp ep, pp; #if 0 static int blksize[ ] = { 0, sizeof(struct nameblock), sizeof(struct constblock), sizeof(struct exprblock), sizeof(struct addrblock), sizeof(struct primblock), sizeof(struct listblock), sizeof(struct errorblock) }; #endif if(p == NULL) return(NULL); if( (tag = p->tag) == TNAME) return(p); #if 0 e = cpblock( blksize[p->tag] , p); #else e = cpblock( sizeof(struct bigblock) , p); #endif switch(tag) { case TCONST: if(e->vtype == TYCHAR) { e->b_const.fconst.ccp = copyn(1+strlen(e->b_const.fconst.ccp), e->b_const.fconst.ccp); e->vleng = cpexpr(e->vleng); } case TERROR: break; case TEXPR: e->b_expr.leftp = cpexpr(p->b_expr.leftp); e->b_expr.rightp = cpexpr(p->b_expr.rightp); break; case TLIST: if((pp = p->b_list.listp)) { ep = e->b_list.listp = mkchain( cpexpr(pp->chain.datap), NULL); for(pp = pp->chain.nextp ; pp ; pp = pp->chain.nextp) ep = ep->chain.nextp = mkchain( cpexpr(pp->chain.datap), NULL); } break; case TADDR: e->vleng = cpexpr(e->vleng); e->b_addr.memoffset = cpexpr(e->b_addr.memoffset); e->b_addr.istemp = NO; break; case TPRIM: e->b_prim.argsp = cpexpr(e->b_prim.argsp); e->b_prim.fcharp = cpexpr(e->b_prim.fcharp); e->b_prim.lcharp = cpexpr(e->b_prim.lcharp); break; default: fatal1("cpexpr: impossible tag %d", tag); } return(e); } void frexpr(p) register bigptr p; { register chainp q; if(p == NULL) return; switch(p->tag) { case TCONST: if( ISCHAR(p) ) { ckfree(p->b_const.fconst.ccp); frexpr(p->vleng); } break; case TADDR: if(p->b_addr.istemp) { frtemp(p); return; } frexpr(p->vleng); frexpr(p->b_addr.memoffset); break; case TERROR: break; case TNAME: return; case TPRIM: frexpr(p->b_prim.argsp); frexpr(p->b_prim.fcharp); frexpr(p->b_prim.lcharp); break; case TEXPR: frexpr(p->b_expr.leftp); if(p->b_expr.rightp) frexpr(p->b_expr.rightp); break; case TLIST: for(q = p->b_list.listp ; q ; q = q->chain.nextp) frexpr(q->chain.datap); frchain( &(p->b_list.listp) ); break; default: fatal1("frexpr: impossible tag %d", p->tag); } ckfree(p); } /* fix up types in expression; replace subtrees and convert names to address blocks */ bigptr fixtype(p) register bigptr p; { if(p == 0) return(0); switch(p->tag) { case TCONST: if( ! ONEOF(p->vtype, MSKINT|MSKLOGICAL|MSKADDR) ) p = putconst(p); return(p); case TADDR: p->b_addr.memoffset = fixtype(p->b_addr.memoffset); return(p); case TERROR: return(p); default: fatal1("fixtype: impossible tag %d", p->tag); case TEXPR: return( fixexpr(p) ); case TLIST: return( p ); case TPRIM: if(p->b_prim.argsp && p->b_prim.namep->vclass!=CLVAR) return( mkfunct(p) ); else return( mklhs(p) ); } } /* special case tree transformations and cleanups of expression trees */ bigptr fixexpr(p) register struct bigblock *p; { bigptr lp; register bigptr rp; register bigptr q; int opcode, ltype, rtype, ptype, mtype; if(p->tag == TERROR) return(p); else if(p->tag != TEXPR) fatal1("fixexpr: invalid tag %d", p->tag); opcode = p->b_expr.opcode; lp = p->b_expr.leftp = fixtype(p->b_expr.leftp); ltype = lp->vtype; if(opcode==OPASSIGN && lp->tag!=TADDR) { err("left side of assignment must be variable"); frexpr(p); return( errnode() ); } if(p->b_expr.rightp) { rp = p->b_expr.rightp = fixtype(p->b_expr.rightp); rtype = rp->vtype; } else { rp = NULL; rtype = 0; } /* force folding if possible */ if( ISCONST(lp) && (rp==NULL || ISCONST(rp)) ) { q = mkexpr(opcode, lp, rp); if( ISCONST(q) ) return(q); ckfree(q); /* constants did not fold */ } if( (ptype = cktype(opcode, ltype, rtype)) == TYERROR) { frexpr(p); return( errnode() ); } switch(opcode) { case OPCONCAT: if(p->vleng == NULL) p->vleng = mkexpr(OPPLUS, cpexpr(lp->vleng), cpexpr(rp->vleng) ); break; case OPASSIGN: if(ltype == rtype) break; if( ! ISCONST(rp) && ISREAL(ltype) && ISREAL(rtype) ) break; if( ISCOMPLEX(ltype) || ISCOMPLEX(rtype) ) break; if( ONEOF(ltype, MSKADDR|MSKINT) && ONEOF(rtype, MSKADDR|MSKINT) && typesize[ltype]>=typesize[rtype] ) break; p->b_expr.rightp = fixtype( mkconv(ptype, rp) ); break; case OPSLASH: if( ISCOMPLEX(rtype) ) { p = call2(ptype, ptype==TYCOMPLEX? "c_div" : "z_div", mkconv(ptype, lp), mkconv(ptype, rp) ); break; } case OPPLUS: case OPMINUS: case OPSTAR: case OPMOD: if(ptype==TYDREAL && ( (ltype==TYREAL && ! ISCONST(lp) ) || (rtype==TYREAL && ! ISCONST(rp) ) )) break; if( ISCOMPLEX(ptype) ) break; if(ltype != ptype) p->b_expr.leftp = fixtype(mkconv(ptype,lp)); if(rtype != ptype) p->b_expr.rightp = fixtype(mkconv(ptype,rp)); break; case OPPOWER: return( mkpower(p) ); case OPLT: case OPLE: case OPGT: case OPGE: case OPEQ: case OPNE: if(ltype == rtype) break; mtype = cktype(OPMINUS, ltype, rtype); if(mtype==TYDREAL && ( (ltype==TYREAL && ! ISCONST(lp)) || (rtype==TYREAL && ! ISCONST(rp)) )) break; if( ISCOMPLEX(mtype) ) break; if(ltype != mtype) p->b_expr.leftp = fixtype(mkconv(mtype,lp)); if(rtype != mtype) p->b_expr.rightp = fixtype(mkconv(mtype,rp)); break; case OPCONV: ptype = cktype(OPCONV, p->vtype, ltype); if(lp->tag==TEXPR && lp->b_expr.opcode==OPCOMMA) { lp->b_expr.rightp = fixtype( mkconv(ptype, lp->b_expr.rightp) ); ckfree(p); p = lp; } break; case OPADDR: if(lp->tag==TEXPR && lp->b_expr.opcode==OPADDR) fatal("addr of addr"); break; case OPCOMMA: break; case OPMIN: case OPMAX: ptype = p->vtype; break; default: break; } p->vtype = ptype; return(p); } #if SZINT < SZLONG /* for efficient subscripting, replace long ints by shorts in easy places */ bigptr shorten(p) register bigptr p; { register bigptr q; if(p->vtype != TYLONG) return(p); switch(p->tag) { case TERROR: case TLIST: return(p); case TCONST: case TADDR: return( mkconv(TYINT,p) ); case TEXPR: break; default: fatal1("shorten: invalid tag %d", p->tag); } switch(p->opcode) { case OPPLUS: case OPMINUS: case OPSTAR: q = shorten( cpexpr(p->rightp) ); if(q->vtype == TYINT) { p->leftp = shorten(p->leftp); if(p->leftp->vtype == TYLONG) frexpr(q); else { frexpr(p->rightp); p->rightp = q; p->vtype = TYINT; } } break; case OPNEG: p->leftp = shorten(p->leftp); if(p->leftp->vtype == TYINT) p->vtype = TYINT; break; case OPCALL: case OPCCALL: p = mkconv(TYINT,p); break; default: break; } return(p); } #endif int fixargs(doput, p0) int doput; struct bigblock *p0; { register chainp p; register bigptr q, t; register int qtag; int nargs; nargs = 0; if(p0) for(p = p0->b_list.listp ; p ; p = p->chain.nextp) { ++nargs; q = p->chain.datap; qtag = q->tag; if(qtag == TCONST) { if(q->vtype == TYSHORT) q = mkconv(tyint, q); if(doput) p->chain.datap = putconst(q); else p->chain.datap = q; } else if(qtag==TPRIM && q->b_prim.argsp==0 && q->b_prim.namep->vclass==CLPROC) p->chain.datap = mkaddr(q->b_prim.namep); else if(qtag==TPRIM && q->b_prim.argsp==0 && q->b_prim.namep->b_name.vdim!=NULL) p->chain.datap = mkscalar(q->b_prim.namep); else if(qtag==TPRIM && q->b_prim.argsp==0 && q->b_prim.namep->b_name.vdovar && (t = memversion(q->b_prim.namep)) ) p->chain.datap = fixtype(t); else p->chain.datap = fixtype(q); } return(nargs); } struct bigblock * mkscalar(np) register struct bigblock *np; { register struct bigblock *ap; vardcl(np); ap = mkaddr(np); #ifdef __vax__ /* on the VAX, prolog causes array arguments to point at the (0,...,0) element, except when subscript checking is on */ if( !checksubs && np->vstg==STGARG) { register struct dimblock *dp; dp = np->vdim; frexpr(ap->memoffset); ap->memoffset = mkexpr(OPSTAR, MKICON(typesize[np->vtype]), cpexpr(dp->baseoffset) ); } #endif return(ap); } bigptr mkfunct(p) register struct bigblock * p; { chainp ep; struct bigblock *ap; struct extsym *extp; register struct bigblock *np; register struct bigblock *q; int k, nargs; int class; np = p->b_prim.namep; class = np->vclass; if(class == CLUNKNOWN) { np->vclass = class = CLPROC; if(np->vstg == STGUNKNOWN) { if((k = intrfunct(np->b_name.varname))) { np->vstg = STGINTR; np->b_name.vardesc.varno = k; np->b_name.vprocclass = PINTRINSIC; } else { extp = mkext( varunder(VL,np->b_name.varname) ); extp->extstg = STGEXT; np->vstg = STGEXT; np->b_name.vardesc.varno = extp - extsymtab; np->b_name.vprocclass = PEXTERNAL; } } else if(np->vstg==STGARG) { if(np->vtype!=TYCHAR && !ftn66flag) warn("Dummy procedure not declared EXTERNAL. Code may be wrong."); np->b_name.vprocclass = PEXTERNAL; } } if(class != CLPROC) fatal1("invalid class code for function", class); if(p->b_prim.fcharp || p->b_prim.lcharp) { err("no substring of function call"); goto error; } impldcl(np); nargs = fixargs( np->b_name.vprocclass!=PINTRINSIC, p->b_prim.argsp); switch(np->b_name.vprocclass) { case PEXTERNAL: ap = mkaddr(np); call: q = mkexpr(OPCALL, ap, p->b_prim.argsp); q->vtype = np->vtype; if(np->vleng) q->vleng = cpexpr(np->vleng); break; case PINTRINSIC: q = intrcall(np, p->b_prim.argsp, nargs); break; case PSTFUNCT: q = stfcall(np, p->b_prim.argsp); break; case PTHISPROC: warn("recursive call"); for(ep = entries ; ep ; ep = ep->entrypoint.nextp) if(ep->entrypoint.enamep == np) break; if(ep == NULL) fatal("mkfunct: impossible recursion"); ap = builtin(np->vtype, varstr(XL, ep->entrypoint.entryname->extname) ); goto call; default: fatal1("mkfunct: impossible vprocclass %d", np->b_name.vprocclass); q = 0; /* XXX gcc */ } ckfree(p); return(q); error: frexpr(p); return( errnode() ); } LOCAL struct bigblock * stfcall(struct bigblock *np, struct bigblock *actlist) { register chainp actuals; int nargs; chainp oactp, formals; int type; struct bigblock *q, *rhs; bigptr ap; register chainp rp; chainp tlist; if(actlist) { actuals = actlist->b_list.listp; ckfree(actlist); } else actuals = NULL; oactp = actuals; nargs = 0; tlist = NULL; type = np->vtype; formals = (chainp)np->b_name.vardesc.vstfdesc->chain.datap; rhs = (bigptr)np->b_name.vardesc.vstfdesc->chain.nextp; /* copy actual arguments into temporaries */ while(actuals!=NULL && formals!=NULL) { rp = ALLOC(rplblock); rp->rplblock.rplnp = q = formals->chain.datap; ap = fixtype(actuals->chain.datap); if(q->vtype==ap->vtype && q->vtype!=TYCHAR && (ap->tag==TCONST || ap->tag==TADDR) ) { rp->rplblock.rplvp = ap; rp->rplblock.rplxp = NULL; rp->rplblock.rpltag = ap->tag; } else { rp->rplblock.rplvp = fmktemp(q->vtype, q->vleng); rp->rplblock.rplxp = fixtype( mkexpr(OPASSIGN, cpexpr(rp->rplblock.rplvp), ap) ); if( (rp->rplblock.rpltag = rp->rplblock.rplxp->tag) == TERROR) err("disagreement of argument types in statement function call"); } rp->rplblock.nextp = tlist; tlist = rp; actuals = actuals->chain.nextp; formals = formals->chain.nextp; ++nargs; } if(actuals!=NULL || formals!=NULL) err("statement function definition and argument list differ"); /* now push down names involved in formal argument list, then evaluate rhs of statement function definition in this environment */ rpllist = hookup(tlist, rpllist); q = mkconv(type, fixtype(cpexpr(rhs)) ); /* now generate the tree ( t1=a1, (t2=a2,... , f))))) */ while(--nargs >= 0) { if(rpllist->rplblock.rplxp) q = mkexpr(OPCOMMA, rpllist->rplblock.rplxp, q); rp = rpllist->rplblock.nextp; frexpr(rpllist->rplblock.rplvp); ckfree(rpllist); rpllist = rp; } frchain( &oactp ); return(q); } struct bigblock * mklhs(struct bigblock *p) { struct bigblock *s; struct bigblock *np; chainp rp; int regn; /* first fixup name */ if(p->tag != TPRIM) return(p); np = p->b_prim.namep; /* is name on the replace list? */ for(rp = rpllist ; rp ; rp = rp->rplblock.nextp) { if(np == rp->rplblock.rplnp) { if(rp->rplblock.rpltag == TNAME) { np = p->b_prim.namep = rp->rplblock.rplvp; break; } else return( cpexpr(rp->rplblock.rplvp) ); } } /* is variable a DO index in a register ? */ if(np->b_name.vdovar && ( (regn = inregister(np)) >= 0) ) { if(np->vtype == TYERROR) return( errnode() ); else { s = BALLO(); s->tag = TADDR; s->vstg = STGREG; s->vtype = TYIREG; s->b_addr.memno = regn; s->b_addr.memoffset = MKICON(0); return(s); } } vardcl(np); s = mkaddr(np); s->b_addr.memoffset = mkexpr(OPPLUS, s->b_addr.memoffset, suboffset(p) ); frexpr(p->b_prim.argsp); p->b_prim.argsp = NULL; /* now do substring part */ if(p->b_prim.fcharp || p->b_prim.lcharp) { if(np->vtype != TYCHAR) err1("substring of noncharacter %s", varstr(VL,np->b_name.varname)); else { if(p->b_prim.lcharp == NULL) p->b_prim.lcharp = cpexpr(s->vleng); if(p->b_prim.fcharp) s->vleng = mkexpr(OPMINUS, p->b_prim.lcharp, mkexpr(OPMINUS, p->b_prim.fcharp, MKICON(1) )); else { frexpr(s->vleng); s->vleng = p->b_prim.lcharp; } } } s->vleng = fixtype( s->vleng ); s->b_addr.memoffset = fixtype( s->b_addr.memoffset ); ckfree(p); return(s); } void deregister(np) struct bigblock *np; { } struct bigblock *memversion(np) register struct bigblock *np; { register struct bigblock *s; if(np->b_name.vdovar==NO || (inregister(np)<0) ) return(NULL); np->b_name.vdovar = NO; s = mklhs( mkprim(np, 0,0,0) ); np->b_name.vdovar = YES; return(s); } int inregister(np) register struct bigblock *np; { return(-1); } int enregister(np) struct bigblock *np; { return(NO); } bigptr suboffset(p) register struct bigblock *p; { int n; bigptr size; chainp cp; bigptr offp, prod; struct dimblock *dimp; bigptr sub[8]; register struct bigblock *np; np = p->b_prim.namep; offp = MKICON(0); n = 0; if(p->b_prim.argsp) for(cp = p->b_prim.argsp->b_list.listp ; cp ; cp = cp->chain.nextp) { sub[n++] = fixtype(cpexpr(cp->chain.datap)); if(n > 7) { err("more than 7 subscripts"); break; } } dimp = np->b_name.vdim; if(n>0 && dimp==NULL) err("subscripts on scalar variable"); else if(dimp && dimp->ndim!=n) err1("wrong number of subscripts on %s", varstr(VL, np->b_name.varname) ); else if(n > 0) { prod = sub[--n]; while( --n >= 0) prod = mkexpr(OPPLUS, sub[n], mkexpr(OPSTAR, prod, cpexpr(dimp->dims[n].dimsize)) ); #ifdef __vax__ if(checksubs || np->vstg!=STGARG) prod = mkexpr(OPMINUS, prod, cpexpr(dimp->baseoffset)); #else prod = mkexpr(OPMINUS, prod, cpexpr(dimp->baseoffset)); #endif if(checksubs) prod = subcheck(np, prod); if(np->vtype == TYCHAR) size = cpexpr(np->vleng); else size = MKICON( typesize[np->vtype] ); prod = mkexpr(OPSTAR, prod, size); offp = mkexpr(OPPLUS, offp, prod); } if(p->b_prim.fcharp && np->vtype==TYCHAR) offp = mkexpr(OPPLUS, offp, mkexpr(OPMINUS, cpexpr(p->b_prim.fcharp), MKICON(1) )); return(offp); } /* * Check if an array is addressed out of bounds. */ bigptr subcheck(struct bigblock *np, bigptr p) { struct dimblock *dimp; bigptr t, badcall; int l1, l2; dimp = np->b_name.vdim; if(dimp->nelt == NULL) return(p); /* don't check arrays with * bounds */ if( ISICON(p) ) { if(p->b_const.fconst.ci < 0) goto badsub; if( ISICON(dimp->nelt) ) { if(p->b_const.fconst.ci < dimp->nelt->b_const.fconst.ci) return(p); else goto badsub; } } if (p->tag==TADDR && p->vstg==STGREG) { t = p; } else { t = fmktemp(p->vtype, NULL); putexpr(mkexpr(OPASSIGN, cpexpr(t), p)); } /* t now cotains evaluated expression */ l1 = newlabel(); l2 = newlabel(); putif(mkexpr(OPLT, cpexpr(t), cpexpr(dimp->nelt)), l1); putif(mkexpr(OPGE, cpexpr(t), MKICON(0)), l1); putgoto(l2); putlabel(l1); badcall = call4(t->vtype, "s_rnge", mkstrcon(VL, np->b_name.varname), mkconv(TYLONG, cpexpr(t)), mkstrcon(XL, procname), MKICON(lineno)); badcall->b_expr.opcode = OPCCALL; putexpr(badcall); putlabel(l2); return t; badsub: frexpr(p); err1("subscript on variable %s out of range", varstr(VL,np->b_name.varname)); return ( MKICON(0) ); } struct bigblock *mkaddr(p) register struct bigblock *p; { struct extsym *extp; register struct bigblock *t; switch( p->vstg) { case STGUNKNOWN: if(p->vclass != CLPROC) break; extp = mkext( varunder(VL, p->b_name.varname) ); extp->extstg = STGEXT; p->vstg = STGEXT; p->b_name.vardesc.varno = extp - extsymtab; p->b_name.vprocclass = PEXTERNAL; case STGCOMMON: case STGEXT: case STGBSS: case STGINIT: case STGEQUIV: case STGARG: case STGLENG: case STGAUTO: t = BALLO(); t->tag = TADDR; t->vclass = p->vclass; t->vtype = p->vtype; t->vstg = p->vstg; t->b_addr.memno = p->b_name.vardesc.varno; t->b_addr.memoffset = MKICON(p->b_name.voffset); if(p->vleng) t->vleng = cpexpr(p->vleng); return(t); case STGINTR: return( intraddr(p) ); } /*debug*/ fprintf(diagfile, "mkaddr. vtype=%d, vclass=%d\n", p->vtype, p->vclass); fatal1("mkaddr: impossible storage tag %d", p->vstg); /* NOTREACHED */ return 0; /* XXX gcc */ } struct bigblock * mkarg(type, argno) int type, argno; { register struct bigblock *p; p = BALLO(); p->tag = TADDR; p->vtype = type; p->vclass = CLVAR; p->vstg = (type==TYLENG ? STGLENG : STGARG); p->b_addr.memno = argno; return(p); } bigptr mkprim(v, args, lstr, rstr) register bigptr v; struct bigblock *args; bigptr lstr, rstr; { register struct bigblock *p; if(v->vclass == CLPARAM) { if(args || lstr || rstr) { err1("no qualifiers on parameter name", varstr(VL,v->b_name.varname)); frexpr(args); frexpr(lstr); frexpr(rstr); frexpr(v); return( errnode() ); } return( cpexpr(v->b_param.paramval) ); } p = BALLO(); p->tag = TPRIM; p->vtype = v->vtype; p->b_prim.namep = v; p->b_prim.argsp = args; p->b_prim.fcharp = lstr; p->b_prim.lcharp = rstr; return(p); } void vardcl(v) register struct bigblock *v; { int nelt; struct dimblock *t; struct bigblock *p; bigptr neltp; if(v->b_name.vdcldone) return; if(v->vtype == TYUNKNOWN) impldcl(v); if(v->vclass == CLUNKNOWN) v->vclass = CLVAR; else if(v->vclass!=CLVAR && v->b_name.vprocclass!=PTHISPROC) { dclerr("used as variable", v); return; } if(v->vstg==STGUNKNOWN) v->vstg = implstg[ letter(v->b_name.varname[0]) ]; switch(v->vstg) { case STGBSS: v->b_name.vardesc.varno = ++lastvarno; break; case STGAUTO: if(v->vclass==CLPROC && v->b_name.vprocclass==PTHISPROC) break; nelt = 1; if((t = v->b_name.vdim)) { if( (neltp = t->nelt) && ISCONST(neltp) ) nelt = neltp->b_const.fconst.ci; else dclerr("adjustable automatic array", v); } p = autovar(nelt, v->vtype, v->vleng); v->b_name.voffset = p->b_addr.memoffset->b_const.fconst.ci; frexpr(p); break; default: break; } v->b_name.vdcldone = YES; } void impldcl(p) register struct bigblock *p; { register int k; int type, leng; if(p->b_name.vdcldone || (p->vclass==CLPROC && p->b_name.vprocclass==PINTRINSIC) ) return; if(p->vtype == TYUNKNOWN) { k = letter(p->b_name.varname[0]); type = impltype[ k ]; leng = implleng[ k ]; if(type == TYUNKNOWN) { if(p->vclass == CLPROC) return; dclerr("attempt to use undefined variable", p); type = TYERROR; leng = 1; } settype(p, type, leng); } } LOCAL int letter(c) register int c; { if( isupper(c) ) c = tolower(c); return(c - 'a'); } #define ICONEQ(z, c) (ISICON(z) && z->b_const.fconst.ci==c) #define COMMUTE { e = lp; lp = rp; rp = e; } struct bigblock * mkexpr(opcode, lp, rp) int opcode; register bigptr lp, rp; { register struct bigblock *e, *e1; int etype; int ltype, rtype; int ltag, rtag; ltype = lp->vtype; ltag = lp->tag; if(rp && opcode!=OPCALL && opcode!=OPCCALL) { rtype = rp->vtype; rtag = rp->tag; } else rtype = rtag = 0; etype = cktype(opcode, ltype, rtype); if(etype == TYERROR) goto error; switch(opcode) { /* check for multiplication by 0 and 1 and addition to 0 */ case OPSTAR: if( ISCONST(lp) ) COMMUTE if( ISICON(rp) ) { if(rp->b_const.fconst.ci == 0) goto retright; goto mulop; } break; case OPSLASH: case OPMOD: if( ICONEQ(rp, 0) ) { err("attempted division by zero"); rp = MKICON(1); break; } if(opcode == OPMOD) break; mulop: if( ISICON(rp) ) { if(rp->b_const.fconst.ci == 1) goto retleft; if(rp->b_const.fconst.ci == -1) { frexpr(rp); return( mkexpr(OPNEG, lp, 0) ); } } if( ISSTAROP(lp) && ISICON(lp->b_expr.rightp) ) { if(opcode == OPSTAR) e = mkexpr(OPSTAR, lp->b_expr.rightp, rp); else if(ISICON(rp) && lp->b_expr.rightp->b_const.fconst.ci % rp->b_const.fconst.ci == 0) e = mkexpr(OPSLASH, lp->b_expr.rightp, rp); else break; e1 = lp->b_expr.leftp; ckfree(lp); return( mkexpr(OPSTAR, e1, e) ); } break; case OPPLUS: if( ISCONST(lp) ) COMMUTE goto addop; case OPMINUS: if( ICONEQ(lp, 0) ) { frexpr(lp); return( mkexpr(OPNEG, rp, 0) ); } if( ISCONST(rp) ) { opcode = OPPLUS; consnegop(rp); } addop: if( ISICON(rp) ) { if(rp->b_const.fconst.ci == 0) goto retleft; if( ISPLUSOP(lp) && ISICON(lp->b_expr.rightp) ) { e = mkexpr(OPPLUS, lp->b_expr.rightp, rp); e1 = lp->b_expr.leftp; ckfree(lp); return( mkexpr(OPPLUS, e1, e) ); } } break; case OPPOWER: break; case OPNEG: if(ltag==TEXPR && lp->b_expr.opcode==OPNEG) { e = lp->b_expr.leftp; ckfree(lp); return(e); } break; case OPNOT: if(ltag==TEXPR && lp->b_expr.opcode==OPNOT) { e = lp->b_expr.leftp; ckfree(lp); return(e); } break; case OPCALL: case OPCCALL: etype = ltype; if(rp!=NULL && rp->b_list.listp==NULL) { ckfree(rp); rp = NULL; } break; case OPAND: case OPOR: if( ISCONST(lp) ) COMMUTE if( ISCONST(rp) ) { if(rp->b_const.fconst.ci == 0) if(opcode == OPOR) goto retleft; else goto retright; else if(opcode == OPOR) goto retright; else goto retleft; } case OPEQV: case OPNEQV: case OPBITAND: case OPBITOR: case OPBITXOR: case OPBITNOT: case OPLSHIFT: case OPRSHIFT: case OPLT: case OPGT: case OPLE: case OPGE: case OPEQ: case OPNE: case OPCONCAT: break; case OPMIN: case OPMAX: case OPASSIGN: case OPCONV: case OPADDR: case OPCOMMA: break; default: fatal1("mkexpr: impossible opcode %d", opcode); } e = BALLO(); e->tag = TEXPR; e->b_expr.opcode = opcode; e->vtype = etype; e->b_expr.leftp = lp; e->b_expr.rightp = rp; if(ltag==TCONST && (rp==0 || rtag==TCONST) ) e = fold(e); return(e); retleft: frexpr(rp); return(lp); retright: frexpr(lp); return(rp); error: frexpr(lp); if(rp && opcode!=OPCALL && opcode!=OPCCALL) frexpr(rp); return( errnode() ); } #define ERR(s) { errs = s; goto error; } int cktype(op, lt, rt) register int op, lt, rt; { char *errs = NULL; /* XXX gcc */ if(lt==TYERROR || rt==TYERROR) goto error1; if(lt==TYUNKNOWN) return(TYUNKNOWN); if(rt==TYUNKNOWN) if(op!=OPNOT && op!=OPBITNOT && op!=OPNEG && op!=OPCALL && op!=OPCCALL && op!=OPADDR) return(TYUNKNOWN); switch(op) { case OPPLUS: case OPMINUS: case OPSTAR: case OPSLASH: case OPPOWER: case OPMOD: if( ISNUMERIC(lt) && ISNUMERIC(rt) ) return( maxtype(lt, rt) ); ERR("nonarithmetic operand of arithmetic operator") case OPNEG: if( ISNUMERIC(lt) ) return(lt); ERR("nonarithmetic operand of negation") case OPNOT: if(lt == TYLOGICAL) return(TYLOGICAL); ERR("NOT of nonlogical") case OPAND: case OPOR: case OPEQV: case OPNEQV: if(lt==TYLOGICAL && rt==TYLOGICAL) return(TYLOGICAL); ERR("nonlogical operand of logical operator") case OPLT: case OPGT: case OPLE: case OPGE: case OPEQ: case OPNE: if(lt==TYCHAR || rt==TYCHAR || lt==TYLOGICAL || rt==TYLOGICAL) { if(lt != rt) ERR("illegal comparison") } else if( ISCOMPLEX(lt) || ISCOMPLEX(rt) ) { if(op!=OPEQ && op!=OPNE) ERR("order comparison of complex data") } else if( ! ISNUMERIC(lt) || ! ISNUMERIC(rt) ) ERR("comparison of nonarithmetic data") return(TYLOGICAL); case OPCONCAT: if(lt==TYCHAR && rt==TYCHAR) return(TYCHAR); ERR("concatenation of nonchar data") case OPCALL: case OPCCALL: return(lt); case OPADDR: return(TYADDR); case OPCONV: if(rt == 0) return(0); case OPASSIGN: if( ISINT(lt) && rt==TYCHAR) return(lt); if(lt==TYCHAR || rt==TYCHAR || lt==TYLOGICAL || rt==TYLOGICAL) if(op!=OPASSIGN || lt!=rt) { /* debug fprintf(diagfile, " lt=%d, rt=%d, op=%d\n", lt, rt, op); */ /* debug fatal("impossible conversion. possible compiler bug"); */ ERR("impossible conversion") } return(lt); case OPMIN: case OPMAX: case OPBITOR: case OPBITAND: case OPBITXOR: case OPBITNOT: case OPLSHIFT: case OPRSHIFT: return(lt); case OPCOMMA: return(rt); default: fatal1("cktype: impossible opcode %d", op); } error: err(errs); error1: return(TYERROR); } LOCAL bigptr fold(e) register struct bigblock *e; { struct bigblock *p; register bigptr lp, rp; int etype, mtype, ltype, rtype, opcode; int i, ll, lr; char *q, *s; union constant lcon, rcon; opcode = e->b_expr.opcode; etype = e->vtype; lp = e->b_expr.leftp; ltype = lp->vtype; rp = e->b_expr.rightp; if(rp == 0) switch(opcode) { case OPNOT: lp->b_const.fconst.ci = ! lp->b_const.fconst.ci; return(lp); case OPBITNOT: lp->b_const.fconst.ci = ~ lp->b_const.fconst.ci; return(lp); case OPNEG: consnegop(lp); return(lp); case OPCONV: case OPADDR: return(e); default: fatal1("fold: invalid unary operator %d", opcode); } rtype = rp->vtype; p = BALLO(); p->tag = TCONST; p->vtype = etype; p->vleng = e->vleng; switch(opcode) { case OPCOMMA: return(e); case OPAND: p->b_const.fconst.ci = lp->b_const.fconst.ci && rp->b_const.fconst.ci; break; case OPOR: p->b_const.fconst.ci = lp->b_const.fconst.ci || rp->b_const.fconst.ci; break; case OPEQV: p->b_const.fconst.ci = lp->b_const.fconst.ci == rp->b_const.fconst.ci; break; case OPNEQV: p->b_const.fconst.ci = lp->b_const.fconst.ci != rp->b_const.fconst.ci; break; case OPBITAND: p->b_const.fconst.ci = lp->b_const.fconst.ci & rp->b_const.fconst.ci; break; case OPBITOR: p->b_const.fconst.ci = lp->b_const.fconst.ci | rp->b_const.fconst.ci; break; case OPBITXOR: p->b_const.fconst.ci = lp->b_const.fconst.ci ^ rp->b_const.fconst.ci; break; case OPLSHIFT: p->b_const.fconst.ci = lp->b_const.fconst.ci << rp->b_const.fconst.ci; break; case OPRSHIFT: p->b_const.fconst.ci = lp->b_const.fconst.ci >> rp->b_const.fconst.ci; break; case OPCONCAT: ll = lp->vleng->b_const.fconst.ci; lr = rp->vleng->b_const.fconst.ci; p->b_const.fconst.ccp = q = (char *) ckalloc(ll+lr); p->vleng = MKICON(ll+lr); s = lp->b_const.fconst.ccp; for(i = 0 ; i < ll ; ++i) *q++ = *s++; s = rp->b_const.fconst.ccp; for(i = 0; i < lr; ++i) *q++ = *s++; break; case OPPOWER: if( ! ISINT(rtype) ) return(e); conspower(&(p->b_const.fconst), lp, rp->b_const.fconst.ci); break; default: if(ltype == TYCHAR) { lcon.ci = cmpstr(lp->b_const.fconst.ccp, rp->b_const.fconst.ccp, lp->vleng->b_const.fconst.ci, rp->vleng->b_const.fconst.ci); rcon.ci = 0; mtype = tyint; } else { mtype = maxtype(ltype, rtype); consconv(mtype, &lcon, ltype, &(lp->b_const.fconst) ); consconv(mtype, &rcon, rtype, &(rp->b_const.fconst) ); } consbinop(opcode, mtype, &(p->b_const.fconst), &lcon, &rcon); break; } frexpr(e); return(p); } /* assign constant l = r , doing coercion */ void consconv(lt, lv, rt, rv) int lt, rt; register union constant *lv, *rv; { switch(lt) { case TYSHORT: case TYLONG: if( ISINT(rt) ) lv->ci = rv->ci; else lv->ci = rv->cd[0]; break; case TYCOMPLEX: case TYDCOMPLEX: switch(rt) { case TYSHORT: case TYLONG: /* fall through and do real assignment of first element */ case TYREAL: case TYDREAL: lv->cd[1] = 0; break; case TYCOMPLEX: case TYDCOMPLEX: lv->cd[1] = rv->cd[1]; break; } case TYREAL: case TYDREAL: if( ISINT(rt) ) lv->cd[0] = rv->ci; else lv->cd[0] = rv->cd[0]; break; case TYLOGICAL: lv->ci = rv->ci; break; } } void consnegop(p) register struct bigblock *p; { switch(p->vtype) { case TYSHORT: case TYLONG: p->b_const.fconst.ci = - p->b_const.fconst.ci; break; case TYCOMPLEX: case TYDCOMPLEX: p->b_const.fconst.cd[1] = - p->b_const.fconst.cd[1]; /* fall through and do the real parts */ case TYREAL: case TYDREAL: p->b_const.fconst.cd[0] = - p->b_const.fconst.cd[0]; break; default: fatal1("consnegop: impossible type %d", p->vtype); } } LOCAL void conspower(powp, ap, n) register union constant *powp; struct bigblock *ap; ftnint n; { register int type; union constant x; switch(type = ap->vtype) /* pow = 1 */ { case TYSHORT: case TYLONG: powp->ci = 1; break; case TYCOMPLEX: case TYDCOMPLEX: powp->cd[1] = 0; case TYREAL: case TYDREAL: powp->cd[0] = 1; break; default: fatal1("conspower: invalid type %d", type); } if(n == 0) return; if(n < 0) { if( ISINT(type) ) { err("integer ** negative power "); return; } n = - n; consbinop(OPSLASH, type, &x, powp, &(ap->b_const.fconst)); } else consbinop(OPSTAR, type, &x, powp, &(ap->b_const.fconst)); for( ; ; ) { if(n & 01) consbinop(OPSTAR, type, powp, powp, &x); if(n >>= 1) consbinop(OPSTAR, type, &x, &x, &x); else break; } } /* do constant operation cp = a op b */ LOCAL void consbinop(opcode, type, cp, ap, bp) int opcode, type; register union constant *ap, *bp, *cp; { int k; double temp; switch(opcode) { case OPPLUS: switch(type) { case TYSHORT: case TYLONG: cp->ci = ap->ci + bp->ci; break; case TYCOMPLEX: case TYDCOMPLEX: cp->cd[1] = ap->cd[1] + bp->cd[1]; case TYREAL: case TYDREAL: cp->cd[0] = ap->cd[0] + bp->cd[0]; break; } break; case OPMINUS: switch(type) { case TYSHORT: case TYLONG: cp->ci = ap->ci - bp->ci; break; case TYCOMPLEX: case TYDCOMPLEX: cp->cd[1] = ap->cd[1] - bp->cd[1]; case TYREAL: case TYDREAL: cp->cd[0] = ap->cd[0] - bp->cd[0]; break; } break; case OPSTAR: switch(type) { case TYSHORT: case TYLONG: cp->ci = ap->ci * bp->ci; break; case TYREAL: case TYDREAL: cp->cd[0] = ap->cd[0] * bp->cd[0]; break; case TYCOMPLEX: case TYDCOMPLEX: temp = ap->cd[0] * bp->cd[0] - ap->cd[1] * bp->cd[1] ; cp->cd[1] = ap->cd[0] * bp->cd[1] + ap->cd[1] * bp->cd[0] ; cp->cd[0] = temp; break; } break; case OPSLASH: switch(type) { case TYSHORT: case TYLONG: cp->ci = ap->ci / bp->ci; break; case TYREAL: case TYDREAL: cp->cd[0] = ap->cd[0] / bp->cd[0]; break; case TYCOMPLEX: case TYDCOMPLEX: zdiv(&cp->dc, &ap->dc, &bp->dc); break; } break; case OPMOD: if( ISINT(type) ) { cp->ci = ap->ci % bp->ci; break; } else fatal("inline mod of noninteger"); default: /* relational ops */ switch(type) { case TYSHORT: case TYLONG: if(ap->ci < bp->ci) k = -1; else if(ap->ci == bp->ci) k = 0; else k = 1; break; case TYREAL: case TYDREAL: if(ap->cd[0] < bp->cd[0]) k = -1; else if(ap->cd[0] == bp->cd[0]) k = 0; else k = 1; break; case TYCOMPLEX: case TYDCOMPLEX: if(ap->cd[0] == bp->cd[0] && ap->cd[1] == bp->cd[1] ) k = 0; else k = 1; break; default: /* XXX gcc */ k = 0; break; } switch(opcode) { case OPEQ: cp->ci = (k == 0); break; case OPNE: cp->ci = (k != 0); break; case OPGT: cp->ci = (k == 1); break; case OPLT: cp->ci = (k == -1); break; case OPGE: cp->ci = (k >= 0); break; case OPLE: cp->ci = (k <= 0); break; } break; } } int conssgn(p) register bigptr p; { if( ! ISCONST(p) ) fatal( "sgn(nonconstant)" ); switch(p->vtype) { case TYSHORT: case TYLONG: if(p->b_const.fconst.ci > 0) return(1); if(p->b_const.fconst.ci < 0) return(-1); return(0); case TYREAL: case TYDREAL: if(p->b_const.fconst.cd[0] > 0) return(1); if(p->b_const.fconst.cd[0] < 0) return(-1); return(0); case TYCOMPLEX: case TYDCOMPLEX: return(p->b_const.fconst.cd[0]!=0 || p->b_const.fconst.cd[1]!=0); default: fatal1( "conssgn(type %d)", p->vtype); } /* NOTREACHED */ return 0; /* XXX gcc */ } char *powint[ ] = { "pow_ii", "pow_ri", "pow_di", "pow_ci", "pow_zi" }; LOCAL bigptr mkpower(p) register struct bigblock *p; { register bigptr q, lp, rp; int ltype, rtype, mtype; lp = p->b_expr.leftp; rp = p->b_expr.rightp; ltype = lp->vtype; rtype = rp->vtype; if(ISICON(rp)) { if(rp->b_const.fconst.ci == 0) { frexpr(p); if( ISINT(ltype) ) return( MKICON(1) ); else return( putconst( mkconv(ltype, MKICON(1))) ); } if(rp->b_const.fconst.ci < 0) { if( ISINT(ltype) ) { frexpr(p); err("integer**negative"); return( errnode() ); } rp->b_const.fconst.ci = - rp->b_const.fconst.ci; p->b_expr.leftp = lp = fixexpr(mkexpr(OPSLASH, MKICON(1), lp)); } if(rp->b_const.fconst.ci == 1) { frexpr(rp); ckfree(p); return(lp); } if( ONEOF(ltype, MSKINT|MSKREAL) ) { p->vtype = ltype; return(p); } } if( ISINT(rtype) ) { if(ltype==TYSHORT && rtype==TYSHORT) q = call2(TYSHORT, "pow_hh", lp, rp); else { if(ltype == TYSHORT) { ltype = TYLONG; lp = mkconv(TYLONG,lp); } q = call2(ltype, powint[ltype-TYLONG], lp, mkconv(TYLONG, rp)); } } else if( ISREAL( (mtype = maxtype(ltype,rtype)) )) q = call2(mtype, "pow_dd", mkconv(TYDREAL,lp), mkconv(TYDREAL,rp)); else { q = call2(TYDCOMPLEX, "pow_zz", mkconv(TYDCOMPLEX,lp), mkconv(TYDCOMPLEX,rp)); if(mtype == TYCOMPLEX) q = mkconv(TYCOMPLEX, q); } ckfree(p); return(q); } /* Complex Division. Same code as in Runtime Library */ LOCAL void zdiv(c, a, b) register struct dcomplex *a, *b, *c; { double ratio, den; double abr, abi; if( (abr = b->dreal) < 0.) abr = - abr; if( (abi = b->dimag) < 0.) abi = - abi; if( abr <= abi ) { if(abi == 0) fatal("complex division by zero"); ratio = b->dreal / b->dimag ; den = b->dimag * (1 + ratio*ratio); c->dreal = (a->dreal*ratio + a->dimag) / den; c->dimag = (a->dimag*ratio - a->dreal) / den; } else { ratio = b->dimag / b->dreal ; den = b->dreal * (1 + ratio*ratio); c->dreal = (a->dreal + a->dimag*ratio) / den; c->dimag = (a->dimag - a->dreal*ratio) / den; } } pcc-20181216/f77/fcom/ftypes.h010064400017500000000000000054331112265322000144750ustar raggewheel/* $Id: ftypes.h,v 1.5 2008/12/19 08:08:48 ragge Exp $ */ /* * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code and documentation must retain the above * copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditionsand the following disclaimer in the * documentation and/or other materials provided with the distribution. * All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed or owned by Caldera * International, Inc. * Neither the name of Caldera International, Inc. nor the names of other * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE * FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OFLIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* variable types * numeric assumptions: * int < reals < complexes * TYDREAL-TYREAL = TYDCOMPLEX-TYCOMPLEX */ #ifndef _FTYPES_H_ #define _FTYPES_H_ #define TYUNKNOWN 0 #define TYADDR 1 #define TYSHORT 2 #define TYLONG 3 #define TYREAL 4 #define TYDREAL 5 #define TYCOMPLEX 6 #define TYDCOMPLEX 7 #define TYLOGICAL 8 #define TYCHAR 9 #define TYSUBR 10 #define TYERROR 11 #define NTYPES (TYERROR+1) /* * Type conversion from pcc to f77 internal format. */ #define FSZADDR (SZPOINT(0)/SZCHAR) /* XXX - typecheck? */ #define FSZSHORT (SZSHORT/SZCHAR) #define FSZINT (SZINT/SZCHAR) #define FSZLONG (SZLONG/SZCHAR) #define ALIADDR (ALPOINT/ALCHAR) #define ALISHORT (ALSHORT/ALCHAR) #define ALILONG (ALLONG/ALCHAR) #define ALIDOUBLE (ALDOUBLE/ALCHAR) #ifndef SZINT #include "macdefs.h" #endif #if SZINT == SZSHORT #define TYINT TYSHORT #else /* SZLONG >= SZINT */ #define TYINT TYLONG #endif #define TYLENG TYLONG #endif /* !_FTYPES_H_ */ pcc-20181216/f77/fcom/gram.dcl010064400017500000000000000134761101126014100144230ustar raggewheelspec: dcl | common | external | intrinsic | equivalence | data | implicit | SSAVE { saveall = YES; } | SSAVE savelist | SFORMAT { fmtstmt(thislabel); setfmt(thislabel); } | SPARAM in_dcl SLPAR paramlist SRPAR ; dcl: type name in_dcl dims lengspec { settype($2, $1, $5); if(ndim>0) setbound($2,ndim,dims); } | dcl SCOMMA name dims lengspec { settype($3, $1, $5); if(ndim>0) setbound($3,ndim,dims); } ; type: typespec lengspec { varleng = $2; } ; typespec: typename { varleng = ($1<0 || $1==TYLONG ? 0 : typesize[$1]); } ; typename: SINTEGER { $$ = TYLONG; } | SREAL { $$ = TYREAL; } | SCOMPLEX { $$ = TYCOMPLEX; } | SDOUBLE { $$ = TYDREAL; } | SDCOMPLEX { $$ = TYDCOMPLEX; } | SLOGICAL { $$ = TYLOGICAL; } | SCHARACTER { $$ = TYCHAR; } | SUNDEFINED { $$ = TYUNKNOWN; } | SDIMENSION { $$ = TYUNKNOWN; } | SAUTOMATIC { $$ = - STGAUTO; } | SSTATIC { $$ = - STGBSS; } ; lengspec: { $$ = varleng; } | SSTAR expr { if( ! ISICON($2) ) { $$ = 0; dclerr("length must be an integer constant", 0); } else $$ = $2->b_const.fconst.ci; } | SSTAR SLPAR SSTAR SRPAR { $$ = 0; } ; common: SCOMMON in_dcl var { incomm( $$ = comblock(0, 0) , $3 ); } | SCOMMON in_dcl comblock var { $$ = $3; incomm($3, $4); } | common opt_comma comblock opt_comma var { $$ = $3; incomm($3, $5); } | common SCOMMA var { incomm($1, $3); } ; comblock: SCONCAT { $$ = comblock(0, 0); } | SSLASH SFNAME SSLASH { $$ = comblock(toklen, token); } ; external: SEXTERNAL in_dcl name { setext($3); } | external SCOMMA name { setext($3); } ; intrinsic: SINTRINSIC in_dcl name { setintr($3); } | intrinsic SCOMMA name { setintr($3); } ; equivalence: SEQUIV in_dcl equivset | equivalence SCOMMA equivset ; equivset: SLPAR equivlist SRPAR { struct equivblock *p; if(nequiv >= MAXEQUIV) fatal("too many equivalences"); p = & eqvclass[nequiv++]; p->eqvinit = 0; p->eqvbottom = 0; p->eqvtop = 0; p->equivs = $2; } ; equivlist: lhs { $$ = ALLOC(eqvchain); $$->eqvchain.eqvitem = $1; } | equivlist SCOMMA lhs { $$ = ALLOC(eqvchain); $$->eqvchain.eqvitem = $3; $$->eqvchain.nextp = $1; } ; data: SDATA in_data datalist | data opt_comma datalist ; in_data: { if(parstate == OUTSIDE) { newproc(); startproc(0, CLMAIN); } if(parstate < INDATA) { enddcl(); parstate = INDATA; } } ; datalist: datavarlist SSLASH vallist SSLASH { ftnint junk; if(nextdata(&junk,&junk) != NULL) { err("too few initializers"); curdtp = NULL; } frdata($1); frrpl(); } ; vallist: { toomanyinit = NO; } val | vallist SCOMMA val ; val: value { dataval(NULL, $1); } | simple SSTAR value { dataval($1, $3); } ; value: simple | addop simple { if( $1==OPMINUS && ISCONST($2) ) consnegop($2); $$ = $2; } | complex_const | bit_const ; savelist: saveitem | savelist SCOMMA saveitem ; saveitem: name { int k; $1->b_name.vsave = 1; k = $1->vstg; if( ! ONEOF(k, M(STGUNKNOWN)|M(STGBSS)|M(STGINIT)) ) dclerr("can only save static variables", $1); } | comblock { $1->extsave = 1; } ; paramlist: paramitem | paramlist SCOMMA paramitem ; paramitem: name SEQUALS expr { if($1->vclass == CLUNKNOWN) { $1->vclass = CLPARAM; $1->b_param.paramval = $3; } else dclerr("cannot make %s parameter", $1); } ; var: name dims { if(ndim>0) setbound($1, ndim, dims); } ; datavar: lhs { struct bigblock *np; vardcl(np = $1->b_prim.namep); if(np->vstg == STGBSS) np->vstg = STGINIT; else if(np->vstg == STGCOMMON) extsymtab[np->b_name.vardesc.varno].extinit = YES; else if(np->vstg==STGEQUIV) eqvclass[np->b_name.vardesc.varno].eqvinit = YES; else if(np->vstg != STGINIT) dclerr("inconsistent storage classes", np); $$ = mkchain($1, 0); } | SLPAR datavarlist SCOMMA dospec SRPAR { chainp p; struct bigblock *q; q = BALLO(); q->tag = TIMPLDO; q->b_impldo.varnp = $4->chain.datap; p = $4->chain.nextp; if(p) { q->b_impldo.implb = p->chain.datap; p = p->chain.nextp; } if(p) { q->b_impldo.impub = p->chain.datap; p = p->chain.nextp; } if(p) { q->b_impldo.impstep = p->chain.datap; p = p->chain.nextp; } frchain( & ($4) ); $$ = mkchain(q, 0); q->b_impldo.datalist = hookup($2, $$); } ; datavarlist: datavar { curdtp = $1; curdtelt = 0; } | datavarlist SCOMMA datavar { $$ = hookup($1, $3); } ; dims: { ndim = 0; } | SLPAR dimlist SRPAR ; dimlist: { ndim = 0; } dim | dimlist SCOMMA dim ; dim: ubound { dims[ndim].lb = 0; dims[ndim].ub = $1; ++ndim; } | expr SCOLON ubound { dims[ndim].lb = $1; dims[ndim].ub = $3; ++ndim; } ; ubound: SSTAR { $$ = 0; } | expr ; labellist: label { nstars = 1; labarray[0] = $1; } | labellist SCOMMA label { labarray[nstars++] = $3; } ; label: labelval { if($1->labinacc) warn1("illegal branch to inner block, statement %s", convic( (ftnint) ($1->stateno) )); else if($1->labdefined == NO) $1->blklevel = blklevel; $1->labused = YES; } ; labelval: SICON { $$ = mklabel( convci(toklen, token) ); } ; implicit: SIMPLICIT in_dcl implist | implicit SCOMMA implist ; implist: imptype SLPAR letgroups SRPAR ; imptype: { needkwd = 1; } type { vartype = $2; } ; letgroups: letgroup | letgroups SCOMMA letgroup ; letgroup: letter { setimpl(vartype, varleng, $1, $1); } | letter SMINUS letter { setimpl(vartype, varleng, $1, $3); } ; letter: SFNAME { if(toklen!=1 || token[0]<'a' || token[0]>'z') { dclerr("implicit item must be single letter", 0); $$ = 0; } else $$ = token[0]; } ; in_dcl: { switch(parstate) { case OUTSIDE: newproc(); startproc(0, CLMAIN); case INSIDE: parstate = INDCL; case INDCL: break; default: dclerr("declaration among executables", 0); } } ; pcc-20181216/f77/fcom/gram.exec010064400017500000000000000043231101125747700146160ustar raggewheelexec: iffable | SDO end_spec label opt_comma dospec { if($3->labdefined) execerr("no backward DO loops"); $3->blklevel = blklevel+1; exdo($3->labelno, $5); } | logif iffable { exendif(); thiswasbranch = NO; } | logif STHEN | SELSEIF end_spec SLPAR expr SRPAR STHEN { exelif($4); lastwasbranch = NO; } | SELSE end_spec { exelse(); lastwasbranch = NO; } | SENDIF end_spec { exendif(); lastwasbranch = NO; } ; logif: SLOGIF end_spec SLPAR expr SRPAR { exif($4); } ; dospec: name SEQUALS exprlist { $$ = mkchain($1, $3); } ; iffable: let lhs SEQUALS expr { exequals($2, $4); } | SASSIGN end_spec labelval STO name { exassign($5, $3); } | SCONTINUE end_spec | goto | io { inioctl = NO; } | SARITHIF end_spec SLPAR expr SRPAR label SCOMMA label SCOMMA label { exarif($4, $6, $8, $10); thiswasbranch = YES; } | call { excall($1, 0, 0, labarray); } | call SLPAR SRPAR { excall($1, 0, 0, labarray); } | call SLPAR callarglist SRPAR { excall($1, mklist($3), nstars, labarray); } | SRETURN end_spec opt_expr { exreturn($3); thiswasbranch = YES; } | stop end_spec opt_expr { exstop($1, $3); thiswasbranch = $1; } ; let: SLET { if(parstate == OUTSIDE) { newproc(); startproc(0, CLMAIN); } } ; goto: SGOTO end_spec label { exgoto($3); thiswasbranch = YES; } | SASGOTO end_spec name { exasgoto($3); thiswasbranch = YES; } | SASGOTO end_spec name opt_comma SLPAR labellist SRPAR { exasgoto($3); thiswasbranch = YES; } | SCOMPGOTO end_spec SLPAR labellist SRPAR opt_comma expr { putcmgo(fixtype($7), nstars, labarray); } ; opt_comma: | SCOMMA ; call: SCALL end_spec name { nstars = 0; $$ = $3; } ; callarglist: callarg { $$ = ($1 ? mkchain($1,0) : 0); } | callarglist SCOMMA callarg { if($3) { if($1) $$ = hookup($1, mkchain($3,0)); else $$ = mkchain($3,0); } } ; callarg: expr | SSTAR label { labarray[nstars++] = $2; $$ = 0; } ; stop: SPAUSE { $$ = 0; } | SSTOP { $$ = 1; } ; exprlist: expr { $$ = mkchain($1, 0); } | exprlist SCOMMA expr { $$ = hookup($1, mkchain($3,0) ); } ; end_spec: { if(parstate == OUTSIDE) { newproc(); startproc(0, CLMAIN); } if(parstate < INDATA) enddcl(); } ; pcc-20181216/f77/fcom/gram.expr010064400017500000000000000051411100730347500146420ustar raggewheelfunarglist: { $$ = 0; } | funargs ; funargs: expr { $$ = mkchain($1, 0); } | funargs SCOMMA expr { $$ = hookup($1, mkchain($3,0) ); } ; expr: uexpr | SLPAR expr SRPAR { $$ = $2; } | complex_const ; uexpr: lhs | simple_const | expr addop expr %prec SPLUS { $$ = mkexpr($2, $1, $3); } | expr SSTAR expr { $$ = mkexpr(OPSTAR, $1, $3); } | expr SSLASH expr { $$ = mkexpr(OPSLASH, $1, $3); } | expr SPOWER expr { $$ = mkexpr(OPPOWER, $1, $3); } | addop expr %prec SSTAR { if($1 == OPMINUS) $$ = mkexpr(OPNEG, $2, 0); else $$ = $2; } | expr relop expr %prec SEQ { $$ = mkexpr($2, $1, $3); } | expr SEQV expr { $$ = mkexpr(OPEQV, $1,$3); } | expr SNEQV expr { $$ = mkexpr(OPNEQV, $1, $3); } | expr SOR expr { $$ = mkexpr(OPOR, $1, $3); } | expr SAND expr { $$ = mkexpr(OPAND, $1, $3); } | SNOT expr { $$ = mkexpr(OPNOT, $2, 0); } | expr SCONCAT expr { $$ = mkexpr(OPCONCAT, $1, $3); } ; addop: SPLUS { $$ = OPPLUS; } | SMINUS { $$ = OPMINUS; } ; relop: SEQ { $$ = OPEQ; } | SGT { $$ = OPGT; } | SLT { $$ = OPLT; } | SGE { $$ = OPGE; } | SLE { $$ = OPLE; } | SNE { $$ = OPNE; } ; lhs: name { $$ = mkprim($1, 0, 0, 0); } | name SLPAR opt_expr SCOLON opt_expr SRPAR { $$ = mkprim($1, 0, $3, $5); } | name SLPAR funarglist SRPAR { $$ = mkprim($1, mklist($3), 0, 0); } | name SLPAR funarglist SRPAR SLPAR opt_expr SCOLON opt_expr SRPAR { $$ = mkprim($1, mklist($3), $6, $8); } ; opt_expr: { $$ = 0; } | expr ; simple: name { if($1->vclass == CLPARAM) $$ = cpexpr($1->b_param.paramval); } | simple_const ; simple_const: STRUE { $$ = mklogcon(1); } | SFALSE { $$ = mklogcon(0); } | SHOLLERITH { $$ = mkstrcon(toklen, token); } | SICON { $$ = mkintcon( convci(toklen, token) ); } | SRCON { $$ = mkrealcon(TYREAL, convcd(toklen, token)); } | SDCON { $$ = mkrealcon(TYDREAL, convcd(toklen, token)); } ; complex_const: SLPAR uexpr SCOMMA uexpr SRPAR { $$ = mkcxcon($2,$4); } ; bit_const: SHEXCON { $$ = mkbitcon(4, toklen, token); } | SOCTCON { $$ = mkbitcon(3, toklen, token); } | SBITCON { $$ = mkbitcon(1, toklen, token); } ; fexpr: unpar_fexpr | SLPAR fexpr SRPAR { $$ = $2; } ; unpar_fexpr: lhs | simple_const | fexpr addop fexpr %prec SPLUS { $$ = mkexpr($2, $1, $3); } | fexpr SSTAR fexpr { $$ = mkexpr(OPSTAR, $1, $3); } | fexpr SSLASH fexpr { $$ = mkexpr(OPSLASH, $1, $3); } | fexpr SPOWER fexpr { $$ = mkexpr(OPPOWER, $1, $3); } | addop fexpr %prec SSTAR { if($1 == OPMINUS) $$ = mkexpr(OPNEG, $2, 0); else $$ = $2; } | fexpr SCONCAT fexpr { $$ = mkexpr(OPCONCAT, $1, $3); } ; pcc-20181216/f77/fcom/gram.head010064400017500000000000000070071101125220500145550ustar raggewheel%{ #include "defines.h" #include "defs.h" static int nstars; static int ndim; static int vartype; static ftnint varleng; struct uux dims[8]; static struct labelblock *labarray[100]; static int lastwasbranch = NO; static int thiswasbranch = NO; %} /* Specify precedences and associativies. */ %left SCOMMA %nonassoc SCOLON %right SEQUALS %left SEQV SNEQV %left SOR %left SAND %left SNOT %nonassoc SLT SGT SLE SGE SEQ SNE %left SCONCAT %left SPLUS SMINUS %left SSTAR SSLASH %right SPOWER %union { struct labelblock *label; struct extsym *extsym; bigptr bigptr; chainp chainp; ftnint fint; char *str; char token; int num; } %type