pcc-20181216 0040755 0001750 0000000 00000000000 13405330641 0011407 5 ustar ragge wheel pcc-20181216/CVS 0040755 0001750 0000000 00000000000 13405330642 0012043 5 ustar ragge wheel pcc-20181216/CVS/Root 0100644 0001750 0000000 00000000011 13405330640 0012753 0 ustar ragge wheel /cvsroot
pcc-20181216/CVS/Repository 0100644 0001750 0000000 00000000004 13405330640 0014211 0 ustar ragge wheel pcc
pcc-20181216/CVS/Entries 0100644 0001750 0000000 00000000670 13405330642 0013456 0 ustar ragge wheel /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/DATESTAMP 0100644 0001750 0000000 00000000011 13405330642 0012721 0 ustar ragge wheel 20181216
pcc-20181216/Makefile.in 0100644 0001750 0000000 00000001454 11573426765 0013555 0 ustar ragge wheel # $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.guess 0100644 0001750 0000000 00000123712 12671244724 0014020 0 ustar ragge wheel #! /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.in 0100644 0001750 0000000 00000010620 13373102423 0013504 0 ustar ragge wheel /* 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.sub 0100644 0001750 0000000 00000106554 13037502140 0013452 0 ustar ragge wheel #! /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/configure 0100755 0001750 0000000 00000557274 13375321267 0013430 0 ustar ragge wheel #! /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.ac 0100644 0001750 0000000 00000042067 13375321267 0013774 0 ustar ragge wheel -*- 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-sh 0100755 0001750 0000000 00000015722 10134152164 0013474 0 ustar ragge wheel #!/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/arch 0040755 0001750 0000000 00000000000 13405330640 0012323 5 ustar ragge wheel pcc-20181216/arch/CVS 0040755 0001750 0000000 00000000000 13405330640 0012756 5 ustar ragge wheel pcc-20181216/arch/CVS/Root 0100644 0001750 0000000 00000000011 13405330640 0013670 0 ustar ragge wheel /cvsroot
pcc-20181216/arch/CVS/Repository 0100644 0001750 0000000 00000000011 13405330640 0015124 0 ustar ragge wheel pcc/arch
pcc-20181216/arch/CVS/Entries 0100644 0001750 0000000 00000000307 13405330640 0014366 0 ustar ragge wheel D/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/amd64 0040755 0001750 0000000 00000000000 13405330640 0013236 5 ustar ragge wheel pcc-20181216/arch/amd64/CVS 0040755 0001750 0000000 00000000000 13405330640 0013671 5 ustar ragge wheel pcc-20181216/arch/amd64/CVS/Root 0100644 0001750 0000000 00000000011 13405330640 0014603 0 ustar ragge wheel /cvsroot
pcc-20181216/arch/amd64/CVS/Repository 0100644 0001750 0000000 00000000017 13405330640 0016045 0 ustar ragge wheel pcc/arch/amd64
pcc-20181216/arch/amd64/CVS/Entries 0100644 0001750 0000000 00000000373 13405330640 0015304 0 ustar ragge wheel /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.c 0100644 0001750 0000000 00000074445 13400541177 0014412 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000044511 13401023455 0014554 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000060456 13376336273 0014664 0 ustar ragge wheel /* $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.h 0100644 0001750 0000000 00000022323 13327034677 0015105 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000017633 13211032627 0014602 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000073307 13376336273 0014576 0 ustar ragge wheel /* $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/arm 0040755 0001750 0000000 00000000000 13405330640 0013102 5 ustar ragge wheel pcc-20181216/arch/arm/CVS 0040755 0001750 0000000 00000000000 13405330640 0013535 5 ustar ragge wheel pcc-20181216/arch/arm/CVS/Root 0100644 0001750 0000000 00000000011 13405330640 0014447 0 ustar ragge wheel /cvsroot
pcc-20181216/arch/arm/CVS/Repository 0100644 0001750 0000000 00000000015 13405330640 0015707 0 ustar ragge wheel pcc/arch/arm
pcc-20181216/arch/arm/CVS/Entries 0100644 0001750 0000000 00000000372 13405330640 0015147 0 ustar ragge wheel /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.c 0100644 0001750 0000000 00000046173 12670064514 0014256 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000035453 12670064514 0014435 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000111476 12772250266 0014523 0 ustar ragge wheel /* $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.h 0100644 0001750 0000000 00000016542 13400732741 0014744 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000016734 12670064514 0014457 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000113742 11660042372 0014424 0 ustar ragge wheel /* $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/hppa 0040755 0001750 0000000 00000000000 13405330640 0013253 5 ustar ragge wheel pcc-20181216/arch/hppa/CVS 0040755 0001750 0000000 00000000000 13405330640 0013706 5 ustar ragge wheel pcc-20181216/arch/hppa/CVS/Root 0100644 0001750 0000000 00000000011 13405330640 0014620 0 ustar ragge wheel /cvsroot
pcc-20181216/arch/hppa/CVS/Repository 0100644 0001750 0000000 00000000016 13405330640 0016061 0 ustar ragge wheel pcc/arch/hppa
pcc-20181216/arch/hppa/CVS/Entries 0100644 0001750 0000000 00000000372 13405330640 0015320 0 ustar ragge wheel /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.c 0100644 0001750 0000000 00000014154 11763621241 0014417 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000045164 12564602654 0014613 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000041755 12772250266 0014676 0 ustar ragge wheel /* $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.h 0100644 0001750 0000000 00000030603 12666600340 0015111 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000011644 11572642122 0014620 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000045361 12026051606 0014573 0 ustar ragge wheel /* $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/i386 0040755 0001750 0000000 00000000000 13405330640 0013014 5 ustar ragge wheel pcc-20181216/arch/i386/CVS 0040755 0001750 0000000 00000000000 13405330640 0013447 5 ustar ragge wheel pcc-20181216/arch/i386/CVS/Root 0100644 0001750 0000000 00000000011 13405330640 0014361 0 ustar ragge wheel /cvsroot
pcc-20181216/arch/i386/CVS/Repository 0100644 0001750 0000000 00000000016 13405330640 0015622 0 ustar ragge wheel pcc/arch/i386
pcc-20181216/arch/i386/CVS/Entries 0100644 0001750 0000000 00000000450 13405330640 0015056 0 ustar ragge wheel /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.c 0100644 0001750 0000000 00000042252 13375321056 0014162 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000011103 11745071434 0014500 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000066322 13375321151 0014342 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000077132 13375320757 0014440 0 ustar ragge wheel /* $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.h 0100644 0001750 0000000 00000036120 13327034677 0014663 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000010223 13060740701 0014345 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000122354 13375320757 0014350 0 ustar ragge wheel /* $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/i86 0040755 0001750 0000000 00000000000 13405330640 0012731 5 ustar ragge wheel pcc-20181216/arch/i86/CVS 0040755 0001750 0000000 00000000000 13405330640 0013364 5 ustar ragge wheel pcc-20181216/arch/i86/CVS/Root 0100644 0001750 0000000 00000000011 13405330640 0014276 0 ustar ragge wheel /cvsroot
pcc-20181216/arch/i86/CVS/Repository 0100644 0001750 0000000 00000000015 13405330640 0015536 0 ustar ragge wheel pcc/arch/i86
pcc-20181216/arch/i86/CVS/Entries 0100644 0001750 0000000 00000000502 13405330640 0014771 0 ustar ragge wheel /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/TODO 0100644 0001750 0000000 00000003630 12447621033 0013503 0 ustar ragge wheel
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.c 0100644 0001750 0000000 00000025702 13372607064 0014103 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000011040 12406012507 0014404 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000034072 13372607064 0014263 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000076712 13372607064 0014354 0 ustar ragge wheel /* $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.h 0100644 0001750 0000000 00000025130 13372607064 0014573 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000017642 13372607064 0014310 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000101423 12447621033 0014245 0 ustar ragge wheel /* $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/m16c 0040755 0001750 0000000 00000000000 13405330640 0013071 5 ustar ragge wheel pcc-20181216/arch/m16c/CVS 0040755 0001750 0000000 00000000000 13405330640 0013524 5 ustar ragge wheel pcc-20181216/arch/m16c/CVS/Root 0100644 0001750 0000000 00000000011 13405330640 0014436 0 ustar ragge wheel /cvsroot
pcc-20181216/arch/m16c/CVS/Repository 0100644 0001750 0000000 00000000016 13405330640 0015677 0 ustar ragge wheel pcc/arch/m16c
pcc-20181216/arch/m16c/CVS/Entries 0100644 0001750 0000000 00000000437 13405330640 0015140 0 ustar ragge wheel /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/TODO 0100644 0001750 0000000 00000000030 10371613725 0013635 0 ustar ragge wheel * Mul/Div does not work. pcc-20181216/arch/m16c/code.c 0100644 0001750 0000000 00000016010 12341704142 0014221 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000021447 12564602654 0014427 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000030303 12772250266 0014477 0 ustar ragge wheel /* $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.h 0100644 0001750 0000000 00000012223 12666600340 0014725 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000032664 12342607746 0014454 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000024635 11572642122 0014416 0 ustar ragge wheel /* $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/m68k 0040755 0001750 0000000 00000000000 13405330640 0013110 5 ustar ragge wheel pcc-20181216/arch/m68k/CVS 0040755 0001750 0000000 00000000000 13405330640 0013543 5 ustar ragge wheel pcc-20181216/arch/m68k/CVS/Root 0100644 0001750 0000000 00000000011 13405330640 0014455 0 ustar ragge wheel /cvsroot
pcc-20181216/arch/m68k/CVS/Repository 0100644 0001750 0000000 00000000016 13405330640 0015716 0 ustar ragge wheel pcc/arch/m68k
pcc-20181216/arch/m68k/CVS/Entries 0100644 0001750 0000000 00000000370 13405330640 0015153 0 ustar ragge wheel /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.c 0100644 0001750 0000000 00000015655 12653171073 0014265 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000026745 13400734330 0014437 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000036747 12772250266 0014540 0 ustar ragge wheel /* $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.h 0100644 0001750 0000000 00000015064 13400734330 0014744 0 ustar ragge wheel /*
* 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.c 0100644 0001750 0000000 00000010041 12653171073 0014446 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000044565 12613707322 0014442 0 ustar ragge wheel /* $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/mips 0040755 0001750 0000000 00000000000 13405330640 0013273 5 ustar ragge wheel pcc-20181216/arch/mips/CVS 0040755 0001750 0000000 00000000000 13405330640 0013726 5 ustar ragge wheel pcc-20181216/arch/mips/CVS/Root 0100644 0001750 0000000 00000000011 13405330640 0014640 0 ustar ragge wheel /cvsroot
pcc-20181216/arch/mips/CVS/Repository 0100644 0001750 0000000 00000000016 13405330640 0016101 0 ustar ragge wheel pcc/arch/mips
pcc-20181216/arch/mips/CVS/Entries 0100644 0001750 0000000 00000000437 13405330640 0015342 0 ustar ragge wheel /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/TODO 0100644 0001750 0000000 00000000123 10730131376 0014036 0 ustar ragge wheel * Fix floating-point arguments in registers
* Fix structure arguments in registers
pcc-20181216/arch/mips/code.c 0100644 0001750 0000000 00000037726 12643236254 0014455 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000037557 13400735172 0014632 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000076133 12772250266 0014714 0 ustar ragge wheel /* $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.h 0100644 0001750 0000000 00000023440 13400735172 0015131 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000013377 11114577350 0014647 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000071101 12642732672 0014617 0 ustar ragge wheel /* $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/mips64 0040755 0001750 0000000 00000000000 13405330640 0013445 5 ustar ragge wheel pcc-20181216/arch/mips64/CVS 0040755 0001750 0000000 00000000000 13405330640 0014100 5 ustar ragge wheel pcc-20181216/arch/mips64/CVS/Root 0100644 0001750 0000000 00000000011 13405330640 0015012 0 ustar ragge wheel /cvsroot
pcc-20181216/arch/mips64/CVS/Repository 0100644 0001750 0000000 00000000020 13405330640 0016246 0 ustar ragge wheel pcc/arch/mips64
pcc-20181216/arch/mips64/CVS/Entries 0100644 0001750 0000000 00000000431 13405330640 0015506 0 ustar ragge wheel /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/TODO 0100644 0001750 0000000 00000000123 12737134034 0014213 0 ustar ragge wheel * Fix floating-point arguments in registers
* Fix structure arguments in registers
pcc-20181216/arch/mips64/code.c 0100644 0001750 0000000 00000040161 12737134034 0014607 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000036717 13401037723 0014777 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000073635 12772250266 0015072 0 ustar ragge wheel /* $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.h 0100644 0001750 0000000 00000023416 13401037723 0015304 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000013502 12737134034 0015007 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000070651 12737134034 0014773 0 ustar ragge wheel /* $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/nova 0040755 0001750 0000000 00000000000 13405330640 0013266 5 ustar ragge wheel pcc-20181216/arch/nova/CVS 0040755 0001750 0000000 00000000000 13405330640 0013721 5 ustar ragge wheel pcc-20181216/arch/nova/CVS/Root 0100644 0001750 0000000 00000000011 13405330640 0014633 0 ustar ragge wheel /cvsroot
pcc-20181216/arch/nova/CVS/Repository 0100644 0001750 0000000 00000000016 13405330640 0016074 0 ustar ragge wheel pcc/arch/nova
pcc-20181216/arch/nova/CVS/Entries 0100644 0001750 0000000 00000000437 13405330640 0015335 0 ustar ragge wheel /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/README 0100644 0001750 0000000 00000014332 12734211072 0014226 0 ustar ragge wheel Calling 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.c 0100644 0001750 0000000 00000014342 12734211072 0014425 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000023264 12734211072 0014610 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000027554 12734211072 0014700 0 ustar ragge wheel /* $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.h 0100644 0001750 0000000 00000012541 12734211072 0015121 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000010102 12734211072 0014614 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000012704 12734211072 0014602 0 ustar ragge wheel /* $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/pdp10 0040755 0001750 0000000 00000000000 13405330640 0013247 5 ustar ragge wheel pcc-20181216/arch/pdp10/CVS 0040755 0001750 0000000 00000000000 13405330640 0013702 5 ustar ragge wheel pcc-20181216/arch/pdp10/CVS/Root 0100644 0001750 0000000 00000000011 13405330640 0014614 0 ustar ragge wheel /cvsroot
pcc-20181216/arch/pdp10/CVS/Repository 0100644 0001750 0000000 00000000017 13405330640 0016056 0 ustar ragge wheel pcc/arch/pdp10
pcc-20181216/arch/pdp10/CVS/Entries 0100644 0001750 0000000 00000000442 13405330640 0015312 0 ustar ragge wheel /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/README 0100644 0001750 0000000 00000001327 10716121264 0014210 0 ustar ragge wheel
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.c 0100644 0001750 0000000 00000011457 13052065664 0014422 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000044043 13052065664 0014577 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000066376 13052065664 0014676 0 ustar ragge wheel /* $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.h 0100644 0001750 0000000 00000016035 12666600340 0015110 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000010701 13052065664 0014612 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000060731 13052065664 0014576 0 ustar ragge wheel /* $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/pdp11 0040755 0001750 0000000 00000000000 13405330640 0013250 5 ustar ragge wheel pcc-20181216/arch/pdp11/CVS 0040755 0001750 0000000 00000000000 13405330640 0013703 5 ustar ragge wheel pcc-20181216/arch/pdp11/CVS/Root 0100644 0001750 0000000 00000000011 13405330640 0014615 0 ustar ragge wheel /cvsroot
pcc-20181216/arch/pdp11/CVS/Repository 0100644 0001750 0000000 00000000017 13405330640 0016057 0 ustar ragge wheel pcc/arch/pdp11
pcc-20181216/arch/pdp11/CVS/Entries 0100644 0001750 0000000 00000000367 13405330640 0015321 0 ustar ragge wheel /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.c 0100644 0001750 0000000 00000013515 13037414055 0014413 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000017322 13037414055 0014573 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000037777 13037414055 0014675 0 ustar ragge wheel /* $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.h 0100644 0001750 0000000 00000015074 13037414055 0015112 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000013232 13037414055 0014610 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000042111 11076650545 0014571 0 ustar ragge wheel /* $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/pdp7 0040755 0001750 0000000 00000000000 13405330640 0013175 5 ustar ragge wheel pcc-20181216/arch/pdp7/CVS 0040755 0001750 0000000 00000000000 13405330640 0013630 5 ustar ragge wheel pcc-20181216/arch/pdp7/CVS/Root 0100644 0001750 0000000 00000000011 13405330640 0014542 0 ustar ragge wheel /cvsroot
pcc-20181216/arch/pdp7/CVS/Repository 0100644 0001750 0000000 00000000016 13405330640 0016003 0 ustar ragge wheel pcc/arch/pdp7
pcc-20181216/arch/pdp7/CVS/Entries 0100644 0001750 0000000 00000000365 13405330640 0015244 0 ustar ragge wheel /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.c 0100644 0001750 0000000 00000012570 13051372643 0014342 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000017757 13051372643 0014536 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000026034 13051372643 0014604 0 ustar ragge wheel /* $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.h 0100644 0001750 0000000 00000012431 13051372643 0015033 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000010000 13051372643 0014525 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000043212 13051372643 0014514 0 ustar ragge wheel /* $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/powerpc 0040755 0001750 0000000 00000000000 13405330640 0014002 5 ustar ragge wheel pcc-20181216/arch/powerpc/CVS 0040755 0001750 0000000 00000000000 13405330640 0014435 5 ustar ragge wheel pcc-20181216/arch/powerpc/CVS/Root 0100644 0001750 0000000 00000000011 13405330640 0015347 0 ustar ragge wheel /cvsroot
pcc-20181216/arch/powerpc/CVS/Repository 0100644 0001750 0000000 00000000021 13405330640 0016604 0 ustar ragge wheel pcc/arch/powerpc
pcc-20181216/arch/powerpc/CVS/Entries 0100644 0001750 0000000 00000000440 13405330640 0016043 0 ustar ragge wheel /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/README 0100644 0001750 0000000 00000005045 10721331206 0014737 0 ustar ragge wheel macdefs.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.c 0100644 0001750 0000000 00000107743 12740415100 0015144 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000064626 13400736753 0015344 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000106006 12772250266 0015414 0 ustar ragge wheel /* $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.h 0100644 0001750 0000000 00000026704 13400736753 0015654 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000021202 12740415100 0015326 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000115116 11473764427 0015337 0 ustar ragge wheel /* $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/sparc64 0040755 0001750 0000000 00000000000 13405330640 0013605 5 ustar ragge wheel pcc-20181216/arch/sparc64/CVS 0040755 0001750 0000000 00000000000 13405330640 0014240 5 ustar ragge wheel pcc-20181216/arch/sparc64/CVS/Root 0100644 0001750 0000000 00000000011 13405330640 0015152 0 ustar ragge wheel /cvsroot
pcc-20181216/arch/sparc64/CVS/Repository 0100644 0001750 0000000 00000000021 13405330640 0016407 0 ustar ragge wheel pcc/arch/sparc64
pcc-20181216/arch/sparc64/CVS/Entries 0100644 0001750 0000000 00000000371 13405330640 0015651 0 ustar ragge wheel /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.c 0100644 0001750 0000000 00000014207 12554367715 0014764 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000012675 11600641205 0015127 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000020743 12772250266 0015222 0 ustar ragge wheel /* $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.h 0100644 0001750 0000000 00000016050 12666600340 0015443 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000004225 11572642122 0015147 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000045754 11572642122 0015137 0 ustar ragge wheel /* $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/superh 0040755 0001750 0000000 00000000000 13405330640 0013631 5 ustar ragge wheel pcc-20181216/arch/superh/CVS 0040755 0001750 0000000 00000000000 13405330640 0014264 5 ustar ragge wheel pcc-20181216/arch/superh/CVS/Root 0100644 0001750 0000000 00000000011 13405330640 0015176 0 ustar ragge wheel /cvsroot
pcc-20181216/arch/superh/CVS/Repository 0100644 0001750 0000000 00000000020 13405330640 0016432 0 ustar ragge wheel pcc/arch/superh
pcc-20181216/arch/superh/CVS/Entries 0100644 0001750 0000000 00000000002 13405330640 0015664 0 ustar ragge wheel D
pcc-20181216/arch/vax 0040755 0001750 0000000 00000000000 13405330640 0013121 5 ustar ragge wheel pcc-20181216/arch/vax/CVS 0040755 0001750 0000000 00000000000 13405330640 0013554 5 ustar ragge wheel pcc-20181216/arch/vax/CVS/Root 0100644 0001750 0000000 00000000011 13405330640 0014466 0 ustar ragge wheel /cvsroot
pcc-20181216/arch/vax/CVS/Repository 0100644 0001750 0000000 00000000015 13405330640 0015726 0 ustar ragge wheel pcc/arch/vax
pcc-20181216/arch/vax/CVS/Entries 0100644 0001750 0000000 00000000372 13405330640 0015166 0 ustar ragge wheel /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.c 0100644 0001750 0000000 00000024576 13260712212 0014267 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000021021 13261206217 0014431 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000074200 13260712212 0014516 0 ustar ragge wheel /* $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.h 0100644 0001750 0000000 00000016472 12666600340 0014767 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000033612 13263334347 0014473 0 ustar ragge wheel /* $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.c 0100644 0001750 0000000 00000040647 12416451150 0014444 0 ustar ragge wheel /* $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/cc 0040755 0001750 0000000 00000000000 13405330641 0011774 5 ustar ragge wheel pcc-20181216/cc/CVS 0040755 0001750 0000000 00000000000 13405330641 0012427 5 ustar ragge wheel pcc-20181216/cc/CVS/Root 0100644 0001750 0000000 00000000011 13405330640 0013340 0 ustar ragge wheel /cvsroot
pcc-20181216/cc/CVS/Repository 0100644 0001750 0000000 00000000007 13405330640 0014601 0 ustar ragge wheel pcc/cc
pcc-20181216/cc/CVS/Entries 0100644 0001750 0000000 00000000146 13405330641 0014040 0 ustar ragge wheel /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.in 0100644 0001750 0000000 00000001353 11700104555 0014116 0 ustar ragge wheel # $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/cc 0040755 0001750 0000000 00000000000 13405330640 0012360 5 ustar ragge wheel pcc-20181216/cc/cc/CVS 0040755 0001750 0000000 00000000000 13405330640 0013013 5 ustar ragge wheel pcc-20181216/cc/cc/CVS/Root 0100644 0001750 0000000 00000000011 13405330640 0013725 0 ustar ragge wheel /cvsroot
pcc-20181216/cc/cc/CVS/Repository 0100644 0001750 0000000 00000000012 13405330640 0015162 0 ustar ragge wheel pcc/cc/cc
pcc-20181216/cc/cc/CVS/Entries 0100644 0001750 0000000 00000000174 13405330640 0014425 0 ustar ragge wheel /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.in 0100644 0001750 0000000 00000004617 13345722730 0014521 0 ustar ragge wheel # $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.1 0100644 0001750 0000000 00000022636 12776675465 0013147 0 ustar ragge wheel .\" $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.c 0100644 0001750 0000000 00000142047 13405142465 0013203 0 ustar ragge wheel /* $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/ccom 0040755 0001750 0000000 00000000000 13405330640 0012714 5 ustar ragge wheel pcc-20181216/cc/ccom/CVS 0040755 0001750 0000000 00000000000 13405330640 0013347 5 ustar ragge wheel pcc-20181216/cc/ccom/CVS/Root 0100644 0001750 0000000 00000000011 13405330640 0014261 0 ustar ragge wheel /cvsroot
pcc-20181216/cc/ccom/CVS/Repository 0100644 0001750 0000000 00000000014 13405330640 0015520 0 ustar ragge wheel pcc/cc/ccom
pcc-20181216/cc/ccom/CVS/Entries 0100644 0001750 0000000 00000001367 13405330640 0014766 0 ustar ragge wheel /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.in 0100644 0001750 0000000 00000014023 13056105125 0015035 0 ustar ragge wheel # $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.c 0100644 0001750 0000000 00000071360 13401023456 0014774 0 ustar ragge wheel /* $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.1 0100644 0001750 0000000 00000031163 13405142556 0014006 0 ustar ragge wheel .\" $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.y 0100644 0001750 0000000 00000157644 13401023456 0014274 0 ustar ragge wheel /* $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