diff -Nur gcc-4.2.4.orig/ccs_version.h gcc-4.2.4/ccs_version.h --- gcc-4.2.4.orig/ccs_version.h 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/ccs_version.h 2015-07-03 18:46:05.717283542 -0500 @@ -0,0 +1,8 @@ +/* This file has been generated by CCS - do not edit. */ + +#define CCS_FULL_VSTR "1.4.0.3" + +#define CCS_MAJOR_VN 1 +#define CCS_MINOR_VN 4 +#define CCS_RELEASE_VN 0 +#define CCS_BUILD_VN 3 diff -Nur gcc-4.2.4.orig/config.guess gcc-4.2.4/config.guess --- gcc-4.2.4.orig/config.guess 2006-10-15 22:27:17.000000000 -0500 +++ gcc-4.2.4/config.guess 2015-07-03 19:15:14.097267674 -0500 @@ -1,14 +1,12 @@ #! /bin/sh # Attempt to guess a canonical system name. -# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, -# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, -# Inc. +# Copyright 1992-2014 Free Software Foundation, Inc. -timestamp='2006-07-02' +timestamp='2014-03-23' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or +# 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 @@ -17,26 +15,22 @@ # General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA -# 02110-1301, USA. +# 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. - - -# Originally written by Per Bothner . -# Please send patches to . Submit a context -# diff and a properly formatted ChangeLog entry. +# 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"). # -# This script attempts to guess a canonical system name similar to -# config.sub. If it succeeds, it prints the system name on stdout, and -# exits with 0. Otherwise, it exits with 1. +# Originally written by Per Bothner. # -# The plan is that this can be called by configure scripts if you -# don't specify an explicit build system type. +# 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 with a ChangeLog entry to config-patches@gnu.org. + me=`echo "$0" | sed -e 's,.*/,,'` @@ -56,8 +50,7 @@ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 -Free Software Foundation, Inc. +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." @@ -139,12 +132,33 @@ 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 tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # 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 @@ -161,6 +175,7 @@ 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 @@ -169,7 +184,7 @@ arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ - | grep __ELF__ >/dev/null + | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? @@ -179,7 +194,7 @@ fi ;; *) - os=netbsd + os=netbsd ;; esac # The OS release @@ -200,6 +215,10 @@ # 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} @@ -222,7 +241,7 @@ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) - UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on @@ -268,7 +287,10 @@ # 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'` - exit ;; + # 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 @@ -294,12 +316,12 @@ echo s390-ibm-zvmoe exit ;; *:OS400:*:*) - echo powerpc-ibm-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:*:*) + arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) @@ -323,14 +345,33 @@ 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:SunOS:5.*:*) - echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + 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 @@ -374,23 +415,23 @@ # 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} + echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} - exit ;; + exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} + echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) - echo m68k-milan-mint${UNAME_RELEASE} - exit ;; + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) - echo m68k-hades-mint${UNAME_RELEASE} - exit ;; + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) - echo m68k-unknown-mint${UNAME_RELEASE} - exit ;; + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; @@ -460,8 +501,8 @@ echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) - # DG/UX returns AViiON for all architectures - UNAME_PROCESSOR=`/usr/bin/uname -p` + # 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 ] || \ @@ -474,7 +515,7 @@ else echo i586-dg-dgux${UNAME_RELEASE} fi - exit ;; + exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; @@ -531,7 +572,7 @@ echo rs6000-ibm-aix3.2 fi exit ;; - *:AIX:*:[45]) + *: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 @@ -574,52 +615,52 @@ 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" ;; + 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 + esac ;; + esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + 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); - #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); - } + 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 @@ -639,7 +680,7 @@ # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | - grep __LP64__ >/dev/null + grep -q __LP64__ then HP_ARCH="hppa2.0w" else @@ -710,22 +751,22 @@ exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd - exit ;; + exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi - exit ;; + exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd - exit ;; + exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd - exit ;; + exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd - exit ;; + exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; @@ -749,14 +790,14 @@ 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 ;; + 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}" + 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} @@ -768,37 +809,51 @@ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) - case ${UNAME_MACHINE} in - pc98) - echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + UNAME_PROCESSOR=`/usr/bin/uname -p` + case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) - echo ${UNAME_MACHINE}-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 ;; - i*:MINGW*:*) + *: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 + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; - x86:Interix*:[3456]*) - echo i586-pc-interix${UNAME_RELEASE} - exit ;; - EM64T:Interix*:[3456]*) - echo x86_64-unknown-interix${UNAME_RELEASE} - 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 @@ -819,200 +874,157 @@ exit ;; *:GNU:*:*) # the GNU system - echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + 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/[-(].*//'`-gnu + 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 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:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu + 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-gnu + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; cris:Linux:*:*) - echo cris-axis-linux-gnu + echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; crisv32:Linux:*:*) - echo crisv32-axis-linux-gnu + echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; frv:Linux:*:*) - echo frv-unknown-linux-gnu + 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-gnu + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m32r*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m68*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; - mips:Linux:*:*) + mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU - #undef mips - #undef mipsel + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) - CPU=mipsel + CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) - CPU=mips + CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF - eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' - /^CPU/{ - s: ::g - p - }'`" - test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } ;; - mips64:Linux:*:*) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - #undef CPU - #undef mips64 - #undef mips64el - #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) - CPU=mips64el - #else - #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) - CPU=mips64 - #else - CPU= - #endif - #endif -EOF - eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' - /^CPU/{ - s: ::g - p - }'`" - test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } - ;; - or32:Linux:*:*) - echo or32-unknown-linux-gnu + openrisc*:Linux:*:*) + echo or1k-unknown-linux-${LIBC} exit ;; - ppc:Linux:*:*) - echo powerpc-unknown-linux-gnu + or32:Linux:*:* | or1k*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; - ppc64:Linux:*:*) - echo powerpc64-unknown-linux-gnu + padre:Linux:*:*) + echo sparc-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 ld.so.1 >/dev/null - if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi - echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + 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-gnu ;; - PA8*) echo hppa2.0-unknown-linux-gnu ;; - *) echo hppa-unknown-linux-gnu ;; + PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; + PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; + *) echo hppa-unknown-linux-${LIBC} ;; esac exit ;; - parisc64:Linux:*:* | hppa64:Linux:*:*) - echo hppa64-unknown-linux-gnu + 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 + echo ${UNAME_MACHINE}-ibm-linux-${LIBC} exit ;; sh64*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sh*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + tile*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; vax:Linux:*:*) - echo ${UNAME_MACHINE}-dec-linux-gnu + echo ${UNAME_MACHINE}-dec-linux-${LIBC} exit ;; x86_64:Linux:*:*) - echo x86_64-unknown-linux-gnu + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; - i*86:Linux:*:*) - # The BFD linker knows what the default object file format is, so - # first see if it will tell us. cd to the root directory to prevent - # problems with other programs or directories called `ld' in the path. - # Set LC_ALL=C to ensure ld outputs messages in English. - ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ - | sed -ne '/supported targets:/!d - s/[ ][ ]*/ /g - s/.*supported targets: *// - s/ .*// - p'` - case "$ld_supported_targets" in - elf32-i386) - TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" - ;; - a.out-i386-linux) - echo "${UNAME_MACHINE}-pc-linux-gnuaout" - exit ;; - coff-i386) - echo "${UNAME_MACHINE}-pc-linux-gnucoff" - exit ;; - "") - # Either a pre-BFD a.out linker (linux-gnuoldld) or - # one that does not give us useful --help. - echo "${UNAME_MACHINE}-pc-linux-gnuoldld" - exit ;; - esac - # Determine whether the default compiler is a.out or elf - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - #include - #ifdef __ELF__ - # ifdef __GLIBC__ - # if __GLIBC__ >= 2 - LIBC=gnu - # else - LIBC=gnulibc1 - # endif - # else - LIBC=gnulibc1 - # endif - #else - #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) - LIBC=gnu - #else - LIBC=gnuaout - #endif - #endif - #ifdef __dietlibc__ - LIBC=dietlibc - #endif -EOF - eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' - /^LIBC/{ - s: ::g - p - }'`" - test x"${LIBC}" != x && { - echo "${UNAME_MACHINE}-pc-linux-${LIBC}" - exit - } - test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; 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 @@ -1020,11 +1032,11 @@ 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, + # 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. + # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) @@ -1041,7 +1053,7 @@ i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; - i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) @@ -1056,7 +1068,7 @@ fi exit ;; i*86:*:5:[678]*) - # UnixWare 7.x, OpenUNIX and OpenServer 6. + # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; @@ -1084,10 +1096,13 @@ 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 i386. - echo i386-pc-msdosdjgpp - exit ;; + # 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 ;; @@ -1122,8 +1137,18 @@ /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; } ;; + /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 ;; @@ -1136,7 +1161,7 @@ rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; - PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) @@ -1156,10 +1181,10 @@ echo ns32k-sni-sysv fi exit ;; - PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort - # says - echo i586-unisys-sysv4 - 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 @@ -1185,11 +1210,11 @@ exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then - echo mips-nec-sysv${UNAME_RELEASE} + echo mips-nec-sysv${UNAME_RELEASE} else - echo mips-unknown-sysv${UNAME_RELEASE} + echo mips-unknown-sysv${UNAME_RELEASE} fi - exit ;; + exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; @@ -1199,6 +1224,12 @@ 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 ;; @@ -1208,6 +1239,15 @@ 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 ;; @@ -1216,9 +1256,31 @@ exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown - case $UNAME_PROCESSOR in - unknown) UNAME_PROCESSOR=powerpc ;; - esac + 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]*:*) @@ -1232,7 +1294,10 @@ *:QNX:*:4*) echo i386-pc-qnx exit ;; - NSE-?:NONSTOP_KERNEL:*:*) + NEO-?:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk${UNAME_RELEASE} + exit ;; + NSE-*:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) @@ -1277,13 +1342,13 @@ echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) - echo mips-sei-seiux${UNAME_RELEASE} + 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` + UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; @@ -1298,158 +1363,13 @@ i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; -esac - -#echo '(No uname command or uname output not recognized.)' 1>&2 -#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 - -eval $set_cc_for_build -cat >$dummy.c < -# include -#endif -main () -{ -#if defined (sony) -#if defined (MIPSEB) - /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, - I don't know.... */ - printf ("mips-sony-bsd\n"); exit (0); -#else -#include - printf ("m68k-sony-newsos%s\n", -#ifdef NEWSOS4 - "4" -#else - "" -#endif - ); exit (0); -#endif -#endif - -#if defined (__arm) && defined (__acorn) && defined (__unix) - printf ("arm-acorn-riscix\n"); exit (0); -#endif - -#if defined (hp300) && !defined (hpux) - printf ("m68k-hp-bsd\n"); exit (0); -#endif - -#if defined (NeXT) -#if !defined (__ARCHITECTURE__) -#define __ARCHITECTURE__ "m68k" -#endif - int version; - version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; - if (version < 4) - printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); - else - printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); - exit (0); -#endif - -#if defined (MULTIMAX) || defined (n16) -#if defined (UMAXV) - printf ("ns32k-encore-sysv\n"); exit (0); -#else -#if defined (CMU) - printf ("ns32k-encore-mach\n"); exit (0); -#else - printf ("ns32k-encore-bsd\n"); exit (0); -#endif -#endif -#endif - -#if defined (__386BSD__) - printf ("i386-pc-bsd\n"); exit (0); -#endif - -#if defined (sequent) -#if defined (i386) - printf ("i386-sequent-dynix\n"); exit (0); -#endif -#if defined (ns32000) - printf ("ns32k-sequent-dynix\n"); exit (0); -#endif -#endif - -#if defined (_SEQUENT_) - struct utsname un; - - uname(&un); - - if (strncmp(un.version, "V2", 2) == 0) { - printf ("i386-sequent-ptx2\n"); exit (0); - } - if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ - printf ("i386-sequent-ptx1\n"); exit (0); - } - printf ("i386-sequent-ptx\n"); exit (0); - -#endif - -#if defined (vax) -# if !defined (ultrix) -# include -# if defined (BSD) -# if BSD == 43 - printf ("vax-dec-bsd4.3\n"); exit (0); -# else -# if BSD == 199006 - printf ("vax-dec-bsd4.3reno\n"); exit (0); -# else - printf ("vax-dec-bsd\n"); exit (0); -# endif -# endif -# else - printf ("vax-dec-bsd\n"); exit (0); -# endif -# else - printf ("vax-dec-ultrix\n"); exit (0); -# endif -#endif - -#if defined (alliant) && defined (i860) - printf ("i860-alliant-bsd\n"); exit (0); -#endif - - exit (1); -} -EOF - -$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && - { echo "$SYSTEM_NAME"; exit; } - -# Apollos put the system type in the environment. - -test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } - -# Convex versions that predate uname can use getsysinfo(1) - -if [ -x /usr/convex/getsysinfo ] -then - case `getsysinfo -f cpu_type` in - c1*) - echo c1-convex-bsd + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros exit ;; - c2*) - if getsysinfo -f scalar_acc - then echo c32-convex-bsd - else echo c2-convex-bsd - fi - exit ;; - c34*) - echo c34-convex-bsd + x86_64:VMkernel:*:*) + echo ${UNAME_MACHINE}-unknown-esx exit ;; - c38*) - echo c38-convex-bsd - exit ;; - c4*) - echo c4-convex-bsd - exit ;; - esac -fi +esac cat >&2 </dev/null`; do \ dir=`echo $$i | sed -e 's/;.*$$//'`; \ @@ -581,8 +586,13 @@ true; \ else \ lib=`${PWD_COMMAND} | sed -e 's,^.*/\([^/][^/]*\)$$,\1,'`; \ - for dir in Makefile $(MULTIDIRS); do \ - if [ -f ../$${dir}/$${lib}/Makefile ]; then \ + for dir in : $(MULTIDIRS); do \ + test $$dir != : || continue; \ +EOF +cat >>Multi.tem <>Multi.tem <<\EOF if (cd ../$${dir}/$${lib}; $(MAKE) $(FLAGS_TO_PASS) $(DO)); \ then true; \ else exit 1; \ @@ -600,7 +610,7 @@ fi # ${ml_toplevel_p} = yes if [ "${ml_verbose}" = --verbose ]; then - echo "Adding multilib support to Makefile in ${ml_realsrcdir}" + echo "Adding multilib support to ${Makefile} in ${ml_realsrcdir}" if [ "${ml_toplevel_p}" = yes ]; then echo "multidirs=${multidirs}" fi @@ -691,7 +701,7 @@ fi ml_origdir=`${PWDCMD-pwd}` - ml_libdir=`echo $ml_origdir | sed -e 's,^.*/,,'` + ml_libdir=`echo "$ml_origdir" | sed -e 's,^.*/,,'` # cd to top-level-build-dir/${with_target_subdir} cd .. @@ -727,7 +737,7 @@ case ${srcdir} in ".") - echo Building symlink tree in `${PWDCMD-pwd}`/${ml_dir}/${ml_libdir} + echo "Building symlink tree in `${PWDCMD-pwd}`/${ml_dir}/${ml_libdir}" if [ "${with_target_subdir}" != "." ]; then ml_unsubdir="../" else @@ -735,7 +745,7 @@ fi (cd ${ml_dir}/${ml_libdir}; ../${dotdot}${ml_unsubdir}symlink-tree ../${dotdot}${ml_unsubdir}${ml_libdir} "") - if [ -f ${ml_dir}/${ml_libdir}/Makefile ]; then + if [ -f ${ml_dir}/${ml_libdir}/${Makefile} ]; then if [ x"${MAKE}" = x ]; then (cd ${ml_dir}/${ml_libdir}; make distclean) else @@ -792,7 +802,7 @@ else # Create a regular expression that matches any string as long # as ML_POPDIR. - popdir_rx=`echo ${ML_POPDIR} | sed 's,.,.,g'` + popdir_rx=`echo "${ML_POPDIR}" | sed 's,.,.,g'` CC_= for arg in ${CC}; do case $arg in @@ -890,17 +900,17 @@ if eval ${ml_config_env} ${ml_config_shell} ${ml_recprog} \ --with-multisubdir=${ml_dir} --with-multisrctop=${multisrctop} \ - ${ac_configure_args} ${ml_srcdiroption} ; then + ${ac_configure_args} ${ml_config_env} ${ml_srcdiroption} ; then true else exit 1 fi - cd ${ML_POPDIR} + cd "${ML_POPDIR}" done - cd ${ml_origdir} + cd "${ml_origdir}" fi fi # ${ml_toplevel_p} = yes diff -Nur gcc-4.2.4.orig/config.sub gcc-4.2.4/config.sub --- gcc-4.2.4.orig/config.sub 2006-10-15 22:27:17.000000000 -0500 +++ gcc-4.2.4/config.sub 2015-07-03 19:15:14.097267674 -0500 @@ -1,44 +1,40 @@ #! /bin/sh # Configuration validation subroutine script. -# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, -# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, -# Inc. - -timestamp='2006-09-20' - -# This file is (in principle) common to ALL GNU software. -# The presence of a machine in this file suggests that SOME GNU software -# can handle that machine. It does not imply ALL GNU software can. -# -# This file is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or +# Copyright 1992-2014 Free Software Foundation, Inc. + +timestamp='2014-09-26' + +# 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. +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA -# 02110-1301, USA. +# 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. +# 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 . Submit a context -# diff and a properly formatted ChangeLog entry. +# Please send patches with a ChangeLog entry to config-patches@gnu.org. # # 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. @@ -72,8 +68,7 @@ version="\ GNU config.sub ($timestamp) -Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 -Free Software Foundation, Inc. +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." @@ -120,12 +115,18 @@ # 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-dietlibc | linux-newlib* | linux-uclibc* | \ - uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ + linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | \ + 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 ] @@ -148,10 +149,13 @@ -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) + -apple | -axis | -knuth | -cray | -microblaze*) os= basic_machine=$1 ;; + -bluegene*) + os=-cnk + ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 @@ -166,10 +170,10 @@ os=-chorusos basic_machine=$1 ;; - -chorusrdb) - os=-chorusrdb + -chorusrdb) + os=-chorusrdb basic_machine=$1 - ;; + ;; -hiux*) os=-hiuxwe2 ;; @@ -214,6 +218,12 @@ -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; + -lynx*178) + os=-lynxos178 + ;; + -lynx*5) + os=-lynxos5 + ;; -lynx*) os=-lynxos ;; @@ -238,59 +248,89 @@ # 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 | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | arc | arceb \ + | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ + | avr | avr32 \ + | be32 | be64 \ | bfin \ - | c4x | clipper \ + | c4x | c8051 | clipper \ | d10v | d30v | dlx | dsp16xx \ - | fr30 | frv \ + | epiphany \ + | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ + | k1om \ + | le32 | le64 \ + | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ - | maxq | mb | microblaze | mcore \ + | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ - | mips64vr | mips64vrel \ + | 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 \ - | nios | nios2 \ + | nds32 | nds32le | nds32be \ + | nios | nios2 | nios2eb | nios2el \ | ns16k | ns32k \ - | or32 \ + | open8 | or1k | or1knd | or32 \ | pdp10 | pdp11 | pj | pjl \ - | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ + | riscv32 | riscv64 \ + | rl78 | rx \ | score \ - | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | 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 \ - | spu | strongarm \ - | tahoe | thumb | tic4x | tic80 | tron \ - | v850 | v850e \ + | spu \ + | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | we32k \ - | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ - | z8k) + | x86 | xc16x | xstormy16 | xtensa \ + | z8k | z80) basic_machine=$basic_machine-unknown ;; - m6811 | m68hc11 | m6812 | m68hc12) - # Motorola 68HC11/12. + 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 ;; @@ -300,6 +340,21 @@ 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. @@ -314,64 +369,86 @@ # 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-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ + | be32-* | be64-* \ | bfin-* | bs2000-* \ - | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ - | clipper-* | craynv-* | cydra-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ + | c8051-* | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ - | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ + | 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-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ - | m88110-* | m88k-* | maxq-* | mcore-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ + | microblaze-* | microblazeel-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ - | mips64vr-* | mips64vrel-* \ + | 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-* \ - | nios-* | nios2-* \ + | nds32-* | nds32le-* | nds32be-* \ + | nios-* | nios2-* | nios2eb-* | nios2el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ + | open8-* \ + | or1k*-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ - | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ - | romp-* | rs6000-* \ - | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | 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-* | strongarm-* | sv1-* | sx?-* \ - | tahoe-* | thumb-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ + | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tile*-* \ | tron-* \ - | v850-* | v850e-* | vax-* \ + | ubicom32-* \ + | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ + | vax-* \ | we32k-* \ - | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ - | xstormy16-* | xtensa-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* \ + | xstormy16-* | xtensa*-* \ | ymp-* \ - | z8k-*) + | 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. @@ -389,7 +466,7 @@ basic_machine=a29k-amd os=-udi ;; - abacus) + abacus) basic_machine=abacus-unknown ;; adobe68k) @@ -435,6 +512,10 @@ basic_machine=m68k-apollo os=-bsd ;; + aros) + basic_machine=i386-pc + os=-aros + ;; aux) basic_machine=m68k-apple os=-aux @@ -443,10 +524,35 @@ 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 @@ -475,8 +581,8 @@ basic_machine=craynv-cray os=-unicosmp ;; - cr16c) - basic_machine=cr16c-unknown + cr16 | cr16-*) + basic_machine=cr16-unknown os=-elf ;; crds | unos) @@ -514,6 +620,10 @@ basic_machine=m88k-motorola os=-sysv3 ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp @@ -629,7 +739,6 @@ i370-ibm* | ibm*) basic_machine=i370-ibm ;; -# I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 @@ -668,6 +777,17 @@ 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 ;; @@ -679,10 +799,21 @@ basic_machine=ns32k-utek os=-sysv ;; + microblaze*) + basic_machine=microblaze-xilinx + ;; + mingw64) + basic_machine=x86_64-pc + os=-mingw64 + ;; mingw32) - basic_machine=i386-pc + basic_machine=i686-pc os=-mingw32 ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; miniframe) basic_machine=m68000-convergent ;; @@ -704,6 +835,10 @@ basic_machine=powerpc-unknown os=-morphos ;; + moxiebox) + basic_machine=moxie-unknown + os=-moxiebox + ;; msdos) basic_machine=i386-pc os=-msdos @@ -711,10 +846,18 @@ 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 @@ -779,6 +922,12 @@ np1) basic_machine=np1-gould ;; + neo-tandem) + basic_machine=neo-tandem + ;; + nse-tandem) + basic_machine=nse-tandem + ;; nsr-tandem) basic_machine=nsr-tandem ;; @@ -809,6 +958,14 @@ 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 ;; @@ -853,9 +1010,10 @@ ;; power) basic_machine=power-ibm ;; - ppc) basic_machine=powerpc-unknown + ppc | ppcbe) basic_machine=powerpc-unknown ;; - ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ppc-* | ppcbe-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown @@ -880,7 +1038,11 @@ basic_machine=i586-unknown os=-pw32 ;; - rdos) + rdos | rdos64) + basic_machine=x86_64-pc + os=-rdos + ;; + rdos32) basic_machine=i386-pc os=-rdos ;; @@ -925,6 +1087,9 @@ basic_machine=sh-hitachi os=-hms ;; + sh5el) + basic_machine=sh5le-unknown + ;; sh64) basic_machine=sh64-unknown ;; @@ -946,6 +1111,9 @@ basic_machine=i860-stratus os=-sysv4 ;; + strongarm-* | thumb-*) + basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; sun2) basic_machine=m68000-sun ;; @@ -1002,17 +1170,9 @@ basic_machine=t90-cray os=-unicos ;; - tic54x | c54x*) - basic_machine=tic54x-unknown - os=-coff - ;; - tic55x | c55x*) - basic_machine=tic55x-unknown - os=-coff - ;; - tic6x | c6x*) - basic_machine=tic6x-unknown - os=-coff + tile*) + basic_machine=$basic_machine-unknown + os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown @@ -1081,6 +1241,9 @@ 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 @@ -1089,6 +1252,10 @@ basic_machine=z8k-unknown os=-sim ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; none) basic_machine=none-none os=-none @@ -1127,7 +1294,7 @@ we32k) basic_machine=we32k-att ;; - sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele) + 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) @@ -1174,9 +1341,12 @@ if [ x"$os" != x"" ] then case $os in - # First match some system type aliases - # that might get confused with valid system types. + # 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|'` ;; @@ -1197,29 +1367,31 @@ # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ - | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ - | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -*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* \ + | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ - | -openbsd* | -solidbsd* \ + | -bitrig* | -openbsd* | -solidbsd* \ | -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* \ - | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ - | -uxpv* | -beos* | -mpeix* | -udk* \ + | -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*) + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) @@ -1258,7 +1430,7 @@ -opened*) os=-openedition ;; - -os400*) + -os400*) os=-os400 ;; -wince*) @@ -1307,7 +1479,7 @@ -sinix*) os=-sysv4 ;; - -tpf*) + -tpf*) os=-tpf ;; -triton*) @@ -1343,12 +1515,14 @@ -aros*) os=-aros ;; - -kaos*) - os=-kaos - ;; -zvmoe) os=-zvmoe ;; + -dicos*) + os=-dicos + ;; + -nacl*) + ;; -none) ;; *) @@ -1371,10 +1545,10 @@ # system, and we'll never get to this point. case $basic_machine in - score-*) + score-*) os=-elf ;; - spu-*) + spu-*) os=-elf ;; *-acorn) @@ -1386,8 +1560,23 @@ arm*-semi) os=-aout ;; - c4x-* | tic4x-*) - os=-coff + 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-*) @@ -1407,13 +1596,13 @@ ;; m68000-sun) os=-sunos3 - # This also exists in the configure program, but was not the - # default. - # os=-sunos4 ;; m68*-cisco) os=-aout ;; + mep-*) + os=-elf + ;; mips*-cisco) os=-elf ;; @@ -1438,7 +1627,7 @@ *-ibm) os=-aix ;; - *-knuth) + *-knuth) os=-mmixware ;; *-wec) @@ -1543,7 +1732,7 @@ -sunos*) vendor=sun ;; - -aix*) + -cnk*|-aix*) vendor=ibm ;; -beos*) diff -Nur gcc-4.2.4.orig/contrib/test_installed gcc-4.2.4/contrib/test_installed --- gcc-4.2.4.orig/contrib/test_installed 2003-07-11 01:05:01.000000000 -0500 +++ gcc-4.2.4/contrib/test_installed 2015-07-03 18:46:05.717283542 -0500 @@ -107,6 +107,8 @@ set srcdir "${testsuite-${srcdir}/gcc/testsuite}" set CFLAGS "" set CXXFLAGS "" +set HOSTCC "cc" +set HOSTCFLAGS "" set GCC_UNDER_TEST "${GCC_UNDER_TEST-${prefix}${prefix+/bin/}gcc}" set GXX_UNDER_TEST "${GXX_UNDER_TEST-${prefix}${prefix+/bin/}g++}" set G77_UNDER_TEST "${G77_UNDER_TEST-${prefix}${prefix+/bin/}g77}" diff -Nur gcc-4.2.4.orig/fixincludes/mkfixinc.sh gcc-4.2.4/fixincludes/mkfixinc.sh --- gcc-4.2.4.orig/fixincludes/mkfixinc.sh 2004-11-23 16:45:53.000000000 -0600 +++ gcc-4.2.4/fixincludes/mkfixinc.sh 2015-07-03 18:46:05.717283542 -0500 @@ -23,6 +23,7 @@ i?86-*-mingw32* | \ i?86-*-uwin* | \ i?86-*-interix* | \ + metag*-linux-uclibc* | \ powerpc-*-eabiaix* | \ powerpc-*-eabisim* | \ powerpc-*-eabi* | \ diff -Nur gcc-4.2.4.orig/gcc/caller-save.c gcc-4.2.4/gcc/caller-save.c --- gcc-4.2.4.orig/gcc/caller-save.c 2007-09-01 10:28:30.000000000 -0500 +++ gcc-4.2.4/gcc/caller-save.c 2015-07-03 18:46:05.717283542 -0500 @@ -36,6 +36,10 @@ #include "tm_p.h" #include "addresses.h" +#ifndef CALLER_SAVE_INSN_CODE +#define CALLER_SAVE_INSN_CODE(CODE) (CODE) +#endif + #ifndef MAX_MOVE_MAX #define MAX_MOVE_MAX MOVE_MAX #endif @@ -776,7 +780,8 @@ /* Emit a new caller-save insn and set the code. */ static struct insn_chain * -insert_one_insn (struct insn_chain *chain, int before_p, int code, rtx pat) +insert_one_insn (struct insn_chain *chain, int before_p, + int code ATTRIBUTE_UNUSED, rtx pat) { rtx insn = chain->insn; struct insn_chain *new; @@ -857,6 +862,6 @@ new->block = chain->block; new->is_caller_save_insn = 1; - INSN_CODE (new->insn) = code; + INSN_CODE (new->insn) = CALLER_SAVE_INSN_CODE (code); return new; } diff -Nur gcc-4.2.4.orig/gcc/calls.c gcc-4.2.4/gcc/calls.c --- gcc-4.2.4.orig/gcc/calls.c 2007-09-01 10:28:30.000000000 -0500 +++ gcc-4.2.4/gcc/calls.c 2015-07-03 18:46:05.717283542 -0500 @@ -829,6 +829,7 @@ { int bytes = int_size_in_bytes (TREE_TYPE (args[i].tree_value)); int endian_correction = 0; + rtx value; if (args[i].partial) { @@ -858,10 +859,22 @@ ) endian_correction = BITS_PER_WORD - bytes * BITS_PER_UNIT; + + value = args[i].value; + +#if METAG_PARTIAL_ARGS + if (args[i].partial) + { + HOST_WIDE_INT excess = (bytes + (UNITS_PER_WORD - 1)) & ~(UNITS_PER_WORD - 1); + + value = adjust_address (value, GET_MODE (value), excess - args[i].partial); + } +#endif + for (j = 0; j < args[i].n_aligned_regs; j++) { rtx reg = gen_reg_rtx (word_mode); - rtx word = operand_subword_force (args[i].value, j, BLKmode); + rtx word = operand_subword_force (value, j, BLKmode); int bitsize = MIN (bytes * BITS_PER_UNIT, BITS_PER_WORD); args[i].aligned_regs[j] = reg; diff -Nur gcc-4.2.4.orig/gcc/config/metag/builtins.md gcc-4.2.4/gcc/config/metag/builtins.md --- gcc-4.2.4.orig/gcc/config/metag/builtins.md 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/builtins.md 2015-07-03 18:46:05.741283542 -0500 @@ -0,0 +1,106 @@ +;; Machine description for GNU compiler, +;; Imagination Technologies Meta version. +;; Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 +;; Imagination Technologies Ltd + +;; This file is part of GCC. + +;; GCC is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 3, or (at your option) any later +;; version. + +;; GCC is distributed in the hope that it will be useful, but WITHOUT ANY +;; WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; . + +;;- meta builtins functions + +;; "__builtin_dcache_preload" data cache preload +(define_insn "dcache_preload" + [(set (reg:SI RAPF_REG) + (unspec_volatile:SI [(match_operand:SI 0 "metag_register_op" "r")] VUNSPEC_DCACHE_PRELOAD))] + "TARGET_BUILTINS_METAC_1_1 || TARGET_BUILTINS_METAC_1_2 || TARGET_BUILTINS_METAC_2_1" + "MOV\\tRAPF,%0\\t\\t%@ (*prefetch OK)" + [(set_attr "type" "fast")]) + +;; "__builtin_dcache_flush" data cache flush +(define_insn "dcache_flush" + [(unspec_volatile [(match_operand:SI 0 "metag_register_op" "r") + (match_operand:SI 1 "metag_register_op" "r")] VUNSPEC_DCACHE)] + "TARGET_BUILTINS_METAC_1_2 || TARGET_BUILTINS_METAC_2_1" + "DCACHE\\t[%0],%1\\t\\t%@ (*flush OK)" + [(set_attr "type" "fast")]) + +;; "__builtin_dcache_refresh" data cache refresh +(define_insn "dcache_refresh" + [(set (reg:SI RAPF_REG) + (unspec_volatile:SI [(match_operand:SI 0 "metag_register_op" "d") + (match_operand:SI 1 "metag_register_op" "a")] VUNSPEC_DCACHE_REFRESH))] + "TARGET_BUILTINS_METAC_1_1 || TARGET_BUILTINS_METAC_1_2 || TARGET_BUILTINS_METAC_2_1" + "* +{ + if (TARGET_BUILTINS_METAC_1_1) + output_asm_insn (\"SETB\\t[%0],%1\\t\\t%@ (*refresh ...\\n\\tLSL\\tRAPF,%0,#6\\t\\t%@ ... OK)\", + operands); + else + output_asm_insn (\"DCACHE\\t[%0],%1\\t\\t%@ (*refresh ...\\n\\tADD\\tRAPF,%0,#0\\t\\t%@ ... OK)\", + operands); + return \"\"; +}" + [(set_attr "type" "two")]) + +;; "__builtin_meta2_cacherd" +(define_insn "meta2_cacherd" + [(set (match_operand:SI 0 "metag_register_op" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "metag_register_op" "r")] VUNSPEC_META2_CACHERD))] + "TARGET_BUILTINS_METAC_2_1" + "CACHERD\\t%0,[%1]\\t\\t%@ (*cacherd OK)" + [(set_attr "type" "fast")]) + +;; "__builtin_meta2_cacherl" +(define_insn "meta2_cacherl" + [(set (match_operand:DI 0 "metag_register_op" "=r") + (unspec_volatile:DI [(match_operand:SI 1 "metag_register_op" "r")] VUNSPEC_META2_CACHERL))] + "TARGET_BUILTINS_METAC_2_1" + "CACHERL\\t%0,%t0,[%1]\\t\\t%@ (*cacherl OK)" + [(set_attr "type" "fast")]) + +;; "__builtin_meta2_cachewd" +(define_insn "meta2_cachewd" + [(unspec_volatile [(match_operand:SI 0 "metag_register_op" "r") + (match_operand:SI 1 "metag_register_op" "r")] VUNSPEC_META2_CACHEWD)] + "TARGET_BUILTINS_METAC_2_1" + "CACHEWD\\t[%0],%1\\t\\t%@ (*cachewd OK)" + [(set_attr "type" "fast")]) + +;; "__builtin_meta2_cachewl" +(define_insn "meta2_cachewl" + [(unspec_volatile [(match_operand:SI 0 "metag_register_op" "r") + (match_operand:DI 1 "metag_register_op" "r")] VUNSPEC_META2_CACHEWL)] + "TARGET_BUILTINS_METAC_2_1" + "CACHEWL\\t[%0],%1,%t1\\t\\t%@ (*cachewl OK)" + [(set_attr "type" "fast")]) + +; "__builtin_metag_bswap" +(define_insn "metag_bswap" + [(set (match_operand:SI 0 "metag_register_op" "=e,f") + (unspec:SI [(match_operand:SI 1 "metag_register_op" "e,f")] UNSPEC_METAG_BSWAP))] + "TARGET_BUILTINS_METAC_2_1 && metag_meta2_bex_enabled" + "BEXD\\t%0,%1\\t\\t%@ (*bswap OK)" + [(set_attr "type" "fast")]) + +; "__builtin_metag_bswapll" +(define_insn "metag_bswapll" + [(set (match_operand:DI 0 "metag_register_op" "=d") + (unspec:DI [(match_operand:DI 1 "metag_register_op" "d")] UNSPEC_METAG_BSWAPLL))] + "TARGET_BUILTINS_METAC_2_1 && metag_meta2_bex_enabled" + "BEXL\\t%t0,%1\\t\\t%@ (*bswapll OK)" + [(set_attr "type" "fast")]) + +;; end of file diff -Nur gcc-4.2.4.orig/gcc/config/metag/combines.md gcc-4.2.4/gcc/config/metag/combines.md --- gcc-4.2.4.orig/gcc/config/metag/combines.md 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/combines.md 2015-07-03 18:46:05.745283542 -0500 @@ -0,0 +1,1052 @@ +;; Machine description for GNU compiler, +;; Imagination Technologies Meta version. +;; Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010 +;; Imagination Technologies Ltd + +;; This file is part of GCC. + +;; GCC is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 3, or (at your option) any later +;; version. + +;; GCC is distributed in the hope that it will be useful, but WITHOUT ANY +;; WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; . + +;; ----------------------------------------------------------------------------- +;; | Recognising SI/HI/QI store pre-inc/dec/modify | +;; ----------------------------------------------------------------------------- + +(define_insn_and_split "*sto__pre_inc_dec_modify_disp_split" + [(set (mem:MEMOP (plus:SI (match_operand:SI 0 "metag_regnofrm_op" "+efhl") + (match_operand:SI 1 "metag_offset6_" ""))) + (match_operand: 2 "metag_register_op" "r")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_dup 1)))] + "TARGET_METAC_1_1 + && !reload_in_progress && !reload_completed" + "#" + "&& TRUE" + [(const_int 0)] + { + rtx pre, mem, insn; + + if (INTVAL (operands[1]) == GET_MODE_SIZE (mode)) + pre = gen_rtx_PRE_INC (SImode, operands[0]); + else if (INTVAL (operands[1]) == -GET_MODE_SIZE (mode)) + pre = gen_rtx_PRE_DEC (SImode, operands[0]); + else + { + rtx plus = gen_rtx_PLUS (SImode, operands[0], operands[1]); + + pre = gen_rtx_PRE_MODIFY (SImode, operands[0], plus); + } + + mem = gen_rtx_MEM (mode, pre); + insn = emit_insn (gen_rtx_SET (VOIDmode, mem, operands[2])); + + if (auto_inc_p (pre)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (pre, 0), REG_NOTES (insn)); + DONE; + } + [(set_attr "type" "fast")]) + +(define_insn_and_split "*sto__pre_modify_reg_split" + [(set (mem:MEMOP (plus:SI (match_operand:SI 0 "metag_regnofrm_op" "+%e,f,h,l") + (match_operand:SI 1 "metag_register_op" "e,f,h,l"))) + (match_operand: 2 "metag_register_op" "t,u,y,z")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_dup 1)))] + "TARGET_METAC_1_1 + && !reload_in_progress && !reload_completed" + "#" + "&& TRUE" + [(const_int 0)] + { + rtx plus = gen_rtx_PLUS (SImode, operands[0], operands[1]); + rtx pre_modify = gen_rtx_PRE_MODIFY (SImode, operands[0], plus); + rtx mem = gen_rtx_MEM (mode, pre_modify); + rtx insn = emit_insn (gen_rtx_SET (VOIDmode, mem, operands[2])); + + if (auto_inc_p (pre_modify)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (pre_modify, 0), REG_NOTES (insn)); + DONE; + } + [(set_attr "type" "fast")]) + +;; ----------------------------------------------------------------------------- + +;; ----------------------------------------------------------------------------- +;; | Recognising SI/HI/QI store post-inc/dec/modify | +;; ----------------------------------------------------------------------------- + +(define_insn_and_split "*sto__post_inc_dec_modify_disp_split" + [(set (mem:MEMOP (match_operand:SI 0 "metag_regnofrm_op" "+efhl")) + (match_operand: 1 "metag_register_op" "r")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_operand:SI 2 "metag_offset6_" "")))] + "TARGET_METAC_1_1 + && !reload_in_progress && !reload_completed" + "#" + "&& TRUE" + [(const_int 0)] + { + rtx post, mem, insn; + + if (INTVAL (operands[2]) == GET_MODE_SIZE (mode)) + post = gen_rtx_POST_INC (SImode, operands[0]); + else if (INTVAL (operands[2]) == -GET_MODE_SIZE (mode)) + post = gen_rtx_POST_DEC (SImode, operands[0]); + else + { + rtx plus = gen_rtx_PLUS (SImode, operands[0], operands[2]); + + post = gen_rtx_POST_MODIFY (SImode, operands[0], plus); + } + + mem = gen_rtx_MEM (mode, post); + insn = emit_insn (gen_rtx_SET (VOIDmode, mem, operands[1])); + + if (auto_inc_p (post)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (post, 0), REG_NOTES (insn)); + DONE; + } + [(set_attr "type" "fast")]) + +(define_insn_and_split "*sto__post_modify_reg_split" + [(set (mem:MEMOP (match_operand:SI 0 "metag_regnofrm_op" "+e,f,h,l")) + (match_operand: 1 "metag_register_op" "t,u,y,z")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_operand:SI 2 "metag_register_op" "e,f,h,l")))] + "TARGET_METAC_1_1 + && !reload_in_progress && !reload_completed" + "#" + "&& TRUE" + [(const_int 0)] + { + rtx plus = gen_rtx_PLUS (SImode, operands[0], operands[2]); + rtx post_modify = gen_rtx_POST_MODIFY (SImode, operands[0], plus); + rtx mem = gen_rtx_MEM (mode, post_modify); + rtx insn = emit_insn (gen_rtx_SET (VOIDmode, mem, operands[1])); + + if (auto_inc_p (post_modify)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (post_modify, 0), REG_NOTES (insn)); + DONE; + } + [(set_attr "type" "fast")]) + +;; ----------------------------------------------------------------------------- + +;; ----------------------------------------------------------------------------- +;; | Recognising QI/HI/SI load pre-inc/dec/modify | +;; ----------------------------------------------------------------------------- + +(define_insn_and_split "*lod__pre_inc_dec_modify_disp_split" + [(set (match_operand: 0 "metag_register_op" "=r") + (mem:MEMOP (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "+efhl") + (match_operand:SI 2 "metag_offset6_" "")))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_dup 2)))] + "TARGET_METAC_1_1 + && !reload_in_progress && !reload_completed" + "#" + "&& TRUE" + [(const_int 0)] + { + rtx pre, mem, insn; + + if (INTVAL (operands[2]) == GET_MODE_SIZE (mode)) + pre = gen_rtx_PRE_INC (SImode, operands[1]); + else if (INTVAL (operands[2]) == -GET_MODE_SIZE (mode)) + pre = gen_rtx_PRE_DEC (SImode, operands[1]); + else + { + rtx plus = gen_rtx_PLUS (SImode, operands[1], operands[2]); + + pre = gen_rtx_PRE_MODIFY (SImode, operands[1], plus); + } + + mem = gen_rtx_MEM (mode, pre); + insn = emit_insn (gen_rtx_SET (VOIDmode, operands[0], mem)); + + if (auto_inc_p (pre)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (pre, 0), REG_NOTES (insn)); + DONE; + } + [(set_attr "type" "fast")]) + +(define_insn_and_split "*lod__pre_modify_reg_split" + [(set (match_operand: 0 "metag_register_op" "=r,r,r,r") + (mem:MEMOP (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "+e,f,h,l") + (match_operand:SI 2 "metag_register_op" "e,f,h,l")))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_dup 2)))] + "TARGET_METAC_1_1 + && !reload_in_progress && !reload_completed" + "#" + "&& TRUE" + [(const_int 0)] + { + rtx plus = gen_rtx_PLUS (SImode, operands[1], operands[2]); + rtx pre_modify = gen_rtx_PRE_MODIFY (SImode, operands[1], plus); + rtx mem = gen_rtx_MEM (mode, pre_modify); + rtx insn = emit_insn (gen_rtx_SET (VOIDmode, operands[0], mem)); + + if (auto_inc_p (pre_modify)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (pre_modify, 0), REG_NOTES (insn)); + DONE; + } + [(set_attr "type" "fast")]) + +;; ----------------------------------------------------------------------------- + +;; ----------------------------------------------------------------------------- +;; | Recognising DI store pre-inc/dec/modify | +;; ----------------------------------------------------------------------------- + +(define_insn_and_split "*sto_di_pre_inc_dec_modify_disp_split" + [(set (mem:DI (plus:SI (match_operand:SI 0 "metag_regnofrm_op" "+efhl") + (match_operand:SI 1 "metag_offset6_di" "O8"))) + (match_operand:DI 2 "metag_register_op" "r")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_dup 1)))] + "TARGET_METAC_1_1 + && !reload_in_progress && !reload_completed" + "#" + "&& TRUE" + [(const_int 0)] + { + rtx pre, mem, insn; + + if (INTVAL (operands[1]) == GET_MODE_SIZE (DImode)) + pre = gen_rtx_PRE_INC (SImode, operands[0]); + else if (INTVAL (operands[1]) == -GET_MODE_SIZE (DImode)) + pre = gen_rtx_PRE_DEC (SImode, operands[0]); + else + { + rtx plus = gen_rtx_PLUS (SImode, operands[0], operands[1]); + + pre = gen_rtx_PRE_MODIFY (SImode, operands[0], plus); + } + + mem = gen_rtx_MEM (DImode, pre); + insn = emit_insn (gen_rtx_SET (VOIDmode, mem, operands[2])); + + if (auto_inc_p (pre)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (pre, 0), REG_NOTES (insn)); + DONE; + } + [(set_attr "type" "fast")]) + +(define_insn_and_split "*sto_di_pre_modify_reg_split" + [(set (mem:DI (plus:SI (match_operand:SI 0 "metag_regnofrm_op" "+e,f,h,l") + (match_operand:SI 1 "metag_register_op" "e,f,h,l"))) + (match_operand:DI 2 "metag_register_op" "a,a,d,d")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_dup 1)))] + "TARGET_METAC_1_1 + && !reload_in_progress && !reload_completed" + "#" + "&& TRUE" + [(const_int 0)] + { + rtx plus = gen_rtx_PLUS (SImode, operands[0], operands[1]); + rtx pre_modify = gen_rtx_PRE_MODIFY (SImode, operands[0], plus); + rtx mem = gen_rtx_MEM (DImode, pre_modify); + rtx insn = emit_insn (gen_rtx_SET (VOIDmode, mem, operands[2])); + + if (auto_inc_p (pre_modify)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (pre_modify, 0), REG_NOTES (insn)); + DONE; + } + [(set_attr "type" "fast")]) + +;; ----------------------------------------------------------------------------- +;; | Recognising DI store post-inc/dec/modify | +;; ----------------------------------------------------------------------------- + +(define_insn_and_split "*sto_di_post_inc_dec_modify_disp_split" + [(set (mem:DI (match_operand:SI 0 "metag_regnofrm_op" "+efhl")) + (match_operand:DI 1 "metag_register_op" "r")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_operand:SI 2 "metag_offset6_di" "O8")))] + "TARGET_METAC_1_1 + && !reload_in_progress && !reload_completed" + "#" + "&& TRUE" + [(const_int 0)] + { + rtx post, mem, insn; + + if (INTVAL (operands[2]) == GET_MODE_SIZE (DImode)) + post = gen_rtx_POST_INC (SImode, operands[0]); + else if (INTVAL (operands[2]) == -GET_MODE_SIZE (DImode)) + post = gen_rtx_POST_DEC (SImode, operands[0]); + else + { + rtx plus = gen_rtx_PLUS (SImode, operands[0], operands[2]); + + post = gen_rtx_POST_MODIFY (SImode, operands[0], plus); + } + + mem = gen_rtx_MEM (DImode, post); + insn = emit_insn (gen_rtx_SET (VOIDmode, mem, operands[1])); + + if (auto_inc_p (post)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (post, 0), REG_NOTES (insn)); + DONE; + } + [(set_attr "type" "fast")]) + +(define_insn_and_split "*sto_di_post_modify_reg_split" + [(set (mem:DI (match_operand:SI 0 "metag_regnofrm_op" "+e,f,h,l")) + (match_operand:DI 1 "metag_register_op" "a,a,d,d")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_operand:SI 2 "metag_register_op" "e,f,h,l")))] + + "TARGET_METAC_1_1 + && !reload_in_progress && !reload_completed" + "#" + "&& TRUE" + [(const_int 0)] + { + rtx plus = gen_rtx_PLUS (SImode, operands[0], operands[2]); + rtx post_modify = gen_rtx_POST_MODIFY (SImode, operands[0], plus); + rtx mem = gen_rtx_MEM (DImode, post_modify); + rtx insn = emit_insn (gen_rtx_SET (VOIDmode, mem, operands[1])); + + if (auto_inc_p (post_modify)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (post_modify, 0), REG_NOTES (insn)); + DONE; + } + [(set_attr "type" "fast")]) + +;; ----------------------------------------------------------------------------- + +;; ----------------------------------------------------------------------------- +;; | Recognising DI load pre-inc/dec/modify | +;; ----------------------------------------------------------------------------- + +(define_insn_and_split "*lod_di_pre_inc_dec_modify_disp_split" + [(set (match_operand:DI 0 "metag_register_op" "=r") + (mem:DI (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "+efhl") + (match_operand:SI 2 "metag_offset6_di" "O8")))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_dup 2)))] + "TARGET_METAC_1_1 + && !reload_in_progress && !reload_completed" + "#" + "&& TRUE" + [(const_int 0)] + { + rtx pre, mem, insn; + + if (INTVAL (operands[2]) == GET_MODE_SIZE (DImode)) + pre = gen_rtx_PRE_INC (SImode, operands[1]); + else if (INTVAL (operands[2]) == -GET_MODE_SIZE (DImode)) + pre = gen_rtx_PRE_DEC (SImode, operands[1]); + else + { + rtx plus = gen_rtx_PLUS (SImode, operands[1], operands[2]); + + pre = gen_rtx_PRE_MODIFY (SImode, operands[1], plus); + } + + mem = gen_rtx_MEM (DImode, pre); + insn = emit_insn (gen_rtx_SET (VOIDmode, operands[0], mem)); + + if (auto_inc_p (pre)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (pre, 0), REG_NOTES (insn)); + DONE; + } + [(set_attr "type" "load")]) + +(define_insn_and_split "*lod_di_pre_modify_reg_split" + [(set (match_operand:DI 0 "metag_register_op" "=r,r,r,r") + (mem:DI (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "+e,f,h,l") + (match_operand:SI 2 "metag_register_op" "e,f,h,l")))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_dup 2)))] + "TARGET_METAC_1_1 + && !reload_in_progress && !reload_completed" + "#" + "&& TRUE" + [(const_int 0)] + { + rtx plus = gen_rtx_PLUS (SImode, operands[1], operands[2]); + rtx pre_modify = gen_rtx_PRE_MODIFY (SImode, operands[1], plus); + rtx mem = gen_rtx_MEM (DImode, pre_modify); + rtx insn = emit_insn (gen_rtx_SET (VOIDmode, operands[0], mem)); + + if (auto_inc_p (pre_modify)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (pre_modify, 0), REG_NOTES (insn)); + DONE; + } + [(set_attr "type" "load")]) + +;; ----------------------------------------------------------------------------- + +;; ----------------------------------------------------------------------------- +;; | Recognising DI load post-inc/dec/modify | +;; ----------------------------------------------------------------------------- + +(define_insn_and_split "*lod_di_post_inc_dec_modify_disp_split" + [(set (match_operand:SI 0 "metag_regnofrm_op" "+efhl") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_di" "O8"))) + (set (match_operand:DI 2 "metag_register_op" "=r") + (mem:DI (match_dup 0)))] + "TARGET_METAC_1_1 + && !reload_in_progress && !reload_completed" + "#" + "&& TRUE" + [(const_int 0)] + { + rtx post, mem, insn; + + if (INTVAL (operands[1]) == GET_MODE_SIZE (DImode)) + post = gen_rtx_PRE_INC (SImode, operands[0]); + else if (INTVAL (operands[1]) == -GET_MODE_SIZE (DImode)) + post = gen_rtx_PRE_DEC (SImode, operands[0]); + else + { + rtx plus = gen_rtx_PLUS (SImode, operands[0], operands[1]); + + post = gen_rtx_POST_MODIFY (SImode, operands[0], plus); + } + + mem = gen_rtx_MEM (DImode, post); + insn = emit_insn (gen_rtx_SET (VOIDmode, operands[2], mem)); + + if (auto_inc_p (post)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (post, 0), REG_NOTES (insn)); + DONE; + } + [(set_attr "type" "load")]) + +(define_insn_and_split "*lod_di_post_modify_reg_split" + [(set (match_operand:SI 0 "metag_regnofrm_op" "+e,f,h,l") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_register_op" "e,f,h,l"))) + (set (match_operand:DI 2 "metag_register_op" "=r,r,r,r") + (mem:DI (match_dup 0)))] + "TARGET_METAC_1_1 + && !reload_in_progress && !reload_completed" + "#" + "&& TRUE" + [(const_int 0)] + { + rtx plus = gen_rtx_PLUS (SImode, operands[0], operands[1]); + rtx post_modify = gen_rtx_POST_MODIFY (SImode, operands[0], plus); + rtx mem = gen_rtx_MEM (DImode, post_modify); + rtx insn = emit_insn (gen_rtx_SET (VOIDmode, operands[2], mem)); + + if (auto_inc_p (post_modify)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (post_modify, 0), REG_NOTES (insn)); + DONE; + } + [(set_attr "type" "load")]) + +;; ----------------------------------------------------------------------------- + +;; ----------------------------------------------------------------------------- +;; | Recognising zero extend EXTHI load pre-inc/dec/modify | +;; ----------------------------------------------------------------------------- + +(define_insn_and_split "*lodz_hi_pre_inc_dec_modify_disp_split" + [(set (match_operand:HI 0 "metag_register_op" "=r") + (zero_extend:HI + (mem:EXTHI (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "+efhl") + (match_operand:SI 2 "metag_offset6_" ""))))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_dup 2)))] + "TARGET_METAC_1_1 + && !reload_in_progress && !reload_completed" + "#" + "&& TRUE" + [(const_int 0)] + { + rtx pre, mem, zextend, insn; + + if (INTVAL (operands[2]) == GET_MODE_SIZE (mode)) + pre = gen_rtx_PRE_INC (SImode, operands[1]); + else if (INTVAL (operands[2]) == -GET_MODE_SIZE (mode)) + pre = gen_rtx_PRE_DEC (SImode, operands[1]); + else + { + rtx plus = gen_rtx_PLUS (SImode, operands[1], operands[2]); + + pre = gen_rtx_PRE_MODIFY (SImode, operands[1], plus); + } + + mem = gen_rtx_MEM (mode, pre); + zextend = gen_rtx_ZERO_EXTEND (HImode, mem); + insn = emit_insn (gen_rtx_SET (VOIDmode, operands[0], zextend)); + + if (auto_inc_p (pre)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (pre, 0), REG_NOTES (insn)); + DONE; + } + [(set_attr "type" "fast")]) + +(define_insn_and_split "*lodz_hi_pre_modify_reg_split" + [(set (match_operand:HI 0 "metag_register_op" "=r,r,r,r") + (zero_extend:HI + (mem:EXTHI (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "+e,f,h,l") + (match_operand:SI 2 "metag_register_op" "e,f,h,l"))))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_dup 2)))] + "TARGET_METAC_1_1 + && !reload_in_progress && !reload_completed" + "#" + "&& TRUE" + [(const_int 0)] + { + rtx plus = gen_rtx_PLUS (SImode, operands[1], operands[2]); + rtx pre_modify = gen_rtx_PRE_MODIFY (SImode, operands[1], plus); + rtx mem = gen_rtx_MEM (mode, pre_modify); + rtx zextend = gen_rtx_ZERO_EXTEND (HImode, mem); + rtx insn = emit_insn (gen_rtx_SET (VOIDmode, operands[0], zextend)); + + if (auto_inc_p (pre_modify)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (pre_modify, 0), REG_NOTES (insn)); + DONE; + } + [(set_attr "type" "fast")]) + +;; ----------------------------------------------------------------------------- + +;; ----------------------------------------------------------------------------- +;; | Recognising zero extend EXTSI load pre-inc/dec/modify | +;; ----------------------------------------------------------------------------- + +(define_insn_and_split "*lodz_si_pre_inc_dec_modify_disp_split" + [(set (match_operand:SI 0 "metag_register_op" "=r") + (zero_extend:SI + (mem:EXTSI (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "+efhl") + (match_operand:SI 2 "metag_offset6_" ""))))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_dup 2)))] + "TARGET_METAC_1_1 + && !reload_in_progress && !reload_completed" + "#" + "&& TRUE" + [(const_int 0)] + { + rtx pre, mem, zextend, insn; + + if (INTVAL (operands[2]) == GET_MODE_SIZE (mode)) + pre = gen_rtx_PRE_INC (SImode, operands[1]); + else if (INTVAL (operands[2]) == -GET_MODE_SIZE (mode)) + pre = gen_rtx_PRE_DEC (SImode, operands[1]); + else + { + rtx plus = gen_rtx_PLUS (SImode, operands[1], operands[2]); + + pre = gen_rtx_PRE_MODIFY (SImode, operands[1], plus); + } + + mem = gen_rtx_MEM (mode, pre); + zextend = gen_rtx_ZERO_EXTEND (SImode, mem); + insn = emit_insn (gen_rtx_SET (VOIDmode, operands[0], zextend)); + + if (auto_inc_p (pre)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (pre, 0), REG_NOTES (insn)); + DONE; + } + [(set_attr "type" "fast")]) + +(define_insn_and_split "*lodz_si_pre_modify_reg_split" + [(set (match_operand:SI 0 "metag_register_op" "=r,r,r,r") + (zero_extend:SI + (mem:EXTSI (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "+e,f,h,l") + (match_operand:SI 2 "metag_register_op" "e,f,h,l"))))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_dup 2)))] + "TARGET_METAC_1_1 + && !reload_in_progress && !reload_completed" + "#" + "&& TRUE" + [(const_int 0)] + { + rtx plus = gen_rtx_PLUS (SImode, operands[1], operands[2]); + rtx pre_modify = gen_rtx_PRE_MODIFY (SImode, operands[1], plus); + rtx mem = gen_rtx_MEM (mode, pre_modify); + rtx zextend = gen_rtx_ZERO_EXTEND (SImode, mem); + rtx insn = emit_insn (gen_rtx_SET (VOIDmode, operands[0], zextend)); + + if (auto_inc_p (pre_modify)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (pre_modify, 0), REG_NOTES (insn)); + DONE; + } + [(set_attr "type" "fast")]) + +;; ----------------------------------------------------------------------------- + +;; ----------------------------------------------------------------------------- +;; | Recognising SF store pre-inc/dec/modify | +;; ----------------------------------------------------------------------------- + +(define_insn_and_split "*sto_sf_pre_inc_dec_modify_disp_split" + [(set (mem:SF + (plus:SI (match_operand:SI 0 "metag_regnofrm_op" "+efhl") + (match_operand:SI 1 "metag_offset6_sf" "O4"))) + (match_operand:SF 2 "metag_register_op" "r")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_dup 1)))] + "TARGET_METAC_1_1 + && !reload_in_progress && !reload_completed" + "#" + "&& TRUE" + [(const_int 0)] + { + rtx pre, mem, insn; + + if (INTVAL (operands[1]) == GET_MODE_SIZE (SFmode)) + pre = gen_rtx_PRE_INC (SImode, operands[0]); + else if (INTVAL (operands[1]) == -GET_MODE_SIZE (SFmode)) + pre = gen_rtx_PRE_DEC (SImode, operands[0]); + else + { + rtx plus = gen_rtx_PLUS (SImode, operands[0], operands[1]); + + pre = gen_rtx_PRE_MODIFY (SImode, operands[0], plus); + } + + mem = gen_rtx_MEM (SFmode, pre); + insn = emit_insn (gen_rtx_SET (VOIDmode, mem, operands[2])); + + if (auto_inc_p (pre)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (pre, 0), REG_NOTES (insn)); + DONE; + } + [(set_attr "type" "fast")]) + +(define_insn_and_split "*sto_sf_pre_modify_reg_split" + [(set (mem:SF + (plus:SI (match_operand:SI 0 "metag_regnofrm_op" "+%e,f,h,l") + (match_operand:SI 1 "metag_register_op" "e,f,h,l"))) + (match_operand:SF 2 "metag_register_op" "t,u,y,z")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_dup 1)))] + "TARGET_METAC_1_1 + && !reload_in_progress && !reload_completed" + "#" + "&& TRUE" + [(const_int 0)] + { + rtx plus = gen_rtx_PLUS (SImode, operands[0], operands[1]); + rtx pre_modify = gen_rtx_PRE_MODIFY (SImode, operands[0], plus); + rtx mem = gen_rtx_MEM (SFmode, pre_modify); + rtx insn = emit_insn (gen_rtx_SET (VOIDmode, mem, operands[2])); + + if (auto_inc_p (pre_modify)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (pre_modify, 0), REG_NOTES (insn)); + DONE; + } + [(set_attr "type" "fast")]) + +;; ----------------------------------------------------------------------------- + +;; ----------------------------------------------------------------------------- +;; | Recognising SF store post-inc/dec/modify | +;; ----------------------------------------------------------------------------- + +(define_insn_and_split "*sto_sf_post_inc_dec_modify_disp_split" + [(set (mem:SF (match_operand:SI 0 "metag_regnofrm_op" "+efhl")) + (match_operand:SF 1 "metag_register_op" "r")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_operand:SI 2 "metag_offset6_sf" "O4")))] + "TARGET_METAC_1_1 + && !reload_in_progress && !reload_completed" + "#" + "&& TRUE" + [(const_int 0)] + { + rtx post, mem, insn; + + if (INTVAL (operands[2]) == GET_MODE_SIZE (SFmode)) + post = gen_rtx_POST_INC (SImode, operands[0]); + else if (INTVAL (operands[2]) == -GET_MODE_SIZE (SFmode)) + post = gen_rtx_POST_DEC (SImode, operands[0]); + else + { + rtx plus = gen_rtx_PLUS (SImode, operands[0], operands[2]); + + post = gen_rtx_POST_MODIFY (SImode, operands[0], plus); + } + + mem = gen_rtx_MEM (SFmode, post); + insn = emit_insn (gen_rtx_SET (VOIDmode, mem, operands[1])); + + if (auto_inc_p (post)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (post, 0), REG_NOTES (insn)); + DONE; + } + [(set_attr "type" "fast")]) + +(define_insn_and_split "*sto_sf_post_modify_reg_split" + [(set (mem:SF (match_operand:SI 0 "metag_regnofrm_op" "+e,f,h,l")) + (match_operand:SF 1 "metag_register_op" "t,u,y,z")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_operand:SI 2 "metag_register_op" "e,f,h,l")))] + "TARGET_METAC_1_1 + && !reload_in_progress && !reload_completed" + "#" + "&& TRUE" + [(const_int 0)] + { + rtx plus = gen_rtx_PLUS (SImode, operands[0], operands[2]); + rtx post_modify = gen_rtx_POST_MODIFY (SImode, operands[0], plus); + rtx mem = gen_rtx_MEM (SFmode, post_modify); + rtx insn = emit_insn (gen_rtx_SET (VOIDmode, mem, operands[1])); + + if (auto_inc_p (post_modify)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (post_modify, 0), REG_NOTES (insn)); + DONE; + } + [(set_attr "type" "fast")]) + +;; ----------------------------------------------------------------------------- + +;; ----------------------------------------------------------------------------- +;; | Recognising SF load pre-inc/dec/modify | +;; ----------------------------------------------------------------------------- + +(define_insn_and_split "*lod_sf_pre_inc_dec_modify_disp_split" + [(set (match_operand:SF 0 "metag_register_op" "=r") + (mem:SF (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "+efhl") + (match_operand:SI 2 "metag_offset6_sf" "O4")))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_dup 2)))] + "TARGET_METAC_1_1 + && !reload_in_progress && !reload_completed" + "#" + "&& TRUE" + [(const_int 0)] + { + rtx pre, mem, insn; + + if (INTVAL (operands[2]) == GET_MODE_SIZE (SFmode)) + pre = gen_rtx_PRE_INC (SImode, operands[1]); + else if (INTVAL (operands[2]) == -GET_MODE_SIZE (SFmode)) + pre = gen_rtx_PRE_DEC (SImode, operands[1]); + else + { + rtx plus = gen_rtx_PLUS (SImode, operands[1], operands[2]); + + pre = gen_rtx_PRE_MODIFY (SImode, operands[1], plus); + } + + mem = gen_rtx_MEM (SFmode, pre); + insn = emit_insn (gen_rtx_SET (VOIDmode, operands[0], mem)); + + if (auto_inc_p (pre)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (pre, 0), REG_NOTES (insn)); + DONE; + } + [(set_attr "type" "fast")]) + +(define_insn_and_split "*lod_sf_pre_modify_reg_split" + [(set (match_operand:SF 0 "metag_register_op" "=r,r,r,r") + (mem:SF (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "+e,f,h,l") + (match_operand:SI 2 "metag_register_op" "e,f,h,l")))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_dup 2)))] + "TARGET_METAC_1_1 + && !reload_in_progress && !reload_completed" + "#" + "&& TRUE" + [(const_int 0)] + { + rtx plus = gen_rtx_PLUS (SImode, operands[1], operands[2]); + rtx pre_modify = gen_rtx_PRE_MODIFY (SImode, operands[1], plus); + rtx mem = gen_rtx_MEM (SFmode, pre_modify); + rtx insn = emit_insn (gen_rtx_SET (VOIDmode, operands[0], mem)); + + if (auto_inc_p (pre_modify)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (pre_modify, 0), REG_NOTES (insn)); + DONE; + } + [(set_attr "type" "fast")]) + +;; ----------------------------------------------------------------------------- +;; | Recognising DF load pre-inc/dec/modify | +;; ----------------------------------------------------------------------------- + +(define_insn_and_split "*lod_df_pre_inc_dec_modify_disp_split" + [(set (match_operand:DF 0 "metag_register_op" "=r") + (mem:DF (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "+efhl") + (match_operand:SI 2 "metag_offset6_df" "O8")))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_dup 2)))] + "TARGET_METAC_1_1 + && !reload_in_progress && !reload_completed" + "#" + "&& TRUE" + [(const_int 0)] + { + rtx pre, mem, insn; + + if (INTVAL (operands[2]) == GET_MODE_SIZE (DFmode)) + pre = gen_rtx_PRE_INC (SImode, operands[1]); + else if (INTVAL (operands[2]) == -GET_MODE_SIZE (DFmode)) + pre = gen_rtx_PRE_DEC (SImode, operands[1]); + else + { + rtx plus = gen_rtx_PLUS (SImode, operands[1], operands[2]); + + pre = gen_rtx_PRE_MODIFY (SImode, operands[1], plus); + } + + mem = gen_rtx_MEM (DFmode, pre); + insn = emit_insn (gen_rtx_SET (VOIDmode, operands[0], mem)); + + if (auto_inc_p (pre)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (pre, 0), REG_NOTES (insn)); + DONE; + } + [(set_attr "type" "load")]) + +(define_insn_and_split "*lod_df_pre_modify_reg_split" + [(set (match_operand:DF 0 "metag_register_op" "=r,r,r,r") + (mem:DF (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "+e,f,h,l") + (match_operand:SI 2 "metag_register_op" "e,f,h,l")))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_dup 2)))] + "TARGET_METAC_1_1 + && !reload_in_progress && !reload_completed" + "#" + "&& TRUE" + [(const_int 0)] + { + rtx plus = gen_rtx_PLUS (SImode, operands[1], operands[2]); + rtx pre_modify = gen_rtx_PRE_MODIFY (SImode, operands[1], plus); + rtx mem = gen_rtx_MEM (DFmode, pre_modify); + rtx insn = emit_insn (gen_rtx_SET (VOIDmode, operands[0], mem)); + + if (auto_inc_p (pre_modify)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (pre_modify, 0), REG_NOTES (insn)); + DONE; + } + [(set_attr "type" "load")]) + +;; ----------------------------------------------------------------------------- + +;; ----------------------------------------------------------------------------- +;; | Recognising DF load post-inc/dec/modify | +;; ----------------------------------------------------------------------------- + +(define_insn_and_split "*lod_df_post_inc_dec_modify_disp_split" + [(set (match_operand:SI 0 "metag_regnofrm_op" "+efhl") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_df" "O8"))) + (set (match_operand:DF 2 "metag_register_op" "=r") + (mem:DF (match_dup 0)))] + "TARGET_METAC_1_1 + && !reload_in_progress && !reload_completed" + "#" + "&& TRUE" + [(const_int 0)] + { + rtx post, mem, insn; + + if (INTVAL (operands[1]) == GET_MODE_SIZE (DFmode)) + post = gen_rtx_PRE_INC (SImode, operands[0]); + else if (INTVAL (operands[1]) == -GET_MODE_SIZE (DFmode)) + post = gen_rtx_PRE_DEC (SImode, operands[0]); + else + { + rtx plus = gen_rtx_PLUS (SImode, operands[0], operands[1]); + + post = gen_rtx_POST_MODIFY (SImode, operands[0], plus); + } + + mem = gen_rtx_MEM (DFmode, post); + insn = emit_insn (gen_rtx_SET (VOIDmode, operands[2], mem)); + + if (auto_inc_p (post)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (post, 0), REG_NOTES (insn)); + DONE; + } + [(set_attr "type" "load")]) + +(define_insn_and_split "*lod_df_post_modify_reg_split" + [(set (match_operand:SI 0 "metag_regnofrm_op" "+e,f,h,l") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_register_op" "e,f,h,l"))) + (set (match_operand:DF 2 "metag_register_op" "=r,r,r,r") + (mem:DF (match_dup 0)))] + "TARGET_METAC_1_1 + && !reload_in_progress && !reload_completed" + "#" + "&& TRUE" + [(const_int 0)] + { + rtx plus = gen_rtx_PLUS (SImode, operands[0], operands[1]); + rtx post_modify = gen_rtx_POST_MODIFY (SImode, operands[0], plus); + rtx mem = gen_rtx_MEM (DFmode, post_modify); + rtx insn = emit_insn (gen_rtx_SET (VOIDmode, operands[2], mem)); + + if (auto_inc_p (post_modify)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (post_modify, 0), REG_NOTES (insn)); + DONE; + } + [(set_attr "type" "load")]) + +;; ----------------------------------------------------------------------------- + +;; ----------------------------------------------------------------------------- +;; | Recognising DF store pre-inc/dec/modify | +;; ----------------------------------------------------------------------------- + +(define_insn_and_split "*sto_df_pre_inc_dec_modify_disp_split" + [(set (mem:DF (plus:SI (match_operand:SI 0 "metag_regnofrm_op" "+efhl") + (match_operand:SI 1 "metag_offset6_df" "O8"))) + (match_operand:DF 2 "metag_register_op" "r")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_dup 1)))] + "TARGET_METAC_1_1 + && !reload_in_progress && !reload_completed" + "#" + "&& TRUE" + [(const_int 0)] + { + rtx pre, mem, insn; + + if (INTVAL (operands[1]) == GET_MODE_SIZE (DFmode)) + pre = gen_rtx_PRE_INC (SImode, operands[0]); + else if (INTVAL (operands[1]) == -GET_MODE_SIZE (DFmode)) + pre = gen_rtx_PRE_DEC (SImode, operands[0]); + else + { + rtx plus = gen_rtx_PLUS (SImode, operands[0], operands[1]); + + pre = gen_rtx_PRE_MODIFY (SImode, operands[0], plus); + } + + mem = gen_rtx_MEM (DFmode, pre); + insn = emit_insn (gen_rtx_SET (VOIDmode, mem, operands[2])); + + if (auto_inc_p (pre)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (pre, 0), REG_NOTES (insn)); + DONE; + } + [(set_attr "type" "fast")]) + +(define_insn_and_split "*sto_df_pre_modify_reg_split" + [(set (mem:DF (plus:SI (match_operand:SI 0 "metag_regnofrm_op" "+e,f,h,l") + (match_operand:SI 1 "metag_register_op" "e,f,h,l"))) + (match_operand:DF 2 "metag_register_op" "a,a,d,d")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_dup 1)))] + "TARGET_METAC_1_1 + && !reload_in_progress && !reload_completed" + "#" + "&& TRUE" + [(const_int 0)] + { + rtx plus = gen_rtx_PLUS (SImode, operands[0], operands[1]); + rtx pre_modify = gen_rtx_PRE_MODIFY (SImode, operands[0], plus); + rtx mem = gen_rtx_MEM (DFmode, pre_modify); + rtx insn = emit_insn (gen_rtx_SET (VOIDmode, mem, operands[2])); + + if (auto_inc_p (pre_modify)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (pre_modify, 0), REG_NOTES (insn)); + DONE; + } + [(set_attr "type" "fast")]) + +;; ----------------------------------------------------------------------------- +;; | Recognising DF store post-inc/dec/modify | +;; ----------------------------------------------------------------------------- + +(define_insn_and_split "*sto_df_post_inc_dec_modify_disp_split" + [(set (mem:DF (match_operand:SI 0 "metag_regnofrm_op" "+efhl")) + (match_operand:DF 1 "metag_register_op" "r")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_operand:SI 2 "metag_offset6_df" "O8")))] + "TARGET_METAC_1_1 + && !reload_in_progress && !reload_completed" + "#" + "&& TRUE" + [(const_int 0)] + { + rtx post, mem, insn; + + if (INTVAL (operands[2]) == GET_MODE_SIZE (DFmode)) + post = gen_rtx_POST_INC (SImode, operands[0]); + else if (INTVAL (operands[2]) == -GET_MODE_SIZE (DFmode)) + post = gen_rtx_POST_DEC (SImode, operands[0]); + else + { + rtx plus = gen_rtx_PLUS (SImode, operands[0], operands[2]); + + post = gen_rtx_POST_MODIFY (SImode, operands[0], plus); + } + + mem = gen_rtx_MEM (DFmode, post); + insn = emit_insn (gen_rtx_SET (VOIDmode, mem, operands[1])); + + if (auto_inc_p (post)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (post, 0), REG_NOTES (insn)); + DONE; + } + [(set_attr "type" "fast")]) + +(define_insn_and_split "*sto_df_post_modify_reg_split" + [(set (mem:DF (match_operand:SI 0 "metag_regnofrm_op" "+e,f,h,l")) + (match_operand:DF 1 "metag_register_op" "a,a,d,d")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_operand:SI 2 "metag_register_op" "e,f,h,l")))] + + "TARGET_METAC_1_1 + && !reload_in_progress && !reload_completed" + "#" + "&& TRUE" + [(const_int 0)] + { + rtx plus = gen_rtx_PLUS (SImode, operands[0], operands[2]); + rtx post_modify = gen_rtx_POST_MODIFY (SImode, operands[0], plus); + rtx mem = gen_rtx_MEM (DFmode, post_modify); + rtx insn = emit_insn (gen_rtx_SET (VOIDmode, mem, operands[1])); + + if (auto_inc_p (post_modify)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (post_modify, 0), REG_NOTES (insn)); + DONE; + } + [(set_attr "type" "fast")]) diff -Nur gcc-4.2.4.orig/gcc/config/metag/constants.md gcc-4.2.4/gcc/config/metag/constants.md --- gcc-4.2.4.orig/gcc/config/metag/constants.md 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/constants.md 2015-07-03 18:46:05.745283542 -0500 @@ -0,0 +1,179 @@ +;; Constants definitions for META +;; Copyright (C) 2007 Imagination Technologies Ltd + +;; This file is part of GCC. + +;; GCC is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 3, or (at your option) any later +;; version. + +;; GCC is distributed in the hope that it will be useful, but WITHOUT ANY +;; WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; . + +;; UNSPEC +(define_constants + [(UNSPEC_GOTOFF 1) + (UNSPEC_GOT 2) + (UNSPEC_PLT 3) + (UNSPEC_PIC 4) + (UNSPEC_PIC_BASE 5) + + (UNSPEC_PROLOGUE_USE 6) + (UNSPEC_CONCAT 7) + (UNSPEC_SIBCALL 8) + (UNSPEC_SIBCALL_VALUE 9) + + (UNSPEC_RET_COND 10) + (UNSPEC_RET_COND_INVERTED 11) + + (UNSPEC_METAG_BSWAP 12) + (UNSPEC_METAG_BSWAPLL 13) + + (UNSPEC_MINIM_JUMP_TABLE 14) + + (UNSPEC_FIRST_TLS 15) + (UNSPEC_TLS 15) + (UNSPEC_TLSGD 16) + (UNSPEC_TLSLDM 17) + (UNSPEC_TLSLDO 18) + (UNSPEC_TLSIE 19) + (UNSPEC_TLSLE 20) + (UNSPEC_LAST_TLS 20)]) + + +;; UNSPEC VOLATILE +(define_constants + [(VUNSPEC_DCACHE_PRELOAD 1) + (VUNSPEC_DCACHE 2) + (VUNSPEC_DCACHE_REFRESH 3) + (VUNSPEC_BLOCKAGE 4) + (VUNSPEC_EPILOGUE 5) + (VUNSPEC_EH_RETURN 6) + (VUNSPEC_META2_CACHERD 7) + (VUNSPEC_META2_CACHERL 8) + (VUNSPEC_META2_CACHEWD 9) + (VUNSPEC_META2_CACHEWL 10) + (VUNSPEC_TTMOV 11) + (VUNSPEC_TTREC 12)]) + + +;; Register +(define_constants + [(D0Ar6_REG 2) + (D1Ar5_REG 3) + (D0Ar4_REG 4) + (D1Ar3_REG 5) + (D0Ar2_REG 6) + (D1Ar1_REG 7) + + (D0Re0_REG 0) + (D1Re0_REG 1) + (D0FrT_REG 8) + (D1RtP_REG 9) + + (FIRST_DATA_REG 0) + (D0_0_REG 0) + (D1_0_REG 1) + (D0_1_REG 2) + (D1_1_REG 3) + (D0_2_REG 4) + (D1_2_REG 5) + (D0_3_REG 6) + (D1_3_REG 7) + (D0_4_REG 8) + (D1_4_REG 9) + (D0_5_REG 10) + (D1_5_REG 11) + (D0_6_REG 12) + (D1_6_REG 13) + (D0_7_REG 14) + (D1_7_REG 15) + (FIRST_ECH_DATA_REG 16) + (D0_8_REG 16) + (D1_8_REG 17) + (D0_9_REG 18) + (D1_9_REG 19) + (D0_10_REG 20) + (D1_10_REG 21) + (D0_11_REG 22) + (D1_11_REG 23) + (D0_12_REG 24) + (D1_12_REG 25) + (D0_13_REG 26) + (D1_13_REG 27) + (D0_14_REG 28) + (D1_14_REG 29) + (D0_15_REG 30) + (D1_15_REG 31) + (LAST_DATA_REG 31) + + (A0StP_REG 32) + (A1GbP_REG 33) + (A0FrP_REG 34) + (A1LbP_REG 35) + + (PIC_REG 35) + + (FIRST_ADDR_REG 32) + (A0_0_REG 32) + (A1_0_REG 33) + (A0_1_REG 34) + (A1_1_REG 35) + (A0_2_REG 36) + (A1_2_REG 37) + (A0_3_REG 38) + (A1_3_REG 39) + (FIRST_ECH_ADDR_REG 40) + (A0_4_REG 40) + (A1_4_REG 41) + (A0_5_REG 42) + (A1_5_REG 43) + (A0_6_REG 44) + (A1_6_REG 45) + (A0_7_REG 46) + (A1_7_REG 47) + (LAST_ADDR_REG 47) + + (FRAME_REG 48) + (CC_REG 49) + (ARGP_REG 50) + (RAPF_REG 51) + (CPC0_REG 52) + (CPC1_REG 53) + (PC_REG 54) + (TXRPT_REG 55) + + (FIRST_FP_REG 56) + (FX_0_REG 56) + (FX_1_REG 57) + (FX_2_REG 58) + (FX_3_REG 59) + (FX_4_REG 60) + (FX_5_REG 61) + (FX_6_REG 62) + (FX_7_REG 63) + (FX_8_REG 64) + (FX_9_REG 65) + (FX_10_REG 66) + (FX_11_REG 67) + (FX_12_REG 68) + (FX_13_REG 69) + (FX_14_REG 70) + (FX_15_REG 71) + (LAST_FP_REG 71) + (TTREC_REG 72) + (TTRECL_REG 73) + (LAST_REG 73)]) + +;; Exception handling - dwarf2 call frame unwinder +(define_constants + [(EH_RETURN_FIRST_DATA_REG 2) + (EH_RETURN_LAST_DATA_REG 3) + (EH_RETURN_STACKADJ_REG 4)]) diff -Nur gcc-4.2.4.orig/gcc/config/metag/constraints.md gcc-4.2.4/gcc/config/metag/constraints.md --- gcc-4.2.4.orig/gcc/config/metag/constraints.md 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/constraints.md 2015-07-03 18:46:05.745283542 -0500 @@ -0,0 +1,319 @@ +;; Constraint definitions for META. +;; Copyright (C) 2007, 2010 Imagination Technologies Ltd + +;; This file is part of GCC. + +;; GCC is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 3, or (at your option) any later +;; version. + +;; GCC is distributed in the hope that it will be useful, but WITHOUT ANY +;; WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; . + +;; Register constraints + +(define_register_constraint "d" "D_REGS" + "data unit register") + +(define_register_constraint "e" "D0_REGS" + "data unit 0 register") + +(define_register_constraint "f" "D1_REGS" + "data unit 1 register") + +(define_register_constraint "a" "A_REGS" + "address unit register") + +(define_register_constraint "h" "A0_REGS" + "address unit 0 register") + +(define_register_constraint "l" "A1_REGS" + "address unit 1 register") + +(define_register_constraint "be" "Be_REGS" + "O2R register data unit 0") + +(define_register_constraint "bf" "Bf_REGS" + "O2R register data unit 1") + +(define_register_constraint "bd" "Bd_REGS" + "O2R register data unit") + +(define_register_constraint "bh" "Bh_REGS" + "O2R register address unit 0") + +(define_register_constraint "bl" "Bl_REGS" + "O2R register address unit 1") + +(define_register_constraint "ba" "Ba_REGS" + "O2R register address unit") + +(define_register_constraint "br" "Br_REGS" + "O2R register any unit") + +(define_register_constraint "t" "nD0_REGS" + "data unit 1, addr unit 0, addr unit 1 register") + +(define_register_constraint "u" "nD1_REGS" + "data unit 0, addr unit 0, addr unit 1 register") + +(define_register_constraint "y" "nA0_REGS" + "data unit 0, data unit 1, addr unit 1 register") + +(define_register_constraint "z" "nA1_REGS" + "data unit 0, addr unit 1, addr unit 0 register") + +(define_register_constraint "q" "nBU_REGS" + "not base unit register") + +(define_register_constraint "Wx" "Wx_REGS" + "control register i.e. TXRPT") + +(define_register_constraint "WQh" "WQh_REGS" + "A0 QuickRoT control registers A0.2 A0.3") + +(define_register_constraint "WQl" "WQl_REGS" + "A1 QuickRoT control registers A1.2 A1.3") + +(define_register_constraint "Ye" "Ye_REGS" + "data unit 0 register 12-bit offsetable") + +(define_register_constraint "Yf" "Yf_REGS" + "data unit 1 register 12-bit offsetable") + +(define_register_constraint "Yd" "Yd_REGS" + "data unit register 12-bit offsetable") + +(define_register_constraint "Yh" "Yh_REGS" + "addr unit 0 register 12-bit offsetable") + +(define_register_constraint "Yl" "Yl_REGS" + "addr unit 1 register 12-bit offsetable") + +(define_register_constraint "Ya" "Ya_REGS" + "addr unit register 12-bit offsetable") + +(define_register_constraint "Yr" "Yr_REGS" + "data/addr register 12-bit offsetable") + +(define_register_constraint "Yne" "nYe_REGS" + "...") + +(define_register_constraint "Ynf" "nYf_REGS" + "...") + +(define_register_constraint "Ynd" "nYd_REGS" + "...") + +(define_register_constraint "Ynh" "nYh_REGS" + "...") + +(define_register_constraint "Ynl" "nYl_REGS" + "...") + +(define_register_constraint "Yna" "nYa_REGS" + "...") + +(define_register_constraint "Ynr" "nYr_REGS" + "...") + +(define_register_constraint "ce" "metag_fpu_resources ? cD0_REGS : D0_REGS" + "data 0 or float unit register") + +(define_register_constraint "cf" "metag_fpu_resources ? cD1_REGS : D1_REGS" + "data 1, or float unit register") + +(define_register_constraint "cd" "metag_fpu_resources ? cD_REGS : D_REGS" + "data, or float unit register") + +(define_register_constraint "ch" "metag_fpu_resources ? cA0_REGS : A0_REGS" + "addr 0 or float unit register") + +(define_register_constraint "cl" "metag_fpu_resources ? cA1_REGS : A1_REGS" + "addr 1 or float unit register") + +(define_register_constraint "ca" "metag_fpu_resources ? cA_REGS : A_REGS" + "addr or float unit register") + +(define_register_constraint "cr" "metag_fpu_resources ? cDA_REGS : DA_REGS" + "data, addr or float unit register") + +(define_register_constraint "ct" "metag_fpu_resources ? cnD0_REGS : nD0_REGS" + "data unit 1, addr unit 0, addr unit 1 or float unit register") + +(define_register_constraint "cu" "metag_fpu_resources ? cnD1_REGS : nD1_REGS" + "data unit 0, addr unit 0, addr unit 1 or float unit register") + +(define_register_constraint "cy" "metag_fpu_resources ? cnA0_REGS : nA0_REGS" + "data unit 0, data unit 0, addr unit 1 or float unit register") + +(define_register_constraint "cz" "metag_fpu_resources ? cnA1_REGS : nA1_REGS" + "data unit 0, data unit 1, addr unit 0 or float unit register") + +(define_register_constraint "cx" "metag_fpu_resources ? FPC_REGS : NO_REGS" + "floating point register") + +(define_register_constraint "cp" "metag_fpu_resources ? FPP_REGS : NO_REGS" + "floating point register pair") + +;; Integer constraints + +(define_constraint "I" + "...." + (and (match_code "const_int") + (match_test "(ival >= -32768 && ival <= -256) || (ival >= 256 && ival <= 65535)"))) + +(define_constraint "J" + "...." + (and (match_code "const_int") + (match_test "(ival & 0x0000FFFF) == 0"))) + +(define_constraint "O0" + "...." + (and (match_code "const_int") + (match_test "(ival & 0xFFFF) == 0"))) + +(define_constraint "O3" + "...." + (and (match_code "const_int") + (match_test "((ival >> 16) & 0x0000FFFF) == 0"))) + +(define_constraint "K" + "..." + (and (match_code "const_int") + (match_test "0 <= ival && ival <= 255"))) + +(define_constraint "L" + "..." + (and (match_code "const_int") + (match_test "0 <= ival && ival <= 31"))) + +(define_constraint "M" + "..." + (and (match_code "const_int") + (match_test "((ival >> 16) & 0xFFFF) == 0x0000FFFF"))) + +(define_constraint "N" + "..." + (and (match_code "const_int") + (match_test "((ival & 0x0000FFFF) == 0x0000FFFF)"))) + +(define_constraint "O1" + "..." + (and (match_code "const_int") + (match_test "-32 <= ival && ival < 32"))) + +(define_constraint "O2" + "..." + (and (match_code "const_int") + (match_test "(-64 <= ival && ival < 64) && (ival & 1) == 0"))) + +(define_constraint "O4" + "..." + (and (match_code "const_int") + (match_test "(-128 <= ival && ival < 128) && (ival & 3) == 0"))) + +(define_constraint "O8" + "..." + (and (match_code "const_int") + (match_test "(-256 <= ival && ival < 256) && (ival & 7) == 0"))) + +(define_constraint "P" + "..." + (and (match_code "const_int") + (match_test "-255 <= ival && ival < 0"))) + +(define_constraint "vci" + "..." + (and (match_code "const_vector") + (match_test "GET_MODE_INNER (mode) == SImode"))) + +(define_constraint "vcf" + "..." + (and (match_code "const_vector") + (match_test "GET_MODE_INNER (mode) == SFmode"))) + +(define_constraint "vc5" + "..." + (and (match_code "const_vector") + (match_test "metag_vector_5bit_op (op, mode)"))) + +(define_constraint "v16" + "..." + (and (match_code "const_vector") + (match_test "metag_vector_16bit_op (op, mode)"))) + +;; Floating-point constraints + +(define_constraint "G" + "Floating-point zero." + (and (match_code "const_double") + (match_test "GET_MODE_CLASS (mode) == MODE_FLOAT && op == CONST0_RTX (mode)"))) + +(define_constraint "H" + "Floating-point one." + (and (match_code "const_double") + (match_test "GET_MODE_CLASS (mode) == MODE_FLOAT && op == CONST1_RTX (mode)"))) + +(define_constraint "ci" + "Floating-point immediates in half precision" + (and (match_code "const_double") + (match_test "GET_MODE_CLASS (mode) == MODE_FLOAT && metag_fphalf_imm_op (op, mode)"))) + +;; General constraints + +(define_constraint "Th" + "@internal" + (and (match_test "metag_mem_base_p (op, A0_REGS)") + (match_test "metag_legitimate_address_p (XEXP (op, 0), GET_MODE (op), true)"))) + +(define_constraint "Tl" + "@internal" + (and (match_test "metag_mem_base_p (op, A1_REGS)") + (match_test "metag_legitimate_address_p (XEXP (op, 0), GET_MODE (op), true)"))) + +(define_constraint "Te" + "@internal" + (and (match_test "metag_mem_base_p (op, D0_REGS)") + (match_test "metag_legitimate_address_p (XEXP (op, 0), GET_MODE (op), true)"))) + +(define_constraint "Tf" + "@internal" + (and (match_test "metag_mem_base_p (op, D1_REGS)") + (match_test "metag_legitimate_address_p (XEXP (op, 0), GET_MODE (op), true)"))) + +(define_constraint "Tr" + "@internal" + (and (match_test "metag_legitimate_address_p (XEXP (op, 0), GET_MODE (op), true)") + (not (match_test "GET_CODE (XEXP (op, 0)) == PLUS + && metag_regs_ok_for_base_offset_p (XEXP (XEXP (op, 0), 0), + XEXP (XEXP (op, 0), 1), + true)")))) + +(define_constraint "Z1" + "..." + (and (match_code "const_int") + (match_test "-2048 <= ival && ival < 2048"))) + +(define_constraint "Z2" + "..." + (and (match_code "const_int") + (match_test "-4096 <= ival && ival < 4096 && (ival & 1) == 0"))) + +(define_constraint "Z4" + "..." + (and (match_code "const_int") + (match_test "-8192 <= ival && ival < 8192 && (ival & 3) == 0"))) + +(define_constraint "Z8" + "..." + (and (match_code "const_int") + (match_test "-16384 <= ival && ival < 16384 && (ival & 7) == 0"))) + diff -Nur gcc-4.2.4.orig/gcc/config/metag/driver-metag.c gcc-4.2.4/gcc/config/metag/driver-metag.c --- gcc-4.2.4.orig/gcc/config/metag/driver-metag.c 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/driver-metag.c 2015-07-03 18:46:05.745283542 -0500 @@ -0,0 +1,276 @@ +/* Subroutines for the gcc driver. + Copyright (C) 2008 Imagination Technologies Ltd + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include +#include +#include "libiberty.h" +#include "filenames.h" + +const char *metag_reduce_options (int argc, const char **argv); +const char *metag_emb_asm_preprocessor (int argc, const char **argv); +const char *metag_emb_onlylast (int argc, const char **argv); +const char *metag_emb_change_suffix (int argc, const char **argv); + +/* This function will reduce all -mmetac options to remove all but + the last one with the %. + +;; See comment at the top of dsppeephole.md for information about +;; dual unit DSP support in the metag backend. + +;; The metag_dsp_peephole2_xxxxxx_convert functions used in these +;; rules promote operands to V2SI mode. They are all structured such +;; that they can be used for both flag setting and non-flag setting +;; rules. + +;; DSP Math peephole2s + +(define_peephole2 + [(set (match_operand:SI 0 "metag_datareg_op" "") + (3OPREG:SI (match_operand:SI 1 "metag_datareg_op" "") + (match_operand:SI 2 "metag_datareg_op" ""))) + (set (match_operand:SI 3 "metag_datareg_op" "") + (3OPREG:SI (match_operand:SI 4 "metag_datareg_op" "") + (match_operand:SI 5 "metag_datareg_op" "")))] + "TARGET_DSP + && metag_dsp_rrr_operands (operands, )" + [(set (match_dup 3) + (3OPREG:V2SI (match_dup 4) + (match_dup 5)))] + { + metag_dsp_peephole2_rrr_convert (operands); + }) + +(define_peephole2 + [(set (match_operand:SI 0 "metag_datareg_op" "") + (3OPIMM16:SI (match_dup 0) + (match_operand:SI 1 "metag_16bit_op" ""))) + (set (match_operand:SI 2 "metag_datareg_op" "") + (3OPIMM16:SI (match_dup 2) + (match_dup 1)))] + "TARGET_DSP + && metag_dsp_ri16_operands (operands) + " + [(set (match_dup 2) + (3OPIMM16:V2SI (match_dup 2) + (match_dup 3)))] + { + metag_dsp_peephole2_ri16_convert (operands); + }) + +(define_peephole2 + [(set (match_operand:SI 0 "metag_datareg_op" "") + (3OPIMM5:SI (match_operand:SI 1 "metag_datareg_op" "") + (match_operand:SI 2 "metag_5bit_op" ""))) + (set (match_operand:SI 3 "metag_datareg_op" "") + (3OPIMM5:SI (match_operand:SI 4 "metag_datareg_op" "") + (match_dup 2)))] + "TARGET_DSP + && metag_dsp_rri5_operands (operands) + " + [(set (match_dup 3) + (3OPIMM5:V2SI (match_dup 4) + (match_dup 5)))] + { + metag_dsp_peephole2_rri5_convert (operands); + }) + +;; DSP MUL peephole + +;; MUL is not supported due to default DSP arithmetic mode being 16x16 + +;; DSP MIN/MAX + +(define_peephole2 + [(parallel + [(set (match_operand:SI 0 "metag_datareg_op" "") + (MINMAX:SI (match_operand:SI 1 "metag_datareg_op" "") + (match_operand:SI 2 "metag_datareg_op" ""))) + (clobber (reg:CC CC_REG))]) + (parallel + [(set (match_operand:SI 3 "metag_datareg_op" "") + (MINMAX:SI (match_operand:SI 4 "metag_datareg_op" "") + (match_operand:SI 5 "metag_datareg_op" ""))) + (clobber (reg:CC CC_REG))])] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_rrr_operands (operands, true)" + [(parallel + [(set (match_dup 3) + (MINMAX:V2SI (match_dup 4) + (match_dup 5))) + (clobber (reg:CC CC_REG))])] + { + metag_dsp_peephole2_rrr_convert (operands); + }) + +;; DSP ABS peephole + +(define_peephole2 + [(parallel + [(set (match_operand:SI 0 "metag_datareg_op" "") + (abs:SI (match_operand:SI 1 "metag_datareg_op" ""))) + (clobber (reg:CC CC_REG))]) + (parallel + [(set (match_operand:SI 2 "metag_datareg_op" "") + (abs:SI (match_operand:SI 3 "metag_datareg_op" ""))) + (clobber (reg:CC CC_REG))])] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_rr_operands (operands)" + [(parallel + [(set (match_dup 2) + (abs:V2SI (match_dup 3))) + (clobber (reg:CC CC_REG))])] + { + metag_dsp_peephole2_rr_convert (operands); + }) + +;; DSP MOV peephole + +(define_peephole2 + [(set (match_operand:SI 0 "metag_datareg_op" "") + (match_operand:SI 1 "metag_datareg_op" "")) + (set (match_operand:SI 2 "metag_datareg_op" "") + (match_operand:SI 3 "metag_datareg_op" ""))] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_rr_operands (operands)" + [(set (match_dup 2) + (match_dup 3))] + { + metag_dsp_peephole2_rr_convert (operands); + }) + +;; DSP Math with flags peepholes + +(define_peephole2 + [(parallel [(set (reg:CC_NOOV CC_REG) + (compare:CC_NOOV + (3OPREG:SI (match_operand:SI 1 "metag_datareg_op" "") + (match_operand:SI 2 "metag_datareg_op" "")) + (const_int 0))) + (set (match_operand:SI 0 "metag_datareg_op" "") + (3OPREG:SI (match_dup 1) + (match_dup 2)))]) + (set (match_operand:SI 3 "metag_datareg_op" "") + (3OPREG:SI (match_operand:SI 4 "metag_datareg_op" "") + (match_operand:SI 5 "metag_datareg_op" "")))] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_rrr_operands (operands, )" + [(parallel [(set (reg:CC_NOOV CC_REG) + (compare:CC_NOOV + (3OPREG:SI (match_dup 1) + (match_dup 2)) + (const_int 0))) + (set (match_dup 3) + (3OPREG:V2SI (match_dup 4) + (match_dup 5)))])] + { + metag_dsp_peephole2_rrr_convert (operands); + }) + +(define_peephole2 + [(set (reg:CC_NOOV CC_REG) + (compare:CC_NOOV + (3OPREG:SI (match_operand:SI 1 "metag_datareg_op" "") + (match_operand:SI 2 "metag_datareg_op" "")) + (const_int 0))) + (set (match_operand:SI 0 "metag_datareg_op" "") + (3OPREG:SI (match_dup 1) + (match_dup 2))) + (set (match_operand:SI 3 "metag_datareg_op" "") + (3OPREG:SI (match_operand:SI 4 "metag_datareg_op" "") + (match_operand:SI 5 "metag_datareg_op" "")))] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_rrr_operands (operands, )" + [(parallel [(set (reg:CC_NOOV CC_REG) + (compare:CC_NOOV + (3OPREG:SI (match_dup 1) + (match_dup 2)) + (const_int 0))) + (set (match_dup 3) + (3OPREG:V2SI (match_dup 4) + (match_dup 5)))])] + { + metag_dsp_peephole2_rrr_convert (operands); + }) + +(define_peephole2 + [(parallel [(set (reg:CC_NOOV CC_REG) + (compare:CC_NOOV + (3OPIMM16:SI (match_operand:SI 0 "metag_datareg_op" "") + (match_operand:SI 1 "metag_16bit_op" "")) + (const_int 0))) + (set (match_dup 0) + (3OPIMM16:SI (match_dup 0) + (match_dup 1)))]) + (set (match_operand:SI 2 "metag_datareg_op" "") + (3OPIMM16:SI (match_dup 2) + (match_dup 1)))] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_ri16_operands (operands) + " + [(parallel [(set (reg:CC_NOOV CC_REG) + (compare:CC_NOOV + (3OPIMM16:SI (match_dup 0) + (match_dup 1)) + (const_int 0))) + (set (match_dup 2) + (3OPIMM16:V2SI (match_dup 2) + (match_dup 3)))])] + { + metag_dsp_peephole2_ri16_convert (operands); + }) + +(define_peephole2 + [(parallel [(set (reg:CC_NOOV CC_REG) + (compare:CC_NOOV + (3OPIMM5:SI (match_operand:SI 1 "metag_datareg_op" "") + (match_operand:SI 2 "metag_5bit_op" "")) + (const_int 0))) + (set (match_operand:SI 0 "metag_datareg_op" "") + (3OPIMM5:SI (match_dup 1) + (match_dup 2)))]) + (set (match_operand:SI 3 "metag_datareg_op" "") + (3OPIMM5:SI (match_operand:SI 4 "metag_datareg_op" "") + (match_dup 2)))] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_rri5_operands (operands) + " + [(parallel [(set (reg:CC_NOOV CC_REG) + (compare:CC_NOOV + (3OPIMM5:SI (match_dup 1) + (match_dup 2)) + (const_int 0))) + (set (match_dup 3) + (3OPIMM5:V2SI (match_dup 4) + (match_dup 5)))])] + { + metag_dsp_peephole2_rri5_convert (operands); + }) + +(define_peephole2 + [(set (reg:CC_NOOV CC_REG) + (compare:CC_NOOV + (3OPIMM16:SI (match_operand:SI 0 "metag_datareg_op" "") + (match_operand:SI 1 "metag_16bit_op" "")) + (const_int 0))) + (set (match_dup 0) + (3OPIMM16:SI (match_dup 0) + (match_dup 1))) + (set (match_operand:SI 2 "metag_datareg_op" "") + (3OPIMM16:SI (match_dup 2) + (match_dup 1)))] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_ri16_operands (operands) + " + [(parallel [(set (reg:CC_NOOV CC_REG) + (compare:CC_NOOV + (3OPIMM16:SI (match_dup 0) + (match_dup 1)) + (const_int 0))) + (set (match_dup 2) + (3OPIMM16:V2SI (match_dup 2) + (match_dup 3)))])] + { + metag_dsp_peephole2_ri16_convert (operands); + }) + +(define_peephole2 + [(set (reg:CC_NOOV CC_REG) + (compare:CC_NOOV + (3OPIMM5:SI (match_operand:SI 1 "metag_datareg_op" "") + (match_operand:SI 2 "metag_5bit_op" "")) + (const_int 0))) + (set (match_operand:SI 0 "metag_datareg_op" "") + (3OPIMM5:SI (match_dup 1) + (match_dup 2))) + (set (match_operand:SI 3 "metag_datareg_op" "") + (3OPIMM5:SI (match_operand:SI 4 "metag_datareg_op" "") + (match_dup 2)))] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_rri5_operands (operands) + " + [(parallel [(set (reg:CC_NOOV CC_REG) + (compare:CC_NOOV + (3OPIMM5:SI (match_dup 1) + (match_dup 2)) + (const_int 0))) + (set (match_dup 3) + (3OPIMM5:V2SI (match_dup 4) + (match_dup 5)))])] + { + metag_dsp_peephole2_rri5_convert (operands); + }) + +;; DSP OP + MOV + +(define_peephole2 + [(set (match_operand:SI 0 "metag_datareg_op" "") + (3OPREG:SI (match_operand:SI 1 "metag_datareg_op" "") + (match_operand:SI 2 "metag_datareg_op" ""))) + (set (match_operand:SI 3 "metag_datareg_op" "") + (3OPREG:SI (match_operand:SI 4 "metag_datareg_op" "") + (match_operand:SI 5 "metag_datareg_op" ""))) + (set (match_operand:SI 6 "metag_datareg_op" "") + (match_dup 0)) + (set (match_operand:SI 7 "metag_datareg_op" "") + (match_dup 3))] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_rrr_mov_operands (operands, ) + && peep2_reg_dead_p (3, operands[0]) + && peep2_reg_dead_p (4, operands[3])" + [(set (match_dup 6) + (3OPREG:V2SI (match_dup 1) + (match_dup 2)))] + { + metag_dsp_peephole2_rrr_mov_convert (operands); + }) + +;; DSP MUL + MOV + +;; MUL is not supported due to default dsp arithmetic mode being 16x16 + +;; DSP ABS + MOV + +(define_peephole2 + [(parallel + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "") + (abs:SI (match_operand:SI 1 "metag_datareg_op" ""))) + (clobber (reg:CC CC_REG))]) + (set (match_operand:SI 4 "metag_datareg_op" "") + (match_dup 0)) + (parallel + [(set (match_operand:SI 2 "metag_reg_nofloat_op" "") + (abs:SI (match_operand:SI 3 "metag_datareg_op" ""))) + (clobber (reg:CC CC_REG))]) + (set (match_operand:SI 5 "metag_datareg_op" "") + (match_dup 2))] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_rr_rr_mov_operands (operands) + && peep2_reg_dead_p (2, operands[0]) + && peep2_reg_dead_p (4, operands[2])" + [(parallel + [(set (match_dup 4) + (abs:SI (match_dup 1))) + (clobber (reg:CC CC_REG))])] + { + metag_dsp_peephole2_rr_mov_convert (operands); + }) + +;; DSP MIN/MAX + MOV + +(define_peephole2 + [(parallel + [(set (match_operand:SI 0 "metag_datareg_op" "") + (MINMAX:SI (match_operand:SI 1 "metag_datareg_op" "") + (match_operand:SI 2 "metag_datareg_op" ""))) + (clobber (reg:CC CC_REG))]) + (set (match_operand:SI 6 "metag_datareg_op" "") + (match_dup 0)) + (parallel + [(set (match_operand:SI 3 "metag_datareg_op" "") + (MINMAX:SI (match_operand:SI 4 "metag_datareg_op" "") + (match_operand:SI 5 "metag_datareg_op" ""))) + (clobber (reg:CC CC_REG))]) + (set (match_operand:SI 7 "metag_datareg_op" "") + (match_dup 3))] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_rrr_mov_operands (operands, ) + && peep2_reg_dead_p (2, operands[0]) + && peep2_reg_dead_p (4, operands[3])" + [(parallel + [(set (match_dup 6) + (MINMAX:SI (match_dup 1) + (match_dup 2))) + (clobber (reg:CC CC_REG))])] + { + metag_dsp_peephole2_rrr_mov_convert (operands); + }) + +;; END DSP Peephole2s + diff -Nur gcc-4.2.4.orig/gcc/config/metag/dsppeephole.md gcc-4.2.4/gcc/config/metag/dsppeephole.md --- gcc-4.2.4.orig/gcc/config/metag/dsppeephole.md 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/dsppeephole.md 2015-07-03 18:46:05.745283542 -0500 @@ -0,0 +1,434 @@ +;; Machine description for GNU compiler, +;; Imagination Technologies Meta version. +;; Copyright (C) 2008 +;; Imagination Technologies Ltd + +;; This file is part of GCC. + +;; GCC is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 3, or (at your option) any later +;; version. + +;; GCC is distributed in the hope that it will be useful, but WITHOUT ANY +;; WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; . + +;; READ THIS... + +;; DSP peephole transformations are mostly templated. There are 3 templates: +;; 1) 3OPREG - This is the set of operations that have 3 register operands +;; 2 input and 1 output. +;; 2) 3OPIMM16 - This is the set of operations that have 3 operands +;; 1 register input, 1 16 bit immediate input, 1 register output +;; 2) 3OPIMM5 - This is the set of operations that have 3 operands +;; 1 register input, 1 5 bit immediate input, 1 register output + +;; Special code attributes: + +;; +;; Indicates if an insn code has commutative input operands. +;; +;; Special immediate conditions for dual unit operations. +;; +;; The name of the insn suitable for use in rtl generation. +;; +;; The assembler nmemonic for the given insn code. + +;; Dual unit conditions: + +;; The conditions for all DSP transformations are checked in the functions +;; called metag_dsp_xxxxxxx_operands. These functions check that the operands +;; in one instruction are an exact mirror of the operands of another +;; instruction. +;; For example metag_dsp_rrr_operands returns true for the following 2 +;; instructions regardless of which order they appear (D1 or D0 first): +;; +;; (set (reg D0Re0 [D0.0]) +;; (operation (reg D0Ar6 [D0.1]) +;; (reg D0Ar4 (D0.2]))) +;; (set (reg D1Re0 [D1.0]) +;; (operation (reg D1Ar5 [D1.1]) +;; (reg D1Ar3 (D1.2]))) + +(define_peephole + [(set (match_operand:SI 0 "metag_datareg_op" "") + (3OPREG:SI (match_operand:SI 1 "metag_datareg_op" "") + (match_operand:SI 2 "metag_datareg_op" ""))) + (set (match_operand:SI 3 "metag_datareg_op" "") + (3OPREG:SI (match_operand:SI 4 "metag_datareg_op" "") + (match_operand:SI 5 "metag_datareg_op" "")))] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_rrr_operands (operands, )" + "DL\\t\\t%0, %1, %2\\t%@ (*\\t%3, %4, %5)" + [(set_attr "type" "fast")]) + +(define_peephole + [(set (match_operand:SI 3 "metag_datareg_op" "") + (3OPREG:SI (match_operand:SI 4 "metag_datareg_op" "") + (match_operand:SI 5 "metag_datareg_op" ""))) + (set (match_operand:SI 0 "metag_datareg_op" "") + (3OPREG:SI (match_operand:SI 1 "metag_datareg_op" "") + (match_operand:SI 2 "metag_datareg_op" "")))] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_rrr_operands (operands, )" + "DL\\t\\t%3, %4, %5\\t%@ (*\\t%0, %1, %2)" + [(set_attr "type" "fast")]) + +(define_peephole + [(set (match_operand:SI 0 "metag_datareg_op" "") + (3OPIMM16:SI (match_dup 0) + (match_operand:SI 1 "metag_16bit_op" ""))) + (set (match_operand:SI 2 "metag_datareg_op" "") + (3OPIMM16:SI (match_dup 2) + (match_dup 1)))] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_ri16_operands (operands) + " + "DL\\t\\t%0, %0, %1\\t%@ (*\\t%2, %2, %1)" + [(set_attr "type" "fast")]) + +(define_peephole + [(set (match_operand:SI 0 "metag_datareg_op" "") + (3OPIMM5:SI (match_operand:SI 1 "metag_datareg_op" "") + (match_operand:SI 2 "metag_5bit_op" ""))) + (set (match_operand:SI 3 "metag_datareg_op" "") + (3OPIMM5:SI (match_operand:SI 4 "metag_datareg_op" "") + (match_dup 2)))] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_rri5_operands (operands) + " + "DL\\t\\t%0, %1, %2\\t%@ (*\\t%3, %4, %2)" + [(set_attr "type" "fast")]) + +;; DSP MIN/MAX + +(define_peephole + [(parallel + [(set (match_operand:SI 0 "metag_datareg_op" "") + (MINMAX:SI (match_operand:SI 1 "metag_datareg_op" "") + (match_operand:SI 2 "metag_datareg_op" ""))) + (clobber (reg:CC CC_REG))]) + (parallel + [(set (match_operand:SI 3 "metag_datareg_op" "") + (MINMAX:SI (match_operand:SI 4 "metag_datareg_op" "") + (match_operand:SI 5 "metag_datareg_op" ""))) + (clobber (reg:CC CC_REG))])] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_rrr_operands (operands, true)" + "DL\\t\\t%0, %1, %2\\t%@ (*\\t%3, %4, %5)" + [(set_attr "type" "fast") + (set_attr "ccstate" "ccx")]) + +;; DSP ABS peephole + +(define_peephole + [(parallel + [(set (match_operand:SI 0 "metag_datareg_op" "") + (abs:SI (match_operand:SI 1 "metag_datareg_op" ""))) + (clobber (reg:CC CC_REG))]) + (parallel + [(set (match_operand:SI 2 "metag_datareg_op" "") + (abs:SI (match_operand:SI 3 "metag_datareg_op" ""))) + (clobber (reg:CC CC_REG))])] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_rr_operands (operands)" + "DL\\tABS\\t%0, %1\\t%@ *ABS\\t%2, %3)" + [(set_attr "type" "fast") + (set_attr "ccstate" "ccx")]) + +;; DSP MOV peephole + +(define_peephole + [(set (match_operand:SI 0 "metag_datareg_op" "") + (match_operand:SI 1 "metag_datareg_op" "")) + (set (match_operand:SI 2 "metag_datareg_op" "") + (match_operand:SI 3 "metag_datareg_op" ""))] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_rr_operands (operands)" + "DL\\tMOV\\t%0, %1\\t%@ (*MOV\\t%2, %3)" + [(set_attr "type" "fast")]) + +;; DSP Math with flags peepholes + +(define_peephole + [(parallel [(set (reg:CC_NOOV CC_REG) + (compare:CC_NOOV + (3OPREG:SI (match_operand:SI 1 "metag_datareg_op" "") + (match_operand:SI 2 "metag_datareg_op" "")) + (const_int 0))) + (set (match_operand:SI 0 "metag_datareg_op" "") + (3OPREG:SI (match_dup 1) + (match_dup 2)))]) + (set (match_operand:SI 3 "metag_datareg_op" "") + (3OPREG:SI (match_operand:SI 4 "metag_datareg_op" "") + (match_operand:SI 5 "metag_datareg_op" "")))] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_rrr_operands (operands, )" + "DL\\tS\\t%0, %1, %2\\t%@ (*S\\t%3, %4, %5)" + [(set_attr "type" "fast") + (set_attr "ccstate" "set")]) + +(define_peephole + [(set (match_operand:SI 3 "metag_datareg_op" "") + (3OPREG:SI (match_operand:SI 4 "metag_datareg_op" "") + (match_operand:SI 5 "metag_datareg_op" ""))) + (parallel [(set (reg:CC_NOOV CC_REG) + (compare:CC_NOOV + (3OPREG:SI (match_operand:SI 1 "metag_datareg_op" "") + (match_operand:SI 2 "metag_datareg_op" "")) + (const_int 0))) + (set (match_operand:SI 0 "metag_datareg_op" "") + (3OPREG:SI (match_dup 1) + (match_dup 2)))])] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_rrr_operands (operands, )" + "DL\\tS\\t%0, %1, %2\\t%@ (*S\\t%3, %4, %5)" + [(set_attr "type" "fast") + (set_attr "ccstate" "set")]) + +(define_peephole + [(set (reg:CC_NOOV CC_REG) + (compare:CC_NOOV + (3OPREG:SI (match_operand:SI 4 "metag_datareg_op" "") + (match_operand:SI 5 "metag_datareg_op" "")) + (const_int 0))) + (set (match_operand:SI 0 "metag_datareg_op" "") + (3OPREG:SI (match_operand:SI 1 "metag_datareg_op" "") + (match_operand:SI 2 "metag_datareg_op" ""))) + (set (match_operand:SI 3 "metag_datareg_op" "") + (3OPREG:SI (match_dup 4) + (match_dup 5)))] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_rrr_operands (operands, )" + "DL\\tS\\t%3, %4, %5\\t%@ (*S\\t%0, %1, %2)" + [(set_attr "type" "fast") + (set_attr "ccstate" "set")]) + +(define_peephole + [(parallel [(set (reg:CC_NOOV CC_REG) + (compare:CC_NOOV + (3OPIMM16:SI (match_operand:SI 0 "metag_datareg_op" "") + (match_operand:SI 1 "metag_16bit_op" "")) + (const_int 0))) + (set (match_dup 0) + (3OPIMM16:SI (match_dup 0) + (match_dup 1)))]) + (set (match_operand:SI 2 "metag_datareg_op" "") + (3OPIMM16:SI (match_dup 2) + (match_dup 1)))] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_ri16_operands (operands) + " + "DL\\tS\\t%0, %0, %1\\t%@ (*S\\t%2, %2, %1)" + [(set_attr "type" "fast") + (set_attr "ccstate" "set")]) + +(define_peephole + [(parallel [(set (reg:CC_NOOV CC_REG) + (compare:CC_NOOV + (3OPIMM5:SI (match_operand:SI 1 "metag_datareg_op" "") + (match_operand:SI 2 "metag_5bit_op" "")) + (const_int 0))) + (set (match_operand:SI 0 "metag_datareg_op" "") + (3OPIMM5:SI (match_dup 1) + (match_dup 2)))]) + (set (match_operand:SI 3 "metag_datareg_op" "") + (3OPIMM5:SI (match_operand:SI 4 "metag_datareg_op" "") + (match_dup 2)))] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_rri5_operands (operands) + " + "DL\\tS\\t%0, %1, %2\\t%@ (*S\\t%3, %4, %2)" + [(set_attr "type" "fast") + (set_attr "ccstate" "set")]) + +(define_peephole + [(set (match_operand:SI 2 "metag_datareg_op" "") + (3OPIMM16:SI (match_dup 2) + (match_operand:SI 1 "metag_16bit_op" ""))) + (parallel [(set (reg:CC_NOOV CC_REG) + (compare:CC_NOOV + (3OPIMM16:SI (match_operand:SI 0 "metag_datareg_op" "") + (match_dup 1)) + (const_int 0))) + (set (match_dup 0) + (3OPIMM16:SI (match_dup 0) + (match_dup 1)))])] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_ri16_operands (operands) + " + "DL\\tS\\t%0, %0, %1\\t%@ (*S\\t%2, %2, %1)" + [(set_attr "type" "fast") + (set_attr "ccstate" "set")]) + +(define_peephole + [(set (match_operand:SI 3 "metag_datareg_op" "") + (3OPIMM5:SI (match_operand:SI 4 "metag_datareg_op" "") + (match_operand:SI 2 "metag_5bit_op" ""))) + (parallel [(set (reg:CC_NOOV CC_REG) + (compare:CC_NOOV + (3OPIMM5:SI (match_operand:SI 1 "metag_datareg_op" "") + (match_dup 2)) + (const_int 0))) + (set (match_operand:SI 0 "metag_datareg_op" "") + (3OPIMM5:SI (match_dup 1) + (match_dup 2)))])] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_rri5_operands (operands) + " + "DL\\tS\\t%0, %1, %2\\t%@ (*S\\t%3, %4, %2)" + [(set_attr "type" "fast") + (set_attr "ccstate" "set")]) + +(define_peephole + [(set (reg:CC_NOOV CC_REG) + (compare:CC_NOOV + (3OPIMM16:SI (match_operand:SI 2 "metag_datareg_op" "") + (match_operand:SI 1 "metag_16bit_op" "")) + (const_int 0))) + (set (match_operand:SI 0 "metag_datareg_op" "") + (3OPIMM16:SI (match_dup 0) + (match_dup 1))) + (set (match_dup 2) + (3OPIMM16:SI (match_dup 2) + (match_dup 1)))] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_ri16_operands (operands) + " + "DL\\tS\\t%2, %2, %1\\t%@ (*S\\t%0, %0, %1)" + [(set_attr "type" "fast") + (set_attr "ccstate" "set")]) + +(define_peephole + [(set (reg:CC_NOOV CC_REG) + (compare:CC_NOOV + (3OPIMM5:SI (match_operand:SI 4 "metag_datareg_op" "") + (match_operand:SI 2 "metag_5bit_op" "")) + (const_int 0))) + (set (match_operand:SI 0 "metag_datareg_op" "") + (3OPIMM5:SI (match_operand:SI 1 "metag_datareg_op" "") + (match_dup 2))) + (set (match_operand:SI 3 "metag_datareg_op" "") + (3OPIMM5:SI (match_dup 4) + (match_dup 2)))] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_rri5_operands (operands) + " + "DL\\tS\\t%3, %4, %2\\t%@ (*S\\t%0, %1, %2)" + [(set_attr "type" "fast") + (set_attr "ccstate" "set")]) + +(define_peephole + [(set (reg:CC_NOOV CC_REG) + (compare:CC_NOOV + (3OPIMM16:SI (match_operand:SI 2 "metag_datareg_op" "") + (match_operand:SI 1 "metag_16bit_op" "")) + (const_int 0))) + (set (match_dup 2) + (3OPIMM16:SI (match_dup 2) + (match_dup 1))) + (set (match_operand:SI 0 "metag_datareg_op" "") + (3OPIMM16:SI (match_dup 0) + (match_dup 1)))] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_ri16_operands (operands) + " + "DL\\tS\\t%2, %2, %1\\t%@ (*S\\t%0, %0, %1)" + [(set_attr "type" "fast") + (set_attr "ccstate" "set")]) + +(define_peephole + [(set (reg:CC_NOOV CC_REG) + (compare:CC_NOOV + (3OPIMM5:SI (match_operand:SI 4 "metag_datareg_op" "") + (match_operand:SI 2 "metag_5bit_op" "")) + (const_int 0))) + (set (match_operand:SI 3 "metag_datareg_op" "") + (3OPIMM5:SI (match_dup 4) + (match_dup 2))) + (set (match_operand:SI 0 "metag_datareg_op" "") + (3OPIMM5:SI (match_operand:SI 1 "metag_datareg_op" "") + (match_dup 2)))] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_rri5_operands (operands) + " + "DL\\tS\\t%3, %4, %2\\t%@ (*S\\t%0, %1, %2)" + [(set_attr "type" "fast") + (set_attr "ccstate" "set")]) + +;; DSP OP + MOV + +(define_peephole + [(set (match_operand:SI 0 "metag_datareg_op" "") + (3OPREG:SI (match_operand:SI 1 "metag_datareg_op" "") + (match_operand:SI 2 "metag_datareg_op" ""))) + (set (match_operand:SI 3 "metag_datareg_op" "") + (3OPREG:SI (match_operand:SI 4 "metag_datareg_op" "") + (match_operand:SI 5 "metag_datareg_op" ""))) + (set (match_operand:SI 6 "metag_datareg_op" "") + (match_dup 0)) + (set (match_operand:SI 7 "metag_datareg_op" "") + (match_dup 3))] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_rrr_mov_operands (operands, ) + && dead_or_set_p (PREV_INSN (insn), operands[0]) + && dead_or_set_p (insn, operands[3])" + "DL\\t\\t%6, %1, %2\\t%@ (*\\t%7, %4, %5)" + [(set_attr "type" "fast")]) + +;; DSP ABS + MOV + +(define_peephole + [(parallel + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "") + (abs:SI (match_operand:SI 1 "metag_datareg_op" ""))) + (clobber (reg:CC CC_REG))]) + (set (match_operand:SI 4 "metag_datareg_op" "") + (match_dup 0)) + (parallel + [(set (match_operand:SI 2 "metag_reg_nofloat_op" "") + (abs:SI (match_operand:SI 3 "metag_datareg_op" ""))) + (clobber (reg:CC CC_REG))]) + (set (match_operand:SI 5 "metag_datareg_op" "") + (match_dup 2))] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_rr_rr_mov_operands (operands) + && dead_or_set_p (PREV_INSN (PREV_INSN (insn)), operands[0]) + && dead_or_set_p (insn, operands[2])" + "DL\\tABS\\t%4, %1\\t%@ (*ABS\\t%5, %2)" + [(set_attr "type" "fast") + (set_attr "ccstate" "ccx")]) + +;; DSP MIN/MAX + MOV + +(define_peephole + [(parallel + [(set (match_operand:SI 0 "metag_datareg_op" "") + (MINMAX:SI (match_operand:SI 1 "metag_datareg_op" "") + (match_operand:SI 2 "metag_datareg_op" ""))) + (clobber (reg:CC CC_REG))]) + (set (match_operand:SI 6 "metag_datareg_op" "") + (match_dup 0)) + (parallel + [(set (match_operand:SI 3 "metag_datareg_op" "") + (MINMAX:SI (match_operand:SI 4 "metag_datareg_op" "") + (match_operand:SI 5 "metag_datareg_op" ""))) + (clobber (reg:CC CC_REG))]) + (set (match_operand:SI 7 "metag_datareg_op" "") + (match_dup 3))] + "TARGET_DSP && !metag_cond_exec_p () + && metag_dsp_rrr_mov_operands (operands, ) + && dead_or_set_p (PREV_INSN (PREV_INSN (insn)), operands[0]) + && dead_or_set_p (insn, operands[3])" + "DL\\t\\t%6, %1, %2\\t%@ (*\\r%7, %4, %5)" + [(set_attr "type" "fast") + (set_attr "ccstate" "ccx")]) + +;; END DSP Peepholes + diff -Nur gcc-4.2.4.orig/gcc/config/metag/elf.h gcc-4.2.4/gcc/config/metag/elf.h --- gcc-4.2.4.orig/gcc/config/metag/elf.h 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/elf.h 2015-07-03 18:46:05.745283542 -0500 @@ -0,0 +1,84 @@ +/* Definitions of target machine for GNU compiler, + for Meta Linux-based GNU systems. + Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 + Free Software Foundation, Inc. + Contributed by Imagination Technologies Ltd (toolkit@metagence.com) + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#ifndef OBJECT_FORMAT_ELF +#error elf.h included before elfos.h +#endif + +#undef BSS_SECTION_ASM_OP + +/* Dots in labels are not allowed. */ + +#define NO_DOT_IN_LABEL 1 + +#define ASM_PN_FORMAT "%s___%lu" + +#undef DBX_DEBUGGING_INFO + +#undef PREFERRED_DEBUGGING_TYPE +#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG + +#undef ASM_FINAL_SPEC + +#ifdef MINIM_DEFAULT +#define DEFAULT_MINIM_LINK_SPEC "%{!mno-minim:%{mmetac=2.1:--minim}} " +#else +#define DEFAULT_MINIM_LINK_SPEC +#endif + +#ifdef METAG_LINK_GLOBAL +#define LINK_MACHINE_TYPE "-m elf32metag_global " +#else +#define LINK_MACHINE_TYPE "-m elf32metag " +#endif + +#undef LINK_SPEC +#define LINK_SPEC \ + LINK_MACHINE_TYPE \ + "%{shared:-shared} " \ + "-init=__init -fini=__fini " \ + "%{mminim:%{mmetac=2.1:--minim}%{!mmetac=2.1:%eMiniM mode is only available on a META 2.1}} "\ + DEFAULT_MINIM_LINK_SPEC \ + "%{!shared: " \ + "%{!static: " \ + "%{rdynamic:-export-dynamic} " \ + "%{!dynamic-linker:-dynamic-linker %(elf_dynamic_linker)}} " \ + "%{static:-static}} " + +#ifndef ASM_COMMENT_START +#define ASM_COMMENT_START "!" +#endif + +#define ASM_IDENTIFY_LANGUAGE(FILE) \ + fprintf (FILE, "%s \"GCC (%s) %s\"\n", IDENT_ASM_OP, \ + lang_identify (), version_string) + + +#undef ASM_OUTPUT_CASE_LABEL + +/* For PIC code we need to explicitly specify (PLT) and (GOT) relocs. */ +#define NEED_PLT_RELOC flag_pic +#define NEED_GOT_RELOC flag_pic + +#ifndef SUBTARGET_CPP_SPEC +#define SUBTARGET_CPP_SPEC "-D__ELF__" +#endif diff -Nur gcc-4.2.4.orig/gcc/config/metag/fp-hard-bit.c gcc-4.2.4/gcc/config/metag/fp-hard-bit.c --- gcc-4.2.4.orig/gcc/config/metag/fp-hard-bit.c 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/fp-hard-bit.c 2015-07-03 18:46:05.745283542 -0500 @@ -0,0 +1,1756 @@ +/* This is a software floating point library which can be used + for targets without hardware floating point. + Copyright (C) 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, + 2004, 2005, 2009 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +. */ + +/* This implements IEEE 754 format arithmetic, but does not provide a + mechanism for setting the rounding mode, or for generating or handling + exceptions. + + The original code by Steve Chamberlain, hacked by Mark Eichin and Jim + Wilson, all of Cygnus Support. */ + +/* The intended way to use this file is to make two copies, add `#define FLOAT' + to one copy, then compile both copies and add them to libgcc.a. */ + +#include "tconfig.h" +#include "coretypes.h" +#include "tm.h" +#include "config/fp-bit.h" + +/* The following macros can be defined to change the behavior of this file: + FLOAT: Implement a `float', aka SFmode, fp library. If this is not + defined, then this file implements a `double', aka DFmode, fp library. + FLOAT_ONLY: Used with FLOAT, to implement a `float' only library, i.e. + don't include float->double conversion which requires the double library. + This is useful only for machines which can't support doubles, e.g. some + 8-bit processors. + CMPtype: Specify the type that floating point compares should return. + This defaults to SItype, aka int. + US_SOFTWARE_GOFAST: This makes all entry points use the same names as the + US Software goFast library. + _DEBUG_BITFLOAT: This makes debugging the code a little easier, by adding + two integers to the FLO_union_type. + NO_DENORMALS: Disable handling of denormals. + NO_NANS: Disable nan and infinity handling + SMALL_MACHINE: Useful when operations on QIs and HIs are faster + than on an SI */ + +/* We don't currently support extended floats (long doubles) on machines + without hardware to deal with them. + + These stubs are just to keep the linker from complaining about unresolved + references which can be pulled in from libio & libstdc++, even if the + user isn't using long doubles. However, they may generate an unresolved + external to abort if abort is not used by the function, and the stubs + are referenced from within libc, since libgcc goes before and after the + system library. */ + +#ifdef DECLARE_LIBRARY_RENAMES + DECLARE_LIBRARY_RENAMES +#endif + +#ifdef EXTENDED_FLOAT_STUBS +extern void abort (void); +void __extendsfxf2 (void) { abort(); } +void __extenddfxf2 (void) { abort(); } +void __truncxfdf2 (void) { abort(); } +void __truncxfsf2 (void) { abort(); } +void __fixxfsi (void) { abort(); } +void __floatsixf (void) { abort(); } +void __addxf3 (void) { abort(); } +void __subxf3 (void) { abort(); } +void __mulxf3 (void) { abort(); } +void __divxf3 (void) { abort(); } +void __negxf2 (void) { abort(); } +void __eqxf2 (void) { abort(); } +void __nexf2 (void) { abort(); } +void __gtxf2 (void) { abort(); } +void __gexf2 (void) { abort(); } +void __lexf2 (void) { abort(); } +void __ltxf2 (void) { abort(); } + +void __extendsftf2 (void) { abort(); } +void __extenddftf2 (void) { abort(); } +void __trunctfdf2 (void) { abort(); } +void __trunctfsf2 (void) { abort(); } +void __fixtfsi (void) { abort(); } +void __floatsitf (void) { abort(); } +void __addtf3 (void) { abort(); } +void __subtf3 (void) { abort(); } +void __multf3 (void) { abort(); } +void __divtf3 (void) { abort(); } +void __negtf2 (void) { abort(); } +void __eqtf2 (void) { abort(); } +void __netf2 (void) { abort(); } +void __gttf2 (void) { abort(); } +void __getf2 (void) { abort(); } +void __letf2 (void) { abort(); } +void __lttf2 (void) { abort(); } +#else /* !EXTENDED_FLOAT_STUBS, rest of file */ + +/* IEEE "special" number predicates */ + +#ifdef NO_NANS + +#define nan() 0 +#define isnan(x) 0 +#define isinf(x) 0 +#else + +#if defined L_thenan_sf +const fp_number_type __thenan_sf = { CLASS_SNAN, 0, 0, {(fractype) 0} }; +#elif defined L_thenan_df +const fp_number_type __thenan_df = { CLASS_SNAN, 0, 0, {(fractype) 0} }; +#elif defined L_thenan_tf +const fp_number_type __thenan_tf = { CLASS_SNAN, 0, 0, {(fractype) 0} }; +#elif defined TFLOAT +extern const fp_number_type __thenan_tf; +#elif defined FLOAT +extern const fp_number_type __thenan_sf; +#else +extern const fp_number_type __thenan_df; +#endif + +INLINE +static fp_number_type * +nan (void) +{ + /* Discard the const qualifier... */ +#ifdef TFLOAT + return (fp_number_type *) (& __thenan_tf); +#elif defined FLOAT + return (fp_number_type *) (& __thenan_sf); +#else + return (fp_number_type *) (& __thenan_df); +#endif +} + +INLINE +static int +isnan ( fp_number_type * x) +{ + return __builtin_expect (x->class == CLASS_SNAN || x->class == CLASS_QNAN, + 0); +} + +INLINE +static int +isinf ( fp_number_type * x) +{ + return __builtin_expect (x->class == CLASS_INFINITY, 0); +} + +#endif /* NO_NANS */ + +INLINE +static int +iszero ( fp_number_type * x) +{ + return x->class == CLASS_ZERO; +} + +INLINE +static void +flip_sign ( fp_number_type * x) +{ + x->sign = !x->sign; +} + +/* Count leading zeroes in N. */ +INLINE +static int +clzusi (USItype n) +{ + extern int __clzsi2 (USItype); + if (sizeof (USItype) == sizeof (unsigned int)) + return __builtin_clz (n); + else if (sizeof (USItype) == sizeof (unsigned long)) + return __builtin_clzl (n); + else if (sizeof (USItype) == sizeof (unsigned long long)) + return __builtin_clzll (n); + else + return __clzsi2 (n); +} + +extern FLO_type pack_d ( fp_number_type * ); + +#if defined(L_pack_df) || defined(L_pack_sf) || defined(L_pack_tf) +FLO_type +pack_d ( fp_number_type * src) +{ + FLO_union_type dst; + fractype fraction = src->fraction.ll; /* wasn't unsigned before? */ + int sign = src->sign; + int exp = 0; + + if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && (isnan (src) || isinf (src))) + { + /* We can't represent these values accurately. By using the + largest possible magnitude, we guarantee that the conversion + of infinity is at least as big as any finite number. */ + exp = EXPMAX; + fraction = ((fractype) 1 << FRACBITS) - 1; + } + else if (isnan (src)) + { + exp = EXPMAX; + if (src->class == CLASS_QNAN || 1) + { +#ifdef QUIET_NAN_NEGATED + fraction |= QUIET_NAN - 1; +#else + fraction |= QUIET_NAN; +#endif + } + } + else if (isinf (src)) + { + exp = EXPMAX; + fraction = 0; + } + else if (iszero (src)) + { + exp = 0; + fraction = 0; + } + else if (fraction == 0) + { + exp = 0; + } + else + { + if (__builtin_expect (src->normal_exp < NORMAL_EXPMIN, 0)) + { +#ifdef NO_DENORMALS + /* Go straight to a zero representation if denormals are not + supported. The denormal handling would be harmless but + isn't unnecessary. */ + exp = 0; + fraction = 0; +#else /* NO_DENORMALS */ + /* This number's exponent is too low to fit into the bits + available in the number, so we'll store 0 in the exponent and + shift the fraction to the right to make up for it. */ + + int shift = NORMAL_EXPMIN - src->normal_exp; + + exp = 0; + + if (shift > FRAC_NBITS - NGARDS) + { + /* No point shifting, since it's more that 64 out. */ + fraction = 0; + } + else + { + int lowbit = (fraction & (((fractype)1 << shift) - 1)) ? 1 : 0; + fraction = (fraction >> shift) | lowbit; + } + if ((fraction & GARDMASK) == GARDMSB) + { + if ((fraction & (1 << NGARDS))) + fraction += GARDROUND + 1; + } + else + { + /* Add to the guards to round up. */ + fraction += GARDROUND; + } + /* Perhaps the rounding means we now need to change the + exponent, because the fraction is no longer denormal. */ + if (fraction >= IMPLICIT_1) + { + exp += 1; + } + fraction >>= NGARDS; +#endif /* NO_DENORMALS */ + } + else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) + && __builtin_expect (src->normal_exp > EXPBIAS, 0)) + { + exp = EXPMAX; + fraction = 0; + } + else + { + exp = src->normal_exp + EXPBIAS; + if (!ROUND_TOWARDS_ZERO) + { + /* IF the gard bits are the all zero, but the first, then we're + half way between two numbers, choose the one which makes the + lsb of the answer 0. */ + if ((fraction & GARDMASK) == GARDMSB) + { + if (fraction & (1 << NGARDS)) + fraction += GARDROUND + 1; + } + else + { + /* Add a one to the guards to round up */ + fraction += GARDROUND; + } + if (fraction >= IMPLICIT_2) + { + fraction >>= 1; + exp += 1; + } + } + fraction >>= NGARDS; + + if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp > EXPMAX) + { + /* Saturate on overflow. */ + exp = EXPMAX; + fraction = ((fractype) 1 << FRACBITS) - 1; + } + } + } + + /* We previously used bitfields to store the number, but this doesn't + handle little/big endian systems conveniently, so use shifts and + masks */ +#ifdef FLOAT_BIT_ORDER_MISMATCH + dst.bits.fraction = fraction; + dst.bits.exp = exp; + dst.bits.sign = sign; +#else +# if defined TFLOAT && defined HALFFRACBITS + { + halffractype high, low, unity; + int lowsign, lowexp; + + unity = (halffractype) 1 << HALFFRACBITS; + + /* Set HIGH to the high double's significand, masking out the implicit 1. + Set LOW to the low double's full significand. */ + high = (fraction >> (FRACBITS - HALFFRACBITS)) & (unity - 1); + low = fraction & (unity * 2 - 1); + + /* Get the initial sign and exponent of the low double. */ + lowexp = exp - HALFFRACBITS - 1; + lowsign = sign; + + /* HIGH should be rounded like a normal double, making |LOW| <= + 0.5 ULP of HIGH. Assume round-to-nearest. */ + if (exp < EXPMAX) + if (low > unity || (low == unity && (high & 1) == 1)) + { + /* Round HIGH up and adjust LOW to match. */ + high++; + if (high == unity) + { + /* May make it infinite, but that's OK. */ + high = 0; + exp++; + } + low = unity * 2 - low; + lowsign ^= 1; + } + + high |= (halffractype) exp << HALFFRACBITS; + high |= (halffractype) sign << (HALFFRACBITS + EXPBITS); + + if (exp == EXPMAX || exp == 0 || low == 0) + low = 0; + else + { + while (lowexp > 0 && low < unity) + { + low <<= 1; + lowexp--; + } + + if (lowexp <= 0) + { + halffractype roundmsb, round; + int shift; + + shift = 1 - lowexp; + roundmsb = (1 << (shift - 1)); + round = low & ((roundmsb << 1) - 1); + + low >>= shift; + lowexp = 0; + + if (round > roundmsb || (round == roundmsb && (low & 1) == 1)) + { + low++; + if (low == unity) + /* LOW rounds up to the smallest normal number. */ + lowexp++; + } + } + + low &= unity - 1; + low |= (halffractype) lowexp << HALFFRACBITS; + low |= (halffractype) lowsign << (HALFFRACBITS + EXPBITS); + } + dst.value_raw = ((fractype) high << HALFSHIFT) | low; + } +# else + dst.value_raw = fraction & ((((fractype)1) << FRACBITS) - (fractype)1); + dst.value_raw |= ((fractype) (exp & ((1 << EXPBITS) - 1))) << FRACBITS; + dst.value_raw |= ((fractype) (sign & 1)) << (FRACBITS | EXPBITS); +# endif +#endif + +#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT) +#ifdef TFLOAT + { + qrtrfractype tmp1 = dst.words[0]; + qrtrfractype tmp2 = dst.words[1]; + dst.words[0] = dst.words[3]; + dst.words[1] = dst.words[2]; + dst.words[2] = tmp2; + dst.words[3] = tmp1; + } +#else + { + halffractype tmp = dst.words[0]; + dst.words[0] = dst.words[1]; + dst.words[1] = tmp; + } +#endif +#endif + + return dst.value; +} +#endif + +#if defined(L_unpack_df) || defined(L_unpack_sf) || defined(L_unpack_tf) +void +unpack_d (FLO_union_type * src, fp_number_type * dst) +{ + /* We previously used bitfields to store the number, but this doesn't + handle little/big endian systems conveniently, so use shifts and + masks */ + fractype fraction; + int exp; + int sign; + +#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT) + FLO_union_type swapped; + +#ifdef TFLOAT + swapped.words[0] = src->words[3]; + swapped.words[1] = src->words[2]; + swapped.words[2] = src->words[1]; + swapped.words[3] = src->words[0]; +#else + swapped.words[0] = src->words[1]; + swapped.words[1] = src->words[0]; +#endif + src = &swapped; +#endif + +#ifdef FLOAT_BIT_ORDER_MISMATCH + fraction = src->bits.fraction; + exp = src->bits.exp; + sign = src->bits.sign; +#else +# if defined TFLOAT && defined HALFFRACBITS + { + halffractype high, low; + + high = src->value_raw >> HALFSHIFT; + low = src->value_raw & (((fractype)1 << HALFSHIFT) - 1); + + fraction = high & ((((fractype)1) << HALFFRACBITS) - 1); + fraction <<= FRACBITS - HALFFRACBITS; + exp = ((int)(high >> HALFFRACBITS)) & ((1 << EXPBITS) - 1); + sign = ((int)(high >> (((HALFFRACBITS + EXPBITS))))) & 1; + + if (exp != EXPMAX && exp != 0 && low != 0) + { + int lowexp = ((int)(low >> HALFFRACBITS)) & ((1 << EXPBITS) - 1); + int lowsign = ((int)(low >> (((HALFFRACBITS + EXPBITS))))) & 1; + int shift; + fractype xlow; + + xlow = low & ((((fractype)1) << HALFFRACBITS) - 1); + if (lowexp) + xlow |= (((halffractype)1) << HALFFRACBITS); + else + lowexp = 1; + shift = (FRACBITS - HALFFRACBITS) - (exp - lowexp); + if (shift > 0) + xlow <<= shift; + else if (shift < 0) + xlow >>= -shift; + if (sign == lowsign) + fraction += xlow; + else if (fraction >= xlow) + fraction -= xlow; + else + { + /* The high part is a power of two but the full number is lower. + This code will leave the implicit 1 in FRACTION, but we'd + have added that below anyway. */ + fraction = (((fractype) 1 << FRACBITS) - xlow) << 1; + exp--; + } + } + } +# else + fraction = src->value_raw & ((((fractype)1) << FRACBITS) - 1); + exp = ((int)(src->value_raw >> FRACBITS)) & ((1 << EXPBITS) - 1); + sign = ((int)(src->value_raw >> (FRACBITS + EXPBITS))) & 1; +# endif +#endif + + dst->sign = sign; + if (exp == 0) + { + /* Hmm. Looks like 0 */ + if (fraction == 0 +#ifdef NO_DENORMALS + || 1 +#endif + ) + { + /* tastes like zero */ + dst->class = CLASS_ZERO; + } + else + { + /* Zero exponent with nonzero fraction - it's denormalized, + so there isn't a leading implicit one - we'll shift it so + it gets one. */ + dst->normal_exp = exp - EXPBIAS + 1; + fraction <<= NGARDS; + + dst->class = CLASS_NUMBER; +#if 1 + while (fraction < IMPLICIT_1) + { + fraction <<= 1; + dst->normal_exp--; + } +#endif + dst->fraction.ll = fraction; + } + } + else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) + && __builtin_expect (exp == EXPMAX, 0)) + { + /* Huge exponent*/ + if (fraction == 0) + { + /* Attached to a zero fraction - means infinity */ + dst->class = CLASS_INFINITY; + } + else + { + /* Nonzero fraction, means nan */ +#ifdef QUIET_NAN_NEGATED + if ((fraction & QUIET_NAN) == 0) +#else + if (fraction & QUIET_NAN) +#endif + { + dst->class = CLASS_QNAN; + } + else + { + dst->class = CLASS_SNAN; + } + /* Keep the fraction part as the nan number */ + dst->fraction.ll = fraction; + } + } + else + { + /* Nothing strange about this number */ + dst->normal_exp = exp - EXPBIAS; + dst->class = CLASS_NUMBER; + dst->fraction.ll = (fraction << NGARDS) | IMPLICIT_1; + } +} +#endif /* L_unpack_df || L_unpack_sf */ + +#if defined(L_addsub_sf) || defined(L_addsub_df) || defined(L_addsub_tf) +static fp_number_type * +_fpadd_parts (fp_number_type * a, + fp_number_type * b, + fp_number_type * tmp) +{ + intfrac tfraction; + + /* Put commonly used fields in local variables. */ + int a_normal_exp; + int b_normal_exp; + fractype a_fraction; + fractype b_fraction; + + if (isnan (a)) + { + return a; + } + if (isnan (b)) + { + return b; + } + if (isinf (a)) + { + /* Adding infinities with opposite signs yields a NaN. */ + if (isinf (b) && a->sign != b->sign) + return nan (); + return a; + } + if (isinf (b)) + { + return b; + } + if (iszero (b)) + { + if (iszero (a)) + { + *tmp = *a; + tmp->sign = a->sign & b->sign; + return tmp; + } + return a; + } + if (iszero (a)) + { + return b; + } + + /* Got two numbers. shift the smaller and increment the exponent till + they're the same */ + { + int diff; + int sdiff; + + a_normal_exp = a->normal_exp; + b_normal_exp = b->normal_exp; + a_fraction = a->fraction.ll; + b_fraction = b->fraction.ll; + + diff = a_normal_exp - b_normal_exp; + sdiff = diff; + + if (diff < 0) + diff = -diff; + if (diff < FRAC_NBITS) + { + if (sdiff > 0) + { + b_normal_exp += diff; + LSHIFT (b_fraction, diff); + } + else if (sdiff < 0) + { + a_normal_exp += diff; + LSHIFT (a_fraction, diff); + } + } + else + { + /* Somethings's up.. choose the biggest */ + if (a_normal_exp > b_normal_exp) + { + b_normal_exp = a_normal_exp; + b_fraction = 0; + } + else + { + a_normal_exp = b_normal_exp; + a_fraction = 0; + } + } + } + + if (a->sign != b->sign) + { + if (a->sign) + { + tfraction = -a_fraction + b_fraction; + } + else + { + tfraction = a_fraction - b_fraction; + } + if (tfraction >= 0) + { + tmp->sign = 0; + tmp->normal_exp = a_normal_exp; + tmp->fraction.ll = tfraction; + } + else + { + tmp->sign = 1; + tmp->normal_exp = a_normal_exp; + tmp->fraction.ll = -tfraction; + } + /* and renormalize it */ + + while (tmp->fraction.ll < IMPLICIT_1 && tmp->fraction.ll) + { + tmp->fraction.ll <<= 1; + tmp->normal_exp--; + } + } + else + { + tmp->sign = a->sign; + tmp->normal_exp = a_normal_exp; + tmp->fraction.ll = a_fraction + b_fraction; + } + tmp->class = CLASS_NUMBER; + /* Now the fraction is added, we have to shift down to renormalize the + number */ + + if (tmp->fraction.ll >= IMPLICIT_2) + { + LSHIFT (tmp->fraction.ll, 1); + tmp->normal_exp++; + } + return tmp; + +} + +FLO_type +add (FLO_type arg_a, FLO_type arg_b) +{ +#if defined(TFLOAT) || (!defined(FLOAT) && !defined(METAC_FPU_DOUBLE)) || !defined(METAC_FPU_FLOAT) + fp_number_type a; + fp_number_type b; + fp_number_type tmp; + fp_number_type *res; + FLO_union_type au, bu; + + au.value = arg_a; + bu.value = arg_b; + + unpack_d (&au, &a); + unpack_d (&bu, &b); + + res = _fpadd_parts (&a, &b, &tmp); + + return pack_d (res); +#else + return arg_a + arg_b; +#endif +} + +FLO_type +sub (FLO_type arg_a, FLO_type arg_b) +{ +#if defined(TFLOAT) || (!defined(FLOAT) && !defined(METAC_FPU_DOUBLE)) || !defined(METAC_FPU_FLOAT) + fp_number_type a; + fp_number_type b; + fp_number_type tmp; + fp_number_type *res; + FLO_union_type au, bu; + + au.value = arg_a; + bu.value = arg_b; + + unpack_d (&au, &a); + unpack_d (&bu, &b); + + b.sign ^= 1; + + res = _fpadd_parts (&a, &b, &tmp); + + return pack_d (res); +#else + return arg_a - arg_b; +#endif +} +#endif /* L_addsub_sf || L_addsub_df */ + +#if defined(L_mul_sf) || defined(L_mul_df) || defined(L_mul_tf) +static inline __attribute__ ((__always_inline__)) fp_number_type * +_fpmul_parts ( fp_number_type * a, + fp_number_type * b, + fp_number_type * tmp) +{ + fractype low = 0; + fractype high = 0; + + if (isnan (a)) + { + a->sign = a->sign != b->sign; + return a; + } + if (isnan (b)) + { + b->sign = a->sign != b->sign; + return b; + } + if (isinf (a)) + { + if (iszero (b)) + return nan (); + a->sign = a->sign != b->sign; + return a; + } + if (isinf (b)) + { + if (iszero (a)) + { + return nan (); + } + b->sign = a->sign != b->sign; + return b; + } + if (iszero (a)) + { + a->sign = a->sign != b->sign; + return a; + } + if (iszero (b)) + { + b->sign = a->sign != b->sign; + return b; + } + + /* Calculate the mantissa by multiplying both numbers to get a + twice-as-wide number. */ + { +#if defined(NO_DI_MODE) || defined(TFLOAT) + { + fractype x = a->fraction.ll; + fractype ylow = b->fraction.ll; + fractype yhigh = 0; + int bit; + + /* ??? This does multiplies one bit at a time. Optimize. */ + for (bit = 0; bit < FRAC_NBITS; bit++) + { + int carry; + + if (x & 1) + { + carry = (low += ylow) < ylow; + high += yhigh + carry; + } + yhigh <<= 1; + if (ylow & FRACHIGH) + { + yhigh |= 1; + } + ylow <<= 1; + x >>= 1; + } + } +#elif defined(FLOAT) + /* Multiplying two USIs to get a UDI, we're safe. */ + { + UDItype answer = (UDItype)a->fraction.ll * (UDItype)b->fraction.ll; + + high = answer >> BITS_PER_SI; + low = answer; + } +#else + /* fractype is DImode, but we need the result to be twice as wide. + Assuming a widening multiply from DImode to TImode is not + available, build one by hand. */ + { + USItype nl = a->fraction.ll; + USItype nh = a->fraction.ll >> BITS_PER_SI; + USItype ml = b->fraction.ll; + USItype mh = b->fraction.ll >> BITS_PER_SI; + UDItype pp_ll = (UDItype) ml * nl; + UDItype pp_hl = (UDItype) mh * nl; + UDItype pp_lh = (UDItype) ml * nh; + UDItype pp_hh = (UDItype) mh * nh; + UDItype res2 = 0; + UDItype res0 = 0; + UDItype ps_hh__ = pp_hl + pp_lh; + if (ps_hh__ < pp_hl) + res2 += (UDItype)1 << BITS_PER_SI; + pp_hl = (UDItype)(USItype)ps_hh__ << BITS_PER_SI; + res0 = pp_ll + pp_hl; + if (res0 < pp_ll) + res2++; + res2 += (ps_hh__ >> BITS_PER_SI) + pp_hh; + high = res2; + low = res0; + } +#endif + } + + tmp->normal_exp = a->normal_exp + b->normal_exp + + FRAC_NBITS - (FRACBITS + NGARDS); + tmp->sign = a->sign != b->sign; + while (high >= IMPLICIT_2) + { + tmp->normal_exp++; + if (high & 1) + { + low >>= 1; + low |= FRACHIGH; + } + high >>= 1; + } + while (high < IMPLICIT_1) + { + tmp->normal_exp--; + + high <<= 1; + if (low & FRACHIGH) + high |= 1; + low <<= 1; + } + + if (!ROUND_TOWARDS_ZERO && (high & GARDMASK) == GARDMSB) + { + if (high & (1 << NGARDS)) + { + /* Because we're half way, we would round to even by adding + GARDROUND + 1, except that's also done in the packing + function, and rounding twice will lose precision and cause + the result to be too far off. Example: 32-bit floats with + bit patterns 0xfff * 0x3f800400 ~= 0xfff (less than 0.5ulp + off), not 0x1000 (more than 0.5ulp off). */ + } + else if (low) + { + /* We're a further than half way by a small amount corresponding + to the bits set in "low". Knowing that, we round here and + not in pack_d, because there we don't have "low" available + anymore. */ + high += GARDROUND + 1; + + /* Avoid further rounding in pack_d. */ + high &= ~(fractype) GARDMASK; + } + } + tmp->fraction.ll = high; + tmp->class = CLASS_NUMBER; + return tmp; +} + +FLO_type +multiply (FLO_type arg_a, FLO_type arg_b) +{ +#if defined(TFLOAT) || (!defined(FLOAT) && !defined(METAC_FPU_DOUBLE)) || !defined(METAC_FPU_FLOAT) + fp_number_type a; + fp_number_type b; + fp_number_type tmp; + fp_number_type *res; + FLO_union_type au, bu; + + au.value = arg_a; + bu.value = arg_b; + + unpack_d (&au, &a); + unpack_d (&bu, &b); + + res = _fpmul_parts (&a, &b, &tmp); + + return pack_d (res); +#else + return arg_a * arg_b; +#endif +} +#endif /* L_mul_sf || L_mul_df || L_mul_tf */ + +#if defined(L_div_sf) || defined(L_div_df) || defined(L_div_tf) +static inline __attribute__ ((__always_inline__)) fp_number_type * +_fpdiv_parts (fp_number_type * a, + fp_number_type * b) +{ + fractype bit; + fractype numerator; + fractype denominator; + fractype quotient; + + if (isnan (a)) + { + return a; + } + if (isnan (b)) + { + return b; + } + + a->sign = a->sign ^ b->sign; + + if (isinf (a) || iszero (a)) + { + if (a->class == b->class) + return nan (); + return a; + } + + if (isinf (b)) + { + a->fraction.ll = 0; + a->normal_exp = 0; + return a; + } + if (iszero (b)) + { + a->class = CLASS_INFINITY; + return a; + } + + /* Calculate the mantissa by multiplying both 64bit numbers to get a + 128 bit number */ + { + /* quotient = + ( numerator / denominator) * 2^(numerator exponent - denominator exponent) + */ + + a->normal_exp = a->normal_exp - b->normal_exp; + numerator = a->fraction.ll; + denominator = b->fraction.ll; + + if (numerator < denominator) + { + /* Fraction will be less than 1.0 */ + numerator *= 2; + a->normal_exp--; + } + bit = IMPLICIT_1; + quotient = 0; + /* ??? Does divide one bit at a time. Optimize. */ + while (bit) + { + if (numerator >= denominator) + { + quotient |= bit; + numerator -= denominator; + } + bit >>= 1; + numerator *= 2; + } + + if (!ROUND_TOWARDS_ZERO && (quotient & GARDMASK) == GARDMSB) + { + if (quotient & (1 << NGARDS)) + { + /* Because we're half way, we would round to even by adding + GARDROUND + 1, except that's also done in the packing + function, and rounding twice will lose precision and cause + the result to be too far off. */ + } + else if (numerator) + { + /* We're a further than half way by the small amount + corresponding to the bits set in "numerator". Knowing + that, we round here and not in pack_d, because there we + don't have "numerator" available anymore. */ + quotient += GARDROUND + 1; + + /* Avoid further rounding in pack_d. */ + quotient &= ~(fractype) GARDMASK; + } + } + + a->fraction.ll = quotient; + return (a); + } +} + +FLO_type +divide (FLO_type arg_a, FLO_type arg_b) +{ + fp_number_type a; + fp_number_type b; + fp_number_type *res; + FLO_union_type au, bu; + + au.value = arg_a; + bu.value = arg_b; + + unpack_d (&au, &a); + unpack_d (&bu, &b); + + res = _fpdiv_parts (&a, &b); + + return pack_d (res); +} +#endif /* L_div_sf || L_div_df */ + +#if defined(L_fpcmp_parts_sf) || defined(L_fpcmp_parts_df) \ + || defined(L_fpcmp_parts_tf) +/* according to the demo, fpcmp returns a comparison with 0... thus + a -1 + a==b -> 0 + a>b -> +1 + */ + +int +__fpcmp_parts (fp_number_type * a, fp_number_type * b) +{ +#if 0 + /* either nan -> unordered. Must be checked outside of this routine. */ + if (isnan (a) && isnan (b)) + { + return 1; /* still unordered! */ + } +#endif + + if (isnan (a) || isnan (b)) + { + return 1; /* how to indicate unordered compare? */ + } + if (isinf (a) && isinf (b)) + { + /* +inf > -inf, but +inf != +inf */ + /* b \a| +inf(0)| -inf(1) + ______\+--------+-------- + +inf(0)| a==b(0)| ab(1) | a==b(0) + -------+--------+-------- + So since unordered must be nonzero, just line up the columns... + */ + return b->sign - a->sign; + } + /* but not both... */ + if (isinf (a)) + { + return a->sign ? -1 : 1; + } + if (isinf (b)) + { + return b->sign ? 1 : -1; + } + if (iszero (a) && iszero (b)) + { + return 0; + } + if (iszero (a)) + { + return b->sign ? 1 : -1; + } + if (iszero (b)) + { + return a->sign ? -1 : 1; + } + /* now both are "normal". */ + if (a->sign != b->sign) + { + /* opposite signs */ + return a->sign ? -1 : 1; + } + /* same sign; exponents? */ + if (a->normal_exp > b->normal_exp) + { + return a->sign ? -1 : 1; + } + if (a->normal_exp < b->normal_exp) + { + return a->sign ? 1 : -1; + } + /* same exponents; check size. */ + if (a->fraction.ll > b->fraction.ll) + { + return a->sign ? -1 : 1; + } + if (a->fraction.ll < b->fraction.ll) + { + return a->sign ? 1 : -1; + } + /* after all that, they're equal. */ + return 0; +} +#endif + +#if defined(L_compare_sf) || defined(L_compare_df) || defined(L_compoare_tf) +CMPtype +compare (FLO_type arg_a, FLO_type arg_b) +{ +#if defined(TFLOAT) || (!defined(FLOAT) && !defined(METAC_FPU_DOUBLE)) || !defined(METAC_FPU_FLOAT) + fp_number_type a; + fp_number_type b; + FLO_union_type au, bu; + + au.value = arg_a; + bu.value = arg_b; + + unpack_d (&au, &a); + unpack_d (&bu, &b); + + return __fpcmp_parts (&a, &b); +#else + if (arg_a < arg_b) + return -1; + else if (arg_a == arg_b) + return 0; + else + return 1; +#endif +} +#endif /* L_compare_sf || L_compare_df */ + +#ifndef US_SOFTWARE_GOFAST + +/* These should be optimized for their specific tasks someday. */ + +#if defined(L_eq_sf) || defined(L_eq_df) || defined(L_eq_tf) +CMPtype +_eq_f2 (FLO_type arg_a, FLO_type arg_b) +{ +#if defined(TFLOAT) || (!defined(FLOAT) && !defined(METAC_FPU_DOUBLE)) || !defined(METAC_FPU_FLOAT) + fp_number_type a; + fp_number_type b; + FLO_union_type au, bu; + + au.value = arg_a; + bu.value = arg_b; + + unpack_d (&au, &a); + unpack_d (&bu, &b); + + if (isnan (&a) || isnan (&b)) + return 1; /* false, truth == 0 */ + + return __fpcmp_parts (&a, &b) ; +#else + return compare (arg_a, arg_b); +#endif +} +#endif /* L_eq_sf || L_eq_df */ + +#if defined(L_ne_sf) || defined(L_ne_df) || defined(L_ne_tf) +CMPtype +_ne_f2 (FLO_type arg_a, FLO_type arg_b) +{ +#if defined(TFLOAT) || (!defined(FLOAT) && !defined(METAC_FPU_DOUBLE)) || !defined(METAC_FPU_FLOAT) + fp_number_type a; + fp_number_type b; + FLO_union_type au, bu; + + au.value = arg_a; + bu.value = arg_b; + + unpack_d (&au, &a); + unpack_d (&bu, &b); + + if (isnan (&a) || isnan (&b)) + return 1; /* true, truth != 0 */ + + return __fpcmp_parts (&a, &b) ; +#else + return compare (arg_a, arg_b); +#endif +} +#endif /* L_ne_sf || L_ne_df */ + +#if defined(L_gt_sf) || defined(L_gt_df) || defined(L_gt_tf) +CMPtype +_gt_f2 (FLO_type arg_a, FLO_type arg_b) +{ +#if defined(TFLOAT) || (!defined(FLOAT) && !defined(METAC_FPU_DOUBLE)) || !defined(METAC_FPU_FLOAT) + fp_number_type a; + fp_number_type b; + FLO_union_type au, bu; + + au.value = arg_a; + bu.value = arg_b; + + unpack_d (&au, &a); + unpack_d (&bu, &b); + + if (isnan (&a) || isnan (&b)) + return -1; /* false, truth > 0 */ + + return __fpcmp_parts (&a, &b); +#else + if (__builtin_isnan (arg_a) || __builtin_isnan (arg_b)) + return -1; + + return compare (arg_a, arg_b); +#endif +} +#endif /* L_gt_sf || L_gt_df */ + +#if defined(L_ge_sf) || defined(L_ge_df) || defined(L_ge_tf) +CMPtype +_ge_f2 (FLO_type arg_a, FLO_type arg_b) +{ +#if defined(TFLOAT) || (!defined(FLOAT) && !defined(METAC_FPU_DOUBLE)) || !defined(METAC_FPU_FLOAT) + fp_number_type a; + fp_number_type b; + FLO_union_type au, bu; + + au.value = arg_a; + bu.value = arg_b; + + unpack_d (&au, &a); + unpack_d (&bu, &b); + + if (isnan (&a) || isnan (&b)) + return -1; /* false, truth >= 0 */ + return __fpcmp_parts (&a, &b) ; +#else + if (__builtin_isnan (arg_a) || __builtin_isnan (arg_b)) + return -1; + + return compare (arg_a, arg_b); +#endif +} +#endif /* L_ge_sf || L_ge_df */ + +#if defined(L_lt_sf) || defined(L_lt_df) || defined(L_lt_tf) +CMPtype +_lt_f2 (FLO_type arg_a, FLO_type arg_b) +{ +#if defined(TFLOAT) || (!defined(FLOAT) && !defined(METAC_FPU_DOUBLE)) || !defined(METAC_FPU_FLOAT) + fp_number_type a; + fp_number_type b; + FLO_union_type au, bu; + + au.value = arg_a; + bu.value = arg_b; + + unpack_d (&au, &a); + unpack_d (&bu, &b); + + if (isnan (&a) || isnan (&b)) + return 1; /* false, truth < 0 */ + + return __fpcmp_parts (&a, &b); +#else + return compare (arg_a, arg_b); +#endif +} +#endif /* L_lt_sf || L_lt_df */ + +#if defined(L_le_sf) || defined(L_le_df) || defined(L_le_tf) +CMPtype +_le_f2 (FLO_type arg_a, FLO_type arg_b) +{ +#if defined(TFLOAT) || (!defined(FLOAT) && !defined(METAC_FPU_DOUBLE)) || !defined(METAC_FPU_FLOAT) + fp_number_type a; + fp_number_type b; + FLO_union_type au, bu; + + au.value = arg_a; + bu.value = arg_b; + + unpack_d (&au, &a); + unpack_d (&bu, &b); + + if (isnan (&a) || isnan (&b)) + return 1; /* false, truth <= 0 */ + + return __fpcmp_parts (&a, &b) ; +#else + return compare (arg_a, arg_b); +#endif +} +#endif /* L_le_sf || L_le_df */ + +#endif /* ! US_SOFTWARE_GOFAST */ + +#if defined(L_unord_sf) || defined(L_unord_df) || defined(L_unord_tf) +CMPtype +_unord_f2 (FLO_type arg_a, FLO_type arg_b) +{ +#if defined(TFLOAT) || (!defined(FLOAT) && !defined(METAC_FPU_DOUBLE)) || !defined(METAC_FPU_FLOAT) + fp_number_type a; + fp_number_type b; + FLO_union_type au, bu; + + au.value = arg_a; + bu.value = arg_b; + + unpack_d (&au, &a); + unpack_d (&bu, &b); + + return (isnan (&a) || isnan (&b)); +#else + return __builtin_isunordered (arg_a, arg_b); +#endif +} +#endif /* L_unord_sf || L_unord_df */ + +#if defined(L_si_to_sf) || defined(L_si_to_df) || defined(L_si_to_tf) +FLO_type +si_to_float (SItype arg_a) +{ +#if defined(TFLOAT) || (!defined(FLOAT) && !defined(METAC_FPU_DOUBLE)) || !defined(METAC_FPU_FLOAT) + fp_number_type in; + + in.class = CLASS_NUMBER; + in.sign = arg_a < 0; + if (!arg_a) + { + in.class = CLASS_ZERO; + } + else + { + USItype uarg; + int shift; + in.normal_exp = FRACBITS + NGARDS; + if (in.sign) + { + /* Special case for minint, since there is no +ve integer + representation for it */ + if (arg_a == (- MAX_SI_INT - 1)) + { + return (FLO_type)(- MAX_SI_INT - 1); + } + uarg = (-arg_a); + } + else + uarg = arg_a; + + in.fraction.ll = uarg; + shift = clzusi (uarg) - (BITS_PER_SI - 1 - FRACBITS - NGARDS); + if (shift > 0) + { + in.fraction.ll <<= shift; + in.normal_exp -= shift; + } + } + return pack_d (&in); +#else + return (FLO_type)arg_a; +#endif +} +#endif /* L_si_to_sf || L_si_to_df */ + +#if defined(L_usi_to_sf) || defined(L_usi_to_df) || defined(L_usi_to_tf) +FLO_type +usi_to_float (USItype arg_a) +{ +#if defined(TFLOAT) || (!defined(FLOAT) && !defined(METAC_FPU_DOUBLE)) || !defined(METAC_FPU_FLOAT) + fp_number_type in; + + in.sign = 0; + if (!arg_a) + { + in.class = CLASS_ZERO; + } + else + { + int shift; + in.class = CLASS_NUMBER; + in.normal_exp = FRACBITS + NGARDS; + in.fraction.ll = arg_a; + + shift = clzusi (arg_a) - (BITS_PER_SI - 1 - FRACBITS - NGARDS); + if (shift < 0) + { + fractype guard = in.fraction.ll & (((fractype)1 << -shift) - 1); + in.fraction.ll >>= -shift; + in.fraction.ll |= (guard != 0); + in.normal_exp -= shift; + } + else if (shift > 0) + { + in.fraction.ll <<= shift; + in.normal_exp -= shift; + } + } + return pack_d (&in); +#else + return (FLO_type)arg_a; +#endif +} +#endif + +#if defined(L_sf_to_si) || defined(L_df_to_si) || defined(L_tf_to_si) +SItype +float_to_si (FLO_type arg_a) +{ +#if defined(TFLOAT) || (!defined(FLOAT) && !defined(METAC_FPU_DOUBLE)) || !defined(METAC_FPU_FLOAT) + fp_number_type a; + SItype tmp; + FLO_union_type au; + + au.value = arg_a; + unpack_d (&au, &a); + + if (iszero (&a)) + return 0; + if (isnan (&a)) + return 0; + /* get reasonable MAX_SI_INT... */ + if (isinf (&a)) + return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT; + /* it is a number, but a small one */ + if (a.normal_exp < 0) + return 0; + if (a.normal_exp > BITS_PER_SI - 2) + return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT; + tmp = a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp); + return a.sign ? (-tmp) : (tmp); +#else + return (SItype)arg_a; +#endif +} +#endif /* L_sf_to_si || L_df_to_si */ + +#if defined(L_sf_to_usi) || defined(L_df_to_usi) || defined(L_tf_to_usi) +#if defined US_SOFTWARE_GOFAST || defined(L_tf_to_usi) +/* While libgcc2.c defines its own __fixunssfsi and __fixunsdfsi routines, + we also define them for GOFAST because the ones in libgcc2.c have the + wrong names and I'd rather define these here and keep GOFAST CYG-LOC's + out of libgcc2.c. We can't define these here if not GOFAST because then + there'd be duplicate copies. */ + +USItype +float_to_usi (FLO_type arg_a) +{ +#if defined(TFLOAT) || (!defined(FLOAT) && !defined(METAC_FPU_DOUBLE)) || !defined(METAC_FPU_FLOAT) + fp_number_type a; + FLO_union_type au; + + au.value = arg_a; + unpack_d (&au, &a); + + if (iszero (&a)) + return 0; + if (isnan (&a)) + return 0; + /* it is a negative number */ + if (a.sign) + return 0; + /* get reasonable MAX_USI_INT... */ + if (isinf (&a)) + return MAX_USI_INT; + /* it is a number, but a small one */ + if (a.normal_exp < 0) + return 0; + if (a.normal_exp > BITS_PER_SI - 1) + return MAX_USI_INT; + else if (a.normal_exp > (FRACBITS + NGARDS)) + return a.fraction.ll << (a.normal_exp - (FRACBITS + NGARDS)); + else + return a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp); +#else + return (USItype)arg_a; +#endif +} +#endif /* US_SOFTWARE_GOFAST */ +#endif /* L_sf_to_usi || L_df_to_usi */ + +#if defined(L_negate_sf) || defined(L_negate_df) || defined(L_negate_tf) +FLO_type +negate (FLO_type arg_a) +{ +#if defined(TFLOAT) || (!defined(FLOAT) && !defined(METAC_FPU_DOUBLE)) || !defined(METAC_FPU_FLOAT) + fp_number_type a; + FLO_union_type au; + + au.value = arg_a; + unpack_d (&au, &a); + + flip_sign (&a); + return pack_d (&a); +#else + return -arg_a; +#endif +} +#endif /* L_negate_sf || L_negate_df */ + +#ifdef FLOAT + +#if defined(L_make_sf) +SFtype +__make_fp(fp_class_type class, + unsigned int sign, + int exp, + USItype frac) +{ + fp_number_type in; + + in.class = class; + in.sign = sign; + in.normal_exp = exp; + in.fraction.ll = frac; + return pack_d (&in); +} +#endif /* L_make_sf */ + +#ifndef FLOAT_ONLY + +/* This enables one to build an fp library that supports float but not double. + Otherwise, we would get an undefined reference to __make_dp. + This is needed for some 8-bit ports that can't handle well values that + are 8-bytes in size, so we just don't support double for them at all. */ + +#if defined(L_sf_to_df) +DFtype +sf_to_df (SFtype arg_a) +{ +#if defined(TFLOAT) || !defined(METAC_FPU_DOUBLE) + fp_number_type in; + FLO_union_type au; + + au.value = arg_a; + unpack_d (&au, &in); + + return __make_dp (in.class, in.sign, in.normal_exp, + ((UDItype) in.fraction.ll) << F_D_BITOFF); +#else + return (DFtype)arg_a; +#endif +} +#endif /* L_sf_to_df */ + +#if defined(L_sf_to_tf) && defined(TMODES) +TFtype +sf_to_tf (SFtype arg_a) +{ + fp_number_type in; + FLO_union_type au; + + au.value = arg_a; + unpack_d (&au, &in); + + return __make_tp (in.class, in.sign, in.normal_exp, + ((UTItype) in.fraction.ll) << F_T_BITOFF); +} +#endif /* L_sf_to_df */ + +#endif /* ! FLOAT_ONLY */ +#endif /* FLOAT */ + +#ifndef FLOAT + +extern SFtype __make_fp (fp_class_type, unsigned int, int, USItype); + +#if defined(L_make_df) +DFtype +__make_dp (fp_class_type class, unsigned int sign, int exp, UDItype frac) +{ + fp_number_type in; + + in.class = class; + in.sign = sign; + in.normal_exp = exp; + in.fraction.ll = frac; + return pack_d (&in); +} +#endif /* L_make_df */ + +#if defined(L_df_to_sf) +SFtype +df_to_sf (DFtype arg_a) +{ +#if defined(TFLOAT) || !defined(METAC_FPU_DOUBLE) + fp_number_type in; + USItype sffrac; + FLO_union_type au; + + au.value = arg_a; + unpack_d (&au, &in); + + sffrac = in.fraction.ll >> F_D_BITOFF; + + /* We set the lowest guard bit in SFFRAC if we discarded any non + zero bits. */ + if ((in.fraction.ll & (((USItype) 1 << F_D_BITOFF) - 1)) != 0) + sffrac |= 1; + + return __make_fp (in.class, in.sign, in.normal_exp, sffrac); +#else + return (SFtype)arg_a; +#endif +} +#endif /* L_df_to_sf */ + +#if defined(L_df_to_tf) && defined(TMODES) \ + && !defined(FLOAT) && !defined(TFLOAT) +TFtype +df_to_tf (DFtype arg_a) +{ + fp_number_type in; + FLO_union_type au; + + au.value = arg_a; + unpack_d (&au, &in); + + return __make_tp (in.class, in.sign, in.normal_exp, + ((UTItype) in.fraction.ll) << D_T_BITOFF); +} +#endif /* L_sf_to_df */ + +#ifdef TFLOAT +#if defined(L_make_tf) +TFtype +__make_tp(fp_class_type class, + unsigned int sign, + int exp, + UTItype frac) +{ + fp_number_type in; + + in.class = class; + in.sign = sign; + in.normal_exp = exp; + in.fraction.ll = frac; + return pack_d (&in); +} +#endif /* L_make_tf */ + +#if defined(L_tf_to_df) +DFtype +tf_to_df (TFtype arg_a) +{ + fp_number_type in; + UDItype sffrac; + FLO_union_type au; + + au.value = arg_a; + unpack_d (&au, &in); + + sffrac = in.fraction.ll >> D_T_BITOFF; + + /* We set the lowest guard bit in SFFRAC if we discarded any non + zero bits. */ + if ((in.fraction.ll & (((UTItype) 1 << D_T_BITOFF) - 1)) != 0) + sffrac |= 1; + + return __make_dp (in.class, in.sign, in.normal_exp, sffrac); +} +#endif /* L_tf_to_df */ + +#if defined(L_tf_to_sf) +SFtype +tf_to_sf (TFtype arg_a) +{ + fp_number_type in; + USItype sffrac; + FLO_union_type au; + + au.value = arg_a; + unpack_d (&au, &in); + + sffrac = in.fraction.ll >> F_T_BITOFF; + + /* We set the lowest guard bit in SFFRAC if we discarded any non + zero bits. */ + if ((in.fraction.ll & (((UTItype) 1 << F_T_BITOFF) - 1)) != 0) + sffrac |= 1; + + return __make_fp (in.class, in.sign, in.normal_exp, sffrac); +} +#endif /* L_tf_to_sf */ +#endif /* TFLOAT */ + +#endif /* ! FLOAT */ +#endif /* !EXTENDED_FLOAT_STUBS */ diff -Nur gcc-4.2.4.orig/gcc/config/metag/fp.md gcc-4.2.4/gcc/config/metag/fp.md --- gcc-4.2.4.orig/gcc/config/metag/fp.md 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/fp.md 2015-07-03 18:46:05.745283542 -0500 @@ -0,0 +1,1037 @@ +;; Machine description for GNU compiler, +;; Imagination Technologies Meta version. +;; Copyright (C) 2008 +;; Imagination Technologies Ltd + +;; This file is part of GCC. + +;; GCC is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 3, or (at your option) any later +;; version. + +;; GCC is distributed in the hope that it will be useful, but WITHOUT ANY +;; WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; . + +;;- instruction definitions + +;;- @@The original PO technology requires these to be ordered by speed, +;;- @@ so that assigner will pick the fastest. + +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. + +;;- When naming insn's (operand 0 of define_insn) be careful about using +;;- names from other targets machine descriptions. + + + +(define_insn_and_split "*movv2sfrr" + [(set (match_operand:V2SF 0 "metag_fpreg_or_dreg_op" "=cx,cx,d, d") + (match_operand:V2SF 1 "metag_fpreg_or_dreg_op" "cx,d, cx,d"))] + "TARGET_FPU_SIMD" + "@ + FL\\tMOV\\t%0,%1\\t%@ (*mov v2sf rr) + # + # + #" + "&& reload_completed" + [(set (match_dup 2) + (match_dup 3)) + (set (match_dup 4) + (match_dup 5))] + { + operands[2] = gen_rtx_REG (SImode, REGNO (operands[0])); + operands[3] = gen_rtx_REG (SImode, REGNO (operands[1])); + operands[4] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + operands[5] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1); + } + [(set_attr "type" "FPfast")]) + +(define_insn_and_split "*movv2sfri" + [(set (match_operand:V2SF 0 "metag_fpreg_op" "=cx") + (match_operand:V2SF 1 "metag_vector_float_op" "vcf"))] + "TARGET_FPU_SIMD" + { + if (rtx_equal_p (CONST_VECTOR_ELT (operands[1], 0), + CONST_VECTOR_ELT (operands[1], 1))) + return "FL\\tMOV\\t%0,#%h1"; + else + return "#"; + } + "&& reload_completed + && !rtx_equal_p (CONST_VECTOR_ELT (operands[1], 0), + CONST_VECTOR_ELT (operands[1], 1))" + [(set (match_dup 2) + (match_dup 4)) + (set (match_dup 3) + (match_dup 5))] + { + operands[2] = gen_rtx_REG (SFmode, REGNO (operands[0])); + operands[3] = gen_rtx_REG (SFmode, REGNO (operands[0]) + 1); + operands[4] = CONST_VECTOR_ELT (operands[1], 0); + operands[5] = CONST_VECTOR_ELT (operands[1], 1); + } + [(set_attr "type" "FPfast")]) + +(define_expand "movv2sf" + [(set (match_operand:V2SF 0 "nonimmediate_operand" "") + (match_operand:V2SF 1 "general_operand" ""))] + "TARGET_FPU_SIMD" + { + if (MEM_P (operands[0]) && !REG_P (operands[1])) + { + /* All except mem = const, mem = mem, or mem = addr can be done quickly */ + if (!no_new_pseudos) + operands[1] = force_reg (V2SFmode, operands[1]); + } + else if (GET_CODE(operands[1]) == CONST_VECTOR) + if ( (!metag_fphalf_imm_op (CONST_VECTOR_ELT (operands[1], 0), SFmode) + || !metag_fphalf_imm_op (CONST_VECTOR_ELT (operands[1], 1), SFmode))) + { + emit_move_insn (gen_rtx_SUBREG (SFmode, operands[0], 0), + CONST_VECTOR_ELT (operands[1], 0)); + emit_move_insn (gen_rtx_SUBREG (SFmode, operands[0], UNITS_PER_WORD), + CONST_VECTOR_ELT (operands[1], 1)); + DONE; + } + } +) + +;; ----------------------------------------------------------------------------- +;; | Matching V2SF load [post/pre]_[inc/dec/modify] +;; ----------------------------------------------------------------------------- + +(define_insn "*lod_v2sf_post_inc" + [(set (match_operand:V2SF 0 "metag_fpreg_op" "=cx") + (mem:V2SF (post_inc:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da"))))] + "TARGET_FPU_SIMD" + "F\\tGETL\\t%0, %t0, [%1++]\\t%@ (*load V2SF post_inc OK)" + [(set_attr "type" "load")]) + +(define_insn "*lod_v2sf_post_dec" + [(set (match_operand:V2SF 0 "metag_fpreg_op" "=cx") + (mem:V2SF (post_dec:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da"))))] + "TARGET_FPU_SIMD" + "F\\tGETL\\t%0, %t0, [%1--]\\t%@ (*load V2SF post_dec OK)" + [(set_attr "type" "load")]) + +(define_insn "*lod_v2sf_pre_inc" + [(set (match_operand:V2SF 0 "metag_fpreg_op" "=cx") + (mem:V2SF (pre_inc:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da"))))] + "TARGET_FPU_SIMD" + "F\\tGETL\\t%0, %t0, [++%1]\\t%@ (*load V2SF pre_inc OK)" + [(set_attr "type" "load")]) + +(define_insn "*lod_v2sf_pre_dec" + [(set (match_operand:V2SF 0 "metag_fpreg_op" "=cx") + (mem:V2SF (pre_dec:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da"))))] + "TARGET_FPU_SIMD" + "F\\tGETL\\t%0, %t0, [--%1]\\t%@ (*load V2SF pre_dec OK)" + [(set_attr "type" "load")]) + +(define_insn "*lod_v2sf_post_modify_disp" + [(set (match_operand:V2SF 0 "metag_fpreg_op" "=cx") + (mem:V2SF (post_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+da") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_offset6_v2sf" "O8")))))] + "TARGET_FPU_SIMD" + "F\\tGETL\\t%0, %t0, [%1+%2++]\\t%@ (*load V2SF post_modify_disp OK)" + [(set_attr "type" "load")]) + +(define_insn "*lod_v2sf_post_modify_reg" + [(set (match_operand:V2SF 0 "metag_fpreg_op" "=cx,cx,cx,cx") + (mem:V2SF (post_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+e, f, h, l") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_reg_nofloat_op" "e, f, h, l")))))] + "TARGET_FPU_SIMD" + "F\\tGETL\\t%0, %t0, [%1+%2++]\\t%@ (*load V2SF post_modify_reg OK)" + [(set_attr "type" "load")]) + +(define_insn "*lod_v2sf_pre_modify_disp" + [(set (match_operand:V2SF 0 "metag_fpreg_op" "=cx") + (mem:V2SF (pre_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+da") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_offset6_v2sf" "O8")))))] + "TARGET_FPU_SIMD" + "F\\tGETL\\t%0, %t0, [%1++%2]\\t%@ (*load V2SF pre_modify_disp OK)" + [(set_attr "type" "load")]) + +(define_insn "*lod_v2sf_pre_modify_reg" + [(set (match_operand:V2SF 0 "metag_fpreg_op" "=cx,cx,cx,cx") + (mem:V2SF (pre_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+e, f, h, l") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_reg_nofloat_op" "e, f, h, l")))))] + "TARGET_FPU_SIMD" + "F\\tGETL\\t%0, %t0, [%1++%2]\\t%@ (*load V2SF pre_modify_reg OK)" + [(set_attr "type" "load")]) + +;; ----------------------------------------------------------------------------- + +(define_insn "*lod_v2sf_off6" + [(set (match_operand:V2SF 0 "metag_fpreg_op" "=cx") + (mem:V2SF (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "da") + (match_operand:SI 2 "metag_offset6_v2sf" "O8"))))] + "TARGET_FPU_SIMD" + "F\\tGETL\\t%0, %t0, [%1+%2]" + [(set_attr "type" "load")]) + +(define_insn "*lod_v2sf_mem" + [(set (match_operand:V2SF 0 "metag_datareg_op" "=d") + (match_operand:V2SF 1 "memory_operand" "m"))] + "TARGET_FPU_SIMD" + "GETL\\t%0, %t0, %1\\t%@ (*lod v2sf rm OK)" + [(set_attr "memaccess" "load")]) + +;; ----------------------------------------------------------------------------- +;; | Matching V2SF store [post/pre]_[inc/dec/modify] +;; ----------------------------------------------------------------------------- + +(define_insn "*sto_v2sf_post_inc" + [(set (mem:V2SF (post_inc:SI (match_operand:SI 0 "metag_reg_nofloat_op" "+da"))) + (match_operand:V2SF 1 "metag_fpreg_op" "cx"))] + "TARGET_FPU_SIMD" + "F\\tSETL\\t[%0++], %1, %t1\\t%@ (*store V2SF post_inc OK)" + [(set_attr "type" "fast")]) + +(define_insn "*sto_v2sf_post_dec" + [(set (mem:V2SF (post_dec:SI (match_operand:SI 0 "metag_reg_nofloat_op" "+da"))) + (match_operand:V2SF 1 "metag_fpreg_op" "cx"))] + "TARGET_FPU_SIMD" + "F\\tSETL\\t[%0--], %1, %t1\\t%@ (*store V2SF post_dec OK)" + [(set_attr "type" "fast")]) + +(define_insn "*sto_v2sf_pre_inc" + [(set (mem:V2SF (pre_inc:SI (match_operand:SI 0 "metag_reg_nofloat_op" "+da"))) + (match_operand:V2SF 1 "metag_fpreg_op" "cx"))] + "TARGET_FPU_SIMD" + "F\\tSETL\\t[++%0], %1, %t1\\t%@ (*store V2SF pre_inc OK)" + [(set_attr "type" "fast")]) + +(define_insn "*sto_v2sf_pre_dec" + [(set (mem:V2SF (pre_dec:SI (match_operand:SI 0 "metag_reg_nofloat_op" "+da"))) + (match_operand:V2SF 1 "metag_fpreg_op" "cx"))] + "TARGET_FPU_SIMD" + "F\\tSETL\\t[--%0], %1, %t1\\t%@ (*store V2SF pre_dec OK)" + [(set_attr "type" "fast")]) + +(define_insn "*sto_v2sf_post_modify_disp" + [(set (mem:V2SF (post_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+da") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_v2sf" "O8")))) + (match_operand:V2SF 2 "metag_fpreg_op" "cx"))] + "TARGET_FPU_SIMD" + "F\\tSETL\\t[%0+%1++], %2, %t2\\t%@ (*store V2SF post_modify_disp OK)" + [(set_attr "type" "fast")]) + +(define_insn "*sto_v2sf_post_modify_reg" + [(set (mem:V2SF (post_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+e, f, h, l") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_reg_nofloat_op" "e, f, h, l")))) + (match_operand:V2SF 2 "metag_fpreg_op" "cx,cx,cx,cx"))] + "TARGET_FPU_SIMD" + "F\\tSETL\\t[%0+%1++], %2, %t2\\t%@ (*store V2SF post_modify_reg OK)" + [(set_attr "type" "fast")]) + +(define_insn "*sto_v2sf_pre_modify_disp" + [(set (mem:V2SF (pre_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+da") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_v2sf" "O8")))) + (match_operand:V2SF 2 "metag_fpreg_op" "cx"))] + "TARGET_FPU_SIMD" + "F\\tSETL\\t[%0++%1], %2, %t2\\t%@ (*store V2SF pre_modify_disp OK)" + [(set_attr "type" "fast")]) + +(define_insn "*sto_v2sf_pre_modify_reg" + [(set (mem:V2SF (pre_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+e, f, h, l") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_reg_nofloat_op" "e, f, h, l")))) + (match_operand:V2SF 2 "metag_fpreg_op" "cx,cx,cx,cx"))] + "TARGET_FPU_SIMD" + "F\\tSETL\\t[%0++%1], %2, %t2\\t%@ (*store V2SF pre_modify_reg OK)" + [(set_attr "type" "fast")]) + +;; ----------------------------------------------------------------------------- + +(define_insn "*sto_v2sf_off6" + [(set (mem:V2SF (plus:SI (match_operand:SI 0 "metag_reg_nofloat_op" "da") + (match_operand:SI 1 "metag_offset6_v2sf" "O8"))) + (match_operand:V2SF 2 "metag_fpreg_op" "cx"))] + "TARGET_FPU_SIMD" + "F\\tSETL\\t[%0+%1], %2, %t2" + [(set_attr "type" "fast")]) + +(define_insn "*sto_v2sf_mem" + [(set (match_operand:V2SF 0 "memory_operand" "=m") + (match_operand:V2SF 1 "metag_datareg_op" "d"))] + "TARGET_FPU_SIMD" + "SETL\\t%0, %1, %t1\\t%@ (*sto v2sf rm OK)" + [(set_attr "type" "FPfast")]) + +; Movement instructions + +(define_insn "abs2" + [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx") + (abs: (match_operand: 1 "metag_fpreg_op" "cx")))] + "" + "F\\tABS%?\\t%0,%1" + [(set_attr "type" "FPmas") + (set_attr "predicable" "yes")]) + +;;(define_insn "*mmovsf_d_to_f" +;; [(match_parallel 0 "metag_mmov_valid" +;; [(set (match_operand:SF 1 "metag_fpreg_op" "=cx") +;; (match_operand:SF 2 "metag_datareg_op" "d" )) +;; (set (match_operand:SF 3 "metag_fpreg_op" "=cx") +;; (match_operand:SF 4 "metag_datareg_op" "d" ))])] +;; "TARGET_FPU" +;; { +;; switch (XVECLEN(operands[0], 0)) +;; { +;; case 2: +;; return "F\\tMMOV\\t%1,%3,%2,%4"; +;; case 3: +;; return "F\\tMMOV\\t%1,%3,%5,%2,%4,%6"; +;; case 4: +;; return "F\\tMMOV\\t%1,%3,%5,%7,%2,%4,%6,%8"; +;; case 5: +;; return "F\\tMMOV\\t%1,%3,%5,%7,%9,%2,%4,%6,%8,%10"; +;; case 6: +;; return "F\\tMMOV\\t%1,%3,%5,%7,%9,%11,%2,%4,%6,%8,%10,%12"; +;; case 7: +;; return "F\\tMMOV\\t%1,%3,%5,%7,%9,%11,%13,%2,%4,%6,%8,%10,%12,%14"; +;; case 8: +;; return "F\\tMMOV\\t%1,%3,%5,%7,%9,%11,%13,%15,%2,%4,%6,%8,%10,%12,%14,%16"; +;; default: +;; gcc_unreachable (); +;; } +;; }) + +(define_insn "*mov__imm" + [(set (match_operand:FMODES 0 "metag_fpreg_op" "=cx") + (match_operand: 1 "metag_fphalf_imm_op" "ci"))] + "" + "F\\tMOV\\t%0,#%h1" + [(set_attr "type" "FPfast")]) + +(define_insn "neg2" + [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx") + (neg: (match_operand: 1 "metag_fpreg_op" "cx")))] + "" + "F\\tNEG%?\\t%0,%1" + [(set_attr "type" "FPmas") + (set_attr "predicable" "yes")]) + +; TODO: PACK +; TODO: SWAP + +; Comparison Operations + +(define_expand "cmp" + [(match_operand:FMODES 0 "metag_fpreg_op" "") + (match_operand: 1 "metag_fpreg_or_imm_op" "")] + "" + { + enum machine_mode mode; + + /* These are processed via the conditional branch define_expand's later */ + metag_compare_op0 = operands[0]; + metag_compare_op1 = operands[1]; + + mode = GET_MODE (operands[1]); + + /* Have to do register to register comparison for big constants */ + if (CONST_DOUBLE_P (operands[1]) && operands[1] != CONST0_RTX (mode)) + metag_compare_op1 = force_reg (mode, operands[1]); + + DONE; + }) + +(define_insn "*cmpsf" + [(set (reg:CCFP CC_REG) + (compare:CCFP + (match_operand:SF 0 "metag_fpreg_op" "cx,cx") + (match_operand:SF 1 "metag_fpreg_or_fpzero_imm_op" "cx,G")))] + "TARGET_FPU" + "@ + F\\tCMP%?\\t%0,%1 + F\\tCMP%?\\t%0,#%h1" + [(set_attr "type" "FPfast")]) + +(define_insn "*cmpdf" + [(set (reg:CCFP CC_REG) + (compare:CCFP + (match_operand:DF 0 "metag_fpreg_op" "cx,cx") + (match_operand:DF 1 "metag_fpreg_or_fpzero_imm_op" "cx,G")))] + "TARGET_FPU && !metag_fpu_single" + "@ + FD\\tCMP%?\\t%0,%1 + FD\\tCMP%?\\t%0,#%h1" + [(set_attr "type" "FPfast")]) + +(define_insn "*abscmpsf2" + [(set (reg:CCFP CC_REG) + (compare:CCFP + (abs:SF (match_operand:SF 0 "metag_fpreg_op" "cx,cx")) + (abs:SF (match_operand:SF 1 "metag_fpreg_or_fpzero_imm_op" "cx,G"))))] + "TARGET_FPU" + "@ + FA\\tCMP%?\\t%0,%1 + FA\\tCMP%?\\t%0,#%h1" + [(set_attr "type" "FPmas")]) + +(define_insn "*abscmpdf2" + [(set (reg:CCFP CC_REG) + (compare:CCFP + (abs:DF (match_operand:DF 0 "metag_fpreg_op" "cx,cx")) + (abs:DF (match_operand:DF 1 "metag_fpreg_or_fpzero_imm_op" "cx,G"))))] + "TARGET_FPU && !metag_fpu_single" + "@ + FDA\\tCMP%?\\t%0,%1 + FDA\\tCMP%?\\t%0,#%h1" + [(set_attr "type" "FPmas") + (set_attr "predicable" "yes")]) + +(define_insn "smax3" + [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx") + (smax: (match_operand: 1 "metag_fpreg_op" "cx") + (match_operand: 2 "metag_fpreg_op" "cx"))) + (clobber (reg:CC CC_REG))] + "" + "F\\tMAX%?\\t%0,%1,%2" + [(set_attr "type" "FPmas") + (set_attr "predicable" "yes") + (set_attr "ccstate" "ccx")]) + +(define_insn "smin3" + [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx") + (smin: (match_operand: 1 "metag_fpreg_op" "cx") + (match_operand: 2 "metag_fpreg_op" "cx"))) + (clobber (reg:CC CC_REG))] + "" + "F\\tMIN%?\\t%0,%1,%2" + [(set_attr "type" "FPmas") + (set_attr "predicable" "yes") + (set_attr "ccstate" "ccx")]) + +; Data Conversion +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "metag_fpreg_op" "=cx") + (float_extend:DF (match_operand:SF 1 "metag_fpreg_op" "cx")))] + "TARGET_FPU && !metag_fpu_single" + "F\\tFTOD%?\\t%0,%1" + [(set_attr "type" "FPmas") + (set_attr "predicable" "yes")]) + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "metag_fpreg_op" "=cx") + (float_truncate:SF (match_operand:DF 1 "metag_fpreg_op" "cx")))] + "TARGET_FPU && !metag_fpu_single" + "F\\tDTOF%?\\t%0,%1" + [(set_attr "type" "FPmas") + (set_attr "predicable" "yes")]) + +;; HFmode isnt supported at the moment but the rules would be something like: +;; +;;(define_insn "truncsfhf2" +;; [(set (match_operand:HF 0 "metag_fpreg_op" "=cx") +;; (float:HF (match_operand:SF 1 "metag_fpreg_op" "cx")))] +;; "TARGET_FPU" +;; "F\\tFTOH%?\\t%0,%1" +;; ) +;; +;;(define_insn "truncdfhf2" +;; [(set (match_operand:HF 0 "metag_fpreg_op" "=cx") +;; (float:HF (match_operand:DF 1 "metag_fpreg_op" "cx")))] +;; "TARGET_FPU" +;; "F\\tDTOH%?\\t%0,%1" +;; ) + +(define_insn "fix_truncsi2" + [(set (match_operand:SI 0 "metag_fpreg_op" "=cx") + (fix:SI (match_operand:FSMODES 1 "metag_fpreg_op" "cx")))] + "" + "FZ\\tTOI%?\\t%0,%1" + [(set_attr "type" "FPmas") + (set_attr "predicable" "yes")]) + +(define_expand "fix_truncsfdi2" + [(set (match_dup 2) + (float_extend:DF (match_operand:SF 1 "metag_fpreg_op" ""))) + (set (match_operand:DI 0 "metag_fpreg_op" "") + (fix:DI (match_dup 2)))] + "TARGET_FPU && !metag_fpu_single" + { + operands[2] = gen_reg_rtx (DFmode); + }) + +(define_insn "fix_truncdfdi2" + [(set (match_operand:DI 0 "metag_fpreg_op" "=cx") + (fix:DI (match_operand:DF 1 "metag_fpreg_op" "cx")))] + "TARGET_FPU && !metag_fpu_single" + "FZ\\tDTOL%?\\t%0,%1" + [(set_attr "type" "FPmas") + (set_attr "predicable" "yes")]) + +(define_expand "fixuns_truncsfdi2" + [(set (match_operand:DI 0 "metag_fpreg_op" "") + (unsigned_fix:DI (match_operand:SF 1 "metag_fpreg_op" "")))] + "TARGET_FPU && !metag_fpu_single" + { + rtx dscr = gen_reg_rtx (SImode); + rtx fscr = gen_reg_rtx (SFmode); + rtx fscr_as_si = gen_rtx_SUBREG (SImode, fscr, 0); + rtx fscr2 = gen_reg_rtx (SFmode); + rtx fdscr = gen_reg_rtx (DFmode); + rtx rdhi = gen_rtx_SUBREG (SImode, operands[0], 4); + rtx temp_operands[1]; + + /* single precision 2^63 is 0x5F000000 */ + emit_move_insn (fscr_as_si, + gen_int_mode (0x5F000000, SImode)); + + /* Is input in 'difficult' range */ + emit_insn (gen_cmpsf (operands[1], fscr)); + gen_metag_compare (GE, temp_operands, 0); + + /* Copy input to scratch */ + emit_move_insn (fscr2, operands[1]); + + /* If it is then wrap around once (note, we dont have to + * deal with the case where it's still difficult, C doesnt define + * overflow behaviour */ + emit_insn (gen_rtx_SET (VOIDmode, fscr2, + gen_rtx_IF_THEN_ELSE (SFmode, + gen_rtx_GE (VOIDmode, temp_operands[0], + const0_rtx), + gen_rtx_MINUS (SFmode, operands[1], + fscr), + fscr2))); + + /* Extend to double before DI conversion */ + emit_insn (gen_rtx_SET (DFmode, fdscr, + gen_rtx_FLOAT_EXTEND (DFmode, fscr2))); + + /* Convert to DI */ + emit_insn (gen_rtx_SET (DImode, operands[0], + gen_rtx_FIX (DImode, fdscr))); + + /* Restore truncated value from earlier */ + emit_insn (gen_rtx_SET (SImode, dscr, + gen_int_mode (0x80000000, SImode))); + emit_insn (gen_rtx_SET (VOIDmode, rdhi, + gen_rtx_IF_THEN_ELSE (SImode, + gen_rtx_GE (VOIDmode, temp_operands[0], + const0_rtx), + gen_rtx_PLUS (SImode, rdhi, + dscr), + rdhi))); + DONE; + + }) + +(define_expand "fixuns_truncdfdi2" + [(set (match_operand:DI 0 "metag_fpreg_op" "") + (unsigned_fix:DI (match_operand:DF 1 "metag_fpreg_op" "")))] + "TARGET_FPU && !metag_fpu_single" + { + rtx dscr = gen_reg_rtx (SImode); + rtx fscr = gen_reg_rtx (DFmode); + rtx fscrlo_as_si = gen_rtx_SUBREG (SImode, fscr, 0); + rtx fscrhi_as_si = gen_rtx_SUBREG (SImode, fscr, 4); + rtx fdscr = gen_reg_rtx (DFmode); + rtx rdhi = gen_rtx_SUBREG (SImode, operands[0], 4); + rtx temp_operands[1]; + + /* double precision 2^63 is 0x43e00000 00000000*/ + emit_move_insn (fscrhi_as_si, + gen_int_mode (0x43e00000, SImode)); + emit_move_insn (fscrlo_as_si, const0_rtx); + + /* Is input in 'difficult' range */ + emit_insn (gen_cmpdf (operands[1], fscr)); + gen_metag_compare (GE, temp_operands, 0); + + /* Copy input to scratch */ + emit_move_insn (fdscr, operands[1]); + + /* If it is then wrap around once (note, we dont have to + * deal with the case where it's still difficult, C doesnt define + * overflow behaviour */ + emit_insn (gen_rtx_SET (VOIDmode, fdscr, + gen_rtx_IF_THEN_ELSE (DFmode, + gen_rtx_GE (VOIDmode, temp_operands[0], + const0_rtx), + gen_rtx_MINUS (DFmode, operands[1], + fscr), + fdscr))); + + /* Convert to DI */ + emit_insn (gen_rtx_SET (DImode, operands[0], + gen_rtx_FIX (DImode, fdscr))); + + /* Restore truncated value from earlier */ + emit_insn (gen_rtx_SET (SImode, dscr, + gen_int_mode (0x80000000, SImode))); + emit_insn (gen_rtx_SET (VOIDmode, rdhi, + gen_rtx_IF_THEN_ELSE (SImode, + gen_rtx_GE (VOIDmode, temp_operands[0], + const0_rtx), + gen_rtx_PLUS (SImode, rdhi, + dscr), + rdhi))); + + DONE; + + }) + +(define_expand "fixuns_truncsfsi2" + [(set (match_operand:SI 0 "metag_fpreg_op" "") + (unsigned_fix:SI (match_operand:SF 1 "metag_fpreg_op" "")))] + "TARGET_FPU && metag_fpu_single" + { + if (metag_fpu_single) + { + rtx dscr = gen_reg_rtx (SImode); + rtx fscr = gen_reg_rtx (SFmode); + rtx fscr_as_si = gen_rtx_SUBREG (SImode, fscr, 0); + rtx fscr2 = gen_reg_rtx (SFmode); + rtx temp_operands[1]; + + /* single precision 2^31 is 0x4F000000 */ + emit_move_insn (fscr_as_si, + gen_int_mode (0x4f000000, SImode)); + + /* Is input in 'difficult' range */ + emit_insn (gen_cmpsf (operands[1], fscr)); + gen_metag_compare (GE, temp_operands, 0); + + /* Copy input to scratch */ + emit_move_insn (fscr2, operands[1]); + + /* If it is then wrap around once (note, we dont have to + * deal with the case where it's still difficult, C doesnt define + * overflow behaviour */ + emit_insn (gen_rtx_SET (VOIDmode, fscr2, + gen_rtx_IF_THEN_ELSE (SFmode, + gen_rtx_GE (VOIDmode, temp_operands[0], + const0_rtx), + gen_rtx_MINUS (SFmode, operands[1], + fscr), + fscr2))); + + /* Convert to SI */ + emit_insn (gen_rtx_SET (SImode, operands[0], + gen_rtx_FIX (SImode, fscr2))); + + /* Restore truncated value from earlier */ + emit_insn (gen_rtx_SET (SImode, dscr, + gen_int_mode (0x80000000, SImode))); + emit_insn (gen_rtx_SET (VOIDmode, operands[0], + gen_rtx_IF_THEN_ELSE (SImode, + gen_rtx_GE (VOIDmode, temp_operands[0], + const0_rtx), + gen_rtx_PLUS (SImode, operands[0], + dscr), + operands[0]))); + + DONE; + } + else + { + rtx op2 = gen_reg_rtx (DFmode); + rtx op3 = gen_reg_rtx (DImode); + + emit_insn (gen_extendsfdf2 (op2, operands[1])); + emit_insn (gen_fix_truncdfdi2 (op3, op2)); + emit_move_insn (operands[0], gen_rtx_SUBREG (SImode, op3, 0)); + DONE; + } + + }) + + +; DTOX, FTOX, DTOXL not supported +(define_insn "floatsi2" + [(set (match_operand:FSMODES 0 "metag_fpreg_op" "=cx") + (float: (match_operand:SI 1 "metag_fpreg_op" "cx")))] + "" + "F\\tITO%?\\t%0,%1" + [(set_attr "type" "FPmas") + (set_attr "predicable" "yes")]) + +(define_expand "floatdisf2" + [(set (match_dup 2) + (float:DF (match_operand:DI 1 "metag_fpreg_op" ""))) + (set (match_operand:SF 0 "metag_fpreg_op" "") + (float_truncate:SF (match_dup 2)))] + "TARGET_FPU && !metag_fpu_single" + { + operands[2] = gen_reg_rtx (DFmode); + }) + +(define_insn "floatdidf2" + [(set (match_operand:DF 0 "metag_fpreg_op" "=cx") + (float:DF (match_operand:DI 1 "metag_fpreg_op" "cx")))] + "TARGET_FPU && !metag_fpu_single" + "F\\tLTOD%?\\t%0,%1" + [(set_attr "type" "FPmas") + (set_attr "predicable" "yes")]) + +(define_expand "floatunshi2" + [(set (match_dup:SI 2) + (zero_extend:SI (match_operand:HI 1 "metag_reg_nofloat_op" ""))) + (set (match_operand:FMODES 0 "metag_fpreg_op" "") + (float: (match_dup 2)))] + "" + { + operands[2] = gen_reg_rtx (SImode); + }) + +(define_expand "floatunssidf2" + [(set (match_dup 2) + (zero_extend:DI (match_operand:SI 1 "metag_register_op" ""))) + (set (match_operand:DF 0 "metag_fpreg_op" "") + (float:DF (match_dup 2)))] + "TARGET_FPU && !metag_fpu_single" + { + operands[2] = gen_reg_rtx (DImode); + }) + +(define_expand "floatunsdidf2" + [(set (match_operand:DF 0 "metag_fpreg_op" "") + (unsigned_float:DF (match_operand:DI 1 "metag_register_op" "")))] + "TARGET_FPU && !metag_fpu_single" + { + metag_expand_didf2 (operands[0], operands[1]); + DONE; + }) + +(define_expand "floatunsdisf2" + [(set (match_dup 2) + (unsigned_float:DF (match_operand:DI 1 "metag_register_op" ""))) + (set (match_operand:SF 0 "metag_fpreg_op" "") + (float_truncate:SF (match_dup 2)))] + "TARGET_FPU && !metag_fpu_single" + { + operands[2] = gen_reg_rtx (DFmode); + + metag_expand_didf2 (operands[2], operands[1]); + + emit_insn (gen_truncdfsf2 (operands[0], operands[2])); + DONE; + }) + +(define_expand "floatunssisf2" + [(set (match_operand:SF 0 "metag_fpreg_op" "") + (unsigned_float:SF (match_operand:SI 1 "metag_register_op" "")))] + "TARGET_FPU && metag_fpu_single" + { + if (metag_fpu_single) + { + rtx dscr = gen_reg_rtx (SImode); + rtx fscr2 = gen_reg_rtx (SFmode); + rtx fscr2_as_si = gen_rtx_SUBREG (SImode, fscr2, 0); + rtx temp_operands[1]; + + /* Test to see if rs is in the difficult range (> 2^31) */ + emit_move_insn (dscr, operands[1]); + metag_compare_op0 = gen_rtx_AND (SImode, dscr, + gen_int_mode (0x80000000, SImode)); + metag_compare_op1 = const0_rtx; + gen_metag_compare (NE, temp_operands, 0); + + /* Drop the 2^31 component */ + emit_insn (gen_andsi3 (dscr, dscr, + gen_int_mode (0x7fffffff, SImode))); + + /* Convert to single */ + emit_insn (gen_floatsisf2 (operands[0], dscr)); + + /* Prepare 2^31 in single precision */ + emit_move_insn (fscr2_as_si, + gen_int_mode (0x4f000000, SImode)); + + /* Add on the missing 2^31 if requried */ + emit_insn (gen_rtx_SET (VOIDmode, operands[0], + gen_rtx_IF_THEN_ELSE (SFmode, + gen_rtx_NE (VOIDmode, temp_operands[0], + const0_rtx), + gen_rtx_PLUS (SFmode, operands[0], fscr2), + operands[0]))); + + DONE; + } + else + { + rtx op2 = gen_reg_rtx (DImode); + rtx op3 = gen_reg_rtx (DFmode); + + emit_insn (gen_zero_extendsidi2 (op2, operands[1])); + emit_insn (gen_floatdidf2 (op3, op2)); + emit_insn (gen_truncdfsf2 (operands[0], op3)); + DONE; + } + }) + +; Basic Arithmetic +; SFmode +(define_insn "add3" + [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx") + (plus: (match_operand: 1 "metag_fpreg_op" "cx") + (match_operand: 2 "metag_fpreg_op" "cx")))] + "" + "F\\tADD%?\\t%0,%1,%2" + [(set_attr "type" "FPmas") + (set_attr "predicable" "yes")]) + +(define_insn "*add_if__cxcxcxcx" + [(set (match_operand:FMODES 0 "metag_fpreg_op" "=cx") + (if_then_else:FMODES (match_operator 1 "comparison_operator" + [(match_operand:CCALL 2 "metag__reg" "") + (const_int 0)]) + (plus:FMODES (match_operand:FMODES 3 "metag_fpreg_op" "cx") + (match_operand:FMODES 4 "metag_fpreg_op" "cx")) + (match_operand:FMODES 5 "metag_fpreg_op" "0")))] + "" + "F\\tADD%z1\\t%0,%3,%4" + [(set_attr "type" "FPmas") + (set_attr "ccstate" "xcc")]) + +(define_insn "*nadd3" + [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx") + (neg: + (plus: (match_operand: 1 "metag_fpreg_op" "cx") + (match_operand: 2 "metag_fpreg_op" "cx"))))] + "" + "FI\\tADD%?\\t%0,%1,%2" + [(set_attr "type" "FPmas") + (set_attr "predicable" "yes")]) + +(define_insn "mul3" + [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx") + (mult: (match_operand: 1 "metag_fpreg_op" "cx") + (match_operand: 2 "metag_fpreg_op" "cx")))] + "" + "F\\tMUL%?\\t%0,%1,%2" + [(set_attr "type" "FPmas") + (set_attr "predicable" "yes")]) + +(define_insn "*nmul3" + [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx") + (neg: + (mult: (match_operand: 1 "metag_fpreg_op" "cx") + (match_operand: 2 "metag_fpreg_op" "cx"))))] + "" + "FI\\tMUL%?\\t%0,%1,%2" + [(set_attr "type" "FPmas") + (set_attr "predicable" "yes")]) + +(define_insn "sub3" + [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx") + (minus: (match_operand: 1 "metag_fpreg_op" "cx") + (match_operand: 2 "metag_fpreg_op" "cx")))] + "" + "F\\tSUB%?\\t%0,%1,%2" + [(set_attr "type" "FPmas") + (set_attr "predicable" "yes")]) + +(define_insn "*sub_if__cxcxcxcx" + [(set (match_operand:FMODES 0 "metag_fpreg_op" "=cx") + (if_then_else:FMODES (match_operator 1 "comparison_operator" + [(match_operand:CCALL 2 "metag__reg" "") + (const_int 0)]) + (minus:FMODES (match_operand:FMODES 3 "metag_fpreg_op" "cx") + (match_operand:FMODES 4 "metag_fpreg_op" "cx")) + (match_operand:FMODES 5 "metag_fpreg_op" "0")))] + "" + "F\\tSUB%z1\\t%0,%3,%4" + [(set_attr "type" "FPmas") + (set_attr "ccstate" "xcc")]) + +(define_insn "*nsub3" + [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx") + (neg: + (minus: (match_operand: 1 "metag_fpreg_op" "cx") + (match_operand: 2 "metag_fpreg_op" "cx"))))] + "" + "FI\\tSUB%?\\t%0,%1,%2" + [(set_attr "type" "FPmas") + (set_attr "predicable" "yes")]) + + +; Extended Floating Point Insn's +; SFmode + +; TODO MUZ +(define_insn "*muladd3_fused" + [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx") + (plus: + (mult: (match_operand: 1 "metag_fpreg_op" "cx") + (match_operand: 2 "metag_fpreg_op" "cx")) + (match_operand: 3 "metag_fpreg_op" "0")))] + "" + "F\\tMUZ\\t%0,%1,%2" + [(set_attr "type" "FPmas")]) + +(define_insn "*muladd13_fused" + [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx") + (plus: + (mult: (match_operand: 1 "metag_fpreg_op" "cx") + (match_operand: 2 "metag_fpreg_op" "cx")) + (match_operand: 3 "metag_fpone_imm_op" "H")))] + "" + "F\\tMUZ1\\t%0,%1,%2" + [(set_attr "type" "FPmas")]) + +(define_insn "*mulsub3_fused" + [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx") + (minus: + (mult: (match_operand: 1 "metag_fpreg_op" "cx") + (match_operand: 2 "metag_fpreg_op" "cx")) + (match_operand: 3 "metag_fpreg_op" "0")))] + "" + "F\\tMUZS\\t%0,%1,%2" + [(set_attr "type" "FPmas")]) + +(define_insn "*mulsub13_fused" + [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx") + (minus: + (mult: (match_operand: 1 "metag_fpreg_op" "cx") + (match_operand: 2 "metag_fpreg_op" "cx")) + (match_operand: 3 "metag_fpone_imm_op" "H")))] + "" + "F\\tMUZS1\\t%0,%1,%2" + [(set_attr "type" "FPmas")]) + +(define_insn "*nmuladd3_fused" + [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx") + (neg: + (plus: + (mult: (match_operand: 1 "metag_fpreg_op" "cx") + (match_operand: 2 "metag_fpreg_op" "cx")) + (match_operand: 3 "metag_fpreg_op" "0"))))] + "" + "FI\\tMUZ\\t%0,%1,%2" + [(set_attr "type" "FPmas")]) + +(define_insn "*nmuladd13_fused" + [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx") + (neg: + (plus: + (mult: (match_operand: 1 "metag_fpreg_op" "cx") + (match_operand: 2 "metag_fpreg_op" "cx")) + (match_operand: 3 "metag_fpone_imm_op" "H"))))] + "" + "FI\\tMUZ1\\t%0,%1,%2" + [(set_attr "type" "FPmas")]) + +(define_insn "*nmulsub3_fused" + [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx") + (neg: + (minus: + (mult: (match_operand: 1 "metag_fpreg_op" "cx") + (match_operand: 2 "metag_fpreg_op" "cx")) + (match_operand: 3 "metag_fpreg_op" "0"))))] + "" + "FI\\tMUZS\\t%0,%1,%2" + [(set_attr "type" "FPmas")]) + +(define_insn "*nmulsub13_fused" + [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx") + (neg: + (minus: + (mult: (match_operand: 1 "metag_fpreg_op" "cx") + (match_operand: 2 "metag_fpreg_op" "cx")) + (match_operand: 3 "metag_fpone_imm_op" "H"))))] + "" + "FI\\tMUZS1\\t%0,%1,%2" + [(set_attr "type" "FPmas")]) + +;; Divides etc + +(define_expand "divsf3" + [(set (match_operand:SF 0 "metag_fpreg_op" "") + (div:SF (match_operand:SF 1 "metag_fpreg_op" "") + (match_operand:SF 2 "metag_fpreg_op" "")))] + "TARGET_FPU && TARGET_FAST_MATH" + { + }) + +(define_expand "divdf3" + [(set (match_operand:DF 0 "metag_fpreg_op" "") + (div:DF (match_dup 3) + (match_operand:DF 2 "metag_fpreg_op" ""))) + (set (match_dup 4) + (neg:DF (minus:DF (mult:DF (match_dup 2) + (match_dup 0)) + (match_dup 3)))) + (set (match_dup 0) + (plus:DF (mult:DF (match_dup 4) + (match_dup 0)) + (match_dup 0))) + (set (match_dup 0) + (mult:DF (match_operand:DF 1 "metag_fpreg_op" "") + (match_dup 0)))] + "TARGET_FPU && !metag_fpu_single && TARGET_FAST_MATH" + { + operands[3] = CONST1_RTX (DFmode); + operands[4] = gen_reg_rtx (DFmode); + }) + +(define_insn_and_split "*div2_fast" + [(set (match_operand:FMODES 0 "metag_fpreg_op" "=&cx") + (div: (match_operand: 1 "metag_fpreg_op" "cx") + (match_operand: 2 "metag_fpreg_op" "cx")))] + " && TARGET_FAST_MATH" + "#" + "&& 1" + [(const_int 0)] + { + emit_insn (gen_rcp2 (operands[0], CONST1_RTX (mode), operands[2])); + emit_insn (gen_mul3 (operands[0], operands[0], operands[1])); + DONE; + } + [(set_attr "type" "FPrecipmas")]) + +(define_insn "rcp2" + [(set (match_operand:FMODES 0 "metag_fpreg_op" "=cx") + (div: (match_operand: 1 "metag_fpone_imm_op" "H") + (match_operand: 2 "metag_fpreg_op" "cx")))] + " && TARGET_FAST_MATH" + { + if (TARGET_FLUSH_TO_ZERO) + return "FZ\\tRCP\\t%0,%2"; + else + return "F\\tRCP\\t%0,%2"; + } + [(set_attr "type" "FPrecip")]) + +(define_insn "*rsq2" + [(set (match_operand:FMODES 0 "metag_fpreg_op" "=cx") + (div: (match_operand: 1 "metag_fpone_imm_op" "H") + (sqrt: (match_operand: 2 "metag_fpreg_op" "cx"))))] + " && TARGET_FAST_MATH" + { + if (TARGET_FLUSH_TO_ZERO) + return "FZ\\tRSQ\\t%0,%2"; + else + return "F\\tRSQ\\t%0,%2"; + } + [(set_attr "type" "FPrecip")]) + +; ADDRE, MULRE, and SUBRE need vector modes +; Memory operations all use core instrutions with U[sd]=9 diff -Nur gcc-4.2.4.orig/gcc/config/metag/lib1funcs.asm gcc-4.2.4/gcc/config/metag/lib1funcs.asm --- gcc-4.2.4.orig/gcc/config/metag/lib1funcs.asm 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/lib1funcs.asm 2015-07-03 18:46:05.749283542 -0500 @@ -0,0 +1,2740 @@ +/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 + Imagination Technologies Ltd + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +. */ + +/* As a special exception, if you link this library with other files, + some of which are compiled with GCC, to produce an executable, + this library does not by itself cause the resulting executable + to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. */ + +!! libgcc1 routines for META cpu. +!! Contributed by Metagence Technologies (toolkit@metagence.com) + +!! Division routines + +#ifdef L_udivsi3 +!! +!! 32-bit division unsigned i/p - passed unsigned 32-bit numbers +!! + .text + .global ___udivsi3 + .type ___udivsi3,function + .align 2 +___udivsi3: +!! +!! Since core is signed divide case, just set control variable +!! + MOV D1Re0,D0Ar2 ! Au already in A1Ar1, Bu -> D1Re0 + MOV D0Re0,#0 ! Result is 0 + MOV D0Ar4,#0 ! Return positive result + B __IDMCUStart + .size ___udivsi3,.-___udivsi3 +#endif + +#ifdef L_divsi3 +!! +!! 32-bit division signed i/p - passed signed 32-bit numbers +!! + .text + .global ___divsi3 + .type ___divsi3,function + .align 2 +___divsi3: +!! +!! A already in D1Ar1, B already in D0Ar2 -> make B abs(B) +!! + MOV D1Re0,D0Ar2 ! A already in A1Ar1, B -> D1Re0 + MOV D0Re0,#0 ! Result is 0 + XOR D0Ar4,D1Ar1,D1Re0 ! D0Ar4 -ive if result is -ive + ABS D1Ar1,D1Ar1 ! abs(A) -> Au + ABS D1Re0,D1Re0 ! abs(B) -> Bu + .global __IDMCUStart + .hidden __IDMCUStart +__IDMCUStart: + CMP D1Ar1,D1Re0 ! Is ( Au > Bu )? + LSR D1Ar3,D1Ar1,#2 ! Calculate (Au & (~3)) >> 2 + CMPHI D1Re0,D1Ar3 ! OR ( (Au & (~3)) <= (Bu << 2) )? + LSLSHI D1Ar3,D1Re0,#1 ! Buq = Bu << 1 + BLS $IDMCUSetup ! Yes: Do normal divide +!! +!! Quick divide setup can assume that CurBit only needs to start at 2 +!! +$IDMCQuick: + CMP D1Ar1,D1Ar3 ! ( A >= Buq )? + ADDCC D0Re0,D0Re0,#2 ! If yes result += 2 + SUBCC D1Ar1,D1Ar1,D1Ar3 ! and A -= Buq + CMP D1Ar1,D1Re0 ! ( A >= Bu )? + ADDCC D0Re0,D0Re0,#1 ! If yes result += 1 + SUBCC D1Ar1,D1Ar1,D1Re0 ! and A -= Bu + ORS D0Ar4,D0Ar4,D0Ar4 ! Return neg result? + NEG D0Ar2,D0Re0 ! Calulate neg result + MOVMI D0Re0,D0Ar2 ! Yes: Take neg result +$IDMCRet: + MOV PC,D1RtP +!! +!! Setup for general unsigned divide code +!! +!! D0Re0 is used to form the result, already set to Zero +!! D1Re0 is the input Bu value, this gets trashed +!! D0Ar6 is curbit which is set to 1 at the start and shifted up +!! D0Ar4 is negative if we should return a negative result +!! D1Ar1 is the input Au value, eventually this holds the remainder +!! +$IDMCUSetup: + CMP D1Ar1,D1Re0 ! Is ( Au < Bu )? + MOV D0Ar6,#1 ! Set curbit to 1 + BCS $IDMCRet ! Yes: Return 0 remainder Au +!! +!! Calculate alignment using FFB instruction +!! + FFB D1Ar5,D1Ar1 ! Find first bit of Au + ANDN D1Ar5,D1Ar5,#31 ! Handle exceptional case. + ORN D1Ar5,D1Ar5,#31 ! if N bit set, set to 31 + FFB D1Ar3,D1Re0 ! Find first bit of Bu + ANDN D1Ar3,D1Ar3,#31 ! Handle exceptional case. + ORN D1Ar3,D1Ar3,#31 ! if N bit set, set to 31 + SUBS D1Ar3,D1Ar5,D1Ar3 ! calculate diff, ffbA - ffbB + MOV D0Ar2,D1Ar3 ! copy into bank 0 + LSLGT D1Re0,D1Re0,D1Ar3 ! ( > 0) ? left shift B + LSLGT D0Ar6,D0Ar6,D0Ar2 ! ( > 0) ? left shift curbit +!! +!! Now we start the divide proper, logic is +!! +!! if ( A >= B ) add curbit to result and subtract B from A +!! shift curbit and B down by 1 in either case +!! +$IDMCLoop: + CMP D1Ar1, D1Re0 ! ( A >= B )? + ADDCC D0Re0, D0Re0, D0Ar6 ! If yes result += curbit + SUBCC D1Ar1, D1Ar1, D1Re0 ! and A -= B + LSRS D0Ar6, D0Ar6, #1 ! Shift down curbit, is it zero? + LSR D1Re0, D1Re0, #1 ! Shift down B + BNZ $IDMCLoop ! Was single bit in curbit lost? + ORS D0Ar4,D0Ar4,D0Ar4 ! Return neg result? + NEG D0Ar2,D0Re0 ! Calulate neg result + MOVMI D0Re0,D0Ar2 ! Yes: Take neg result + MOV PC,D1RtP + .size ___divsi3,.-___divsi3 +#endif + +!! Modulus routines + +#ifdef L_umodsi3 +!! +!! 32-bit modulus unsigned i/p - passed unsigned 32-bit numbers +!! + .text + .global ___umodsi3 + .type ___umodsi3,function + .align 2 +___umodsi3: +#ifdef __PIC__ + SETL [A0StP++],D0FrT,D1RtP ! Save return address + CALLR D1RtP,___udivsi3@PLT + GETL D0FrT,D1RtP,[--A0StP] ! Recover return address +#else + MOV D0FrT,DRtP ! Save original return address + CALLR D1RtP,___udivsi3 + MOV D1RtP,D0FrT ! Recover return address +#endif + MOV D0Re0,D1Ar1 ! Return remainder + MOV PC,D1RtP + .size ___umodsi3,.-___umodsi3 +#endif + +#ifdef L_modsi3 +!! +!! 32-bit modulus signed i/p - passed signed 32-bit numbers +!! + .text + .global ___modsi3 + .type ___modsi3,function + .align 2 +___modsi3: +#ifdef __PIC__ + MOV D0.4,D1Ar1 + SETL [A0StP++],D0.4,D1RtP ! Save A and return address + CALLR D1RtP,___divsi3@PLT + GETL D0.4,D1RtP,[--A0StP] ! Recover A and return address + MOV D1Re0,D0.4 +#else + MOV D0FrT,D1RtP ! Save original return address + MOV A0.2,D1Ar1 ! Save A in A0.2 + CALLR D1RtP,___divsi3 + MOV D1RtP,D0FrT ! Recover return address + MOV D1Re0,A0.2 ! Recover A +#endif + MOV D0Re0,D1Ar1 ! Return remainder + ORS D1Re0,D1Re0,D1Re0 ! Was A negative? + NEG D1Ar1,D1Ar1 ! Negate remainder + MOVMI D0Re0,D1Ar1 ! Return neg remainder + MOV PC, D1RtP + .size ___modsi3,.-___modsi3 +#endif + +!! Floating point support routines + +#ifdef L_adddf3 +!! +!! Floating point - double add +!! + .text + .global ___adddf3 + .type ___adddf3,function + .align 2 +___adddf3: + AND D1Re0, D1Ar1, D1Ar3 + ANDT D1Re0, D1Re0, #0x8000 ! sign1 & sign2 + + LSL D0Re0, D1Ar1, #1 ! Ignore sign + ORS D0Re0, D0Re0, D0Ar2 ! Zero? + + LSL D0Re0, D1Ar3, #1 ! Ignore sign + ORSZ D0Re0, D0Re0, D0Ar4 ! Zero + + MOVZ PC, D1RtP ! both zero return +/-Zero + + LSL D0Re0, D1Ar1, #1 ! Ignore sign + ORS D0Re0, D0Re0, D0Ar2 ! Zero? + + MOVZ D0Re0, D0Ar4 + MOVZ D1Re0, D1Ar3 + MOVZ PC, D1RtP ! Arg1 zero return Arg2 + + LSL D0Re0, D1Ar3, #1 ! Ignore sign + ORS D0Re0, D0Re0, D0Ar4 ! Zero? + + MOVZ D1Re0, D1Ar1 + MOVZ D0Re0, D0Ar2 + MOVZ PC, D1RtP ! Arg2 zero return Arg1 + + MOV D1Ar5, D1Ar1 + ANDMT D1Ar5, D1Ar5, #0x7FFF + LSR D1Ar5, D1Ar5, #20 ! exp1 + + MOV D0Ar6, D1Ar3 + ANDMT D0Ar6, D0Ar6, #0x7FFF + LSR D0Ar6, D0Ar6, #20 ! exp2 + + MOV D0Re0, D1Ar5 + SUBS D1Re0, D0Re0, D0Ar6 ! exp = exp1 - exp2 ---> D1Re0 + BGE $L2 + + SWAP D0Re0, D1Ar3 ! mant1 <-> mant2 + SWAP D0Re0, D1Ar1 + SWAP D0Re0, D1Ar3 + + SWAP D1Re0, D0Ar4 + SWAP D1Re0, D0Ar2 + SWAP D1Re0, D0Ar4 + + SWAP D0Ar6, D1Ar5 ! exp1 <-> exp2 + NEG D1Re0, D1Re0 ! exp = -exp + +$L2: + CMP D1Re0, #54 + BLE $L3 + + MOV D1Re0, D1Ar1 + MOV D0Re0, D0Ar2 + + MOV PC, D1RtP + +$L3: + SWAP D1Re0, D0Re0 + + ADDS D1Ar1, D1Ar1, #0 + ANDMT D1Ar1, D1Ar1, #0x000F + ORT D1Ar1, D1Ar1, #0x0010 + LSL D1Ar1, D1Ar1, #9 + + LSR D1Re0, D0Ar2, #23 + OR D1Ar1, D1Ar1, D1Re0 + LSL D0Ar2, D0Ar2, #9 ! man1 <<= 9 ---> D1Ar1:D0Ar2 + + BGE $L4 + + NEGS D0Ar2, D0Ar2 + NEG D1Ar1, D1Ar1 + SUBNZ D1Ar1, D1Ar1, #1 ! man1 D1Ar1:D0Ar2 + +$L4: + ADDS D1Ar3, D1Ar3, #0 + ANDMT D1Ar3, D1Ar3, #0x000F + ORT D1Ar3, D1Ar3, #0x0010 + LSL D1Ar3, D1Ar3, #9 + + LSR D1Re0, D0Ar4, #23 + OR D1Ar3, D1Ar3, D1Re0 + LSL D0Ar4, D0Ar4, #9 ! man2 <<= 9 --->D1Ar3, D0Ar4 + + BGE $L5 + + NEGS D0Ar4, D0Ar4 + NEG D1Ar3, D1Ar3 + SUBNZ D1Ar3, D1Ar3, #1 ! man2 D1Ar3:D0Ar4 + +$L5: + SWAP D1Re0, D0Re0 + CMP D1Re0, #32 ! ought to consider 32 <= exp1 - exp2 <64 + BGE $L6 + + CMP D1Re0, #0 ! Zero is a special case + BZ $L7 + + MOV D0Re0, D1Re0 + NEG D0Re0, D0Re0 + ADD D0Re0, D0Re0, #32 ! 32 + (- (exp1 - exp2)) + ! man2 D1Ar3:D0Ar4 + MOV D0Ar6, D1Re0 ! man2 >> exp1 - exp2 + LSR D0Ar4, D0Ar4, D0Ar6 + MOV D0Ar6, D1Ar3 + LSL D0Ar6, D0Ar6, D0Re0 + OR D0Ar4, D0Ar4, D0Ar6 + ASR D1Ar3, D1Ar3, D1Re0 + B $L7 + +$L6: ! exp >= 32 + SUB D1Re0, D1Re0, #32 + ASRS D0Ar4, D1Ar3, D1Re0 ! man2 >>= exp + MOV D1Ar3, #-1 + ADDGE D1Ar3, D1Ar3, #1 + +$L7: ! man (D1Re0:D1Re0) + ADDS D0Re0, D0Ar2, D0Ar4 ! man = man1 + man2 + ADD D1Re0, D1Ar1, D1Ar3 + ADDCS D1Re0, D1Re0, #1 + + MOV D0Ar6, #0 ! assume sign +ve + + CMP D1Re0, #0 ! man < 0 ? + BGT $L9 + BLT $L8 + + CMP D0Re0, #0 + + MOVZ PC, D1RtP ! man == 0 return 0 + +$L8: + CMP D1Re0, #0 ! man < 0 + BZ $L9 ! treat D1Re0 0 as positive + + MOVT D0Ar6, #0x8000 ! sign -ve + + ! man D1Re0:D0Re0 + NEGS D0Re0, D0Re0 ! man = -man + NEG D1Re0, D1Re0 + SUBNZ D1Re0, D1Re0, #1 + +$L9: ! man +ve + NORM D1Ar1, D1Re0 + BZ $L10 ! MSword zero + + CMP D1Ar1, #0 ! Already normalised ? + BZ $L11 ! yes, skip normlisation + + MOV D0Ar2, D1Re0 ! Shifting < 32 bits + FFB D0Ar2, D0Ar2 + + LSL D1Re0, D1Re0, D1Ar1 ! MSWord + ADD D0Ar2, D0Ar2, #2 + LSR D1Ar3, D0Re0, D0Ar2 + OR D1Re0, D1Re0, D1Ar3 + + MOV D0Ar2, D1Ar1 + LSL D0Re0, D0Re0, D0Ar2 ! LSWord + + SUB D1Ar5, D1Ar5, D1Ar1 ! exp -= NORM (man) + B $L11 + +$L10: ! Shifting >= 32 bits + MOVS D1Re0, D0Re0 ! Shift by 32 bits. + SUBGT D0Re0, D0Re0, D0Re0 + + LSRLT D1Re0, D1Re0, #1 ! If the results has MSBit set the + LSLLT D0Re0, D0Re0, #31 ! we must only shift by 31 bits so + ! we dont use NORM on a neg value. + + SUBLT D1Ar5, D1Ar5, #31 ! adjust exponent + SUBGE D1Ar5, D1Ar5, #32 + + NORM D1Ar1, D1Re0 + + + NEG D0Ar4, D1Ar1 ! (32 - D1Ar1) + ADD D0Ar4, D0Ar4, #32 + + LSR D0Ar4, D0Re0, D0Ar4 + MOV D0Ar2, D1Ar1 + LSL D0Re0, D0Re0, D0Ar2 + OR D0Re0, D0Re0, D0Ar4 + LSL D1Re0, D1Re0, D1Ar1 + + SUB D1Ar5, D1Ar5, D1Ar1 ! exp -= NORM (man) + +$L11: + ADD D1Ar5, D1Ar5, #(10-9) + + TST D0Re0, #(1<<10) + BZ $L12 + + ADDS D0Re0, D0Re0, #1 ! man += 1 + ADDCS D1Re0, D1Re0, #1 + +$L12: + ADDS D0Re0, D0Re0, #((1<<9)-1) + ADDCS D1Re0, D1Re0, #1 + + TSTT D1Re0, #0x8000 ! rounding overflowed? + BZ $L14 + + ! adjust man and exp + LSR D0Re0, D0Re0, #1 ! man >>= 1 + LSL D0Ar2, D1Re0, #(32-1) + LSR D1Re0, D1Re0, #1 + OR D0Re0, D0Re0, D0Ar2 + + ADD D1Ar5, D1Ar5, #1 ! exp += 1 + +$L14: + CMP D1Ar5, #0 ! exp <= 0 ? + SUBLE D0Re0, D0Re0, D0Re0 ! underflow + MOVLE D1Re0, D1Ar3 + MOVLE PC, D1RtP ! return +/-Zero + + LSR D0Re0, D0Re0, #10 + LSL D0Ar4, D1Re0, #(32-10) + OR D0Re0, D0Re0, D0Ar4 + LSR D1Re0, D1Re0, #10 ! man >>= 10 + + ANDMT D1Re0, D1Re0, #0x000F + LSL D1Ar5, D1Ar5, #(52 - 32) ! position exp + MOV D1Ar3, D0Ar6 + OR D1Ar5, D1Ar5, D1Ar3 ! sign|exp + OR D1Re0, D1Re0, D1Ar5 ! man|exp|sign -> D1Re0, D0Re0 + + MOV PC, D1RtP + .size ___adddf3,.-___adddf3 +#endif + +#ifdef L_addsf3 +!! +!! Floating point - float add +!! + .text + .global ___addsf3 + .type ___addsf3,function + .align 2 +___addsf3: + MOV D1Re0, D0Ar2 + AND D1Re0, D1Re0, D1Ar1 + ANDT D1Re0, D1Re0, #0x8000 ! sign = sign1 & sign2 + + LSLS D0Re0, D1Ar1, #1 ! Ignore sign bit + LSL D0Re0, D0Ar2, #1 + ORSZ D0Re0, D0Re0, D0Re0 + + MOVZ D0Re0, D1Re0 ! sign = sign1 & sign2 + MOVZ PC, D1RtP ! both zero return +/-Zero + + LSLS D0Re0, D1Ar1, #1 ! Ignore sign bit + MOVZ D0Re0, D0Ar2 + MOVZ PC, D1RtP ! Arg1 zero return Arg2 + + LSLS D0Re0, D0Ar2, #1 ! Ignore sign bit + MOVZ D0Re0, D1Ar1 + MOVZ PC, D1RtP ! Arg2 zero return Arg1 + + MOV D1Ar5, D1Ar1 + ANDMT D1Ar5, D1Ar5, #0x7FFF + LSR D1Ar5, D1Ar5, #23 ! exp1 + + MOV D1Ar3, D0Ar2 + ANDMT D1Ar3, D1Ar3, #0x7FFF + LSR D1Ar3, D1Ar3, #23 ! exp2 + + SUB D0Re0, D1Ar5, D1Ar3 ! exp1 - exp2 + CMP D0Re0, #25 ! >25 + + MOVGT D0Re0, D1Ar1 + MOVGT PC, D1RtP + + CMP D0Re0, #-25 ! <-25 + + MOVLT D0Re0, D0Ar2 + MOVLT PC, D1RtP + + MOV D0Ar6, D1Ar1 + ANDMT D0Ar6, D0Ar6, #0x007F + ORT D0Ar6, D0Ar6, #0x0080 ! man1 + LSL D0Ar6, D0Ar6, #6 ! man1 <<= 6 + + MOV D0Ar4, D0Ar2 + ANDMT D0Ar4, D0Ar4, #0x007F + ORT D0Ar4, D0Ar4, #0x0080 ! man2 + LSL D0Ar4, D0Ar4, #6 ! man2 <<= 6 + + CMP D1Ar1, #0 + BGE $L4 + + NEG D0Ar6, D0Ar6 ! man1 = -man1 + +$L4: + CMP D0Ar2, #0 + BGE $L5 + + NEG D0Ar4, D0Ar4 ! man2 = -man2 + +$L5: + CMP D0Re0, #0 ! D0Re0 = exp1 - exp2 + BGE $L6 + + NEG D0Re0, D0Re0 + ASR D0Ar6, D0Ar6, D0Re0 ! man1 >> (exp2 - exp1) + MOV D1Ar5, D1Ar3 ! D1Ar5 = exp2 + B $L7 + +$L6: + ASR D0Ar4, D0Ar4, D0Re0 ! man2 >> (exp1 - exp2) + +$L7: + ADDS D0Re0, D0Ar6, D0Ar4 ! man = man1 + man2 + MOV D1Re0, #0 ! --> sign + MOVZ PC, D1RtP + + BGT $L8 + MOVT D1Re0, #0x8000 ! --->sign + NEG D0Re0, D0Re0 + +$L8: + MOV D0Ar4, D0Re0 ! man + ANDT D0Ar4, D0Ar4, #0xE000 + CMP D0Ar4, #0 + BNE $L9 + + LSL D0Re0, D0Re0, #1 + SUB D1Ar5, D1Ar5, #1 + B $L8 + +$L9: + MOV D0Ar4, D0Re0 ! D0Ar4 = man + ANDT D0Re0, D0Re0, #0x4000 + CMP D0Re0, #0 + BZ $L11 + + LSR D0Ar4, D0Ar4, #1 + ADD D1Ar5, D1Ar5, #1 + +$L11: + MOV D0Ar6, D0Ar4 + AND D0Ar6, D0Ar6, #0x40 + CMP D0Ar6, #0 + ADDNZ D0Ar4, D0Ar4, #1 + ADD D0Ar4, D0Ar4, #0x1F + MOV D0Ar6, D0Ar4 + ANDT D0Ar6, D0Ar6, #0x4000 + CMP D0Ar6, #0 + BZ $L13 + + ASR D0Ar4, D0Ar4, #1 + ADD D1Ar5, D1Ar5, #1 + +$L13: + CMP D1Ar5, #0 ! exp <= 0 ? + MOVLE D0Re0, D1Re0 ! underflow + MOVLE PC, D1RtP ! return +/-Zero + + LSR D0Ar4, D0Ar4, #6 ! man >>= 6 + MOV D0Ar6, D1Ar5 + LSL D0Ar6, D0Ar6, #23 + + MOV D0Re0, D1Re0 + OR D0Re0, D0Re0, D0Ar6 + ANDMT D0Ar4, D0Ar4, #0x007F + OR D0Re0, D0Re0, D0Ar4 + + MOV PC, D1RtP + .size ___addsf3,.-___addsf3 +#endif + +#ifdef L_subdf3 +!! +!! Floating point - double sub +!! + .text + .global ___subdf3 + .type ___subdf3,function + .align 2 +___subdf3: + MOV D1Re0, D0Ar4 + ORS D0Re0, D1Ar3, D1Re0 + MOVZ D1Re0, D1Ar1 + MOVZ D0Re0, D0Ar2 + MOVZ PC, D1RtP + XORT D1Ar3, D1Ar3, #0x8000 +#ifdef __PIC__ + B ___adddf3@PLT +#else + B ___adddf3 +#endif + .size ___subdf3,.-___subdf3 +#endif + +#ifdef L_addsf3 +!! +!! Floating point - float sub +!! + .text + .global ___subsf3 + .type ___subsf3,function + .align 2 +___subsf3: + CMP D0Ar2, #0 + MOVZ D0Re0, D1Ar1 + MOVZ PC, D1RtP + XORT D0Ar2, D0Ar2, #0x8000 +#ifdef __PIC__ + B ___addsf3@PLT +#else + B ___addsf3 +#endif + .size ___subsf3,.-___subsf3 +#endif + +#ifdef L_negdf2 +!! +!! Floating point - double negate +!! + .text + .global ___negdf2 + .type ___negdf2,function + .align 2 +___negdf2: + MOV D0Re0, D0Ar2 + MOV D1Re0, D1Ar1 + XORT D1Re0, D1Re0, #0x8000 + MOV PC, D1RtP + .size ___negdf2,.-___negdf2 +#endif + +#ifdef L_negsf2 +!! +!! Floating point - double negate +!! + .text + .global ___negsf2 + .type ___negsf2,function + .align 2 +___negsf2: + MOV D0Re0, D1Ar1 + XORT D0Re0, D0Re0, #0x8000 + MOV PC, D1RtP + .size ___negsf2,.-___negsf2 +#endif + +#ifdef L_cmpdf2 +!! +!! Compare two double(s) +!! return -1 if < +!! 0 if == +!! +1 if > + .text + .global ___cmpdf2 + .type ___cmpdf2,function + .align 2 +___cmpdf2: + LSR A0.2, D1Ar1, #31 ! sign1 + LSR A0.3, D1Ar3, #31 ! sign2 + + LSR D1Ar5, D1Ar1, #(52-32) ! exp1 + AND D1Ar5, D1Ar5, #0x07FF + + LSR D0Ar6, D1Ar3, #(52-32) ! exp2 + AND D0Ar6, D0Ar6, #0x07FF + + ANDMT D1Ar1, D1Ar1, #0x000F ! mant1 + ANDMT D1Ar3, D1Ar3, #0x000F ! mant1 + +!! +!! if (D_NAN_P (dp1) || D_NAN_P (dp2)) +!! return 1; + + MOV D0Re0, #1 + + CMP D1Ar5, #0x07FF ! exp1 == 0x07FF + BNE $L1 + + ORS D1Re0, D1Ar1, D1Ar1 ! HI(mant1) == 0? + ORSZ D1Re0, D0Ar2, D0Ar2 ! and LO(mant1) == 0? + MOVNZ PC, D1RtP ! no, Nan, return 1 + + B $L2 + +$L1: + + CMP D0Ar6, #0x07FF ! exp2 == 0x07FF + BNE $L2 + + ORS D1Re0, D1Ar3, D1Ar3 ! HI(mant2) == 0 ? + ORSZ D1Re0, D0Ar4, D0Ar4 ! and LO(mant2) == 0 ? + MOVNZ PC, D1RtP ! no, Nan, return 1 + +$L2: +!! +!! if (D_INF_P (dp1) && D_INF_P (dp2)) +!! return sign2 - sign1; +!! + + SUB D0Re0, A0.3, A0.2 + + MOV D1Re0, D0Ar6 + AND D1Re0, D1Re0, D1Ar5 + CMP D1Re0, #0x7FF ! (exp1 & exp2) == 0x7FF + + CMPEQ D1Ar1,D1Ar3 + CMPEQ D0Ar2,D0Ar4 ! mant1 == mant2 + CMPEQ D1Ar1, #0 + CMPEQ D0Ar2, #0 ! == 0 + MOVEQ PC, D1RtP + +!! if (D_INF_P (dp1)) +!! return sign1 ? -1 : 1; + + MOV D0Re0, #0 ! result + MOV D1Re0, A0.2 + TST D1Re0, #1 ! sign1 ? + SUBNZ D0Re0, D0Re0, #1 ! -1 + ADDZ D0Re0, D0Re0, #1 ! +1 + + CMP D1Ar5, #0x7FF ! exp1 == 0x7FF + MOVEQ D1Re0, D0Ar2 + ORSEQ D1Re0, D1Re0, D1Ar1 ! mant1 == 0 + MOVEQ PC, D1RtP + +!! +!! if (D_INF_P (dp2)) +!! return sign2 ? 1 : -1; + + MOV D0Re0, #0 ! result + MOV D1Re0, A0.3 + TST D1Re0, #1 ! sign2 ? + ADDNZ D0Re0, D0Re0, #1 ! +1 + SUBZ D0Re0, D0Re0, #1 ! -1 + + CMP D0Ar6, #0x7FF ! exp2 == 0x7FF + MOVEQ D1Re0, D0Ar4 + ORSEQ D1Re0, D1Re0, D1Ar3 ! mant2 == 0 + MOVEQ PC, D1RtP + +!! +!! if (D_ZERO_P (dp1) && D_ZERO_P (dp2)) +!! return 0; + + MOV D0Re0, #0 + MOV D1Re0, D0Ar6 + ORS D1Re0, D1Re0, D1Ar5 ! exp1 | exp1 + ORSZ D1Re0, D1Ar1, D1Ar3 ! mant1 | mant2 + ORSZ D1Re0, D0Ar2, D0Ar4 + MOVZ PC, D1RtP ! both zero return 0 +!! +!! if (D_ZERO_P (dp1)) +!! return sign2 ? 1 : -1; +!! + + ! result (D0Re0) already 0 + MOV D1Re0, A0.3 + TST D1Re0, #1 ! sign2? + ADDNZ D0Re0, D0Re0, #1 ! +1 + SUBZ D0Re0, D0Re0, #1 ! -1 + + ORS D1Re0, D1Ar5, D1Ar5 ! exp1 == 0 + ORSZ D1Re0, D1Ar1, D1Ar1 ! and mant1 == 0 + ORSZ D1Re0, D0Ar2, D0Ar2 + MOVZ PC, D1RtP + +!! if (D_ZERO_P (dp2)) +!! return sign1 ? -1 : 1; + + MOV D0Re0, #0 ! result + MOV D1Re0, A0.2 + TST D1Re0, #1 ! sign1? + SUBNZ D0Re0, D0Re0, #1 ! -1 + ADDZ D0Re0, D0Re0, #1 ! +1 + + ORS D1Re0, D0Ar6, D0Ar6 ! exp2 == 0 + ORSZ D1Re0, D1Ar3, D1Ar3 ! and mant2 == 0 + ORSZ D1Re0, D0Ar4, D0Ar4 + MOVZ PC, D1RtP + +!! /* Normalize the numbers. */ +!! D_NORMALIZE (dp1, exp1, mant1); +!! D_NORMALIZE (dp2, exp2, mant2); + +!! now both are "normal". + + MOV D0Re0, #0 ! result + MOV D1Re0,A0.2 + TST D1Re0, #1 ! sign1 + SUBNZ D0Re0, D0Re0, #1 ! -1 + ADDZ D0Re0, D0Re0, #1 ! +1 + + SUB D1Re0, A0.2, A0.3 + CMP D1Re0, #0 ! sign1 != sign2 + MOVNE PC, D1RtP ! yes, return sign1 ? -1 : +1 + + MOV D1Re0, D0Ar6 + CMP D1Ar5, D1Re0 ! exp1 > exp2 + MOVGT PC, D1RtP ! yes, return sign1 ? -1 : +1 + + NEG D0Re0, D0Re0 ! result -= result + MOVLT PC, D1RtP ! exp < exp2 return -(sign1 ? -1 : +1) + + CMP D1Ar1, D1Ar3 ! HI(mant1) < HI(mant2) + CMPEQ D0Ar2, D0Ar4 ! LO(mant1) < LO(mant2) + MOVLO PC, D1RtP ! yes, return -(sign1 ? -1 : +1) + + NEG D0Re0, D0Re0 ! result = -result + MOVHI PC, D1RtP ! > return sign1 ? -1 : +1 + + MOV D0Re0, #0 + MOV PC, D1RtP + .size ___cmpdf2,.-___cmpdf2 +#endif + +#ifdef L_cmpdf2_nan +!! +!! Filters for Nan arguments before calling ___cmpdf2 +!! +!! If either Arg1 or Arg2 is Nan then return Arg3 (D1Ar5) +!! otherwise tail calls ___cmpdf2 +!! + .text + .global ___cmpdf2_nan + .type ___cmpdf2_nan,function + .align 2 +___cmpdf2_nan: + LSR D1Re0, D1Ar1, #(52-32) ! arg1 NAN ? + AND D1Re0, D1Re0, #0x07FF + CMP D1Re0, #0x07FF ! exp all 1s + BNE $L10 + + MOV D0Ar6, D1Ar1 + LSL D0Ar6, D0Ar6, #(64-52) ! mantisa non-zero? + ORS D0Ar6, D0Ar6, D0Ar2 + MOVNZ D0Re0, D1Ar5 + MOVNZ PC, D1RtP ! return (D1Ar3) + +$L10: + LSR D1Re0, D1Ar3, #(52-32) ! arg2 NAN ? + AND D1Re0, D1Re0, #0x07FF + CMP D1Re0, #0x07FF ! exp all 1s + BNE $L11 + + MOV D0Ar6, D1Ar3 + LSL D0Ar6, D0Ar6, #(64-52) ! mantisa non-zero? + ORS D0Ar6, D0Ar6, D0Ar4 + MOVNZ D0Re0, D1Ar5 + MOVNZ PC, D1RtP ! return (D1Ar3) + +$L11: +#ifdef __PIC__ + B ___cmpdf2@PLT +#else + B ___cmpdf2 +#endif + .size ___cmpdf2_nan,.-___cmpdf2_nan +#endif + +#ifdef L_cmpsf2 +!! +!! Compare two float(s) +!! return -1 if < +!! 0 if == +!! +1 if > +!! + .text + .global ___cmpsf2 + .type ___cmpsf2,function + .align 2 +___cmpsf2: + LSR D1Ar3, D1Ar1, #31 ! sign1 + LSR D1Ar5, D0Ar2, #31 ! sign2 + + LSR D0Ar4, D1Ar1, #23 ! exp1 + AND D0Ar4, D0Ar4, #0x00FF + + LSR D0Ar6, D0Ar2, #23 ! exp2 + AND D0Ar6, D0Ar6, #0x00FF + + ANDMT D1Ar1, D1Ar1, #0x007F ! mant1 + ANDMT D0Ar2, D0Ar2, #0x007F ! mant2 + +!! if (F_NAN_P (fp1) || F_NAN_P (fp2)) +!! return 1; + + MOV D0Re0, #1 + + CMP D0Ar4, #0xFF ! exp1 == 0xFF? + BNE $L1 + + CMP D1Ar1, #0 ! and mant1 == 0? + MOVNZ PC, D1RtP ! No, Nan, return 1 + + B $L2 + +$L1: + CMP D0Ar6, #0xFF ! exp2 == 0xFF? + BNE $L2 + + CMP D0Ar2, #0 ! mant2 == 0? + MOVNZ PC, D1RtP ! No, Nan, return 1 + +$L2: + +!! if (F_INF_P (fp1) && F_INF_P (fp2)) +!! return sign2 - sign1; + + SUB D0Re0, D1Ar5, D1Ar3 ! sign2 - sign1 + + AND D1Re0, D0Ar4, D0Ar6 + CMP D1Re0, #0xFF ! (exp1 & exp2) == 0xFF + MOV D1Re0, D0Ar2 + CMPEQ D1Ar1, D1Re0 ! mant1 == mant2 + CMPEQ D1Ar1, #0 ! == 0 + MOVEQ PC, D1RtP + +!! if (F_INF_P (fp1)) +!! return sign1 ? -1 : 1; + + MOV D0Re0, #0 ! result + TST D1Ar3, #1 ! sign1 ? + SUBNZ D0Re0, D0Re0, #1 ! -1 + ADDZ D0Re0, D0Re0, #1 ! +1 + + CMP D0Ar4, #0x00FF ! exp1 == 0xFF + CMPEQ D1Ar1, #0 ! mant1 == 0 + MOVEQ PC, D1RtP + +!! if (F_INF_P (fp2)) +!! return sign2 ? 1 : -1; + + MOV D0Re0, #0 ! result + TST D1Ar5, #1 ! sign2 ? + ADDNZ D0Re0, D0Re0, #1 ! +1 + SUBZ D0Re0, D0Re0, #1 ! -1 + + CMP D0Ar6, #0x00FF ! exp2 == 0xFF + CMPEQ D0Ar2, #0 ! mant2 == 0 + MOVEQ PC, D1RtP + +!! if (F_ZERO_P (fp1) && F_ZERO_P (fp2)) +!! return 0; + + MOV D0Re0, #0 + ORS D1Re0, D0Ar4, D0Ar6 ! exp1 | exp2 + MOV D1Re0, D0Ar2 + ORSZ D1Re0, D1Ar1, D1Re0 ! mant1 | mant1 + MOVZ PC, D1RtP ! both zero return 0 + +!! if (F_ZERO_P (fp1)) +!! return sign2 ? 1 : -1; + + ! result (D0Re0) already 0 + TST D1Ar5, #1 ! sign2 ? + ADDNZ D0Re0, D0Re0, #1 ! +1 + SUBZ D0Re0, D0Re0, #1 ! -1 + + ORS D1Re0, D0Ar4, D0Ar4 ! exp1 == 0 + ORSZ D1Re0, D1Ar1, D1Ar1 ! and mant1 == 0? + MOVZ PC, D1RtP + +!! if (F_ZERO_P (fp2)) +!! return sign1 ? -1 : 1; + + MOV D0Re0, #0 ! result + TST D1Ar3, #1 ! sign1 ? + SUBNZ D0Re0, D0Re0, #1 ! -1 + ADDZ D0Re0, D0Re0, #1 ! +1 + + ORS D1Re0, D0Ar6, D0Ar2 ! exp2 and mant2 == 0? + MOVZ PC, D1RtP + +!! /* Normalize the numbers. */ +!! F_NORMALIZE (fp1, exp1, mant1); +!! F_NORMALIZE (fp2, exp2, mant2); + +!! now both are "normal". + + MOV D0Re0, #0 ! result + TST D1Ar3, #1 ! sign1 ? + SUBNZ D0Re0, D0Re0, #1 ! -1 + ADDZ D0Re0, D0Re0, #1 ! +1 + + CMP D1Ar3, D1Ar5 ! sign1 != sign2 + MOVNE PC, D1RtP ! yes, return sign1 ? -1 : +1 + + CMP D0Ar4, D0Ar6 ! exp1 > exp2 + MOVGT PC, D1RtP ! yes, return sign1 ? -1 : +1 + + NEG D0Re0, D0Re0 ! result -= result + MOVLT PC, D1RtP ! exp < exp2 return -(sign1 ? -1 : +1) + + MOV D1Re0, D0Ar2 + CMP D1Ar1, D1Re0 ! mant1 < mant2 + MOVLT PC, D1RtP ! yes, return -(sign1 ? -1 : +1) + + NEG D0Re0, D0Re0 ! result = -result + MOVGT PC, D1RtP ! > return sign1 ? -1 : +1 + + MOV D0Re0, #0 + MOV PC, D1RtP + .size ___cmpsf2,.-___cmpsf2 +#endif + +#ifdef L_cmpsf2_nan +!! +!! Filters for Nan arguments before calling ___cmpsf2 +!! +!! If either Arg1 or Arg2 is Nan then return Arg3 (D1Ar3) +!! otherwise tail calls ___cmpsf2 +!! + .text + .global ___cmpsf2_nan + .type ___cmpsf2_nan,function + .align 2 +___cmpsf2_nan: + LSR D1Re0, D1Ar1, #23 ! arg1 NAN ? + AND D1Re0, D1Re0, #0x00FF + CMP D1Re0, #0x00FF ! exp all 1s + BNE $L10 + + MOV D1Re0, D1Ar1 + LSLS D1Re0, D1Re0, #(32-23) ! mantisa non-zero? + MOVNZ D0Re0, D1Ar3 + MOVNZ PC, D1RtP ! return (D1Ar3) + +$L10: + LSR D1Re0, D0Ar2, #23 ! arg2 NAN ? + AND D1Re0, D1Re0, #0x00FF + CMP D1Re0, #0x00FF ! exp all 1s + BNE $L11 + + MOV D1Re0, D0Ar2 + LSLS D1Re0, D1Re0, #(32-23) ! mantisa non-zero? + MOVNZ D0Re0, D1Ar3 + MOVNZ PC, D1RtP ! return (D1Ar3) + +$L11: +#ifdef __PIC__ + B ___cmpsf2@PLT +#else + B ___cmpsf2 +#endif + .size ___cmpsf2_nan,.-___cmpsf2_nan +#endif + +#ifdef L_eqdf2 +!! +!! Floating point - double comparison routines ==,!=,<,<==,>,>= +!! Wrapper entry points for common cmpdf2 routine, these entry points +!! set up correct return value if either is Nan. +!! + .text + .global ___eqdf2 + .type ___eqdf2,function + .global ___nedf2 + .type ___nedf2,function + .global ___ltdf2 + .type ___ltdf2,function + .global ___ledf2 + .type ___ledf2,function + .align 2 +___eqdf2: +___nedf2: +___ltdf2: +___ledf2: + +!! If either is NAN return +1 + + MOV D1Ar5, #1 +#ifdef __PIC__ + B ___cmpdf2_nan@PLT +#else + B ___cmpdf2_nan +#endif + .size ___eqdf2,.-___eqdf2 + .size ___nedf2,.-___nedf2 + .size ___ltdf2,.-___ltdf2 + .size ___ledf2,.-___ledf2 + + .global ___gedf2 + .type ___gedf2,function + .global ___gtdf2 + .type ___gtdf2,function + .align 2 +___gedf2: +___gtdf2: + +!! If either is NAN return -1 + + MOV D1Ar5, #-1 +#ifdef __PIC__ + B ___cmpdf2_nan@PLT +#else + B ___cmpdf2_nan +#endif + .size ___gedf2,.-___gedf2 + .size ___gtdf2,.-___gtdf2 +#endif + +#ifdef L_eqsf2 +!! +!! Floating point - float comparison routines ==,!=,<,<==,>,>= +!! Wrapper entry points for common cmpsf2 routine, these entry points +!! set up correct return value if either is Nan. +!! + .text + .global ___eqsf2 + .type ___eqsf2,function + .global ___nesf2 + .type ___nesf2,function + .global ___ltsf2 + .type ___ltsf2,function + .global ___lesf2 + .type ___lesf2,function + .align 2 +___eqsf2: +___nesf2: +___ltsf2: +___lesf2: + +!! If either is NAN return +1 + + MOV D1Ar3, #1 +#ifdef __PIC__ + B ___cmpsf2_nan@PLT +#else + B ___cmpsf2_nan +#endif + .size ___eqsf2,.-___eqsf2 + .size ___nesf2,.-___nesf2 + .size ___ltsf2,.-___ltsf2 + .size ___lesf2,.-___lesf2 + + .global ___gesf2 + .type ___gesf2,function + .global ___gtsf2 + .type ___gtsf2,function + .align 2 +___gesf2: +___gtsf2: + +!! If either is NAN return -1 + + MOV D1Ar3, #-1 +#ifdef __PIC__ + B ___cmpsf2_nan@PLT +#else + B ___cmpsf2_nan +#endif + .size ___gesf2,.-___gesf2 + .size ___gtsf2,.-___gtsf2 +#endif + +!! Division routines. + +#ifdef L_divdf3 +!! +!! Function : double divdf3 (double a1, double a2) +!! +!! Args : a1 - double precision floating point number (D1Ar1:D0Ar2) +!! : a2 - double precision floating point number (D1Ar3:D0Ar4) +!! +!! Description: Returns a1 divided by a2 (D1Re0:D0Re0) +!! +!! Returns : (+/-)0.0 / (+/-)0.0 = QNaN +!! : (+/-)Inf / (+/-)Inf = NaN +!! : n / (+/-)Inf = 0.0 +!! : n / (+/-)0.0 = (+/-)Inf +!! : a1 / a2 = n. +!! +!! Notes : QNaN = 0xFFF80000:00000000 (Quiet NaN) +!! : SNan = 0xFFF7FFFF:FFFFFFFF (Signaling Nan) +!! : +Inf = 0x7FF00000:00000000 +!! : -Inf = 0xFFF00000:00000000 +!! : +0 = 0x00000000:00000000 +!! : -0 = 0x80000000:00000000 +!! + .text + .global ___divdf3 + .type ___divdf3,function + .align 2 +___divdf3: + XOR D1Re0, D1Ar1, D1Ar3 ! sign1 ^ sign2 + ANDT D1Re0, D1Re0, #0x8000 ! extract sign result + + ! Test if a1 == 0.0 + LSL D0Re0, D1Ar1, #1 ! Ignore sign bit + ORS D0Re0, D0Re0, D0Ar2 ! a1 == 0 ? + BZ $A1IsZero + + ! Test if a2 == 0.0 + LSL D0Re0, D1Ar3, #1 ! Ignore sign bit + ORS D0Re0, D0Re0, D0Ar4 ! a2 == 0 ? + BNZ $DoDivision + + ! a1 != 0.0 and a2 == 0.0, so return +/-Inf + ORT D1Re0, D1Re0, #0x7FF0 ! Set exponent for (+/-)Inf + MOV PC, D1RtP + +$A1IsZero: + LSL D0Re0, D1Ar3, #1 ! Ignore sign bit + ORS D0Re0, D0Re0, D0Ar4 ! a2 == 0 ? + MOV D0Re0, #0 + + ! a1 == 0.0 and a2 != 0.0, so return +/-Zero + SUBNZ D0Re0, D0Re0, D0Re0 + MOVNZ PC, D1RtP ! (zero return already set up) + + ! a1 == 0.0 and a2 == 0.0, so return QNaN. + MOVT D1Re0, #0xFFF8 ! maybe sign depends on sign1 ^ sign2 + MOV PC, D1RtP + +$DoDivision: + MOV A0.3, D1Re0 ! sign -> A0.3 + + MOV D1Ar5, D1Ar1 + ANDMT D1Ar5, D1Ar5, #0x7FFF + LSR D1Ar5, D1Ar5, #20 ! exp1 + + MOV D1Re0, D1Ar3 + ANDMT D1Re0, D1Re0, #0x7FFF + LSR D1Re0, D1Re0, #20 ! exp2 + + SUB D1Ar5, D1Ar5, D1Re0 ! exp = exp1 - exp2 + 1022 + ADD D1Ar5, D1Ar5, #1022 ! exp ---> D1Ar5 + MOV A0.2, D1Ar5 ! exp ---> A0.2 + + ANDMT D1Ar1, D1Ar1, #0x000F + ORT D1Ar1, D1Ar1, #0x0010 ! man1 --->D1Ar1, D0Ar2 + + ANDMT D1Ar3, D1Ar3, #0x000F + ORT D1Ar3, D1Ar3, #0x0010 ! man2 --->D1Ar3, D0Ar4 + + CMP D1Ar1, D1Ar3 ! man1 < man2 + BGT $L2 + BLT $L3 + + CMP D0Ar2, D0Ar4 + BGE $L2 + +$L3: + LSL D1Ar1, D1Ar1, #1 ! man1 <<= 1 + LSR D1Ar5, D0Ar2, #(32-1) + OR D1Ar1, D1Ar1, D1Ar5 + LSL D0Ar2, D0Ar2, #1 + + SUB A0.2, A0.2, #1 ! exp -= 1 + +$L2: + MOV D0Re0, #0 ! prepare the result in D1Re0, D0Re0 + ! mask = 1<<53 split into 21 + 31 + MOVT D0Ar6, #(1<<(21-16)) ! 1<< 21 + MOV D1Ar5, #2 + +$L5: + ! while (mask) + CMP D0Ar6, #0 + BZ $L4 + + CMP D1Ar1, D1Ar3 ! man1 >= man2 + BLT $L5_1 + BGT $L5_2 + + CMP D0Ar2, D0Ar4 + BLT $L5_1 + +$L5_2: + OR D0Re0, D0Re0, D0Ar6 ! result |= mask + + SUB D1Ar1, D1Ar1, D1Ar3 ! man1 - man2 + SUBS D0Ar2, D0Ar2, D0Ar4 + SUBCS D1Ar1, D1Ar1, #1 + +$L5_1: + LSL D1Ar1, D1Ar1, #1 ! man1 <<= 1 + TSTT D0Ar2, #0x8000 + ORNZ D1Ar1, D1Ar1, #1 ! MSBit -> LSBit + LSL D0Ar2, D0Ar2, #1 + + LSR D0Ar6, D0Ar6, #1 ! mask >>= 1 + B $L5 + +$L4: + SUBS D1Ar5, D1Ar5, #1 + BZ $L6 + + MOV D1Re0, D0Re0 + MOV D0Re0, #0 + MOVT D0Ar6, #(1<<(31-16)) ! 1 << 31 + B $L5 + +$L6: + ADDS D0Re0, D0Re0, #1 ! result += 1 + ADDCS D1Re0, D1Re0, #1 + + ADD D1Ar3, A0.2, #1 ! exp += 1 + + LSR D0Re0, D0Re0, #1 ! result <<= 1 + LSL D0Ar2, D1Re0, #(32-1) + OR D0Re0, D0Re0, D0Ar2 + LSR D1Re0, D1Re0, #1 + + MOV D1Ar1, A0.3 + ANDMT D1Re0, D1Re0, #0x000F ! discard hidden bit + OR D1Re0, D1Re0, D1Ar1 ! combine sign + + MOV D1Ar5, #0 + MAX D1Ar3, D1Ar3, D1Ar5 ! exp < 0 ? + SUBLT D0Re0, D0Re0, D0Re0 ! < 0 return +/-Zero + MOVLT D1Re0, D1Ar1 + MOVLT PC, D1RtP + + SUBEQ D0Re0, D0Re0, D0Re0 ! Don(t) currently handle + MOVEQ D1Re0, D1Ar1 ! denormals, so return + MOVEQ PC, D1RtP ! +/-Zero + + MOV D1Ar5, #0x7FF + MIN D1Ar3, D1Ar3, D1Ar5 ! exp >= 0x7FF + SUBGE D0Re0, D0Re0, D0Re0 ! >= return +/- Inf + MOVGE D1Re0, D1Ar1 + + LSL D1Ar3, D1Ar3, #20 ! postion exp + OR D1Re0, D1Re0, D1Ar3 ! combine exp + + MOV PC, D1RtP + .size ___divdf3,.-___divdf3 +#endif + +#ifdef L_divsf3 +!! +!! Function : float divsf3 (float a1, float a2) +!! +!! Args : a1 - single precision floating point number (D1Ar1) +!! : a2 - single precision floating point number (D0Ar2) +!! +!! Description: Returns a1 divided by a2 (D0Re0) +!! +!! Returns : (+/-)0.0 / (+/-)0.0 = QNaN +!! : (+/-)Inf / (+/-)Inf = NaN +!! : n / (+/-)Inf = 0.0 +!! : n / (+/-)0.0 = (+/-)Inf +!! : a1 / a2 = n. +!! +!! Notes : QNaN = 0xFFC00000 (Quiet NaN) +!! : SNan = 0xFFBFFFFF (Signaling Nan) +!! : +Inf = 0x7F800000 +!! : -Inf = 0xFF800000 +!! : +0 = 0x00000000 +!! : -0 = 0x80000000 +!! + .text + .global ___divsf3 + .type ___divsf3,function + .align 2 +___divsf3: + MOV D0Re0, D1Ar1 + XOR D0Re0, D0Re0, D0Ar2 ! sign1 ^ sign2 + ANDT D0Re0, D0Re0, #0x8000 ! extract sign + + ! Test if a1 == 0.0 + LSLS D1Re0, D1Ar1, #1 ! Ignore sign bit + BZ $L1 + + ! Test if a2 == 0.0 + LSLS D0Ar4, D0Ar2, #1 ! Ignore sign bit + BNZ $L2 + + ! a1 != 0.0 and a2 == 0.0 so return +/-Inf + ORT D0Re0, D0Re0, #0x7F80 + MOV PC, D1RtP + +$L1: + ! 0 / X return QNan or +/-Zero + LSLS D0Ar4, D0Ar2, #1 ! Ignore sign bit (D0Ar4) + + ! a1 == 0.0 and a2 != 0.0, so return +/-Zero + MOVNZ PC, D1RtP ! (zero return already set up) + + ! a1 == 0.0 and a2 == 0.0, so return QNAN + MOVT D0Re0, #0xFFC0 ! maybe sign depends on sign1 ^ sign2 + MOV PC, D1RtP + +$L2: + MOV D0Ar4, D0Re0 ! sign bit + + MOV D1Ar5, D1Ar1 + ANDMT D1Ar5, D1Ar5, #0x7FFF + LSR D1Ar5, D1Ar5, #23 ! exp1 + + MOV D1Re0, D0Ar2 + ANDMT D1Re0, D1Re0, #0x7FFF + LSR D1Re0, D1Re0, #23 ! exp2 + + SUB D1Ar5, D1Ar5, D1Re0 + ADD D1Ar5, D1Ar5, #126 ! exp = exp1 - exp2 + 126 + + MOV D0Ar6, D1Ar1 + ANDMT D0Ar6, D0Ar6, #0x007F + ORT D0Ar6, D0Ar6, #0x0080 ! man1 -->D0Ar6 + + MOV D0Re0, D0Ar2 + ANDMT D0Re0, D0Re0, #0x007F + ORT D0Re0, D0Re0, #0x0080 ! man2 --> D0Re0 + + CMP D0Ar6, D0Re0 ! man1 < man2 + BGE $L3 + + LSL D0Ar6, D0Ar6, #1 ! man1 <<= 1 + SUB D1Ar5, D1Ar5, #1 ! exp -= 1 + +$L3: + !mask = 0x01000000 + MOVT D1Ar1, #0x0100 + MOV D1Re0, #0 ! result = 0 + +$L4: + CMP D0Ar6, D0Re0 + ORGE D1Re0, D1Re0, D1Ar1 ! result |= mask + SUBGE D0Ar6, D0Ar6, D0Re0 + + LSL D0Ar6, D0Ar6, #1 ! man1 <<= 1 + LSRS D1Ar1, D1Ar1, #1 ! mask >>= 1 + BNZ $L4 + + ADD D1Ar1, D1Re0, #1 ! result += 1 + + ADD D1Ar5, D1Ar5, #1 ! exp += 1 + LSR D1Ar1, D1Ar1, #1 ! result >>= 1 + + ANDMT D1Ar1, D1Ar1, #0x007F ! remove hidden bit + + MOV D1Ar3, #0 + MAX D1Ar5, D1Ar5, D1Ar3 ! exp < 0 ? + MOVLT D0Re0, D0Ar4 ! < 0 return +/-Zero + MOVLT PC, D1RtP + + MOVEQ D0Re0, D0Ar4 ! Don(t) currently handle + MOVEQ PC, D1RtP ! denormals, so return +/-Zero + + MOV D1Ar3, #0xFF + MIN D1Ar5, D1Ar5, D1Ar3 ! exp >= 0xFF + SUBGE D1Ar1, D1Ar1, D1Ar1 ! >= return +/-Inf + + LSL D1Ar5, D1Ar5, #23 + OR D0Re0, D1Ar1, D1Ar5 ! man|exp + OR D0Re0, D0Re0, D0Ar4 ! |sign ->D0Re0 + + MOV PC, D1RtP + .size ___divsf3,.-___divsf3 +#endif + +!! Floating point multiplication + +#ifdef L_muldf3 +!! +!! Floating point - double multiplicatiion +!! + .text + .global ___muldf3 + .type ___muldf3,function + .align 2 +___muldf3: + XOR D1Re0, D1Ar1, D1Ar3 ! sign1 ^ sign2 + ANDT D1Re0, D1Re0, #0x8000 ! extract sign bit + LSL D0Re0, D1Ar1, #1 ! Ignore sign + ORS D0Re0, D0Re0, D0Ar2 ! zero * ... + MOVZ PC, D1RtP ! return 0 + + LSL D0Re0, D1Ar3, #1 ! Ignore sign + ORS D0Re0, D0Re0, D0Ar4 ! ... * zero + MOVZ PC, D1RtP ! return 0 + + MSETL [A0StP], D0.4, D0.5, D0.6, D0.7 + + MOV D1Ar5, D1Ar1 + ANDMT D1Ar5, D1Ar5, #0x7FFF + LSR D1Ar5, D1Ar5, #20 ! exp1 + + MOV D1.5, D1Ar3 + ANDMT D1.5, D1.5, #0x7FFF + LSR D1.5, D1.5, #20 ! exp2 + + SUB D1Ar5, D1Ar5, #1022 + ADD D1Ar5, D1Ar5, D1.5 ! exp = exp1 + exp2 - 1022 + + MOV D1.5, D1Ar1 + ANDMT D1.5, D1.5, #0x000F + ORT D1.5, D1.5, #0x0010 ! man1 --->D1.5, D0.5 + MOV D0.5, D0Ar2 + + MOV D1.6, D1Ar3 + ANDMT D1.6, D1.6, #0x000F + ORT D1.6, D1.6, #0x0010 ! man2 --->D1.6, D0.6 + MOV D0.6, D0Ar4 + + XOR D1Re0, D1Ar1, D1Ar3 ! store the sign bit + MOV D0Re0, D1Ar5 + + SETL [A0StP+#8++], D0Re0,D1Re0 ! XXX + + LSR D0Ar6, D0.5, #21 ! D1Ar1:D0Ar2 = man1 >> 21 + LSL D0Ar2, D1.5, #(32-21) + MOV D1Ar1, #0 ! top 32 bits are zero + OR D0Ar2, D0Ar2, D0Ar6 + + LSR D0Ar6, D0.6, #21 ! D1Ar3:D0Ar4 = man2 >> 21 + LSL D0Ar4, D1.6, #(32-21) + MOV D1Ar3, #0 ! top 32 bits are zero + OR D0Ar4, D0Ar4, D0Ar6 + + CALLR D1RtP, ___muldi3_ + + MOV D1.7, D1Re0 + MOV D0.7, D0Re0 + + LSR D0Ar6, D0.5, #21 ! man1 >> 21 + LSL D0Ar2, D1.5, #(32-21) + MOV D1Ar1, #0 + OR D0Ar2, D0Ar2, D0Ar6 + + MOV D0Ar4, D0.6 + ANDMT D0Ar4, D0Ar4, #0x001F + MOV D1Ar3, #0 + + CALLR D1RtP, ___muldi3_ + + LSR D0Re0, D0Re0, #21 ! >> 21 + LSL D0Ar6, D1Re0, #(32-21) + LSR D1Re0, D1Re0, #21 + OR D0Re0, D0Re0, D0Ar6 + + ADDS D0.7, D0.7, D0Re0 ! D1.7:D0.7 + D1Re0:D0Re0 + ADD D1.7, D1.7, D1Re0 + ADDCS D1.7, D1.7, #1 + + MOV D1Ar1, #0 + LSL D0Ar2, D1.6, #(32-21) ! man2 >> 21 + LSR D0Ar6, D0.6, #21 + OR D0Ar2, D0Ar2, D0Ar6 + + MOV D0Ar4, D0.5 + ANDMT D0Ar4, D0Ar4, #0x001F + MOV D1Ar3, #0 + + CALLR D1RtP, ___muldi3_ + + LSR D0Re0, D0Re0, #21 ! >> 21 + LSL D0Ar6, D1Re0, #(32-21) + LSR D1Re0, D1Re0, #21 + OR D0Re0, D0Re0, D0Ar6 + + ADDS D0.7, D0.7, D0Re0 ! D1.7:D0.7 + D1Re0:D0Re0 + ADD D1.7, D1.7, D1Re0 + ADDCS D1.7, D1.7, #1 + + GETL D0Re0,D1Re0, [A0StP++#-8] ! prepare to recover D1Re0, D1Ar5 + + MOV D1.6, D1.7 + MOV D0.6, D0.7 + + LSR D0.6, D0.6, #2 ! man >> 2 (d1.6, d0.6) + LSL D0.5, D1.6, #(32-2) + LSR D1.6, D1.6, #2 + OR D0.6, D0.6, D0.5 + + MOV D1Ar5, D0Re0 + + MOV D0Re0, D1.6 + ANDT D0Re0, D0Re0, #0x2000 ! 1 << 61 + CMP D0Re0, #0 ! round ... + BZ $L11 + + ADDS D0.6, D0.6, #0x100 ! D1.6:D0.6 + 0x100 + ADDCS D1.6, D1.6, #1 + + LSL D0.5, D1.6, #(32-9) ! >> 9 + LSR D0.6, D0.6, #9 + LSR D1.6, D1.6, #9 + OR D0.6, D0.6, D0.5 + B $L13 + +$L11: + ADDS D0.6, D0.6, #0x80 ! +128 + ADDCS D1.6, D1.6, #1 + + LSR D0.6, D0.6, #8 ! >> 8 + LSL D0.5, D1.6, #(32-8) + LSR D1.6, D1.6, #8 + OR D0.6, D0.6, D0.5 + + SUB D1Ar5, D1Ar5, #1 ! exp -= 1 + +$L13: + MOV D0Re0, D1.6 + ANDT D0Re0, D0Re0, #0x0020 + CMP D0Re0, #0 + BZ $L14 + + LSR D0.6, D0.6, #1 ! man >> 1 + LSL D0.5, D1.6, #(32-1) + LSR D1.6, D1.6, #1 + OR D0.6, D0.6, D0.5 + + ADD D1Ar5, D1Ar5, #1 ! exp += 1 + +$L14: + ANDT D1Re0, D1Re0, #0x8000 ! get the sign bit + MOV D1Ar1, D1Re0 ! remember sign + ANDMT D1.6, D1.6, #0x000F ! remove hidden bit + OR D1Re0, D1Re0, D1.6 ! sign | HI(mantisa) + MOV D0Re0, D0.6 ! LO(mantisa) + + SUB A0.3, A0StP, #32 + MGETL D0.4, D0.5, D0.6, D0.7, [A0.3] + SUB A0StP, A0StP, #32 + + MOV D1Ar3, #0 + MAX D1Ar5, D1Ar5, D1Ar3 ! exp < 0 ? + SUBLT D0Re0, D0Re0, D0Re0 ! < 0 return +/-Zero + MOVLT D1Re0, D1Ar1 + MOVLT PC, D1RtP + + SUBEQ D0Re0, D0Re0, D0Re0 ! Don(t) currently handle + MOVEQ D1Re0, D1Ar1 ! denormals, so return + MOVEQ PC, D1RtP ! +/-Zero + + MOV D1Ar3, #0x7FF + MIN D1Ar5, D1Ar5, D1Ar3 ! exp >= 0x7FF ? + SUBGE D0Re0, D0Re0, D0Re0 ! >= return +/-Inf + MOVGE D1Re0, D1Ar1 + + LSL D1Ar5, D1Ar5, #20 ! position exp + OR D1Re0, D1Re0, D1Ar5 ! add exp + + MOV PC, D1RtP + +!! +!! 32-bit x 32-bit -> 64-bit +!! + .align 2 +___muldi3_: + MOV A0.2, D0Ar6 + MOV A0.3, D1Ar5 + + LSR D1Ar1, D0Ar2, #16 ! h1 + LSR D1Ar3, D0Ar4, #16 ! high 2 + MULW D1Re0, D1Ar1, D1Ar3 ! h1 * h2 + + MOV D0Ar6, #0xFFFF + AND D1Ar5, D0Ar2, D0Ar6 ! l1 + MULW D0Re0, D1Ar5, D1Ar3 ! l1 * h2 + + AND D0Ar2, D0Ar4, D0Ar6 ! l2 + MOV D0Ar4, D1Ar1 ! h1 + MULW D1Ar1, D0Ar4, D0Ar2 ! h1 * l2 + + MOV D0Ar4, D1Ar5 ! l1 + LSR D1Ar5, D0Re0, #16 + LSL D0Re0, D0Re0, #16 + ADD D1Re0, D1Re0, D1Ar5 + LSR D1Ar5, D1Ar1, #16 + ADD D1Re0, D1Re0, D1Ar5 + LSL D0Ar6, D1Ar1, #16 + + ADDS D0Re0, D0Re0, D0Ar6 + ADDCS D1Re0, D1Re0, #1 + + MULW D0Ar6, D0Ar2, D0Ar4 + + ADDS D0Re0, D0Re0, D0Ar6 + ADDCS D1Re0, D1Re0, #1 + + MOV D0Ar6, A0.2 + MOV D1Ar5, A0.3 + + MOV PC, D1RtP + .size ___muldf3,.-___muldf3 +#endif + +#ifdef L_mulsf3 +!! +!! Floating point - float multiplication +!! + .text + .global ___mulsf3 + .type ___mulsf3,function + .align 2 +___mulsf3: + MOV D0Re0, D1Ar1 + XOR D0Re0, D0Re0, D0Ar2 ! sign1 ^ sign2 + ANDT D0Re0, D0Re0, #0x8000 ! extract sign bit + LSLS D1Re0, D1Ar1, #1 ! Ignore sign + MOVZ PC, D1RtP ! +/-Zero * ... return Zero + + LSLS D1Re0, D0Ar2, D0Ar2 ! Ignore sign + MOVZ PC, D1RtP ! ... * +/-Zero return Zero + + MOV D1Ar5, D1Ar1 + ANDMT D1Ar5, D1Ar5, #0x7fff + LSR D1Ar5, D1Ar5, #23 ! exp1 + + MOV D1Re0, D0Ar2 + ANDMT D1Re0, D1Re0, #0x7fff + LSR D1Re0, D1Re0, #23 ! exp2 + + SUB D1Ar5, D1Ar5, #126 ! exp = exp1 - 126 + ADD D1Ar5, D1Ar5, D1Re0 ! exp += exp2 + + MOV D0Ar6, D1Ar1 + ANDMT D0Ar6, D0Ar6, #0x7f + ORT D0Ar6, D0Ar6, #0x80 ! man1 + + MOV D0Re0, D0Ar2 + ANDMT D0Re0, D0Re0, #0x7f + ORT D0Re0, D0Re0, #0x80 ! man2 + + MOV D1Re0, D0Ar2 + XOR D1Re0, D1Ar1, D1Re0 ! store the sign bit in D1Re0 + + LSR D0Ar2, D0Ar6, #8 + LSR D0Ar4, D0Re0, #8 + MULW D1Ar1, D0Ar2, D0Ar4 ! one 16X16 + + MOV D0Ar2, D0Ar6 + AND D0Ar2, D0Ar2, #0xff + MULW D1Ar3, D0Ar2, D0Ar4 ! one 8X16 + + LSR D0Ar2, D0Ar6, #8 + MOV D0Ar4, D0Re0 + AND D0Ar4, D0Ar4, #0xff + MULW D0Re0, D0Ar2, D0Ar4 ! another 16X8 + + SWAP D1Re0, D0Re0 + ADD D1Ar3, D1Ar3, D1Re0 ! add 16x8(s) partial results + LSR D1Ar3, D1Ar3, #8 + ADD D1Ar1, D1Ar1, D1Ar3 ! accumulate partial result + + LSR D1Ar1, D1Ar1, #2 ! man >> 2 + TSTT D1Ar1, #0x2000 ! round ... + + ADDNZ D1Ar1, D1Ar1, #0x20 + LSRNZ D1Ar1, D1Ar1, #6 + + ADDZ D1Ar1, D1Ar1, #0x10 + LSRZ D1Ar1, D1Ar1, #5 + SUBZ D1Ar5, D1Ar5, #1 + + TSTT D1Ar1, #0x100 + + LSRNZ D1Ar1, D1Ar1, #1 + ADDNZ D1Ar5, D1Ar5, #1 + + ANDT D0Re0, D0Re0, #0x8000 ! get the sign bit + ANDMT D1Ar1, D1Ar1, #0x7f ! remove hidden hit + + MOV D1Ar3, #0 + MAX D1Ar5, D1Ar5, D1Ar3 ! exp < 0 ? + MOVLT PC, D1RtP ! < 0 return +/-Zero + ! Don(t) currently handle + MOVEQ PC, D1RtP ! denormals, so return +/-Zero + + MOV D1Ar3, #0xFF + MIN D1Ar5, D1Ar5, D1Ar3 ! exp >= 0xFF ? + SUBGE D1Ar1, D1Ar1, D1Ar1 ! >= return +/-Inf + + MOV D1Re0, D0Re0 + LSL D1Ar5, D1Ar5, #23 + OR D1Re0, D1Re0, D1Ar5 ! sign|exp + OR D0Re0, D1Re0, D1Ar1 ! |man ->D0Re0 + + MOV PC, D1RtP + .size ___mulsf3,.-___mulsf3 +#endif + +!! Floating point conversion routines + +#ifdef L_extendsfdf2 +!! +!! float -> double conversion +!! + .text + .global ___extendsfdf2 + .type ___extendsfdf2,function + .align 2 +___extendsfdf2: + LSLS D0Re0, D1Ar1, #1 ! Ignore sign bit + MOVZ D1Re0, D1Ar1 ! +/- Zero + MOVZ PC, D1RtP ! return +/- Zero + + MOV D1Ar3, D1Ar1 + ANDT D1Ar3, D1Ar3, #0x8000 ! extract sign (D1Ar3) + + MOV D0Ar2, D1Ar1 ! extract mant (D0Ar2) + ANDMT D0Ar2, D0Ar2, #0x007F + + LSR D1Re0, D1Ar1, #23 ! extract exp (D1Re0) + AND D1Re0, D1Re0, #0x00FF + + ADD D1Re0, D1Re0, #(1023-127) ! exp += ... + + LSL D1Re0, D1Re0, #(52-32) ! position exp MSWord + + OR D1Re0, D1Re0, D1Ar3 ! combine with sign | exp + + MOV D1Ar3, D0Ar2 ! extract mant MSWord + LSR D1Ar3, D1Ar3, #(23-(52-32)) + + OR D1Re0, D1Re0, D1Ar3 ! combine sign | exp | mant + LSL D0Re0, D0Ar2, #(32 - 3) ! 3 = (23-(52-32)) + + MOV PC, D1RtP + .size ___extendsfdf2,.-___extendsfdf2 +#endif + +#ifdef L_truncdfsf2 +!! +!! double -> float conversion +!! + .text + .global ___truncdfsf2 + .type ___truncdfsf2,function + .align 2 +___truncdfsf2: ! has round solution + LSL D0Re0, D1Ar1, #1 ! Ignore sign bit + ORS D0Re0, D0Re0, D0Ar2 ! zero? + MOVZ D0Re0, D1Ar1 + MOVZ PC, D1RtP ! return +/-Zero + +!! extract sign + MOV D0Ar6, D1Ar1 + ANDT D0Ar6, D0Ar6, #0x8000 ! save sign + +!! extract exponent + MOV D1Re0, D1Ar1 + ANDMT D1Re0, D1Re0, #0x7FFF ! remove the sign bit + LSR D1Re0, D1Re0, #20 + SUB D1Re0, D1Re0, #(1023-127) + +!! extract mantisa + ANDMT D1Ar1, D1Ar1, #0x000F + +!! add hidden bit + ORT D1Ar1, D1Ar1, #0x0010 + +!! position significand for rounding + LSL D0Re0, D1Ar1, #4 ! (24 - (52 - 32)) + LSR D0Ar2, D0Ar2, #(32 - 4) + OR D0Re0, D0Re0, D0Ar2 + + ADD D0Re0, D0Re0, #1 ! round + 1 + TSTT D0Re0, #0xFE00 ! test round overflowed? + ADDNZ D1Re0, D1Re0, #1 + LSR D0Re0, D0Re0, #1 + +!! check biased exponent within range 0 .. 254 + CMP D1Re0, #0 + MOVLT D0Re0, D0Ar6 ! return +/- Zero + MOVLT PC, D1RtP ! return 0 + + MOVT D0Ar4, #0x7F80 ! Inf + OR D0Ar4, D0Ar4, D0Ar6 ! +/-Inf + + CMP D1Re0, #254 + MOVGT D0Re0, D0Ar4 + MOVGT PC, D1RtP ! return +/Inf + +!! pack sign , exp, mantisa + ANDMT D0Re0, D0Re0, #0x007F ! remove hidden bit + LSL D0Ar2, D1Re0, #23 ! align exp + OR D0Re0, D0Re0, D0Ar2 ! exp | mantisa + OR D0Re0, D0Re0, D0Ar6 ! sign | exp | mantisa + MOV PC, D1RtP ! done + .size ___truncdfsf2,.-___truncdfsf2 +#endif + +!! Floating point -> integer conversion. + +#ifdef L_fixdfdi +!! +!! Floating point - double -> signed long long +!! + .text + .global ___fixdfdi + .type ___fixdfdi,function + .align 2 +___fixdfdi: + MOV D0Re0, D1Ar1 + ORS D0Re0, D0Re0, D0Ar2 + MOVZ D1Re0, D0Re0 + MOVZ PC, D1RtP + + MOV D1Re0, D1Ar1 + ANDMT D1Re0, D1Re0, #0x7FFF ! discard sign bit + + LSR D1Re0, D1Re0, #20 + SUBS D1Re0, D1Re0, #1085 ! exp + BLE $L3 + +!! exp > 0 not representable (overflow) + + TSTT D1Ar1, #0x8000 ! signed? + MOVT D1Re0, #0x8000 ! yes, result + MOV D0Re0, #0 ! MIN_INT + SUBZ D1Re0, D1Re0, #1 ! else result + SUBZ D0Re0, D0Re0, #1 ! MAX_INT + MOV PC, D1RtP ! return + +$L3: + CMP D1Re0, #-62 ! -(BITS_PER_DI - 2) + SUBLT D0Re0, D0Re0, D0Re0 + MOVLT D1Re0, D0Re0 + MOVLT PC, D1RtP ! underflow + + MOV D0Ar6, D1Re0 ! exp + + MOV D0Re0, D0Ar2 + MOV D1Re0, D1Ar1 ! man -> D1Re0, D0Re0 + + ANDMT D1Re0, D1Re0, #0x000F + ORT D1Re0, D1Re0, #0x0010 + + LSL D1Re0, D1Re0, #10 ! man <<=10 + + LSR D1Ar5, D0Re0, #22 + OR D1Re0, D1Re0, D1Ar5 ! mantissa + + LSL D0Re0, D0Re0, #10 + + CMP D0Ar6, #0 + BZ $L5 + + CMP D0Ar6, #-32 + BGT $L5_1 + BLT $L5_2 + +!! >> 32 bits. + MOV D0Re0, D1Re0 + MOV D1Re0, #0 + B $L5 + +$L5_2: +!! >> more than 32 bits + + ADD D0Ar6, D0Ar6, #32 + CMP D0Ar6, #-32 + +!! >> more than 64 bits, return 0 + ADDLE D0Re0, D0Re0, D0Re0 + MOVLE PC, D1RtP + + MOV D0Re0, D1Re0 + MOV D1Re0, #0 + NEG D0Ar6, D0Ar6 + LSR D0Re0, D0Re0, D0Ar6 + B $L5 + +$L5_1: +!! >> less than 32 bits + CMP D0Ar6, #0 ! shift >>0 ? + BEQ $L5 + + ADD D1Ar5, D0Ar6, #32 ! (32 + (-exp)) + LSL D0Ar2, D1Re0, D1Ar5 + + NEG D0Ar6, D0Ar6 + LSR D0Re0, D0Re0, D0Ar6 + + MOV D1Ar5, D0Ar6 + LSR D1Re0, D1Re0, D1Ar5 + + OR D0Re0, D0Re0, D0Ar2 + +$L5: + TSTT D1Ar1, #0x8000 ! test sign + MOVZ PC, D1RtP + + NEGS D0Re0, D0Re0 ! change sign + NEG D1Re0, D1Re0 + SUBNZ D1Re0, D1Re0, #1 + MOV PC, D1RtP + .size ___fixdfdi,.-___fixdfdi +#endif + +#ifdef L_fixdfsi +!! +!! Floating point - double -> signed long long +!! + .text + .global ___fixdfsi + .type ___fixdfsi,function + .align 2 +___fixdfsi: + MOV D0Re0, D1Ar1 + ORS D0Re0, D0Re0, D0Ar2 ! zero? + MOVZ PC, D1RtP ! return 0 + + MOV D1Re0, D1Ar1 ! keep sign bit + + LSR D0Ar6, D1Ar1, #20 ! extact exponent (D0Ar6) + AND D0Ar6, D0Ar6, #0x07FF + SUBS D0Ar6, D0Ar6, #1053 ! exp -= (1023 + 30) + BLE $L1 + +!! exp > 0 not representable (overflow) + + TSTT D1Re0, #0x8000 ! signed ? + MOVT D0Re0, #0x8000 ! yes, result MIN INT + SUBZ D0Re0, D0Re0, #1 ! no, result MAX INT + MOV PC, D1RtP ! return + +$L1: + ANDMT D1Ar1, D1Ar1, #0x000F ! extract mantisa + ORT D1Ar1, D1Ar1, #0x0010 ! add hidden bit + LSR D1Ar3, D0Ar2, #22 ! (32 - 10) + LSL D0Ar2, D0Ar2, #10 + LSL D1Ar1, D1Ar1, #10 + OR D1Ar1, D1Ar1, D1Ar3 + + CMP D0Ar6, #-30 ! -(BITS_PER_SI - 2) + + SUBLT D0Re0, D0Re0, D0Re0 ! < -30 underflow + MOVLT PC, D1RtP ! return 0 + + MOV D0Re0, D1Ar1 + NEG D0Ar6, D0Ar6 + LSR D0Re0, D0Re0, D0Ar6 ! mant >>= exp + TSTT D1Re0, #0x8000 ! signed? + + MOVZ PC, D1RtP ! return mant + NEG D0Re0, D0Re0 + MOV PC, D1RtP ! return -mant + .size ___fixdfsi,.-___fixdfsi +#endif + +#ifdef L_fixsfdi +!! +!! Floating point - float -> signed long long +!! + .text + .global ___fixsfdi + .type ___fixsfdi,function + .align 2 +___fixsfdi: + SETL [A0StP+#8++], D0.4, D1RtP +#ifdef __PIC__ + CALLR D1RtP, ___extendsfdf2@PLT +#else + CALLR D1RtP, ___extendsfdf2 +#endif + MOV D1Ar1, D1Re0 + MOV D0Ar2, D0Re0 + + GETL D0.4, D1RtP, [A0StP++#-8] + +#ifdef __PIC__ + B ___fixdfdi@PLT +#else + B ___fixdfdi +#endif + .size ___fixsfdi,.-___fixsfdi +#endif + +#ifdef L_fixsfsi +!! +!! Floating point - float -> signed int/long +!! + .text + .global ___fixsfsi + .type ___fixsfsi,function + .align 2 +___fixsfsi: + LSLS D0Re0, D1Ar1, #1 ! Ignore sign bit + MOVZ PC, D1RtP ! Zero? return 0 + + MOV D1Re0, D1Ar1 + ANDMT D1Re0, D1Re0, #0x7FFF ! remove sign bit + LSR D1Re0, D1Re0, #23 + SUBS D1Re0, D1Re0, #(127 + 30) + + BLE $L3 + +!! exp > 0 (overflow) return MIN_INT or MAX_INT + + MOVT D0Re0, #0x8000 ! MIN_INT (0x80000000) + TSTT D1Ar1, #0x8000 + SUBZ D0Re0, D0Re0, #1 ! MAX_INT (0x7FFFFFFF) + MOV PC, D1RtP + +$L3: + CMP D1Re0, #-30 ! -(BITS_PER_SI - 2) + + SUBLT D0Re0, D0Re0, D0Re0 ! underflow? + MOVLT PC, D1RtP ! return 0 + + MOV D0Re0, D1Ar1 + ANDMT D1Ar1, D1Ar1, #0x007F ! extract mantisa + ORT D1Ar1, D1Ar1, #0x0080 ! add hidden bit + LSL D1Ar1, D1Ar1, #7 + + CMP D1Re0, #0 + BZ $L5 + + NEG D1Re0, D1Re0 + LSR D1Ar1, D1Ar1, D1Re0 +$L5: + + TSTT D0Re0, #0x8000 ! signed? + MOV D0Re0, D1Ar1 + MOVZ PC, D1RtP + NEG D0Re0, D0Re0 + MOV PC, D1RtP + .size ___fixsfsi,.-___fixsfsi +#endif + +#ifdef L_fixunsdfdi +!! +!! Floating point - double -> unsigned long long +!! + .text + .global ___fixunsdfdi + .type ___fixunsdfdi,function + .align 2 +___fixunsdfdi: + LSL D0Re0, D1Ar1, #1 ! Ignore sign bit + ORS D0Re0, D0Re0, D0Ar2 ! zero? + MOVZ D1Re0, D0Re0 + MOVZ PC, D1RtP ! return 0 + + TSTT D1Ar1, #0x8000 ! Negative? + SUBNZ D0Re0, D0Re0, D0Re0 ! < 0 + MOVNZ D1Re0, D0Re0 + MOVNZ PC, D1RtP ! return 0 + + LSR D1Ar3, D1Ar1, #20 ! extract exponent (D1Ar3) + SUBS D1Ar3, D1Ar3, #1086 ! exp -= (1023 + 32 + 31) + + SUBGT D0Re0, D0Re0, D0Re0 ! exp > 0 + SUBGT D0Re0, D0Re0, #1 + MOVGT D1Re0, D0Re0 + MOVGT PC, D1RtP ! return MAX_UDI + + ANDMT D1Ar1, D1Ar1, #0x000F ! extract mantisa + LSR D1Ar5, D0Ar2, #21 ! (32 - 11) + LSL D0Ar2, D0Ar2, #11 + LSL D1Ar1, D1Ar1, #11 + OR D1Ar1, D1Ar1, D1Ar5 + ORT D1Ar1, D1Ar1, #0x8000 ! add hidden bit + + CMP D1Ar3, #-32 ! -exp >= 32 + BLE $L9 ! branch + + CMP D1Ar3, #0 ! exp == 0? + MOVEQ D1Re0, D1Ar1 + MOVEQ D0Re0, D0Ar2 + MOVEQ PC, D1RtP + +!! Shift < 32 bits + + ADD D1Re0, D1Ar3, #32 ! (32 + (-exp)) + LSL D0Re0, D1Ar1, D1Re0 ! H << (exp - 32) + NEG D1Ar3, D1Ar3 ! exp = -exp + MOV D1Ar5, D0Ar2 + LSR D1Re0, D1Ar1, D1Ar3 ! H >> exp + LSR D0Ar6, D1Ar5, D1Ar3 ! L >> exp + OR D0Re0, D0Re0, D0Ar6 + MOV PC, D1RtP + +$L9: + +!! Shift >= 32 bits + + MOV D1Re0, #0 ! shifting >= 32 (MSWord result 0) + ADD D1Ar3, D1Ar3, #32 + CMP D1Ar3, #-31 ! -((BITS_PER_DI - 32) - 1) + + MOVLT D0Re0, D1Re0 ! underflow? + MOVLT PC, D1RtP ! return 0 + + NEG D1Ar3, D1Ar3 ! exp = -exp + LSR D1Ar1, D1Ar1, D1Ar3 ! >>(exp - 32) + MOV D0Re0, D1Ar1 + MOV PC, D1RtP + .size ___fixunsdfdi,.-___fixunsdfdi +#endif + +#ifdef L_fixunsdfsi +!! +!! Floating point - double -> unsigned int/long +!! + .text + .global ___fixunsdfsi + .type ___fixunsdfsi,function +___fixunsdfsi: + LSL D0Re0, D1Ar1, #1 ! Ignore sign bit + ORS D0Re0, D0Re0, D0Ar2 ! zero? + MOVZ PC, D1RtP ! return 0 + + TSTT D1Ar1, #0x8000 ! Negative? + SUBNZ D0Re0, D0Re0, D0Re0 ! < 0 + MOVNZ PC, D1RtP ! return 0 + + LSR D0Ar6, D1Ar1, #20 ! extract exponent (D0Ar6) + SUBS D0Ar6, D0Ar6, #(1023+32+31) ! exp -= (1023 + 32 + 31) + + SUBGT D0Re0, D0Re0, D0Re0 ! exp > 0 (overflow) + SUBGT D0Re0, D0Re0, #1 + MOVGT PC, D1RtP ! return MAX_USI + + ANDMT D1Ar1, D1Ar1, #0x000F ! extract mantisa + LSR D1Ar3, D0Ar2, #21 ! (32 - 11) + LSL D0Ar2, D0Ar2, #11 + LSL D1Ar1, D1Ar1, #11 + OR D1Ar1, D1Ar1, D1Ar3 + ORT D1Ar1, D1Ar1, #0x8000 ! add hidden bit + + NEG D0Ar6, D0Ar6 ! exp = -exp + CMP D0Ar6, #64 ! exp >= BITS_PER_DI ? + + SUBGE D0Re0, D0Re0, D0Re0 ! >= underflow + MOVGE PC, D1RtP ! return 0 + + CMP D0Ar6, #32 ! exp > (BITS_PER_DI - BITS_PER_SI) + SUBLT D0Re0, D0Re0, D0Re0 ! < overflow + SUBLT D0Re0, D0Re0, #1 + MOVLT PC, D1RtP ! return MAX_USI_INT + + SUB D0Ar6, D0Ar6, #32 ! exp -= (BITS_PER_DI - BITS_PER_SI) + + MOV D0Re0, D1Ar1 + LSR D0Re0, D0Re0, D0Ar6 ! return mant >> exp + MOV PC, D1RtP + .size ___fixunsdfsi,.-___fixunsdfsi +#endif + +#ifdef L_fixunssfdi +!! +!! Floating point - float -> unsigned long long +!! + .text + .global ___fixunssfdi + .type ___fixunssfdi,function + .align 2 +___fixunssfdi: + LSLS D0Re0, D1Ar1, #1 ! Ignore sign bit + MOVZ PC, D1RtP ! Zero? return 0 + + TSTT D1Ar1, #0x8000 ! Negative? + SUBNZ D0Re0, D0Re0, D0Re0 ! < 0 + MOVNZ D1Re0, D0Re0 + MOVNZ PC, D1RtP ! return 0 + + LSR D0Ar6, D1Ar1, #23 ! extract exponent (D0Ar6) + SUBS D0Ar6, D0Ar6, #(127+63) + + SUBGT D0Re0, D0Re0, D0Re0 ! exp > 0 (overflow) + SUBGT D0Re0, D0Re0, #1 + MOVGT D1Re0, D0Re0 + MOVGT PC, D1RtP ! return MAX_UDI + + CMP D0Ar6, #-(64-1) ! -exp > (BITS_PER_DI - 1) + + SUBLT D0Re0, D0Re0, D0Re0 ! underflow + MOVLT D1Re0, D0Re0 + MOVLT PC, D1RtP ! return 0 + + LSL D1Re0, D1Ar1, #(63-32-23) ! extract mantisa MSWord + ORT D1Re0, D1Re0, #0x8000 ! add hidden bit + + CMP D0Ar6, #-32 + NEG D0Ar4, D0Ar6 + MOV D1Ar3, D0Ar4 + BLE $L1 + +!! Shift < 32 bits + + ORS D0Re0, D1Ar3, D1Ar3 ! shifting 0 ? + MOVZ PC, D1RtP ! + + ADD D1Ar5, D0Ar6, #32 ! (-exp) + 32 + + LSL D0Re0, D1Re0, D1Ar5 ! mant >> exp + LSR D1Re0, D1Re0, D1Ar3 + + MOV PC, D1RtP +$L1: +!! Shift > 32 bits + SUB D1Ar3, D1Ar3, #32 ! exp -= 32 + + LSR D0Re0, D1Re0, D1Ar3 + MOV D1Re0, #0 + + MOV PC, D1RtP + .size ___fixunssfdi,.-___fixunssfdi +#endif + +#ifdef L_fixunssfsi +!! +!! Floating point - float -> unsigned int/long +!! + .text + .global ___fixunssfsi + .type ___fixunssfsi,function + .align 2 +___fixunssfsi: + LSLS D0Re0, D1Ar1, #1 ! Ignore sign bit + MOVZ PC, D1RtP ! Zero? return 0 + + TSTT D1Ar1, #0x8000 ! Negative? + SUBNZ D0Re0, D0Re0, D0Re0 ! < 0 + MOVNZ PC, D1RtP ! return 0 + + LSR D0Ar6, D1Ar1, #23 ! extract exponent (D0Ar6) + SUBS D0Ar6, D0Ar6, #(127+31) + + SUBGT D0Re0, D0Re0, D0Re0 ! exp > 0 (overflow) + SUBGT D0Re0, D0Re0, #1 + MOVGT PC, D1RtP ! return MAX_USI + + CMP D0Ar6, #-(32-1) ! -exp > (BITS_PER_SI - 1) + + SUBLT D0Re0, D0Re0, D0Re0 ! underflow + MOVLT PC, D1RtP ! return 0 + + LSL D0Re0, D1Ar1, #(31-23) ! extract mantisa + ORT D0Re0, D0Re0, #0x8000 ! add hidden bit + + NEG D0Ar6, D0Ar6 + + LSR D0Re0, D0Re0, D0Ar6 ! mant >> exp + + MOV PC, D1RtP + .size ___fixunssfsi,.-___fixunssfsi +#endif + +!! Integer -> Floating point conversion + +#ifdef L_floatdidf +!! +!! signed long long -> double conversion +!! + .text + .global ___floatdidf + .type ___floatdidf,function + .align 2 +___floatdidf: + + MOV D1Ar3, #(1023+32+30) ! exp + MOV D0Ar6, #0 ! sign, assume +ve + + ORS D1Re0, D1Ar1, D1Ar1 + BLT $L1 + BGT $L2 + + ORS D0Re0, D0Ar2, D0Ar2 + BNE $L2 + + MOV PC, D1RtP + +$L1: + ! <0 + MOVT D0Ar6, #0x8000 ! sign, -ve + + NEGS D0Ar2, D0Ar2 ! negate + NEG D1Re0, D1Ar1 + SUBNZ D1Re0, D1Re0, #1 + + CMP D1Re0, #0 ! negative? + BGT $L2 ! branch, not MIN DI + +! Handle most negative value + + LSR D0Ar2, D0Ar2, #1 ! significand >>= 1 + LSL D0Ar4, D1Re0, #(32-1) + OR D0Ar2, D0Ar2, D0Ar4 + LSR D1Re0, D1Re0, #1 + + ADD D1Ar3, D1Ar3, #1 ! exp += 1 + +$L2: + MOV D0Re0, D0Ar2 ! mantisa + NORM D1Ar1, D1Re0 ! normalize up + BZ $L4 ! MSWord zero + + CMP D1Ar1, #0 ! Already normalised ? + BZ $L5 ! yes, skip normalisation + + MOV D0Ar4, D1Re0 + FFB D0Ar4, D0Ar4 + + LSL D1Re0, D1Re0, D1Ar1 + ADD D0Ar4, D0Ar4, #2 + LSR D1Ar5, D0Re0, D0Ar4 + OR D1Re0, D1Re0, D1Ar5 + MOV D0Ar4, D1Ar1 + LSL D0Re0, D0Re0, D0Ar4 + + SUB D1Ar3, D1Ar3, D1Ar1 + B $L5 + +$L4: + SWAP D1Re0, D0Re0 ! D1Re0 <- D0Re0, D0Re0 <- #0 + SUB D1Ar3, D1Ar3, #32 + + NORM D1Ar1, D1Re0 + LSRLT D1Re0, D1Re0, #1 ! Watch out for low 32-bits with MSbit set + ADDLT D1Ar3, D1Ar3, #1 ! adjust exp and mantissa + + LSL D1Re0, D1Re0, D1Ar1 + + SUB D1Ar3, D1Ar3, D1Ar1 + +$L5: + TST D0Re0, #(1<<9) ! Test MSbit discared + LSR D0Re0, D0Re0, #10 ! Discard excess bits not representable + LSL D0Ar4, D1Re0, #(32 - 10) + LSR D1Re0, D1Re0, #10 + OR D0Re0, D0Re0, D0Ar4 + BZ $L7 + + ADDS D0Re0, D0Re0, #1 ! Round up if MSbit discarded non-zero + ADDCS D1Re0, D1Re0, #1 + +$L6: + TSTT D1Re0, #0xFFE0 ! Round up overflowed? + BZ $L7 + + ADD D1Ar3, D1Ar3, #1 ! yes, adjust exp +=1 + LSR D0Re0, D0Re0, #1 ! and adjust significand shifting >>1 + LSL D0Ar4, D1Re0, #(32 - 1) + LSR D1Re0, D1Re0, #1 + OR D0Re0, D0Re0, D0Ar4 + B $L6 + +$L7: + ANDMT D1Re0, D1Re0, #0x000F ! remove hidden bit <- mantisa MSword + + LSL D1Ar3, D1Ar3, #(52-32) ! position exp in result + MOV D1Ar1, D0Ar6 ! sign + OR D1Re0, D1Re0, D1Ar1 ! combine with sign -> sign | mant + OR D1Re0, D1Re0, D1Ar3 ! combine with exp -> sign | exp | mant + + MOV PC, D1RtP + .size ___floatdidf,.-___floatdidf +#endif + +#ifdef L_floatdisf +!! +!! signed signed long long -> float conversion +!! + .text + .global ___floatdisf + .type ___floatdisf,function +___floatdisf: + + MOV D0Ar6, #(127+32+30) ! exp + MOV D0Re0, #0 ! sign + + CMP D1Ar1, #0 + BLT $L1 + BGT $L2 + + CMP D0Ar2, #0 + BNE $L2 + + MOV PC, D1RtP +$L1: + ! <0 + MOVT D0Re0, #0x8000 + + NEGS D0Ar2, D0Ar2 ! negate + NEG D1Ar1, D1Ar1 + SUBNZ D1Ar1, D1Ar1, #1 + + CMP D1Ar1, #0 ! deal min DI + BGT $L2 ! branch not min DI + + LSR D0Ar2, D0Ar2, #1 ! significand >> 1 + MOV D0Ar4, D1Ar1 + LSL D0Ar4, D0Ar4, #(32-1) + OR D0Ar2, D0Ar2, D0Ar4 + LSR D1Ar1, D1Ar1, #1 + + ADD D0Ar6, D0Ar6, #1 ! exp += 1 + +$L2: ! normalize up + NORM D1Re0, D1Ar1 + BZ $L4 ! MSWord zero + + CMP D1Re0, #0 ! Already normalised ? + BZ $L5 ! yes, skip normalisation + + MOV D0Ar4, D1Ar1 + FFB D0Ar4, D0Ar4 + + LSL D1Ar1, D1Ar1, D1Re0 + ADD D0Ar4, D0Ar4, #2 + LSR D1Ar5, D0Ar2, D0Ar4 + OR D1Ar1, D1Ar1, D1Ar5 + MOV D0Ar4, D1Re0 + LSL D0Ar2, D0Ar2, D0Ar4 + + MOV D0Ar4, D1Re0 + SUB D0Ar6, D0Ar6, D0Ar4 + B $L5 + +$L4: + SWAP D1Ar1, D0Ar2 ! D1Ar1 <- D0Ar2, D0Ar2 <- #0 + SUB D0Ar6, D0Ar6, #32 + + NORM D1Re0, D1Ar1 + LSL D1Ar1, D1Ar1, D1Re0 + + MOV D0Ar4, D1Re0 + SUB D0Ar6, D0Ar6, D0Ar4 + +$L5: + MOV D0Ar2, D1Ar1 + TST D0Ar2, #(1<<6) ! Round before discarding + LSR D0Ar2, D0Ar2, #7 ! Discard excess bits not representable + ADDNZ D0Ar2, D0Ar2, #1 + +$L6: + TSTT D0Ar2, #0xFF00 ! Round up overflowed? + BZ $L7 + + ADD D0Ar6, D0Ar6, #1 ! yes, adjust exp += 1 + LSR D0Ar2, D0Ar2, #1 ! adn adjust significand shifting >>1 + B $L6 + +$L7: + ANDMT D0Ar2, D0Ar2, #0x007F ! remove hidden bit <- mantisa + + LSL D0Ar6, D0Ar6, #23 ! position exp in result + OR D0Re0, D0Re0, D0Ar6 ! combine sign with exp -> sign|exp + OR D0Re0, D0Re0, D0Ar2 ! combine sign|exp with mant -> sign|exp|mant + + MOV PC, D1RtP + .size ___floatdisf,.-___floatdisf +#endif + +#ifdef L_floatsidf +!! +!! signed int/long -> double conversion +!! + .text + .global ___floatsidf + .type ___floatsidf,function + .align 2 +___floatsidf: + + MOV D1Ar5, #(1023+30) ! exp + MOV D1Re0, #0 ! assume result +ve + CMP D1Ar1, #0 ! num < 0 + BGT $L2 + + ! <= 0 + MOVEQ D0Re0, D1Re0 + MOVEQ PC, D1RtP ! num == 0 return 0 + + ! < 0 + MOVT D1Re0, #0x8000 ! result will be -ve + NEG D1Ar1, D1Ar1 ! num -= num + CMP D1Ar1, #0 ! num < 0 + BGT $L2 + + ! < 0 (num == MIN_INT) + LSR D1Ar1, D1Ar1, #1 ! num >>= 1 + ADD D1Ar5, D1Ar5, #1 ! exp += 1 + +$L2: + NORM D1Ar3, D1Ar1 ! Make MSBit non-zero + LSL D1Ar1, D1Ar1, D1Ar3 ! num <<= N + SUB D1Ar5, D1Ar5, D1Ar3 ! exp -= N + + MOV D0Re0, D1Ar1 ! position mantisa LSWord + LSL D0Re0, D0Re0, #(32-10) + + LSL D1Ar5, D1Ar5, #(52-32) ! position exponent + OR D1Re0, D1Re0, D1Ar5 ! combine sign | exp + + LSR D1Ar1, D1Ar1, #10 ! position significand MSWord + ANDMT D1Ar1, D1Ar1, #0x000F ! discard hidden bit + OR D1Re0, D1Re0, D1Ar1 ! combine sign | exp | mantisa + + MOV PC, D1RtP + .size ___floatsidf,.-___floatsidf +#endif + +#ifdef L_floatunsidf +!! +!! unsigned int/long -> double conversion +!! + .text + .global ___floatunsidf + .type ___floatunsidf,function + .align 2 +___floatunsidf: + + MOV D1Ar5, #(1023+30) ! exp + MOV D1Re0, #0 ! assume result +ve + CMP D1Ar1, #0 ! num == 0 + + ! == 0 + MOVEQ D0Re0, D1Re0 + MOVEQ PC, D1RtP ! num == 0 return 0 + + NORM D1Ar3, D1Ar1 ! Make MSBit non-zero + LSL D1Ar1, D1Ar1, D1Ar3 ! num <<= N + SUB D1Ar5, D1Ar5, D1Ar3 ! exp -= N + + MOV D0Re0, D1Ar1 ! position mantisa LSWord + LSL D0Re0, D0Re0, #(32-10) + + LSL D1Ar5, D1Ar5, #(52-32) ! position exponent + OR D1Re0, D1Re0, D1Ar5 ! combine sign | exp + + LSR D1Ar1, D1Ar1, #10 ! position significand MSWord + ANDMT D1Ar1, D1Ar1, #0x000F ! discard hidden bit + OR D1Re0, D1Re0, D1Ar1 ! combine sign | exp | mantisa + + MOV PC, D1RtP + .size ___floatunsidf,.-___floatunsidf +#endif + +#ifdef L_floatsisf +!! +!! signed int/long -> float conversion +!! + .text + .global ___floatsisf + .type ___floatsisf,function + .align 2 +___floatsisf: + MOV D0Ar6, #(127+32-2) ! exp + MOV D1Re0, #0 ! sign + ORS D0Re0, D1Ar1, D1Ar1 ! num ? -ve, zero, +ve + BGT $L2 ! branch, +ve + ! <= + MOVZ PC, D1RtP ! zero, return 0 + + ! < 0 + MOVT D1Re0, #0x8000 ! sign + NEGS D1Ar1, D1Ar1 ! Make >= 0 + BGT $L2 ! branch, +ve + + ! Handle MIN INT + LSR D1Ar1, D1Ar1, #1 ! num >>= 1 + ADD D0Ar6, D0Ar6, #1 ! exp += 1 + +$L2: ! num > 0 + NORM D1Ar3, D1Ar1 ! Shift up N bits + LSL D1Ar1, D1Ar1, D1Ar3 ! num <<= N + MOV D0Ar4, D1Ar3 + SUB D0Ar6, D0Ar6, D0Ar4 ! exp -= N + + LSR D1Ar1, D1Ar1, #(8-2) + ADD D1Ar1, D1Ar1, #1 ! round + MOV D0Re0, D1Ar1 ! mantisa --> D0Re0 + + TSTT D1Ar1, #0xFE00 ! rounding overflowed ? + ADDNZ D0Ar6, D0Ar6, #1 ! yes, adjust exp++ + LSR D0Re0, D0Re0, #1 ! position mantisa + + LSL D0Ar6, D0Ar6, #23 ! position exponent + ANDMT D0Re0, D0Re0, #0x007F ! remove hidden bit + OR D0Re0, D0Re0, D0Ar6 ! man | exp + + MOV D0Ar6, D1Re0 + OR D0Re0, D0Re0, D0Ar6 ! |sign + + MOV PC, D1RtP + .size ___floatsisf,.-___floatsisf +#endif + +#ifdef L_floatunsisf +!! +!! signed int/long -> float conversion +!! + .text + .global ___floatunsisf + .type ___floatunsisf,function + .align 2 +___floatunsisf: + MOV D0Ar6, #(127+32-2) ! exp + ORS D0Re0, D1Ar1, D1Ar1 ! num ? -ve, zero, +ve + ! <= + MOVZ PC, D1RtP ! zero, return 0 + + NORM D1Ar3, D1Ar1 ! Shift up N bits + LSL D1Ar1, D1Ar1, D1Ar3 ! num <<= N + MOV D0Ar4, D1Ar3 + SUB D0Ar6, D0Ar6, D0Ar4 ! exp -= N + + LSR D1Ar1, D1Ar1, #(8-2) + ADD D1Ar1, D1Ar1, #1 ! round + MOV D0Re0, D1Ar1 ! mantisa --> D0Re0 + + TSTT D1Ar1, #0xFE00 ! rounding overflowed ? + ADDNZ D0Ar6, D0Ar6, #1 ! yes, adjust exp++ + LSR D0Re0, D0Re0, #1 ! position mantisa + + LSL D0Ar6, D0Ar6, #23 ! position exponent + ANDMT D0Re0, D0Re0, #0x007F ! remove hidden bit + OR D0Re0, D0Re0, D0Ar6 ! man | exp + + MOV PC, D1RtP + .size ___floatunsisf,.-___floatunsisf +#endif + +#ifdef L_unordsf2 + .text + .global ___unordsf2 + .type ___unordsf2,function + .align 2 +___unordsf2: + MOV PC, D1RtP +#endif + +#ifdef L_unorddf2 + .text + .global ___unorddf2 + .type ___unorddf2,function + .align 2 +___unorddf2: + MOV PC, D1RtP + .size ___unorddf2,.-___unorddf2 +#endif + diff -Nur gcc-4.2.4.orig/gcc/config/metag/linux-atomic.asm gcc-4.2.4/gcc/config/metag/linux-atomic.asm --- gcc-4.2.4.orig/gcc/config/metag/linux-atomic.asm 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/linux-atomic.asm 2015-07-03 18:46:05.749283542 -0500 @@ -0,0 +1,227 @@ +.macro linkset_check + DEFR D0FrT, TXSTAT + ANDT D0FrT, D0FrT, #HI(0x3F000000) + CMPT D0FrT, #HI(0x02000000) +.endm + +.macro func_start func_name + .text + .global \func_name + .type \func_name,function + .align 2 +\func_name: +1: +.endm + +.macro func_end func_name + linkset_check + BNE 1b + cache_flush + 2: MOV PC, D1RtP + .size \func_name, .-\func_name +.endm + +.macro cache_flush + MOV D0FrT, #0 + DCACHE [D1Ar1], D0FrT +.endm + +.macro sync_fetch_and_op op op_name n mode +func_start ___sync_fetch_and_\op_name\()_\n + LNKGET\mode D0Re0, [D1Ar1] + \op D0FrT, D0Re0, D0Ar2 + LNKSET\mode [D1Ar1], D0FrT +func_end ___sync_fetch_and_\op_name\()_\n +.endm + +.macro sync_fetch_and_op_8 op op_name +func_start ___sync_fetch_and_\op_name\()_8 + LNKGETL D0Re0, D1Re0, [D1Ar1] + \op A0.2, D0Re0, D0Ar4 + \op A1.2, D1Re0, D1Ar3 + LNKSETL [D1Ar1], A0.2, A1.2 +func_end ___sync_fetch_and_\op_name\()_8 +.endm + +.macro sync_fetch_and_alu_op_8 op op_name +func_start ___sync_fetch_and_\op_name\()_8 + LNKGETL D0Re0, D1Re0, [D1Ar1] + \op\()S A0.2, D0Re0, D0Ar4 + \op A1.2, D1Re0, D1Ar3 + \op\()CS A1.2, A1.2, #1 + LNKSETL [D1Ar1], A0.2, A1.2 +func_end ___sync_fetch_and_\op_name\()_8 +.endm + +.macro sync_op_and_fetch op op_name n mode +func_start ___sync_\op_name\()_and_fetch_\n + LNKGET\mode D0Re0, [D1Ar1] + \op D0Re0, D0Re0, D0Ar2 + LNKSET\mode [D1Ar1], D0Re0 +func_end ___sync_\op_name\()_and_fetch_\n +.endm + +.macro sync_op_and_fetch_8 op op_name +func_start ___sync_\op_name\()_and_fetch_8 + LNKGETL D0Re0, D1Re0, [D1Ar1] + \op D0Re0, D0Re0, D0Ar4 + \op D1Re0, D1Re0, D1Ar3 + LNKSETL [D1Ar1], D0Re0, D1Re0 +func_end ___sync_\op_name\()_and_fetch_8 +.endm + +.macro sync_alu_op_and_fetch_8 op op_name +func_start ___sync_\op_name\()_and_fetch_8 + LNKGETL D0Re0, D1Re0, [D1Ar1] + \op\()S D0Re0, D0Re0, D0Ar4 + \op D1Re0, D1Re0, D1Ar3 + \op\()CS D1Re0, D1Re0, #1 + LNKSETL [D1Ar1], D0Re0, D1Re0 +func_end ___sync_\op_name\()_and_fetch_8 +.endm + +.macro sync_fetch_and_op_neg op op_name n mode +func_start ___sync_fetch_and_\op_name\()_\n + LNKGET\mode D0Re0, [D1Ar1] + \op D0FrT, D0Re0, D0Ar2 + XOR D0FrT, D0FrT, #-1 + LNKSET\mode [D1Ar1], D0FrT +func_end ___sync_fetch_and_\op_name\()_\n +.endm + +.macro sync_fetch_and_op_neg_8 op op_name +func_start ___sync_fetch_and_\op_name\()_8 + LNKGETL D0Re0, D1Re0, [D1Ar1] + \op D0Ar6, D0Re0, D0Ar4 + \op D1Ar5, D1Re0, D1Ar3 + XOR D0Ar6, D0Ar6, #-1 + XOR D1Ar5, D1Ar5, #-1 + LNKSETL [D1Ar1], D0Ar6, D1Ar5 +func_end ___sync_fetch_and_\op_name\()_8 +.endm + +.macro sync_op_neg_and_fetch op op_name n mode +func_start ___sync_\op_name\()_and_fetch_\n + LNKGET\mode D0Re0, [D1Ar1] + \op D0Re0, D0Re0, D0Ar2 + XOR D0Re0, D0Re0, #-1 + LNKSET\mode [D1Ar1], D0Re0 +func_end ___sync_\op_name\()_and_fetch_\n +.endm + +.macro sync_op_neg_and_fetch_8 op op_name +func_start ___sync_\op_name\()_and_fetch_8 + LNKGETL D0Re0, D1Re0, [D1Ar1] + \op D0Re0, D0Re0, D0Ar4 + \op D1Re0, D1Re0, D1Ar3 + XOR D0Re0, D0Re0, #-1 + XOR D1Re0, D1Re0, #-1 + LNKSETL [D1Ar1], D0Re0, D1Re0 +func_end ___sync_\op_name\()_and_fetch_8 +.endm + +.macro sync_val_compare_and_swap n mode +func_start ___sync_val_compare_and_swap_\n + LNKGET\mode D0Re0, [D1Ar1] + CMP D0Re0, D0Ar2 + LNKSET\mode\()EQ [D1Ar1], D1Ar3 + BNE 2f +func_end ___sync_val_compare_and_swap_\n +.endm + +func_start ___sync_val_compare_and_swap_8 + LNKGETL D0Re0, D1Re0, [D1Ar1] + CMP D0Re0, D0Ar4 + CMPEQ D1Re0, D1Ar3 + LNKSETLEQ [D1Ar1], D0Ar6, D1Ar5 + BNE 2f +func_end ___sync_val_compare_and_swap_8 + +.macro sync_bool_compare_and_swap n mode +func_start ___sync_bool_compare_and_swap_\n + MOV D0Re0, #1 + 1: LNKGET\mode D0FrT, [D1Ar1] + CMP D0FrT, D0Ar2 + LNKSET\mode\()EQ [D1Ar1], D1Ar3 + XORNE D0Re0, D0Re0, D0Re0 + BNE 2f +func_end ___sync_bool_compare_and_swap_\n +.endm + +func_start ___sync_bool_compare_and_swap_8 + MOV D0Re0, #1 + 1: LNKGETL A0.2, A1.2, [D1Ar1] + CMP D0Ar4, A0.2 + CMPEQ D1Ar3, A1.2 + LNKSETLEQ [D1Ar1], D0Ar6, D1Ar5 + XORNE D0Re0, D0Re0, D0Re0 + BNE 2f +func_end ___sync_bool_compare_and_swap_8 + +.macro sync_lock_test_and_set n mode +func_start ___sync_lock_test_and_set_\n + LNKGET\mode D0Re0, [D1Ar1] + LNKSET\mode [D1Ar1], D0Ar2 +func_end ___sync_lock_test_and_set_\n +.endm + +func_start ___sync_lock_test_and_set_8 + LNKGETL D0Re0, D1Re0, [D1Ar1] + LNKSETL [D1Ar1], D0Ar4, D1Ar3 +func_end ___sync_lock_test_and_set_8 + +.macro sync_fetch_and_op_size op op_name + sync_fetch_and_op \op \op_name 1 B + sync_fetch_and_op \op \op_name 2 W + sync_fetch_and_op \op \op_name 4 D + + sync_op_and_fetch \op \op_name 1 B + sync_op_and_fetch \op \op_name 2 W + sync_op_and_fetch \op \op_name 4 D +.endm + +.macro sync_fetch_and_op_neg_size op op_name + sync_fetch_and_op_neg \op \op_name 1 B + sync_fetch_and_op_neg \op \op_name 2 W + sync_fetch_and_op_neg \op \op_name 4 D + sync_fetch_and_op_neg_8 \op \op_name + + sync_op_neg_and_fetch \op \op_name 1 B + sync_op_neg_and_fetch \op \op_name 2 W + sync_op_neg_and_fetch \op \op_name 4 D + sync_op_neg_and_fetch_8 \op \op_name +.endm + +sync_fetch_and_op_size ADD add +sync_fetch_and_op_size SUB sub +sync_fetch_and_op_size OR or +sync_fetch_and_op_size AND and +sync_fetch_and_op_size XOR xor + +sync_fetch_and_op_8 OR or +sync_fetch_and_op_8 AND and +sync_fetch_and_op_8 XOR xor + +sync_op_and_fetch_8 OR or +sync_op_and_fetch_8 AND and +sync_op_and_fetch_8 XOR xor + +sync_fetch_and_alu_op_8 ADD add +sync_fetch_and_alu_op_8 SUB sub + +sync_alu_op_and_fetch_8 ADD add +sync_alu_op_and_fetch_8 SUB sub + +sync_fetch_and_op_neg_size AND nand + +sync_val_compare_and_swap 1 B +sync_val_compare_and_swap 2 W +sync_val_compare_and_swap 4 D + +sync_bool_compare_and_swap 1 B +sync_bool_compare_and_swap 2 W +sync_bool_compare_and_swap 4 D + +sync_lock_test_and_set 1 B +sync_lock_test_and_set 2 W +sync_lock_test_and_set 4 D diff -Nur gcc-4.2.4.orig/gcc/config/metag/linux-elf.h gcc-4.2.4/gcc/config/metag/linux-elf.h --- gcc-4.2.4.orig/gcc/config/metag/linux-elf.h 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/linux-elf.h 2015-07-03 18:46:05.749283542 -0500 @@ -0,0 +1,77 @@ +/* Definitions of target machine for GNU compiler + for Meta Linux-based GNU systems using ELF. + Copyright (C) 2004, 2007 Free Software Foundation, Inc. + Contributed by Imagination Technologies Ltd (toolkit@metagence.com) + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#undef TARGET_VERSION +#define TARGET_VERSION fputs (" (Metag Linux GNU)", stderr) + +#undef SUBTARGET_EXTRA_SPECS +#define SUBTARGET_EXTRA_SPECS \ + { "elf_dynamic_linker", ELF_DYNAMIC_LINKER }, + +#define ELF_DYNAMIC_LINKER "/lib/ld-uClibc.so.0" + +#define TARGET_OS_CPP_BUILTINS() \ + do \ + { \ + LINUX_TARGET_OS_CPP_BUILTINS (); \ + } \ +while (0) + +#undef LIB_SPEC +#define LIB_SPEC \ + "%{pthread:-lpthread} " \ + "%{shared:-lc} " \ + "%{!shared: %{profile:-lc_p} %{!profile:-lc}} " + +#undef TYPE_OPERAND_FMT +#define TYPE_OPERAND_FMT "@%s" + +#undef GLOBAL_ASM_OP +#define GLOBAL_ASM_OP "\t.global\t" + + +/* Provide a STARTFILE_SPEC appropriate for ELF. Here we add the + (even more) magical crtbegin.o file which provides part of the + support for getting C++ file-scope static object constructed before + entering `main'. + + Don't bother seeing crtstuff.c -- there is absolutely no hope of + getting that file to understand multiple GPs. GNU Libc provides a + hand-coded version that is used on Linux; it could be copied here + if there is ever a need. */ + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC \ + "%{!shared: " \ + "%{pg:crt1.o%s} %{!pg:%{p:crt1.o%s} " \ + "%{!p:%{profile:crt1.o%s} " \ + "%{!profile:crt1.o%s}}}} " \ + "crti.o%s %{!shared:crtbegin.o%s} %{shared:crtbeginS.o%s} " + +/* Provide a ENDFILE_SPEC appropriate for ELF. Here we tack on the + magical crtend.o file which provides part of the support for + getting C++ file-scope static object constructed before entering + `main', followed by a normal ELF "finalizer" file, `crtn.o'. */ + +#undef ENDFILE_SPEC +#define ENDFILE_SPEC \ + "%{!shared:crtend.o%s} %{shared:crtendS.o%s} crtn.o%s" + diff -Nur gcc-4.2.4.orig/gcc/config/metag/linux.h gcc-4.2.4/gcc/config/metag/linux.h --- gcc-4.2.4.orig/gcc/config/metag/linux.h 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/linux.h 2015-07-03 18:46:05.749283542 -0500 @@ -0,0 +1,32 @@ +/* Definitions of target machine for GNU compiler, + for Meta Linux-based GNU systems. + Copyright (C) 2005, 2007 Free Software Foundation, Inc. + Contributed by Imagination Technologies Ltd (toolkit@metagence.com) + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#undef CPP_SUBTARGET_SPEC +#define CPP_SUBTARGET_SPEC \ + "%{posix:-D_POSIX_SOURCE} " \ + "%{pthread:-D_REENTRANT -D_PTHREADS} " + +#define NO_IMPLICIT_EXTERN_C + +#define CPLUSPLUS_CPP_SPEC "-D_GNU_SOURCE %(cpp)" + +#undef TARGET_C99_FUNCTIONS +#define TARGET_C99_FUNCTIONS 1 diff -Nur gcc-4.2.4.orig/gcc/config/metag/metag.c gcc-4.2.4/gcc/config/metag/metag.c --- gcc-4.2.4.orig/gcc/config/metag/metag.c 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/metag.c 2015-07-03 18:46:05.765283542 -0500 @@ -0,0 +1,7661 @@ +/* Definitions of target machine for GNU compiler. + Imagination Technologies Meta version. + Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2010 + Imagination Technologies Ltd + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "rtl.h" +#include "tree.h" +#include "obstack.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "real.h" +#include "insn-config.h" +#include "conditions.h" +#include "insn-flags.h" +#include "output.h" +#include "insn-attr.h" +#include "flags.h" +#include "reload.h" +#include "function.h" +#include "expr.h" +#include "optabs.h" +#include "toplev.h" +#include "recog.h" +#include "ggc.h" +#include "except.h" +#include "c-pragma.h" +#include "integrate.h" +#include "cfgloop.h" +#include "tm_p.h" +#include "timevar.h" +#include "options.h" +#include "cgraph.h" +#include "target.h" +#include "target-def.h" +#include "tm-constrs.h" +#include "langhooks.h" +#include "version.h" +#include + +/* Is the given character a logical line separator for the assembler? + Set the default to be the gas line separator and allow the embedded + backend to override it. */ +#ifndef IS_ASM_LOGICAL_LINE_SEPARATOR +#define IS_ASM_LOGICAL_LINE_SEPARATOR(C) ((C) == ';') +#endif + +#define IS_PSEUDO_REGNO(REGNO) \ + ((REGNO) != INVALID_REGNUM && (REGNO) >= FIRST_PSEUDO_REGISTER) + +#define IS_HARD_OR_VIRT_REGNO(REGNO) \ + ((REGNO) != INVALID_REGNUM && (REGNO) < FIRST_PSEUDO_REGISTER) + +#define NO_FUNCTION_CSE + +#define REGNO_BIT(REGNO) (1U << ((REGNO) >> 1)) + +#define df_regs_ever_live_p(REGNO) regs_ever_live[(unsigned)(REGNO)] + +static tree metag_handle_model_decl_attribute (tree *, tree, tree, int, bool *); +static int metag_consumer_stalls_from_load_multi (rtx, rtx); +static bool metag_consumer_is_o2r (rtx, rtx, int, int); +static bool metag_pass_in_reg (CUMULATIVE_ARGS *, enum machine_mode, tree, bool); +static bool metag_same_reg_p (rtx, rtx, bool); +static long metag_const_double_sfmode (rtx); +static unsigned int metag_calculate_ech_ctx (void); +static unsigned int metag_adjust_savesize_ech (unsigned int*, unsigned int*, + unsigned int*); +static void metag_emit_byte_swap16 (rtx, rtx); +static void metag_emit_byte_swap32 (rtx, rtx); +static int metag_asm_insn_count (rtx); +static bool metag_is_label_within_function (rtx); +static rtx metag_function_return_reg (enum machine_mode mode); + +/* METAG specific attribute support. + + model - select code model used to access data + + on VAR_DECL effects code that references symbol (weak effect) + + small: intended to be addressed using A1GbP+OG(..) (1 inst) + large: intended to be addresses using A1GbP+HI(..)+LO(..) (3 insts) + + on FUNCTION_DECL effects code within function concerned (strong effect) + + small: access all small data using A1GbP+OG(..) (no fn overhead) + access all larger data using A1GbP+OLA(..) + large: access all data using A1GbP+HI(..)+LO(..) (no fn overhead) + +*/ + +const struct +attribute_spec metag_attribute_table[] = +{ +/*{ name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ + { "model", 1, 1, true, false, false, metag_handle_model_decl_attribute }, + { NULL, 0, 0, false, false, false, NULL } +}; + +#define DEF_MCC \ + DEF_MCC_CODES(A, NV, "A"), \ + DEF_MCC_CODES(NV, A, "NV"), \ + DEF_MCC_CODES(EQ, NE, "EQ"), \ + DEF_MCC_CODES(NE, EQ, "NE"), \ + DEF_MCC_CODES(LO, HS, "LO"), \ + DEF_MCC_CODES(HS, LO, "HS"), \ + DEF_MCC_CODES(MI, PL, "MI"), \ + DEF_MCC_CODES(PL, MI, "PL"), \ + DEF_MCC_CODES(VS, VC, "VS"), \ + DEF_MCC_CODES(VC, VS, "VC"), \ + DEF_MCC_CODES(HI, LS, "HI"), \ + DEF_MCC_CODES(LS, HI, "LS"), \ + DEF_MCC_CODES(GE, LT, "GE"), \ + DEF_MCC_CODES(LT, GE, "LT"), \ + DEF_MCC_CODES(GT, LE, "GT"), \ + DEF_MCC_CODES(LE, GT, "LE"), \ + DEF_MCC_CODES(CS, CC, "CS"), \ + DEF_MCC_CODES(CC, CS, "CC"), \ + DEF_MCC_CODES(FEQ, UNE, "FEQ"), \ + DEF_MCC_CODES(UNE, FEQ, "UNE"), \ + DEF_MCC_CODES(FGT, NFGT, "FGT"), \ + DEF_MCC_CODES(FGE, NFGE, "FGE"), \ + DEF_MCC_CODES(FLT, NFLT, "FLT"), \ + DEF_MCC_CODES(FLE, NFLE, "FLE"), \ + DEF_MCC_CODES(U, NU, "UVS"), \ + DEF_MCC_CODES(FLEG, NFLEG, "FVC"), \ + DEF_MCC_CODES(UGT, NUGT, "UGT"), \ + DEF_MCC_CODES(UGE, NUGE, "UGE"), \ + DEF_MCC_CODES(ULT, NULT, "ULT"), \ + DEF_MCC_CODES(ULE, NULE, "ULE"), \ + DEF_MCC_CODES(NFGT, FGT, "ULE"), \ + DEF_MCC_CODES(NFGE, FGE, "ULT"), \ + DEF_MCC_CODES(NFLT, FLT, "UGE"), \ + DEF_MCC_CODES(NFLE, FLE, "UGT"), \ + DEF_MCC_CODES(NU, U, "FVC"), \ + DEF_MCC_CODES(NFLEG, FLEG, "UVS"), \ + DEF_MCC_CODES(NUGT, UGT, "FLE"), \ + DEF_MCC_CODES(NUGE, UGE, "FLT"), \ + DEF_MCC_CODES(NULT, ULT, "FGE"), \ + DEF_MCC_CODES(NULE, ULE, "FGT") + +#define MCC_MAX MCC_NULE + +#define DEF_MCC_CODES(CODE, INV, ASMCODE) MCC_##CODE + +typedef enum /* GCC : META condition codes */ +{ + DEF_MCC +} metag_cc; + +static metag_cc get_metag_cc (rtx); +static metag_cc get_metag_cc_float (enum rtx_code); +static bool metag_is_cc_quiet (metag_cc); + +#undef DEF_MCC_CODES +#define DEF_MCC_CODES(CODE, INV, ASMCODE) MCC_##INV +static metag_cc const metag_inv_cc[MCC_MAX + 1] = +{ + DEF_MCC +}; + +#undef DEF_MCC_CODES +#define DEF_MCC_CODES(CODE, INV, ASMCODE) ASMCODE + +static const char * const metag_cc_names[MCC_MAX + 1] = +{ + DEF_MCC +}; + +rtx metag_compare_op0; +rtx metag_compare_op1; + +enum metag_model metag_model; + +/* Which META core we're generating code for. */ +enum metac_target metac_target; + +/* Which META core we are scheduling for see (define_attr "metacore" ...) */ +enum attr_metacore metacore; + +/* What FPU pipeline are we targetting */ +int metag_fpu_single = 0; + +/* Are we allowed to use any fpu resources */ +int metag_fpu_resources = 0; + +/* How wide is the widest memory access on this core */ +int metag_memory_width = 64; + +/* Should MiniM jump tables be emitted short, long or auto detected */ +enum metag_jump_table_branch metag_jump_table_branch = METAG_MINIM_JUMP_TABLE_BRANCH_AUTO; + +/* -mextensions flags */ +bool metag_meta2_bex_enabled = false; + +/* Force tbictxsave to be enabled */ +int metag_force_tbictxsave = true; + +/* A finite state machine takes care of noticing whether or not instructions + can be conditionally executed, and thus decrease execution time and code + size by deleting branch instructions. The fsm is controlled by + final_prescan_insn, and controls the actions of ASM_OUTPUT_OPCODE. */ + +/* For an explanation of these variables, see final_prescan_insn below. */ +static int metag_ccfsm_state; +static metag_cc metag_current_cc; +static GTY(()) rtx metag_target_insn = NULL_RTX; +static int metag_target_label; +static int metag_max_insns_skipped = 10; + +#define METAG_DEBUG_CCEXEC 0 + +#if METAG_DEBUG_CCEXEC +static const char *attr_cond_name (enum attr_cond); +static const char *attr_ccstate_name (enum attr_ccstate); +static const char *attr_predicale_name (enum attr_predicable); +#endif + + +bool +metag_datareg_p (unsigned int regno) +{ +#if FIRST_DATA_REG == 0 + return regno <= LAST_DATA_REG; +#else + return FIRST_DATA_REG <= regno && regno <= LAST_DATA_REG; +#endif +} + +bool +metag_addrreg_p (unsigned int regno) +{ + return FIRST_ADDR_REG <= regno && regno <= LAST_ADDR_REG; +} + +bool +metag_fpcreg_p (unsigned int regno) +{ + return FIRST_FP_REG <= regno && regno <= LAST_FP_REG; +} + +bool +metag_fppreg_p (unsigned int regno) +{ + return FIRST_FP_REG <= regno && regno <= LAST_FP_REG && ((regno - FIRST_FP_REG) & 1) == 0; +} + +#define METAG_DATAREG_UNIT(REGNO) ((REGNO) & 1) +#define METAG_DATAREG_REGN(REGNO) ((REGNO) >> 1) + +static long +metag_const_double_sfmode (rtx op) +{ + long l; + REAL_VALUE_TYPE rv; + + REAL_VALUE_FROM_CONST_DOUBLE (rv, op); + REAL_VALUE_TO_TARGET_SINGLE (rv, l); + return l; +} + +void +metag_split_movsi_immediate (rtx operands[]) +{ + rtx target= operands[0]; + rtx imm = operands[1]; + HOST_WIDE_INT value = INTVAL (imm); + + if ((value & 0x0000FFFF) == 0) + emit_move_insn (target, imm); + else if ((value & 0xFFFF0000) == 0) + emit_move_insn (target, imm); + else if ((value & 0xFFFF8000) == 0xFFFF8000) + emit_move_insn (target, imm); + else + { + HOST_WIDE_INT ival; + + ival = trunc_int_for_mode (value & 0xFFFF0000, SImode); + emit_move_insn (target, GEN_INT (ival)); + + ival = trunc_int_for_mode (value & 0x0000FFFF, SImode); + emit_insn (gen_addsi3 (target, target, GEN_INT (ival))); + } +} + +void +metag_split_movsf_immediate (rtx operands[]) +{ + rtx ops[2]; + + ops[0] = gen_rtx_REG (SImode, REGNO (operands[0])); + if (CONST_DOUBLE_P (operands[1])) + { + HOST_WIDE_INT ival = metag_const_double_sfmode (operands[1]); + + ival = trunc_int_for_mode (ival, SImode); + ops[1] = GEN_INT (ival); + } + else if (CONST_INT_P (operands[1])) + ops[1] = operands[1]; + else + gcc_unreachable (); + + metag_split_movsi_immediate (ops); +} + +void +metag_split_movdi (rtx operands[]) +{ + unsigned int dst_reg = REGNO (operands[0]); + unsigned int src_reg = REGNO (operands[1]); + + emit_move_insn (gen_rtx_REG (SImode, dst_reg), + gen_rtx_REG (SImode, src_reg)); + + emit_move_insn (gen_rtx_REG (SImode, dst_reg + 1), + gen_rtx_REG (SImode, src_reg + 1)); +} + +void +metag_split_movdi_immediate (rtx operands[]) +{ + unsigned int dst_reg = REGNO (operands[0]); + rtx imm[2]; + rtx ops[2]; + + split_double (operands[1], &imm[0], &imm[1]); + + ops[0] = gen_rtx_REG (SImode, dst_reg); + ops[1] = imm[0]; + metag_split_movsi_immediate (ops); + + ops[0] = gen_rtx_REG (SImode, dst_reg + 1); + ops[1] = imm[1]; + metag_split_movsi_immediate (ops); +} + +void +metag_split_movdf (rtx operands[]) +{ + unsigned int dst_reg = REGNO (operands[0]); + unsigned int src_reg = REGNO (operands[1]); + + emit_move_insn (gen_rtx_REG (SImode, dst_reg), + gen_rtx_REG (SImode, src_reg)); + + emit_move_insn (gen_rtx_REG (SImode, dst_reg + 1), + gen_rtx_REG (SImode, src_reg + 1)); +} + +void +metag_split_movdf_immediate (rtx operands[]) +{ + unsigned int dst_reg = REGNO (operands[0]); + rtx imm[2]; + rtx ops[2]; + + split_double (operands[1], &imm[0], &imm[1]); + + ops[0] = gen_rtx_REG (SImode, dst_reg); + ops[1] = imm[0]; + metag_split_movsi_immediate (ops); + + ops[0] = gen_rtx_REG (SImode, dst_reg + 1); + ops[1] = imm[1]; + + metag_split_movsi_immediate (ops); +} + +#define metag_non_leaf_function_p() \ + (reload_completed ? cfun->machine->non_leaf : !leaf_function_p ()) + +#define TBICTX_XMCC_BIT 0x0020 +#define TBICTX_XDX8_BIT 0x0100 +#define TBICTX_XAX4_BIT 0x0200 +#define TBICTX_XEXT_BIT 0x1000 + +static unsigned int +metag_calculate_ech_ctx (void) +{ + unsigned int ech_ctx = 0; + + /* Now emit ECH support */ + if (TARGET_ECH) + { + int regno; + + for (regno = FIRST_ECH_DATA_REG ; regno <= LAST_DATA_REG ; regno++) + if (df_regs_ever_live_p (regno)) + { + ech_ctx |= (TBICTX_XDX8_BIT << 16); + break; + } + + for (regno = FIRST_ECH_ADDR_REG ; regno <= LAST_ADDR_REG ; regno++) + if (df_regs_ever_live_p (regno)) + { + ech_ctx |= (TBICTX_XAX4_BIT << 16); + break; + } + } + + return ech_ctx; +} + +static unsigned int +metag_adjust_savesize_ech (unsigned int* savesize_gp, unsigned int* extras_gp, + unsigned int* FP_SP_offset) +{ + unsigned int ech_ctx = metag_calculate_ech_ctx (); + + if (ech_ctx != 0) + { + *extras_gp |= REGNO_BIT (METAG_ECH_REGNUM); + *savesize_gp += UNITS_PER_WORD * 2; + + if (FP_SP_offset != NULL && METAG_ECH_REGNUM >= MIN_METAG_CSAVE_REGNUM) + *FP_SP_offset += UNITS_PER_WORD * 2; + } + + return ech_ctx; +} + +/* function prologue */ + +void +metag_function_prologue (FILE *file ATTRIBUTE_UNUSED, HOST_WIDE_INT size) +{ + unsigned int savesize_gp = 0; + unsigned int savesize_eh = 0; + unsigned int FP_SP_offset = 0; + unsigned int pretend_size = ALIGN_ON_STACK_BOUNDARY (current_function_pretend_args_size); + unsigned int pretend_regs = pretend_size / UNITS_PER_WORD; + bool non_leaf = metag_non_leaf_function_p (); + unsigned int extras_gp = 0; + unsigned int extras_eh = 0; + unsigned int ech_ctx = 0; + bool loads_pic_register; + + if (metag_ccfsm_state || metag_target_insn) + gcc_unreachable (); /* Sanity check */ + + /* Track basis for the varargs we save */ + if (cfun->machine->anonymous_args) + fprintf (file, ASM_COMMENT_START " Store varargs in registers %d (%d)\n", + current_function_pretend_args_size, pretend_size); + else if (current_function_pretend_args_size) + fprintf (file, ASM_COMMENT_START " Store partial args in registers %d (%d)\n", + current_function_pretend_args_size, pretend_size); + + /* Add in outgoing sizes */ + if (size != 0) + fprintf (file, ASM_COMMENT_START " Allocate local size %ld\n", (long)size); + + if (non_leaf) + fprintf (file, ASM_COMMENT_START " Allocate outgoing %d\n", + current_function_outgoing_args_size); + + size += current_function_outgoing_args_size; + + /* Round size of local stack to preserve 64-bit alignments */ + size = ALIGN_ON_STACK_BOUNDARY (size); + + /* Make pretend regs into the first non-varargs register number */ + pretend_regs += MIN_METAG_PARM_REGNUM; + + { + unsigned int regno; + + for (regno = MIN_METAG_PARM_REGNUM; regno <= MAX_METAG_CSAVE_REGNUM; regno += 2) + { + if (regno < pretend_regs + || (!call_used_regs[regno] + && (df_regs_ever_live_p (regno + 0) || df_regs_ever_live_p (regno + 1)))) + { + extras_gp |= REGNO_BIT (regno); + + /* Push this data register */ + savesize_gp += UNITS_PER_WORD * 2; + + if (regno >= MIN_METAG_CSAVE_REGNUM) + FP_SP_offset += UNITS_PER_WORD * 2; + } + } + } + + /* Exception handler bits */ + if (current_function_calls_eh_return) + { + unsigned int n; + + for (n = 0; n < NUM_EH_RETURN_DATA_REGS; n++) + { + unsigned int regno = EH_RETURN_DATA_REGNO (n); + + if (regno != INVALID_REGNUM) + { + unsigned int regbit = REGNO_BIT (regno); + + if ((extras_eh & regbit) == 0) + { + extras_eh |= regbit; + savesize_eh += UNITS_PER_WORD * 2; + FP_SP_offset += UNITS_PER_WORD * 2; + } + } + } + } + + /* Adjust the saved registers for ECH support */ + ech_ctx = metag_adjust_savesize_ech (&savesize_gp, &extras_gp, &FP_SP_offset); + + /* Recover original pretend regs */ + pretend_regs -= MIN_METAG_PARM_REGNUM; + + /* Can only save frame pointer from D0 temporary */ + if (cfun->machine->frame_pointer_epilogue) + fputs (ASM_COMMENT_START " frame_pointer_needed to optimize epilogue\n", file); + else if (frame_pointer_needed) + fputs (ASM_COMMENT_START " GCC says frame_pointer_needed\n", file); + + if (frame_pointer_needed || non_leaf) + { + if (non_leaf) + { + extras_gp |= REGNO_BIT (RETURN_POINTER_REGNUM); + fputs (ASM_COMMENT_START " Save return address for non_leaf\n", file); + } + else + fputs (ASM_COMMENT_START " Save return address with callers frame\n", file); + + if (frame_pointer_needed) + extras_gp |= REGNO_BIT (TEMP_D0FRT_REGNUM); + + savesize_gp += UNITS_PER_WORD * 2; + FP_SP_offset += UNITS_PER_WORD * 2; + } + else if (df_regs_ever_live_p (RETURN_POINTER_REGNUM)) + { + extras_gp |= REGNO_BIT (RETURN_POINTER_REGNUM); + + /* Push this data register */ + savesize_gp += UNITS_PER_WORD * 2; + if (RETURN_POINTER_REGNUM >= MIN_METAG_CSAVE_REGNUM) + FP_SP_offset += UNITS_PER_WORD * 2; + } + + loads_pic_register = METAG_CURRENT_FUNCTION_LOADS_PIC_REGISTER (); + if (loads_pic_register) + FP_SP_offset += UNITS_PER_WORD * 2; /* Save PIC register. */ + + /* Sanity checks between initial_elimination and prologue. + If any of these tests fail then the generated code will be wrong so abort. */ + + gcc_assert (cfun->machine->valid); + gcc_assert (cfun->machine->savesize_gp == savesize_gp); + gcc_assert (cfun->machine->savesize_eh == savesize_eh); + gcc_assert (cfun->machine->FP_SP_offset == FP_SP_offset); + gcc_assert (cfun->machine->frame_pointer_needed == frame_pointer_needed); + gcc_assert (cfun->machine->non_leaf == non_leaf); + gcc_assert (cfun->machine->out_local_size == (unsigned HOST_WIDE_INT)size); + gcc_assert (cfun->machine->calls_eh_return == current_function_calls_eh_return); + gcc_assert (cfun->machine->extras_gp == extras_gp); + gcc_assert (cfun->machine->extras_eh == extras_eh); + gcc_assert (cfun->machine->uses_pic_offset_table == current_function_uses_pic_offset_table); + gcc_assert (cfun->machine->loads_pic_register == loads_pic_register); + gcc_assert (cfun->machine->ech_ctx_required == (ech_ctx != 0)); +} + +void +metag_function_end_prologue (FILE *file) +{ + fputs (ASM_COMMENT_START " End prologue\n", file); + return; +} + +void +metag_function_begin_epilogue (FILE *file) +{ + fputs (ASM_COMMENT_START " Begin epilogue\n", file); + return; +} + +/* function epilogue */ + +void +metag_function_epilogue (FILE *file ATTRIBUTE_UNUSED, HOST_WIDE_INT size ATTRIBUTE_UNUSED) +{ + return; +} + +/* Is the return sequence just recover return address and return - two insts */ +bool +metag_cheap_return (bool cond) +{ + unsigned int regno = 0; + unsigned int savesize_gp = 0; + unsigned int extras_gp = 0; + unsigned int ech_ctx = 0; + bool non_leaf = metag_non_leaf_function_p (); + + if (!METAG_USE_RETURN_INSN (cond)) + return false; + + if (non_leaf) + savesize_gp += UNITS_PER_WORD * 2; /* Must recover return address so return is not that cheap! */ + + + /* Adjust the saved registers for ECH support */ + ech_ctx = metag_adjust_savesize_ech (&savesize_gp, &extras_gp, NULL); + + for (regno = MIN_METAG_PARM_REGNUM; regno <= MAX_METAG_CSAVE_REGNUM; regno += 2) + { + if (!call_used_regs[regno] + && (df_regs_ever_live_p(regno + 0) || df_regs_ever_live_p(regno + 1))) + { + /* Cannot do any pops in a conditional return/call */ + if (cond) + return false; + + /* Cannot do simple return - too many pops! */ + if (savesize_gp != 0) + return false; + + /* Have to do at least one pop */ + savesize_gp = UNITS_PER_WORD * 2; + } + } + + if (!(frame_pointer_needed || non_leaf) && df_regs_ever_live_p (RETURN_POINTER_REGNUM)) + { + /* Have to do at least one pop */ + savesize_gp += UNITS_PER_WORD * 2; + } + + if (current_function_calls_eh_return) + return false; + + /* Cannot make the pop conditional! */ + if (cond && savesize_gp != 0) + return false; + + /* Detect those hardware trace scenarios that lead to three extra instructions */ + if (cond && cfun->machine->hwtrace) + return false; + + /* We can announce our intentions to optimise returns */ + return true; +} + +/* All the code we need to perform a function sibcall */ +const char * +output_sibcall (rtx operands[], unsigned int op_offset) +{ + char buf[1024]; + rtx CallAddr; + + if (MEM_P (operands[op_offset])) + CallAddr = XEXP (operands[op_offset], 0); + else + CallAddr = operands[op_offset]; + + if (!TARGET_METAC_1_1 && SYMBOL_REF_P (CallAddr)) + { + if (METAG_FLAG_PIC) + gcc_unreachable (); + else /* !METAG_FLAG_PIC */ + { + /* Calculate return pointer using fast address bank add */ + sprintf (buf, "MOVT\t%s, #HI(%%c%d)", + reg_names[A0_2_REG], op_offset); + output_asm_insn (buf, operands); + + /* The actual call is a branch */ + sprintf (buf, "JUMP\t%s, #LO(%%c%d)", + reg_names[A0_2_REG], op_offset); + output_asm_insn (buf, operands); + } + } + else if (SYMBOL_REF_P (CallAddr)) + { + if (METAG_FLAG_PIC) + { + if (SYMBOL_REF_LOCAL_P (CallAddr)) + { + /* Local funcs go via relative call */ + if (TARGET_MODEL_SMALL) + { + sprintf (buf, "B\t%%c%d", op_offset); + output_asm_insn (buf, operands); + } + else + { + sprintf (buf, "B\t%%c%d", op_offset); + output_asm_insn (buf, operands); + } + } + else + { + /* The actual call is to an external function so goes via the PLT */ + sprintf (buf, "B\t%%c%d@PLT", op_offset); + output_asm_insn (buf, operands); + } + } + else /* !METAG_FLAG_PIC */ + { + sprintf (buf, "B\t%%c%d", op_offset); + output_asm_insn (buf, operands); + } + } + else if (REG_P (CallAddr) + && REGNO (CallAddr) != RETURN_POINTER_REGNUM) + { + sprintf (buf, "MOV%%?\tPC, %s", reg_names[REGNO (CallAddr)]); + output_asm_insn (buf, operands); + } + else + gcc_unreachable (); + + return ""; +} + +/* All the code we need to perform a function call */ +const char * +output_call (rtx operands[], unsigned int op_offset) +{ + char buf[1024]; + const char * prefix = "(*call instance "; + const char * const no_prefix = ""; + rtx CallAddr; + + if (MEM_P (operands[op_offset])) + CallAddr = XEXP (operands[op_offset], 0); + else + CallAddr = operands[op_offset]; + + if (!TARGET_METAC_1_1 && SYMBOL_REF_P (CallAddr)) + { + if (METAG_FLAG_PIC) + gcc_unreachable (); + else /* !METAG_FLAG_PIC */ + { + /* Calculate return pointer using fast address bank add */ + sprintf (buf, "MOVT\t%s, #HI(%%c%d)\t%s %s", + reg_names[RETURN_POINTER_REGNUM], op_offset, ASM_COMMENT_START, prefix); + output_asm_insn (buf, operands); + prefix = no_prefix; + + /* The actual call is a branch */ + sprintf (buf, "CALL\t%s, #LO(%%c%d)\t%s ... OK)", + reg_names[RETURN_POINTER_REGNUM], op_offset, ASM_COMMENT_START); + output_asm_insn (buf, operands); + + /* Some calls need additional padding instructions */ + metag_pad_function_call (CallAddr); + } + } + else if (SYMBOL_REF_P (CallAddr)) + { + if (METAG_FLAG_PIC) + { + if (SYMBOL_REF_LOCAL_P (CallAddr)) + { + /* Local funcs go via relative CALL */ + if (TARGET_MODEL_SMALL) + { + sprintf (buf, "CALLR\t%s, %%c%d\t%s %s)", + reg_names[RETURN_POINTER_REGNUM], op_offset, ASM_COMMENT_START, prefix); + output_asm_insn (buf, operands); + prefix = no_prefix; + } + else + { + sprintf (buf, "CALLR\t%s, %%c%d\t%s %s)", + reg_names[RETURN_POINTER_REGNUM], op_offset, ASM_COMMENT_START, prefix); + output_asm_insn (buf, operands); + prefix = no_prefix; + } + } + else + { + /* The actual call is to an external function so goes via the PLT */ + sprintf (buf, "CALLR\t%s, %%c%d@PLT\t%s %s)", + reg_names[RETURN_POINTER_REGNUM], op_offset, ASM_COMMENT_START, prefix); + output_asm_insn (buf, operands); + prefix = no_prefix; + } + } + else /* !METAG_FLAG_PIC */ + { + /* The actual call is a branch */ + sprintf (buf, "CALLR\t%s, %%c%d\t%s %s)", + reg_names[RETURN_POINTER_REGNUM], op_offset, ASM_COMMENT_START, prefix); + output_asm_insn (buf, operands); + prefix = no_prefix; + } + + /* Some calls need additional padding instructions */ + metag_pad_function_call (CallAddr); + } + else if (REG_P (CallAddr) + && REGNO (CallAddr) != RETURN_POINTER_REGNUM) + { + /* Must move the address to call into D1RtP */ + sprintf (buf, "MOV%%?\t%s, %s\t%s %s ...", + reg_names[RETURN_POINTER_REGNUM], + reg_names[REGNO (CallAddr)], ASM_COMMENT_START, prefix); + output_asm_insn (buf, operands); + + /* The actual call is a SWAP */ + sprintf (buf, "SWAP%%?\tPC, %s\t%s ... OK)", + reg_names[RETURN_POINTER_REGNUM], ASM_COMMENT_START); + output_asm_insn (buf, operands); + } + else + metag_abort (CallAddr); + + return ""; +} + +unsigned int +metag_mem_base (rtx op) +{ + rtx ref; + + /* We only match with MEM operands */ + if (!MEM_P (op)) + return INVALID_REGNUM; + + /* Get root of address expression */ + ref = XEXP (op, 0); + + if (SYMBOL_REF_P (ref)) + { + /* Must be a direct access to an atomic symbol */ + return GLOBAL_POINTER_REGNUM; + } + + if (GET_CODE (ref) == PLUS + || GET_CODE (ref) == PRE_INC + || GET_CODE (ref) == PRE_DEC + || GET_CODE (ref) == POST_INC + || GET_CODE (ref) == POST_DEC + || GET_CODE (ref) == PRE_MODIFY + || GET_CODE (ref) == POST_MODIFY) + { + /* De-reference first parameter of address expression */ + ref = XEXP (ref, 0); + } + + if (SUBREG_P (ref) + && REG_P (SUBREG_REG (ref))) + { + unsigned int regno = REGNO (SUBREG_REG (ref)); + + if (IS_HARD_OR_VIRT_REGNO (regno)) + return regno + SUBREG_BYTE (ref); + + return regno; + } + + if (REG_P (ref)) + return REGNO (ref); + + return INVALID_REGNUM; +} + +bool +metag_mem_base_p (rtx op, enum reg_class class) +{ + unsigned int reg_num = metag_mem_base (op); + + /* We only match with MEM operands */ + if (reg_num == INVALID_REGNUM) + return false; + + if (reg_renumber != NULL && IS_PSEUDO_REGNO (reg_num)) + reg_num = reg_renumber[reg_num]; + + if (reg_num == INVALID_REGNUM) + return false; + + return METAG_REGNO_REG_CLASS (reg_num) == class; +} + +int +debug_metag_md (void) +{ + static int counter = 0; + + return counter++; +} + +bool +metag_slow_store (rtx mem, rtx reg) +{ + unsigned int regno; + + if (!MEM_P (mem)) + return false; + + if (REG_P (reg)) + regno = REGNO (reg); + else if (SUBREG_P (reg) + && REG_P (SUBREG_REG (reg))) + { + regno = REGNO (SUBREG_REG (reg)); + if (IS_HARD_OR_VIRT_REGNO (regno)) + regno += SUBREG_BYTE (reg); + } + else + return false; + + if (reg_renumber != NULL && IS_PSEUDO_REGNO (regno)) + regno = reg_renumber[regno]; + + if (IS_PSEUDO_REGNO (regno)) + return false; + + if (GET_MODE_SIZE (GET_MODE (mem)) <= UNITS_PER_WORD) + return metag_mem_base_p (mem, METAG_REGNO_REG_CLASS (regno)); + else + return (metag_mem_base_p (mem, METAG_REGNO_REG_CLASS (regno)) + || metag_mem_base_p (mem, METAG_REGNO_REG_CLASS (regno + 1))); +} + +rtx +metag_gen_safe_temp (enum machine_mode mode, rtx reg) +{ + unsigned int regno; + + gcc_assert ( A0_SCRATCH != INVALID_REGNUM && fixed_regs[A0_SCRATCH] + && A1_SCRATCH != INVALID_REGNUM && fixed_regs[A1_SCRATCH]); + + if (REG_P (reg)) + regno = REGNO (reg); + else if (SUBREG_P (reg) + && REG_P (SUBREG_REG (reg))) + { + regno = REGNO (SUBREG_REG (reg)); + if (IS_HARD_OR_VIRT_REGNO (regno)) + regno += SUBREG_BYTE (reg); + } + else + regno = INVALID_REGNUM; + + if (reg_renumber != NULL && IS_PSEUDO_REGNO (regno)) + regno = reg_renumber[regno]; + + gcc_assert (regno != INVALID_REGNUM); + + if (METAG_REGNO_REG_CLASS (regno) == A1_REGS + && GET_MODE_SIZE (mode) <= UNITS_PER_WORD) + { + gcc_assert (regno != A0_SCRATCH); + + /* Not safe to use register in same unit */ + return gen_rtx_REG (mode, A0_SCRATCH); + } + + /* Provide suitable temp register */ + if (GET_MODE_SIZE (GET_MODE (reg)) > UNITS_PER_WORD) + { + gcc_assert (regno != A0_SCRATCH); + gcc_assert (regno != A1_SCRATCH); + + return gen_rtx_REG (mode, A0_SCRATCH); + } + + gcc_assert (regno != A1_SCRATCH); + + return gen_rtx_REG (mode, A1_SCRATCH); +} + +enum machine_mode +metag_select_cc_mode (enum rtx_code code, rtx x, rtx y) +{ +#undef LETS_US_SEE +#ifdef LETS_US_SEE + fprintf (stderr, "metag_select_cc_mode %s\n", GET_RTX_NAME (code)); + debug_rtx (x); + debug_rtx (y); +#endif + + /* An operation that sets the condition codes as a side-effect, the + V flag is not set correctly, so we can only use comparisons where + this doesn't matter. (For LT and GE we can use MI and PL instead. */ + if (GET_MODE (x) == SImode + && y == const0_rtx + && (code == EQ || code == NE || code == LT || code == GE) + && (GET_CODE (x) == PLUS + || GET_CODE (x) == MINUS + || GET_CODE (x) == AND + || GET_CODE (x) == IOR + || GET_CODE (x) == XOR + || GET_CODE (x) == NOT + || GET_CODE (x) == NEG + || GET_CODE (x) == LSHIFTRT + || GET_CODE (x) == ASHIFT + || GET_CODE (x) == ASHIFTRT + || GET_CODE (x) == SIGN_EXTEND + || GET_CODE (x) == ZERO_EXTEND + || GET_CODE (x) == ZERO_EXTRACT)) + { +#ifdef LETS_US_SEE + fputs (" return NOOV\n", stderr); +#endif + return CC_NOOVmode; + } + + /* A special case, Combine likes to generate + (compare (reg X) (neg (reg Y)) + instead of + (compare (plus (reg X) (reg y)) + (const_int 0)) + */ + if (GET_MODE (x) == SImode + && (code == EQ || code == NE || code == LT || code == GE) + && GET_CODE (y) == NEG) + { +#ifdef LETS_US_SEE + fputs (" return NOOV\n", stderr); +#endif + return CC_NOOVmode; + } + + /* If we're comparingi EQ/NE against 0 then use Zmode */ + if (GET_MODE (x) == SImode + && y == const0_rtx + && (code == EQ || code == NE)) + { +#ifdef LETS_US_SEE + fputs (" return Z\n", stderr); +#endif + return CC_Zmode; + } + + if ((GET_MODE (x) == HImode || GET_MODE (x) == QImode) + && (code == EQ || code == NE)) + { + /* Enough to trigger the patterns if HI/QI equality involved */ +#ifdef LETS_US_SEE + fputs (" return Z\n", stderr); +#endif + return CC_Zmode; + } + + if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) + { + if (metag_is_cc_quiet (get_metag_cc_float (code))) + { +#ifdef LETS_US_SEE + fputs (" return FP_Q\n", stderr); +#endif + return CC_FP_Qmode; + } + else + { +#ifdef LETS_US_SEE + fputs (" return FP\n", stderr); +#endif + return CC_FPmode; + } + } + +#ifdef LETS_US_SEE + fputs (" return CC\n", stderr); +#endif + return CCmode; +} + +bool +gen_metag_compare (enum rtx_code code, rtx operands[], int index) +{ + if (!(code == LTGT || code == UNEQ)) + { + enum machine_mode mode = SELECT_CC_MODE (code, metag_compare_op0, + metag_compare_op1); + + rtx cc_reg = gen_rtx_REG (mode, MCC_REGNUM); + + emit_insn (gen_rtx_SET (VOIDmode, + cc_reg, + gen_rtx_COMPARE (mode, metag_compare_op0, metag_compare_op1))); + + operands[index] = cc_reg; + + return true; + } + + return false; +} + +static metag_cc +get_metag_cc_float (enum rtx_code comp_code) +{ + switch (comp_code) + { + case NE: return MCC_UNE; + case EQ: return MCC_FEQ; + case GE: return MCC_FGE; + case GT: return MCC_FGT; + case LE: return MCC_FLE; + case LT: return MCC_FLT; +/* LTGT cannot be handled by META */ +/* UNEQ cannot be handled by META */ + case UNGE: return MCC_UGE; + case UNGT: return MCC_UGT; + case UNLE: return MCC_ULE; + case UNLT: return MCC_ULT; + case UNORDERED: return MCC_U; + case ORDERED: return MCC_FLEG; + default: + break; + } + gcc_unreachable (); +} + +static metag_cc +get_metag_cc (rtx comparison) +{ + enum machine_mode mode = GET_MODE (XEXP (comparison, 0)); + enum rtx_code comp_code = GET_CODE (comparison); + + if (GET_MODE_CLASS (mode) != MODE_CC) + mode = SELECT_CC_MODE (comp_code, XEXP (comparison, 0), + XEXP (comparison, 1)); + + switch (mode) + { + case CC_NOOVmode: + switch (comp_code) + { + case NE: return MCC_NE; + case EQ: return MCC_EQ; + case GE: return MCC_PL; + case LT: return MCC_MI; + case LTU: return MCC_CS; + case GEU: return MCC_CC; + default: + break; + } + break; + + case CC_Zmode: + switch (comp_code) + { + case NE: return MCC_NE; + case EQ: return MCC_EQ; + default: + break; + } + break; + + case CC_FPmode: + case CC_FP_Qmode: + return get_metag_cc_float (comp_code); + + case CCmode: + switch (comp_code) + { + case NE: return MCC_NE; + case EQ: return MCC_EQ; + case GE: return MCC_GE; + case GT: return MCC_GT; + case LE: return MCC_LE; + case LT: return MCC_LT; + case GEU: return MCC_HS; + case GTU: return MCC_HI; + case LEU: return MCC_LS; + case LTU: return MCC_LO; + default: + break; + } + break; + + default: + break; + } + + metag_abort (comparison); +} + +static bool +metag_is_cc_quiet (metag_cc metag_comp_code) +{ + switch (metag_comp_code) + { + case MCC_FEQ: + case MCC_UNE: + case MCC_U: + case MCC_UGT: + case MCC_UGE: + case MCC_ULT: + case MCC_ULE: + case MCC_NU: + case MCC_NUGT: + case MCC_NUGE: + case MCC_NULT: + case MCC_NULE: + return true; + case MCC_FGT: + case MCC_FGE: + case MCC_FLT: + case MCC_FLE: + case MCC_FLEG: + case MCC_NFGT: + case MCC_NFGE: + case MCC_NFLT: + case MCC_NFLE: + case MCC_NFLEG: + return false; +/* LTGT cannot be handled by META */ +/* UNEQ cannot be handled by META */ + default: + gcc_unreachable (); + } +} + +/* Recognise VAR_DECL DECL's which are atomics of size <= 8 + + For the metag we only want to mark variables that are atomic and less + than 64-bits for optimisation as condidates for direct LOAD/STORE using + A1LbP or A1GbP as a base. + + All other symbols will be accessed indirectly using OGA(), this is true of + functions, string constants, or constructors. +*/ + +#define SET_SYMBOL_FLAG_SMALL(SYMBOL) \ + (SYMBOL_REF_FLAGS (SYMBOL) = (SYMBOL_REF_FLAGS (SYMBOL) & ~METAG_SYMBOL_FLAG_GLOBAL \ + & ~METAG_SYMBOL_FLAG_LARGE) \ + | METAG_SYMBOL_FLAG_SMALL) + +#define SET_SYMBOL_FLAG_LARGE(SYMBOL) \ + (SYMBOL_REF_FLAGS (SYMBOL) = (SYMBOL_REF_FLAGS (SYMBOL) & ~METAG_SYMBOL_FLAG_GLOBAL \ + & ~METAG_SYMBOL_FLAG_SMALL) \ + | METAG_SYMBOL_FLAG_LARGE) + +#define SET_SYMBOL_FLAG_GLOBAL(SYMBOL) \ + (SYMBOL_REF_FLAGS (SYMBOL) = (SYMBOL_REF_FLAGS (SYMBOL) & ~METAG_SYMBOL_FLAG_SMALL \ + & ~METAG_SYMBOL_FLAG_LARGE) \ + | METAG_SYMBOL_FLAG_GLOBAL) + +#define SET_SYMBOL_FLAG_BYTE(SYMBOL) \ + (SYMBOL_REF_FLAGS (SYMBOL) = (SYMBOL_REF_FLAGS (SYMBOL) & ~METAG_SYMBOL_FLAG_WORD \ + & ~METAG_SYMBOL_FLAG_DWORD \ + & ~METAG_SYMBOL_FLAG_LONG) \ + | METAG_SYMBOL_FLAG_BYTE) + +#define SET_SYMBOL_FLAG_WORD(SYMBOL) \ + (SYMBOL_REF_FLAGS (SYMBOL) = (SYMBOL_REF_FLAGS (SYMBOL) & ~METAG_SYMBOL_FLAG_BYTE \ + & ~METAG_SYMBOL_FLAG_DWORD \ + & ~METAG_SYMBOL_FLAG_LONG) \ + | METAG_SYMBOL_FLAG_WORD) + +#define SET_SYMBOL_FLAG_DWORD(SYMBOL) \ + (SYMBOL_REF_FLAGS (SYMBOL) = (SYMBOL_REF_FLAGS (SYMBOL) & ~METAG_SYMBOL_FLAG_BYTE \ + & ~METAG_SYMBOL_FLAG_WORD \ + & ~METAG_SYMBOL_FLAG_LONG) \ + | METAG_SYMBOL_FLAG_DWORD) + +#define SET_SYMBOL_FLAG_LONG(SYMBOL) \ + (SYMBOL_REF_FLAGS (SYMBOL) = (SYMBOL_REF_FLAGS (SYMBOL) & ~METAG_SYMBOL_FLAG_BYTE \ + & ~METAG_SYMBOL_FLAG_WORD \ + & ~METAG_SYMBOL_FLAG_DWORD) \ + | METAG_SYMBOL_FLAG_LONG) + +#define SET_SYMBOL_FLAG_UNKN(SYMBOL) \ + (SYMBOL_REF_FLAGS (SYMBOL) = (SYMBOL_REF_FLAGS (SYMBOL) & ~METAG_SYMBOL_FLAG_BYTE \ + & ~METAG_SYMBOL_FLAG_WORD \ + & ~METAG_SYMBOL_FLAG_DWORD \ + & ~METAG_SYMBOL_FLAG_LONG) + +/* This macro definition, if any, is executed immediately after the rtl for + decl has been created and stored in DECL_RTL (decl). The value of the rtl + will be a mem whose address is a symbol_ref. + + The usual thing for this macro to do is to record a flag in the symbol_ref + (such as SYMBOL_REF_FLAG) or to store a modified name string in the + symbol_ref (if one bit is not enough information). + + For META we do both, the METAG_SYMBOL_FLAG_DIRECT is set if- + + The decl defines the address of an atomic variable <= 8 bytes in size + AND either we are targeting SMALL compilation mode + AND the decl DOES NOT HAVE __attribute__ ((model(large))) + or we are targeting LARGE compilation mode + AND the decl HAS __attribute__ ((model(small))) + + The METAG_SYMBOL_FLAG_DIRECT hence indicates if direct access to the data + symbols value is to be supported by the instruction patterns provided the + size of the load/store matches the size of atomic value concerned. The access + causes the symbol is to be generally accessed using either A1GbP+OG(..) or + A1GbP+OGA(...) if the address or value is to be accessed. + + METAG_SYMBOL_FLAG_SMALL + If SYMBOL_REF_FLAG_DIRECT set to directly access data using- + + GETx Reg, [A1GbP+#OG(Symbol)] ; x set to name[2] + SETx [A1GbP+#OG(Symbol)], Reg ; x set to name[2] + + else and if address of location required- + + GETD Reg, [A1GbP+#OGA(Symbol)] + + METAG_SYMBOL_FLAG_LARGE + Only support access to a data symbol's address via- + + MOV Reg, A1GbP ; name[2] will be 'X' + ADDT Reg, Reg, #HI(OG(Symbol)) ; 32-bit offset + ADD Reg, Reg, #LO(OG(Symbol)) + + METAG_SYMBOL_FLAG_GLOBAL + Only support access as a absolute global address- + + MOVT Reg, #HI(Symbol) ; 32-bit absolute address + ADD Reg, Reg, #LO(Symbol) + + The following flags: + METAG_SYMBOL_FLAG_BYTE + METAG_SYMBOL_FLAG_WORD + METAG_SYMBOL_FLAG_DWORD + METAG_SYMBOL_FLAG_LONG + are used to indicate either the size of a directly accessible data symbol or + that only the address of the item can be accessed directly because it is + too large, a small array, a small structure, a small union, or not in the + optimised data section at all. +*/ + +void +metag_encode_section_info (tree decl, rtx rtl, int first) +{ + char SorLorG = '\0'; + rtx symbol = NULL_RTX; + bool direct = false; + char size = 'X'; + default_encode_section_info (decl, rtl, first); + + /* Grab the symbol from the rtl passed in */ + symbol = XEXP (rtl, 0); + + if (METAG_FLAG_PIC) + { + /* PIC code only needs to deal with functions and variables */ + if (TREE_CODE (decl) != FUNCTION_DECL + && TREE_CODE (decl) != VAR_DECL) + return; + + gcc_assert (SYMBOL_REF_P (symbol)); + + direct = SYMBOL_REF_LOCAL_P (symbol); + } + else if (metag_bfd_tls_referenced_p (rtl)) + { + if (TREE_CODE (decl) != VAR_DECL) + return; + } + else + { + /* Note: Binutils toolchain DOESN'T support #OG or #OGA addressing + via A1GbP so we ignore the memory model and always use direct + 32-bit absolute access. */ + + /* Direct 32-bit absolute access */ + SorLorG = 'G'; + size = 'X'; + direct = false; + + if (SorLorG == 'S') + SET_SYMBOL_FLAG_SMALL (symbol); + else if (SorLorG == 'L') + SET_SYMBOL_FLAG_LARGE (symbol); + else if (SorLorG == 'G') + SET_SYMBOL_FLAG_GLOBAL (symbol); + else + gcc_unreachable (); + + if (size == 'B') + SET_SYMBOL_FLAG_BYTE (symbol); + else if (size == 'W') + SET_SYMBOL_FLAG_WORD (symbol); + else if (size == 'D') + SET_SYMBOL_FLAG_DWORD (symbol); + else if (size == 'L') + SET_SYMBOL_FLAG_LONG (symbol); + else if (size == 'X') + SET_SYMBOL_FLAG_LONG (symbol); + else + gcc_unreachable (); + } + + if (direct) + SYMBOL_REF_FLAGS (symbol) |= METAG_SYMBOL_FLAG_DIRECT; + else + SYMBOL_REF_FLAGS (symbol) &= ~METAG_SYMBOL_FLAG_DIRECT; +} + +/* With DSP features enabled, the compiler will use the V2SImode + vectors and with FPU features enabled, the compiler will use + V2SFmode */ + +bool +metag_vector_mode_supported_p (enum machine_mode mode) +{ + return (TARGET_DSP && (mode == V2SImode)) + || (TARGET_FPU_SIMD && (mode == V2SFmode)); +} + +/* Called by OVERRIDE_OPTIONS to initialize various things. */ + +void +metag_override_options (void) +{ + static const struct cpu_table { + const char *const name; + const enum processor_type processor; + const enum attr_metacore tune; + const enum metac_target cpu; + } cpu_table[] = { + { "0.1", PROCESSOR_METAC_0_1, METACORE_METAC_0_1, METAC_0_1_ID }, + { "1.0", PROCESSOR_METAC_1_0, METACORE_METAC_1_0, METAC_1_0_ID }, + { "1.1", PROCESSOR_METAC_1_1, METACORE_METAC_1_1, METAC_1_1_ID }, + { "1.2", PROCESSOR_METAC_1_2, METACORE_METAC_1_2, METAC_1_2_ID }, + { "2.1", PROCESSOR_METAC_2_1, METACORE_METAC_2_1, METAC_2_1_ID }, + { NULL, 0, 0, 0 } + }; + + if (strcmp (metag_model_string, "small") == 0) + { + warning (0, "Small memory model not supported, using large model"); + metag_model = METAG_MODEL_LARGE; + } + else if (strcmp (metag_model_string, "large") == 0) + metag_model = METAG_MODEL_LARGE; + else + error ("bad value %qs for -mmodel switch", metag_model_string); + + /* If it's not defined or still has the initial value then use METAC_DEFAULT + to set the target string. The conversion of string into ID can then take + place as normal. */ + if (strcmp (metag_cpu_string, "") == 0) + { + if (TARGET_MTX) + metag_cpu_string = "1.2"; + else + metag_cpu_string = METAC_DEFAULT; + } + + if (metag_cpu_string) + { + unsigned int i; + bool newer_than_default = false; + + for (i = 0; cpu_table[i].name != NULL; i++) + { + if (strcmp (metag_cpu_string, cpu_table[i].name) == 0) + { + /* This test is present in order to prevent a toolchain built for an old core + allowing a newer core to be targetted. The rest of the toolchain may + therefore not support the newer core! */ + if (newer_than_default) + { + error ("Bad value %qs for -mmetac switch. Must not be more recent than %qs.", metag_cpu_string, METAC_DEFAULT); + break; + } + metac_target = cpu_table[i].cpu; + metacore = cpu_table[i].tune; + break; + } + + if (strcmp (METAC_DEFAULT, cpu_table[i].name) == 0) + newer_than_default = true; + } + + if (cpu_table[i].name == NULL) + error ("Bad value %qs for -mmetac switch", metag_cpu_string); + } + + if (metag_tune_string) + { + unsigned int i; + + for (i = 0; cpu_table[i].name != NULL; i++) + if (strcmp (metag_tune_string, cpu_table[i].name) == 0) + { + metacore = cpu_table[i].tune; + break; + } + + if (cpu_table[i].name == NULL) + error ("bad value %qs for -mtune switch", metag_tune_string); + } + + if (TARGET_MTX) + { + if (metac_target != METAC_1_2_ID) + error ("MTX is based on a Meta 1.2 core, use -mmetac=1.2"); + } + + if (TARGET_MINIM_CORE) + metag_max_insns_skipped = 2; + + if (TARGET_FPU_SIMD && (!TARGET_FPU + || metag_fpu_single)) + error ("-msimd-float only valid with -mhard-float=D"); + + if (!TARGET_METAC_2_1 && TARGET_FPU) + error ("FPU not available on specified processor: %s", metag_cpu_string); + + if (!TARGET_METAC_2_1 && metag_meta2_bex_enabled) + error ("The 'bex' extension is not available for the specified meta core"); + + metag_override_options_per_os(); + flag_no_function_cse = 1; +} + +bool +metag_return_in_memory (tree type) +{ + HOST_WIDE_INT size = int_size_in_bytes (type); + + return (size < 0 || size > UNITS_PER_WORD * 2); +} + +void +metag_abort (rtx val) +{ + debug_rtx (val); + gcc_unreachable (); +} + +static void +metag_emit_load_post_inc (rtx dstbase, enum machine_mode mode, rtx dst, + HOST_WIDE_INT dstoffset, unsigned int reg) +{ +#if 0 + rtx addrm mem, insn; + + addr = gen_rtx_POST_INC (Pmode, dst); + mem = adjust_automodify_address_nv (dstbase, mode, addr, dstoffset); + insn = emit_insn (gen_rtx_SET (VOIDmode, + mem, + gen_rtx_REG (mode, reg))); + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (addr, 0), REG_NOTES (insn)); +#else + rtx plus, mem, insn, set1, set2; + + mem = adjust_automodify_address_nv (dstbase, mode, dst, dstoffset); + + dst = XEXP (mem, 0); + plus = gen_rtx_PLUS (SImode, dst, + gen_int_mode (GET_MODE_SIZE (mode), SImode)); + set1 = gen_rtx_SET (VOIDmode, mem, gen_rtx_REG (mode, reg)); + set2 = gen_rtx_SET (VOIDmode, dst, plus); + + insn = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2)); + XVECEXP (insn, 0, 0) = set1; + XVECEXP (insn, 0, 1) = set2; + emit_insn (insn); +#endif +} + +rtx +metag_gen_load_multiple (unsigned int base_regno, + unsigned int count, + enum machine_mode mode, + rtx from, + bool write_back, + rtx basemem, + HOST_WIDE_INT * offsetp) +{ + HOST_WIDE_INT offset = *offsetp; + unsigned int i; + unsigned int word_size = GET_MODE_SIZE (mode); + unsigned int j; + rtx result; + + if (count < 2) + gcc_unreachable (); + + result = gen_rtx_PARALLEL (VOIDmode, + rtvec_alloc (count + (write_back ? 1 : 0))); + if (write_back) + { + XVECEXP (result, 0, 0) = gen_rtx_SET (VOIDmode, + from, + plus_constant (from, count * word_size)); + i = 1; + count++; + } + else + i = 0; + + for (j = 0; i < count; i++, j++) + { + rtx addr = plus_constant (from, j * word_size); + rtx mem = adjust_automodify_address_nv (basemem, mode, addr, offset); + + XVECEXP (result, 0, i) = gen_rtx_SET (VOIDmode, + gen_rtx_REG (mode, base_regno + (j * 2)), + mem); + + offset += word_size; + } + + if (write_back) + *offsetp = offset; + + return result; +} + +rtx +metag_gen_store_multiple (unsigned int base_regno, + unsigned int count, + enum machine_mode mode, + rtx to, + bool write_back, + rtx basemem, + HOST_WIDE_INT * offsetp) +{ + HOST_WIDE_INT offset = *offsetp; + unsigned int i; + unsigned int word_size = GET_MODE_SIZE (mode); + unsigned int j; + rtx result; + + if (count < 2) + gcc_unreachable (); + + result = gen_rtx_PARALLEL (VOIDmode, + rtvec_alloc (count + (write_back ? 1 : 0))); + + if (write_back) + { + XVECEXP (result, 0, 0) = gen_rtx_SET (VOIDmode, + to, + plus_constant (to, count * word_size)); + i = 1; + count++; + } + else + i = 0; + + for (j = 0; i < count; i++, j++) + { + rtx addr = plus_constant (to, j * word_size); + rtx mem = adjust_automodify_address_nv (basemem, mode, addr, offset); + + XVECEXP (result, 0, i) = gen_rtx_SET (VOIDmode, + mem, + gen_rtx_REG (mode, base_regno + (j * 2))); + offset += word_size; + } + + if (write_back) + *offsetp = offset; + + return result; +} + +bool +metag_gen_movmemqi (rtx operands[]) +{ + HOST_WIDE_INT xfer_bytes_to_go; /* # bytes to xfer in big chunks */ + HOST_WIDE_INT last_bytes; /* # bytes left over */ + HOST_WIDE_INT srcoffset; + HOST_WIDE_INT dstoffset; + enum machine_mode word_mode; /* mode in which to do the transfer */ + unsigned int word_size; /* units in which to transfer */ + unsigned int do_in_bytes = 0; + unsigned int do_in_max; /* max # of bytes to do in on go */ + rtx src; + rtx dst; + rtx dstbase; + rtx srcbase; + + if ( !CONST_INT_P (operands[2]) + || !CONST_INT_P (operands[3]) + || INTVAL (operands[2]) > 96 + || INTVAL (operands[2]) < 8 + || INTVAL (operands[3]) & 3) + return false; + + dstbase = operands[0]; + srcbase = operands[1]; + + dst = copy_addr_to_reg (XEXP (dstbase, 0)); + src = copy_addr_to_reg (XEXP (srcbase, 0)); + if ((INTVAL (operands[3]) & 7) == 0 + && INTVAL (operands[2]) >= 16) + { + /* Data 64-bit aligned with enough for two transfers */ + xfer_bytes_to_go = INTVAL (operands[2]) & ~(UNITS_PER_WORD * 2 - 1); + word_mode = DImode; + word_size = UNITS_PER_WORD * 2; + last_bytes = INTVAL (operands[2]) & (UNITS_PER_WORD * 2 - 1); + do_in_max = 4 * word_size; + + /* Cannot use 64-bit mode if it's too short! */ + gcc_assert (xfer_bytes_to_go >= 16); + } + else + { + /* Data not 64-bit aligned, used paired bursts so still 64-bit organised */ + xfer_bytes_to_go = INTVAL (operands[2]) & ~(UNITS_PER_WORD - 1); + word_mode = SImode; + word_size = UNITS_PER_WORD; + last_bytes = INTVAL (operands[2]) & (UNITS_PER_WORD - 1); + do_in_max = 5 * word_size; + + if ((xfer_bytes_to_go + last_bytes) > 64) + return false; + } + + gcc_assert (do_in_max > 0); + + dstoffset = srcoffset = 0; + + while (xfer_bytes_to_go > 0) + { + unsigned int first_regno; + + /* Burst loop, transfer upto 32 or 20 bytes each */ + do_in_bytes = xfer_bytes_to_go; + + /* On the input side bytes at the end count as an extra word */ + if (last_bytes != 0) + do_in_bytes += word_size; + + if (do_in_bytes >= do_in_max * 2) + { + /* At least two full bursts left */ + do_in_bytes = do_in_max; + } + else if (do_in_bytes > do_in_max) + { + /* Don't leave a runt at the end */ + do_in_bytes |= (word_size * 2) - 1; + do_in_bytes >>= 1; + do_in_bytes += 1; + } +#if 0 + first_regno = D0_0_REG; +#else + first_regno = D0_2_REG; + if (D0_7_REG - 2 * ((do_in_bytes / word_size)-1) < first_regno) + first_regno = D0_7_REG - 2 * ((do_in_bytes / word_size)-1); +#endif + + /* Load the data */ + emit_insn (metag_gen_load_multiple (first_regno, do_in_bytes / word_size, + word_mode, src, true, + srcbase, &srcoffset)); + + if (xfer_bytes_to_go < (int)do_in_bytes) + { + /* Replace the rounded up size with the real extra size */ + do_in_bytes -= word_size; + xfer_bytes_to_go = 0; + } + else + { + /* Reduce bytes to go */ + xfer_bytes_to_go -= do_in_bytes; + } + + /* Store the data */ + if (do_in_bytes >= 2 * word_size) + emit_insn (metag_gen_store_multiple (first_regno, do_in_bytes / word_size, + word_mode, dst, true, + dstbase, &dstoffset)); + else if (do_in_bytes >= word_size) + { + metag_emit_load_post_inc (dstbase, word_mode, dst, + dstoffset, first_regno); + dstoffset += word_size; + } + else + gcc_unreachable (); + } + + /* Are we finished? */ + if (last_bytes > 0) + { +#if 0 + unsigned int last_regno = D0_0_REG + 2 * (do_in_bytes / word_size); +#else + unsigned int last_regno = D0_2_REG + 2 * (do_in_bytes / word_size); + if (D0_7_REG - 2 * (do_in_bytes / word_size) < D0_2_REG) + last_regno -= D0_2_REG - (D0_7_REG - 2 * (do_in_bytes / word_size)); +#endif + + /* Here we handle and remaining 4-byte chunks left to xfer */ + if ((last_bytes & 4) != 0) + { + gcc_assert (word_size == UNITS_PER_WORD * 2); + /* Store last 32-bit word and switch remainder into SImode */ + + /* Generate write for bottom SImode subreg of last DImode register, + Further manipulation needed on upper part of DImode register */ + metag_emit_load_post_inc (dstbase, SImode, dst, + dstoffset, last_regno); + + dstoffset += 4; + + /* If we have any remaing 2-byte or 1-byte chunks left adjust dst */ + if ((last_bytes & 3) != 0) + last_regno = last_regno + 1; + } + + /* Here we handle any remaining 2-byte chunks left to xfer */ + if ((last_bytes & 2) != 0) + { + metag_emit_load_post_inc (dstbase, HImode, dst, + dstoffset, last_regno); + + dstoffset += 2; + + /* If we have any remaing 1-byte chunks left adjust dst */ + if ((last_bytes & 1) != 0) + { + rtx tmp = gen_rtx_REG (SImode, last_regno); + + emit_insn (gen_lshrsi3 (tmp, tmp, GEN_INT (16))); + } + } + + /* Here we handle any remaining 1-byte chunks left to xfer */ + if ((last_bytes & 1) != 0) + { + metag_emit_load_post_inc (dstbase, QImode, dst, + dstoffset, last_regno); + + dstoffset += 1; + } + } + + return true; +} + +#if METAG_DEBUG_CCEXEC +static const char * +attr_cond_name (enum attr_cond attr) +{ + switch (attr) + { + case COND_YES: + return "yes"; + case COND_NO: + return "no"; + default: + break; + } + + return "??"; +} + +static const char * +attr_ccstate_name (enum attr_ccstate attr) +{ + switch (attr) + { + case CCSTATE_XCC: + return "xcc"; + case CCSTATE_SET: + return "set"; + case CCSTATE_FASTSET: + return "fastset"; + case CCSTATE_FASTFASTSET: + return "fastfastset"; + case CCSTATE_CCX: + return "ccx"; + case CCSTATE_NCC: + return "ncc"; + default: + break; + } + + return "???"; +} + +static const char * +attr_predicable_name (enum attr_predicable attr) +{ + switch (attr) + { + case PREDICABLE_YES: + return "yes"; + case PREDICABLE_NO: + return "no"; + default: + break; + } + + return "??"; +} +#endif + + +/* The state of the fsm controlling condition codes are: + 0: normal, do nothing special + 1: make ASM_OUTPUT_OPCODE not output this instruction + 2: make ASM_OUTPUT_OPCODE not output this instruction + 3: make instructions conditional + 4: make instructions conditional + + State transitions (state->state by whom under condition): + 0 -> 1 final_prescan_insn if the `target' is a label + 0 -> 2 final_prescan_insn if the `target' is an unconditional branch + 1 -> 3 ASM_OUTPUT_OPCODE after not having output the conditional branch + 2 -> 4 ASM_OUTPUT_OPCODE after not having output the conditional branch + 3 -> 0 ASM_OUTPUT_INTERNAL_LABEL if the `target' label is reached + (the target label has CODE_LABEL_NUMBER equal to metag_target_label). + 4 -> 0 final_prescan_insn if the `target' unconditional branch is reached + (the target insn is metag_target_insn). + + If the jump clobbers the conditions then we use states 2 and 4. + + A similar thing can be done with conditional return insns. + + XXX In case the `target' is an unconditional branch, this conditionalising + of the instructions always reduces code size, but not always execution + time. But then, I want to reduce the code size to somewhere near what + /bin/cc produces. */ + +void +metag_final_prescan_insn (rtx insn) +{ + /* BODY will hold the body of INSN. */ + rtx body = PATTERN (insn); + + /* This will be 1 if trying to repeat the trick, and things need to be + reversed if it appears to fail. */ + int reverse = 0; + + /* START_INSN will hold the insn from where we start looking. This is the + first insn after the following code_label if REVERSE is true. */ + rtx start_insn = insn; + + /* If in state 4, check if the target branch is reached, in order to + change back to state 0. */ + if (metag_ccfsm_state == 4) + { + if (insn == metag_target_insn) + { + metag_target_insn = NULL_RTX; + metag_ccfsm_state = 0; + } + return; + } + + /* If in state 3, it is possible to repeat the trick, if this insn is an + unconditional branch to a label, and immediately following this branch + is the previous target label which is only used once, and the label this + branch jumps to is not too far off. */ + if (metag_ccfsm_state == 3) + { + if (simplejump_p (insn)) + { + start_insn = next_nonnote_insn (start_insn); + if (BARRIER_P (start_insn)) + { + /* XXX Isn't this always a barrier? */ + start_insn = next_nonnote_insn (start_insn); + } + + if (GET_CODE (start_insn) == CODE_LABEL + && CODE_LABEL_NUMBER (start_insn) == metag_target_label + && LABEL_NUSES (start_insn) == 1) + reverse = true; + else + return; + } + else + return; + } + + if (metag_ccfsm_state != 0 && !reverse) + gcc_unreachable (); + + if (!JUMP_P (insn)) + return; + + /* This jump might be paralleled with a clobber of the condition codes + the jump should always come first */ + if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) > 0) + body = XVECEXP (body, 0, 0); + + /* If this jump uses the hardware loop counter, leave it alone */ + if (reg_mentioned_p (gen_rtx_REG (VOIDmode, TXRPT_REGNUM), body)) + return; + + /* If this is a conditional return then we don't want to know */ + if (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == PC + && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE + && (GET_CODE (XEXP (SET_SRC (body), 1)) == RETURN + || GET_CODE (XEXP (SET_SRC (body), 2)) == RETURN)) + return; + + if (reverse + || (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == PC + && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE)) + { + int insns_skipped = 0; + int fail = 0; + int quit = false, succeed = false; + /* Flag which part of the IF_THEN_ELSE is the LABEL_REF. */ + int then_not_else = true; + rtx this_insn = start_insn; + rtx label = NULL_RTX; + + /* Register the insn jumped to. */ + if (reverse) + label = XEXP (SET_SRC (body), 0); + else if (LABEL_REF_P (XEXP (SET_SRC (body), 1))) + label = XEXP (XEXP (SET_SRC (body), 1), 0); + else if (LABEL_REF_P (XEXP (SET_SRC (body), 2))) + { + label = XEXP (XEXP (SET_SRC (body), 2), 0); + then_not_else = false; + } + else + gcc_unreachable (); + +#if METAG_DEBUG_CCEXEC + fprintf (stderr, "CE =====\n"); debug_rtx (insn); +#endif + /* See how many insns this branch skips, and what kind of insns. If all + insns are okay, and the label or unconditional branch to the same + label is not too far away, succeed. */ + while (!quit && !succeed && insns_skipped < metag_max_insns_skipped) + { + this_insn = next_nonnote_insn (this_insn); + if (!this_insn) + break; + + /* Only count recognised instructions others aren't relevant.*/ + + if (INSN_P (this_insn) && INSN_CODE (this_insn) >= 0) + insns_skipped++; + + switch (GET_CODE (this_insn)) + { + case CODE_LABEL: + /* Succeed if it is the target label, otherwise fail since + control falls in from somewhere else. */ + if (this_insn == label) + { + if (fail == 0) + { + metag_ccfsm_state = 1; + succeed = true; +#if METAG_DEBUG_CCEXEC + fprintf (stderr, "CE found label after %d successes\n", insns_skipped); +#endif + } + else + { +#if METAG_DEBUG_CCEXEC + fprintf (stderr, "CE found label after %d failures\n", fail); +#endif + quit = true; + } + } + else + { +#if METAG_DEBUG_CCEXEC + fprintf (stderr, "CE failed CODE_LABEL after %d insns\n", insns_skipped); +#endif + fail++; + } + + break; + + case BARRIER: + /* Succeed if the following insn is the target label. + Otherwise fail. + If return insns are used then the last insn in a function + will be a barrier. */ + this_insn = next_nonnote_insn (this_insn); + if (this_insn && this_insn == label) + { + if (fail == 0) + { + metag_ccfsm_state = 1; + succeed = true; +#if METAG_DEBUG_CCEXEC + fprintf (stderr, "CE found label after %d successes\n", insns_skipped); +#endif + } + else + { +#if METAG_DEBUG_CCEXEC + fprintf (stderr, "CE found label after %d failures\n", fail); +#endif + quit = true; + } + } + else + { +#if METAG_DEBUG_CCEXEC + fprintf (stderr, "CE failed BARRIER after %d insns\n", insns_skipped); +#endif + fail++; + } + + break; + + case CALL_INSN: +#if 0 + if (!(GET_CODE (operands[?]) == REG + && REGNO (operands[?]) != RETURN_POINTER_REGNUM)) +#endif + { +#if METAG_DEBUG_CCEXEC + fprintf (stderr, "CE failed CALL_INSN after %d insns\n", insns_skipped); + debug_rtx (this_insn); +#endif + fail++; + } + break; + + case JUMP_INSN: + /* If this is an unconditional branch to the same label, succeed. + If it is to another label, do nothing. If it is conditional, + fail. */ + /* XXX Probably, the tests for SET and the PC are unnecessary. */ + + { + rtx scanbody = PATTERN (this_insn); + + if (GET_CODE (scanbody) == SET + && GET_CODE (SET_DEST (scanbody)) == PC) + { + if (LABEL_REF_P (SET_SRC (scanbody)) + && XEXP (SET_SRC (scanbody), 0) == label && !reverse) + { + if (fail == 0) + { + metag_ccfsm_state = 2; + succeed = true; +#if METAG_DEBUG_CCEXEC + fprintf (stderr, "CE found jump to target label after %d successes\n", insns_skipped); +#endif + } + else + { +#if METAG_DEBUG_CCEXEC + fprintf (stderr, "CE found uncond branch after %d failures\n", fail); +#endif + quit = true; + } + } + else if (GET_CODE (SET_SRC (scanbody)) == IF_THEN_ELSE) + { +#if METAG_DEBUG_CCEXEC + fprintf (stderr, "CE failed JUMP_INSN IF_THEN_ELSE after %d insn\n", insns_skipped); + debug_rtx (this_insn); +#endif + fail++; + } + } + else if (GET_CODE (scanbody) == RETURN) + { + if (!metag_cheap_return (true)) + { +#if METAG_DEBUG_CCEXEC + fprintf (stderr, "CE failed JUMP_INSN RETURN (not cheap) after %d insn\n", insns_skipped); + debug_rtx (this_insn); +#endif + fail++; + } + } + else + { +#if METAG_DEBUG_CCEXEC + fprintf (stderr, "CE failed JUMP_INSN not recognised after %d insn\n", insns_skipped); + debug_rtx (this_insn); +#endif + fail++; + } + } + + break; + + case INSN: + if (INSN_CODE (this_insn) >= 0) + { + enum attr_cond cond_attr = get_attr_cond (this_insn); + enum attr_predicable predicable_attr = get_attr_predicable (this_insn); + enum attr_ccstate ccstate_attr = get_attr_ccstate (this_insn); + + /* A predicated instruction can't be COND_EXEC unless + the predication condition matches the condexec + condition. At present we ALWAYS reject predicated + instructions which is safe but sub-optimal. */ + if (predicable_attr == PREDICABLE_YES && GET_CODE (PATTERN (this_insn)) == COND_EXEC) + { +#if METAG_DEBUG_CCEXEC + fprintf (stderr, "CE failed INSN PREDICABLE=%s and COND_EXEC after %d insns\n", + attr_predicable_name (predicable_attr), + insns_skipped); + debug_rtx (this_insn); +#endif + fail++; + } + + /* Only insns which don't modify CC can be cond-exec */ + if (cond_attr != COND_YES || ccstate_attr != CCSTATE_NCC) + { +#if METAG_DEBUG_CCEXEC + fprintf (stderr, "CE failed INSN COND=%s CSTATE=%s after %d insns\n", + attr_cond_name (cond_attr), + attr_ccstate_name (ccstate_attr), + insns_skipped); + debug_rtx (this_insn); +#endif + fail++; + } + } + else if (asm_noperands (PATTERN (this_insn)) >= 0) + { +#if METAG_DEBUG_CCEXEC + fprintf (stderr, "CE failed ASM_OPERANDS after %d insns\n", + insns_skipped); + debug_rtx (this_insn); +#endif + fail++; + } + else if (GET_CODE (PATTERN (this_insn)) != USE) + { + /* Anything else not recognised with the exception of + an USE (typically an USE of return register) fails + conditional execution. */ +#if METAG_DEBUG_CCEXEC + fprintf (stderr, "CE failed unrecognised after %d insns\n", + insns_skipped); + debug_rtx (this_insn); +#endif + fail++; + } + + break; + + default: + break; + } + } + + if (succeed) + { + if (metag_ccfsm_state == 1 || reverse) + metag_target_label = CODE_LABEL_NUMBER (label); + else if (metag_ccfsm_state == 2) + { + while (this_insn && GET_CODE (PATTERN (this_insn)) == USE) + { + this_insn = next_nonnote_insn (this_insn); + if (this_insn + && (BARRIER_P (this_insn) + || GET_CODE (this_insn) == CODE_LABEL)) + gcc_unreachable (); + } + + if (!this_insn) + { + /* Oh, dear! we ran off the end.. give up */ + if (INSN_CODE (insn) >= 0) + { + recog (PATTERN (insn), insn, NULL); + cleanup_subreg_operands (insn); + } + + metag_ccfsm_state = 0; + metag_target_insn = NULL_RTX; + return; + } + + metag_target_insn = this_insn; + } + else + gcc_unreachable (); + + /* If REVERSE is true, METAG_CURRENT_CC needs to be inverted + * from what it was. */ + if (!reverse) + metag_current_cc = get_metag_cc (XEXP (SET_SRC (body), 0)); + + if (reverse || then_not_else) + metag_current_cc = metag_inv_cc [metag_current_cc]; + } + + if (INSN_CODE (insn) >= 0) + { + /* restore recog_operand (getting the attributes of other insns can + destroy this array, but final.c assumes that it remains intact + across this call; since the insn has been recognized already we + call recog direct). */ + recog (PATTERN (insn), insn, NULL); + cleanup_subreg_operands (insn); + } + } +} + +bool +metag_cond_exec_p (void) +{ + return (metag_ccfsm_state == 3 || metag_ccfsm_state == 4); +} + +void +metag_print_cc_if_conditional (FILE *stream) +{ + if (metag_cond_exec_p ()) + { + gcc_assert (current_insn_predicate == NULL_RTX); + fputs (metag_cc_names[metag_current_cc], stream); + } + else if (current_insn_predicate != NULL_RTX) + fputs (metag_cc_names[get_metag_cc (current_insn_predicate)], stream); + + return; +} + +bool +metag_consume_branch (rtx insn ATTRIBUTE_UNUSED) +{ + if (metag_ccfsm_state == 1 || metag_ccfsm_state == 2) + { + metag_ccfsm_state += 2; + return true; + } + + return false; +} + + +/* Output to FILE code to call mcount. */ +void +metag_function_profiler (FILE *file) +{ + if (1 || !TARGET_METAC_1_1) + { + fprintf (file, "\tMOVT\t%s, #HI(_mcount_wrapper)\n", + reg_names[TEMP_D0FRT_REGNUM]); + fprintf (file, "\tCALL\t%s, #LO(_mcount_wrapper)\n", + reg_names[TEMP_D0FRT_REGNUM]); + } + else + fprintf (file, "\tCALLR\t%s, _mcount_wrapper\n", + reg_names[TEMP_D0FRT_REGNUM]); +} + +static bool +metag_same_reg_p (rtx reg1, rtx reg2, bool strict) +{ + unsigned int r1 = REGNO (reg1); + unsigned int r2 = REGNO (reg2); + + if (IS_PSEUDO_REGNO (r1) && reg_renumber != NULL) + r1 = reg_renumber[r1]; + + if (IS_PSEUDO_REGNO (r2) && reg_renumber != NULL) + r2 = reg_renumber[r2]; + + return strict ? IS_HARD_OR_VIRT_REGNO (r1) && IS_HARD_OR_VIRT_REGNO (r2) && r1 == r2 + : r1 != INVALID_REGNUM && r1 != INVALID_REGNUM && r1 == r2; +} + +static bool +metag_regs_same_regclass_p (rtx reg1, rtx reg2, bool strict) +{ + unsigned int r1 = REGNO (reg1); + unsigned int r2 = REGNO (reg2); + enum reg_class class1; + enum reg_class class2; + + if (IS_PSEUDO_REGNO (r1) && reg_renumber != NULL) + r1 = reg_renumber[r1]; + + if (IS_PSEUDO_REGNO (r2) && reg_renumber != NULL) + r2 = reg_renumber[r2]; + + class1 = METAG_REGNO_REG_CLASS (r1); + class2 = METAG_REGNO_REG_CLASS (r2); + + return strict ? class1 != NO_REGS && class2 != NO_REGS && class1 == class2 + : class1 != NO_REGS && class2 != NO_REGS && class1 == class2; +} + +bool +metag_same_regclass_p (rtx reg1, rtx reg2) +{ + return metag_regs_same_regclass_p (reg1, reg2, true); +} + +/* Return true iff the registers are in the same function unit + (i.e. D0, D1, A0, A1, CTRL). */ + +bool +metag_regno_same_unit_p (unsigned int regno1, unsigned int regno2) +{ + enum reg_class class1 = METAG_REGNO_REG_CLASS (regno1); + enum reg_class class2 = METAG_REGNO_REG_CLASS (regno2); + + return class1 != NO_REGS && class2 != NO_REGS && class1 == class2; +} + +/* (post_modify (REG ...) + (plus (REG ...) + (REG ...))) + or + + (post_modify (REG ...) + (plus (REG ...) + (CONST_INT ...))) +*/ +bool +metag_legitimate_modify_p (rtx addr, enum machine_mode mode, bool strict) +{ + rtx op0 = XEXP (addr, 0); + rtx op1 = XEXP (addr, 1); + rtx op2; + rtx op3; + + if (GET_CODE (op1) != PLUS) + return false; + + if (!METAG_LEGITIMATE_REG_P (op0, strict)) + return false; + + op2 = XEXP (op1, 0); + op3 = XEXP (op1, 1); + if (!METAG_LEGITIMATE_REG_P (op2, strict)) + return false; + + if (!metag_same_reg_p (op0, op2, strict)) + return false; + + if (REG_P (op3)) + return METAG_LEGITIMATE_TWIN_P (op2, op3, mode, strict); + + if (CONST_INT_P (op3) && metag_offset6_mode (op3, mode)) + return true; + + return false; +} + +long +metag_const_double_to_hp (rtx op, bool *inexact) +{ + REAL_VALUE_TYPE rv; + long half = 0; + bool dummy_inexact; + + if (!inexact) + inexact = &dummy_inexact; + + REAL_VALUE_FROM_CONST_DOUBLE (rv, op); + + *inexact = false; + + if (GET_MODE(op) == SFmode) + { + long tgsingle; + bool tgsgn; + long tgexp; + long tgman; + + REAL_VALUE_TO_TARGET_SINGLE (rv, tgsingle); + + /* Split the parts */ + tgsgn = ((tgsingle & 0x80000000ul) != 0); + tgexp = (tgsingle & 0x7F800000) >> 23; + tgman = tgsingle & 0x007FFFFF; + + /* If the fractional part would need rounding, raise inexact */ + if (tgman & 0x00001FFF) + *inexact = true; + + /* Convert to HF (truncate) */ + + /* Exp == MAX we must preserve the Inf or NaN */ + if (tgexp == 0xFF) + half = tgman ? 0x7C01 : 0x7C00; + /* Exp == 0 is special we must not bias adjust it */ + else if (tgexp == 0x00) + half = tgman >> (23 - 10); + else + { + tgexp -= 127; /* Remove SF bias */ + tgexp += 15; /* Add HF bias */ + tgman >>= 23 - 10; + + if (tgexp >= 32) + { + *inexact = true; + half = 0x7C00; /* Overflow to inf */ + } + else if (tgexp < 0) + { + *inexact = true; + half = 0x0000; /* Underflow to 0 */ + } + else + half = (tgexp & 0x01F) << 10 + | (tgman & 0x3FF); + } + + /* Copy the sign */ + if (tgsgn) + half |= 0x8000; + } + else if (GET_MODE(op) == DFmode) + { + long tgdouble[2]; + bool tgsgn; + long tgexp; + long tgman[2]; + + REAL_VALUE_TO_TARGET_DOUBLE (rv, tgdouble); + + /* Split the parts */ + tgsgn = ((tgdouble[1] & 0x80000000ul) != 0); + tgexp = (tgdouble[1] & 0x7FF00000) >> (52-32); + tgman[1] = (tgdouble[1] & 0x000FFFFF); + tgman[0] = tgdouble[0]; + + /* If the fractional part would need rounding, reject */ + if (tgman[1] & 0x0000FFFF || tgman[0]) + *inexact = true; + + /* Convert to HF (truncate) */ + + /* Exp == MAX we must preserve the Inf or NaN */ + if (tgexp == 0x7FF) + half = tgman[1] || tgman[0] ? 0x7C01 : 0x7C00; + /* Exp == 0 is special we must not bias adjust it */ + else if (tgexp == 0x00) + half = tgman[1] >> (52 - 10 - 32); + else + { + tgexp -= 1023; /* Remove SF bias */ + tgexp += 15; /* Add HF bias */ + tgman[0] = tgman[1] >> (52 - 10 - 32); + tgman[1] = 0; + + if (tgexp >= 32) + { + *inexact = true; + half = 0x7C00; /* Overflow to inf */ + } + else if (tgexp < 0) + { + *inexact = true; + half = 0x0000; /* Underflow to 0 */ + } + else + half = (tgexp & 0x01F) << 10 + | (tgman[0] & 0x3FF); + } + + /* Copy the sign */ + if (tgsgn) + half |= 0x8000; + } + + return half; +} + +void +metag_print_operand (FILE * file, rtx op, enum rtx_code code) +{ + if (code == '?') + metag_print_cc_if_conditional (file); + else if (code == '@') + fputs (ASM_COMMENT_START, file); + else if (code == 'z') + fputs (metag_cc_names[get_metag_cc (op)], file); + else if (code == 'Z') + fputs (metag_cc_names[metag_inv_cc [get_metag_cc (op)]], file); + else if (code == 'h') + { + if (GET_CODE (op) == CONST_VECTOR) + { + gcc_assert (GET_MODE_INNER (GET_MODE (op)) == SFmode); + gcc_assert (rtx_equal_p (CONST_VECTOR_ELT (op, 0), + CONST_VECTOR_ELT (op, 1))); + op = CONST_VECTOR_ELT (op, 0); + } + fprintf (file, "0x%04lX", metag_const_double_to_hp (op, NULL)); + } + else if (REG_P (op)) + { + if (code == 't') + fputs (reg_names[REGNO (op) + 1], file); + else + fputs (reg_names[REGNO (op)], file); + } + else + { + if (MEM_P (op)) + { + if (SYMBOL_REF_P (XEXP (op, 0))) + { + /* Abort if we're about to generate #OG addressing. */ + debug_rtx (op); + gcc_unreachable (); + } + else + output_address (op); + } + else + { + if (CONST_DOUBLE_P (op) && GET_MODE (op) == SFmode) + { + long value = metag_const_double_sfmode (op); + + if (code != 'c') + fputc ('#', file); + fprintf (file, "0x%08lx", value); + } + else + { + if (code != 'c') + { + rtx itemp = op; + + fputc ('#', file); + if (CONST_INT_P (op) + && (INTVAL (op) < -32768 || INTVAL (op) > 0x0000FFFF)) + itemp = GEN_INT (((INTVAL (op)) >> 16) & 0x0000FFFF); + + output_addr_const (file, itemp); + } + else if (CONST_INT_P (op) + && (INTVAL (op) < -32768 || INTVAL (op) > 0x0000FFFF)) + fprintf (file, "0x%08lx", (long)INTVAL (op)); + else + output_addr_const (file, op); + } + } + } +} + +static void +metag_output_pic_addr_const (FILE *file, rtx addr) +{ + output_addr_const (file, XVECEXP (addr, 0, 0)); + switch (XINT (addr, 1)) + { + case UNSPEC_GOT: + fputs ("@GOT", file); + break; + case UNSPEC_GOTOFF: + fputs ("@GOTOFF", file); + break; + case UNSPEC_PLT: + fputs ("@PLT", file); + break; + default: + metag_abort (addr); + break; + } +} + +void +metag_print_operand_address (FILE *file, rtx op) +{ + rtx addr = MEM_P (op) ? XEXP (op, 0) : op; + rtx offset; + rtx reg; + int inc; + + switch (GET_CODE (addr)) + { + case SYMBOL_REF: + /* Abort if we're about to generate #OG addressing. */ + gcc_unreachable (); + break; + case REG: + fprintf (file, "[%s]", reg_names[REGNO (addr)]); + break; + case PRE_INC: + reg = XEXP (addr, 0); + inc = GET_MODE_SIZE (GET_MODE (op)); + fprintf (file, "[%s ++#%d]", reg_names[REGNO (reg)], inc); + break; + case POST_INC: + reg = XEXP (addr, 0); + inc = GET_MODE_SIZE (GET_MODE (op)); + fprintf (file, "[%s+#%d++]", reg_names[REGNO (reg)], inc); + break; + case PRE_DEC: + reg = XEXP (addr, 0); + inc = GET_MODE_SIZE (GET_MODE (op)); + fprintf (file, "[%s ++#(-%d)]", reg_names[REGNO (reg)], inc); + break; + case POST_DEC: + reg = XEXP (addr, 0); + inc = GET_MODE_SIZE (GET_MODE (op)); + fprintf (file, "[%s+#(-%d)++]", reg_names[REGNO (reg)], inc); + break; + case PRE_MODIFY: + reg = XEXP (addr, 0); + if (GET_CODE (XEXP (addr, 1)) != PLUS) + metag_abort (op); + else + { + rtx op0 = XEXP (XEXP (addr, 1), 0); + + if (!REG_P (op0)) + metag_abort (op); + else if (REGNO (reg) != REGNO (op0)) + metag_abort (op); + else + { + rtx op1 = XEXP (XEXP (addr, 1), 1); + + if (REG_P (op1)) + fprintf (file, "[%s++%s]", + reg_names[REGNO (op0)], reg_names[REGNO (op1)]); + else if (CONST_INT_P (op1)) + fprintf (file, "[%s++#(%ld)]", + reg_names[REGNO (op0)], INTVAL (op1)); + else + metag_abort (op); + } + } + break; + case POST_MODIFY: + reg = XEXP (addr, 0); + if (GET_CODE (XEXP (addr, 1)) != PLUS) + metag_abort (op); + else + { + rtx op0 = XEXP (XEXP (addr, 1), 0); + + if (!REG_P (op0)) + metag_abort (op); + else if (REGNO (reg) != REGNO (op0)) + metag_abort (op); + else + { + rtx op1 = XEXP (XEXP (addr, 1), 1); + + if (REG_P (op1)) + fprintf (file, "[%s+%s++]", + reg_names[REGNO (op0)], reg_names[REGNO (op1)]); + else if (CONST_INT_P (op1)) + fprintf (file, "[%s+#(%ld)++]", + reg_names[REGNO (op0)], INTVAL (op1)); + else + metag_abort (op); + } + } + break; + case PLUS: + reg = XEXP (addr, 0); + if (CONST_INT_P (reg)) + { + offset = reg; + reg = XEXP (addr, 1); + } + else + offset = XEXP (addr, 1); + + if (!REG_P (reg)) + metag_abort (addr); + + if (REG_P (offset)) + fprintf (file, "[%s + %s]", + reg_names[REGNO (reg)], reg_names[REGNO (offset)]); + else if (CONST_INT_P (offset)) + fprintf (file, "[%s + #%ld]", reg_names[REGNO (reg)], INTVAL (offset)); + else if (METAG_FLAG_PIC + && reg == pic_offset_table_rtx + && GET_CODE (offset) == CONST + && GET_CODE (XEXP (offset, 0)) == UNSPEC + && XVECLEN (XEXP (offset, 0), 0) == 1 + && (XINT (XEXP (offset, 0), 1) == UNSPEC_GOT + || XINT (XEXP (offset, 0), 1) == UNSPEC_PLT)) + { + fprintf (file, "[%s + #(", reg_names[REGNO (reg)]); + metag_output_pic_addr_const (file, XEXP (offset, 0)); + fputs (")]", file); + } + else + metag_abort (addr); + break; + default: + if (CONSTANT_ADDRESS_P (addr)) + output_addr_const (file, addr); + else + metag_abort (addr); + break; + } +} + +int +metag_arg_partial_bytes (CUMULATIVE_ARGS * cum, enum machine_mode mode, tree type, bool named) +{ + unsigned int acum; + unsigned int aarg; + unsigned int nbytes; + + /* variadic arguments a.k.a named are ALWAYS passed on the stack */ + + if (!named) + return 0; + + acum = ROUND_ADVANCE_CUM (cum->narg, mode, type); + aarg = ROUND_ADVANCE_ARG (mode, type); + + nbytes = ((acum < MAX_METAG_PARM_BYTES && MAX_METAG_PARM_BYTES < (acum + aarg)) + ? (MAX_METAG_PARM_BYTES - acum) + : 0); + + if (cum->partial == 0) + { + if (nbytes > 0) + { + int size = METAG_ARG_SIZE (mode, type); + int nstack = size - nbytes; + + gcc_assert ((nstack & (STACK_BOUNDARY_BYTES - 1)) == 0); + } + + cum->partial = nbytes; + } + else + gcc_assert (nbytes == 0); + + return nbytes; +} + +bool +metag_pass_by_reference (CUMULATIVE_ARGS * cum ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + tree type ATTRIBUTE_UNUSED, + bool named ATTRIBUTE_UNUSED) +{ + return false; +} + +static bool +metag_pass_in_reg (CUMULATIVE_ARGS * cum, + enum machine_mode mode, + tree type, + bool named ATTRIBUTE_UNUSED) +{ + int rcum; + + if (!named) + return false; + + if (cum->narg >= MAX_METAG_PARM_BYTES) + return false; + + rcum = ROUND_ADVANCE_CUM (cum->narg, mode, type); + if (rcum >= MAX_METAG_PARM_BYTES) + return false; + + return true; +} + +bool +metag_must_pass_in_stack (enum machine_mode mode ATTRIBUTE_UNUSED, + tree type ATTRIBUTE_UNUSED) +{ + return false; +} + +rtx +metag_function_arg (CUMULATIVE_ARGS * cum, enum machine_mode mode, tree type, bool named) +{ + bool pass_in_reg = metag_pass_in_reg (cum, mode, type, named); + int reg; + + if (!pass_in_reg) + return NULL_RTX; + + reg = CALCULATE_REG (MAX_METAG_PARM_REGNUM, cum->narg, mode, type); + if (reg < MIN_METAG_PARM_REGNUM) + reg = MIN_METAG_PARM_REGNUM; + + return gen_rtx_REG (mode, reg); +} + +void +metag_function_arg_advance (CUMULATIVE_ARGS * cum, enum machine_mode mode, tree type, bool named ATTRIBUTE_UNUSED) +{ + cum->narg = ROUND_ADVANCE_CUM (cum->narg, mode, type) + ROUND_ADVANCE_ARG (mode, type); + return; +} + +/* Define the offset between two registers, one to be eliminated, + and the other its replacement, at the start of a routine. + + To kick things off we work out OFFSET as the size of the frame save + area. Then we need to apply the following- + + ARG_POINTER = STACK_POINTER - (PRETEND + SAVE + PIC_SAVE + LOCAL + OUT_GOING) + ARG_POINTER = HARD_FRAME_POINTER - (PRETEND ) + FRAME_POINTER = STACK_POINTER - ( + SAVE + PIC_SAVE + LOCAL + OUT_GOING) + FRAME_POINTER = HARD_FRAME_POINTER + ( + SAVE + PIC_SAVE ) + */ + +int +metag_initial_elimination_offset (int from, int to) +{ + /* This section of code and output_fn_prologue/epilogue + * MUST agree on how the stack is going to be layedout. + * Any discrepancy will result in wrong code being + * generated. + */ + + HOST_WIDE_INT out_local_size = get_frame_size (); + bool non_leaf = metag_non_leaf_function_p (); + unsigned int savesize_gp = 0; + unsigned int savesize_eh = 0; + unsigned int FP_SP_offset = 0; + unsigned int pic_save_size = 0; + unsigned int pretend_size = ALIGN_ON_STACK_BOUNDARY (current_function_pretend_args_size); + unsigned int extras_gp = 0; + unsigned int extras_eh = 0; + unsigned int ech_ctx = 0; + unsigned int pretend_regs; + int delta; + bool loads_pic_register; + + if (pretend_size != 0) + { + /* Determine # register pairs needed for pretend args. */ + pretend_regs = pretend_size / UNITS_PER_WORD; + } + else + pretend_regs = 0; + + out_local_size = ALIGN_ON_STACK_BOUNDARY (out_local_size + current_function_outgoing_args_size); + + /* Make pretend regs into the first non-varargs register number */ + pretend_regs += MIN_METAG_PARM_REGNUM; + + { + unsigned int regno; + + for (regno = MIN_METAG_PARM_REGNUM; + regno <= MAX_METAG_CSAVE_REGNUM; + regno += 2) + { + if (regno < pretend_regs + || (!call_used_regs[regno] + && (df_regs_ever_live_p (regno + 0) || df_regs_ever_live_p (regno + 1)))) + { + extras_gp |= REGNO_BIT (regno); + savesize_gp += UNITS_PER_WORD * 2; + + if (regno >= MIN_METAG_CSAVE_REGNUM) + FP_SP_offset += UNITS_PER_WORD * 2; + } + } + } + + /* Adjust the saved registers for ECH support */ + ech_ctx = metag_adjust_savesize_ech (&savesize_gp, &extras_gp, &FP_SP_offset); + + if (current_function_calls_eh_return) + { + unsigned int n; + + for (n = 0; n < NUM_EH_RETURN_DATA_REGS; n++) + { + unsigned int regno = EH_RETURN_DATA_REGNO (n); + + if (regno != INVALID_REGNUM) + { + unsigned int regbit = REGNO_BIT (regno); + + if ((extras_eh & regbit) == 0) + { + extras_eh |= regbit; + savesize_eh += UNITS_PER_WORD * 2; + FP_SP_offset += UNITS_PER_WORD * 2; + } + } + } + } + + if (frame_pointer_needed || non_leaf) + { + savesize_gp += UNITS_PER_WORD * 2, FP_SP_offset += UNITS_PER_WORD * 2; + + if (non_leaf) + extras_gp |= REGNO_BIT (RETURN_POINTER_REGNUM); + + if (frame_pointer_needed) + extras_gp |= REGNO_BIT (TEMP_D0FRT_REGNUM); + } + else if (df_regs_ever_live_p (RETURN_POINTER_REGNUM)) + { + extras_gp |= REGNO_BIT (RETURN_POINTER_REGNUM); + + /* Have to do at least one pop */ + savesize_gp += UNITS_PER_WORD * 2; + } + + loads_pic_register = METAG_CURRENT_FUNCTION_LOADS_PIC_REGISTER (); + if (loads_pic_register) + pic_save_size += UNITS_PER_WORD * 2; + + cfun->machine->frame_pointer_needed = frame_pointer_needed; + cfun->machine->non_leaf = non_leaf; + cfun->machine->savesize_gp = savesize_gp; + cfun->machine->savesize_eh = savesize_eh; + cfun->machine->FP_SP_offset = FP_SP_offset + pic_save_size; + cfun->machine->pic_save_size = pic_save_size; + cfun->machine->out_local_size = out_local_size; + cfun->machine->calls_eh_return = current_function_calls_eh_return; + cfun->machine->extras_gp = extras_gp; + cfun->machine->extras_eh = extras_eh; + cfun->machine->uses_pic_offset_table = current_function_uses_pic_offset_table; + cfun->machine->loads_pic_register = loads_pic_register; + cfun->machine->ech_ctx_required = (ech_ctx != 0); + cfun->machine->arg_adjust_delta = 0; + cfun->machine->frame_adjust_delta = 0; + cfun->machine->can_use_short_branch = false; + cfun->machine->valid = true; + + switch (from) + { + case ARG_POINTER_REGNUM: + switch (to) + { + case STACK_POINTER_REGNUM: + delta = -savesize_gp - savesize_eh - pic_save_size - out_local_size; + if (cfun->machine->anonymous_args) + delta += ALIGN_ON_STACK_BOUNDARY (cfun->machine->anonymous_args_size); + cfun->machine->arg_adjust_delta = delta; + return delta; + case HARD_FRAME_POINTER_REGNUM: + delta = -pretend_size; + if (cfun->machine->anonymous_args) + delta += ALIGN_ON_STACK_BOUNDARY (cfun->machine->anonymous_args_size); + cfun->machine->arg_adjust_delta = delta; + return delta; + default: + gcc_unreachable (); + } + break; + case FRAME_POINTER_REGNUM: + switch (to) + { + case STACK_POINTER_REGNUM: + delta = -out_local_size; + cfun->machine->frame_adjust_delta = delta; + return delta; + case HARD_FRAME_POINTER_REGNUM: + delta = -pretend_size + savesize_gp + savesize_eh + pic_save_size; + cfun->machine->frame_adjust_delta = delta; + return delta; + default: + gcc_unreachable (); + break; + } + break; + default: + gcc_unreachable (); + break; + } + + gcc_unreachable (); +} + +typedef struct hwtrace_fn +{ + const char * name; + int onoff; + struct hwtrace_fn *next; +} hwtrace_fn; + +/* A simple linked list records info about "#pragma hwtrace_function (name, 0|1) */ +static hwtrace_fn *hwtrace_function_list = NULL; +/* records default if #pragma hwtrace_function (*, 0|1) */ +static int hwtrace_function_default = -1; /* < 0 none, 0 off > 1 on */ + +static bool +hwtrace_function_enabled (tree function_decl) +{ + if (function_decl) + { + const char * fnname = IDENTIFIER_POINTER (DECL_NAME (function_decl)); + hwtrace_fn *next = hwtrace_function_list; + + while (next != NULL) + { + if (strcmp (next->name, fnname) == 0) + return next->onoff; + + next = next->next; + } + + if (hwtrace_function_default < 0) + return true; + + if (hwtrace_function_default > 0) + return true; + + return false; + } + + return true; +} + +static struct machine_function * +metag_init_machine_status (void) +{ + struct machine_function *machine + = (machine_function *) ggc_alloc_cleared (sizeof (*machine)); + bool enabled = hwtrace_function_enabled (current_function_decl); + + machine->valid = false; + machine->hwtrace = TARGET_HWTRACE && enabled; + machine->hwtrace_leaf = TARGET_HWTRACE_LEAF && enabled; + machine->hwtrace_retpc = TARGET_HWTRACE_RETPC && enabled; + + machine->cond_return_state = METAG_COND_RETURN_NONE; + return machine; +} + +void +metag_init_expanders (void) +{ + init_machine_status = metag_init_machine_status; +} + +bool +metag_legitimate_address_p (rtx addr, enum machine_mode mode, bool strict) +{ + rtx tmp; + + if (METAG_FLAG_PIC && SYMBOLIC_CONST (addr)) + return metag_legitimate_pic_address_disp_p (addr); + + if (SYMBOL_REF_P (addr) && METAG_SYMBOL_FLAG_DIRECT_P (addr)) + return true; + + tmp = addr; + + if (SUBREG_P (tmp) + && (GET_MODE_SIZE (GET_MODE (tmp)) + < GET_MODE_SIZE (GET_MODE (SUBREG_REG (tmp))))) + tmp = SUBREG_REG (tmp); + + if (METAG_LEGITIMATE_REG_P (tmp, strict)) + return true; + + if (METAG_LEGITIMATE_PRE_INCDEC_P (addr, mode, strict)) + return true; + + if (METAG_LEGITIMATE_POST_INCDEC_P (addr, mode, strict)) + return true; + + if (METAG_LEGITIMATE_PRE_MODIFY_P (addr, mode, strict)) + return true; + + if (METAG_LEGITIMATE_POST_MODIFY_P (addr, mode, strict)) + return true; + + if (GET_CODE (addr) == PLUS) + { + rtx op0 = XEXP (addr, 0); + rtx op1 = XEXP (addr, 1); + + if (SUBREG_P (op0) + && (GET_MODE_SIZE (GET_MODE (op0)) + < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0))))) + op0 = SUBREG_REG (op0); + + if (METAG_LEGITIMATE_REG_P (op0, strict)) + { + if (REG_P (op1) + && METAG_LEGITIMATE_TWIN_P (op0, op1, mode, strict)) + return true; + + if (CONST_INT_P (op1) + && METAG_LEGITIMATE_OFF_P (op0, op1, mode, strict)) + return true; + } + + if (METAG_FLAG_PIC && op0 == pic_offset_table_rtx) + return metag_legitimate_pic_address_disp_p (op1); + } + + if (0 && GET_CODE (addr) == PLUS) + { + rtx op0 = XEXP (addr, 0); + rtx op1 = XEXP (addr, 1); + + if (GET_CODE (op0) == PLUS + && GET_CODE (op1) == CONST_INT) + { + rtx op3 = XEXP (op0, 0); + rtx op4 = XEXP (op0, 1); + + if (CONST_INT_P (op4)) + { + if (SUBREG_P (op3) + && (GET_MODE_SIZE (GET_MODE (op3)) + < GET_MODE_SIZE (GET_MODE (SUBREG_REG (op3))))) + op3 = SUBREG_REG (op3); + + op4 = GEN_INT (INTVAL (op1) + INTVAL (op4)); + if (METAG_LEGITIMATE_REG_P (op3, strict) + && METAG_LEGITIMATE_OFF_P (op3, op4, mode, strict)) + return true; + } + } + } + + return false; +} + +bool +metag_legitimate_regno_p (unsigned int regno, bool strict) +{ + if (strict) + { + if (IS_PSEUDO_REGNO (regno) && reg_renumber != NULL) + regno = reg_renumber [regno]; + + return regno <= FRAME_POINTER_REGNUM || regno == ARG_POINTER_REGNUM; + } + + return regno != INVALID_REGNUM; +} + +bool +metag_legitimate_reg_p (rtx reg, bool strict) +{ + return REG_P (reg) ? metag_legitimate_regno_p (REGNO (reg), strict) + : false; +} + +/* Return true iff BASE and OFF are valid for Reg + Reg addressing. + If STRICT is true then we need to be strict w.r.t pseduo registers + */ +bool +metag_regs_ok_for_base_offset_p (rtx base_reg, rtx off_reg, bool strict) +{ + if (!METAG_LEGITIMATE_REG_P (base_reg, strict)) + return false; + + if (!METAG_LEGITIMATE_REG_P (off_reg, strict)) + return false; + + return metag_regs_same_regclass_p (base_reg, off_reg, strict); +} + +bool +metag_reg_ok_for_base_p (rtx reg ATTRIBUTE_UNUSED, bool strict) +{ + return strict ? STRICT_REG_OK_FOR_BASE_P (reg) + : NONSTRICT_REG_OK_FOR_BASE_P (reg); +} + +bool +metag_reg_ok_for_offset_p (rtx reg, bool strict) +{ + return strict ? STRICT_REG_OK_FOR_OFFSET_P (reg) + : NONSTRICT_REG_OK_FOR_OFFSET_P (reg); +} + +bool +metag_reg_ok_for_index_p (rtx reg ATTRIBUTE_UNUSED, bool strict) +{ + return strict ? STRICT_REG_OK_FOR_INDEX_P (reg) + : NONSTRICT_REG_OK_FOR_INDEX_P (reg); +} + +bool +metag_legitimate_post_incdec_p (rtx addr, enum machine_mode mode ATTRIBUTE_UNUSED, bool strict) +{ + return (GET_CODE (addr) == POST_INC || GET_CODE (addr) == POST_DEC) + && METAG_LEGITIMATE_REG_P (XEXP (addr, 0), strict) + && !METAG_ELIMINABLE_REG_P (XEXP (addr, 0)); +} + +bool +metag_legitimate_pre_incdec_p (rtx addr, enum machine_mode mode ATTRIBUTE_UNUSED, bool strict) +{ + return (GET_CODE (addr) == PRE_INC || GET_CODE (addr) == PRE_DEC) + && METAG_LEGITIMATE_REG_P (XEXP (addr, 0), strict) + && !METAG_ELIMINABLE_REG_P (XEXP (addr, 0)); +} + +bool +metag_legitimate_off_p (rtx base, rtx off, enum machine_mode mode, bool strict ATTRIBUTE_UNUSED) +{ + if (CONST_INT_P (off)) + { + HOST_WIDE_INT value = INTVAL (off); + unsigned int modesize = GET_MODE_SIZE (mode); + + if ((value & (modesize - 1)) == 0) + { + unsigned int regno = REGNO (base); + HOST_WIDE_INT limit; + + if (reg_renumber != NULL && IS_PSEUDO_REGNO (regno)) + regno = reg_renumber[regno]; + + if (metag_regno12bit_p (regno) + && (!metag_fpu_resources + || (GET_MODE_CLASS (mode) != MODE_FLOAT))) + limit = 2048; + else if (cfun && regno == ARG_POINTER_REGNUM) + value += cfun->machine->arg_adjust_delta, limit = 2048; + else if (cfun && regno == FRAME_POINTER_REGNUM) + { + if (reload_in_progress) + return true; + + value += cfun->machine->frame_adjust_delta, limit = 2048; + } + else if (!strict && !reload_in_progress && !reload_completed + && (regno == ARG_POINTER_REGNUM + || regno == FRAME_POINTER_REGNUM)) + limit = 2048; + else if (!strict && !reload_in_progress && !reload_completed && IS_PSEUDO_REGNO (regno) + && (!metag_fpu_resources + || (GET_MODE_CLASS (mode) != MODE_FLOAT))) + limit = 2048; + else + limit = 32; + + limit *= modesize; + + return (-limit <= value && value < limit); + } + } + + return false; +} + +bool +metag_legitimate_twin_p (rtx base, rtx off, enum machine_mode mode ATTRIBUTE_UNUSED, bool strict) +{ + return METAG_REGS_OK_FOR_BASE_OFFSET_P (base, off, strict); +} + +bool +metag_frame_related_rtx (rtx op) +{ + return (REG_P (op) + && (op == frame_pointer_rtx + || op == arg_pointer_rtx + || op == virtual_incoming_args_rtx + || op == virtual_stack_vars_rtx + || op == virtual_stack_dynamic_rtx + || op == virtual_outgoing_args_rtx + || op == virtual_cfa_rtx + || REGNO (op) == FRAME_POINTER_REGNUM + || REGNO (op) == ARG_POINTER_REGNUM)); +} + + +/* Returns 1 if OP contains a symbol reference */ + +bool +metag_symbolic_reference_mentioned_p (rtx op) +{ + const char *fmt; + int i; + + if (SYMBOL_REF_P (op) || LABEL_REF_P (op)) + return true; + + fmt = GET_RTX_FORMAT (GET_CODE (op)); + for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--) + { + if (fmt[i] == 'E') + { + int j; + + for (j = XVECLEN (op, i) - 1; j >= 0; j--) + if (metag_symbolic_reference_mentioned_p (XVECEXP (op, i, j))) + return true; + } + else if (fmt[i] == 'e' && metag_symbolic_reference_mentioned_p (XEXP (op, i))) + return true; + } + + return false; +} + +bool +metag_legitimate_pic_address_disp_p (rtx disp) +{ + if (GET_CODE (disp) != CONST) + return false; + + disp = XEXP (disp, 0); + + if (GET_CODE (disp) == PLUS) + { + if (!CONST_INT_P (XEXP (disp, 1))) + return false; + + disp = XEXP (disp, 0); + } + + if (GET_CODE (disp) != UNSPEC + || XVECLEN (disp, 0) != 1) + return false; + + /* Must be @GOT but not @GOTOFF */ + if (XINT (disp, 1) != UNSPEC_GOT) + return false; + + if (!SYMBOL_REF_P (XVECEXP (disp, 0, 0)) + && !LABEL_REF_P (XVECEXP (disp, 0, 0))) + return false; + + return true; +} + +/* Try machine-dependent ways of modifying an illegitimate address + to be legitimate. If we find one, return the new, valid address. + This macro is used in only one place: `memory_address' in explow.c. + + OLDX is the address as it was before break_out_memory_refs was called. + In some cases it is useful to look at this to decide what needs to be done. + + MODE and WIN are passed so that this macro can use + GO_IF_LEGITIMATE_ADDRESS. + + It is always safe for this macro to do nothing. It exists to recognize + opportunities to optimize the output. +*/ + +rtx +metag_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED) +{ + + /* We currently only have support for thread local storage (TLS) + under META Linux. There is no TLS support for the embedded + toolchain */ + + if (tls_symbolic_operand_p (x)) + return metag_bfd_legitimize_tls_address (x); + + if (METAG_FLAG_PIC) + return SYMBOLIC_CONST (x) ? metag_legitimize_pic_address (x, 0) : x; + + return x; +} + +/* This function has been created by using the output template from the movsi + insn in metag.md */ + +void +metag_emit_move_sequence (rtx operands[], + enum machine_mode mode ATTRIBUTE_UNUSED) +{ + + if (metag_bfd_tls_referenced_p (operands[1])) + { + rtx tmp = operands[1]; + rtx addend = NULL; + + /* All TLS symbols should be wrapped in an UNSPEC prior to reload (the + check is performed by metag_bfd_tls_referenced_p) if they are still + symbols raise an error */ + if (reload_in_progress) + gcc_unreachable (); + else + { + /* Catch and fix the case where GCC is trying to offset a TLS symbol */ + if (GET_CODE (tmp) == CONST && GET_CODE (XEXP (tmp, 0)) == PLUS) + { + addend = XEXP (XEXP (tmp, 0), 1); + tmp = XEXP (XEXP (tmp, 0), 0); + } + + gcc_assert (GET_CODE (tmp) == SYMBOL_REF); + gcc_assert (SYMBOL_REF_TLS_MODEL (tmp) != 0); + + tmp = metag_bfd_legitimize_tls_address (tmp); + + if (addend) + { + tmp = gen_rtx_PLUS (mode, tmp, addend); + tmp = force_operand (tmp, operands[0]); + } + + operands[1] = tmp; + + if (MEM_P (operands[0])) + { + /* All except mem = const, mem = mem, or mem = addr can be done quickly */ + operands[1] = force_reg (SImode, operands[1]); + } + } + } + else if (METAG_FLAG_PIC && SYMBOLIC_CONST (operands[1])) + { + if (MEM_P (operands[0]) && SYMBOLIC_CONST (operands[1])) + operands[1] = force_reg (Pmode, operands[1]); + else + { + rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode); + + operands[1] = metag_legitimize_pic_address (operands[1], temp); + } + } + else if (MEM_P (operands[0])) + { + /* All except mem = const, mem = mem, or mem = addr can be done quickly */ + operands[1] = force_reg (SImode, operands[1]); + } + + if (REG_P (operands[0]) + && REGNO (operands[0]) == TXRPT_REGNUM) + { + if (CONST_INT_P (operands[1]) + && !(METAG_CONST_OK_FOR_LETTERS_KPIJ (operands[1]))) + { + operands[1] = force_reg (SImode, operands[1]); + } + } +} + +/* Return a legitimate reference for ORIG (an address) using the + register REG. If REG is 0, a new pseudo is generated. + + There are two types of references that must be handled: + + 1. Global data references must load the address from the GOT, via + the PIC reg. An insn is emitted to do this load, and the reg is + returned. + + 2. Static data references, constant pool addresses, and code labels + compute the address as an offset from the GOT, whose base is in + the PIC reg. Static data objects have SYMBOL_REF_FLAG set to + differentiate them from global data objects. The returned + address is the PIC reg + an unspec constant. +*/ + +rtx +metag_legitimize_pic_address (rtx orig, rtx reg) +{ + rtx addr = orig; + rtx new = orig; + rtx base; + + if (LABEL_REF_P (addr) + || (SYMBOL_REF_P (addr) + && (CONSTANT_POOL_ADDRESS_P (addr) + || METAG_SYMBOL_FLAG_DIRECT_P (addr) + || SYMBOL_REF_LOCAL_P (addr)))) + { + /* This symbol may be referenced via a displacement from the PIC + base address (@GOTOFF). */ + + /* Only mark this function as needing pic if we are not being called + as part of a cost-estimation process */ + if (!ir_type ()) + current_function_uses_pic_offset_table = 1; + + new = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, addr), UNSPEC_GOTOFF); + new = gen_rtx_CONST (VOIDmode, new); + new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new); + + if (reg != 0) + { + emit_move_insn (reg, new); + new = reg; + } + } + else if (SYMBOL_REF_P (addr)) + { + /* This symbol must be referenced via a load from the + Global Offset Table (@GOT). */ + + /* Only mark this function as needing pic if we are not being called + as part of a cost-estimation process */ + if (!ir_type ()) + current_function_uses_pic_offset_table = 1; + + new = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, addr), UNSPEC_GOT); + new = gen_rtx_CONST (VOIDmode, new); + new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new); + new = gen_rtx_MEM (Pmode, new); + + if (reg == 0) + reg = gen_reg_rtx (Pmode); + + emit_move_insn (reg, new); + new = reg; + } + else + { + if (GET_CODE (addr) == CONST) + { + addr = XEXP (addr, 0); + if (GET_CODE (addr) == UNSPEC) + { + /* Check that the unspec is one of the ones we generate? */ + } + else if (GET_CODE (addr) != PLUS) + abort(); + } + + if (GET_CODE (addr) == PLUS) + { + rtx op0 = XEXP (addr, 0), op1 = XEXP (addr, 1); + + /* Check first to see if this is a constant offset from a @GOTOFF + symbol reference. */ + if ((LABEL_REF_P (op0) + || (SYMBOL_REF_P (op0) + && (CONSTANT_POOL_ADDRESS_P (op0) + || METAG_SYMBOL_FLAG_DIRECT_P (op0)))) + && CONST_INT_P (op1)) + { + /* Only mark this function as needing pic if we are not being called + as part of a cost-estimation process */ + if (!ir_type ()) + current_function_uses_pic_offset_table = 1; + + new = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, op0), UNSPEC_GOTOFF); + new = gen_rtx_PLUS (Pmode, new, op1); + new = gen_rtx_CONST (VOIDmode, new); + new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new); + + if (reg != 0) + { + emit_move_insn (reg, new); + new = reg; + } + } + else + { + base = metag_legitimize_pic_address (XEXP (addr, 0), reg); + new = metag_legitimize_pic_address (XEXP (addr, 1), + base == reg ? NULL_RTX : reg); + + if (CONST_INT_P (new)) + new = plus_constant (base, INTVAL (new)); + else + { + if (GET_CODE (new) == PLUS && CONSTANT_P (XEXP (new, 1))) + { + base = gen_rtx_PLUS (Pmode, base, XEXP (new, 0)); + new = XEXP (new, 1); + } + + new = gen_rtx_PLUS (Pmode, base, new); + } + } + } + } + + return new; +} + +/* Compute a (partial) cost for rtx X. Return true if the complete + cost has been computed, and false if subexpressions should be + scanned. In either case, *TOTAL contains the cost result. */ + +bool +metag_rtx_costs (rtx x, int code, int outer_code, int *total) +{ + switch (code) + { + case CONST_INT: + if (satisfies_constraint_K (x)) + *total = (outer_code == SET ? COSTS_N_INSNS (1) : + outer_code == PLUS ? 0 : + outer_code == MINUS ? 0 : + outer_code == AND ? 0 : + outer_code == IOR ? 0 : + outer_code == XOR ? 0 : + outer_code == COMPARE ? 0 : + COSTS_N_INSNS (1)); + else if (satisfies_constraint_P (x)) + *total = (outer_code == SET ? COSTS_N_INSNS (1) : + outer_code == PLUS ? 0 : + outer_code == MINUS ? 0 : + outer_code == AND ? 0 : + outer_code == IOR ? 0 : + outer_code == XOR ? 0 : + outer_code == COMPARE ? 0 : + COSTS_N_INSNS (1)); + else if ((INTVAL (x) & 0xffff) == 0xffff + && (outer_code == AND || outer_code == IOR || outer_code == XOR)) + *total = COSTS_N_INSNS (1); + else if ((INTVAL (x) & 0xffff0000) == 0xffff0000 + && (outer_code == AND || outer_code == IOR || outer_code == XOR)) + *total = COSTS_N_INSNS (1); + else if (INTVAL (x) >= -32768 && INTVAL (x) <= 65535) + *total = COSTS_N_INSNS (1); + else if ((INTVAL (x) & 0xffff) == 0) + *total = COSTS_N_INSNS (2); + else + *total = COSTS_N_INSNS (5); + break; + case CONST: + if (outer_code == MEM) + { + *total = COSTS_N_INSNS (1); + return true; + } + *total = COSTS_N_INSNS (2); + break; + case LABEL_REF: + case SYMBOL_REF: + *total = COSTS_N_INSNS (6); + break; + case CONST_DOUBLE: + *total = COSTS_N_INSNS (10); + break; + case MULT: + *total = COSTS_N_INSNS (2); + break; + case DIV: + case UDIV: + case MOD: + case UMOD: + *total = COSTS_N_INSNS (50); + break; + case PLUS: + case MINUS: + if (GET_MODE (x) == SImode) + { + rtx exp = XEXP (x, 0); + unsigned int reg0 = REG_P (XEXP (x, 0)) ? REGNO (XEXP (x, 0)) : INVALID_REGNUM; + unsigned int reg1 = REG_P (XEXP (x, 1)) ? REGNO (XEXP (x, 1)) : INVALID_REGNUM; + + if (reg_renumber != NULL && IS_PSEUDO_REGNO (reg0)) + reg0 = reg_renumber[reg0]; + + if (reg_renumber != NULL && IS_PSEUDO_REGNO (reg1)) + reg1 = reg_renumber[reg1]; + + if (IS_HARD_OR_VIRT_REGNO (reg0) + && IS_HARD_OR_VIRT_REGNO (reg1) + && METAG_REGNO_REG_CLASS (reg0) != METAG_REGNO_REG_CLASS (reg1)) + { + /* Cannot really add/sub registers in different units */ + *total = COSTS_N_INSNS (50); + } + else if (exp != frame_pointer_rtx + && exp != stack_pointer_rtx + && exp != arg_pointer_rtx) + *total = COSTS_N_INSNS (1); + else + *total = COSTS_N_INSNS (2); + } + else + *total = COSTS_N_INSNS (4); + + break; + case COMPARE: + *total = COSTS_N_INSNS (1); + break; + case MEM: + if (outer_code == SIGN_EXTEND) + *total = COSTS_N_INSNS (2); + else + *total = COSTS_N_INSNS (1); + break; + case SIGN_EXTEND: + *total = COSTS_N_INSNS (1); + break; + default: + *total = COSTS_N_INSNS (1); + break; + } + + return false; +} + +int +metag_sched_adjust_cost (rtx insn, rtx link, + rtx dep_insn, int cost) +{ + switch (REG_NOTE_KIND (link)) + { + case REG_DEP_ANTI: + case REG_DEP_OUTPUT: + return 0; + case REG_DEP_TRUE: + if (recog_memoized (insn) >= 0 && recog_memoized (dep_insn) >= 0) + { + enum attr_type type_attr = get_attr_type (dep_insn); + enum attr_memaccess memaccess_attr = get_attr_memaccess (dep_insn); + + /* Match the twox|threex|fourx|fivex loads */ + if ((type_attr == TYPE_TWOX || type_attr == TYPE_THREEX + || type_attr == TYPE_FOURX || type_attr == TYPE_FIVEX) + && memaccess_attr == MEMACCESS_LOAD) + { + /* If the dependency is based on either of the last 2 registers + * loaded, the latency increases. */ + cost += metag_consumer_stalls_from_load_multi (dep_insn, insn); + } + + /* If there is an o2rhint then the insn may have an o2r operand which + * may stall. */ + switch (get_attr_o2rhint (insn)) + { + case O2RHINT_NONE: + break; + case O2RHINT_OP2OP1: + /* insn has an o2r operand if units of operands 2 and 1 differ. */ + if (metag_consumer_is_o2r (dep_insn, insn, 2, 1)) + return cost + 1; + + break; + case O2RHINT_OP1OP0: + /* insn has an o2r operand if units of operands 1 and 0 differ. */ + if (metag_consumer_is_o2r (dep_insn, insn, 1, 0)) + return cost + 1; + + break; + default: + /* Bad o2rhint, missing a case for the hint. */ + gcc_unreachable (); + } + + break; + } + break; + default: + break; + } + + return cost; +} + +int +metag_address_cost (rtx x) +{ + switch (GET_CODE (x)) + { + case REG: + return 0; + case LABEL_REF: + case SYMBOL_REF: + case CONST: + case MEM: + return 10; + case PRE_INC: + case POST_INC: + case PRE_DEC: + case POST_DEC: + case PRE_MODIFY: + case POST_MODIFY: + return 0; + case PLUS: + if (REG_P (XEXP (x, 0)) + && (REG_P (XEXP (x, 1)) || CONST_INT_P (XEXP (x, 1)))) + return 2; + break; + default: + break; + } + + return 6; +} + +#define add_builtin_function(NAME, TYPE, CODE, CLASS, LIBNAME, ATTR) \ + lang_hooks.builtin_function (NAME, TYPE, CODE, CLASS, LIBNAME, ATTR) + +void +metag_init_builtins(void) +{ + tree nothrow = tree_cons (get_identifier ("nothrow"), NULL, NULL); +#if 0 + tree const_throw = tree_cons (get_identifier ("const"), NULL, nothrow); +#endif + tree endlink = void_list_node; + tree ftdcache_preload + = build_function_type (ptr_type_node, + tree_cons (NULL_TREE, ptr_type_node, + endlink)); + + tree ftdcache_flush + = build_function_type (void_type_node, + tree_cons (NULL_TREE, ptr_type_node, + endlink)); + + tree ftdcache_refresh + = build_function_type (ptr_type_node, + tree_cons (NULL_TREE, ptr_type_node, + endlink)); + + tree ftmeta2_cacherd + = build_function_type (unsigned_intSI_type_node, + tree_cons (NULL_TREE, ptr_type_node, + endlink)); + + tree ftmeta2_cacherl + = build_function_type (unsigned_intDI_type_node, + tree_cons (NULL_TREE, ptr_type_node, + endlink)); + + tree ftmeta2_cachewd + = build_function_type (void_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, unsigned_intSI_type_node, + endlink))); + + tree ftmeta2_cachewl + = build_function_type (void_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, unsigned_intDI_type_node, + endlink))); + + tree ftmetag_bswap + = build_function_type (intSI_type_node, + tree_cons (NULL_TREE, intSI_type_node, + endlink)); + + tree ftmetag_bswaps + = build_function_type (intHI_type_node, + tree_cons (NULL_TREE, intHI_type_node, + endlink)); + + tree ftmetag_bswapll + = build_function_type (intDI_type_node, + tree_cons (NULL_TREE, intDI_type_node, + endlink)); + + tree ftmetag_wswap + = build_function_type (intSI_type_node, + tree_cons (NULL_TREE, intSI_type_node, + endlink)); + + tree ftmetag_wswapll + = build_function_type (intDI_type_node, + tree_cons (NULL_TREE, intDI_type_node, + endlink)); + + tree ftmetag_dswapll + = build_function_type (intDI_type_node, + tree_cons (NULL_TREE, intDI_type_node, + endlink)); + + + + add_builtin_function ("__builtin_dcache_preload", ftdcache_preload, + METAG_BUILTIN_DCACHE_PRELOAD, + BUILT_IN_MD, + NULL, nothrow); + + add_builtin_function ("__builtin_dcache_flush", ftdcache_flush, + METAG_BUILTIN_DCACHE_FLUSH, + BUILT_IN_MD, + NULL, nothrow); + + add_builtin_function ("__builtin_dcache_refresh", + ftdcache_refresh, + METAG_BUILTIN_DCACHE_REFRESH, + BUILT_IN_MD, + NULL, nothrow); + + add_builtin_function ("__builtin_meta2_cacherd", + ftmeta2_cacherd, + METAG_BUILTIN_META2_CACHERD, + BUILT_IN_MD, + NULL, nothrow); + + add_builtin_function ("__builtin_meta2_cacherl", + ftmeta2_cacherl, + METAG_BUILTIN_META2_CACHERL, + BUILT_IN_MD, + NULL, nothrow); + + add_builtin_function ("__builtin_meta2_cachewd", + ftmeta2_cachewd, + METAG_BUILTIN_META2_CACHEWD, + BUILT_IN_MD, + NULL, nothrow); + + add_builtin_function ("__builtin_meta2_cachewl", + ftmeta2_cachewl, + METAG_BUILTIN_META2_CACHEWL, + BUILT_IN_MD, + NULL, nothrow); + + add_builtin_function ("__builtin_metag_bswaps", + ftmetag_bswaps, + METAG_BUILTIN_METAG_BSWAPS, + BUILT_IN_MD, + NULL, nothrow); + + add_builtin_function ("__builtin_metag_bswap", + ftmetag_bswap, + METAG_BUILTIN_METAG_BSWAP, + BUILT_IN_MD, + NULL, nothrow); + + add_builtin_function ("__builtin_metag_bswapll", + ftmetag_bswapll, + METAG_BUILTIN_METAG_BSWAPLL, + BUILT_IN_MD, + NULL, nothrow); + + add_builtin_function ("__builtin_metag_wswap", + ftmetag_wswap, + METAG_BUILTIN_METAG_WSWAP, + BUILT_IN_MD, + NULL, nothrow); + + add_builtin_function ("__builtin_metag_wswapll", + ftmetag_wswapll, + METAG_BUILTIN_METAG_WSWAPLL, + BUILT_IN_MD, + NULL, nothrow); + + add_builtin_function ("__builtin_metag_dswapll", + ftmetag_dswapll, + METAG_BUILTIN_METAG_DSWAPLL, + BUILT_IN_MD, + NULL, nothrow); + /* Initialise the builtin functions for the operating system gcc + is targeting code for */ + metag_init_builtins_per_os (); + +} + +/* Emit the optimal byte swap sequence for a 16 bit byte swap */ + +static void +metag_emit_byte_swap16 (rtx out, rtx in) +{ + rtx tmp = gen_reg_rtx (SImode); + + emit_insn (gen_andsi3 (out, in, + gen_int_mode (0x0000FFFF, SImode))); + emit_insn (gen_lshrsi3 (tmp, out, GEN_INT (BITS_PER_UNIT))); + emit_insn (gen_ashlsi3 (out, out, GEN_INT (BITS_PER_UNIT * 3))); + emit_insn (gen_ashrsi3 (out, out, GEN_INT (BITS_PER_UNIT * 2))); + emit_insn (gen_iorsi3 (out, out, tmp)); +} + +/* Emit the optimal byte swap sequence for a 32 bit byte swap */ + +static void +metag_emit_byte_swap32 (rtx out, rtx in) +{ + rtx tmp = gen_reg_rtx (SImode); + + emit_insn (gen_rotsi2_16 (tmp, in)); + emit_insn (gen_lshrsi3 (out, tmp, GEN_INT (8))); + emit_insn (gen_andsi3 (tmp, tmp, + gen_int_mode (0xFFFF00FF, SImode))); + emit_insn (gen_andsi3 (out, out, + gen_int_mode (0xFFFF00FF, SImode))); + emit_insn (gen_ashlsi3 (tmp, tmp, GEN_INT (8))); + emit_insn (gen_iorsi3 (out, out, tmp)); +} + +/* Expand an expression EXP that calls a built-in function, + with result going to TARGET if that's convenient + (and in mode MODE if that's convenient). + SUBTARGET may be used as the target for computing one of EXP's operands. + IGNORE is nonzero if the value is to be ignored. */ + +rtx +metag_expand_builtin (tree exp, rtx target ATTRIBUTE_UNUSED, + rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); + tree arglist = TREE_OPERAND (exp, 1); + int fcode = DECL_FUNCTION_CODE (fndecl); + + switch (fcode) + { + case METAG_BUILTIN_DCACHE_PRELOAD: /* void * __builtin_dcache_preload (void *) */ + if ( TARGET_BUILTINS_METAC_1_1 + || TARGET_BUILTINS_METAC_1_2 + || TARGET_BUILTINS_METAC_2_1) + { + tree arg0 = TREE_VALUE (arglist); + rtx op0 = expand_normal (arg0); + enum machine_mode mode0 = insn_data[CODE_FOR_dcache_preload].operand[0].mode; + rtx pat; + + if (! (*insn_data[CODE_FOR_dcache_preload].operand[0].predicate)(op0, mode0)) + op0 = copy_to_mode_reg (mode0, op0); + + pat = GEN_FCN (CODE_FOR_dcache_preload)(op0); + + if (!pat) + return NULL_RTX; + emit_insn (pat); + return op0; + } + else + error ("__builtin_dcache_preload not supported for metac %s", metag_cpu_string); + break; + case METAG_BUILTIN_DCACHE_FLUSH: /* void __builtin_dcache_flush (void *) */ + if ( TARGET_BUILTINS_METAC_1_2 + || TARGET_BUILTINS_METAC_2_1) + { + tree arg0 = TREE_VALUE (arglist); + rtx op0 = expand_normal (arg0); + rtx op1; + enum machine_mode mode0 = insn_data[CODE_FOR_dcache_flush].operand[0].mode; + enum machine_mode mode1 = insn_data[CODE_FOR_dcache_flush].operand[1].mode; + rtx pat; + + if (! (*insn_data[CODE_FOR_dcache_flush].operand[0].predicate)(op0, mode0)) + op0 = copy_to_mode_reg (mode0, op0); + + op1 = gen_reg_rtx (mode1); + + pat = GEN_FCN (CODE_FOR_dcache_flush)(op0, op1); + + if (!pat) + return NULL_RTX; + + emit_move_insn (op1, const0_rtx); + emit_insn (pat); + return const1_rtx; + } + else + error ("__builtin_dcache_flush not supported for metac %s", metag_cpu_string); + break; + case METAG_BUILTIN_DCACHE_REFRESH: /* void * __builtin_dcache_refresh (void *) */ + if ( TARGET_BUILTINS_METAC_1_1 + || TARGET_BUILTINS_METAC_1_2 + || TARGET_BUILTINS_METAC_2_1) + { + tree arg0 = TREE_VALUE (arglist); + rtx op0 = expand_normal (arg0); + rtx op1; + enum machine_mode mode0 = insn_data[CODE_FOR_dcache_refresh].operand[0].mode; + enum machine_mode mode1 = insn_data[CODE_FOR_dcache_refresh].operand[1].mode; + rtx pat; + + if (! (*insn_data[CODE_FOR_dcache_refresh].operand[0].predicate)(op0, mode0)) + op0 = copy_to_mode_reg (mode0, op0); + + op1 = gen_reg_rtx (mode1); + + pat = GEN_FCN (CODE_FOR_dcache_refresh)(op0, op1); + + if (!pat) + return NULL_RTX; + + emit_move_insn (op1, const0_rtx); + emit_insn (pat); + return op0; + } + else + error ("__builtin_dcache_refresh not supported for metac %s", metag_cpu_string); + break; + case METAG_BUILTIN_META2_CACHERD: /* unsigned long __builtin_meta2_cacherd (void *) */ + case METAG_BUILTIN_META2_CACHERL: /* unsigned long long __builtin_meta2_cacherl (void *) */ + if (TARGET_BUILTINS_METAC_2_1) + { + tree arg0 = TREE_VALUE (arglist); + rtx op1 = expand_normal (arg0); + enum machine_mode tgtmode; + enum machine_mode mode1; + enum insn_code icode = CODE_FOR_meta2_cacherd; + rtx pat; + + if (fcode == METAG_BUILTIN_META2_CACHERL) + icode = CODE_FOR_meta2_cacherl; + + tgtmode = insn_data[icode].operand[0].mode; + mode1 = insn_data[icode].operand[1].mode; + + if (target == 0 || !insn_data[icode].operand[0].predicate (target, tgtmode)) + target = gen_reg_rtx (tgtmode); + + if (! (*insn_data[icode].operand[1].predicate)(op1, mode1)) + op1 = copy_to_mode_reg (mode1, op1); + + pat = GEN_FCN (icode)(target, op1); + + if (!pat) + return NULL_RTX; + + emit_insn (pat); + return target; + } + else + error ("__builtin_meta2_cacher[dl] not supported for metac %s", metag_cpu_string); + break; + case METAG_BUILTIN_META2_CACHEWD: /* void __builtin_meta2_cachewd (void *, unsigned lon) */ + case METAG_BUILTIN_META2_CACHEWL: /* void __builtin_meta2_cachewl (void *, unsigned long long) */ + if (TARGET_BUILTINS_METAC_2_1) + { + tree arg0 = TREE_VALUE (arglist); + tree arg1 = TREE_VALUE (TREE_CHAIN (arglist)); + rtx op0 = expand_normal (arg0); + rtx op1 = expand_normal (arg1); + + enum machine_mode mode0; + enum machine_mode mode1; + enum insn_code icode = CODE_FOR_meta2_cachewd; + rtx pat; + + if (fcode == METAG_BUILTIN_META2_CACHEWL) + icode = CODE_FOR_meta2_cachewl; + + mode0 = insn_data[icode].operand[0].mode; + mode1 = insn_data[icode].operand[1].mode; + + if (! (*insn_data[icode].operand[0].predicate)(op0, mode0)) + op0 = copy_to_mode_reg (mode0, op0); + + if (! (*insn_data[icode].operand[1].predicate)(op1, mode1)) + op1 = copy_to_mode_reg (mode1, op1); + + pat = GEN_FCN (icode)(op0, op1); + + if (!pat) + return NULL_RTX; + + emit_insn (pat); + return const1_rtx; + } + else + error ("__builtin_meta2_cachew[dl] not supported for metac %s (or extension disabled)", metag_cpu_string); + break; + case METAG_BUILTIN_METAG_BSWAPS: /* short __builtin_metag_bswaps (short) */ + case METAG_BUILTIN_METAG_BSWAP: /* int __builtin_metag_bswap (int) */ + case METAG_BUILTIN_METAG_BSWAPLL: /* long long __builtin_metag_bswap (long long) */ + if (!TARGET_BUILTINS_METAC_2_1 && metag_meta2_bex_enabled) + error ("The 'bex' extension is only available on a META 2.1 core"); + else + { + tree arg0 = TREE_VALUE (arglist); + rtx op1 = expand_normal (arg0); + + enum machine_mode mode; + + if (fcode == METAG_BUILTIN_METAG_BSWAPS) + /* This looks like it should be HImode, but type promotion on the arguments causes + shorts to become ints so SImode actually needs to be used */ + mode = SImode; + else if (fcode == METAG_BUILTIN_METAG_BSWAP) + mode = SImode; + else + mode = DImode; + + if (target == 0 || !metag_register_op (target, mode)) + target = gen_reg_rtx (mode); + + if (!metag_register_op (op1, mode)) + op1 = copy_to_mode_reg (mode, op1); + + if (metag_meta2_bex_enabled) + { + if (fcode == METAG_BUILTIN_METAG_BSWAPS) + { + emit_insn (gen_metag_bswap (target, op1)); + emit_insn (gen_ashrsi3 (target, target, GEN_INT ((UNITS_PER_WORD / 2) * BITS_PER_UNIT))); + } + else if (fcode == METAG_BUILTIN_METAG_BSWAP) + emit_insn (gen_metag_bswap (target, op1)); + else + emit_insn (gen_metag_bswapll (target, op1)); + } + else + { + /* Generate the optimal byte swap sequence */ + if (fcode == METAG_BUILTIN_METAG_BSWAPS) + metag_emit_byte_swap16 (target, op1); + else if (fcode == METAG_BUILTIN_METAG_BSWAP) + metag_emit_byte_swap32 (target, op1); + else + { + rtx target_lo = gen_rtx_SUBREG (SImode, target, 0); + rtx target_hi = gen_rtx_SUBREG (SImode, target, 4); + rtx op1_lo = gen_rtx_SUBREG (SImode, op1, 0); + rtx op1_hi = gen_rtx_SUBREG (SImode, op1, 4); + + metag_emit_byte_swap32 (target_lo, op1_hi); + metag_emit_byte_swap32 (target_hi, op1_lo); + } + } + + return target; + } + break; + case METAG_BUILTIN_METAG_WSWAP: /* int __builtin_metag_wswap (int) */ + case METAG_BUILTIN_METAG_WSWAPLL: /* long long __builtin_metag_wswapll (long long) */ + case METAG_BUILTIN_METAG_DSWAPLL: /* long long __builtin_metag_dswapll (long long) */ + { + + tree arg0 = TREE_VALUE (arglist); + rtx op1 = expand_normal (arg0); + + enum machine_mode mode; + + if (fcode == METAG_BUILTIN_METAG_WSWAP) + mode = SImode; + else + mode = DImode; + + if (target == 0 || !metag_register_op (target, mode)) + target = gen_reg_rtx (mode); + + if (!metag_register_op (op1, mode)) + op1 = copy_to_mode_reg (mode, op1); + + if (fcode == METAG_BUILTIN_METAG_WSWAP) + { + emit_insn (gen_rotsi2_16 (target, op1)); + } + else if (fcode == METAG_BUILTIN_METAG_WSWAPLL) + { + rtx target_lo = gen_rtx_SUBREG (SImode, target, 0); + rtx target_hi = gen_rtx_SUBREG (SImode, target, 4); + if (TARGET_DSP) + { + emit_insn (gen_parallel_rotsi2_16 (target, op1)); + emit_insn (gen_swapsi (target_hi, target_lo)); + } + else + { + rtx op1_lo = gen_rtx_SUBREG (SImode, op1, 0); + rtx op1_hi = gen_rtx_SUBREG (SImode, op1, 4); + emit_insn (gen_rotsi2_16 (target_lo, op1_lo)); + emit_insn (gen_rotsi2_16 (target_hi, op1_hi)); + emit_insn (gen_swapsi (target_hi, target_lo)); + } + } + else if (fcode == METAG_BUILTIN_METAG_DSWAPLL) + { + rtx target_lo = gen_rtx_SUBREG (SImode, target, 0); + rtx target_hi = gen_rtx_SUBREG (SImode, target, 4); + emit_insn (gen_movdi (target, op1)); + emit_insn (gen_swapsi (target_hi, target_lo)); + } + return target; + } + break; + default: + break; + } + + /* Expand any operating system specific builtin functions */ + return metag_expand_builtin_per_os (exp, target); +} + +static tree +metag_handle_model_decl_attribute (tree *node ATTRIBUTE_UNUSED, + tree name ATTRIBUTE_UNUSED, + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, + bool *no_add_attrs ATTRIBUTE_UNUSED) +{ + tree value = TREE_VALUE (args); + + if (strcmp (IDENTIFIER_POINTER (name), "model") == 0) + { + if (TREE_CODE (value) != STRING_CST) + { + warning (OPT_Wattributes, + "argument of %qs attribute is not a string constant", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + else if ( strcmp (TREE_STRING_POINTER (value), "small") != 0 + && strcmp (TREE_STRING_POINTER (value), "large") != 0) + { + warning (OPT_Wattributes, + "argument %qs of %qs is not \"small\" or \"large\"", + TREE_STRING_POINTER (value), IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + } + + return NULL_TREE; +} + +tree +metag_merge_decl_attributes (tree decl1, tree decl2) +{ + return merge_decl_attributes (decl1, decl2); +} + +tree +metag_merge_type_attributes (tree type1, tree type2) +{ + return merge_type_attributes (type1, type2); +} + +int +metag_comp_type_attributes (tree type1, tree type2) +{ + tree m1 = lookup_attribute ("model", TYPE_ATTRIBUTES (type1)); + tree m2 = lookup_attribute ("model", TYPE_ATTRIBUTES (type2)); + + if (m1 != NULL_TREE) + m1 = TREE_VALUE (m1); + + if (m2 != NULL_TREE) + m2 = TREE_VALUE (m2); + + if (m1 && m2 && TREE_CODE (m1) == STRING_CST && TREE_CODE (m2) == STRING_CST) + return strcmp (TREE_STRING_POINTER (m1), TREE_STRING_POINTER (m2)) == 0 ? 1 : 0; + + return 1; +} + +int +metag_letter_for_const (rtx value) +{ + if (satisfies_constraint_L (value)) + return 'L'; + else if (satisfies_constraint_P (value)) + return 'P'; + else if (satisfies_constraint_K (value)) + return 'K'; + else if (satisfies_constraint_I (value)) + return 'I'; + else if (satisfies_constraint_J (value)) + return 'J'; + else if (satisfies_constraint_M (value)) + return 'M'; + else if (satisfies_constraint_N (value)) + return 'N'; + else + return 0; +} + +bool +metag_const_ok_for_letters_p (rtx value, const char letters[]) +{ + char c; + + while ((c = *letters++) != '\0') + { + switch (c) + { + case 'L': + if (satisfies_constraint_L (value)) + return true; + break; + case 'P': + if (satisfies_constraint_P (value)) + return true; + break; + case 'K': + if (satisfies_constraint_K (value)) + return true; + break; + case 'I': + if (satisfies_constraint_I (value)) + return true; + break; + case 'J': + if (satisfies_constraint_J (value)) + return true; + break; + case 'M': + if (satisfies_constraint_M (value)) + return true; + break; + case 'N': + if (satisfies_constraint_N (value)) + return true; + break; + case 'O': + switch (*letters) + { + case '0': + letters++; + if (satisfies_constraint_O0 (value)) + return true; + break; + case '1': + letters++; + if (satisfies_constraint_O1 (value)) + return true; + break; + case '2': + letters++; + if (satisfies_constraint_O2 (value)) + return true; + break; + case '3': + letters++; + if (satisfies_constraint_O3 (value)) + return true; + break; + case '4': + letters++; + if (satisfies_constraint_O4 (value)) + return true; + break; + case '5': + gcc_unreachable (); + break; + case '6': + gcc_unreachable (); + break; + case '7': + gcc_unreachable (); + break; + case '8': + letters++; + if (satisfies_constraint_O8 (value)) + return true; + break; + case '9': + gcc_unreachable (); + break; + default: + break; + } + break; + default: + gcc_unreachable (); + } + } + + return false; +} + +void +metag_machine_dependent_reorg (void) +{ + return; +} + +void +metag_setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode ATTRIBUTE_UNUSED, + tree type, int *pretend_size, + int no_rtl ATTRIBUTE_UNUSED) +{ + int narg = ROUND_ADVANCE_CUM (cum->narg, mode, type); + + cfun->machine->anonymous_args = true; + + if (narg < MAX_METAG_PARM_BYTES) + { + *pretend_size = MAX_METAG_PARM_BYTES - narg; + cfun->machine->anonymous_args_size = *pretend_size; + } +} + +bool +metag_function_ok_for_sibcall (tree fndecl, tree exp) +{ + return (current_function_outgoing_args_size == 0 + && !current_function_calls_alloca + && !current_function_stdarg + && current_function_pretend_args_size == 0 + && (fndecl == NULL_TREE || metag_function_ok_for_sibcall_per_os (fndecl, exp))); +} + +#define PARM_BYTE_BOUNDARY (PARM_BOUNDARY / BITS_PER_UNIT) + +tree +metag_gimplify_va_arg_expr (tree valist, tree type, + tree *pre_p ATTRIBUTE_UNUSED, + tree *post_p ATTRIBUTE_UNUSED) +{ + tree ptr; + tree valist_type = TREE_TYPE (valist); + tree t; + int size; + bool indirect = pass_by_reference (NULL, TYPE_MODE (type), type, false); + HOST_WIDE_INT boundary; + + if (indirect) + type = build_pointer_type (type); + + ptr = build_pointer_type (type); + + boundary = FUNCTION_ARG_BOUNDARY (TYPE_MODE (type), type); + + if (boundary < (int)TYPE_ALIGN (type)) + { + type = build_variant_type_copy (type); + TYPE_ALIGN (type) = boundary; + } + + size = int_size_in_bytes (type); + + boundary /= BITS_PER_UNIT; + if (boundary > PARM_BYTE_BOUNDARY && size > 0) + { + tree u; + + u = fold_convert (valist_type, size_int (size)); + t = build2 (MINUS_EXPR, valist_type, valist, u); + + u = fold_convert (valist_type, size_int (-boundary)); + t = build2 (BIT_AND_EXPR, valist_type, t, u); + } + else if (boundary == PARM_BYTE_BOUNDARY && size > 0) + { + tree u; + + u = fold_convert (valist_type, size_int (PARM_BYTE_BOUNDARY)); + t = build2 (MINUS_EXPR, valist_type, valist, u); + } + else if (boundary == PARM_BYTE_BOUNDARY && size == 0) + t = valist; + else + gcc_unreachable (); + + t = build2 (MODIFY_EXPR, valist_type, valist, t); + + t = fold_convert (ptr, t); + + if (indirect) + t = build_va_arg_indirect_ref (t); + + return build_va_arg_indirect_ref (t); +} + +#undef PARM_BYTE_BOUNDARY + +/* True if MODE is valid for the target. By "valid", we mean able to + be manipulated in non-trivial ways. In particular, this means all + the arithmetic is supported. + + Currently, TImode is not valid + Thus, we return false when PRECISION is 2 * BITS_PER_WORD and + 2 * BITS_PER_WORD isn't equal LONG_LONG_TYPE_SIZE. +*/ + +bool +metag_scalar_mode_supported_p (enum machine_mode mode) +{ + int precision = GET_MODE_PRECISION (mode); + + switch (GET_MODE_CLASS (mode)) + { + case MODE_PARTIAL_INT: + case MODE_INT: + if (precision == CHAR_TYPE_SIZE) + return true; + if (precision == SHORT_TYPE_SIZE) + return true; + if (precision == INT_TYPE_SIZE) + return true; + if (precision == LONG_TYPE_SIZE) + return true; + if (precision == LONG_LONG_TYPE_SIZE) + return true; + return false; + + case MODE_FLOAT: + if (precision == FLOAT_TYPE_SIZE) + return true; + if (precision == DOUBLE_TYPE_SIZE) + return true; + if (precision == LONG_DOUBLE_TYPE_SIZE) + return true; + return false; + + case MODE_DECIMAL_FLOAT: + return false; + + default: + gcc_unreachable (); + } +} + +enum reg_class +metag_secondary_reload (bool in_p, rtx x, enum reg_class class, + enum machine_mode mode, secondary_reload_info *sri) +{ + return default_secondary_reload (in_p, x, class, mode, sri); +} + +enum reg_class +metag_secondary_reload_class (enum reg_class class, enum machine_mode mode, rtx x, bool in_p) +{ + if (in_p) + { + if (reg_class_subset_p (FPC_REGS, class)) + { + switch (GET_CODE (x)) + { + case SYMBOL_REF: + case CONST_INT: + case CONST: + return GENERAL_REGS; + + case SUBREG: + if (metag_fpu_resources) + { + x = SUBREG_REG (x); + + if (!metag_hard_genreg_op (x, VOIDmode)) + return D_REGS; + } + + break; + + /* We can only reload from memory if it's 32 or 64 bit */ + /* 12bit offsets are not supported for FX registers either */ + case MEM: + if (mode != SImode && mode != DImode + && GET_MODE_CLASS (mode) != MODE_FLOAT) + return D_REGS; + + if (GET_CODE (XEXP (x, 0)) == PLUS + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT) + { + HOST_WIDE_INT offset = INTVAL (XEXP (XEXP (x, 0), 1)); + + if (offset / GET_MODE_SIZE (mode) >= 32 + || offset / GET_MODE_SIZE (mode) < -32) + return D_REGS; + } + + if (metag_fpu_resources && SYMBOL_REF_P (XEXP (x, 0))) + return D_REGS; + + /* With only single precision hard-float we must not reload + direct to FX registers for DFmode values*/ + if (metag_fpu_resources && metag_fpu_single && mode == DFmode) + return D_REGS; + + break; + + /* We can reload const_double to FX but only if it's a half precision, + * otherwise we must use GENERAL_REGS + */ + case CONST_DOUBLE: + if (metag_fpu_resources + && (GET_MODE_CLASS (mode) != MODE_FLOAT + || !metag_fphalf_imm_op (x, mode) + || (metag_fpu_single + && mode == DFmode))) + return D_REGS; + + break; + + /* Theres no connection from A0/A1 to/from FX */ + case REG: + if (metag_fpu_resources && METAG_ADDR_REG_P (true_regnum (x))) + return D_REGS; + + break; + + case PLUS: + if (metag_fpu_resources && GET_MODE_CLASS (mode) != MODE_FLOAT) + return DA_REGS; + + break; + + default: + break; + } + } + else if (reg_class_subset_p (A0_REGS, class) + || reg_class_subset_p (A1_REGS, class)) + { + /* We have some restrictions on copying to A0/A1 with respect + * to floating point + */ + switch (GET_CODE (x)) + { + /* Theres no connection from A0/A1 to/from FX */ + case REG: + if (metag_fpu_resources && METAG_FPC_REG_P (true_regnum (x))) + return D_REGS; + + break; + + default: + break; + } + } + } + else + { + if (reg_class_subset_p (FPC_REGS, class)) + { + switch (GET_CODE (x)) + { + /* Theres no connection from A0/A1 to/from FX */ + case REG: + if (metag_fpu_resources && METAG_ADDR_REG_P (true_regnum (x))) + return D_REGS; + + break; + + case SUBREG: + if (metag_fpu_resources) + { + x = SUBREG_REG (x); + + if (!metag_hard_genreg_op (x, VOIDmode)) + return D_REGS; + } + + break; + + /* We can only reload to memory if it's 32 or 64 bit */ + /* 12bit offsets are not supported for FX registers either */ + case MEM: + if (mode != SImode && mode != DImode + && GET_MODE_CLASS (mode) != MODE_FLOAT) + return D_REGS; + + if (GET_CODE (XEXP (x, 0)) == PLUS + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT) + { + HOST_WIDE_INT offset = INTVAL (XEXP (XEXP (x, 0), 1)); + + if (offset / GET_MODE_SIZE (mode) >= 32 + || offset / GET_MODE_SIZE (mode) < -32) + return D_REGS; + } + + if (metag_fpu_resources && SYMBOL_REF_P (XEXP (x, 0))) + return D_REGS; + + /* With only single precision hard-float we must not reload + direct to FX registers for DFmode values*/ + if (metag_fpu_resources && metag_fpu_single && mode == DFmode) + return D_REGS; + + break; + + case PLUS: + if (metag_fpu_resources && GET_MODE_CLASS (mode) != MODE_FLOAT) + return DA_REGS; + + break; + + default: + break; + } + } + else if (reg_class_subset_p (A0_REGS, class) + || reg_class_subset_p (A1_REGS, class)) + { + /* We have some restrictions on copying to A0/A1 with respect + * to floating point + */ + switch (GET_CODE (x)) + { + /* Theres no connection from A0/A1 to/from FX */ + case REG: + if (metag_fpu_resources && METAG_FPC_REG_P (true_regnum (x))) + return D_REGS; + + break; + + default: + break; + } + } + + if (MEM_P (x)) + { + rtx addr = XEXP (x, 0); + + switch (GET_CODE (addr)) + { + case PRE_MODIFY: + case POST_MODIFY: + addr = XEXP (addr, 0); + break; + default: + break; + } + + if (GET_CODE (addr) == PLUS) + { + rtx op0 = XEXP (addr, 0); + rtx op1 = XEXP (addr, 1); + + if (REG_P (op0) && REG_P (op1)) + { + int regno = true_regnum (op0); + + switch (METAG_REGNO_REG_CLASS (regno)) + { + case A0_REGS: + if (reg_class_subset_p (A0_REGS, class)) + { + switch (mode) + { + case QImode: + case HImode: + case SImode: + case SFmode: + return nA0_REGS; + case V2SFmode: + return FPC_REGS; + default: + break; + } + + return D_REGS; + } + break; + case A1_REGS: + if (reg_class_subset_p (A1_REGS, class)) + { + switch (mode) + { + case QImode: + case HImode: + case SImode: + case SFmode: + return nA1_REGS; + case V2SFmode: + return FPC_REGS; + default: + break; + } + + return D_REGS; + } + break; + case D0_REGS: + if (reg_class_subset_p (D0_REGS, class)) + { + switch (mode) + { + case QImode: + case HImode: + case SImode: + case SFmode: + return nD0_REGS; + case V2SFmode: + return FPC_REGS; + default: + break; + } + + return A_REGS; + } + break; + case D1_REGS: + if (reg_class_subset_p (D1_REGS, class)) + { + switch (mode) + { + case QImode: + case HImode: + case SImode: + case SFmode: + return nD1_REGS; + case V2SFmode: + return FPC_REGS; + default: + break; + } + + return A_REGS; + } + break; + default: + break; + } + } + } + } + } + + return NO_REGS; +} + +/* Output code to add DELTA to the first argument, and then jump + to FUNCTION. Used for C++ multiple inheritance. */ + +void +metag_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED, + HOST_WIDE_INT delta, + HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED, + tree function) +{ + unsigned int this_regno = MAX_METAG_PARM_REGNUM; /* "this" */ + + /* This 1st argument is "this" unless thunk returns the result in memory, + in which case there is a hidden 1st argument we contains a pointer to + where the result should be stored. */ + if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)) + this_regno--; + + /* Add delta to "this" */ + if (satisfies_constraint_I (GEN_INT (delta))) + asm_fprintf (file, "\tADD\t%r, %r, #%wd\n", this_regno, this_regno, delta); + else if (satisfies_constraint_I (GEN_INT (-delta))) + asm_fprintf (file, "\tSUB\t%r, %r, #%wd\n", this_regno, this_regno, -delta); + else if (satisfies_constraint_K (GEN_INT (delta))) + asm_fprintf (file, "\tADD\t%r, %r, #%wd\n", this_regno, this_regno, delta); + else if (satisfies_constraint_K (GEN_INT (-delta))) + asm_fprintf (file, "\tSUB\t%r, %r, #%wd\n", this_regno, this_regno, -delta); + else if ((delta & 0x0000FFFF) == 0) + asm_fprintf (file, "\tADDT\t%r, %r, #HI(%wd)\n", this_regno, this_regno, delta); + else if (((-delta) & 0x0000FFFF) == 0) + asm_fprintf (file, "\tSUBT\t%r, %r, #HI(%wd)\n", this_regno, this_regno, -delta); + else if ((delta & 0xFFFF0000) == 0) + asm_fprintf (file, "\tADD\t%r, %r, #LO(%wd)\n", this_regno, this_regno, delta); + else if (((-delta) & 0xFFFF0000) == 0) + asm_fprintf (file, "\tSUB\t%r, %r, #LO(%wd)\n", this_regno, this_regno, -delta); + else + { + asm_fprintf (file, "\tADDT\t%r, %r, #HI(%wd)\n", this_regno, this_regno, delta); + asm_fprintf (file, "\tADD\t%r, %r, #LO(%wd)\n", this_regno, this_regno, delta); + } + + /* If needed, add *(*THIS + VCALL_OFFSET) to THIS. */ + if (vcall_offset != 0) + { + unsigned int temp1 = D0_0_REG; + unsigned int temp2 = D1_0_REG; + + /* Set TEMP1 to *THIS. */ + asm_fprintf (file, "\tGETD\t%r, [%r]\n", temp1, this_regno); + + /* Load the offset from (TEMP1 + VCALL_OFFSET) in TEMP2 ... */ + if (-128 <= vcall_offset && vcall_offset <= 124) + asm_fprintf (file, "\tGETD\t%r, [%r+#(%wd)]\n", temp2, temp1, vcall_offset); + else + { + if (satisfies_constraint_I (GEN_INT (vcall_offset))) + asm_fprintf (file, "\tADD\t%r, %r, #%wd\n", temp1, temp1, vcall_offset); + else if (satisfies_constraint_I (GEN_INT (-vcall_offset))) + asm_fprintf (file, "\tSUB\t%r, %r, #%wd\n", temp1, temp1, -vcall_offset); + else if (satisfies_constraint_K (GEN_INT (vcall_offset))) + asm_fprintf (file, "\tADD\t%r, %r, #%wd\n", temp1, temp1, vcall_offset); + else if (satisfies_constraint_K (GEN_INT (-vcall_offset))) + asm_fprintf (file, "\tSUB\t%r, %r, #%wd\n", temp1, temp1, -vcall_offset); + else if ((vcall_offset & 0x0000FFFF) == 0) + asm_fprintf (file, "\tADDT\t%r, %r, #HI(%wd)\n", temp1, temp1, vcall_offset); + else if (((-vcall_offset) & 0x0000FFFF) == 0) + asm_fprintf (file, "\tSUBT\t%r, %r, #HI(%wd)\n", temp1, temp1, -vcall_offset); + else if ((vcall_offset & 0xFFFF0000) == 0) + asm_fprintf (file, "\tADD\t%r, %r, #LO(%wd)\n", temp1, temp1, vcall_offset); + else if (((-vcall_offset) & 0xFFFF0000) == 0) + asm_fprintf (file, "\tSUB\t%r, %r, #LO(%wd)\n", temp1, temp1, -vcall_offset); + else + { + asm_fprintf (file, "\tADDT\t%r, %r, #HI(%wd)\n", temp1, temp1, vcall_offset); + asm_fprintf (file, "\tADD\t%r, %r, #LO(%wd)\n", temp1, temp1, vcall_offset); + } + + asm_fprintf (file, "\tGETD\t%r, [%r]\n", temp2, temp1); + } + + /* ... and add it to THIS. */ + asm_fprintf (file, "\tADD\t%r, %r, %r\n", this_regno, this_regno, temp2); + } + + fputs ("\tB\t", file); + { + rtx symbol = XEXP (DECL_RTL (function), 0); + + gcc_assert (SYMBOL_REF_P (symbol)); + + assemble_name (file, XSTR (symbol, 0)); + if (METAG_FLAG_PIC && !SYMBOL_REF_LOCAL_P (symbol)) + fputs ("@PLT", file); + } + fputc ('\n', file); +} + +bool +metag_can_output_mi_thunk (tree thunk_decl ATTRIBUTE_UNUSED, + HOST_WIDE_INT delta ATTRIBUTE_UNUSED, + HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED, + tree function_decl ATTRIBUTE_UNUSED) +{ + return true; +} + +bool +metag_handle_option (size_t code, const char *arg, int value) +{ + switch (code) + { + case OPT_mhard_float: + { + int length = strlen(arg); + + metag_fpureg_string = "16"; + metag_fpu_resources = 1; + + /* Turn off SIMD float whenever we see a hardfloat option */ + target_flags &= ~MASK_FPU_SIMD; + + if (length == 0) + metag_fpu_single = 0; + else if (length == 2 && arg[0] == '=') + if (arg[1] == 'S') + metag_fpu_single = 1; + else if (arg[1] == 'D') + metag_fpu_single = 0; + else + error("-mhard-float takes an optional argument of S or D. E.g. -mhard-float=S"); + /* If set to none then just use soft float */ + else if (length == 5 && strncmp ("none", &arg[1], 4) == 0) + { + metag_fpu_resources = 0; + metag_fpureg_string = ""; + target_flags &= ~MASK_FPU; + } + else + error("-mhard-float takes an optional argument of S or D. E.g. -mhard-float=S"); + } + break; + + case OPT_msoft_float: + target_flags &= ~MASK_FPU_SIMD; + break; + + case OPT_mdsp: + if (value) + metag_extreg_string = "8844"; + else + metag_extreg_string = "0000"; + break; + + case OPT_mwidth_: + { + metag_memory_width = strtol (metag_width_string, NULL, 10); + if (metag_memory_width != 32 + && metag_memory_width != 64) + error ("Invalid memory width specified. Permitted widths are 32 or 64."); + } + break; + + case OPT_mjump_table_branch_: + { + if (strncmp (metag_jump_table_string, "short", 5) == 0) + metag_jump_table_branch = METAG_MINIM_JUMP_TABLE_BRANCH_SHORT; + else if (strncmp (metag_jump_table_string, "long", 4) == 0) + metag_jump_table_branch = METAG_MINIM_JUMP_TABLE_BRANCH_LONG; + else if (strncmp (metag_jump_table_string, "auto", 4) == 0) + metag_jump_table_branch = METAG_MINIM_JUMP_TABLE_BRANCH_AUTO; + else + error ("-mjump-table-branch must be either 'long', 'short' or 'auto'"); + } + break; + + case OPT_mcond_exec: + return true; + + case OPT_mextensions_: + { + char* extension = (char*)metag_extensions_string; + int extension_length = 0; + unsigned int i; + char* comma_position; + + for (i = 0 ; i < strlen(extension) ; i++) + extension[i] = tolower (extension[i]); + + while (strlen(extension) != 0) + { + comma_position = strchr (metag_extensions_string, ','); + + if (comma_position == NULL) + extension_length = strlen (extension); + else + extension_length = (comma_position-extension); + + if (strncmp (extension, "bex", (extension_length > 3) ? extension_length : 3) == 0) + metag_meta2_bex_enabled = true; + else /* Print the rest of the list in the warning */ + warning (0, "Instruction set extension not known in list: %s", extension); + + extension += extension_length; + } + } + break; + + case OPT_mtbictxsave: + metag_force_tbictxsave = value; + break; + + case OPT_mhwtrace: + if (!value) + { + target_flags &= ~MASK_HWTRACE_RETPC; + target_flags &= ~MASK_HWTRACE_LEAF; + } + break; + + case OPT_mhwtrace_retpc: + case OPT_mhwtrace_leaf: + if (value) + target_flags |= MASK_HWTRACE; + break; + + default: + break; + } + + return metag_handle_option_per_os (code, arg, value); +} + +bool +metag_zeroextract_mask_p (rtx op0, rtx op1) +{ + rtx value = GEN_INT (((1 << INTVAL (op0)) - 1) << INTVAL (op1)); + + return satisfies_constraint_I (value) || + satisfies_constraint_P (value) || + satisfies_constraint_K (value) || + satisfies_constraint_J (value) || + satisfies_constraint_M (value) || + satisfies_constraint_N (value); +} + +rtx +metag_return_addr_rtx (int count, rtx frame ATTRIBUTE_UNUSED) +{ + if (count != 0) + return NULL_RTX; + + return get_hard_reg_initial_val (Pmode, RETURN_POINTER_REGNUM); +} + +HOST_WIDE_INT +metag_function_arg_boundary (enum machine_mode mode, tree type) +{ + HOST_WIDE_INT size; + + if (type != NULL_TREE) + size = int_size_in_bytes (type); + else + size = GET_MODE_BITSIZE (mode); + + if (size < 0) + return BIGGEST_ALIGNMENT; + else if (size > UNITS_PER_WORD) + return BIGGEST_ALIGNMENT; + else + return PARM_BOUNDARY; +} + +int +metag_first_parm_offset (tree fndecl ATTRIBUTE_UNUSED) +{ + if (cfun->machine->anonymous_args) + return current_function_pretend_args_size + - ALIGN_ON_STACK_BOUNDARY (current_function_pretend_args_size); + + return 0; +} + +/* WORK NEEDED: Check that the condition for consumer is not always or never */ + +bool +metag_consumer_is_cond_p (rtx producer, rtx consumer) +{ + return (GET_CODE (PATTERN (consumer)) == COND_EXEC) + && (get_attr_ccstate (producer) == CCSTATE_SET); +} + +bool +metag_bypass_before_reload_p (rtx producer ATTRIBUTE_UNUSED, rtx consumer ATTRIBUTE_UNUSED) +{ + return !reload_in_progress && !reload_completed; +} + +int +metag_consumer_stalls_from_load_multi (rtx producer, rtx consumer) +{ + int opno; + bool firstoperand = true; + unsigned int penultimate_reg = INVALID_REGNUM; + unsigned int last_reg = INVALID_REGNUM; + int stalls = 0; /* Zero stalls to begin with */ + + /* Extract the insn to iterate over the output operands */ + extract_insn (producer); + + for (opno = 0 ; opno < recog_data.n_operands ; opno++) + { + if (recog_data.operand_type[opno] == OP_OUT) + { + rtx op; + + /* Ignore the first output as it refers to the offset addition */ + if (firstoperand) + { + firstoperand = false; + continue; + } + + /* Find the output register number*/ + op = recog_data.operand[opno]; + if (SUBREG_P (op)) + op = SUBREG_REG (op); + + if (REG_P (op)) + { + unsigned int regno = REGNO (op); + + if (IS_HARD_OR_VIRT_REGNO (regno)) + { + /* Save the two highest numbered load destination register numbers. */ + if (last_reg == INVALID_REGNUM || regno > last_reg) + { + penultimate_reg = last_reg; + last_reg = regno; + } + else if (penultimate_reg == INVALID_REGNUM || regno > penultimate_reg) + penultimate_reg = regno; + } + } + } + } + + /* Both penultimate_reg and last_reg should have values now, if not there + * is a big problem. */ + gcc_assert (penultimate_reg != INVALID_REGNUM && last_reg != INVALID_REGNUM); + + /* Extract the consumer to examine its operands. */ + extract_insn (consumer); + + /* If the consumer is an MSET it has to be handled differently... */ + if (store_multiop (PATTERN (consumer), VOIDmode)) + { + unsigned int first_reg = INVALID_REGNUM; + unsigned int second_reg = INVALID_REGNUM; + + /* For MSET instructions stalls only occur if: + * 1) The penultimate load collides with the initial store + * 2) The last load collides with the initial store + * 3) The last load collides with the 2nd store + */ + firstoperand = true; + for (opno = 0 ; opno < recog_data.n_operands ; opno++) + { + if (recog_data.operand_type[opno] == OP_IN) + { + rtx op; + + /* Ignore the first input as it refers to the offset + * addition. */ + if (firstoperand) + { + firstoperand = false; + continue; + } + + /* Find the input register number. */ + op = recog_data.operand[opno]; + if (SUBREG_P (op)) + op = SUBREG_REG (op); + + if (REG_P (op)) + { + unsigned int regno = REGNO (op); + + if (IS_HARD_OR_VIRT_REGNO (regno)) + { + /* Save the two lowest numbered store source register numbers. */ + if (first_reg == INVALID_REGNUM || regno < first_reg) + { + second_reg = first_reg; + first_reg = regno; + } + else if (second_reg == INVALID_REGNUM || regno < second_reg) + second_reg = regno; + } + } + } + } + + /* First and second regs should have valid numbers now. */ + gcc_assert (first_reg != INVALID_REGNUM + && second_reg != INVALID_REGNUM); + + if (last_reg == first_reg) + stalls = 2; + else if (last_reg == second_reg || penultimate_reg == first_reg) + stalls = 1; + } + else + { + /* For anything other than MSET we examine all input operands + * and return a stall count if any operand collides with the + * penultimate or last value loaded. */ + for (opno = 0 ; opno < recog_data.n_operands ; opno++) + { + if (recog_data.operand_type[opno] == OP_IN) + { + rtx op; + + /* Find the register number. */ + op = recog_data.operand[opno]; + if (SUBREG_P (op)) + op = SUBREG_REG (op); + + if (REG_P (op)) + { + unsigned int regno = REGNO (op); + + if (IS_HARD_OR_VIRT_REGNO (regno)) + { + /* + * The consumer will stall for 2 cycles if it uses the last + * register and 1 cycle if it uses the penultimate + * register. + */ + if (regno == last_reg) + { + stalls = 2; + /* Maximum stalls, no point checking further. */ + break; + } + else if (regno == penultimate_reg) + stalls = 1; + } + } + } + } + } + + return stalls; + } + +/* Detect if any of the output registers of producer are used + * as an O2R input of consumer + * + * op1 identifies the operand that may be o2r + * op2 identifies the operand to check for a mismatch in units. */ + +bool +metag_consumer_is_o2r (rtx producer, rtx consumer, int op1, int op2) +{ + enum reg_class o2rregclass = NO_REGS; + enum reg_class op2regclass = NO_REGS; + unsigned int o2rregno = INVALID_REGNUM; + unsigned int op2regno = INVALID_REGNUM; + rtx op; + + /* The registers aren't known until reload has completed. */ + + if (!reload_completed) + return false; + + extract_insn (consumer); + + if (recog_data.n_operands <= ((op1 > op2) ? op1 : op2) + || recog_data.operand_type[op1] == OP_OUT) + { + /* Bad insn pattern. o2rhint attribute incorrect + * o2rhint should say which operands must be in different units for + * insn to have an O2R operand generated. both operands must be + * IN or INOUT. */ + gcc_unreachable (); + } + + /* Find the register class for op2. */ + op = recog_data.operand[op2]; + if (SUBREG_P (op)) + op = SUBREG_REG (op); + + if (REG_P (op)) + op2regno = REGNO (op); + + /* We should know the registers at this point. */ + gcc_assert (IS_HARD_OR_VIRT_REGNO (op2regno)); + + op2regclass = METAG_REGNO_REG_CLASS (op2regno); + + /* Find the register number for op1. */ + op = recog_data.operand[op1]; + if (SUBREG_P (op)) + op = SUBREG_REG (op); + + if (REG_P (op)) + o2rregno = REGNO (op); + + /* We should know the register at this point. */ + gcc_assert (IS_HARD_OR_VIRT_REGNO (o2rregno)); + + o2rregclass = METAG_REGNO_REG_CLASS (o2rregno); + + /* Check if op1 and op2 have different class registers. */ + if (op2regclass != o2rregclass) + { + int opno; + + /* We have an O2R operand in op1, check it against all OUT / INOUT + * operands of producer. */ + extract_insn (producer); + + for (opno = 0 ; opno < recog_data.n_operands ; opno++) + { + if (recog_data.operand_type[opno] != OP_INOUT) + { + op = recog_data.operand[opno]; + if (SUBREG_P (op)) + op = SUBREG_REG (op); + + if (REG_P (op)) + { + unsigned int regno = REGNO (op); + + /* We should know the register at this point. */ + gcc_assert (IS_HARD_OR_VIRT_REGNO (regno)); + + if (regno == o2rregno) + return true; /* Producer has output reg that feeds o2r + operand in consumer. */ + } + } + } + } + + return false; +} + +bool +metag_hard_regno_rename_ok_p (rtx insn, + unsigned int from, + unsigned int to) +{ + /* Insn must have been recognised and rename permitted */ + if (INSN_CODE (insn) >= 0 && get_attr_rename (insn)) + { + if (cfun->machine->ech_ctx_required) + /* Where an ECH context has been allocated, allow any + hard register to be renamed */ + return from <= LAST_ADDR_REG && to <= LAST_ADDR_REG; + else + { + /* When an ECH context has not been allocated, restrict + rename to the GP register set, regardless of what + registers are available */ + return from <= LAST_ADDR_REG + && ((to < FIRST_ECH_DATA_REG) + || (to >= FIRST_ADDR_REG + && to < FIRST_ECH_ADDR_REG)); + } + } + else + return false; +} + +enum reg_class +metag_regno_reg_class_minimal (unsigned int regno) +{ + if (regno == D0_0_REG || regno == D0_1_REG) + return Ye_REGS; + + if (regno == D1_0_REG || regno == D1_1_REG) + return Yf_REGS; + + if (regno == A0_0_REG || regno == A0_1_REG) + return Yh_REGS; + + if (regno == A1_0_REG || regno == A1_1_REG) + return Yl_REGS; + + if (regno == A0_2_REG || regno == A0_3_REG) + return WQh_REGS; + + if (regno == A1_2_REG || regno == A1_3_REG) + return WQl_REGS; + + if (regno == ARG_POINTER_REGNUM || regno == FRAME_POINTER_REGNUM) + return Yh_REGS; + + return metag_regno_reg_class_unit (regno); +} + +enum reg_class +metag_regno_reg_class_unit (unsigned int regno) +{ + if (regno == HARD_FRAME_POINTER_REGNUM + || regno == STACK_POINTER_REGNUM + || regno == ARG_POINTER_REGNUM + || regno == FRAME_POINTER_REGNUM) + return A0_REGS; + + if (METAG_DATA_REG_P (regno)) + return (regno & 1) ? D1_REGS : D0_REGS; + + if (METAG_ADDR_REG_P (regno)) + return (regno & 1) ? A1_REGS : A0_REGS; + + if (METAG_FPC_REG_P (regno)) + return FPC_REGS; + + if (regno == CPC0_REG) + return A0_REGS; + + if (regno == CPC1_REG) + return A1_REGS; + + if (regno == PC_REG) + return A_REGS; + + if (regno == TXRPT_REG || regno == TTREC_REG) + return Wx_REGS; + + return NO_REGS; +} + +/* Make the last instruction frame related and note that it performs + the operation described by FRAME_PATTERN. */ + +static void +metag_set_frame_expr (rtx frame_pattern) +{ + rtx insn = get_last_insn (); + + RTX_FRAME_RELATED_P (insn) = 1; + if (frame_pattern != NULL_RTX) + REG_NOTES (insn) = alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR, + frame_pattern, + REG_NOTES (insn)); +} + +/* Make the last instruction frame related. */ + +static void +metag_set_frame_related (void) +{ + metag_set_frame_expr (NULL_RTX); +} + +static void +metag_push_frameregs (unsigned extras, unsigned int first_reg, unsigned int last_reg) +{ + rtx basemem = gen_rtx_MEM (DImode, stack_pointer_rtx); + unsigned int count = 0; + unsigned int RegList[8]; + unsigned int *pRegList = RegList; + + { + unsigned int regno; + + for (regno = first_reg; regno <= last_reg; regno += 2) + if ((extras & REGNO_BIT (regno)) != 0) + { + gcc_assert (pRegList < &RegList[sizeof(RegList)/sizeof(RegList[0])]); + + *pRegList++ = regno; + } + } + + count = pRegList - RegList; + gcc_assert (0 < count && count <= sizeof(RegList)/sizeof(RegList[0])); + + if (count == 1) + { + rtx frame_expr = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (3)); + rtx set; + + emit_insn (gen_rtx_SET (VOIDmode, + gen_rtx_MEM (DImode, + gen_rtx_POST_INC (Pmode, + stack_pointer_rtx)), + gen_rtx_REG (DImode, RegList[0]))); + + /* Describe the above instruction to the Drwarf2 call frame unwinder. */ + set = gen_rtx_SET (VOIDmode, + gen_rtx_MEM (SImode, stack_pointer_rtx), + gen_rtx_REG (SImode, RegList[0])); + XVECEXP (frame_expr, 0, 0) = set; + RTX_FRAME_RELATED_P (set) = 1; + + set = gen_rtx_SET (VOIDmode, + gen_rtx_MEM (SImode, + plus_constant (stack_pointer_rtx, + UNITS_PER_WORD)), + gen_rtx_REG (SImode, RegList[0] + 1)); + XVECEXP (frame_expr, 0, 1) = set; + RTX_FRAME_RELATED_P (set) = 1; + + set = gen_rtx_SET (VOIDmode, + stack_pointer_rtx, + plus_constant (stack_pointer_rtx, + UNITS_PER_WORD * 2)); + XVECEXP (frame_expr, 0, 2) = set; + RTX_FRAME_RELATED_P (set) = 1; + + metag_set_frame_expr (frame_expr); + } + else + { + rtx result = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (1 + count)); + rtx frame_expr = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (1 + count * 2)); + rtx set; + + set = gen_rtx_SET (VOIDmode, + stack_pointer_rtx, + plus_constant (stack_pointer_rtx, + count * UNITS_PER_WORD * 2)); + XVECEXP (result, 0, 0) = set; + + set = copy_rtx (set); + XVECEXP (frame_expr, 0, count * 2) = set; + RTX_FRAME_RELATED_P (set) = 1; + + { + unsigned int offset = 0; + unsigned int i; + + for (i = 0; i < count; i++) + { + rtx addr = plus_constant (stack_pointer_rtx, i * UNITS_PER_WORD * 2); + rtx mem = adjust_automodify_address_nv (basemem, DImode, addr, offset); + rtx set; + int j; + + set = gen_rtx_SET (VOIDmode, mem, gen_rtx_REG (DImode, RegList[i])); + XVECEXP (result, 0, 1 + i) = set; + + for (j = 0; j < 2; j++) + { + set = gen_rtx_SET (VOIDmode, + gen_rtx_MEM (SImode, + plus_constant (stack_pointer_rtx, + offset)), + gen_rtx_REG (SImode, RegList[i] + j)); + XVECEXP (frame_expr, 0, i * 2 + j) = set; + RTX_FRAME_RELATED_P (set) = 1; + + offset += UNITS_PER_WORD; + } + } + + emit_insn (result); + + metag_set_frame_expr (frame_expr); + } + } +} + +void +metag_expand_prologue (void) +{ + unsigned int savesize_gp = 0; + unsigned int savesize_eh = 0; + unsigned int FP_SP_offset = 0; + HOST_WIDE_INT size = get_frame_size (); + unsigned int pretend_size = ALIGN_ON_STACK_BOUNDARY (current_function_pretend_args_size); + unsigned int pretend_regs = pretend_size / UNITS_PER_WORD; + unsigned int extras_gp = 0; + unsigned int extras_eh = 0; + unsigned int ech_ctx = 0; + bool non_leaf = metag_non_leaf_function_p (); + rtx use = NULL_RTX; + bool loads_pic_register; + + /* Round size of local stack to preserve 64-bit alignments */ + size = ALIGN_ON_STACK_BOUNDARY (size + current_function_outgoing_args_size); + + /* Make pretend regs into the first non-varargs register number */ + pretend_regs += MIN_METAG_PARM_REGNUM; + + { + unsigned int regno; + + for (regno = MIN_METAG_PARM_REGNUM; regno <= MAX_METAG_CSAVE_REGNUM; regno += 2) + { + if (regno < pretend_regs + || (!call_used_regs[regno] + && (df_regs_ever_live_p (regno + 0) || df_regs_ever_live_p (regno + 1)))) + { + /* Push this data register */ + savesize_gp += UNITS_PER_WORD * 2; + extras_gp |= REGNO_BIT (regno); + + if (regno >= MIN_METAG_CSAVE_REGNUM) + FP_SP_offset += UNITS_PER_WORD * 2; + } + } + } + + /* Adjust the saved registers for ECH support */ + ech_ctx = metag_adjust_savesize_ech (&savesize_gp, &extras_gp, &FP_SP_offset); + + /* Recover original pretend regs */ + pretend_regs -= MIN_METAG_PARM_REGNUM; + + if (cfun->tail_call_emit && cfun->machine->hwtrace_leaf) + { + /* The entry point of a function that ends in a tail call needs to be + marked up when tracing all functions */ + + emit_insn (gen_ttmov_si (gen_rtx_REG (SImode, TEMP_D0FRT_REGNUM), + gen_rtx_REG (SImode, RETURN_POINTER_REGNUM))); + } + else if (!frame_pointer_needed && cfun->machine->hwtrace_leaf) + { + /* The entry point of all functions need to be marked up when tracing + all functions regardless of whether the frame pointer is omitted. + Handle the case where the frame pointer is omitted here. See below + for other case. */ + + emit_insn (gen_ttmov_si (gen_rtx_REG (SImode, TEMP_D0FRT_REGNUM), + hard_frame_pointer_rtx)); + + /* This is NOT frame related because there is no frame pointer really */ + } + + if (frame_pointer_needed || non_leaf) + { + if (non_leaf) + extras_gp |= REGNO_BIT (RETURN_POINTER_REGNUM); + + /* Save return address and maybe frame pointer via {D0Frt,D1RtP} pair */ + savesize_gp += UNITS_PER_WORD * 2; + FP_SP_offset += UNITS_PER_WORD * 2; + + if (frame_pointer_needed) + { + /* Need to spill A0FrP ready for saving and calc new frame */ + if (cfun->machine->hwtrace) + { + rtx frame_expr; + /* Mark up function entry when frame pointer is not omitted, for all + types of H/W tracing */ + emit_insn (gen_ttmov_si (gen_rtx_REG (SImode, TEMP_D0FRT_REGNUM), + hard_frame_pointer_rtx)); + frame_expr = gen_rtx_SET (VOIDmode, gen_rtx_REG (SImode, TEMP_D0FRT_REGNUM), + hard_frame_pointer_rtx); + RTX_FRAME_RELATED_P (frame_expr) = 1; + metag_set_frame_expr (frame_expr); + } + else + { + emit_insn (gen_rtx_SET (VOIDmode, + gen_rtx_REG (SImode, TEMP_D0FRT_REGNUM), + hard_frame_pointer_rtx)); + + metag_set_frame_related (); + } + + /* Save return address and frame pointer via (D0FrT,D1RtP) pair */ + extras_gp |= REGNO_BIT (TEMP_D0FRT_REGNUM); + + emit_insn (gen_addsi3 (hard_frame_pointer_rtx, + stack_pointer_rtx, + gen_int_mode (pretend_size, SImode))); + metag_set_frame_related (); + + use = hard_frame_pointer_rtx; + } + } + else if (df_regs_ever_live_p (RETURN_POINTER_REGNUM)) + { + extras_gp |= REGNO_BIT (RETURN_POINTER_REGNUM); + + /* Have to do at least ine pop */ + savesize_gp += UNITS_PER_WORD * 2; + + if (RETURN_POINTER_REGNUM >= MIN_METAG_CSAVE_REGNUM) + FP_SP_offset += UNITS_PER_WORD * 2; + } + + if (current_function_calls_eh_return) + { + unsigned int n; + + for (n = 0; n < NUM_EH_RETURN_DATA_REGS; n++) + { + unsigned int regno = EH_RETURN_DATA_REGNO (n); + + if (regno != INVALID_REGNUM) + { + unsigned int regbit = REGNO_BIT (regno); + + if ((extras_eh & regbit) == 0) + { + extras_eh |= regbit; + savesize_eh += UNITS_PER_WORD * 2; + FP_SP_offset += UNITS_PER_WORD * 2; + } + } + } + } + + loads_pic_register = METAG_CURRENT_FUNCTION_LOADS_PIC_REGISTER (); + if (loads_pic_register) + FP_SP_offset += UNITS_PER_WORD * 2;/* Save PIC register. */ + + /* Sanity checks between initial_elimination and prologue. If these + tests fail then the generated code will be wrong so abort. */ + + gcc_assert (cfun->machine->valid); + + gcc_assert (cfun->machine->savesize_gp == savesize_gp); + gcc_assert (cfun->machine->savesize_eh == savesize_eh); + gcc_assert (cfun->machine->FP_SP_offset == FP_SP_offset); + gcc_assert (cfun->machine->frame_pointer_needed == frame_pointer_needed); + gcc_assert (cfun->machine->non_leaf == non_leaf); + gcc_assert (cfun->machine->extras_gp == extras_gp); + gcc_assert (cfun->machine->extras_eh == extras_eh); + gcc_assert (cfun->machine->calls_eh_return == current_function_calls_eh_return); + gcc_assert (cfun->machine->uses_pic_offset_table == current_function_uses_pic_offset_table); + gcc_assert (cfun->machine->loads_pic_register == loads_pic_register); + gcc_assert (cfun->machine->ech_ctx_required == (ech_ctx != 0)); + + /* When ECH support is enabled, the register pair including D0.8 may be saved + therefore include it in the initial push */ + if (extras_gp != 0) + metag_push_frameregs (extras_gp, MIN_METAG_PARM_REGNUM, TARGET_ECH ? + METAG_ECH_REGNUM : + MAX_METAG_CSAVE_REGNUM); + + if (extras_eh != 0) + metag_push_frameregs (extras_eh, EH_RETURN_FIRST_DATA_REG, EH_RETURN_LAST_DATA_REG); + + if (loads_pic_register) + { + rtx frame_expr = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2)); + rtx set; + + emit_insn (gen_rtx_SET (VOIDmode, + gen_rtx_MEM (DImode, + gen_rtx_POST_INC (Pmode, + stack_pointer_rtx)), + gen_rtx_UNSPEC (DImode, + gen_rtvec (2, + hard_frame_pointer_rtx, + pic_offset_table_rtx), + UNSPEC_CONCAT))); + + /* Describe the above instruction to the Dwarf2 call frame unwinder. */ + + set = gen_rtx_SET (VOIDmode, + gen_rtx_MEM (SImode, + plus_constant (stack_pointer_rtx, + UNITS_PER_WORD)), + pic_offset_table_rtx); + XVECEXP (frame_expr, 0, 0) = set; + RTX_FRAME_RELATED_P (set) = 1; + + set = gen_rtx_SET (VOIDmode, + stack_pointer_rtx, + plus_constant (stack_pointer_rtx, + 2 * UNITS_PER_WORD)); + XVECEXP (frame_expr, 0, 1) = set; + RTX_FRAME_RELATED_P (set) = 1; + + metag_set_frame_expr (frame_expr); + } + + /* Allocate local stack based storage */ + if (size != 0) + { + rtx frame_expr = gen_rtx_SET (VOIDmode, + stack_pointer_rtx, + plus_constant (stack_pointer_rtx, + size)); + + emit_insn (gen_addsi3 (stack_pointer_rtx, + stack_pointer_rtx, + gen_int_mode (size, SImode))); + + metag_set_frame_expr (frame_expr); + } + + /* Initialise PIC register. */ + if (loads_pic_register) + { + emit_insn (gen_load_pic (pic_offset_table_rtx, + gen_rtx_REG (SImode, CPC1_REG))); + emit_insn (gen_prologue_use (pic_offset_table_rtx)); + } + + if (use != NULL_RTX) + emit_insn (gen_prologue_use (use)); + + if (ech_ctx != 0) + { + rtx reg_ech = gen_rtx_REG (SImode, METAG_ECH_REGNUM); + + /* Only store context if we used a register. The ECH register will be + reset to zero by any system supporting ECH contexts prior to + restoring the context for a process using ECH. + + We must always store the DX8 part of the context as ECH implicitly + uses D0.8. */ + + ech_ctx |= ((TBICTX_XMCC_BIT | TBICTX_XEXT_BIT | TBICTX_XDX8_BIT) << 16); + + /* GCC does not use DSP RAM so the lower 16 bits will be zero */ + gcc_assert ((ech_ctx & 0xFFFF) == 0); + + /* Guaranteed to have bottom 16bits zero, and hence will be set in a + single instruction */ + emit_insn (gen_rtx_SET (SImode, reg_ech, + gen_int_mode (ech_ctx, SImode))); + emit_insn (gen_prologue_use (reg_ech)); + + } + + emit_insn (gen_blockage ()); +} + +void +metag_expand_epilogue (bool epilogue_for_tailcall) +{ + unsigned int savesize_gp = 0; + unsigned int savesize_eh = 0; + unsigned int picsize = 0; + unsigned int num_saved_regs = 0; + unsigned int extras_gp = 0; + unsigned int extras_eh = 0; + unsigned int ech_ctx = 0; + bool non_leaf = metag_non_leaf_function_p (); + int pretend_size = ALIGN_ON_STACK_BOUNDARY (current_function_pretend_args_size); + HOST_WIDE_INT size = get_frame_size (); + unsigned int RegList[8]; + unsigned int *pRegList = RegList; + bool loads_pic_register; + + emit_insn (gen_blockage ()); + + /* Round size of local stack to preserve 64-bit alignments */ + size = ALIGN_ON_STACK_BOUNDARY (size + current_function_outgoing_args_size); + + /* Calculate number of registers to restore + if they contain pretend args save all, else save registers with data in them */ + { + unsigned int regno; + + for (regno = MIN_METAG_CSAVE_REGNUM; regno <= MAX_METAG_CSAVE_REGNUM; regno += 2) + { + if (!call_used_regs[regno] + && (df_regs_ever_live_p(regno + 0) || df_regs_ever_live_p(regno + 1))) + { + /* Need to restore all normal Dx register pairs required */ + savesize_gp += UNITS_PER_WORD * 2; + extras_gp |= REGNO_BIT (regno); + } + } + } + + /* Adjust the saved registers for ECH support */ + ech_ctx = metag_adjust_savesize_ech (&savesize_gp, &extras_gp, NULL); + + /* No registers so far for MGETL|GETL */ + + if (frame_pointer_needed || non_leaf) + { + /* Restore frame pointer via D0FRT or restore return address */ + + if (non_leaf) + { + /* Have to get D1RtP back */ + extras_gp |= REGNO_BIT (RETURN_POINTER_REGNUM); + } + + if (frame_pointer_needed) + { + /* Must restore callers frame pointer */ + extras_gp |= REGNO_BIT (TEMP_D0FRT_REGNUM); + } + + savesize_gp += UNITS_PER_WORD * 2; + } + else if (df_regs_ever_live_p (RETURN_POINTER_REGNUM)) + { + extras_gp |= REGNO_BIT (RETURN_POINTER_REGNUM); + + /* Have to do at least one pop */ + savesize_gp += UNITS_PER_WORD * 2; + } + + if (current_function_calls_eh_return) + { + unsigned int n; + + for (n = 0; n < NUM_EH_RETURN_DATA_REGS; n++) + { + unsigned int regno = EH_RETURN_DATA_REGNO (n); + + if (regno != INVALID_REGNUM) + { + unsigned int regbit = REGNO_BIT (regno); + + if ((extras_eh & regbit) == 0) + { + extras_eh |= regbit; + savesize_eh += UNITS_PER_WORD * 2; + } + } + } + } + + loads_pic_register = METAG_CURRENT_FUNCTION_LOADS_PIC_REGISTER (); + if (loads_pic_register) + picsize += UNITS_PER_WORD * 2; + + if (!frame_pointer_needed && size > 16352) + { + HOST_WIDE_INT excess = size & 0xFFFF0000; + + /* LCS is too big to use as direct offset for recovery */ + if (excess != 0) + { + emit_insn (gen_addsi3 (stack_pointer_rtx, + stack_pointer_rtx, + GEN_INT (-trunc_int_for_mode (excess, SImode)))); + size &= 0xFFFF; + } + + if (size > 16352) + { + emit_insn (gen_addsi3 (stack_pointer_rtx, + stack_pointer_rtx, + GEN_INT (-trunc_int_for_mode (size, SImode)))); + size = 0; + } + } + + if (loads_pic_register) + { + if (frame_pointer_needed) + emit_insn (gen_rtx_SET (VOIDmode, + gen_rtx_UNSPEC (DImode, + gen_rtvec (2, + hard_frame_pointer_rtx, + pic_offset_table_rtx), + UNSPEC_CONCAT), + gen_rtx_MEM (DImode, + plus_constant (hard_frame_pointer_rtx, + savesize_gp + savesize_eh)))); + else + emit_insn (gen_rtx_SET (VOIDmode, + gen_rtx_UNSPEC (DImode, + gen_rtvec (2, + hard_frame_pointer_rtx, + pic_offset_table_rtx), + UNSPEC_CONCAT), + gen_rtx_MEM (DImode, + plus_constant (stack_pointer_rtx, + -(HOST_WIDE_INT)(size + picsize))))); + } + + if (extras_eh != 0) + { + unsigned int delta = 0; + unsigned int regno; + + for (regno = 0; regno < 32; regno += 2) + { + if ((extras_eh & REGNO_BIT (regno)) != 0) + { + if (frame_pointer_needed) + { + emit_insn (gen_rtx_SET (VOIDmode, + gen_rtx_REG (DImode, regno), + gen_rtx_MEM (DImode, + plus_constant (hard_frame_pointer_rtx, + savesize_gp + delta)))); + } + else + { + HOST_WIDE_INT offset = -(HOST_WIDE_INT)(size + picsize + savesize_eh); + + emit_insn (gen_rtx_SET (VOIDmode, + gen_rtx_REG (DImode, regno), + gen_rtx_MEM (DImode, + plus_constant (stack_pointer_rtx, + offset + delta)))); + } + + delta += UNITS_PER_WORD * 2; + } + } + } + + if (extras_gp != 0) + { + unsigned int regno; + + for (regno = MIN_METAG_PARM_REGNUM; regno < 32; regno += 2) + { + if ((extras_gp & REGNO_BIT (regno)) != 0) + { + HOST_WIDE_INT offset = -(HOST_WIDE_INT)(size + picsize + savesize_eh + savesize_gp); + + gcc_assert (pRegList < &RegList[sizeof(RegList)/sizeof(RegList[0])]); + + if (!frame_pointer_needed + && (savesize_gp != UNITS_PER_WORD * 2 || pretend_size != 0 || (size + picsize) >= 256)) + { + offset += num_saved_regs * UNITS_PER_WORD * 2; + + emit_insn (gen_rtx_SET (VOIDmode, + gen_rtx_REG (DImode, regno), + gen_rtx_MEM (DImode, + plus_constant (stack_pointer_rtx, + offset)))); + pRegList = RegList; + } + else if (!frame_pointer_needed) + { + /* Only one pair and no pretend args, pre-decrement stack! */ + emit_insn (gen_rtx_SET (VOIDmode, + gen_rtx_REG (DImode, regno), + gen_rtx_MEM (DImode, + gen_rtx_PRE_MODIFY (Pmode, + stack_pointer_rtx, + plus_constant (stack_pointer_rtx, + offset))))); + pRegList = RegList; + + /* Stack predecremented above */ + size = -(HOST_WIDE_INT)(savesize_gp + savesize_eh + picsize); + } + else + *pRegList++ = regno; + + /* Count them */ + num_saved_regs++; + } + } + } + + /* Take account of pretend args stored on the stack by the prologue */ + savesize_gp += pretend_size; + + if (pRegList != RegList) + { + rtx basemem = gen_rtx_MEM (DImode, hard_frame_pointer_rtx); + unsigned int count = pRegList - RegList; + + gcc_assert (count > 0); + + /* Use frame pointer to recover caller-saved regs */ + if (count == 1) + { + /* Only one pair needed, advance frame pointer */ + emit_insn (gen_rtx_SET (VOIDmode, + gen_rtx_REG (DImode, RegList[0]), + gen_rtx_MEM (DImode, + gen_rtx_POST_INC (Pmode, + hard_frame_pointer_rtx)))); + } + else + { + rtx result = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (1 + count)); + unsigned int offset = 0; + unsigned int i; + + XVECEXP (result, 0, 0) = gen_rtx_SET (VOIDmode, + hard_frame_pointer_rtx, + plus_constant (hard_frame_pointer_rtx, + count * UNITS_PER_WORD * 2)); + + for (i = 0; i < count; i++) + { + rtx addr = plus_constant (hard_frame_pointer_rtx, i * UNITS_PER_WORD * 2); + rtx mem = adjust_automodify_address_nv (basemem, DImode, addr, offset); + + gcc_assert (i <= count); + + XVECEXP (result, 0, 1 + i) = gen_rtx_SET (VOIDmode, + gen_rtx_REG (DImode, RegList[i]), + mem); + offset += UNITS_PER_WORD * 2; + } + + emit_insn (result); + } + + /* Use frame pointer to recover stack pointer */ + emit_insn (gen_addsi3 (stack_pointer_rtx, + hard_frame_pointer_rtx, + GEN_INT (-trunc_int_for_mode (savesize_gp, SImode)))); + } + else if (frame_pointer_needed) + { + /* Use unmolested frame pointer to recover stack pointer */ + emit_insn (gen_addsi3 (stack_pointer_rtx, + hard_frame_pointer_rtx, + GEN_INT (-trunc_int_for_mode (pretend_size, SImode)))); + } + else + { + HOST_WIDE_INT adjust = size + picsize + savesize_eh + savesize_gp; + + /* Calculate return stack adjustment directly including savesize */ + + if (adjust != 0) + emit_insn (gen_addsi3 (stack_pointer_rtx, + stack_pointer_rtx, + GEN_INT (-trunc_int_for_mode (adjust, SImode)))); + } + + /* We should be able to insert code here for EPILOGUE delay-slots if + frame_pointer_needed. The next instruction will stall waiting + for return data from the MGETL or GETL done above in this case. */ + + if (frame_pointer_needed) + { + if (!cfun->machine->hwtrace || cfun->machine->hwtrace_retpc) + { + /* Restore callers frame pointer. The HWTRACE code below will take + care of this when enabled, unless the RETPC method is being used, + in which case it must be done here as normal. */ + + emit_insn (gen_rtx_SET (VOIDmode, + hard_frame_pointer_rtx, + gen_rtx_REG (SImode, TEMP_D0FRT_REGNUM))); + } + } + else if ((!cfun->tail_call_emit || !epilogue_for_tailcall) + && cfun->machine->hwtrace_leaf && cfun->machine->hwtrace_retpc + && !non_leaf && df_regs_ever_live_p (TEMP_D0FRT_REGNUM)) + { + /* When tracing all leaf functions with the RETPC method, and we are + in a leaf function that has clobbered D0FrT and the frame pointer + is not needed (and this function doesn't end in a sibcall)... + Then D0FrT must be recovered from the frame pointer ready to be used + below */ + + emit_insn (gen_rtx_SET (VOIDmode, + gen_rtx_REG (SImode, TEMP_D0FRT_REGNUM), + hard_frame_pointer_rtx)); + } + + if ((!cfun->tail_call_emit || !epilogue_for_tailcall) + && cfun->machine->hwtrace_retpc) + { + /* The RETPC method of tracing is a MOVL TTREC, x,y. Emit one when + the function does not end in a sibcall*/ + + emit_insn (gen_ttrec (gen_rtx_REG (DImode, TTREC_REGNUM), + gen_rtx_REG (DImode, TEMP_D0FRT_REGNUM))); + } + else if ((!cfun->tail_call_emit || !epilogue_for_tailcall) + && cfun->machine->hwtrace + && (frame_pointer_needed || cfun->machine->hwtrace_leaf)) + { + /* The standard method of tracing is to mark up the FP restore with a + TTMOV. + This is done when tracing leaf functions or the frame pointer is + needed. In the latter case this replaces the normal frame pointer + restore from above. */ + + emit_insn (gen_ttmov_si (hard_frame_pointer_rtx, + gen_rtx_REG (SImode, TEMP_D0FRT_REGNUM))); + } + + /* Returns to exception handlers require an additional stack adjustment. */ + if (current_function_calls_eh_return) + emit_insn (gen_subsi3 (stack_pointer_rtx, + stack_pointer_rtx, + EH_RETURN_STACKADJ_RTX)); + + return; +} + +/* Return TRUE if it is possible to return using a simple return + sequence instruction, possibly conditional. */ + +bool +metag_use_return_insn (bool cond) +{ + if (! reload_completed) + return false; + + if (current_function_profile) + return false; + + if (current_function_calls_alloca) + return false; + + if (current_function_calls_eh_return) + return false; + + if (current_function_outgoing_args_size != 0) + return false; + + if (current_function_pretend_args_size != 0) + return false; + + if (cfun->machine->anonymous_args_size != 0) + return false; + + if (cfun->machine->out_local_size != 0) + return false; + + if (cfun->machine->savesize_gp != 0) + return false; + + if (cfun->machine->loads_pic_register != 0) + return false; + + if (cond && cfun->machine->hwtrace) + return false; + + return true; +} + +/* Verify that any instruction that supports conditional execution + * includes the '%?' placeholder if that instruction has been + * marked as conditional. */ +void +metag_asm_output_opcode (FILE *file ATTRIBUTE_UNUSED, const char * opcode) +{ + if (metag_cond_exec_p () || current_insn_predicate != NULL_RTX) + { + if (strchr (opcode, '?') == NULL) + gcc_unreachable (); + } +} + +const char * +metag_invalid_within_doloop (rtx insn) +{ + if (CALL_P (insn)) + return "Function call in the loop."; + + if (INSN_P (insn) && asm_noperands (PATTERN (insn)) >= 0 && + regno_clobbered_p (TXRPT_REGNUM, insn, SImode, 0)) + return "In-line assembler clobbering TXRPT."; + + return NULL; +} + +/* Return TRUE iff the frame-pointer is required to efficiently restore + * the stack frame during the epilogue. */ + +static bool +metag_frame_pointer_required_for_epilogue_restore (void) +{ + return cfun->machine->frame_pointer_epilogue + = metag_non_leaf_function_p () + && (ALIGN_ON_STACK_BOUNDARY (get_frame_size () + + current_function_outgoing_args_size) > 16352); +} + +/* Return TRUE if the frame-pointer is required. */ + +bool +metag_frame_pointer_required (void) +{ + return (current_function_calls_alloca + || current_function_has_nonlocal_label + || profile_flag + || (cfun->machine->valid && cfun->machine->frame_pointer_epilogue) + || cfun->machine->accesses_prev_frame + || metag_frame_pointer_required_for_epilogue_restore ()); +} + +void +metag_setup_frame_addresses (void) +{ + cfun->machine->accesses_prev_frame = true; +} + +void +metag_expand_set_return_address (rtx source) +{ + unsigned int savesize_gp = 0; + unsigned int savesize_eh = 0; + unsigned int picsize = 0; + unsigned int extras_gp = 0; + unsigned int extras_eh = 0; + unsigned int ech_ctx = 0; + bool non_leaf = metag_non_leaf_function_p (); + HOST_WIDE_INT size = get_frame_size (); + bool loads_pic_register; + + /* Round size of local stack to preserve 64-bit alignments */ + size = ALIGN_ON_STACK_BOUNDARY (size + current_function_outgoing_args_size); + + /* Calculate number of registers to restore + if they contain pretend args save all, else save registers with data in them */ + { + unsigned int regno; + + for (regno = MIN_METAG_CSAVE_REGNUM; regno <= MAX_METAG_CSAVE_REGNUM; regno += 2) + { + if (!call_used_regs[regno] + && (df_regs_ever_live_p (regno + 0) || df_regs_ever_live_p (regno + 1))) + { + /* Need to restore all normal Dx register pairs required */ + savesize_gp += UNITS_PER_WORD * 2; + extras_gp |= REGNO_BIT (regno); + } + } + } + + /* Adjust the saved registers for ECH support */ + ech_ctx = metag_adjust_savesize_ech (&savesize_gp, &extras_gp, NULL); + + if (frame_pointer_needed || non_leaf) + { + /* Restore frame pointer via D0FRT or restore return address */ + + if (non_leaf) + extras_gp |= REGNO_BIT (RETURN_POINTER_REGNUM); + + if (frame_pointer_needed) + extras_gp |= REGNO_BIT (TEMP_D0FRT_REGNUM); + + savesize_gp += UNITS_PER_WORD * 2; + } + else if (df_regs_ever_live_p (RETURN_POINTER_REGNUM)) + { + extras_gp |= REGNO_BIT (RETURN_POINTER_REGNUM); + + /* Have to do at least one pop */ + savesize_gp += UNITS_PER_WORD * 2; + } + + if (current_function_calls_eh_return) + { + unsigned int n; + + for (n = 0; n < NUM_EH_RETURN_DATA_REGS; n++) + { + unsigned int regno = EH_RETURN_DATA_REGNO (n); + + if (regno != INVALID_REGNUM) + { + unsigned int regbit = REGNO_BIT (regno); + + if ((extras_eh & regbit) == 0) + { + extras_eh |= regbit; + savesize_eh += UNITS_PER_WORD * 2; + } + } + } + } + + loads_pic_register = METAG_CURRENT_FUNCTION_LOADS_PIC_REGISTER (); + if (loads_pic_register) + picsize += UNITS_PER_WORD * 2; + + gcc_assert (cfun->machine->valid); + gcc_assert (cfun->machine->savesize_gp == savesize_gp); + gcc_assert (cfun->machine->savesize_eh == savesize_eh); + gcc_assert (cfun->machine->extras_gp == extras_gp); + gcc_assert (cfun->machine->extras_eh == extras_eh); + gcc_assert (cfun->machine->pic_save_size == picsize); + gcc_assert (cfun->machine->uses_pic_offset_table == current_function_uses_pic_offset_table); + gcc_assert (cfun->machine->loads_pic_register == loads_pic_register); + + if ((extras_gp & REGNO_BIT (RETURN_POINTER_REGNUM)) != 0) + { + rtx base; + + /* The return address is @ hard frame pointer + UNITS_PER_WORD */ + if (frame_pointer_needed) + base = plus_constant (hard_frame_pointer_rtx, UNITS_PER_WORD); + else + base = plus_constant (stack_pointer_rtx, + -(HOST_WIDE_INT)(size + picsize + savesize_eh + savesize_gp - UNITS_PER_WORD)); + + emit_insn (gen_rtx_SET (VOIDmode, + gen_rtx_MEM (SImode, base), + source)); + } + else + emit_insn (gen_rtx_SET (VOIDmode, + gen_rtx_REG (SImode, RETURN_POINTER_REGNUM), + source)); + + return; +} + +bool +metag_doloop_loop_nest_optimized (struct loop * loop, struct doloopnest * nest) +{ + for ( ; nest != NULL ; nest = nest->next) + if (nest->inner == loop) + return true; + + return false; +} + +bool +metag_doloop_check_any_nest_optimized (struct loop * loop, struct doloopnest * nest) +{ + if (loop->inner == NULL) + /* Check if nest already has an optimized loop */ + return metag_doloop_loop_nest_optimized (loop, nest); + else + { + struct loop* innerloops = loop->inner; + + for ( ; innerloops != NULL ; innerloops = innerloops->next) + if (metag_doloop_check_any_nest_optimized (innerloops, nest)) + return true; + } + + return false; +} + +void +metag_doloop_mark_nests_optimized (struct loop * loop, struct doloopnest ** nest_p) +{ + /* Check if the nest already has an optimized loop */ + if (loop->inner == NULL) + { + while (*nest_p != NULL) + /* Find the end of the list of nests */ + nest_p = &((*nest_p)->next); + + /* Add the new loop nest (innermost loop) to the list */ + *nest_p = (struct doloopnest *)xmalloc (sizeof (struct doloopnest)); + (*nest_p)->next = NULL; + (*nest_p)->inner = loop; + } + else + { + /* Process all inner siblings if this loop is not innermost */ + struct loop* innerloops = loop->inner; + + for ( ; innerloops != NULL ; innerloops = innerloops->next) + metag_doloop_mark_nests_optimized (innerloops, nest_p); + } +} + +bool +metag_current_function_loads_pic_register (void) +{ +#if 0 + /* We need to perform more analysis and house keeping + before we can optimize the loading of PIC register + based on local/global properties of functions. + + At present we only mark functions to load the pic + register if it uses the PIC register, but this + doesn't interact correctly with the intended local/ + global optimization. + + Consider + + extern int a; + + static void s(void) { a = 1; } + + void g (void) { s (); } + + We need g() to load/restore the PIC and s() to + inherit the PIC from g(); + + */ + if (flag_unit_at_a_time) + { + struct cgraph_local_info * local_info + = cgraph_local_info (current_function_decl); + + if (local_info && local_info->local) + return false; + } +#endif + + return current_function_uses_pic_offset_table; +} + +#define MODE_BASE_REG_CLASS(MODE) (MODE) + +rtx +metag_legitimize_reload_address (rtx x, enum machine_mode mode, + int opnum, int type, + int ind_levels ATTRIBUTE_UNUSED) +{ + if (GET_CODE (x) == PLUS + && REG_P (XEXP (x, 0)) + && IS_HARD_OR_VIRT_REGNO (REGNO (XEXP (x, 0))) + && METAG_LEGITIMATE_REG_P (XEXP (x, 0), TRUE) + && CONST_INT_P (XEXP (x, 1))) + { + if (!strict_memory_address_p (mode, x)) + { +#if 0 + unsigned int modesize = GET_MODE_SIZE (mode); + HOST_WIDE_INT value = INTVAL (XEXP (x, 1)); + HOST_WIDE_INT limit_top; + HOST_WIDE_INT limit_bot; + HOST_WIDE_INT delta; + + if (metag_reg12bit_op (XEXP (x, 0), mode)) + limit_top = 2048 * modesize; + else + limit_top = 32 * modesize; + + limit_bot = -limit_top; + limit_top = (limit_top - 1) & ~(modesize - 1); + + if (limit_top <= value && value < limit_top + 255) + delta = limit_top; + else if (limit_bot - 255 <= value && value < -limit_bot) + delta = limit_bot; + else + delta = 0; +#endif + + x = gen_rtx_PLUS (GET_MODE (x), + gen_rtx_PLUS (GET_MODE (x), XEXP (x, 0), + XEXP (x, 1)), + GEN_INT (0)); + push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL, + MODE_BASE_REG_CLASS (mode), GET_MODE (x), + VOIDmode, 0, 0, opnum, type); + + return x; + } + } + + return NULL_RTX; +} + +bool +metag_offset6_mode (rtx op, enum machine_mode mode) +{ + gcc_assert (CONST_INT_P (op)); + + switch (mode) + { + case DImode: + return metag_offset6_di (op, mode); + + case SImode: + return metag_offset6_si (op, mode); + + case HImode: + return metag_offset6_hi (op, mode); + + case QImode: + return metag_offset6_qi (op, mode); + + case DFmode: + return metag_offset6_df (op, mode); + + case SFmode: + return metag_offset6_sf (op, mode); + + case V2SImode: + return metag_offset6_v2si (op, mode); + + case V2SFmode: + return metag_offset6_v2sf (op, mode); + + default: + gcc_unreachable (); + } + + return false; +} + +bool +metag_offset12_mode (rtx op, enum machine_mode mode) +{ + gcc_assert (CONST_INT_P (op)); + + switch (mode) + { + case DImode: + return metag_offset12_di (op, mode); + + case SImode: + return metag_offset12_si (op, mode); + + case HImode: + return metag_offset12_hi (op, mode); + + case QImode: + return metag_offset12_qi (op, mode); + + case DFmode: + return metag_offset12_df (op, mode); + + case SFmode: + return metag_offset12_sf (op, mode); + + case V2SImode: + return metag_offset12_v2si (op, mode); + + case V2SFmode: + return metag_offset12_v2sf (op, mode); + + default: + gcc_unreachable (); + } + + return false; +} + +bool +metag_regno12bit_p (unsigned int regno) +{ + return regno == D0_0_REG || regno == D0_1_REG + || regno == D1_0_REG || regno == D1_1_REG + || regno == A0_0_REG || regno == A0_1_REG + || regno == A1_0_REG || regno == A1_1_REG; +} + +bool +metag_split_early (void) +{ + return reload_completed; +} + +bool +metag_split_hi_lo_sum_early (void) +{ + return reload_completed; +} + +void +metag_internal_label (FILE *file, const char *prefix, unsigned long labelno) +{ + if (metag_ccfsm_state == 3 + && (unsigned)metag_target_label == labelno + && strcmp (prefix, "L") == 0) + { + metag_ccfsm_state = 0; + metag_target_insn = NULL; + } + + default_internal_label (file, prefix, labelno); + return; +} + +bool +metag_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode) +{ + if (GET_MODE_CLASS (mode) == MODE_CC) + return regno == MCC_REGNUM; + else if (regno == MCC_REGNUM) + return false; + + if (LAST_ADDR_REG < regno && regno < FIRST_FP_REG) + return mode == SImode; + + if (FIRST_FP_REG <= regno && regno <= LAST_FP_REG) + { + /* FP regs can hold anything that fits in a single reg or a pair */ + if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD) + return true; + else + return ((regno - FIRST_FP_REG) & 1) == 0 && ((regno + HARD_REGNO_NREGS (regno, mode) - 1) <= LAST_FP_REG); + } + + if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD) + return true; + else + { + unsigned int last_permitted_reg = LAST_ADDR_REG; + + /* V2SI can only use data registers */ + if (mode == V2SImode || mode == V2SFmode) + last_permitted_reg = LAST_DATA_REG; + + return ((regno <= last_permitted_reg && (regno & 1) == 0)) && ((regno + HARD_REGNO_NREGS (regno, mode) - 1) <= last_permitted_reg); + } + + return false; +} + +bool +metag_dsp_ri16_operands (rtx operands[]) +{ + int dunit0, dunit2; + int regno0, regno2; + + /* Reject if not all registers and also in DATA register class. */ + if (!(REG_P (operands[0 ]) + && METAG_DATA_REG_P (REGNO (operands[0 ])) + && REG_P (operands[0+2]) + && METAG_DATA_REG_P (REGNO (operands[0+2])) + && GET_CODE (operands[1 ]) == CONST_INT + && metag_16bit_op (operands[1], GET_MODE (operands[1])))) + return false; + + dunit0 = METAG_DATAREG_UNIT (REGNO (operands[0 ])); + dunit2 = METAG_DATAREG_UNIT (REGNO (operands[0+2])); + + regno0 = METAG_DATAREG_REGN (REGNO (operands[0 ])); + regno2 = METAG_DATAREG_REGN (REGNO (operands[0+2])); + + /* Accept if register units and regno's match. */ + return (dunit0 != dunit2 && regno0 == regno2); + +} + +bool +metag_dsp_rri5_operands (rtx operands[]) +{ + int dunit0, dunit1, dunit3, dunit4; + int regno0, regno1, regno3, regno4; + + /* Reject if not all registers and also in DATA register class. */ + if (!(REG_P (operands[0 ]) + && METAG_DATA_REG_P (REGNO (operands[0 ])) + && REG_P (operands[0+1]) + && METAG_DATA_REG_P (REGNO (operands[0+1])) + && REG_P (operands[3+0]) + && METAG_DATA_REG_P (REGNO (operands[3+0])) + && REG_P (operands[3+1]) + && METAG_DATA_REG_P (REGNO (operands[3+1])) + && GET_CODE (operands[2 ]) == CONST_INT + && metag_5bit_op (operands[2], GET_MODE (operands[2])))) + return false; + + dunit0 = METAG_DATAREG_UNIT (REGNO (operands[0 ])); + dunit1 = METAG_DATAREG_UNIT (REGNO (operands[0+1])); + dunit3 = METAG_DATAREG_UNIT (REGNO (operands[3 ])); + dunit4 = METAG_DATAREG_UNIT (REGNO (operands[3+1])); + + regno0 = METAG_DATAREG_REGN (REGNO (operands[0 ])); + regno1 = METAG_DATAREG_REGN (REGNO (operands[0+1])); + regno3 = METAG_DATAREG_REGN (REGNO (operands[3 ])); + regno4 = METAG_DATAREG_REGN (REGNO (operands[3+1])); + + /* Reject if register units don't match. */ + if (dunit0 != dunit1 + || dunit3 != dunit4 + || dunit0 == dunit3) + return false; + + /* Reject is dest registers don't match. */ + if (regno0 != regno3) + return false; + + /* Accept if src register match. */ + return (regno1 == regno4); +} + +bool +metag_dsp_rrr_operands (rtx operands[], bool commutable) +{ + int dunit0, dunit1, dunit2, dunit3, dunit4, dunit5; + int regno0, regno1, regno2, regno3, regno4, regno5; + + /* Reject if not operands DATA registers. */ + if (!(REG_P (operands[0 ]) + && METAG_DATA_REG_P (REGNO (operands[0 ])) + && REG_P (operands[0+3]) + && METAG_DATA_REG_P (REGNO (operands[0+3])) + && REG_P (operands[1 ]) + && METAG_DATA_REG_P (REGNO (operands[1 ])) + && REG_P (operands[1+3]) + && METAG_DATA_REG_P (REGNO (operands[1+3])) + && REG_P (operands[2]) + && METAG_DATA_REG_P (REGNO (operands[2 ])) + && REG_P (operands[2+3]) + && METAG_DATA_REG_P (REGNO (operands[2+3])))) + return false; + + dunit0 = METAG_DATAREG_UNIT (REGNO (operands[0 ])); + dunit1 = METAG_DATAREG_UNIT (REGNO (operands[1 ])); + dunit2 = METAG_DATAREG_UNIT (REGNO (operands[2 ])); + + dunit3 = METAG_DATAREG_UNIT (REGNO (operands[0+3])); + dunit4 = METAG_DATAREG_UNIT (REGNO (operands[1+3])); + dunit5 = METAG_DATAREG_UNIT (REGNO (operands[2+3])); + + regno0 = METAG_DATAREG_REGN (REGNO (operands[0 ])); + regno1 = METAG_DATAREG_REGN (REGNO (operands[1 ])); + regno2 = METAG_DATAREG_REGN (REGNO (operands[2 ])); + + regno3 = METAG_DATAREG_REGN (REGNO (operands[0+3])); + regno4 = METAG_DATAREG_REGN (REGNO (operands[1+3])); + regno5 = METAG_DATAREG_REGN (REGNO (operands[2+3])); + + /* Reject if register units don't match. */ + if (dunit0 != dunit1 + || dunit1 != dunit2 + || dunit3 != dunit4 + || dunit4 != dunit5 + || dunit0 == dunit3) + return false; + + /* Reject is dest registers don't match. */ + if (regno0 != regno3) + return false; + + /* Accept if src register match. */ + return ((regno1 == regno4 && regno2 == regno5) + || (commutable + && (regno1 == regno5 && regno2 == regno4))); +} + +bool +metag_dsp_rrr_mov_operands (rtx operands[], bool commutable) +{ + int dunit1, dunit2, dunit4, dunit5, dunit6, dunit7; + int regno1, regno2, regno4, regno5, regno6, regno7; + + /* Reject if not operands DATA registers. */ + if (!(REG_P (operands[0 ]) + && REG_P (operands[0+3]) + && REG_P (operands[1 ]) + && METAG_DATA_REG_P (REGNO (operands[1 ])) + && REG_P (operands[1+3]) + && METAG_DATA_REG_P (REGNO (operands[1+3])) + && REG_P (operands[2]) + && METAG_DATA_REG_P (REGNO (operands[2 ])) + && REG_P (operands[2+3]) + && METAG_DATA_REG_P (REGNO (operands[2+3])) + && REG_P (operands[0+6]) + && METAG_DATA_REG_P (REGNO (operands[0+6])) + && REG_P (operands[1+6]) + && METAG_DATA_REG_P (REGNO (operands[1+6])))) + return false; + + dunit1 = METAG_DATAREG_UNIT (REGNO (operands[1 ])); + dunit2 = METAG_DATAREG_UNIT (REGNO (operands[2 ])); + dunit4 = METAG_DATAREG_UNIT (REGNO (operands[1+3])); + dunit5 = METAG_DATAREG_UNIT (REGNO (operands[2+3])); + dunit6 = METAG_DATAREG_UNIT (REGNO (operands[6 ])); + dunit7 = METAG_DATAREG_UNIT (REGNO (operands[7 ])); + + regno1 = METAG_DATAREG_REGN (REGNO (operands[1 ])); + regno2 = METAG_DATAREG_REGN (REGNO (operands[2 ])); + regno4 = METAG_DATAREG_REGN (REGNO (operands[1+3])); + regno5 = METAG_DATAREG_REGN (REGNO (operands[2+3])); + regno6 = METAG_DATAREG_REGN (REGNO (operands[0+6])); + regno7 = METAG_DATAREG_REGN (REGNO (operands[1+6])); + + /* Reject if register units don't match */ + if ( dunit1 != dunit2 + || dunit1 != dunit6 + || dunit4 != dunit5 + || dunit4 != dunit7 + || dunit6 == dunit7) + return false; + + /* Reject is dest registers don't match. */ + if (regno6 != regno7) + return false; + + /* Accept if src register's match. */ + return ((regno1 == regno4 && regno2 == regno5) + || (commutable + && (regno1 == regno5 && regno2 == regno4))); +} + +bool +metag_dsp_rr_operands (rtx operands[]) +{ + int dunit0, dunit1, dunit2, dunit3; + int regno0, regno1, regno2, regno3; + + /* Reject if not all are registers and also in DATA register class. */ + if (!(REG_P (operands[0 ]) + && METAG_DATA_REG_P (REGNO (operands[0 ])) + && REG_P (operands[0+2]) + && METAG_DATA_REG_P (REGNO (operands[0+2])) + && REG_P (operands[1 ]) + && METAG_DATA_REG_P (REGNO (operands[1 ])) + && REG_P (operands[1+2]) + && METAG_DATA_REG_P (REGNO (operands[1+2])))) + return false; + + dunit0 = METAG_DATAREG_UNIT (REGNO (operands[0 ])); + dunit1 = METAG_DATAREG_UNIT (REGNO (operands[1 ])); + dunit2 = METAG_DATAREG_UNIT (REGNO (operands[0+2])); + dunit3 = METAG_DATAREG_UNIT (REGNO (operands[1+2])); + + regno0 = METAG_DATAREG_REGN (REGNO (operands[0 ])); + regno1 = METAG_DATAREG_REGN (REGNO (operands[1 ])); + regno2 = METAG_DATAREG_REGN (REGNO (operands[0+2])); + regno3 = METAG_DATAREG_REGN (REGNO (operands[1+2])); + + /* Accept if register units and regno's match. */ + return ( dunit0 == dunit1 + && dunit2 == dunit3 + && dunit0 != dunit2 + && regno0 == regno2 + && regno1 == regno3); +} + +bool +metag_dsp_rr_rr_mov_operands (rtx operands[]) +{ + int dunit1, dunit3, dunit4, dunit5; + int regno1, regno3, regno4, regno5; + + /* Reject if not operands DATA registers. */ + if (!(REG_P (operands[0 ]) + && REG_P (operands[0+2]) + && REG_P (operands[1 ]) + && METAG_DATA_REG_P (REGNO (operands[1 ])) + && REG_P (operands[1+2]) + && METAG_DATA_REG_P (REGNO (operands[1+2])) + && REG_P (operands[0+4]) + && METAG_DATA_REG_P (REGNO (operands[0+4])) + && REG_P (operands[1+4]) + && METAG_DATA_REG_P (REGNO (operands[1+4])))) + return false; + + dunit1 = METAG_DATAREG_UNIT (REGNO (operands[1 ])); + dunit3 = METAG_DATAREG_UNIT (REGNO (operands[1+2])); + dunit4 = METAG_DATAREG_UNIT (REGNO (operands[4 ])); + dunit5 = METAG_DATAREG_UNIT (REGNO (operands[5 ])); + + regno1 = METAG_DATAREG_REGN (REGNO (operands[1 ])); + regno3 = METAG_DATAREG_REGN (REGNO (operands[1+2])); + regno4 = METAG_DATAREG_REGN (REGNO (operands[0+4])); + regno5 = METAG_DATAREG_REGN (REGNO (operands[1+4])); + + /* Accept if register units and regno's match. */ + return ( dunit4 == dunit1 + && dunit5 == dunit3 + && dunit4 != dunit5 + && regno4 == regno5 + && regno5 == regno3 + && regno4 == regno5); +} + +/* This function sets operands 2,3 to support both flag setting and non flag + setting dsp peephole 2 transformations */ +void +metag_dsp_peephole2_rr_convert (rtx operands[]) +{ + int adjust = 0; + + if (REGNO (operands[0]) > REGNO (operands[0+2])) + adjust = 2; + + operands[2] = gen_rtx_REG (V2SImode, REGNO (operands[0 + adjust])); + operands[3] = gen_rtx_REG (V2SImode, REGNO (operands[1 + adjust])); +} + +void +metag_dsp_peephole2_rr_mov_convert (rtx operands[]) +{ + int adjustin = 0; + int adjustout = 0; + + if (REGNO (operands[1]) > REGNO (operands[1+2])) + { + adjustin = 2; + adjustout = 1; + } + operands[4] = gen_rtx_REG (V2SImode, REGNO (operands[4 + adjustout])); + operands[1] = gen_rtx_REG (V2SImode, REGNO (operands[1 + adjustin])); +} + +/* This function sets operands 3,4,5 to support both flag setting and non flag + setting dsp peephole 2 transformations */ +void +metag_dsp_peephole2_rrr_convert (rtx operands[]) +{ + int adjust = 0; + + if (REGNO (operands[0]) > REGNO (operands[0+3])) + adjust = 3; + + operands[3] = gen_rtx_REG (V2SImode, REGNO (operands[0 + adjust])); + operands[4] = gen_rtx_REG (V2SImode, REGNO (operands[1 + adjust])); + operands[5] = gen_rtx_REG (V2SImode, REGNO (operands[2 + adjust])); +} + +void +metag_dsp_peephole2_rrr_mov_convert (rtx operands[]) +{ + int adjustin = 0; + int adjustout = 0; + + /* Operands 0 and 3 are not related in this case */ + if (REGNO (operands[1]) > REGNO (operands[1+3])) + { + adjustin = 3; + adjustout = 1; + } + operands[6] = gen_rtx_REG (V2SImode, REGNO (operands[6 + adjustout])); + operands[1] = gen_rtx_REG (V2SImode, REGNO (operands[1 + adjustin])); + operands[2] = gen_rtx_REG (V2SImode, REGNO (operands[2 + adjustin])); +} + +/* This function sets operands 2 and 3 to support both flag setting and non flag + setting dsp peephole 2 transformations */ +void +metag_dsp_peephole2_ri16_convert (rtx operands[]) +{ + int adjust = 0; + + if (REGNO (operands[0]) > REGNO (operands[0+2])) + adjust = 2; + + operands[2] = gen_rtx_REG (V2SImode, REGNO (operands[0 + adjust])); + operands[3] = gen_rtx_CONST_VECTOR (V2SImode, + gen_rtvec (2, operands[1], operands[1])); +} + +/* This function sets operands 3,4,5 to support both flag setting and non flag + setting dsp peephole 2 transformations */ +void +metag_dsp_peephole2_rri5_convert (rtx operands[]) +{ + int adjust = 0; + + if (REGNO (operands[0]) > REGNO (operands[0+3])) + adjust = 3; + + operands[3] = gen_rtx_REG (V2SImode, REGNO (operands[0 + adjust])); + operands[4] = gen_rtx_REG (V2SImode, REGNO (operands[1 + adjust])); + operands[5] = gen_rtx_CONST_VECTOR (V2SImode, + gen_rtvec (2, operands[2], operands[2])); +} + +bool +metag_move_valid_p (rtx to, rtx from) +{ + gcc_assert (reload_completed); + + if (REG_P (from)) + { + if (METAG_FPC_REG_P (REGNO (from)) && METAG_ADDR_REG_P (REGNO (to))) + return false; + else if (METAG_ADDR_REG_P (REGNO (from)) && METAG_FPC_REG_P (REGNO (to))) + return false; + } + else if (CONST_INT_P (from)) + { + if (METAG_FPC_REG_P (REGNO (to))) + return false; + } + + return true; +} + +#define builtin_define(TXT) cpp_define (pfile, TXT) +#define builtin_assert(TXT) cpp_assert (pfile, TXT) + +void +metag_cpu_cpp_builtins (cpp_reader *pfile) +{ + switch (metac_target) + { + case METAC_0_1_ID: + builtin_define ("METAC_0_1"); + break; + case METAC_1_0_ID: + builtin_define ("METAC_1_0"); + break; + case METAC_1_1_ID: + builtin_define ("METAC_1_1"); + break; + case METAC_1_2_ID: + builtin_define ("METAC_1_2"); + break; + case METAC_2_1_ID: + builtin_define ("METAC_2_1"); + break; + } + + switch (metacore) + { + case METACORE_METAC_0_1: + builtin_define ("METAC_TUNE_0_1"); + break; + case METACORE_METAC_1_0: + builtin_define ("METAC_TUNE_1_0"); + break; + case METACORE_METAC_1_1: + builtin_define ("METAC_TUNE_1_1"); + break; + case METACORE_METAC_1_2: + builtin_define ("METAC_TUNE_1_2"); + break; + case METACORE_METAC_2_1: + builtin_define ("METAC_TUNE_2_1"); + break; + } + + if (TARGET_FPU) + { + builtin_define ("METAC_FPU_FLOAT"); + + if (TARGET_FPU_SIMD) + builtin_define ("METAC_FPU_LFLOAT"); + + if (!metag_fpu_single) + builtin_define ("METAC_FPU_DOUBLE"); + } + + if (strcmp (metag_charset_string, "basic") == 0) + builtin_define ("strcmp=strcmpbcs"); + + if (TARGET_MINIM) + builtin_define ("METAC_MINIM_ENC"); + + if (metag_memory_width == 32) + builtin_define ("METAC_MEMW_32"); + else if (metag_memory_width == 64) + builtin_define ("METAC_MEMW_64"); + + builtin_define ("__metag__"); + builtin_define ("__METAG__"); + builtin_define ("__METAG"); + + builtin_define ("METAG"); + + builtin_assert ("cpu=metag"); + builtin_assert ("machine=metag"); +} + +void +metag_expand_didf2 (rtx out, rtx in) +{ + rtx dscr = gen_reg_rtx (DImode); + rtx dscrhi = gen_rtx_SUBREG (SImode, dscr, 4); + rtx fscr2 = gen_reg_rtx (DFmode); + rtx fscr2hi_as_si = gen_rtx_SUBREG (SImode, fscr2, 4); + rtx fscr2lo_as_si = gen_rtx_SUBREG (SImode, fscr2, 0); + rtx operands[1]; + + /* Test to see if rs is in the difficult range (> 2^63) */ + emit_move_insn (dscr, in); + metag_compare_op0 = gen_rtx_AND (SImode, dscrhi, + gen_int_mode (0x80000000, SImode)); + metag_compare_op1 = const0_rtx; + gen_metag_compare (NE, operands, 0); + + /* Drop the 2^63 component */ + emit_insn (gen_andsi3 (dscrhi, dscrhi, + gen_int_mode (0x7fffffff, SImode))); + + /* Convert to double */ + emit_insn (gen_floatdidf2 (out, dscr)); + + /* Prepare 2^63 in double precision */ + emit_move_insn (fscr2hi_as_si, + gen_int_mode (0x43e00000, SImode)); + emit_move_insn (fscr2lo_as_si, GEN_INT (0x0)); + + /* Add on the missing 2^63 if requried */ + emit_insn (gen_rtx_SET (VOIDmode, out, + gen_rtx_IF_THEN_ELSE (DFmode, + gen_rtx_NE (VOIDmode, operands[0], + const0_rtx), + gen_rtx_PLUS (DFmode, out, fscr2), + out))); + + +} + +#define PRAGMA_JUMP_TABLE_BRANCH_WARNING() \ + do { \ + warning (OPT_Wpragmas, "Incorrect syntax for '#pragma mjump-table-branch=small|large|auto'"); \ + return; \ + } while (0) + +void +metag_pragma_jump_table_branch (struct cpp_reader* pFile ATTRIBUTE_UNUSED) +{ + tree x; + const char * option = NULL; + + if (pragma_lex (&x) != CPP_MINUS) + PRAGMA_JUMP_TABLE_BRANCH_WARNING (); + + if (pragma_lex (&x) != CPP_NAME || strncmp (IDENTIFIER_POINTER (x), "table", 5) != 0) + PRAGMA_JUMP_TABLE_BRANCH_WARNING (); + + if (pragma_lex (&x) != CPP_MINUS) + PRAGMA_JUMP_TABLE_BRANCH_WARNING (); + + if (pragma_lex (&x) != CPP_NAME || strncmp (IDENTIFIER_POINTER (x), "branch", 6) != 0) + PRAGMA_JUMP_TABLE_BRANCH_WARNING (); + + if (pragma_lex (&x) != CPP_EQ) + PRAGMA_JUMP_TABLE_BRANCH_WARNING (); + + if (pragma_lex (&x) != CPP_NAME) + PRAGMA_JUMP_TABLE_BRANCH_WARNING (); + + option = IDENTIFIER_POINTER (x); + + if (pragma_lex (&x) != CPP_EOF) + PRAGMA_JUMP_TABLE_BRANCH_WARNING (); + + if (strncmp (option, "short", 5) == 0) + metag_jump_table_branch = METAG_MINIM_JUMP_TABLE_BRANCH_SHORT; + else if (strncmp (option, "long", 4) == 0) + metag_jump_table_branch = METAG_MINIM_JUMP_TABLE_BRANCH_LONG; + else if (strncmp (option, "auto", 4) == 0) + metag_jump_table_branch = METAG_MINIM_JUMP_TABLE_BRANCH_AUTO; + else if (strncmp (option, "default", 7) == 0) + { + if (strncmp (metag_jump_table_string, "short", 5) == 0) + metag_jump_table_branch = METAG_MINIM_JUMP_TABLE_BRANCH_SHORT; + else if (strncmp (metag_jump_table_string, "long", 4) == 0) + metag_jump_table_branch = METAG_MINIM_JUMP_TABLE_BRANCH_LONG; + else if (strncmp (metag_jump_table_string, "auto", 4) == 0) + metag_jump_table_branch = METAG_MINIM_JUMP_TABLE_BRANCH_AUTO; + } + else + PRAGMA_JUMP_TABLE_BRANCH_WARNING (); +} + +#define PRAGMA_HWTRACE_SYNTAX_ERROR() \ + do { \ + warning (OPT_Wpragmas, "Incorrect syntax for '#pragma hwtrace_function (func|*,0|1)"); \ + return; \ + } while (0) + + +void +metag_pragma_hwtrace_function (struct cpp_reader* pFile ATTRIBUTE_UNUSED) +{ + tree x; + const char * name = NULL; + int onoff; + + if (pragma_lex (&x) != CPP_OPEN_PAREN) + PRAGMA_HWTRACE_SYNTAX_ERROR (); + + switch (pragma_lex (&x)) + { + case CPP_MULT: + name = "*"; + break; + case CPP_NAME: + name = IDENTIFIER_POINTER (x); + break; + default: + PRAGMA_HWTRACE_SYNTAX_ERROR (); + } + + if (pragma_lex (&x) != CPP_COMMA) + PRAGMA_HWTRACE_SYNTAX_ERROR (); + + if (pragma_lex (&x) != CPP_NUMBER) + PRAGMA_HWTRACE_SYNTAX_ERROR (); + + if (TREE_CODE (x) != INTEGER_CST) + PRAGMA_HWTRACE_SYNTAX_ERROR (); + + onoff = TREE_INT_CST_LOW (x); + + if (pragma_lex (&x) != CPP_CLOSE_PAREN) + PRAGMA_HWTRACE_SYNTAX_ERROR (); + + if (pragma_lex (&x) != CPP_EOF) + PRAGMA_HWTRACE_SYNTAX_ERROR (); + + if (strcmp (name, "*") == 0) + hwtrace_function_default = onoff ? 1 : 0; + else + { + hwtrace_fn * new_fn = xmalloc (sizeof (hwtrace_fn)); + + new_fn->name = xstrdup (name); + new_fn->onoff = onoff ? 1 : 0; + new_fn->next = hwtrace_function_list; + + hwtrace_function_list = new_fn; + } +} + +/* Determine if 'label_ref' refers to a label in the current function */ +void +metag_can_use_short_branch (void) +{ + /* Once we have determined that we can use a short branch there is no need + to check again. We re-do the check if only long branches are allowed + even though the decision will not change */ + if (!cfun->machine->can_use_short_branch) + { + /* Do the analysis */ + rtx insn = next_active_insn (get_insns()); + int count = 0; + + while (insn) + { + rtx body = PATTERN (insn); + /* Inline assembler... Take a best guess at the instruction count + then multiply by 8 to assume all insns need long encodings */ + if (GET_CODE (body) == ASM_INPUT || asm_noperands (body) >= 0) + count += (metag_asm_insn_count (body) << 3); + else if (GET_CODE (body) == ADDR_DIFF_VEC) + { + int i; + /* Add in the branches in jump tables */ + for (i = 0 ; i < XVECLEN (body, 1) ; i++) + { + /* If a label is within the function it 'can' be short + encoded therefore it takes up 4 bytes of PC address + space. If a label is not within the function then + branch tables must be long encoded */ + if (metag_is_label_within_function (XVECEXP (body, 1, i))) + count += 4; + else + { + count += 2049; + break; + } + } + } + else if (GET_CODE (body) != UNSPEC_VOLATILE + || XINT (body, 1) != VUNSPEC_BLOCKAGE) + /* *2 for each instruction to make them 'long' */ + count += (get_attr_length (insn) << 1); + + insn = next_active_insn (insn); + + if (count > 2048) + break; + } + + /* 2048 is the number of bytes in PC address space that a short + branch can jump forward or backwards to. The 'count' variable + conservatively counts the number of bytes in the function + assuming all instructions will be double their stated size, + (double being a long MiniM encoding) */ + + cfun->machine->can_use_short_branch = (count <= 2048); + } +} + +static bool +metag_is_label_within_function (rtx label_ref) +{ + rtx insn = get_insns(); + + while ((insn = next_label (insn)) != 0) + if (CODE_LABEL_NUMBER (insn) == CODE_LABEL_NUMBER (XEXP (label_ref, 0))) + return true; + + return false; +} + +static int +metag_asm_insn_count (rtx body) +{ + const char *template; + int count = 1; + + if (GET_CODE (body) == ASM_INPUT) + template = XSTR (body, 0); + else + template = decode_asm_operands (body, NULL, NULL, NULL, NULL); + + for (; *template; template++) + if (IS_ASM_LOGICAL_LINE_SEPARATOR (*template) || *template == '\n') + count++; + + return count; +} + +/* Generate a conditional branch instruction, inserting the label number for + the return stub */ +char * +metag_gen_cond_return_branch (const char * pattern) +{ + int length = strlen(pattern) + 21; + char * buf = xmalloc (length); + + snprintf (buf, length, pattern, cfun->funcdef_no); + + if (cfun->machine->cond_return_state == METAG_COND_RETURN_NONE) + cfun->machine->cond_return_state = METAG_COND_RETURN_REQD; + + return buf; +} + +/* Generate the return stub instruction inserting the label number for the + return stub */ +char * +metag_gen_cond_return_stub (void) +{ + static const char * pattern = "$LX%d:\n\tMOV\tPC, D1RtP"; + int length = strlen(pattern) + 21; + char * buf = xmalloc (length); + + snprintf (buf, length, pattern, cfun->funcdef_no); + + cfun->machine->cond_return_state = METAG_COND_RETURN_DONE; + + return buf; +} + +/* Create a stub at the end of a function if one is required and not already + emitted. */ +void +metag_emit_cond_return_stub_if_reqd (void) +{ + if (cfun->machine->cond_return_state == METAG_COND_RETURN_REQD) + { + char * stub = metag_gen_cond_return_stub (); + + fputs (stub, asm_out_file); + fputc ('\n', asm_out_file); + cfun->machine->cond_return_state = METAG_COND_RETURN_DONE; + + free (stub); + } +} + +bool +metag_output_addr_const_extra (FILE * stream, rtx x) +{ + if (GET_CODE(x) == CONST_VECTOR && GET_MODE(x) == V2SImode) + { + /* WORK NEEDED: Assert more rigourously that the values are identical */ + gcc_assert (INTVAL (CONST_VECTOR_ELT (x, 0)) == INTVAL (CONST_VECTOR_ELT (x, 1))); + output_addr_const (stream, CONST_VECTOR_ELT (x, 0)); + return true; + } + return false; +} + +/* Produces a rtx representing the return register (D0Re0) using the correct mode. */ +rtx +metag_function_return_reg (enum machine_mode mode) +{ + if (GET_MODE_CLASS (mode) == MODE_INT && GET_MODE_SIZE (mode) < UNITS_PER_WORD) + return gen_rtx_REG (SImode, D0Re0_REG); + else + return gen_rtx_REG (mode, D0Re0_REG); +} + +rtx +metag_libcall_value (enum machine_mode mode) +{ + return metag_function_return_reg (mode); +} + +rtx +metag_function_value (tree ret_type, tree fn_decl_or_type ATTRIBUTE_UNUSED, bool outgoing ATTRIBUTE_UNUSED) +{ + return metag_function_return_reg (TYPE_MODE (ret_type)); +} + +#include "gt-metag.h" diff -Nur gcc-4.2.4.orig/gcc/config/metag/metag.h gcc-4.2.4/gcc/config/metag/metag.h --- gcc-4.2.4.orig/gcc/config/metag/metag.h 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/metag.h 2015-07-03 18:46:05.765283542 -0500 @@ -0,0 +1,1955 @@ +/* Definitions of target machine for GNU compiler. + Imagination Technologies Meta version. + Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 + Imagination Technologies Ltd + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#ifndef __METAG_H_ +#define __METAG_H_ + +#define USE_EH_FRAME_REGISTRY + +/* Which processor to schedule for. The metacore attribute defines a list that + mirrors this list, so changes to metag.md must be made at the same time. */ + +enum processor_type +{ + PROCESSOR_METAC_1_0, + PROCESSOR_METAC_1_1, + PROCESSOR_METAC_1_2, + PROCESSOR_METAC_0_1, + PROCESSOR_METAC_2_1, + PROCESSOR_METAC_MAX +}; + +/* Support for a compile-time default CPU, et cetera. The rules are: + --with-cpu is ignored if -mmetac is specified. + --with-tune is ignored if -mtune is specified. */ +#define OPTION_DEFAULT_SPECS \ + {"cpu", "%{!mmetac=*:-mmetac=%(VALUE)}" }, \ + {"tune", "%{!mtune=*:-mtune=%(VALUE)}" }, \ + {"fpu", "%{mhard-float|mhard-float=*|msoft-float|msimd-float:; :-mhard-float=%(VALUE)}" } \ + +/* Handle the pragma to alter the default jump_table_branch size. */ +#define REGISTER_TARGET_PRAGMAS() \ + do { \ + c_register_pragma (0, "mjump", metag_pragma_jump_table_branch); \ + c_register_pragma (0, "hwtrace_function", metag_pragma_hwtrace_function); \ + } while (0) + +#define SYMBOL_REF_P(RTX) (GET_CODE (RTX) == SYMBOL_REF) +#define LABEL_REF_P(RTX) (GET_CODE (RTX) == LABEL_REF) +#define CONST_DOUBLE_P(RTX) (GET_CODE (RTX) == CONST_DOUBLE) +#define SUBREG_P(RTX) (GET_CODE (RTX) == SUBREG) + +#define TARGET_USE_JCR_SECTION 0 + +#define TARGET_LIBGCC_SDATA_SECTION DATA_SECTION_ASM_OP + +#define TARGET_FAST_MATH fast_math_flags_set_p () + +#define DWARF2_UNWIND_INFO 1 + +#define NUM_EH_RETURN_DATA_REGS \ + (EH_RETURN_LAST_DATA_REG - EH_RETURN_FIRST_DATA_REG + 1) + +#define EH_RETURN_DATA_REGNO(N) \ + ((N) < NUM_EH_RETURN_DATA_REGS \ + ? EH_RETURN_FIRST_DATA_REG + (N) : INVALID_REGNUM) + +#define EH_RETURN_STACKADJ_RTX \ + gen_rtx_REG (SImode, EH_RETURN_STACKADJ_REG) + +#define DWARF_FRAME_REGISTERS (2 + 8 + 3) + +/* An optimisation for reducing the size of an unwind table. Only registers + * that will be present in a frame are included + * + * D1.0 and D1.1 are present as they are the EH_RETURN data registers + * D0FrT and D1RtP because they store the frame pointer and return address + * D1Ar1 -> D0Ar6 are the call save registers + * A1LbP is present as it is the PIC register for META Linux + * A0StP and A0FrP are obvious! + * + * D0.8 is not included as it is not applicable to Linux and the relevant + * code that refers to this table is not currently used in the embedded + * toolchain + */ + +#define DWARF_REG_TO_UNWIND_COLUMN_TABLE \ +static signed char const dwarf_reg_to_unwind_column[FIRST_PSEUDO_REGISTER + 1] =\ +{ \ + /* D0_0/D1_0 ... D0_7/D1_7 */ \ + -1, -1, 0, 1, -1, -1, -1, -1, 2, 3, 4, 5, 6, 7, 8, 9, \ + /* D0_8/D1_8 ... D0_15/D1_15 */ \ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, \ + /* A0_0/A1_0 .. A0_7/A1_7 */ \ + 10, -1, 11, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, \ + /* FRAME ... TXRPT */ \ + -1, -1, -1, -1, -1, -1, -1, -1, -1, \ + /* FX */ \ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, \ + /* TTREC(L) */ \ + -1, -1 \ +} + +#define DWARF_REG_TO_UNWIND_COLUMN(REGNO) \ + dwarf_reg_to_unwind_column[REGNO] + +/* We're using ELF files */ + +#define OBJECT_FORMAT_ELF + +#ifndef CPP_SUBTARGET_SPEC +#define CPP_SUBTARGET_SPEC "" +#endif + +#undef CPP_SPEC +#define CPP_SPEC \ + "%(cpp_cpu_arch) " \ + "%(cpp_subtarget) " \ + "%{pthread: -D_THREAD_SAFE} " + +#define CPP_CPU_ARCH_SPEC "" + +#ifndef SUBTARGET_EXTRA_SPECS +#define SUBTARGET_EXTRA_SPECS +#endif + +#ifndef SUBTARGET_CPP_SPEC +#define SUBTARGET_CPP_SPEC "" +#endif + +/* This macro defines names of additional specifications to put in the specs + that can be used in various specifications like CC1_SPEC. Its definition + is an initializer with a subgrouping for each command option. + + Each subgrouping contains a string constant, that defines the + specification name, and a string constant that used by the GNU CC driver + program. + + Do not define this macro if it does not need to do anything. */ + +#define EXTRA_SPECS \ + { "metac_default", METAC_DEFAULT }, \ + { "cpp_cpu_arch", CPP_CPU_ARCH_SPEC }, \ + { "cpp_subtarget", CPP_SUBTARGET_SPEC }, \ + { "subtarget_cpp_spec", SUBTARGET_CPP_SPEC }, \ + SUBTARGET_EXTRA_SPECS + +/* Run-time compilation parameters selecting different hardware subsets. */ + +extern int frame_pointer_needed; +extern int target_flags; + +/* Define the information needed to expand branch insns. This is stored from + the previous compare operation - which we do not expand at all! */ +extern GTY(()) rtx metag_compare_op0; +extern GTY(()) rtx metag_compare_op1; + +/* Macros used in the machine description to test the flags. */ + +extern int optimize; + +#define TARGET_COND_EXEC_OPTIMIZE (optimize && TARGET_COND_EXEC) +#define TARGET_MINIM_CORE (TARGET_MINIM && TARGET_MINIM_OPTIMISE) + +enum metag_jump_table_branch +{ + METAG_MINIM_JUMP_TABLE_BRANCH_AUTO, + METAG_MINIM_JUMP_TABLE_BRANCH_LONG, + METAG_MINIM_JUMP_TABLE_BRANCH_SHORT +}; + +extern int metag_fpu_single; +extern enum metag_jump_table_branch metag_jump_table_branch; +extern int metag_fpu_resources; +extern int metag_force_tbictxsave; + +/* Access Models + + The __model__ attribute can be used to select the code model to use when + accessing particular objects. */ + +enum metag_model { METAG_MODEL_SMALL, METAG_MODEL_LARGE }; + +extern enum metag_model metag_model; +#define TARGET_MODEL_SMALL (metag_model == METAG_MODEL_SMALL) +#define TARGET_MODEL_LARGE (metag_model == METAG_MODEL_LARGE) + +/* Target options */ +enum metac_target +{ + METAC_1_0_ID, + METAC_1_1_ID, + METAC_1_2_ID, + METAC_0_1_ID, + METAC_2_1_ID +}; + +extern enum metac_target metac_target; + +#define TARGET_METAC_0_1 \ + (metac_target == METAC_0_1_ID) + +#define TARGET_METAC_1_0 \ + (metac_target == METAC_1_0_ID) + +#define TARGET_METAC_1_1 \ + (metac_target == METAC_1_1_ID || metac_target == METAC_1_2_ID || \ + metac_target == METAC_0_1_ID || metac_target == METAC_2_1_ID) + +#define TARGET_METAC_1_2 \ + (metac_target == METAC_1_2_ID || metac_target == METAC_0_1_ID \ + metac_target == METAC_2_1_ID) + +#define TARGET_METAC_2_1 \ + (metac_target == METAC_2_1_ID) + +/* target machine storage layout */ + +/* Define this if most significant bit is lowest numbered + in instructions that operate on numbered bit-fields. */ +#define BITS_BIG_ENDIAN 0 + +/* Define this if most significant byte of a word is the lowest numbered. */ +#define BYTES_BIG_ENDIAN 0 + +/* Define this if most significant word of a multiword is lowest numbered. */ +#define WORDS_BIG_ENDIAN 0 + +/* number of bits in an addressable storage unit */ +#define BITS_PER_UNIT 8 + +/* Width in bits of a "word", which is the contents of a machine register. + Note that this is not necessarily the width of data type `int'; + if using 16-bit ints on a metag, this would still be 32. + But on a machine with 16-bit registers, this would be 16. */ +#define BITS_PER_WORD 32 + +/* Width of a word, in units (bytes). */ +#define UNITS_PER_WORD 4 + +/* Width of a SIMD word, in units (bytes). */ +#define UNITS_PER_SIMD_WORD 8 + +/* Width in bits of a pointer. + See also the macro `Pmode' defined below. */ +#define POINTER_SIZE 32 + +/* Allocation boundary (in *bits*) for storing arguments in argument list. */ +#define PARM_BOUNDARY 32 + +/* Boundary (in *bits*) on which stack pointer should be aligned. */ +#define STACK_BOUNDARY 64 + +#define STACK_BOUNDARY_BYTES (STACK_BOUNDARY / BITS_PER_UNIT) + +#define ALIGN_ON_STACK_BOUNDARY(X) \ + (((X) + STACK_BOUNDARY_BYTES - 1) & ~(STACK_BOUNDARY_BYTES - 1)) + +/* Allocation boundary (in *bits*) for the code of a function. */ +#define FUNCTION_BOUNDARY 32 + +/* Alignment of field after `int : 0' in a structure. */ +#define EMPTY_FIELD_BOUNDARY 32 + +/* No data type wants to be aligned rounder than this. */ +/* metag_emb_asm_select_section asserts that BIGGEST_ALIGNMENT is 64. This is + because a specific section is required for any alignment bigger than 4 + bytes. Currently only 8 byte alignment maximum is supported, anything + greater is ignored and converted to 8 byte alignment. + 1, 2 and 4 byte alignment do not need special sections as the automatic + alignment handling in the assembler will correctly align such sections + depending on the data contained within. Only 8 byte must be explicitly + stated. */ +#define BIGGEST_ALIGNMENT 64 + +/* Every structure's size must be a multiple of this. */ +#define STRUCTURE_SIZE_BOUNDARY 32 + +/* The best alignment to use in cases where we have a choice. */ +#define FASTEST_ALIGNMENT 32 + +/* Make strings 32-bit aligned so strcpy from constants will be faster. */ +#define CONSTANT_ALIGNMENT(EXP, ALIGN) \ + ((TREE_CODE (EXP) == STRING_CST && (ALIGN) < FASTEST_ALIGNMENT) \ + ? FASTEST_ALIGNMENT : (ALIGN)) + +/* Make arrays of chars 32-bit aligned for the same reasons. */ +#define DATA_ALIGNMENT(TYPE, ALIGN) \ + (TREE_CODE (TYPE) == ARRAY_TYPE \ + && TYPE_MODE (TREE_TYPE (TYPE)) == QImode \ + && (ALIGN) < FASTEST_ALIGNMENT ? FASTEST_ALIGNMENT : (ALIGN)) + +/* Make local arrays of chars 32-bit aligned for the same reasons. */ +#define LOCAL_ALIGNMENT(TYPE, ALIGN) \ + (TREE_CODE (TYPE) == ARRAY_TYPE \ + && TYPE_MODE (TREE_TYPE (TYPE)) == QImode \ + && (ALIGN) < FASTEST_ALIGNMENT ? FASTEST_ALIGNMENT : (ALIGN)) + +/* Define this if move instructions will actually fail to work + when given unaligned data. */ +#define STRICT_ALIGNMENT 1 + +/* Define number of bits in most basic integer type. + (If undefined, default is BITS_PER_WORD). */ +#define INT_TYPE_SIZE 32 + +/* Integer bit fields have the same size and alignment as actual integers */ +#define PCC_BITFIELD_TYPE_MATTERS 1 + +/* Specify the size_t type. */ +#define SIZE_TYPE "unsigned int" + +/* Standard register usage. */ + +/* Number of actual hardware registers. + The hardware registers are assigned numbers for the compiler + from 0 to just below FIRST_PSEUDO_REGISTER. + All registers that the compiler knows about must be given numbers, + even those that are not normally considered general registers. */ +#define FIRST_PSEUDO_REGISTER 74 + +/* 1 for registers that have pervasive standard uses + and are not available for the register allocator. */ +#define FIXED_REGISTERS \ +{ \ + /* D0.0/D1.0-D0.7/D1.7 */ \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, \ + /* D0.8/D1.8-D0.15/D1.15 currently reserved */ \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + /* A0.0/A1.0-A0.7/A1.7 */ \ + 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, \ + /* FRAME, CC, ARGP, RAPF, CPC0, CPC1, PC, TXRPT */ \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + /* FX */ \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + /* TTREC(L) */ \ + 1, 1 \ +} + +/* 1 for registers not available across function calls. + These must include the FIXED_REGISTERS and also any + registers that can be used without being saved. + The latter must include the registers where values are returned + and the register where structure-value addresses are passed. + Aside from that, you can include as many other registers as you like. */ +#define CALL_USED_REGISTERS \ +{ \ + /* D0.0/D1.0-D0.7/D1.7 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, \ + /* D0.8-D0.15/D1.8-D1.15 currently reserved */ \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + /* A0.0/A1.0-A0.7/A1.7 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + /* FRAME, CC, ARGP, RAPF, CPC0, CPC1, PC, TXRPT */ \ + 1, 1, 1, 1, 1, 1, 1, 1, \ + /* FX */ \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + /* TTREC(L) */ \ + 1, 1 \ +} + +/* Like `CALL_USED_REGISTERS' except this macro doesn't require that + the entire set of `FIXED_REGISTERS' be included. + (`CALL_USED_REGISTERS' must be a superset of `FIXED_REGISTERS'). + This macro is optional. If not specified, it defaults to the value + of `CALL_USED_REGISTERS'. */ + +#define CALL_REALLY_USED_REGISTERS \ +{ \ + /* D0/D1 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, \ + /* D0/D1 currently reserved */ \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + /* A0/A1 */ \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + /* FRAME, CC, ARGP, RAPF, CPC0, CPC1, PC, TXRPT */ \ + 1, 1, 1, 1, 1, 1, 1, 0, \ + /* FX */ \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + /* TTREC(L) */ \ + 1, 1 \ +} + +/* Make sure everything's fine if we *don't* have a given processor. + This assumes that putting a register in fixed_regs will keep the + compilers mitt's completely off it. We don't bother to zero it out + of register classes. */ +#define CONDITIONAL_REGISTER_USAGE \ + do { \ + static const int bases[] = {16, 17, 40, 41, 0}; \ + static const int strides[] = { 2, 2, 2, 2, 0}; \ + static const int limits[] = { 8, 8, 4, 4, 0}; \ + const char *pmetagopt = metag_extreg_string; \ + int unit; \ + long int fpuregs = strtol (metag_fpureg_string, NULL, 10); \ + bool extended_reg_enabled = false; \ + \ + /* Minimum 3 fpu regs, maximum 16 */ \ + if (fpuregs != 0) \ + { \ + /* The compiler may use FX registers so all sections are FPU*/ \ + metag_fpu_resources = 1; \ + fpuregs = (fpuregs > 16) ? 16 : (fpuregs < 3) ? 3 : fpuregs; \ + } \ + \ + if (strlen (pmetagopt) != 0 && strlen (pmetagopt) != 4) \ + error ("-mextreg takes an argument of four digits"); \ + \ + if (TARGET_METAC_1_1) \ + { \ + /* Don't need temporary registers in AX unit */ \ + fixed_regs[A0_3_REG] = 0; \ + fixed_regs[A1_3_REG] = 0; \ + /* Hence compact default/minimum register set to 8844 for v1.1 */ \ + fixed_regs[A0_4_REG] = 1; \ + fixed_regs[A1_4_REG] = 1; \ + } \ + \ + /* Enabled only the extended regs specified in the extreg string */ \ + for (unit = 0; *pmetagopt != 0 && limits[unit]; unit++) \ + { \ + int add = (*pmetagopt++ - '0'); \ + int reg = bases[unit]; \ + \ + if (add > limits[unit]) \ + add = limits[unit]; \ + \ + while (add-- > 0) \ + { \ + if (TARGET_MTX) \ + error ("MTX does not support extended registers\n"); \ + extended_reg_enabled = true; \ + fixed_regs[reg] = 0; \ + reg += strides[unit]; \ + } \ + } \ + \ + if (extended_reg_enabled && metag_force_tbictxsave) \ + target_flags |= MASK_ECH; \ + \ + if (TARGET_ECH) \ + { \ + if (fixed_regs[METAG_ECH_REGNUM] == 0) \ + fixed_regs[METAG_ECH_REGNUM] = 1; \ + else \ + error ("-mtbictxsave cannot be used unless D0.8 is enabled via -mextreg\n" \ + "Either use -mno-tbictxsave or enable D0.8"); \ + } \ + \ + for ( ; fpuregs > 0 ; fpuregs-- ) \ + fixed_regs[FIRST_FP_REG+fpuregs-1] = 0; \ + \ + if (METAG_FLAG_PIC) \ + fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1 ; \ + } while (0) + +/* Determine which register classes are very likely used by spill registers. + local-alloc.c won't allocate pseudos that have these classes as their + preferred class unless they are "preferred or nothing". */ + +#define CLASS_LIKELY_SPILLED_P(CLASS) \ + (reg_class_size[(int) (CLASS)] == 1 \ + || (CLASS) == A0_REGS \ + || (CLASS) == A1_REGS \ + || (CLASS) == A_REGS \ + || (CLASS) == Ye_REGS \ + || (CLASS) == Yf_REGS \ + || (CLASS) == Yd_REGS \ + || (CLASS) == Yh_REGS \ + || (CLASS) == Yl_REGS \ + || (CLASS) == Ya_REGS \ + || (CLASS) == Yr_REGS) + +/* The order in which registers should be allocated is defined so that the + result registers are treated as the last scratch registers to be used + after the argument registers are used in least likely used first order. + Then we do the call-saved registers and address unit registers in numeric + order - which is the default anyway. */ +#define REG_ALLOC_ORDER \ +{ \ + /* D0.4 happens to be a completely free scratch register */ \ + D0_4_REG, \ + /* If we have tons of free scratch data registers use them first */ \ + D0_8_REG, D1_8_REG, D0_9_REG, D1_9_REG, D0_10_REG, D1_10_REG, \ + D0_11_REG, D1_11_REG, D0_12_REG, D1_12_REG, D0_13_REG, D1_13_REG, \ + D0_14_REG, D1_14_REG, D0_15_REG, D1_15_REG, \ + /* Then use the args and result registers in least-used first order */ \ + /* The D0.1 and D1.1 are however used for 12bit offsets so are */ \ + /* towards the end */ \ + D0_2_REG, D1_2_REG, D0_3_REG, D1_3_REG, \ + D0_1_REG, D1_1_REG, D1_0_REG, D0_0_REG, \ + /* Then use the call-saved registers */ \ + D0_5_REG, D1_5_REG, D0_6_REG, D1_6_REG, D0_7_REG, D1_7_REG, \ + /* Then use the address unit scratch registers */ \ + A0_2_REG, A1_2_REG, A0_3_REG, A1_3_REG, A0_4_REG, A1_4_REG, \ + A0_5_REG, A1_5_REG, A0_6_REG, A1_6_REG, A0_7_REG, A1_7_REG, \ + /* FX - disuade use of FCC_REGS class */ \ + FX_0_REG , FX_1_REG , FX_2_REG , FX_3_REG , \ + FX_4_REG , FX_5_REG , FX_6_REG , FX_7_REG , \ + FX_8_REG , FX_9_REG , FX_10_REG, FX_11_REG, \ + FX_12_REG, FX_13_REG, FX_14_REG, FX_15_REG, \ + TXRPT_REG, TTREC_REG, TTRECL_REG, \ + /* The remainder can never be allocated by the compiler anyway */ \ + D1_4_REG, A0_0_REG, A1_0_REG, A0_1_REG, A1_1_REG, \ + FRAME_REG, CC_REG, ARGP_REG, RAPF_REG, CPC0_REG, CPC1_REG, PC_REG \ +} + +/* Specify the registers used for certain standard purposes. + The values of these macros are register numbers. */ + +/* Register used for the program counter */ +#define PC_REGNUM PC_REG + +/* Logical base register for access to arguments of the function. */ +#define ARG_POINTER_REGNUM ARGP_REG + +/* Condition flag register */ +#define MCC_REGNUM CC_REG + +/* Extended context support register */ +#define METAG_ECH_REGNUM D0_8_REG + +/* Logical base register for access to local variables of the function. */ +#define FRAME_POINTER_REGNUM FRAME_REG + +/* Real frame pointer register */ +#define HARD_FRAME_POINTER_REGNUM A0FrP_REG + +/* First and last register that accepts function arguments, D1.3 - D0.1 */ +#define MIN_METAG_PARM_REGNUM D0Ar6_REG /* Actually contains last arg! */ +#define MAX_METAG_PARM_REGNUM D1Ar1_REG /* Actually contains first arg! */ + +/* The number of registers used for parameter passing. Local to this file. */ +#define MAX_METAG_PARM_REGS (1 + (MAX_METAG_PARM_REGNUM - MIN_METAG_PARM_REGNUM)) +#define MAX_METAG_PARM_BYTES (MAX_METAG_PARM_REGS * UNITS_PER_WORD) + +/* D0.4 is used temporarily to save/restore A0FrP */ +#define TEMP_D0FRT_REGNUM D0FrT_REG + +/* First and last register that is call-saved, D0.5 - D1.7 */ +#define MIN_METAG_CSAVE_REGNUM D0_5_REG +#define MAX_METAG_CSAVE_REGNUM D1_7_REG + +/* Register to use for call/return addresses D1RtP */ +#define RETURN_POINTER_REGNUM D1RtP_REG + +/* Register to use for pushing function arguments. */ +#define STACK_POINTER_REGNUM A0StP_REG + +/* Register in which static-chain is passed to a function. */ +#define GLOBAL_POINTER_REGNUM A1GbP_REG +#define STATIC_CHAIN_REGNUM D0Re0_REG + +/* Some temporaries are currently left for internal library/config use */ +#define A0_SCRATCH (!TARGET_METAC_1_1 ? A0_3_REG : INVALID_REGNUM) +#define A1_SCRATCH (!TARGET_METAC_1_1 ? A1_3_REG : INVALID_REGNUM) + +/* Structure value address is passed is 'hidden' parameter */ +#define STRUCT_VALUE 0 + +#define RAPF_REGNUM RAPF_REG + +#define CPC0_REGNUM CPC0_REG +#define CPC1_REGNUM CPC1_REG + +#define TXRPT_REGNUM TXRPT_REG +#define TTREC_REGNUM TTREC_REG + +#define DECREMENT_AND_BRANCH_REG(MODE) gen_rtx_REG (MODE, TXRPT_REGNUM) + +#define TABLEJUMP_USES_DBRA_REG 0 + +/* Value should be nonzero if functions must have frame pointers. + Zero means the frame pointer need not be set up (and parms + may be accessed via the stack pointer) in functions that seem suitable. + This is computed in `reload', in reload1.c. */ +#define FRAME_POINTER_REQUIRED \ + metag_frame_pointer_required () + +#define SETUP_FRAME_ADDRESSES() \ + metag_setup_frame_addresses () + +/* Definitions for register eliminations. + + This is an array of structures. Each structure initializes one pair + of eliminable registers. The "from" register number is given first, + followed by "to". Eliminations of the same "from" register are listed + in order of preference. + + We have two registers that MUST be eliminated FRAME_POINTER and + ARG_POINTER. ARG_POINTER is ALWAYS eliminated to either STACK_POINTER_REGNUM + or HARD_FRAME_POINTER_REGNUM. FRAME_POINTER is ALWAYS eliminated to either + STACK_POINTER_REGNUM or HARD_FRAME_POINTER_REGNUM. + + STACK_POINTER_REGUM is the preferred elimination. */ + +#define ELIMINABLE_REGS \ +{ \ + {ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ + {ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \ + {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ + {FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM} \ +} + +/* Given FROM and TO register numbers, say whether this elimination is allowed. + Frame pointer elimination is automatically handled. + + Only eliminate down to the HARD_FRAME_POINTER if it's available. */ +#define CAN_ELIMINATE(FROM, TO) \ + (((TO) == STACK_POINTER_REGNUM && frame_pointer_needed) ? 0 : 1) + +/* Define the offset between two registers, one to be eliminated, + and the other its replacement, at the start of a routine. + */ + +#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ + ((OFFSET) = metag_initial_elimination_offset (FROM, TO)) + +/* Return number of consecutive hard regs needed starting at reg REGNO + to hold something of mode MODE. + This is ordinarily the length in words of a value of mode MODE + but can be less for certain modes in special long registers. */ +#define HARD_REGNO_NREGS(REGNO, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + +/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + metag_hard_regno_mode_ok (REGNO, MODE) + +/* Value is 1 if it is a good idea to tie two pseudo registers + when one has mode MODE1 and one has mode MODE2. + If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2, + for any hard reg, then this must be 0 for correct output. */ +#define MODES_TIEABLE_P(MODE1, MODE2) \ + (GET_MODE_CLASS (MODE1) == GET_MODE_CLASS (MODE2)) + +/* Define the classes of registers for register constraints in the + machine description. Also define ranges of constants. + + One of the classes must always be named ALL_REGS and include all hard regs. + If there is more than one class, another class must be named NO_REGS + and contain no registers. + + The name GENERAL_REGS must be the name of a class (or an alias for + another name such as ALL_REGS). This is the class of registers + that is allowed by "g" or "r" in a register constraint. + Also, registers outside this class are allocated only when + instructions express preferences for them. + + The classes must be numbered in nondecreasing order; that is, + a larger-numbered class must never be contained completely + in a smaller-numbered class. + + For any two classes, it is very desirable that there be another + class that represents their union. */ + +enum reg_class +{ + NO_REGS, + Wx_REGS, + WQh_REGS, + WQl_REGS, + Ye_REGS, + Yf_REGS, + Yd_REGS, + Yh_REGS, + Yl_REGS, + Ya_REGS, + Yr_REGS, + D0_REGS, + D1_REGS, + D_REGS, + A0_REGS, + A1_REGS, + A_REGS, + DA_REGS, + Be_REGS, + Bf_REGS, + Bd_REGS, + Bh_REGS, + Bl_REGS, + Ba_REGS, + Br_REGS, + nD0_REGS, + nD1_REGS, + nA0_REGS, + nA1_REGS, + nBU_REGS, + nYe_REGS, + nYf_REGS, + nYd_REGS, + nYh_REGS, + nYl_REGS, + nYa_REGS, + nYr_REGS, + GENERAL_REGS, + FPP_REGS, + FPC_REGS, + cD0_REGS, + cD1_REGS, + cD_REGS, + cA0_REGS, + cA1_REGS, + cA_REGS, + cnD0_REGS, + cnD1_REGS, + cnA0_REGS, + cnA1_REGS, + cDA_REGS, + ALL_REGS, + LIM_REG_CLASSES +}; + +#define N_REG_CLASSES ((int) LIM_REG_CLASSES) + +/* Give names of register classes as strings for dump file. */ + +#define REG_CLASS_NAMES \ +{ \ + "NO_REGS", \ + "Wx_REGS", \ + "WQh_REGS", \ + "WQl_REGS", \ + "Ye_REGS", \ + "Yf_REGS", \ + "Yd_REGS", \ + "Yh_REGS", \ + "Yl_REGS", \ + "Ya_REGS", \ + "Yr_REGS", \ + "D0_REGS", \ + "D1_REGS", \ + "D_REGS", \ + "A0_REGS", \ + "A1_REGS", \ + "A_REGS", \ + "DA_REGS", \ + "Be_REGS", \ + "Bf_REGS", \ + "Bd_REGS", \ + "Bh_REGS", \ + "Bl_REGS", \ + "Ba_REGS", \ + "Br_REGS", \ + "nD0_REGS", \ + "nD1_REGS", \ + "nA0_REGS", \ + "nA1_REGS", \ + "nBU_REGS", \ + "nYe_REGS", \ + "nYf_REGS", \ + "nYd_REGS", \ + "nYh_REGS", \ + "nYl_REGS", \ + "nYa_REGS", \ + "nYr_REGS", \ + "GENERAL_REGS", \ + "FPP_REGS", \ + "FPC_REGS", \ + "cD0_REGS", \ + "cD1_REGS", \ + "cD_REGS", \ + "cA0_REGS", \ + "cA1_REGS", \ + "cA_REGS", \ + "cnD0_REGS", \ + "cnD1_REGS", \ + "cnA0_REGS", \ + "cnA1_REGS", \ + "cDA_REGS", \ + "ALL_REGS" \ +} + +/* Define which registers fit in which classes. + This is an initializer for a vector of HARD_REG_SET + of length N_REG_CLASSES. */ + +#define REG_CLASS_CONTENTS \ +{ \ + { 0x00000000, 0x00000000, 0x00000000 }, /* NO_REGS */ \ + { 0x00000000, 0x00800000, 0x00000300 }, /* Wx_REGS */ \ + { 0x00000000, 0x00000050, 0x00000000 }, /* WQh_REGS */ \ + { 0x00000000, 0x000000a0, 0x00000000 }, /* WQl_REGS */ \ + { 0x00000005, 0x00000000, 0x00000000 }, /* Ye_REGS */ \ + { 0x0000000a, 0x00000000, 0x00000000 }, /* Yf_REGS */ \ + { 0x0000000f, 0x00000000, 0x00000000 }, /* Yd_REGS */ \ + { 0x00000000, 0x00000005, 0x00000000 }, /* Yh_REGS */ \ + { 0x00000000, 0x0000000a, 0x00000000 }, /* Yl_REGS */ \ + { 0x00000000, 0x0000000f, 0x00000000 }, /* Ya_REGS */ \ + { 0x0000000f, 0x0000000f, 0x00000000 }, /* Yr_REGS */ \ + { 0x55555555, 0x00000000, 0x00000000 }, /* D0_REGS */ \ + { 0xaaaaaaaa, 0x00000000, 0x00000000 }, /* D1_REGS */ \ + { 0xffffffff, 0x00000000, 0x00000000 }, /* D_REGS */ \ + { 0x00000000, 0x00005555, 0x00000000 }, /* A0_REGS */ \ + { 0x00000000, 0x0000aaaa, 0x00000000 }, /* A1_REGS */ \ + { 0x00000000, 0x0000ffff, 0x00000000 }, /* A_REGS */ \ + { 0xffffffff, 0x0000ffff, 0x00000000 }, /* DA_REGS */ \ + { 0x5555ffff, 0x0000ffff, 0x00000000 }, /* Be_REGS */ \ + { 0xaaaaffff, 0x0000ffff, 0x00000000 }, /* Bf_REGS */ \ + { 0x0000ffff, 0x0000ffff, 0x00000000 }, /* Bd_REGS */ \ + { 0x0000ffff, 0x0000ffff, 0x00000000 }, /* Bh_REGS */ \ + { 0x0000ffff, 0x0000ffff, 0x00000000 }, /* Bl_REGS */ \ + { 0x0000ffff, 0x0000ffff, 0x00000000 }, /* Ba_REGS */ \ + { 0x0000ffff, 0x0000ffff, 0x00000000 }, /* Br_REGS */ \ + { 0xaaaaaaaa, 0x0000ffff, 0x00000000 }, /* nD0_REGS */ \ + { 0x55555555, 0x0000ffff, 0x00000000 }, /* nD1_REGS */ \ + { 0xffffffff, 0x0000aaaa, 0x00000000 }, /* nA0_REGS */ \ + { 0xffffffff, 0x00005555, 0x00000000 }, /* nA1_REGS */ \ + { 0xffff0000, 0x00000000, 0x00000000 }, /* nBU_REGS */ \ + { 0xfffffffa, 0x0000ffff, 0x00000000 }, /* nYe_REGS */ \ + { 0xfffffff5, 0x0000ffff, 0x00000000 }, /* nYf_REGS */ \ + { 0xfffffff0, 0x0000ffff, 0x00000000 }, /* nYd_REGS */ \ + { 0xffffffff, 0x0000fffa, 0x00000000 }, /* nYh_REGS */ \ + { 0xffffffff, 0x0000fff5, 0x00000000 }, /* nYl_REGS */ \ + { 0xffffffff, 0x0000fff0, 0x00000000 }, /* nYa_REGS */ \ + { 0xfffffff0, 0x0000fff0, 0x00000000 }, /* nYr_REGS */ \ + { 0xffffffff, 0x0000ffff, 0x00000000 }, /* GENERAL_REGS */ \ + { 0x00000000, 0x55000000, 0x00000055 }, /* FPP_REGS */ \ + { 0x00000000, 0xff000000, 0x000000ff }, /* FPC_REGS */ \ + { 0x55555555, 0xff000000, 0x000000ff }, /* cD0_REGS */ \ + { 0xaaaaaaaa, 0xff000000, 0x000000ff }, /* cD1_REGS */ \ + { 0xffffffff, 0xff000000, 0x000000ff }, /* cD_REGS */ \ + { 0x00000000, 0xff005555, 0x000000ff }, /* cA0_REGS */ \ + { 0x00000000, 0xff00aaaa, 0x000000ff }, /* cA1_REGS */ \ + { 0x00000000, 0xff00ffff, 0x000000ff }, /* cA_REGS */ \ + { 0xaaaaaaaa, 0xff00ffff, 0x000000ff }, /* cnD0_REGS */ \ + { 0x55555555, 0xff00ffff, 0x000000ff }, /* cnD1_REGS */ \ + { 0xffffffff, 0xff00aaaa, 0x000000ff }, /* cnA0_REGS */ \ + { 0xffffffff, 0xff005555, 0x000000ff }, /* cnA1_REGS */ \ + { 0xffffffff, 0xff00ffff, 0x000000ff }, /* cDA_REGS */ \ + { 0xffffffff, 0xff80ffff, 0x000003ff } /* ALL_REGS */ \ +} + +/* The same information, inverted: + Return the class number of the smallest class containing + reg number REGNO. This could be a conditional expression + or could index an array. */ + +#define REGNO_REG_CLASS(REGNO) \ + metag_regno_reg_class_minimal (REGNO) + +#define METAG_REGNO_REG_CLASS(REGNO) \ + metag_regno_reg_class_unit (REGNO) + +#define METAG_REGNO_SAME_UNIT(REGNUM1, REGNUM2) \ + metag_regno_same_unit_p (REGNUM1, REGNUM2) + +/* The class value for index registers, and the one for base regs. */ +#define INDEX_REG_CLASS NO_REGS +#define BASE_REG_CLASS GENERAL_REGS + +#define IN_RANGE_P(VALUE, LOW, HIGH) \ + ((LOW) <= (VALUE) && (VALUE) <= (HIGH)) + +#define METAG_CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) 0 + +/* Define the cost of moving between registers of various classes. */ +#define REGISTER_MOVE_COST(MODE, CLASS1, CLASS2) \ + ((int)(CLASS1) == (int)(CLASS2) ? 1 : 4 ) + +/* A C expressions returning the cost of moving data of MODE from a register to + or from memory. Keep it higher than max register/register costs */ +#define MEMORY_MOVE_COST(MODE, CLASS, IN) 8 + +/* Given an rtx X being reloaded into a reg required to be + in class CLASS, return the class of reg to actually use. + In general this is just CLASS; but on some machines + in some cases it is preferable to use a more restrictive class. */ +#define PREFERRED_RELOAD_CLASS(X, CLASS) (CLASS) + +#define SECONDARY_INPUT_RELOAD_CLASS(CLASS, MODE, X) \ + metag_secondary_reload_class (CLASS, MODE, X, true) + +#define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS, MODE, X) \ + metag_secondary_reload_class (CLASS, MODE, X, false) + +/* Return the maximum number of consecutive registers + needed to represent mode MODE in a register of class CLASS. */ +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + +/* Stack layout; function entry, exit and calling. */ + +/* Define this if pushing a word on the stack + makes the stack pointer a smaller address. */ +/*#define STACK_GROWS_DOWNWARD*/ + +/* Define this if the nominal address of the stack frame + is at the high-address end of the local variables; + that is, each additional local variable allocated + goes at a more negative offset in the frame. */ +/* #define FRAME_GROWS_DOWNWARD */ + +#define ARGS_GROW_DOWNWARD + +/* We use post increment on metag because of 64-bit vs 32-bit alignments */ +#define STACK_PUSH_CODE POST_INC + +/* Offset within stack frame to start allocating local variables at. + If FRAME_GROWS_DOWNWARD, this is the offset to the END of the + first local allocated. Otherwise, it is the offset to the BEGINNING + of the first local allocated. */ +#define STARTING_FRAME_OFFSET 0 + +/* This points to the location of dynamically allocated memory on the stack + immediately after the stack pointer has been adjusted by the amount of + memory desired. */ +#define STACK_DYNAMIC_OFFSET(FNDECL) \ + (-(current_function_outgoing_args_size + (STACK_POINTER_OFFSET))) + +/* If we generate an insn to push BYTES bytes, + this says how many the stack pointer really advances by. + (incompatible with ACCUMULATE_OUTGOING_ARGS) +#define PUSH_ROUNDING(BYTES) (((BYTES) + 3) & ~3) */ + +/* If nonzero, the maximum amount of space required for outgoing arguments will be + computed and placed into the variable current_function_outgoing_args_size. No space + will be pushed onto the stack for each call; instead, the function prologue should + increase the stack frame size by this amount. Setting both PUSH_ARGS and + ACCUMULATE_OUTGOING_ARGS is not proper. +*/ +#define ACCUMULATE_OUTGOING_ARGS 1 + +/* Offset of first parameter from the argument pointer register value. */ +#define FIRST_PARM_OFFSET(FNDECL) \ + metag_first_parm_offset (FNDECL) + +/* A C expression whose value is RTL representing the value of the return + address for the frame COUNT steps up from the current frame. */ + +#define RETURN_ADDR_RTX(COUNT, FRAME) \ + metag_return_addr_rtx (COUNT, FRAME) + +/* Value is 1 if returning from a function call automatically + pops the arguments described by the number-of-args field in the call. + FUNDECL is the declaration node of the function (as a tree), + FUNTYPE is the data type of the function (as a tree), + or for a library call it is an identifier node for the subroutine name. */ + +#define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, SIZE) (0) + +/* Define how to find the value returned by a library function + assuming the value has mode MODE. */ + +/* On the metag the return value is in D0.0/D1.0 regardless. */ + +#define LIBCALL_VALUE(MODE) metag_libcall_value (MODE) + +/* 1 if N is a possible register number for a function value. + On the metag, D1.0/D1.1 is the only register thus used. */ + +#define FUNCTION_VALUE_REGNO_P(N) ((N) == 0) + +/* A C expression which can inhibit the returning of certain function values + in registers, based on the type of value. A nonzero value says to return + the function value in memory, just as large structures are always + returned. Here type will be a C expression of type tree, representing the + data type of the value. We target all 64-bit or less structures as return + in registers. */ +#define RETURN_IN_MEMORY(TYPE) metag_return_in_memory (TYPE) + +/* Define this macro to be 1 if all structure and union return values must be + in memory. We want 64-bit structs to return in registers under the control + of the RETURN_IN_MEMORY macro. */ +#define DEFAULT_PCC_STRUCT_RETURN 0 + +/* 1 if N is a possible register number for function argument passing. */ +#define FUNCTION_ARG_REGNO_P(N) \ + (MIN_METAG_PARM_REGNUM <= (N) && (N) <= MAX_METAG_PARM_REGNUM) + +/* Define a data type for recording info about an argument list + during the scan of that argument list. This data type should + hold all necessary information about the function itself + and about the args processed so far, enough to enable macros + such as FUNCTION_ARG to determine where the next arg should go. + + On the metag, this is a single integer, which is a number of bytes + of arguments scanned so far. */ +struct cumulative_args +{ + int narg; + int partial; +}; + +#define CUMULATIVE_ARGS struct cumulative_args + +/* Initialize a variable CUM of type CUMULATIVE_ARGS + for a call to a function whose data type is FNTYPE. + For a library call, FNTYPE is 0. */ +#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS) \ + ((CUM).narg = 0, (CUM).partial = 0) + +/* Round VALUE up to next multiple of SIZE (Assumes SIZE is 2^N for some N */ +#define ROUND_TO_SIZE(VALUE, SIZE) \ + (((VALUE) + (SIZE) - 1) & ~((SIZE) - 1)) + +/* Round VALUE up to a double word boundary */ +#define ROUND_TO_DWORD(VALUE) \ + ROUND_TO_SIZE (VALUE, 2 * UNITS_PER_WORD) + +/* Round VALUE up to a word boundary */ +#define ROUND_TO_WORD(VALUE) \ + ROUND_TO_SIZE (VALUE, UNITS_PER_WORD) + +/* Round VALUE up to a word boundary */ +#define ROUND_ADVANCE(VALUE) \ + ROUND_TO_WORD (VALUE) + +/* Argument size rounded up to word size. */ +#define METAG_ARG_SIZE(MODE, TYPE) \ + ((MODE) == BLKmode \ + ? ROUND_TO_WORD (int_size_in_bytes (TYPE)) \ + : ROUND_TO_WORD (GET_MODE_SIZE (MODE))) + +/* Round arg MODE/TYPE up to the next word boundary. */ +#define ROUND_ADVANCE_ARG(MODE, TYPE) \ + METAG_ARG_SIZE (MODE, TYPE) + +/* Round CUM up to the necessary point for argument MODE/TYPE. */ +#define ROUND_ADVANCE_CUM(CUM, MODE, TYPE) \ + (METAG_ARG_SIZE (MODE, TYPE) > UNITS_PER_WORD \ + ? (ROUND_TO_DWORD ((CUM) + METAG_ARG_SIZE (MODE, TYPE)) \ + - METAG_ARG_SIZE (MODE, TYPE)) \ + : (CUM)) + +/* Offset base register by one for 64-bit atomic values and the whole size of + struct/union parameters */ +#define ROUND_BASEREG_NUM(MODE, TYPE) \ + ((ROUND_ADVANCE_ARG (MODE, TYPE) / UNITS_PER_WORD) - 1) + +/* Update the data in CUM to advance over an argument of mode MODE and data + type TYPE. TYPE is null for libcalls where that information may not be + available. */ +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + metag_function_arg_advance (&(CUM), MODE, TYPE, NAMED) + +/* Calculate register to place argument. align correctly for 64-bit data */ +#define CALCULATE_REG(BASE_REG, CUM, MODE, TYPE) \ + ((BASE_REG) - ((ROUND_ADVANCE_CUM (CUM, MODE, TYPE) / UNITS_PER_WORD) \ + + ROUND_BASEREG_NUM (MODE, TYPE))) + +/* Define where to put the arguments to a function. + Value is zero to push the argument on the stack, + or a hard register in which to store the argument. + + MODE is the argument's machine mode. + TYPE is the data type of the argument (as a tree). + This is null for libcalls where that information may + not be available. + CUM is a variable of type CUMULATIVE_ARGS which gives info about + the preceding args and about the function being called. + NAMED is nonzero if this argument is a named parameter + (otherwise it is an extra parameter matching an ellipsis). */ + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ + metag_function_arg (&(CUM), MODE, TYPE, NAMED) + +/* Defined if some argument types need more than PARM_BOUNDARY alignment */ +#define FUNCTION_ARG_BOUNDARY(MODE, TYPE) \ + metag_function_arg_boundary (MODE, TYPE) + +/* Perform any actions needed for a function that is receiving a variable number + of arguments. CUM is as above. MODE and TYPE are the mode and type of the + current parameter. PRETEND_SIZE is a variable that should be set to the amount + of stack that must be pushed by the prologue to pretend that our caller pushed + it. + + Normally, this macro will push all remaining incoming registers on the stack + and set PRETEND_SIZE to the length of the registers pushed. + + On Metag, PRETEND_SIZE is set in order to have the prologue push the last + named argument and all anonymous arguments onto the stack .*/ + +/* Don't output profile counters. */ +#define NO_PROFILE_COUNTERS 1 + +/* Output assembler code to FILE to increment profiler label # LABELNO + for profiling a function entry. */ + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + do { \ + if (!TARGET_HWTRACE) \ + metag_function_profiler (FILE); \ + } while (0) + +/* Output assembler code to FILE to initialize this source file's + basic block profiling info, if that has not already been done. */ + +#define FIXME_FUNCTION_BLOCK_PROFILER(FILE, LABELNO) \ + fprintf (FILE, ASM_COMMENT_START " block profile code %u\n", (LABELNO)) + +/* Output assembler code to FILE to increment the entry-count for + the BLOCKNO'th basic block in this source file. */ + +#define FIXME_BLOCK_PROFILER(FILE, BLOCKNO) \ + fprintf (FILE, ASM_COMMENT_START " profile code %u\n", 4 * (BLOCKNO)) + +/* EXIT_IGNORE_STACK should be nonzero if, when returning from a function, + the stack pointer does not matter. The value is tested only in + functions that have frame pointers. + No definition is equivalent to always zero. */ +#define EXIT_IGNORE_STACK 1 + +/* Determine if the epilogue should be output as RTL. + You should override this if you define FUNCTION_EXTRA_EPILOGUE. */ +#define METAG_CHEAP_RETURN metag_cheap_return + +#if 1 +#define TRAMPOLINE_SECTION text_section + +/* Output assembler code for a block containing the constant parts + of a trampoline, leaving space for the variable parts. */ + +/* On the metag, the trampoline contains 4 instructions + 2 data words: + MOV TEMP_D0FRT_REGNUM, PC + GETD STATIC_CHAIN_REGNUM, [TEMP_D0FRT_REGNUM + #(16 - 4)] + GETD TEMP_D0FRT_REGNUM, [TEMP_D0FRT_REGNUM + #(20 - 4)] + MOV PC, TEMP_D0FRT_REGNUM + .long + .long + */ + +/* Define offsets from start of Trampoline for the dynamic static + chain and function address data words. */ +#define TRAMP_SC_OFFSET 16 /* Static chain offset. */ +#define TRAMP_FN_OFFSET 20 /* Function address offset. */ + +#define TRAMPOLINE_TEMPLATE(FILE) \ +do { \ + const char * const scratch = reg_names[TEMP_D0FRT_REGNUM]; \ + const char * const chain = reg_names[STATIC_CHAIN_REGNUM]; \ + \ + fprintf (FILE, "\tMOV\t%s, PC\n", scratch); \ + fprintf (FILE, "\tGETD\t%s, [%s + #%d]\n", \ + chain, scratch, TRAMP_SC_OFFSET - 4); \ + fprintf (FILE, "\tGETD\t%s, [%s + #%d]\n", \ + scratch, scratch, TRAMP_FN_OFFSET - 4); \ + fprintf (FILE, "\tMOV\tPC, %s\n", scratch); \ + fputs (targetm.asm_out.aligned_op.si, FILE); \ + fputs ("\t0\n", FILE); \ + fputs (targetm.asm_out.aligned_op.si, FILE); \ + fputs ("\t0\n", FILE); \ +} while (0) + +/* Length in units of the trampoline for entering a nested function. */ + +#define TRAMPOLINE_SIZE (UNITS_PER_WORD * 6) + +/* Emit RTL insns to initialize the variable parts of a trampoline. + FNADDR is an RTX for the address of the function's pure code. + CXT is an RTX for the static chain value for the function. */ + +#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \ +do { \ + if (!TARGET_MTX) \ + { \ + if (!TARGET_MINIM) \ + { \ + emit_move_insn (gen_rtx_MEM (SImode, \ + plus_constant (TRAMP, TRAMP_SC_OFFSET)), \ + CXT); \ + emit_move_insn (gen_rtx_MEM (SImode, \ + plus_constant (TRAMP, TRAMP_FN_OFFSET)), \ + FNADDR); \ + } \ + else \ + error ("GNU C nested C function extension not supported for MiniM.\n");\ + } \ + else \ + error ("GNU C nested C function extension not supported.\n"); \ +} while (0) + +#endif + + +/* Initialize data used by insn expanders. This is called from insn_emit, + once for every function before code is generated. */ + +#define INIT_EXPANDERS metag_init_expanders () + +/* Addressing modes, and classification of registers for them. */ + +#define HAVE_PRE_INCREMENT 1 +#define HAVE_POST_INCREMENT 1 +#define HAVE_PRE_DECREMENT 1 +#define HAVE_POST_DECREMENT 1 + +#define HAVE_PRE_MODIFY_REG 1 +#define HAVE_POST_MODIFY_REG 1 +#define HAVE_PRE_MODIFY_DISP 1 +#define HAVE_POST_MODIFY_DISP 1 + +/* Macros to check register numbers against specific register classes. */ + +/* These assume that REGNO is a hard or pseudo reg number. + They give nonzero only if REGNO is a hard reg of the suitable class + or a pseudo reg currently allocated to a suitable hard reg. + Since they use reg_renumber, they are safe only once reg_renumber + has been allocated, which happens in local-alloc.c. */ + +#define REGNO_OK_FOR_INDEX_P(REGNO) \ + FALSE /* REGNO_OK_FOR_BASE_P (REGNO) */ + +#define TEST_REGNO(R, OP, VALUE) \ + (((unsigned)(R) OP (VALUE)) || (unsigned)reg_renumber[R] OP (VALUE)) + +#define REGNO_OK_FOR_BASE_P(REGNO) \ + (TEST_REGNO (REGNO, <=, FRAME_POINTER_REGNUM) \ + || TEST_REGNO (REGNO, ==, ARG_POINTER_REGNUM)) + +/* Maximum number of registers that can appear in a valid memory address. */ +#define MAX_REGS_PER_ADDRESS 2 + +/* Recognize any constant value that is a valid address. */ + +#define CONSTANT_ADDRESS_P(X) \ + (LABEL_REF_P (X) \ + || SYMBOL_REF_P (X) \ + || CONST_INT_P (X) \ + || GET_CODE (X) == CONST) + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. + + TODO: This will need to be changed (see definition in metag-linux.h) + when implementing TLS for the embedded toolchain. + */ + +#define LEGITIMATE_CONSTANT_P(X) 1 + +/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx + and check its validity for a certain class. + We have two alternate definitions for each of them. + The usual definition accepts all pseudo regs; the other rejects + them unless they have been allocated suitable hard regs. + The symbol REG_OK_STRICT causes the latter definition to be used. + + Most source files want to accept pseudo regs in the hope that + they will get allocated to the class that the insn wants them to be in. + Source files for reload pass need to be strict. + After reload, it makes no difference, since pseudo regs have + been eliminated by then. */ + +#ifndef REG_OK_STRICT +#define REG_OK_STRICT_FLAG FALSE +#else +#define REG_OK_STRICT_FLAG TRUE +#endif + +/* -------------------------------- BEGIN NONSTRICT ------------------------ */ + +#define NONSTRICT_REGNO_OK_P(R) \ + METAG_LEGITIMATE_REGNO_P (R, false) + +#define NONSTRICT_REG_OK_P(R) \ + METAG_LEGITIMATE_REG_P (R, false) + +/* Nonzero if X is a hard reg that can be used as an index + or if it is a pseudo reg. */ +#define NONSTRICT_REG_OK_FOR_INDEX_P(X) \ + FALSE /* NONSTRICT_REGNO_OK_P (REGNO (X)) */ + +/* Nonzero if X is a hard reg that can be used as a base reg + or if it is a pseudo reg. */ +#define NONSTRICT_REG_OK_FOR_BASE_P(X) \ + FALSE /* NONSTRICT_REGNO_OK_P (REGNO (X)) */ + +/* Nonzero if X is a hard reg that can be used as a base reg + or if it is a pseudo reg. */ +#define NONSTRICT_REG_OK_FOR_OFFSET_P(X) \ + NONSTRICT_REG_OK_P (X) + +/* Nonzero if the pair of hard regs are okay to use as base + offset + or if either is a psuedo reg. */ +#define NONSTRICT_REGS_OK_FOR_BASE_OFFSET_P(X, Y) \ + METAG_REGS_OK_FOR_BASE_OFFSET_P (X, Y, false) + +/* ---------------------------------- END NONSTRICT ------------------------ */ + +/* ----------------------------------- BEGIN STRICT ------------------------ */ + +#define STRICT_REGNO_OK_P(R) \ + METAG_LEGITIMATE_REGNO_P (R, true) + +#define STRICT_REG_OK_P(R) \ + METAG_LEGITIMATE_REG_P (R, false) + +/* Nonzero if X is a hard reg that can be used as an index. */ +#define STRICT_REG_OK_FOR_INDEX_P(X) \ + FALSE /* STRICT_REGNO_OK_P (REGNO (X)) */ + +/* Nonzero if X is a hard reg that can be used as a base reg. */ +#define STRICT_REG_OK_FOR_BASE_P(X) \ + FALSE /* STRICT_REGNO_OK_P (REGNO (X)) */ + +/* Nonzero if X is a hard reg that can be used as a base reg. */ +#define STRICT_REG_OK_FOR_OFFSET_P(X) \ + STRICT_REG_OK_P (X) + +/* Nonzero if the pair of hard regs is okay to use as base + offset */ +#define STRICT_REGS_OK_FOR_BASE_OFFSET_P(X, Y) \ + METAG_REGS_OK_FOR_BASE_OFFSET_P (X, Y, true) + +/* ------------------------------------ END STRICT ------------------------- */ + +/* Nonzero if X is a hard reg that can be used as an index + or if it is a pseudo reg. */ +#define REG_OK_FOR_INDEX_P(X) \ + METAG_REG_OK_FOR_INDEX_P (X, REG_OK_STRICT_FLAG) + +#define METAG_REG_OK_FOR_INDEX_P(X, STRICT) \ + metag_reg_ok_for_index_p (X, STRICT) + +/* Nonzero if X is a hard reg that can be used as a base reg. */ +#define REG_OK_FOR_BASE_P(X) \ + METAG_REG_OK_FOR_BASE_P (X, REG_OK_STRICT_FLAG) + +#define METAG_REG_OK_FOR_BASE_P(X, STRICT) \ + metag_reg_ok_for_base_p (X, STRICT) + +/* Nonzero if X is a hard reg that can be used as a base reg. */ +#define REG_OK_FOR_OFFSET_P(X) \ + METAG_REG_OK_FOR_OFFSET_P (X, REG_OK_STRICT_FLAG) + +#define METAG_REG_OK_FOR_OFFSET_P(X, STRICT) \ + metag_reg_ok_for_offset_p (X, STRICT) + +/* Nonzero if the pair of hard regs is okay to use as base + offset */ +#define METAG_REGS_OK_FOR_BASE_OFFSET_P(X, Y, STRICT) \ + metag_regs_ok_for_base_offset_p (X, Y, STRICT) + +/* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression + that is a valid memory address for an instruction. + The MODE argument is the machine mode for the MEM expression + that wants to use this address. */ + +#define METAG_LEGITIMATE_REGNO_P(REGNUM, STRICT) \ + metag_legitimate_regno_p (REGNUM, STRICT) + +#define METAG_LEGITIMATE_REG_P(REG, STRICT) \ + metag_legitimate_reg_p (REG, STRICT) + +/* PRE_MODIFY */ +#define METAG_LEGITIMATE_PRE_MODIFY_P(ADDR, MODE, STRICT) \ + (GET_CODE (ADDR) == PRE_MODIFY \ + && metag_legitimate_modify_p (ADDR, MODE, STRICT)) + +/* POST_MODIFY */ +#define METAG_LEGITIMATE_POST_MODIFY_P(ADDR, MODE, STRICT) \ + (GET_CODE (ADDR) == POST_MODIFY \ + && metag_legitimate_modify_p (ADDR, MODE, STRICT)) + +/* PRE_INC/PRE_DEC supportable */ +#define METAG_LEGITIMATE_PRE_INCDEC_P(ADDR, MODE, STRICT) \ + metag_legitimate_pre_incdec_p (ADDR, MODE, STRICT) + +/* POST_INC/POST_DEC supportable */ +#define METAG_LEGITIMATE_POST_INCDEC_P(ADDR, MODE, STRICT) \ + metag_legitimate_post_incdec_p (ADDR, MODE, STRICT) + +/* Two ranges of offset are supported dependant on base & mode */ +#define METAG_LEGITIMATE_OFF_P(BASE, OFF, MODE, STRICT) \ + metag_legitimate_off_p (BASE, OFF, MODE, STRICT) + +/* [ Rb + Ro ] */ +#define METAG_LEGITIMATE_TWIN_P(BASE, OFF, MODE, STRICT) \ + metag_legitimate_twin_p (BASE, OFF, MODE, STRICT) + +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, LABEL) \ + do { \ + if (metag_legitimate_address_p (X, MODE, REG_OK_STRICT_FLAG)) \ + goto LABEL; \ + } while (0) + +#define SYMBOLIC_CONST(X) \ + (SYMBOL_REF_P (X) \ + || LABEL_REF_P (X) \ + || (GET_CODE (X) == CONST && metag_symbolic_reference_mentioned_p (X))) + +/* Go to LABEL if ADDR (a legitimate address expression) + has an effect that depends on the machine mode it is used for. */ +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) \ + do { \ + if ( GET_CODE (ADDR) == PRE_DEC \ + || GET_CODE (ADDR) == POST_DEC \ + || GET_CODE (ADDR) == PRE_INC \ + || GET_CODE (ADDR) == POST_INC \ + || GET_CODE (ADDR) == PRE_MODIFY \ + || GET_CODE (ADDR) == POST_MODIFY) \ + goto LABEL; \ + } while (0) + +/* Specify the machine mode that this machine uses + for the index in the tablejump instruction. */ +#define CASE_VECTOR_MODE SImode + +/* Define as C expression which evaluates to nonzero if the tablejump + instruction expects the table to contain offsets from the address of the + table. */ +#define CASE_VECTOR_PC_RELATIVE 1 + +/* Define this as 1 if `char' should by default be signed; else as 0. */ +#define DEFAULT_SIGNED_CHAR 0 + +/* Max number of bytes we can move from memory to memory + in one reasonably fast instruction. */ +#define MOVE_MAX 4 + +/* Nonzero if access to memory by bytes is the same speed as words */ +#define SLOW_BYTE_ACCESS 1 + +/* Define this to be nonzero if shift instructions ignore all but the low-order + few bits. */ +#define SHIFT_COUNT_TRUNCATED 1 + +/* Value is 1 if truncating an integer of INPREC bits to OUTPREC bits + is done just by pretending it is already truncated. */ +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 + +/* Define if loading in MODE, an integral mode narrower than BITS_PER_WORD + will either zero-extend or sign-extend. The value of this macro should + be the code that says which one of the two operations is implicitly + done, NIL if none. */ +#define LOAD_EXTEND_OP(MODE) ZERO_EXTEND + +/* We assume that the store-condition-codes instructions store 0 for false + and some other value for true. This is the value stored for true. */ +/* #define STORE_FLAG_VALUE -1 */ + +/* Define this macro if it is advisable to hold scalars in registers + in a wider mode than that declared by the program. In such cases, + the value is constrained to be within the bounds of the declared + type, but kept valid in the wider mode. The signedness of the + extension may differ from that of the type. It is faster to + zero extend chars than to sign extend them on META, with 16 bit + values it's less obvious */ +#define PROMOTE_MODE(MODE, UNSIGNEDP, TYPE) \ + do { \ + if (GET_MODE_CLASS (MODE) == MODE_INT \ + && GET_MODE_SIZE (MODE) < UNITS_PER_WORD) \ + (MODE) = SImode; \ + } while (0) + +/* Specify the machine mode that pointers have. + After generation of rtl, the compiler makes no further distinction + between pointers and any other objects of this machine mode. */ +#define Pmode SImode + +/* A function address in a call instruction + is a byte address (for indexing purposes) + so give the MEM rtx a byte's mode. */ +#define FUNCTION_MODE QImode + +/* Try to generate sequences that don't involve branches; enables cc insts */ +#define BRANCH_COST 3 + +/* Comparison extensions- + + CC_NOOVmode is used when the state of the overflow flag is irrelavent to + the compare case - e.g. comparison against zero is required. + + CC_Zmode is used as a more refined case of CC_NOOVmode where only the zero + flag is relevant. For example if a HI or QI source value is being tested + directly and the condition in EQ or NE in this case it's left to the + pattern to check for other factors like zero as rhs of comparison. + +*/ + +#define SELECT_CC_MODE(OP, X, Y) \ + metag_select_cc_mode ((OP), (X), (Y)) + +#define REVERSIBLE_CC_MODE(MODE) (1) + +#define REVERSE_CONDITION(CODE, MODE) \ + (((MODE) != CC_FPmode && (MODE) != CC_FP_Qmode) ? reverse_condition (CODE) \ + : reverse_condition_maybe_unordered (CODE)) + +/* Output to assembler file text saying following lines + may contain character constants, extra white space, comments, etc. */ + +#define ASM_APP_ON "" + +/* Output to assembler file text saying following lines + no longer contain unusual constructs. */ + +#define ASM_APP_OFF "" + + + +#define METAG_SYMBOL_FLAG_DIRECT (SYMBOL_FLAG_MACH_DEP << 0) +#define METAG_SYMBOL_FLAG_DIRECT_P(SYMBOL) \ + ((SYMBOL_REF_FLAGS (SYMBOL) & METAG_SYMBOL_FLAG_DIRECT) != 0) + +#define METAG_SYMBOL_FLAG_SMALL (SYMBOL_FLAG_MACH_DEP << 1) +#define METAG_SYMBOL_FLAG_SMALL_P(SYMBOL) \ + ((SYMBOL_REF_FLAGS (SYMBOL) & METAG_SYMBOL_FLAG_SMALL) != 0) + +#define METAG_SYMBOL_FLAG_LARGE (SYMBOL_FLAG_MACH_DEP << 2) +#define METAG_SYMBOL_FLAG_LARGE_P(SYMBOL) \ + ((SYMBOL_REF_FLAGS (SYMBOL) & METAG_SYMBOL_FLAG_LARGE) != 0) + +#define METAG_SYMBOL_FLAG_GLOBAL (SYMBOL_FLAG_MACH_DEP << 3) +#define METAG_SYMBOL_FLAG_GLOBAL_P(SYMBOL) \ + ((SYMBOL_REF_FLAGS (SYMBOL) & METAG_SYMBOL_FLAG_GLOBAL) != 0) + +#define METAG_SYMBOL_FLAG_BYTE (SYMBOL_FLAG_MACH_DEP << 4) +#define METAG_SYMBOL_FLAG_BYTE_P(SYMBOL) \ + ((SYMBOL_REF_FLAGS (SYMBOL) & METAG_SYMBOL_FLAG_BYTE) != 0) + +#define METAG_SYMBOL_FLAG_WORD (SYMBOL_FLAG_MACH_DEP << 5) +#define METAG_SYMBOL_FLAG_WORD_P(SYMBOL) \ + ((SYMBOL_REF_FLAGS (SYMBOL) & METAG_SYMBOL_FLAG_WORD) != 0) + +#define METAG_SYMBOL_FLAG_DWORD (SYMBOL_FLAG_MACH_DEP << 6) +#define METAG_SYMBOL_FLAG_DWORD_P(SYMBOL) \ + ((SYMBOL_REF_FLAGS (SYMBOL) & METAG_SYMBOL_FLAG_DWORD) != 0) + +#define METAG_SYMBOL_FLAG_LONG (SYMBOL_FLAG_MACH_DEP << 7) +#define METAG_SYMBOL_FLAG_LONG_P(SYMBOL) \ + ((SYMBOL_REF_FLAGS (SYMBOL) & METAG_SYMBOL_FLAG_LONG) != 0) + +#define OVERRIDE_OPTIONS \ + metag_override_options () + +/* How to refer to registers in assembler output. + This sequence is indexed by compiler's hard-register-number (see above). */ + +#define REGISTER_NAMES \ +{ \ + /* D0/D1 */ \ + "D0Re0", "D1Re0", "D0Ar6", "D1Ar5", "D0Ar4", "D1Ar3", "D0Ar2", "D1Ar1", \ + "D0.4", "D1RtP", "D0.5", "D1.5", "D0.6", "D1.6", "D0.7", "D1.7", \ + /* D0/D1 reserved */ \ + "D0.8", "D1.8", "D0.9", "D1.9", "D0.10", "D1.10", "D0.11", "D1.11", \ + "D0.12", "D1.12", "D0.13", "D1.13", "D0.14", "D1.14", "D0.15", "D1.15", \ + /* A0/A1 */ \ + "A0StP", "A1GbP", "A0FrP", "A1LbP", "A0.2", "A1.2", "A0.3", "A1.3", \ + "A0.4", "A1.4", "A0.5", "A1.5", "A0.6", "A1.6", "A0.7", "A1.7", \ + /* Fakes may be seen in RTL */ \ + "FRAMEP","MCC", "ARGP", "RAPF", "CPC0", "CPC1", "PC", "TXRPT", \ + /* FX */ \ + "FX.0", "FX.1", "FX.2" , "FX.3" , "FX.4" , "FX.5" , "FX.6" , "FX.7" , \ + "FX.8", "FX.9", "FX.10", "FX.11", "FX.12", "FX.13", "FX.14", "FX.15", \ + /* TTREC(L) */ \ + "TTREC", "TTRECL" \ +} + +#define ADDITIONAL_REGISTER_NAMES \ +{ \ + {"D0.0", D0_0_REG}, \ + {"D1.0", D1_0_REG}, \ + {"D0.1", D0_1_REG}, \ + {"D1.1", D1_1_REG}, \ + {"D0.2", D0_2_REG}, \ + {"D1.2", D1_2_REG}, \ + {"D0.3", D0_3_REG}, \ + {"D1.3", D1_3_REG}, \ + {"D1.4", D1_4_REG}, \ + {"A0.0", A0_0_REG}, \ + {"A1.0", A1_0_REG}, \ + {"A0.1", A0_1_REG}, \ + {"A1.1", A1_1_REG}, \ + {"D0FrT", D0_4_REG}, \ + {"cc", CC_REG} \ +} + +#define ASM_IDENTIFY_CPU ".cpu" + +#define META_IDENTIFY_CPU(FILE) \ + fprintf (FILE, "!\t%s\tmeta%s\n", ASM_IDENTIFY_CPU, metag_cpu_string) + +/* A FILE comment and register declaration section should always + begin the output. */ + +/* Use direct B xx jump tables in code */ +#define JUMP_TABLES_IN_TEXT_SECTION 1 + +/* How to renumber registers for dbx and gdb. */ + +#define DBX_REGISTER_NUMBER(REGNO) (REGNO) + +#undef DWARF2_DENUGGING_INFO +#define DWARF2_DEBUGGING_INFO 1 +#define CAN_DEBUG_WITHOUT_FP + +#define SUPPORTS_INIT_PRIORITY 0 + +/* The prefix to add to internally generated labels. */ +#undef LOCAL_LABEL_PREFIX +#define LOCAL_LABEL_PREFIX "$" + +#undef IMMEDIATE_PREFIX +#define IMMEDIATE_PREFIX "#" + +/* This is how to output an insn to push a register on the stack. + It need not be very fast code. */ + +#define ASM_OUTPUT_REG_PUSH(FILE, REGNO) \ + fprintf (FILE, "\tSETD\t[%s+#4++], %s\n", \ + reg_names[STACK_POINTER_REGNUM], reg_names[REGNO]) + +/* This is how to output an insn to pop a register from the stack. + It need not be very fast code. */ +#define ASM_OUTPUT_REG_POP(FILE, REGNO) \ + fprintf (FILE, "\tGETD\t%s, [%s+#(-4)++]\n", reg_names[REGNO], \ + reg_names[STACK_POINTER_REGNUM]) + +/* This is how to output an element of a case-vector that is absolute. */ +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + asm_fprintf (FILE, "\t%s\t%L%d\t" ASM_COMMENT_START \ + " (abs table not expected)\n", \ + targetm.asm_out.aligned_op.si, \ + VALUE) + + +/* This is how to output an element of a case-vector that is relative. */ +/* This is the first implementation of MiniM short branches. There is no check + to ensure jump targets are in range of a short encoding yet. Short is used + if requested otherwise long is used */ +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ + asm_fprintf (FILE, "\t%sB\t%LL%d\t\t" ASM_COMMENT_START \ + " (table %LL%d OK)\n", \ + (!TARGET_MINIM) ? "" : \ + ((metag_jump_table_branch == METAG_MINIM_JUMP_TABLE_BRANCH_AUTO \ + && cfun->machine->can_use_short_branch) \ + || metag_jump_table_branch == METAG_MINIM_JUMP_TABLE_BRANCH_SHORT) \ + ? "XS\t" : "XL\t", \ + VALUE, REL) + +#define PRINT_OPERAND(FILE, X, CODE) \ + metag_print_operand (FILE, X, CODE) + +#ifdef ENABLE_ASSERT_CHECKING +#define ASM_OUTPUT_OPCODE(FILE, OPCODE) \ + metag_asm_output_opcode (FILE, OPCODE) +#endif /* ENABLE_ASSERT_CHECKING */ + +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ + metag_print_operand_address (FILE, ADDR) + +#define OUTPUT_ADDR_CONST_EXTRA(FILE, X, FAIL) \ + do { \ + if (!metag_output_addr_const_extra (FILE, X)) \ + goto FAIL; \ + } while (0) + +/* On the META we want to pass partial stack/reg arguments such that + * the first N bytes of the argument are passed on the stack and the + * remaining M bytes of the argument are passed in registers. + * + * This allows the function prologue to just push the partial registers + * onto the stack, which can be combined with the normal stack frame + * setup. + * + * This macro is used in the machine independent files expr.c and function.c + * to enable some META specific code for handling partial args. + */ +#define METAG_PARTIAL_ARGS 1 + +/* Only perform branch elimination (by making instructions conditional) if + we're optimising. Otherwise it's of no use anyway. */ +#define FINAL_PRESCAN_INSN(INSN, OPVEC, NOPERANDS) \ + do { \ + if (TARGET_COND_EXEC_OPTIMIZE) \ + { \ + int saved_alternative = which_alternative; \ + \ + metag_final_prescan_insn (INSN); \ + which_alternative = saved_alternative; \ + } \ + } while (0) + +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) ((CODE) == '?' || (CODE) == '@') + +enum metag_builtins +{ + METAG_BUILTIN_DCACHE_PRELOAD, + METAG_BUILTIN_DCACHE_FLUSH, + METAG_BUILTIN_DCACHE_REFRESH, + METAG_BUILTIN_META2_CACHERD, + METAG_BUILTIN_META2_CACHERL, + METAG_BUILTIN_META2_CACHEWD, + METAG_BUILTIN_META2_CACHEWL, + METAG_BUILTIN_METAG_BSWAPS, + METAG_BUILTIN_METAG_BSWAP, + METAG_BUILTIN_METAG_BSWAPLL, + METAG_BUILTIN_METAG_WSWAP, + METAG_BUILTIN_METAG_WSWAPLL, + METAG_BUILTIN_METAG_DSWAPLL, + METAG_BUILTIN_THREAD_POINTER +}; + +#define TARGET_BUILTINS_METAC_1_0 \ + (metac_target == METAC_1_0_ID) + +#define TARGET_BUILTINS_METAC_1_1 \ + (metac_target == METAC_1_1_ID) + +#define TARGET_BUILTINS_METAC_1_2 \ + (metac_target == METAC_1_2_ID || metac_target == METAC_0_1_ID) + +#define TARGET_BUILTINS_METAC_2_1 \ + (metac_target == METAC_2_1_ID) + +#define METAG_CURRENT_FUNCTION_LOADS_PIC_REGISTER() \ + metag_current_function_loads_pic_register () + +#define ASSEMBLE_SYMBOL_REF(STREAM, X) \ + assemble_name (STREAM, XSTR (X, 0)) + +/* The architecture define. */ +extern char metag_arch_name[]; + +/* Target CPU builtins. */ +#define TARGET_CPU_CPP_BUILTINS() \ + metag_cpu_cpp_builtins (pfile) + +#define METAG_CONST_OK_FOR_LETTERS_KPIJ(VALUE) \ + metag_const_ok_for_letters_p (VALUE, "KIPJ") + +#define METAG_CONST_OK_FOR_LETTERS_KPIJO3(VALUE) \ + metag_const_ok_for_letters_p (VALUE, "KIPJO3") + +#define METAG_LETTER_FOR_CONST(VALUE) \ + metag_letter_for_const (VALUE) + +#define METAG_DATA_REG_P(REGNUM) \ + metag_datareg_p (REGNUM) + +#define METAG_ADDR_REG_P(REGNUM) \ + metag_addrreg_p (REGNUM) + +#define METAG_FPC_REG_P(REGNUM) \ + metag_fpcreg_p (REGNUM) + +#define METAG_FPP_REG_P(REGNUM) \ + metag_fppreg_p (REGNUM) + +extern char * metag_gen_cond_return_branch (const char *); +extern char * metag_gen_cond_return_stub (void); +extern void metag_emit_cond_return_stub_if_reqd (void); + +/* Track the status of condition returns. 'REQD' means that a stub is + required at the end of the function. 'DONE' means the stub has been emitted + and should not be emitted again */ +enum metag_cond_return_state +{ + METAG_COND_RETURN_NONE, + METAG_COND_RETURN_REQD, + METAG_COND_RETURN_DONE +}; + +typedef struct machine_function GTY(()) +{ + int valid; + int can_use_short_branch; + int pretend_regs; + int anonymous_args; + int anonymous_args_size; + int uses_pic_offset_table; + int loads_pic_register; + unsigned int savesize_gp; + unsigned int savesize_eh; + unsigned int FP_SP_offset; + unsigned int pic_save_size; + unsigned int out_local_size; + int ech_ctx_required; + int frame_pointer_needed; + int non_leaf; + int frame_pointer_epilogue; + int accesses_prev_frame; + unsigned int extras_gp; + unsigned int extras_eh; + unsigned int calls_eh_return; + int arg_adjust_delta; + int frame_adjust_delta; + int hwtrace; + int hwtrace_leaf; + int hwtrace_retpc; + enum metag_cond_return_state cond_return_state; +} machine_function; + +#define INCOMING_RETURN_ADDR_RTX \ + gen_rtx_REG (SImode, RETURN_POINTER_REGNUM) + +#define DWARF_FRAME_RETURN_COLUMN \ + DWARF_FRAME_REGNUM (RETURN_POINTER_REGNUM) + +#define ASM_FPRINTF_EXTENSIONS(FILE, ARGS, P) \ + case '@': \ + fputs (ASM_COMMENT_START, FILE); \ + break; \ + \ + case 'r': \ + fputs (reg_names [va_arg (ARGS, unsigned int)], file); \ + break; + +#define HARD_REGNO_RENAME_OK_FOR_INSN(INSN, FROM, TO) \ + metag_hard_regno_rename_ok_p (INSN, FROM, TO) + +#define EPILOGUE_USES(REGNO) \ + ((REGNO) == D1RtP_REG || (REGNO) == A0FrP_REG \ + || (TARGET_ECH && (REGNO) == METAG_ECH_REGNUM)) + +#define METAG_USE_RETURN_INSN(ISCOND) \ + metag_use_return_insn (ISCOND) + +/* A stucture to support counting the number of doloop optimised loops per nest */ +struct doloopnest +{ + struct loop* inner; + struct doloopnest* next; +}; + +#define DOLOOP_OPTIMIZE_INIT() \ + struct doloopnest * nests = NULL + +#define DOLOOP_OPTIMIZE_LOOP(LOOP) \ + do { \ + /* Determine if any inner loop nests are already optimized */ \ + if (!metag_doloop_check_any_nest_optimized (LOOP, nests)) \ + /* If we doloop optimize this loop, mark all inner loops as optimized */ \ + if (doloop_optimize (LOOP)) \ + metag_doloop_mark_nests_optimized (LOOP, &nests); \ + } while (0) + + +#define DOLOOP_OPTIMIZE_FINI() \ + do { \ + /* Free the doloop nest counters */ \ + while (nests != NULL) \ + { \ + struct doloopnest * next = nests->next; \ + \ + free (nests); \ + nests = next; \ + } \ + } while (0) + +/* Try a machine-dependent way of reloading an illegitimate address + operand. If we find one, push the reload and jump to WIN. This + macro is used in only one place: `find_reloads_address' in reload.c. + + For the META, we wish to handle large displacements off a base + register by splitting the addend across a MOV and the mem insn. + This can cut the number of reloads needed. */ +#define LEGITIMIZE_RELOAD_ADDRESS(X, MODE, OPNUM, TYPE, IND, WIN) \ + do { \ + rtx new ## X = metag_legitimize_reload_address (X, MODE, OPNUM, TYPE, IND); \ + \ + if (new ## X) \ + { \ + (X) = new ## X; \ + goto WIN; \ + } \ + } while (0) + +#define METAG_ELIMINABLE_REG_P(X) \ + (REGNO (X) == FRAME_POINTER_REGNUM || REGNO (X) == ARG_POINTER_REGNUM) + + +#define SPLIT_EARLY \ + metag_split_early () + +#define SPLIT_HI_LO_SUM_EARLY \ + metag_split_hi_lo_sum_early () + +#define CALLER_SAVE_INSN_CODE(CODE) (-1) + +/* In driver-metag.c. */ +extern const char *metag_reduce_options (int argc, const char **argv); +extern const char *metag_emb_asm_preprocessor (int argc, const char **argv); +extern const char *metag_emb_onlylast (int argc, const char **argv); +extern const char *metag_emb_change_suffix (int argc, const char **argv); +#define EXTRA_SPEC_FUNCTIONS \ + { "meta_preprocessor", metag_emb_asm_preprocessor }, \ + { "meta_reduce_options", metag_reduce_options }, \ + { "meta_onlylast", metag_emb_onlylast }, \ + { "meta_change_suffix", metag_emb_change_suffix }, + + +/* Do not re-invent the wheel! + Instead of writing our very own option file expander, get gcc to do it + convert the -mcpu-config=file option to be @file and expand */ + +#define GCC_DRIVER_HOST_INITIALIZATION \ + do { \ + int i; \ + char * inject_options = getenv ("METAG_COMPILER_OPTIONS"); \ + \ + /* Allow option injection from the environment primarily to reduce the \ + build system logic required when building GCC with its library code and \ + data in sections with non-standard names. This feature may find uses \ + outside of this initial purpose but it's general use is discouraged. */ \ + \ + if (inject_options != NULL) \ + { \ + int env_argc = 0; \ + int new_argc = 0; \ + char** new_argv = NULL; \ + char** env_argv = buildargv (inject_options); \ + \ + if (env_argv == NULL) \ + { \ + fputs ("\nout of memory\n", stderr); \ + xexit (1); \ + } \ + \ + /* Count the number of arguments. */ \ + while (env_argv[env_argc] && *env_argv[env_argc]) \ + ++env_argc; \ + \ + /* Make space for the new arguments */ \ + new_argc = argc + env_argc; \ + new_argv = (char **)xmalloc (sizeof (char*) * (new_argc + 1)); \ + \ + /* Fill in the new argv */ \ + new_argv[0] = argv[0]; \ + memcpy (new_argv + 1, env_argv, sizeof (char *) * env_argc); \ + memcpy (new_argv + env_argc + 1, argv + 1, \ + sizeof (char *) * (argc - 1)); \ + new_argv[new_argc] = NULL; \ + \ + /* Swap in the new argv */ \ + argv = new_argv; \ + argc = new_argc; \ + \ + /* Free the env_argv */ \ + free (env_argv); \ + } \ + \ + for (i = 1 ; i < argc ; i++) \ + { \ + if (strncmp ("-mcpu-config=", argv[i], 13) == 0) \ + { \ + argv[i] = argv[i]+12; \ + *argv[i] = '@'; \ + } \ + } \ + \ + expandargv (&argc, &argv); \ + \ + prune_options (&argc, &argv); \ + } while (0) + +#endif /* __METAG_H */ + +#define METAG_HAVE_TLS targetm.have_tls diff -Nur gcc-4.2.4.orig/gcc/config/metag/metag-linux.c gcc-4.2.4/gcc/config/metag/metag-linux.c --- gcc-4.2.4.orig/gcc/config/metag/metag-linux.c 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/metag-linux.c 2015-07-03 18:46:05.749283542 -0500 @@ -0,0 +1,660 @@ +/* Definitions of target machine for GNU compiler. + Imagination Technologies Meta version. + Copyright (C) 2008 + Imagination Technologies Ltd + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "rtl.h" +#include "tree.h" +#include "obstack.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "real.h" +#include "insn-config.h" +#include "conditions.h" +#include "insn-flags.h" +#include "output.h" +#include "insn-attr.h" +#include "flags.h" +#include "reload.h" +#include "function.h" +#include "expr.h" +#include "optabs.h" +#include "toplev.h" +#include "recog.h" +#include "ggc.h" +#include "except.h" +#include "c-pragma.h" +#include "integrate.h" +#include "cfgloop.h" +#include "tm_p.h" +#include "timevar.h" +#include "options.h" +#include "cgraph.h" +#include "target.h" +#include "target-def.h" +#include "tm-constrs.h" +#include "langhooks.h" +#include "version.h" + +/* --------------------------- begin target defines --------------------------*/ +/* --------------------------- begin asm_out section -------------------------*/ + +#undef TARGET_ASM_ALIGNED_DI_OP +#define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t" + +#undef TARGET_ASM_INTERNAL_LABEL +#define TARGET_ASM_INTERNAL_LABEL metag_internal_label + +#undef TARGET_ASM_FUNCTION_PROLOGUE +#define TARGET_ASM_FUNCTION_PROLOGUE metag_function_prologue + +#undef TARGET_ASM_FUNCTION_END_PROLOGUE +#define TARGET_ASM_FUNCTION_END_PROLOGUE metag_function_end_prologue + +#undef TARGET_ASM_FUNCTION_BEGIN_EPILOGUE +#define TARGET_ASM_FUNCTION_BEGIN_EPILOGUE metag_function_begin_epilogue + +#undef TARGET_ASM_FUNCTION_EPILOGUE +#define TARGET_ASM_FUNCTION_EPILOGUE metag_function_epilogue + +static section * metag_bfd_select_section (tree, int, unsigned HOST_WIDE_INT); +#undef TARGET_ASM_SELECT_SECTION +#define TARGET_ASM_SELECT_SECTION metag_bfd_select_section + +static void metag_bfd_asm_unique_section (tree, int); +#undef TARGET_ASM_UNIQUE_SECTION +#define TARGET_ASM_UNIQUE_SECTION metag_bfd_asm_unique_section + +#undef TARGET_ASM_OUTPUT_MI_THUNK +#define TARGET_ASM_OUTPUT_MI_THUNK metag_output_mi_thunk + +#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK +#define TARGET_ASM_CAN_OUTPUT_MI_THUNK metag_can_output_mi_thunk + +/* A FILE comment and register declaration section must always + * begin the output. */ +static void metag_bfd_asm_file_start (void); +#undef TARGET_ASM_FILE_START +#define TARGET_ASM_FILE_START metag_bfd_asm_file_start + +/* Tidies everything up at the end of the file. */ +static void metag_bfd_asm_file_end (void); +#undef TARGET_ASM_FILE_END +#define TARGET_ASM_FILE_END metag_bfd_asm_file_end + +/* ---------------------------- end asm_out section --------------------------*/ +/* ---------------------------- begin sched section --------------------------*/ + +#undef TARGET_SCHED_ADJUST_COST +#define TARGET_SCHED_ADJUST_COST metag_sched_adjust_cost + +/* ----------------------------- end sched section ---------------------------*/ +/* ---------------------------- begin vector section -------------------------*/ +/* ----------------------------- end vector section --------------------------*/ +/* ------------------------------- begin section -----------------------------*/ + +#undef TARGET_DEFAULT_TARGET_FLAGS +#ifdef MINIM_DEFAULT +#define TARGET_DEFAULT_TARGET_FLAGS ((MASK_COND_EXEC) | (MASK_MINIM) | (MASK_MINIM_OPTIMISE) | (MASK_FLUSH_TO_ZERO)) +#else +#define TARGET_DEFAULT_TARGET_FLAGS ((MASK_COND_EXEC) | (MASK_MINIM_OPTIMISE) | (MASK_FLUSH_TO_ZERO)) +#endif + +#undef TARGET_HANDLE_OPTION +#define TARGET_HANDLE_OPTION metag_handle_option + +#undef TARGET_MERGE_DECL_ATTRIBUTES +#define TARGET_MERGE_DECL_ATTRIBUTES metag_merge_decl_attributes + +#undef TARGET_MERGE_TYPE_ATTRIBUTES +#define TARGET_MERGE_TYPE_ATTRIBUTES metag_merge_type_attributes + +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE metag_attribute_table + +#undef TARGET_COMP_TYPE_ATTRIBUTES +#define TARGET_COMP_TYPE_ATTRIBUTES metag_comp_type_attributes + +#undef TARGET_INIT_BUILTINS +#define TARGET_INIT_BUILTINS metag_init_builtins + +#undef TARGET_EXPAND_BUILTIN +#define TARGET_EXPAND_BUILTIN metag_expand_builtin + +#undef TARGET_FUNCTION_OK_FOR_SIBCALL +#define TARGET_FUNCTION_OK_FOR_SIBCALL metag_function_ok_for_sibcall + +#undef TARGET_ENCODE_SECTION_INFO +#define TARGET_ENCODE_SECTION_INFO metag_encode_section_info + +static const char *metag_bfd_strip_name_encoding (const char *); +#undef TARGET_STRIP_NAME_ENCODING +#define TARGET_STRIP_NAME_ENCODING metag_bfd_strip_name_encoding + +#undef TARGET_SCALAR_MODE_SUPPORTED_P +#define TARGET_SCALAR_MODE_SUPPORTED_P metag_scalar_mode_supported_p + +#undef TARGET_VECTOR_MODE_SUPPORTED_P +#define TARGET_VECTOR_MODE_SUPPORTED_P metag_vector_mode_supported_p + +#undef TARGET_RTX_COSTS +#define TARGET_RTX_COSTS metag_rtx_costs + +#undef TARGET_ADDRESS_COST +#define TARGET_ADDRESS_COST metag_address_cost + +#undef TARGET_MACHINE_DEPENDENT_REORG +#define TARGET_MACHINE_DEPENDENT_REORG metag_machine_dependent_reorg + +#undef TARGET_GIMPLIFY_VA_ARG_EXPR +#define TARGET_GIMPLIFY_VA_ARG_EXPR metag_gimplify_va_arg_expr + +#undef TARGET_INVALID_WITHIN_DOLOOP +#define TARGET_INVALID_WITHIN_DOLOOP metag_invalid_within_doloop + +/* -------------------------------- end section ------------------------------*/ +/* ---------------------------- begin calls section --------------------------*/ + +#undef TARGET_PROMOTE_FUNCTION_ARGS +#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true + +#undef TARGET_PROMOTE_FUNCTION_RETURN +#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true + +#undef TARGET_FUNCTION_VALUE +#define TARGET_FUNCTION_VALUE metag_function_value + +#undef TARGET_PROMOTE_PROTOTYPES +#define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true + +#undef TARGET_PASS_BY_REFERENCE +#define TARGET_PASS_BY_REFERENCE metag_pass_by_reference + +#undef TARGET_SETUP_INCOMING_VARARGS +#define TARGET_SETUP_INCOMING_VARARGS metag_setup_incoming_varargs + +#undef TARGET_MUST_PASS_IN_STACK +#define TARGET_MUST_PASS_IN_STACK metag_must_pass_in_stack + +#undef TARGET_ARG_PARTIAL_BYTES +#define TARGET_ARG_PARTIAL_BYTES metag_arg_partial_bytes + +/* ----------------------------- end calls section ---------------------------*/ +/* ------------------------------- begin section -----------------------------*/ + +#undef TARGET_SECONDARY_RELOAD +#define TARGET_SECONDARY_RELOAD metag_secondary_reload + +/* -------------------------------- end section ------------------------------*/ +/* ----------------------------- begin cxx section ---------------------------*/ + +/* C++ specific macros */ + +/* ------------------------------ end cxx section ----------------------------*/ +/* ------------------------------- begin section -----------------------------*/ + +#undef TARGET_HAVE_NAMED_SECTIONS +#define TARGET_HAVE_NAMED_SECTIONS true + +#undef TARGET_HAVE_SWITCHABLE_BSS_SECTIONS +#define TARGET_HAVE_SWITCHABLE_BSS_SECTIONS false + +/* -------------------------------- end section ------------------------------*/ + +#undef TARGET_CANNOT_FORCE_CONST_MEM +#define TARGET_CANNOT_FORCE_CONST_MEM metag_bfd_tls_referenced_p + +struct gcc_target targetm = TARGET_INITIALIZER; + +/* ---------------------------- end target defines ---------------------------*/ + +static void +metag_bfd_asm_file_start (void) +{ + fprintf (asm_out_file, "%s Generated by gcc %s for Meta(Linux)/elf\n", + ASM_COMMENT_START, version_string); + + fputc ('\n', asm_out_file); + output_file_directive (asm_out_file, main_input_filename); + + fputc ('\n', asm_out_file); + META_IDENTIFY_CPU (asm_out_file); + fputc ('\n', asm_out_file); +} + +static void +metag_bfd_asm_file_end (void) +{ + return; +} + +static const char * +metag_bfd_strip_name_encoding (const char *str) +{ + gcc_assert (str[0] != '&'); + + return str + (str[0] == '*'); +} + +/* Construct a unique section name based on the decl name and the + categorization performed above. */ + +static void +metag_bfd_asm_unique_section (tree decl, int reloc) +{ + /* We only need to use .gnu.linkonce if we don't have COMDAT groups. */ + bool one_only = DECL_ONE_ONLY (decl) && !HAVE_COMDAT_GROUP; + const char *prefix, *name; + size_t nlen, plen; + char *string; + + switch (categorize_decl_for_section (decl, reloc)) + { + case SECCAT_TEXT: + prefix = one_only ? ".gnu.linkonce.t." : ".text."; + break; + case SECCAT_RODATA: + prefix = one_only ? ".gnu.linkonce.r." : ".rodata."; + break; + case SECCAT_RODATA_MERGE_STR: + case SECCAT_RODATA_MERGE_STR_INIT: + case SECCAT_RODATA_MERGE_CONST: + prefix = one_only ? ".gnu.linkonce.r." : ".rodata."; + break; + case SECCAT_SRODATA: + prefix = one_only ? ".gnu.linkonce.s2." : ".sdata2."; + break; + case SECCAT_DATA: + prefix = one_only ? ".gnu.linkonce.d." : ".data."; + break; + case SECCAT_DATA_REL: + prefix = one_only ? ".gnu.linkonce.d.rel." : ".data.rel."; + break; + case SECCAT_DATA_REL_LOCAL: + prefix = one_only ? ".gnu.linkonce.d.rel.local" : ".data.rel.local."; + break; + case SECCAT_DATA_REL_RO: + prefix = one_only ? ".gnu.linkonce.d.rel.ro." : ".data.rel.ro."; + break; + case SECCAT_DATA_REL_RO_LOCAL: + prefix = one_only ? ".gnu.linkonce.d.rel.ro.local." : ".data.rel.ro.local."; + break; + case SECCAT_SDATA: + prefix = one_only ? ".gnu.linkonce.s." : ".sdata."; + break; + case SECCAT_BSS: + prefix = one_only ? ".gnu.linkonce.d." : ".data."; + break; + case SECCAT_SBSS: + prefix = one_only ? ".gnu.linkonce.s." : ".sdata."; + break; + /* Add default handlers to deal with tdata and tbss sections */ + case SECCAT_TDATA: + prefix = one_only ? ".gnu.linkonce.td." : ".tdata."; + break; + case SECCAT_TBSS: + prefix = one_only ? ".gnu.linkonce.tb." : ".tbss."; + break; + default: + gcc_unreachable (); + } + plen = strlen (prefix); + + name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); + name = targetm.strip_name_encoding (name); + nlen = strlen (name); + + string = alloca (nlen + plen + 1); + memcpy (string, prefix, plen); + memcpy (string + plen, name, nlen + 1); + + DECL_SECTION_NAME (decl) = build_string (nlen + plen, string); +} + +static section * +metag_bfd_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED) +{ + const char *sname; + + switch (categorize_decl_for_section (decl, reloc)) + { + case SECCAT_TEXT: + /* We're not supposed to be called on FUNCTION_DECLs. */ + gcc_unreachable (); + case SECCAT_RODATA: + return readonly_data_section; + case SECCAT_RODATA_MERGE_STR: + return mergeable_string_section (decl, align, 0); + case SECCAT_RODATA_MERGE_STR_INIT: + return mergeable_string_section (DECL_INITIAL (decl), align, 0); + case SECCAT_RODATA_MERGE_CONST: + return mergeable_constant_section (DECL_MODE (decl), align, 0); + case SECCAT_SRODATA: + sname = ".sdata2"; + break; + case SECCAT_DATA: + return data_section; + case SECCAT_DATA_REL: + sname = ".data.rel"; + break; + case SECCAT_DATA_REL_LOCAL: + sname = ".data.rel.local"; + break; + case SECCAT_DATA_REL_RO: + sname = ".data.rel.ro"; + break; + case SECCAT_DATA_REL_RO_LOCAL: + sname = ".data.rel.ro.local"; + break; + case SECCAT_SDATA: + sname = ".sdata"; + break; + /* Add default handler to deal with tdata sections */ + case SECCAT_TDATA: + sname = ".tdata"; + break; + case SECCAT_BSS: + return data_section; + case SECCAT_SBSS: + return sdata_section; + /* Add default handler to deal with tbss sections */ + case SECCAT_TBSS: + sname = ".tbss"; + break; + default: + gcc_unreachable (); + } + if (!DECL_P (decl)) + decl = NULL_TREE; + return get_named_section (decl, sname, reloc); +} + +bool +metag_handle_option_per_os (size_t code ATTRIBUTE_UNUSED, const char *arg ATTRIBUTE_UNUSED, int value ATTRIBUTE_UNUSED) +{ + return true; +} + +void +metag_override_options_per_os (void) +{ + if (TARGET_MTX) + error ("Meta Linux does not have MTX support"); + + if (metac_target == METAC_1_0_ID + || metac_target == METAC_1_1_ID + || metac_target == METAC_0_1_ID) + error ("Meta Linux does not have support for the specified core"); +} + +/* Return 1 if X is a thread local symbol */ + +static int +metag_tls_symbol_ref_1 (rtx *x, void *data ATTRIBUTE_UNUSED) +{ + if (GET_CODE (*x) == SYMBOL_REF) + return SYMBOL_REF_TLS_MODEL (*x) != 0; + + /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are + TLS offsets, not real symbol references. */ + if (GET_CODE (*x) == UNSPEC + && XINT (*x, 1) >= UNSPEC_FIRST_TLS + && XINT (*x, 1) <= UNSPEC_LAST_TLS) + return -1; + + return 0; +} + +/* Return 1 if X contains a thread-local symbol. */ + +bool +metag_bfd_tls_referenced_p (rtx x) +{ + if (!METAG_HAVE_TLS) + return false; + + return for_each_rtx (&x, &metag_tls_symbol_ref_1, 0); +} + +bool +metag_function_ok_for_sibcall_per_os (tree fndecl ATTRIBUTE_UNUSED, tree exp ATTRIBUTE_UNUSED) +{ + return true; +} + +void +metag_pad_function_call (rtx symbol_ref ATTRIBUTE_UNUSED) +{ + return; +} + +bool +metag_tbiassert_p (rtx symbol_ref ATTRIBUTE_UNUSED) +{ + return false; +} + +/* Construct the SYMBOL_REF for the __tls_get_addr function. */ + +static GTY(()) rtx metag_tls_symbol; + +static rtx +metag_tls_get_addr (void) +{ + if (!metag_tls_symbol) + metag_tls_symbol = gen_rtx_SYMBOL_REF (Pmode, "__tls_get_addr"); + + return metag_tls_symbol; +} + +/* Construct the SYMBOL_REF for the __metag_load_tp function. */ + +static GTY(()) rtx metag_tp_symbol; + +static rtx +metag_load_tp (void) +{ + if (!metag_tp_symbol) + metag_tp_symbol = gen_rtx_SYMBOL_REF (Pmode, "__metag_load_tp"); + + return metag_tp_symbol; +} + +/* Generates rtl to call the metag_load_tp function to get the address of the + thread pointer. The rtx representing the register containing this address + is then returned. */ + +static rtx +gen_metag_load_tp (void) +{ + rtx ret0, ret, tp, tmp, insn, eqv; + ret0 = gen_rtx_REG (Pmode, D0Re0_REG); + ret = gen_reg_rtx (Pmode); + tp = gen_reg_rtx (Pmode); + + start_sequence (); + tmp = gen_rtx_MEM (QImode, metag_load_tp ()); + insn = gen_call_value (ret0, tmp, const0_rtx); + insn = emit_call_insn (insn); + CONST_OR_PURE_CALL_P (insn) = 1; + insn = get_insns (); + end_sequence (); + + /* We need this equivalence expression so that the RTL optimiser + can figure out it only needs to place one call to + __metag_load_tp regardless of how many thread-local variables + are present. */ + eqv = gen_rtx_UNSPEC (VOIDmode, + gen_rtvec (1, metag_load_tp ()), + UNSPEC_TLS); + emit_libcall_block (insn, tp, ret0, eqv); + + return tp; +} + +/* Return the TLS type for TLS symbols, 0 otherwise. */ + +bool +tls_symbolic_operand_p (rtx op) +{ + return ((GET_CODE (op) == SYMBOL_REF) && (SYMBOL_REF_TLS_MODEL (op) != 0)); +} + +/* These functions are part of a framework to allow the support of OS + specific builtin functions within GCC. + The only builtin function for META Linux is __builtin_thread_pointer + which returns the address of the thread pointer. */ + +void +metag_init_builtins_per_os (void) +{ + tree nothrow = tree_cons (get_identifier ("nothrow"), NULL, NULL); + tree ftmetag_tp = build_function_type (ptr_type_node, void_list_node); + + lang_hooks.builtin_function ("__builtin_thread_pointer", + ftmetag_tp, + METAG_BUILTIN_THREAD_POINTER, + BUILT_IN_MD, + NULL, + nothrow); +} + +/* Performs the expansion of the META Linux builtin functions */ + +rtx +metag_expand_builtin_per_os (tree exp, rtx target) +{ + tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); + int fcode = DECL_FUNCTION_CODE (fndecl); + + switch(fcode) + { + case METAG_BUILTIN_THREAD_POINTER: /* void * __builtin_thread_pointer (void) */ + target = gen_metag_load_tp (); + return target; + default: + break; + } + + return NULL_RTX; +} + +/* Adds code to calculate the address of a TLS operand */ + +rtx +metag_bfd_legitimize_tls_address (rtx addr) +{ + rtx tmp, tga, ret, tp, arg1, insn, ret0, eqv; + + gcc_assert (!no_new_pseudos); + gcc_assert (SYMBOL_REF_P(addr)); + + switch (SYMBOL_REF_TLS_MODEL (addr)) + { + case TLS_MODEL_GLOBAL_DYNAMIC: + + current_function_uses_pic_offset_table = 1; + arg1 = gen_rtx_REG (Pmode, D1Ar1_REG); + ret0 = gen_rtx_REG (Pmode, D0Re0_REG); + ret = gen_reg_rtx (Pmode); + + start_sequence (); + emit_insn (gen_tls_gd (arg1, pic_offset_table_rtx, addr)); + tga = gen_rtx_MEM (QImode, metag_tls_get_addr ()); + insn = gen_call_value (ret0, tga, const0_rtx); + insn = emit_call_insn (insn); + CONST_OR_PURE_CALL_P (insn) = 1; + use_reg (&CALL_INSN_FUNCTION_USAGE (insn), arg1); + insn = get_insns (); + end_sequence (); + + emit_libcall_block (insn, ret, ret0, addr); + + return ret; + + case TLS_MODEL_LOCAL_DYNAMIC: + + current_function_uses_pic_offset_table = 1; + arg1 = gen_rtx_REG (Pmode, D1Ar1_REG); + ret0 = gen_rtx_REG (Pmode, D0Re0_REG); + tmp = gen_reg_rtx (Pmode); + ret = gen_reg_rtx (Pmode); + + start_sequence (); + emit_insn (gen_tls_ldm (arg1, pic_offset_table_rtx, addr)); + tga = gen_rtx_MEM (QImode, metag_tls_get_addr ()); + insn = gen_call_value (ret0, tga, const0_rtx); + insn = emit_call_insn (insn); + CONST_OR_PURE_CALL_P (insn) = 1; + use_reg (&CALL_INSN_FUNCTION_USAGE (insn), arg1); + insn = get_insns (); + end_sequence (); + + /* We need this equivalence expression so that the RTL optimiser + can figure out it only needs to place one call to + __tls_get_addr regardless of how many local-dynamic model + variables are present. */ + eqv = gen_rtx_UNSPEC (VOIDmode, + gen_rtvec (1, metag_tls_get_addr ()), + UNSPEC_TLSLDM); + + emit_libcall_block (insn, tmp, ret0, eqv); + + insn = gen_tls_ldo (ret, tmp, addr); + emit_insn (insn); + + return ret; + + case TLS_MODEL_INITIAL_EXEC: + + tmp = gen_reg_rtx (Pmode); + + /* Produce different relocations depending on if PIC is enabled or not */ + if (METAG_FLAG_PIC) + { + current_function_uses_pic_offset_table = 1; + emit_insn (gen_tls_ie (tmp, pic_offset_table_rtx, addr)); + } + else + { + current_function_uses_pic_offset_table = 0; + emit_insn (gen_tls_non_pic_ie (tmp, addr)); + } + + tp = gen_metag_load_tp (); + + return gen_rtx_PLUS (Pmode, tp, tmp); + + case TLS_MODEL_LOCAL_EXEC: + + tmp = gen_reg_rtx (Pmode); + tp = gen_metag_load_tp (); + + emit_insn (gen_tls_le (tmp, tp, addr)); + + return tmp; + + default: + gcc_unreachable (); + } +} diff -Nur gcc-4.2.4.orig/gcc/config/metag/metag-linux.h gcc-4.2.4/gcc/config/metag/metag-linux.h --- gcc-4.2.4.orig/gcc/config/metag/metag-linux.h 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/metag-linux.h 2015-07-03 18:46:05.749283542 -0500 @@ -0,0 +1,177 @@ +/* Definitions of target machine for GNU compiler. + Imagination Technologies Meta version. + Copyright (C) 2008 + Imagination Technologies Ltd + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "metag.h" + +/* OG and OGA addressing are not available */ +#define OG_ENABLED false + +#define METAG_FLAG_PIC flag_pic + +/* The prefix to add to user-visible assembler symbols. */ +#undef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "_" + +#ifdef MINIM_DEFAULT +#define DEFAULT_MINIM_ASM_SPEC "%{!mno-minim:-minim} " +#else +#define DEFAULT_MINIM_ASM_SPEC +#endif + +#define ASM_SPEC \ + "%:meta_reduce_options(%{mmetac=*&mhard-float*&msoft-float&msimd-float}) " \ + "%{mdsp:%{mmetac=1.2:-mdsp=metac12}%{mmetac=2.1:-mdsp=metac21}} " \ + "%{mmetac=0.1:-mcpu=metac01} " \ + "%{mmetac=1.0:-mcpu=metac10} " \ + "%{mmetac=1.1:-mcpu=metac11} " \ + "%{mmetac=1.2:-mcpu=metac12} " \ + "%{mmetac=2.1:-mcpu=metac21} " \ + "%{mhard-float*:%{mmetac=2.1:-mfpu=metac21}%{!mmetac=2.1:%eThe floating point unit is only available on a META 2.1}} " \ + "%{mminim:-minim} " \ + DEFAULT_MINIM_ASM_SPEC + +/* This is how to output an assembler line for a numeric constant byte. */ + +#define ASM_OUTPUT_BYTE(FILE, VALUE) \ + fprintf (FILE, "\t.byte\t0x%x\n", (int) ((VALUE) & 0xff)) + +/* There has been some confusion over the meaning of the .align directive + in gas over the last few years. However there is now a new directive + called .balign that is explicitly defined as taking an absolute alignment + value rather than a log2 value. We will now use this by default if + available and leave the old implementation as is (even though it is wrong) */ +#ifdef HAVE_GAS_BALIGN_AND_P2ALIGN + +#undef ASM_OUTPUT_ALIGN +#define ASM_OUTPUT_ALIGN(FILE, LOG) \ + do { \ + if ((LOG)!=0) \ + fprintf ((FILE), "\t.balign %d\n", 1<<(LOG)); \ + } while (0) + +#else + +#undef ASM_OUTPUT_ALIGN +#define ASM_OUTPUT_ALIGN(FILE, LOG) \ + do { \ + if ((LOG) != 0) \ + fprintf (FILE, "%s%u\n", ALIGN_ASM_OP, LOG); \ + } while (0) + +#endif + +/* This says how to output an assembler line + to define a global common symbol. */ + +#define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ + do { \ + fputs ("\t.comm\t", FILE); \ + assemble_name (FILE, (NAME)); \ + fprintf (FILE, ",%u\n", (SIZE)); \ + } while (0) + +/* This says how to output an assembler line + to define a local common symbol. */ + +#define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE,ROUNDED) \ + do { \ + fputs ("\t.lcomm\t", FILE); \ + assemble_name (FILE, (NAME)); \ + fprintf (FILE, ",%u\n", (SIZE)); \ + } while (0) + +#define TEXT_SECTION_ASM_OP ".text" + +#define DATA_SECTION_ASM_OP ".data" + +#define DATA_SECTION DATA_SECTION_ASM_OP + +/* Try machine-dependent ways of modifying an illegitimate address + to be legitimate. If we find one, return the new, valid address. + This macro is used in only one place: `memory_address' in explow.c. + + OLDX is the address as it was before break_out_memory_refs was called. + In some cases it is useful to look at this to decide what needs to be done. + + MODE and WIN are passed so that this macro can use + GO_IF_LEGITIMATE_ADDRESS. + + It is always safe for this macro to do nothing. It exists to recognize + opportunities to optimize the output. */ + +#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \ + do { \ + (X) = metag_legitimize_address (X, OLDX, MODE); \ + if (memory_address_p (MODE, X)) \ + goto WIN; \ + } while (0) + +#undef ASM_GENERATE_INTERNAL_LABEL +#define ASM_GENERATE_INTERNAL_LABEL(LABEL, PREFIX, NUM) \ + sprintf (LABEL, "*%s%s%u", LOCAL_LABEL_PREFIX, PREFIX, (unsigned)(NUM)) + +/* Register to hold the addressing base for position independent + code access to data items. */ +#define PIC_OFFSET_TABLE_REGNUM PIC_REG + +/* Nonzero if the constant value X is a legitimate general operand + when generating PIC code. It is given that flag_pic is on and + that X satisfies CONSTANT_P or is a CONST_DOUBLE. */ + +#define LEGITIMATE_PIC_OPERAND_P(X) \ + (! SYMBOLIC_CONST (X) || metag_legitimate_pic_address_disp_p (X)) + +/* The `FINALIZE_PIC' macro serves as a hook to emit these special + codes once the function is being compiled into assembly code, but + not before. (It is not done before, because in the case of + compiling an inline function, it would lead to multiple PIC + prologues being included in functions which used inline functions + and were compiled to assembly language.) */ + +#define FIXME_FINALIZE_PIC \ + do \ + { \ + extern int current_function_uses_pic_offset_table; \ + \ + current_function_uses_pic_offset_table \ + |= profile_flag | profile_block_flag; \ + } \ + while (0) + +#define ASSEMBLE_END_FUNCTION(DECL,FNNAME) \ + do { \ + metag_emit_cond_return_stub_if_reqd (); \ + } while (0) + +#ifdef HAVE_AS_TLS +#undef TARGET_HAVE_TLS +#define TARGET_HAVE_TLS HAVE_AS_TLS +#endif + +/* Nonzero if the constant value X is a legitimate general operand. + It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. + + This is true apart from cases where the symbol represents a TLS + symbol. */ + +#undef LEGITIMATE_CONSTANT_P +#define LEGITIMATE_CONSTANT_P(X) \ + (!tls_symbolic_operand_p (X)) diff -Nur gcc-4.2.4.orig/gcc/config/metag/metag-linux.opt gcc-4.2.4/gcc/config/metag/metag-linux.opt --- gcc-4.2.4.orig/gcc/config/metag/metag-linux.opt 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/metag-linux.opt 2015-07-03 18:46:05.749283542 -0500 @@ -0,0 +1,25 @@ +; Copyright (C) 2008 Imagination Technologies Ltd + +; This file is part of GCC. + +; GCC is free software; you can redistribute it and/or modify it under +; the terms of the GNU General Public License as published by the Free +; Software Foundation; either version 3, or (at your option) any later +; version. + +; GCC is distributed in the hope that it will be useful, but WITHOUT ANY +; WARRANTY; without even the implied warranty of MERCHANTABILITY or +; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +; for more details. + +; You should have received a copy of the GNU General Public License +; along with GCC; see the file COPYING3. If not see +; . + + +; Default model is large (small model is 'better' but not supported +; in binutils toolchain +mmodel= +Target RejectNegative Joined Var(metag_model_string) Init("large") +Memory access model (small|large) [NOTE: small not supported] + diff -Nur gcc-4.2.4.orig/gcc/config/metag/metag.md gcc-4.2.4/gcc/config/metag/metag.md --- gcc-4.2.4.orig/gcc/config/metag/metag.md 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/metag.md 2015-07-03 18:46:05.773283541 -0500 @@ -0,0 +1,8255 @@ +;; Machine description for GNU compiler, +;; Imagination Technologies Meta version. +;; Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2010 +;; Imagination Technologies Ltd + +;; This file is part of GCC. + +;; GCC is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 3, or (at your option) any later +;; version. + +;; GCC is distributed in the hope that it will be useful, but WITHOUT ANY +;; WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; . + +;;- instruction definitions + +;;- @@The original PO technology requires these to be ordered by speed, +;;- @@ so that assigner will pick the fastest. + +;;- See file "rtl.def" for documentation on define_insn, match_*, et. al. + +;;- When naming insn's (operand 0 of define_insn) be careful about using +;;- names from other targets machine descriptions. + + +;; MODE macros +(define_mode_macro CCALL [CC_FP CC_FP_Q CC CC_NOOV CC_Z]) + +(define_mode_macro CCFP [CC_FP CC_FP_Q]) + +(define_mode_macro CCANY [CC CC_NOOV CC_Z]) + +(define_mode_macro CCZNC [CC_NOOV CC_Z]) + +(define_mode_macro IMODES [QI HI SI DI]) + +(define_mode_macro FMODES [SF DF]) + +(define_mode_macro FLMODES [SF DF V2SF]) + +; Floating point storage modes +; This is same as FMODES at the moment but HF would go here when it's supported +; WHen HF is added some insns need to be split as HF conversions have a single +; cycle stall whereas others have 5 cycle stalls +(define_mode_macro FSMODES [SF DF]) + +(define_mode_macro MODES [QI HI SI DI SF DF V2SF V2SI]) + +(define_mode_macro EXTDI [QI HI SI]) + +(define_mode_macro EXTSI [QI HI]) + +(define_mode_macro EXTHI [QI]) + +(define_mode_macro MEMOP [QI HI SI]) + +;; MODE attrs + +(define_mode_attr S [(DI "8") (SI "4") (HI "2") (QI "1") (SF "4") (DF "8") (V2SF "8") (V2SI "8")]) + +(define_mode_attr W [(DI "L") (SI "D") (HI "W") (QI "B") (SF "D") (DF "L") (V2SF "L") (V2SI "L")]) + +(define_mode_attr P [(DI "l") (SI "d") (HI "w") (QI "b") (SF "d") (DF "l") (V2SF "l") (V2SI "l")]) + +(define_mode_attr O [(DI "O8") (SI "O4") (HI "O2") (QI "O1") (SF "O4") (DF "O8") (V2SF "O8") (V2SI "O8")]) + +(define_mode_attr Z [(DI "Z8") (SI "Z4") (HI "Z2") (QI "Z1") (SF "Z4") (DF "Z8") (V2SF "Z8") (V2SI "Z8")]) + +(define_mode_attr FT [(SF "F") (DF "D")]) +(define_mode_attr FW [(SF "" ) (DF "D") (DI "D") (V2SF "L")]) +(define_mode_attr fcondition [(SF "TARGET_FPU") (DF "TARGET_FPU && !metag_fpu_single") (V2SF "TARGET_FPU_SIMD")]) + +(define_mode_attr CCQ [(CC_FP "") (CC_FP_Q "Q")]) + +;; CODE macros + +(define_code_macro CCCOND [eq ne gt gtu lt ltu ge geu le leu]) + +(define_code_macro CCFPCOND [eq ne + gt ge lt le unordered ltgt ordered + ungt unge unlt unle uneq]) + +(define_code_macro CCANYCOND [eq ne + gtu ltu geu leu + gt ge lt le unordered ordered + ungt unge unlt unle]) + +;; These code macros significantly simplify the peephole and vector patterns required +;; for supporting dual unit DSP operations + +(define_code_macro 3OPREG [plus minus and ior xor ashift ashiftrt lshiftrt]) +(define_code_macro 3OPIMM16 [plus minus and ior xor]) +(define_code_macro 3OPIMM5 [ashift ashiftrt lshiftrt]) +(define_code_macro MINMAX [smin smax]) + +;; CODE attrs + +;; These code attributes are used for peephole and vector patterns that support +;; dual unit DSP operations + +(define_code_attr MNEMONIC [(plus "ADD") (minus "SUB") (and "AND") (ior "OR") (xor "XOR") + (ashift "LSL") (ashiftrt "ASR") (lshiftrt "LSR") (smin "MIN") + (smax "MAX")]) + +(define_code_attr commutative [(plus "true") (minus "false") (and "true") (ior "true") (xor "true") + (ashift "false") (ashiftrt "false") (lshiftrt "false") (smin "true") + (smax "true")]) + +(define_code_attr expander [(plus "add") (minus "sub") (and "and") (ior "ior") (xor "xor") + (ashift "ashl") (ashiftrt "ashr") (lshiftrt "lshr") (smin "smin") + (smax "smax")]) + +(define_code_attr dualunitimmcondition [(plus "&& !(TARGET_METAC_1_0 && (INTVAL (operands[1]) & 1) == 1)") + (minus "&& !(TARGET_METAC_1_0 && (INTVAL (operands[1]) & 1) == 1)") + (and "") (ior "") (xor "") (ashift "") (ashiftrt "") (lshiftrt "") + (smin "") (smax "")]) + +;; constants + + +(include "constants.md") +(include "predicates.md") +(include "constraints.md") +(include "pipeline.md") + +;; Insn type. Used to default other attribute values. +(define_attr "type" + "fast,swap,slow,two,twox,three,threex,\ + load,read,four,fourx,five,fivex,sixx,\ + sevenx,mult,slowslow,nop,block,branch,\ + FPfast,FPrecip,FPmas,FPrecipmas,unknown,invalid" + (const_string "unknown")) + +;; Indiate of insn is suitable for register renaming +(define_attr "rename" "no,yes" (const_string "yes")) + +;; Indicate if insn is conditional +(define_attr "cond" "no,yes" (const_string "no")) + +;; Conditional execution attribute, implicitly used when creating predicated insns +(define_attr "predicable" "no,yes" (const_string "no")) + +;; Type of memory operation +(define_attr "memaccess" "load,store,none" (const_string "none")) + +;; O2R hints +;; op2op1 - operand 2 is O2R if not in the same unit as operand 1 +;; op1op0 - operand 1 is O2R if not in the same unit as operand 0 +(define_attr "o2rhint" "op2op1,op1op0,none" (const_string "none")) + +;; Insn ccstate. Used to track interaction with the condition flags + +; xcc means that the condition codes are used by the insn in the process of +; outputting code + +; set means that the purpose of the insn is to set the condition codes. + +; ccx means that the condition codes are altered in an undefined manner, if +; they are altered at all + +; ncc means that the condition codes are neither altered nor affect the +; output of this insn + +(define_attr "ccstate" "xcc,set,fastset,fastfastset,ccx,ncc" (const_string "ncc")) + +;; Length (in # of insns). +(define_attr "length" "" + (cond [(eq_attr "type" "two,slowslow,read") (const_int 8) + (eq_attr "type" "three") (const_int 12) + (eq_attr "type" "four") (const_int 16) + (eq_attr "type" "five") (const_int 20)] + (const_int 4))) + +;; User supplied instructions +(define_asm_attributes + [(set_attr "type" "unknown") + (set_attr "ccstate" "ccx") + (set_attr "length" "4") + (set_attr "cond" "no") + (set_attr "predicable" "no") + (set_attr "memaccess" "none") + (set_attr "o2rhint" "none") + (set_attr "rename" "no")]) + + +;; Metac core revision. +;; Used to select meta core revision specific insn scheduling. +;; this attribute must exactly match the processor_type enumeration in metag.h + +(define_attr "metacore" "metac_1_0,metac_1_1,metac_1_2,metac_0_1,metac_2_1" + (const (symbol_ref "metacore"))) + +;; prologue/epilogue +(define_expand "prologue" + [(clobber (const_int 0))] + "" + { + metag_expand_prologue (); + DONE; + } +) + +(define_expand "epilogue" + [(return)] + "" + { + metag_expand_epilogue (false); + emit_jump_insn (gen_return_internal ()); + DONE; + } +) + +(define_expand "sibcall_epilogue" + [(return)] + "" + { + metag_expand_epilogue (true); + DONE; + } +) + +(define_insn "prologue_use" + [(unspec:SI [(match_operand:SI 0 "register_operand" "r")] UNSPEC_PROLOGUE_USE)] + "" + "%@%@ %0 needed for prologue" +) + +;; Patterns for exception handling + +(define_expand "eh_return" + [(use (match_operand:SI 0 "register_operand" "r"))] + "" + { + emit_insn (gen_eh_return_internal (operands[0])); + DONE; + } +) + +(define_insn_and_split "eh_return_internal" + [(unspec_volatile [(match_operand:SI 0 "register_operand" "r")] VUNSPEC_EH_RETURN)] + "" + "#" + "reload_completed" + [(const_int 0)] + { + metag_expand_set_return_address (operands[0]); + DONE; + } +) + + +(define_insn "blockage" + [(unspec_volatile [(const_int 0)] VUNSPEC_BLOCKAGE)] + "" + "" + [(set_attr "length" "0") + (set_attr "type" "block")]) + + +;; move instructions + +(define_insn "swapsi" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "+e,f,h,l") + (match_operand:SI 1 "metag_reg_nofloat_op" "+t,u,y,z")) + (set (match_dup 1) + (match_dup 0))] + "" + "SWAP%?\\t%0, %1\\t%@ (*swap SI OK)" + [(set_attr "type" "swap") + (set_attr "predicable" "yes") + (set_attr "cond" "yes")]) + +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +;; movsi is made up of many parts.. ;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +(define_expand "movsi" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (match_operand:SI 1 "general_operand" ""))] + "" + { + + /* The output template that was here has been moved in the + metag_emit_move_sequence function in metag.c */ + metag_emit_move_sequence (operands, SImode); + } +) + +;; The problem: +;; GCC cannot differentiate a legitimate address from an illegitimate one when the only +;; factor affecting the split is the class that the register being loaded to or stored +;; from belongs to. + +;; This problem affects FX registers with SImode values in them. FX registers can only +;; be stored and loaded from register+6bit offset whereas all other registers can be +;; stored and loaded from register+12bit offset if the base register supports it. + +;; The solution: +;; Prevent reload from having a free-for-all on determining legitimate addresses. The +;; fallback case in mov_si therefore DOES NOT contain the FP register class in either +;; of the memory constraint alternatives. Reload will fix this by reloading any FX +;; register into another register as required. + +;; The caveat: +;; This solution prevents FX registers being reloaded directly to and from memory. To +;; solve this, the 6 and 12 bit load/store insns are above the fallback mov_si +;; pattern so as to allow FX registers to be reloaded to and from memory directly. + +;; WORK NEEDED: Prove this does actually allow FX registers holding SImode values to +;; be directly loaded and stored to base+6bit offset addresses. + +(define_insn "*sto_si_1_1_off12" + [(set (mem:SI (plus:SI (match_operand:SI 0 "metag_reg12bit_op" "da,Yr") + (match_operand:SI 1 "metag_offset12_si" "O4,Z4"))) + (match_operand:SI 2 "metag_reg_nofloat_op" "da,da"))] + "TARGET_METAC_1_1" + "SETD\\t[%0+%1], %2" + [(set_attr "type" "fast")]) + +(define_insn "*sto_si_1_1_off6" + [(set (mem:SI (plus:SI (match_operand:SI 0 "metag_reg_nofloat_op" "da") + (match_operand:SI 1 "metag_offset6_si" "O4"))) + (match_operand:SI 2 "metag_register_op" "cr"))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETD\\t[%0+%1], %2\\t%@ (*sto SI off6 OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[2])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +(define_insn "*lod_si_off12" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da,da") + (mem:SI (plus:SI (match_operand:SI 1 "metag_reg12bit_op" "da,Yr") + (match_operand:SI 2 "metag_offset12_si" "O4,Z4"))))] + "" + "GETD\\t%0, [%1+%2]" + [(set_attr "type" "load")]) + +(define_insn "*lod_si_off" + [(set (match_operand:SI 0 "metag_register_op" "=cr") + (mem:SI (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "da") + (match_operand:SI 2 "metag_offset6_si" "O4"))))] + "" + { + static const char fmt[] = "F\\tGETD\\t%0, [%1+%2]\\t%@ (*lod SI off6 OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +;; This instruction gets used by reload to generate reload instruction +;; which is why it needs to handle r -> mem and mem -> r alternatives. +;; Do not handle TXRPT as it cannot handle base + 12bit offsets loads/stores +;; Patterns below handle txrpt moving between R_REGS and Wx_REGS + +(define_insn "*mov_si" + [(set (match_operand:SI 0 "metag_register_op" "=e,f,h,l,r,?*cx, r,!*m,*cx,!d") + (match_operand:SI 1 "metag_register_op" "e,f,h,l,r,?*cx,!*m, r,!d, *cx"))] + "" + { + switch (which_alternative) + { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 8: + case 9: + if (METAG_FPC_REG_P (REGNO (operands[0])) + && METAG_FPC_REG_P (REGNO (operands[1]))) + return "F\\tMOV%?\\t%0, %1"; + else + return "MOV%?\\t%0, %1"; + case 6: + if (METAG_FPC_REG_P (REGNO (operands[0]))) + return "F\\tGETD\\t%0, %1"; + else + return "GETD\\t%0, %1"; + case 7: + if (METAG_FPC_REG_P (REGNO (operands[1]))) + return "F\\tSETD\\t%0, %1"; + else + return "SETD\\t%0, %1"; + default: + gcc_unreachable (); + } + } + [(set_attr "type" "fast,fast,fast,fast,slow,fast,load,fast,slow,slow") + (set_attr "cond" "yes,yes,yes,yes,yes,yes,no,no,yes,yes") + (set_attr "memaccess" "none,none,none,none,none,none,load,store,none,none") + (set_attr "predicable" "yes")]) + +(define_insn "ttmov_si" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (unspec_volatile:SI [(match_operand:SI 1 "metag_reg_nofloat_op" "da")] VUNSPEC_TTMOV))] + "" + "TTMOV%?\\t%0, %1 %@ H/W Tracing. Normal MOV but with value also sent to trace port" + [(set_attr "type" "fast") + (set_attr "cond" "yes") + (set_attr "predicable" "yes") + (set_attr "rename" "no")]) + +(define_insn "ttrec" + [(set (match_operand:DI 0 "metag_ttrec_op" "=Wx") + (unspec_volatile:DI [(match_operand:DI 1 "metag_reg_nofloat_op" "da")] VUNSPEC_TTREC))] + "" + "MOVL%?\\t%0, %1, %t1 %@ H/W Tracing. Functionally a NOP. Values sent to trace port" + [(set_attr "type" "fast") + (set_attr "cond" "yes") + (set_attr "predicable" "yes") + (set_attr "rename" "no")]) + +(define_insn "*mov_si_rxrpt_r" + [(set (match_operand:SI 0 "metag_txrpt_op" "=Wx") + (match_operand:SI 1 "metag_register_op" "r"))] + "" + "MOV%?\\t%0, %1" + [(set_attr "type" "fast") + (set_attr "predicable" "yes")]) + +(define_insn "*mov_si_r_txrpt" + [(set (match_operand:SI 0 "metag_register_op" "=r") + (match_operand:SI 1 "metag_txrpt_op" "Wx"))] + "" + "MOV%?\\t%0, %1" + [(set_attr "type" "fast") + (set_attr "predicable" "yes")]) + +(define_insn "*mov_si_txrpt_ri" + [(set (match_operand:SI 0 "metag_txrpt_op" "=Wx,Wx,Wx") + (match_operand:SI 1 "metag_txrpt_src_op" "KIP,J, r"))] + "" + "@ + MOV\\t%0, %1 + MOVT\\t%0, %1 + MOV%?\\t%0, %1" + [(set_attr "type" "fast,fast,fast") + (set_attr "cond" "no,no,yes")]) + +;; movsi - all the immediate to register sets +(define_insn "*cond__mov_si_zero" + [(cond_exec + (match_operator 1 "comparison_operator" + [(match_operand:CCALL 2 "metag__reg" "") + (const_int 0)]) + (set (match_operand:SI 0 "metag_reg_nofloat_op" "=d,a") + (const_int 0)))] + "TARGET_COND_EXEC_OPTIMIZE" + "SUB%?\\t%0, %0, %0" + [(set_attr "type" "fast,slow")]) + +(define_insn "*mov_si_zero" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=d,a") + (const_int 0))] + "TARGET_COND_EXEC_OPTIMIZE" + { + if (metag_cond_exec_p ()) + return "SUB%?\\t%0, %0, %0"; + else + return "MOV\\t%0, #0"; + } + [(set_attr "type" "fast,slow") + (set_attr "cond" "yes")]) + +(define_insn "*set_si_KIP" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (match_operand:SI 1 "metag_KIP_operand" "KIP"))] + "" + "MOV\\t%0, %1\\t\\t%@ (*set si rKIP OK)" + [(set_attr "type" "fast")]) + +(define_insn "*set_si_J" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (match_operand:SI 1 "metag_J_operand" "J"))] + "" + "MOVT\\t%0, %1\\t\\t%@ (*set si rJ OK)" + [(set_attr "type" "fast")]) + +(define_insn "*set_si_HI" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (match_operand:SI 1 "metag_O0_operand" "O0"))] + "" + "MOVT\\t%0, #HI(%c1)\\t%@ (*set si rO0 OK)" + [(set_attr "type" "fast")]) + +(define_insn "*set_si_LO" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (match_operand:SI 1 "metag_O3_operand" "O3"))] + "" + "MOVT\\t%0, #LO(%c1)\\t%@ (*set si rO3 OK)" + [(set_attr "type" "fast")]) + +(define_insn_and_split "*set_si" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da, da,da") + (match_operand:SI 1 "metag_bigint_op" "IPK,J, n"))] + "" + "#" + "reload_completed" + [(const_int 0)] + { + metag_split_movsi_immediate (operands); + DONE; + } + [(set_attr "type" "fast,fast,two")]) + +;; movsi - symbol_ref to register sets +(define_insn "*set_si_symbol_got" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (mem:SI (plus:SI (match_operand:SI 1 "metag_pic_reg" "a") + (const (unspec [(match_operand:SI 2 "symbolic_operand" "")] UNSPEC_GOT)))))] + "METAG_FLAG_PIC&& operands[1] == pic_offset_table_rtx" + "GETD\\t%0, [%1+#(%c2@GOT)]\\t%@ (*set si r-picsym OK)" + [(set_attr "type" "load")]) + +(define_insn "*add_si_HI_symbol_gotoff" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0") + (high:SI (const (unspec [(match_operand:SI 2 "symbolic_operand" "")] UNSPEC_GOTOFF)))))] + "METAG_FLAG_PIC" + "ADDT\\t%0, %1, #HI(%c2@GOTOFF)" + [(set_attr "type" "fast")]) + +(define_insn "*mov_si_HI_symbol_gotoff" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (high:SI (const (unspec [(match_operand:SI 1 "symbolic_operand" "")] UNSPEC_GOTOFF))))] + "METAG_FLAG_PIC" + "MOVT\\t%0, #HI(%c1@GOTOFF)" + [(set_attr "type" "fast")]) + +(define_insn "*add_si_LO_symbol_gotoff" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (lo_sum:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0") + (const (unspec [(match_operand:SI 2 "symbolic_operand" "")] UNSPEC_GOTOFF))))] + "METAG_FLAG_PIC" + "ADD\\t%0, %1, #LO(%c2@GOTOFF)" + [(set_attr "type" "fast")]) + +(define_insn_and_split "*set_si_symbol_gotoff" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=&da") + (plus:SI (match_operand:SI 1 "metag_pic_reg" "a") + (const (unspec [(match_operand:SI 2 "symbolic_operand" "")] UNSPEC_GOTOFF))))] + "METAG_FLAG_PIC&& operands[1] == pic_offset_table_rtx" + "#" + "&& SPLIT_HI_LO_SUM_EARLY" + [(set (match_dup 0) + (match_dup 1)) + (set (match_dup 0) + (plus:SI (match_dup 0) + (high:SI (const (unspec [(match_dup 2)] UNSPEC_GOTOFF))))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (const (unspec [(match_dup 2)] UNSPEC_GOTOFF))))] + "" + [(set_attr "type" "three")]) + +(define_insn_and_split "*set_si_symbol_gotoff_val" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=&da") + (const (unspec [(match_operand:SI 1 "symbolic_operand" "")] UNSPEC_GOTOFF)))] + "METAG_FLAG_PIC" + "#" + "&& SPLIT_HI_LO_SUM_EARLY" + [(set (match_dup 0) + (high:SI (const (unspec [(match_dup 1)] UNSPEC_GOTOFF)))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (const (unspec [(match_dup 1)] UNSPEC_GOTOFF))))] + "" + [(set_attr "type" "two")]) + +(define_insn "*add_si_HI_symbol_large" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0") + (high:SI (match_operand 2 "metag_symlarge_op" ""))))] + "OG_ENABLED" + "ADDT\\t%0, %1, #HI(OG(%c2))" + [(set_attr "type" "fast")]) + +(define_insn "*add_si_LO_symbol_large" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (lo_sum:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0") + (match_operand 2 "metag_symlarge_op" "")))] + "OG_ENABLED" + "ADD\\t%0, %1, #LO(OG(%c2))" + [(set_attr "type" "fast")]) + +(define_insn_and_split "*set_si_symbol_large" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=&l,!&da") + (match_operand:SI 1 "metag_symlarge_op" ""))] + "OG_ENABLED" + "#" + "&& SPLIT_HI_LO_SUM_EARLY" + [(set (match_dup 0) + (match_dup 2)) + (set (match_dup 0) + (plus:SI (match_dup 0) + (high:SI (match_dup 1)))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (match_dup 1)))] + { + operands[2] = gen_rtx_REG (SImode, A1GbP_REG); + } + [(set_attr "type" "three")]) + +(define_insn "*set_si_HI_symbol_global" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (high:SI (match_operand:SI 1 "metag_symglobal_op" "")))] + "!METAG_FLAG_PIC" + "MOVT\\t%0,#HI(%c1)" + [(set_attr "type" "fast")]) + +(define_insn "*add_si_LO_symbol_global" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (lo_sum:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0") + (match_operand:SI 2 "metag_symglobal_op" "" )))] + "!METAG_FLAG_PIC" + "ADD\\t%0, %1, #LO(%c2)" + [(set_attr "type" "fast")]) + +(define_insn_and_split "*set_si_symbol_global" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (match_operand:SI 1 "metag_symglobal_op" ""))] + "!METAG_FLAG_PIC" + "#" + "&& SPLIT_HI_LO_SUM_EARLY" + [(set (match_dup 0) + (high:SI (match_dup 1))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (match_dup 1)))] + "" + [(set_attr "type" "two")]) + +(define_insn "*set_si_symbol_small" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (match_operand:SI 1 "metag_symsmall_op" ""))] + "OG_ENABLED" + "GETD\\t%0, [A1GbP+#OGA(%c1)]\\t%@ (*set si r-ssym OK)" + [(set_attr "type" "load")]) + +(define_insn "*set_si_symbol_off_small" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (const:SI (plus:SI (match_operand:SI 1 "metag_symsmall_op" "") + (match_operand:SI 2 "const_int_operand" ""))))] + "OG_ENABLED" + "GETD\\t%0, [A1GbP+#OGA(%c1+%c2)]\\t%@ (*set si r-ssym OK)" + [(set_attr "type" "load")]) + +(define_insn "*add_si_HI_symbol_off_pic" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0") + (high:SI (const + (plus:SI (unspec [(match_operand:SI 2 "symbolic_operand" "")] UNSPEC_GOTOFF) + (match_operand:SI 3 "const_int_operand" ""))))))] + "METAG_FLAG_PIC" + "ADDT\\t%0, %1, #HI(%c2@GOTOFF+%c3)" + [(set_attr "type" "fast")]) + +(define_insn "*mov_si_HI_symbol_off_pic" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (high:SI (const + (plus:SI (unspec [(match_operand:SI 1 "symbolic_operand" "")] UNSPEC_GOTOFF) + (match_operand:SI 2 "const_int_operand" "")))))] + "METAG_FLAG_PIC" + "MOVT\\t%0, #HI(%c1@GOTOFF+%c2)" + [(set_attr "type" "fast")]) + +(define_insn "*add_si_LO_symbol_off_pic" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (lo_sum:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0") + (const + (plus:SI (unspec [(match_operand:SI 2 "symbolic_operand" "")] UNSPEC_GOTOFF) + (match_operand:SI 3 "const_int_operand" "")))))] + "METAG_FLAG_PIC" + "ADD\\t%0, %1, #LO(%c2@GOTOFF+%c3)" + [(set_attr "type" "fast")]) + +(define_insn_and_split "*set_si_symbol_off_pic" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=&da") + (plus:SI (match_operand:SI 1 "metag_pic_reg" "a") + (const + (plus:SI (unspec [(match_operand:SI 2 "symbolic_operand" "")] UNSPEC_GOTOFF) + (match_operand:SI 3 "const_int_operand" "")))))] + "METAG_FLAG_PIC&& operands[1] == pic_offset_table_rtx" + "#" + "&& SPLIT_HI_LO_SUM_EARLY" + [(set (match_dup 0) + (match_dup 1)) + (set (match_dup 0) + (plus:SI (match_dup 0) + (high:SI (const + (plus:SI (unspec [(match_dup 2)] UNSPEC_GOTOFF) + (match_dup 3)))))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (const + (plus:SI (unspec [(match_dup 2)] UNSPEC_GOTOFF) + (match_dup 3)))))] + "" + [(set_attr "type" "three")]) + +(define_insn_and_split "*set_si_symbol_off_pic_val" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=&da") + (const + (plus:SI (unspec [(match_operand:SI 1 "symbolic_operand" "")] UNSPEC_GOTOFF) + (match_operand:SI 2 "const_int_operand" ""))))] + "METAG_FLAG_PIC" + "#" + "&& SPLIT_HI_LO_SUM_EARLY" + [(set (match_dup 0) + (high:SI (const + (plus:SI (unspec [(match_dup 1)] UNSPEC_GOTOFF) + (match_dup 2))))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (const + (plus:SI (unspec [(match_dup 1)] UNSPEC_GOTOFF) + (match_dup 2)))))] + "" + [(set_attr "type" "two")]) + +(define_insn "*add_si_HI_symbol_off_large" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0") + (high:SI (const:SI (plus:SI (match_operand:SI 2 "metag_symlarge_op" "") + (match_operand:SI 3 "const_int_operand" ""))))))] + "OG_ENABLED" + "ADDT\\t%0, %1, #HI(OG(%c2+%c3))" + [(set_attr "type" "fast")]) + +(define_insn "*add_si_LO_symbol_off_large" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (lo_sum:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0") + (const:SI (plus:SI (match_operand:SI 2 "metag_symlarge_op" "") + (match_operand:SI 3 "const_int_operand" "")))))] + "OG_ENABLED" + "ADD\\t%0, %1, #LO(OG(%c2+%c3))" + [(set_attr "type" "fast")]) + +(define_insn_and_split "*set_si_symbol_off_large" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=l,!da") + (const:SI (plus:SI (match_operand:SI 1 "metag_symlarge_op" "") + (match_operand:SI 2 "const_int_operand" ""))))] + "OG_ENABLED" + "#" + "&& SPLIT_HI_LO_SUM_EARLY" + [(set (match_dup 0) + (match_dup 3)) + (set (match_dup 0) + (plus:SI (match_dup 0) + (high:SI (match_dup 4)))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (match_dup 4)))] + { + operands[3] = gen_rtx_REG (SImode, A1GbP_REG); + operands[4] = gen_rtx_CONST (SImode, + gen_rtx_PLUS (SImode, + operands[1], + operands[2])); + } + [(set_attr "type" "three,four")]) + +(define_insn "*set_si_HI_symbol_off_global" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (high:SI (const:SI (plus:SI (match_operand:SI 1 "metag_symglobal_op" "") + (match_operand:SI 2 "const_int_operand" "")))))] + "!METAG_FLAG_PIC" + "MOVT\\t%0,#HI(%c1+%c2)" + [(set_attr "type" "fast")]) + +(define_insn "*add_si_LO_symbol_off_global" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (lo_sum:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0") + (const:SI (plus:SI (match_operand:SI 2 "metag_symglobal_op" "" ) + (match_operand:SI 3 "const_int_operand" "" )))))] + "!METAG_FLAG_PIC" + "ADD\\t%0, %1, #LO(%c2+%c3)" + [(set_attr "type" "fast")]) + +(define_insn_and_split "*set_si_symbol_off_global" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (const:SI (plus:SI (match_operand:SI 1 "metag_symglobal_op" "") + (match_operand:SI 2 "const_int_operand" ""))))] + "!METAG_FLAG_PIC" + "#" + "&& SPLIT_HI_LO_SUM_EARLY" + [(set (match_dup 0) + (high:SI (match_dup 3))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (match_dup 3)))] + { + operands[3] = gen_rtx_CONST (SImode, + gen_rtx_PLUS (SImode, + operands[1], + operands[2])); + } + [(set_attr "type" "two")]) + +;; movsi - code address to register sets +(define_insn "*set_si_HI_label" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (high:SI (match_operand:SI 1 "code_address" "")))] + "!METAG_FLAG_PIC" + "MOVT\\t%0,#HI(%c1)" + [(set_attr "type" "fast")]) + +(define_insn "*add_si_LO_label" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (lo_sum:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0") + (match_operand:SI 2 "code_address" "" )))] + "!METAG_FLAG_PIC" + "ADD\\t%0, %1, #LO(%c2)" + [(set_attr "type" "fast")]) + +(define_insn_and_split "*set_si_label" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (match_operand:SI 1 "code_address" ""))] + "!METAG_FLAG_PIC" + "#" + "&& SPLIT_HI_LO_SUM_EARLY" + [(set (match_dup 0) + (high:SI (match_dup 1))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (match_dup 1)))] + "" + [(set_attr "type" "two")]) + +(define_insn "*set_si_HI_label_off" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (high:SI (const:SI (plus:SI (match_operand:SI 1 "code_address" "") + (match_operand:SI 2 "const_int_operand" "")))))] + "!METAG_FLAG_PIC" + "MOVT\\t%0,#HI(%c1+%c2)" + [(set_attr "type" "fast")]) + +(define_insn "*add_si_LO_label_off" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (lo_sum:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0") + (const:SI (plus:SI (match_operand:SI 2 "code_address" "" ) + (match_operand:SI 3 "const_int_operand" "" )))))] + "!METAG_FLAG_PIC" + "ADD\\t%0, %1, #LO(%c2+%c3)" + [(set_attr "type" "fast")]) + +(define_insn_and_split "*set_si_label_off" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (const:SI (plus:SI (match_operand:SI 1 "code_address" "") + (match_operand:SI 2 "const_int_operand" ""))))] + "!METAG_FLAG_PIC" + "#" + "&& SPLIT_HI_LO_SUM_EARLY" + [(set (match_dup 0) + (high:SI (match_dup 3))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (match_dup 3)))] + { + operands[3] = gen_rtx_CONST (SImode, + gen_rtx_PLUS (SImode, + operands[1], + operands[2])); + } + [(set_attr "type" "two")]) + +(define_insn "*add_si_HI_label_pic" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0") + (high:SI (const (unspec [(label_ref:SI (match_operand 2 "" ""))] UNSPEC_GOTOFF)))))] + "METAG_FLAG_PIC" + "ADDT\\t%0, %0, #HI(%c2@GOTOFF)" + [(set_attr "type" "fast")]) + +(define_insn "*mov_si_HI_label_pic" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (high:SI (const (unspec [(label_ref:SI (match_operand 1 "" ""))] UNSPEC_GOTOFF))))] + "METAG_FLAG_PIC" + "MOVT\\t%0, #HI(%c1@GOTOFF)" + [(set_attr "type" "fast")]) + +(define_insn "*add_si_LO_label_pic" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (lo_sum:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0") + (const (unspec [(label_ref:SI (match_operand 2 "" ""))] UNSPEC_GOTOFF))))] + "METAG_FLAG_PIC" + "ADD\\t%0, %0, #LO(%c2@GOTOFF)" + [(set_attr "type" "fast")]) + +(define_insn_and_split "*set_si_label_pic" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=&da") + (plus:SI (match_operand:SI 1 "metag_pic_reg" "a") + (const (unspec [(label_ref:SI (match_operand 2 "" ""))] UNSPEC_GOTOFF))))] + "METAG_FLAG_PIC&& operands[1] == pic_offset_table_rtx" + "#" + "&& SPLIT_HI_LO_SUM_EARLY" + [(set (match_dup 0) + (match_dup 1)) + (set (match_dup 0) + (plus:SI (match_dup 0) + (high:SI (const (unspec [(label_ref:SI (match_dup 2))] UNSPEC_GOTOFF))))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (const (unspec [(label_ref:SI (match_dup 2))] UNSPEC_GOTOFF))))] + "" + [(set_attr "type" "three")]) + +(define_insn_and_split "*set_si_label_pic_val" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=&da") + (const (unspec [(label_ref:SI (match_operand 1 "" ""))] UNSPEC_GOTOFF)))] + "METAG_FLAG_PIC" + "#" + "&& SPLIT_HI_LO_SUM_EARLY" + [(set (match_dup 0) + (high:SI (const (unspec [(label_ref:SI (match_dup 1))] UNSPEC_GOTOFF)))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (const (unspec [(label_ref:SI (match_dup 1))] UNSPEC_GOTOFF))))] + "" + [(set_attr "type" "two")]) + +(define_insn "*add_si_HI_label_off_pic" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0") + (high:SI (const + (plus:SI (unspec [(label_ref:SI (match_operand 2 "" ""))] UNSPEC_GOTOFF) + (match_operand:SI 3 "const_int_operand" ""))))))] + "METAG_FLAG_PIC" + "ADDT\\t%0, %1, #HI(%c2@GOTOFF+%c3)" + [(set_attr "type" "fast")]) + +(define_insn "*mov_si_HI_label_off_pic" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (high:SI (const + (plus:SI (unspec [(label_ref:SI (match_operand 1 "" ""))] UNSPEC_GOTOFF) + (match_operand:SI 2 "const_int_operand" "")))))] + "METAG_FLAG_PIC" + "MOVT\\t%0, #HI(%c1@GOTOFF+%c2)" + [(set_attr "type" "fast")]) + +(define_insn "*add_si_LO_label_off_pic" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (lo_sum:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0") + (const + (plus:SI (unspec [(label_ref:SI (match_operand 2 "" ""))] UNSPEC_GOTOFF) + (match_operand:SI 3 "const_int_operand" "")))))] + "METAG_FLAG_PIC" + "ADD\\t%0, %0, #LO(%c2@GOTOFF+%c3)" + [(set_attr "type" "fast")]) + +(define_insn_and_split "*set_si_label_off_pic" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=&da") + (plus:SI (match_operand:SI 1 "metag_pic_reg" "a") + (const + (plus:SI (unspec [(label_ref:SI (match_operand 2 "" ""))] UNSPEC_GOTOFF) + (match_operand:SI 3 "const_int_operand" "")))))] + "METAG_FLAG_PIC" + "#" + "&& SPLIT_HI_LO_SUM_EARLY" + [(set (match_dup 0) + (match_dup 1)) + (set (match_dup 0) + (plus:SI (match_dup 0) + (high:SI (const + (plus:SI (unspec [(label_ref:SI (match_dup 2))] UNSPEC_GOTOFF) + (match_dup 3)))))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (const + (plus:SI (unspec [(label_ref:SI (match_dup 2))] UNSPEC_GOTOFF) + (match_dup 3)))))] + "" + [(set_attr "type" "three")]) + +(define_insn_and_split "*set_si_label_off_pic_val" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=&da") + (const + (plus:SI (unspec [(label_ref:SI (match_operand 1 "" ""))] UNSPEC_GOTOFF) + (match_operand:SI 2 "const_int_operand" ""))))] + "METAG_FLAG_PIC" + "#" + "&& SPLIT_HI_LO_SUM_EARLY" + [(set (match_dup 0) + (high:SI (const + (plus:SI (unspec [(label_ref:SI (match_dup 1))] UNSPEC_GOTOFF) + (match_dup 2))))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (const + (plus:SI (unspec [(label_ref:SI (match_dup 1))] UNSPEC_GOTOFF) + (match_dup 2)))))] + "" + [(set_attr "type" "two")]) + +;; ----------------------------------------------------------------------------- +;; | Matching SI store post/pre_inc/dec/modify and emitting ASM | +;; | ** These rules MUST come before the put_si_1_1 rule ** | +;; ----------------------------------------------------------------------------- + +(define_insn "*sto_si_post_inc" + [(set (mem:SI (post_inc:SI (match_operand:SI 0 "metag_reg_nofloat_op" "+da"))) + (match_operand:SI 1 "metag_register_op" "cr"))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETD\\t[%0++], %1\\t%@ (*store SI post_inc OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[1])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +(define_insn "*sto_si_post_dec" + [(set (mem:SI (post_dec:SI (match_operand:SI 0 "metag_reg_nofloat_op" "+da"))) + (match_operand:SI 1 "metag_register_op" "cr"))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETD\\t[%0--], %1\\t%@ (*store SI post_dec OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[1])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +(define_insn "*sto_si_pre_inc" + [(set (mem:SI (pre_inc:SI (match_operand:SI 0 "metag_reg_nofloat_op" "+da"))) + (match_operand:SI 1 "metag_register_op" "cr"))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETD\\t[++%0], %1\\t%@ (*store SI pre_inc OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[1])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +(define_insn "*sto_si_pre_dec" + [(set (mem:SI (pre_dec:SI (match_operand:SI 0 "metag_reg_nofloat_op" "+da"))) + (match_operand:SI 1 "metag_register_op" "cr"))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETD\\t[--%0], %1\\t%@ (*store SI pre_dec OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[1])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +(define_insn "*sto_si_post_modify_disp" + [(set (mem:SI (post_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+e, f, h, l") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_si" "O4,O4,O4,O4")))) + (match_operand:SI 2 "metag_register_op" "t, u, y, z"))] + "!TARGET_METAC_1_1" + "SETD\\t[%0+%1++], %2\\t%@ (*store SI post_modify_disp OK)" + [(set_attr "type" "fast")]) + +(define_insn "*sto_si_post_modify_disp_1_1" + [(set (mem:SI (post_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+da") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_si" "O4")))) + (match_operand:SI 2 "metag_register_op" "cr"))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETD\\t[%0+%1++], %2\\t%@ (*store SI post_modify_disp OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[2])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +(define_insn "*sto_si_post_modify_reg" + [(set (mem:SI (post_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+e, f, h, l") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_reg_nofloat_op" "e, f, h, l")))) + (match_operand:SI 2 "metag_register_op" "ct,cu,cy,cz"))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETD\\t[%0+%1++], %2\\t%@ (*store SI post_modify_reg OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[2])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +(define_insn "*sto_si_pre_modify_disp" + [(set (mem:SI (pre_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+e, f, h, l") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_si" "O4,O4,O4,O4")))) + (match_operand:SI 2 "metag_reg_nofloat_op" "t, u, y, z"))] + "!TARGET_METAC_1_1" + "SETD\\t[%0++%1], %2\\t%@ (*store SI pre_modify_disp OK)" + [(set_attr "type" "fast,fast,fast,fast")]) + +(define_insn "*sto_si_pre_modify_disp_1_1" + [(set (mem:SI (pre_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+da") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_si" "O4")))) + (match_operand:SI 2 "metag_register_op" "cr"))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETD\\t[%0++%1], %2\\t%@ (*store SI pre_modify_disp OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[2])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +(define_insn "*sto_si_pre_modify_reg_1_1" + [(set (mem:SI (pre_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+e, f, h, l") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_reg_nofloat_op" "e, f, h, l")))) + (match_operand:SI 2 "metag_register_op" "ct,cu,cy,cz"))] + "" + { + static const char fmt[] = "F\\tSETD\\t[%0++%1], %2\\t%@ (*store SI pre_modify_reg OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[2])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +;; ----------------------------------------------------------------------------- + +;; ----------------------------------------------------------------------------- +;; | Non-side effecting base+offset store SI and catchall store SI cases | +;; ----------------------------------------------------------------------------- + +;; movsi - base+index register to memory (stors's) +(define_insn "*sto_si_mar" + [(set (mem:SI (plus:SI (match_operand:SI 0 "metag_regnofrm_op" "%e, f, h, l") + (match_operand:SI 1 "metag_regnofrm_op" " e, f, h, l"))) + (match_operand:SI 2 "metag_register_op" "ct,cu,cy,cz"))] + "" + { + static const char fmt[] = "F\\tSETD\\t[%0+%1], %2\\t%@ (*sto si mar OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[2])) ? 0 : 2]; + } + [(set_attr "type" "fast") + (set_attr "length" "4,4,4,4")]) + +;; movsi - register to memory (stores) some are fast, rest match spillsi below +(define_insn "*sto_si_reg_indirect" + [(set (mem:SI (match_operand:SI 0 "metag_reg_nofloat_op" "e,f,h,l,!*da")) + (match_operand:SI 1 "metag_register_op" "t,u,y,z, *da"))] + "TARGET_COND_EXEC_OPTIMIZE && !TARGET_METAC_1_1" + "@ + SETD%?\\t[%0], %1\\t%@ (*sto si [e]t OK) + SETD%?\\t[%0], %1\\t%@ (*sto si [f]u OK) + SETD%?\\t[%0], %1\\t%@ (*sto si [h]y OK) + SETD%?\\t[%0], %1\\t%@ (*sto si [l]z OK) + #" + [(set_attr "type" "fast,fast,fast,fast,invalid") + (set_attr "cond" "yes,yes,yes,yes,no")]) + +(define_insn "*sto_si" + [(set (match_operand:SI 0 "memory_operand" "=Tr,Te,Tf,Th,Tl,!*m") + (match_operand:SI 1 "metag_register_op" "r, t, u, y, z, !*da"))] + "!TARGET_METAC_1_1 && !reload_completed" + "@ + SETD\\t%0, %1\\t%@ (*sto si [r]r OK) + SETD\\t%0, %1\\t%@ (*sto si [e]t OK) + SETD\\t%0, %1\\t%@ (*sto si [f]u OK) + SETD\\t%0, %1\\t%@ (*sto si [h]y OK) + SETD\\t%0, %1\\t%@ (*sto si [l]z OK) + SETD\\t%0, %1\\t%@ (*sto si [m]r OK)" + [(set_attr "type" "fast,fast,fast,fast,fast,invalid")]) + +(define_insn "*sto_si_postreload" + [(set (match_operand:SI 0 "memory_operand" "=Tr,Te,Tf,Th,Tl") + (match_operand:SI 1 "metag_register_op" "r, t, u, y, z"))] + "!TARGET_METAC_1_1 && reload_completed" + "@ + SETD\\t%0, %1\\t%@ (*sto si [r]r OK) + SETD\\t%0, %1\\t%@ (*sto si [e]r OK) + SETD\\t%0, %1\\t%@ (*sto si [f]r OK) + SETD\\t%0, %1\\t%@ (*sto si [h]r OK) + SETD\\t%0, %1\\t%@ (*sto si [l]r OK)" + [(set_attr "type" "fast")]) + +;; movsi - all the register to register|memory moves +(define_insn "*sto_si_reg_indirect_1_1" + [(set (mem:SI (match_operand:SI 0 "metag_reg_nofloat_op" "da")) + (match_operand:SI 1 "metag_register_op" "cr"))] + "TARGET_COND_EXEC_OPTIMIZE && TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETD%?\\t[%0], %1\\t%@ (*sto si [r]r OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[1])) ? 0 : 2]; + } + [(set_attr "type" "fast") + (set_attr "cond" "yes") + (set_attr "predicable" "yes")]) + +(define_insn "*sto_si_1_1" + [(set (match_operand:SI 0 "memory_operand" "=Tr,Te,Tf,Th,Tl,!*m") + (match_operand:SI 1 "metag_reg_nofloat_op" "r, t, u, y, z, !*da"))] + "TARGET_METAC_1_1 && !reload_completed" + "@ + SETD\\t%0, %1\\t%@ (*sto si [r]r OK) + SETD\\t%0, %1\\t%@ (*sto si [e]t OK) + SETD\\t%0, %1\\t%@ (*sto si [f]u OK) + SETD\\t%0, %1\\t%@ (*sto si [h]y OK) + SETD\\t%0, %1\\t%@ (*sto si [l]z OK) + SETD\\t%0, %1\\t%@ (*sto si [m]r OK)" + [(set_attr "type" "fast,fast,fast,fast,fast,invalid")]) + +(define_insn "*sto_si_1_1_postreload" + [(set (match_operand:SI 0 "memory_operand" "=Tr,Te,Tf,Th,Tl") + (match_operand:SI 1 "metag_reg_nofloat_op" "r, t, u, y, z"))] + "TARGET_METAC_1_1 && reload_completed" + "@ + SETD\\t%0, %1\\t%@ (*sto si [r]r OK) + SETD\\t%0, %1\\t%@ (*sto si [e]t OK) + SETD\\t%0, %1\\t%@ (*sto si [f]u OK) + SETD\\t%0, %1\\t%@ (*sto si [h]y OK) + SETD\\t%0, %1\\t%@ (*sto si [l]z OK)" + [(set_attr "type" "fast")]) + +;; spillsi - register to memory (stores) from source/dest in same bank +(define_split + [(set (match_operand:SI 0 "memory_operand" "") + (match_operand:SI 1 "metag_register_op" ""))] + "!TARGET_METAC_1_1 + && reload_completed + && metag_slow_store (operands[0], operands[1])" + [(set (match_dup 2) + (match_dup 1)) + (set (match_dup 0) + (match_dup 2))] + { + operands[2] = metag_gen_safe_temp (SImode, operands[1]); + } +) + +;; ----------------------------------------------------------------------------- + +;; ----------------------------------------------------------------------------- +;; | Matching SI load post/pre_inc/dec/modify and emitting ASM | +;; ----------------------------------------------------------------------------- + +(define_insn "*lod_si_post_inc" + [(set (match_operand:SI 0 "metag_register_op" "=cr") + (mem:SI (post_inc:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da"))))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tGETD\\t%0, [%1++]\\t%@ (*load SI post_inc OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lod_si_post_dec" + [(set (match_operand:SI 0 "metag_register_op" "=cr") + (mem:SI (post_dec:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da"))))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tGETD\\t%0, [%1--]\\t%@ (*load SI post_dec OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lod_si_pre_inc" + [(set (match_operand:SI 0 "metag_register_op" "=cr") + (mem:SI (pre_inc:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da"))))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tGETD\\t%0, [++%1]\\t%@ (*load SI pre_inc OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lod_si_pre_dec" + [(set (match_operand:SI 0 "metag_register_op" "=cr") + (mem:SI (pre_dec:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da"))))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tGETD\\t%0, [--%1]\\t%@ (*load SI pre_dec OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lod_si_post_modify_disp" + [(set (match_operand:SI 0 "metag_register_op" "=cr") + (mem:SI (post_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+da") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_offset6_si" "O4")))))] + "" + { + static const char fmt[] = "F\\tGETD\\t%0, [%1+%2++]\\t%@ (*load SI post_modify_disp OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lod_si_post_modify_reg" + [(set (match_operand:SI 0 "metag_register_op" "=cr,cr,cr,cr") + (mem:SI (post_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+e, f, h, l") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_reg_nofloat_op" "e, f, h, l")))))] + "" + { + static const char fmt[] = "F\\tGETD\\t%0, [%1+%2++]\\t%@ (*load SI post_modify_reg OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lod_si_pre_modify_disp" + [(set (match_operand:SI 0 "metag_register_op" "=cr") + (mem:SI (pre_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+da") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_offset6_si" "O4")))))] + "" + { + static const char fmt[] = "F\\tGETD\\t%0, [%1++%2]\\t%@ (*load SI pre_modify_disp OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lod_si_pre_modify_reg" + [(set (match_operand:SI 0 "metag_register_op" "=cr,cr,cr,cr") + (mem:SI (pre_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+e, f, h, l") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_reg_nofloat_op" "e, f, h, l")))))] + "" + { + static const char fmt[] = "F\\tGETD\\t%0, [%1++%2]\\t%@ (*load SI pre_modify_reg OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +;; ----------------------------------------------------------------------------- + +;; ----------------------------------------------------------------------------- +;; | Non-side effecting base+offset load SI and catchall load SI | +;; ----------------------------------------------------------------------------- + +(define_insn "*lod_si" + [(set (match_operand:SI 0 "metag_register_op" "=cr") + (mem:SI (match_operand:SI 1 "metag_reg_nofloat_op" "da")))] + "" + { + static const char fmt[] = "F\\tGETD\\t%0, [%1]"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +;; movsi - base+index memory to register (loads) +(define_insn "*lod_si_rma" + [(set (match_operand:SI 0 "metag_register_op" "=cr,cr,cr,cr") + (mem:SI (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "e, f, h, l") + (match_operand:SI 2 "metag_regnofrm_op" "e, f, h, l"))))] + "" + { + static const char fmt[] = "F\\tGETD\\t%0, [%1+%2]\\t%@ (*lod si rma OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +;; Removed FPC alternative owing to lack of 12bit offset support +;; base+12bit load to FX occurs during conversion of virtual_stack_args +(define_insn "*lod_si_mem" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (match_operand:SI 1 "memory_operand" "m"))] + "" + "GETD\\t%0, %1\\t%@ (*lod si rm OK)" + [(set_attr "type" "load")]) + +;; ----------------------------------------------------------------------------- + +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +;; movhi is made up of many parts.. ;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +(define_expand "movhi" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (match_operand:HI 1 "general_operand" ""))] + "" + { + if (MEM_P (operands[0])) + { + /* All except mem = const or mem = mem can be done quickly */ + operands[1] = force_reg (HImode, operands[1]); + } + } +) + +;; movhi - all the register to register moves +(define_insn "*mov_hi" + [(set (match_operand:HI 0 "metag_register_op" "=e,f,h,l,cx,d, cx,da") + (match_operand:HI 1 "metag_register_op" "e,f,h,l,cx,cx,d, da"))] + "" + "MOV%?\\t%0, %1\\t\\t%@ (*mov hi rr OK)" + [(set_attr "type" "fast,fast,fast,fast,fast,slow,slow,slow") + (set_attr "cond" "yes,yes,yes,yes,yes,yes,yes,yes") + (set_attr "predicable" "yes")]) + +;; movhi - all the immediate to register sets +(define_insn "*set_hi" + [(set (match_operand:HI 0 "metag_reg_nofloat_op" "=da") + (match_operand:HI 1 "metag_int_operand" "KIP"))] + "" + "MOV\\t%0, %1\\t\\t%@ (*set hi rI OK)" + [(set_attr "type" "fast")]) + +;; ----------------------------------------------------------------------------- + +;; ----------------------------------------------------------------------------- +;; | Matching HI store post/pre_inc/dec/modify and emitting ASM | +;; ----------------------------------------------------------------------------- + +(define_insn "*sto_hi_post_inc" + [(set (mem:HI (post_inc:SI (match_operand:SI 0 "metag_reg_nofloat_op" "+da"))) + (match_operand:HI 1 "metag_reg_nofloat_op" "da"))] + "TARGET_METAC_1_1" + "SETW\\t[%0++], %1\\t%@ (*store HI post_inc OK)" + [(set_attr "type" "fast")]) + +(define_insn "*sto_hi_post_dec" + [(set (mem:HI (post_dec:SI (match_operand:SI 0 "metag_reg_nofloat_op" "+da"))) + (match_operand:HI 1 "metag_reg_nofloat_op" "da"))] + "TARGET_METAC_1_1" + "SETW\\t[%0--], %1\\t%@ (*store HI post_dec OK)" + [(set_attr "type" "fast")]) + +(define_insn "*sto_hi_pre_inc" + [(set (mem:HI (pre_inc:SI (match_operand:SI 0 "metag_reg_nofloat_op" "+da"))) + (match_operand:HI 1 "metag_reg_nofloat_op" "da"))] + "TARGET_METAC_1_1" + "SETW\\t[++%0], %1\\t%@ (*store HI pre_inc OK)" + [(set_attr "type" "fast")]) + +(define_insn "*sto_hi_pre_dec" + [(set (mem:HI (pre_dec:SI (match_operand:SI 0 "metag_reg_nofloat_op" "+da"))) + (match_operand:HI 1 "metag_reg_nofloat_op" "da"))] + "TARGET_METAC_1_1" + "SETW\\t[--%0], %1\\t%@ (*store HI pre_dec OK)" + [(set_attr "type" "fast")]) + +(define_insn "*sto_hi_post_modify_disp" + [(set (mem:HI (post_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+e, f, h, l") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_hi" "O2,O2,O2,O2")))) + (match_operand:HI 2 "metag_reg_nofloat_op" "t, u, y, z"))] + "!TARGET_METAC_1_1" + "SETW\\t[%0+%1++], %2\\t%@ (*store HI post_modify_disp OK)" + [(set_attr "type" "fast,fast,fast,fast")]) + +(define_insn "*sto_hi_post_modify_disp_1_1" + [(set (mem:HI (post_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+da") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_hi" "O2")))) + (match_operand:HI 2 "metag_reg_nofloat_op" "da"))] + "TARGET_METAC_1_1" + "SETW\\t[%0+%1++], %2\\t%@ (*store HI post_modify_disp OK)" + [(set_attr "type" "fast")]) + +(define_insn "*sto_hi_post_modify_reg" + [(set (mem:HI (post_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+e,f,h,l") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_reg_nofloat_op" "e,f,h,l")))) + (match_operand:HI 2 "metag_reg_nofloat_op" "t,u,y,z"))] + "" + "SETW\\t[%0+%1++], %2\\t%@ (*store HI post_modify_reg OK)" + [(set_attr "type" "fast,fast,fast,fast")]) + +(define_insn "*sto_hi_pre_modify_disp" + [(set (mem:HI (pre_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+e, f, h, l") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_hi" "O2,O2,O2,O2")))) + (match_operand:HI 2 "metag_reg_nofloat_op" "t, u, y, z"))] + "!TARGET_METAC_1_1" + "SETW\\t[%0++%1], %2\\t%@ (*store HI pre_modify_disp OK)" + [(set_attr "type" "fast,fast,fast,fast")]) + +(define_insn "*sto_hi_pre_modify_disp_1_1" + [(set (mem:HI (pre_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+da") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_hi" "O2")))) + (match_operand:HI 2 "metag_reg_nofloat_op" "da"))] + "TARGET_METAC_1_1" + "SETW\\t[%0++%1], %2\\t%@ (*store HI pre_modify_disp OK)" + [(set_attr "type" "fast")]) + +(define_insn "*sto_hi_pre_modify_reg" + [(set (mem:HI (pre_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+e,f,h,l") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_reg_nofloat_op" "e,f,h,l")))) + (match_operand:HI 2 "metag_reg_nofloat_op" "t,u,y,z"))] + "" + "SETW\\t[%0++%1], %2\\t%@ (*store HI pre_modify_reg OK)" + [(set_attr "type" "fast,fast,fast,fast")]) + +;; ----------------------------------------------------------------------------- + +;; ----------------------------------------------------------------------------- +;; | Non-side effecting base+offset store HI and catchall store HI cases | +;; ----------------------------------------------------------------------------- + +;; movhi - base+index register to memory (stors's) +(define_insn "*sto_hi_mar" + [(set (mem:HI (plus:SI (match_operand:SI 0 "metag_regnofrm_op" "%e,f,h,l") + (match_operand:SI 1 "metag_regnofrm_op" " e,f,h,l"))) + (match_operand:HI 2 "metag_reg_nofloat_op" " t,u,y,z"))] + "" + "SETW\\t[%0+%1], %2\\t%@ (*sto hi mar OK)" + [(set_attr "type" "fast") + (set_attr "length" "4,4,4,4")]) + +;; movhi - register to memory (stores) some are fast, rest match spillhi below +(define_insn "*sto_hi_reg_indirect" + [(set (mem:HI (match_operand:SI 0 "metag_reg_nofloat_op" "e,f,h,l,!*da")) + (match_operand:HI 1 "metag_reg_nofloat_op" "t,u,y,z, *da"))] + "TARGET_COND_EXEC_OPTIMIZE && !TARGET_METAC_1_1" + "@ + SETW%?\\t[%0], %1\\t%@ (*sto hi [e]t OK) + SETW%?\\t[%0], %1\\t%@ (*sto hi [f]u OK) + SETW%?\\t[%0], %1\\t%@ (*sto hi [h]y OK) + SETW%?\\t[%0], %1\\t%@ (*sto hi [l]z OK) + #" + [(set_attr "type" "fast,fast,fast,fast,invalid") + (set_attr "cond" "yes,yes,yes,yes,no")]) + +(define_insn "*sto_hi" + [(set (match_operand:HI 0 "memory_operand" "=Tr,Te,Tf,Th,Tl,!*m") + (match_operand:HI 1 "metag_reg_nofloat_op" "r, t, u, y, z, !*da"))] + "!TARGET_METAC_1_1 && !reload_completed" + "@ + SETW\\t%0, %1\\t%@ (*sto hi [r]r OK) + SETW\\t%0, %1\\t%@ (*sto hi [e]t OK) + SETW\\t%0, %1\\t%@ (*sto hi [f]u OK) + SETW\\t%0, %1\\t%@ (*sto hi [h]y OK) + SETW\\t%0, %1\\t%@ (*sto hi [l]z OK) + SETW\\t%0, %1\\t%@ (*sto hi [m]r OK)" + [(set_attr "type" "fast,fast,fast,fast,fast,invalid")]) + +(define_insn "*sto_hi_postreload" + [(set (match_operand:HI 0 "memory_operand" "=Tr,Te,Tf,Th,Tl") + (match_operand:HI 1 "metag_reg_nofloat_op" "r, t, u, y, z"))] + "!TARGET_METAC_1_1 && reload_completed" + "@ + SETW\\t%0, %1\\t%@ (*sto hi [r]r OK) + SETW\\t%0, %1\\t%@ (*sto hi [e]t OK) + SETW\\t%0, %1\\t%@ (*sto hi [f]u OK) + SETW\\t%0, %1\\t%@ (*sto hi [h]y OK) + SETW\\t%0, %1\\t%@ (*sto hi [l]z OK)" + [(set_attr "type" "fast")]) + +(define_insn "*sto_hi_reg_indirect_1_1" + [(set (mem:HI (match_operand:SI 0 "metag_reg_nofloat_op" "da")) + (match_operand:HI 1 "metag_reg_nofloat_op" "da"))] + "TARGET_COND_EXEC_OPTIMIZE && TARGET_METAC_1_1" + "SETW%?\\t[%0], %1\\t%@ (*sto hi [r]r OK)" + [(set_attr "type" "fast") + (set_attr "cond" "yes") + (set_attr "predicable" "yes")]) + +(define_insn "*sto_hi_1_1_off12" + [(set (mem:HI (plus:SI (match_operand:SI 0 "metag_reg12bit_op" "da,Yr") + (match_operand:SI 1 "metag_offset12_hi" "O2,Z2"))) + (match_operand:HI 2 "metag_reg_nofloat_op" "da,da"))] + "TARGET_METAC_1_1" + "SETW\\t[%0+%1], %2" + [(set_attr "type" "fast")]) + +(define_insn "*sto_hi_1_1_off6" + [(set (mem:HI (plus:SI (match_operand:SI 0 "metag_reg_nofloat_op" "da") + (match_operand:SI 1 "metag_offset6_hi" "O2"))) + (match_operand:HI 2 "metag_reg_nofloat_op" "da"))] + "TARGET_METAC_1_1" + "SETW\\t[%0+%1], %2" + [(set_attr "type" "fast")]) + +(define_insn "*sto_hi_1_1" + [(set (match_operand:HI 0 "memory_operand" "=Tr,Te,Tf,Th,Tl,!*m") + (match_operand:HI 1 "metag_reg_nofloat_op" "r, t, u, y, z, !*da"))] + "TARGET_METAC_1_1 && !reload_completed" + "@ + SETW\\t%0, %1\\t%@ (*sto hi [r]r OK) + SETW\\t%0, %1\\t%@ (*sto hi [e]r OK) + SETW\\t%0, %1\\t%@ (*sto hi [f]r OK) + SETW\\t%0, %1\\t%@ (*sto hi [h]r OK) + SETW\\t%0, %1\\t%@ (*sto hi [l]r OK) + SETW\\t%0, %1\\t%@ (*sto hi [m]r OK)" + [(set_attr "type" "fast,fast,fast,fast,fast,invalid")]) + +(define_insn "*sto_hi_1_1_postreload" + [(set (match_operand:HI 0 "memory_operand" "=Tr,Te,Tf,Th,Tl") + (match_operand:HI 1 "metag_reg_nofloat_op" "r, t, u, y, z"))] + "TARGET_METAC_1_1 && reload_completed" + "@ + SETW\\t%0, %1\\t%@ (*sto hi [r]r OK) + SETW\\t%0, %1\\t%@ (*sto hi [e]r OK) + SETW\\t%0, %1\\t%@ (*sto hi [f]r OK) + SETW\\t%0, %1\\t%@ (*sto hi [h]r OK) + SETW\\t%0, %1\\t%@ (*sto hi [l]r OK)" + [(set_attr "type" "fast")]) + +;; spillhi - register to memory (stores) from source/dest in same bank +(define_split + [(set (match_operand:HI 0 "memory_operand" "") + (match_operand:HI 1 "metag_register_op" ""))] + "!TARGET_METAC_1_1 + && reload_completed + && metag_slow_store (operands[0], operands[1])" + [(set (match_dup 2) + (match_dup 1)) + (set (match_dup 0) + (match_dup 2))] + { + operands[2] = metag_gen_safe_temp (HImode, operands[1]); + } +) + +;; ----------------------------------------------------------------------------- + +;; ----------------------------------------------------------------------------- +;; | Matching HI load post/pre_inc/dec/modify and emitting ASM | +;; ----------------------------------------------------------------------------- + +(define_insn "*lod_hi_post_inc" + [(set (match_operand:HI 0 "metag_reg_nofloat_op" "=da") + (mem:HI (post_inc:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da"))))] + "TARGET_METAC_1_1" + "GETW\\t%0, [%1++]\\t%@ (*load HI post_inc OK)" + [(set_attr "type" "load")]) + +(define_insn "*lod_hi_post_dec" + [(set (match_operand:HI 0 "metag_reg_nofloat_op" "=da") + (mem:HI (post_dec:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da"))))] + "TARGET_METAC_1_1" + "GETW\\t%0, [%1--]\\t%@ (*load HI post_dec OK)" + [(set_attr "type" "load")]) + +(define_insn "*lod_hi_pre_inc" + [(set (match_operand:HI 0 "metag_reg_nofloat_op" "=da") + (mem:HI (pre_inc:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da"))))] + "TARGET_METAC_1_1" + "GETW\\t%0, [++%1]\\t%@ (*load HI pre_inc OK)" + [(set_attr "type" "load")]) + +(define_insn "*lod_hi_pre_dec" + [(set (match_operand:HI 0 "metag_reg_nofloat_op" "=da") + (mem:HI (pre_dec:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da"))))] + "TARGET_METAC_1_1" + "GETW\\t%0, [--%1]\\t%@ (*load HI pre_dec OK)" + [(set_attr "type" "load")]) + +(define_insn "*lod_hi_post_modify_disp" + [(set (match_operand:HI 0 "metag_reg_nofloat_op" "=da") + (mem:HI (post_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+da") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_offset6_hi" "O2")))))] + "" + "GETW\\t%0, [%1+%2++]\\t%@ (*load HI post_modify_disp OK)" + [(set_attr "type" "load")]) + +(define_insn "*lod_hi_post_modify_reg" + [(set (match_operand:HI 0 "metag_reg_nofloat_op" "=da,da,da,da") + (mem:HI (post_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+e, f, h, l") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_reg_nofloat_op" "e, f, h, l")))))] + "" + "GETW\\t%0, [%1+%2++]\\t%@ (*load HI post_modify_reg OK)" + [(set_attr "type" "load")]) + +(define_insn "*lod_hi_pre_modify_disp" + [(set (match_operand:HI 0 "metag_reg_nofloat_op" "=da") + (mem:HI (pre_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+da") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_offset6_hi" "O2")))))] + "" + "GETW\\t%0, [%1++%2]\\t%@ (*load HI pre_modify_disp OK)" + [(set_attr "type" "load")]) + +(define_insn "*lod_hi_pre_modify_reg" + [(set (match_operand:HI 0 "metag_reg_nofloat_op" "=da,da,da,da") + (mem:HI (pre_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+e,f,h,l") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_reg_nofloat_op" "e,f,h,l")))))] + "" + "GETW\\t%0, [%1++%2]\\t%@ (*load HI pre_modify_reg OK)" + [(set_attr "type" "load")]) + +;; ----------------------------------------------------------------------------- + +;; ----------------------------------------------------------------------------- +;; | Non-side effecting base+offset load HI and catchall load HI | +;; ----------------------------------------------------------------------------- + +(define_insn "*lod_hi" + [(set (match_operand:HI 0 "metag_reg_nofloat_op" "=da") + (mem:HI (match_operand:SI 1 "metag_reg_nofloat_op" "da")))] + "" + "GETW\\t%0, [%1]\\t%@ (*lod hi rma OK)" + [(set_attr "type" "load")]) + +;; movhi - base+index memory to register (loads) +(define_insn "*lod_hi_rma" + [(set (match_operand:HI 0 "metag_reg_nofloat_op" "=da,da,da,da") + (mem:HI (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "%e, f, h, l ") + (match_operand:SI 2 "metag_regnofrm_op" "e, f, h, l "))))] + "" + "GETW\\t%0, [%1+%2]\\t%@ (*lod hi rma OK)" + [(set_attr "type" "load")]) + +(define_insn "*lod_hi_off12" + [(set (match_operand:HI 0 "metag_reg_nofloat_op" "=da,da") + (mem:HI (plus:SI (match_operand:SI 1 "metag_reg12bit_op" "da,Yr") + (match_operand:SI 2 "metag_offset12_hi" "O2,Z2"))))] + "" + "GETW\\t%0, [%1+%2]" + [(set_attr "type" "load")]) + +(define_insn "*lod_hi_off" + [(set (match_operand:HI 0 "metag_reg_nofloat_op" "=da") + (mem:HI (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "da") + (match_operand:SI 2 "metag_offset6_hi" "O2"))))] + "" + "GETW\\t%0, [%1+%2]" + [(set_attr "type" "load")]) + +(define_insn "*lod_hi_mem" + [(set (match_operand:HI 0 "metag_reg_nofloat_op" "=da") + (match_operand:HI 1 "memory_operand" "m"))] + "" + "GETW\\t%0, %1\\t%@ (*lod hi rm OK)" + [(set_attr "type" "load")]) + +;; ----------------------------------------------------------------------------- + +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +;; movqi is made up of many parts.. ;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +(define_expand "movqi" + [(set (match_operand:QI 0 "nonimmediate_operand" "") + (match_operand:QI 1 "general_operand" ""))] + "" + { + if (MEM_P (operands[0])) + { + /* All except mem = const or mem = mem can be done quickly */ + operands[1] = force_reg (QImode, operands[1]); + } + } +) + +;; movqi - all the register to register moves +(define_insn "*mov_qi" + [(set (match_operand:QI 0 "metag_register_op" "=e,f,h,l,cx,cd,?da") + (match_operand:QI 1 "metag_register_op" "e,f,h,l,cx,cd,?da"))] + "" + "MOV%?\\t%0, %1\\t\\t%@ (*mov qi rr OK)" + [(set_attr "type" "fast,fast,fast,fast,fast,slow,slow") + (set_attr "cond" "yes,yes,yes,yes,yes,yes,yes") + (set_attr "predicable" "yes")]) + +;; movqi - all the immediate to register sets +(define_insn "*set_qi" + [(set (match_operand:QI 0 "metag_reg_nofloat_op" "=da") + (match_operand:QI 1 "metag_int_operand" "KP"))] + "" + "MOV\\t%0, %1\\t\\t%@ (*set qi rI OK)" + [(set_attr "type" "fast")]) + +;; ----------------------------------------------------------------------------- +;; | Matching QI store post/pre_inc/dec/modify and emitting ASM | +;; ----------------------------------------------------------------------------- + +(define_insn "*sto_qi_post_inc" + [(set (mem:QI (post_inc:SI (match_operand:SI 0 "metag_reg_nofloat_op" "+da"))) + (match_operand:QI 1 "metag_reg_nofloat_op" "da"))] + "TARGET_METAC_1_1" + "SETB\\t[%0++], %1\\t%@ (*store QI post_inc OK)" + [(set_attr "type" "fast")]) + +(define_insn "*sto_qi_post_dec" + [(set (mem:QI (post_dec:SI (match_operand:SI 0 "metag_reg_nofloat_op" "+da"))) + (match_operand:QI 1 "metag_reg_nofloat_op" "da"))] + "TARGET_METAC_1_1" + "SETB\\t[%0--], %1\\t%@ (*store QI post_dec OK)" + [(set_attr "type" "fast")]) + +(define_insn "*sto_qi_pre_inc" + [(set (mem:QI (pre_inc:SI (match_operand:SI 0 "metag_reg_nofloat_op" "+da"))) + (match_operand:QI 1 "metag_reg_nofloat_op" "da"))] + "TARGET_METAC_1_1" + "SETB\\t[++%0], %1\\t%@ (*store QI pre_inc OK)" + [(set_attr "type" "fast")]) + +(define_insn "*sto_qi_pre_dec" + [(set (mem:QI (pre_dec:SI (match_operand:SI 0 "metag_reg_nofloat_op" "+da"))) + (match_operand:QI 1 "metag_reg_nofloat_op" "da"))] + "TARGET_METAC_1_1" + "SETB\\t[--%0], %1\\t%@ (*store QI pre_dec OK)" + [(set_attr "type" "fast")]) + +(define_insn "*sto_qi_post_modify_disp" + [(set (mem:QI (post_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+e, f, h, l") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_qi" "O1,O1,O1,O1")))) + (match_operand:QI 2 "metag_reg_nofloat_op" "t, u, y, z"))] + "!TARGET_METAC_1_1" + "SETB\\t[%0+%1++], %2\\t%@ (*store QI post_modify_disp OK)" + [(set_attr "type" "fast,fast,fast,fast")]) + +(define_insn "*sto_qi_post_modify_disp_1_1" + [(set (mem:QI (post_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+da") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_qi" "O1")))) + (match_operand:QI 2 "metag_reg_nofloat_op" "da"))] + "TARGET_METAC_1_1" + "SETB\\t[%0+%1++], %2\\t%@ (*store QI post_modify_disp OK)" + [(set_attr "type" "fast")]) + +(define_insn "*sto_qi_post_modify_reg" + [(set (mem:QI (post_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+e,f,h,l") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_reg_nofloat_op" "e,f,h,l")))) + (match_operand:QI 2 "metag_reg_nofloat_op" "t,u,y,z"))] + "" + "SETB\\t[%0+%1++], %2\\t%@ (*store QI post_modify_reg OK)" + [(set_attr "type" "fast,fast,fast,fast")]) + +(define_insn "*sto_qi_pre_modify_disp" + [(set (mem:QI (pre_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+e, f, h, l") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_qi" "O1,O1,O1,O1")))) + (match_operand:QI 2 "metag_reg_nofloat_op" "t, u, y, z"))] + "!TARGET_METAC_1_1" + "SETB\\t[%0++%1], %2\\t%@ (*store QI pre_modify_disp OK) @2" + [(set_attr "type" "fast,fast,fast,fast")]) + +(define_insn "*sto_qi_pre_modify_disp_1_1" + [(set (mem:QI (pre_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+da") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_qi" "O1")))) + (match_operand:QI 2 "metag_reg_nofloat_op" "da"))] + "TARGET_METAC_1_1" + "SETB\\t[%0++%1], %2\\t%@ (*store QI pre_modify_disp OK)" + [(set_attr "type" "fast")]) + +(define_insn "*sto_qi_pre_modify_reg" + [(set (mem:QI (pre_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+e,f,h,l") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_reg_nofloat_op" "e,f,h,l")))) + (match_operand:QI 2 "metag_reg_nofloat_op" "t,u,y,z"))] + "" + "SETB\\t[%0++%1], %2\\t%@ (*store QI pre_modify_reg OK)" + [(set_attr "type" "fast,fast,fast,fast")]) + +;; ----------------------------------------------------------------------------- + +;; ----------------------------------------------------------------------------- +;; | Non-side effecting base+offset store QI and catchall store QI cases | +;; ----------------------------------------------------------------------------- + +;; movqi - base+index register to memory (stors's) +(define_insn "*sto_qi_mar" + [(set (mem:QI (plus:SI (match_operand:SI 0 "metag_regnofrm_op" "%e,f,h,l") + (match_operand:SI 1 "metag_regnofrm_op" " e,f,h,l"))) + (match_operand:QI 2 "metag_reg_nofloat_op" " t,u,y,z"))] + "" + "SETB\\t[%0+%1], %2\\t%@ (*sto qi mar OK)" + [(set_attr "type" "fast") + (set_attr "length" "4,4,4,4")]) + +;; movqi - register to memory (stores) some are fast, rest match spillqi below +(define_insn "*sto_qi_reg_indirect" + [(set (mem:QI (match_operand:SI 0 "metag_reg_nofloat_op" "e,f,h,l,!*da")) + (match_operand:QI 1 "metag_reg_nofloat_op" "t,u,y,z, *da"))] + "TARGET_COND_EXEC_OPTIMIZE && !TARGET_METAC_1_1" + "@ + SETB%?\\t[%0], %1\\t%@ (*sto qi [e]t OK) + SETB%?\\t[%0], %1\\t%@ (*sto qi [f]u OK) + SETB%?\\t[%0], %1\\t%@ (*sto qi [h]y OK) + SETB%?\\t[%0], %1\\t%@ (*sto qi [l]z OK) + #" + [(set_attr "type" "fast,fast,fast,fast,invalid") + (set_attr "cond" "yes,yes,yes,yes,no")]) + +(define_insn "*sto_qi" + [(set (match_operand:QI 0 "memory_operand" "=Tr,Te,Tf,Th,Tl,!*m") + (match_operand:QI 1 "metag_reg_nofloat_op" "r, t, u, y, z, !*da"))] + "!TARGET_METAC_1_1 && !reload_completed" + "@ + SETB\\t%0, %1\\t%@ (*sto qi [r]r OK) + SETB\\t%0, %1\\t%@ (*sto qi [e]r OK) + SETB\\t%0, %1\\t%@ (*sto qi [f]r OK) + SETB\\t%0, %1\\t%@ (*sto qi [h]r OK) + SETB\\t%0, %1\\t%@ (*sto qi [l]r OK) + SETB\\t%0, %1\\t%@ (*sto qi [m]r OK)" + [(set_attr "type" "fast,fast,fast,fast,fast,invalid")]) + +(define_insn "*sto_qi_postreload" + [(set (match_operand:QI 0 "memory_operand" "=Tr,Te,Tf,Th,Tl") + (match_operand:QI 1 "metag_reg_nofloat_op" "r, t, u, y, z"))] + "!TARGET_METAC_1_1 && reload_completed" + "@ + SETB\\t%0, %1\\t%@ (*sto qi [r]r OK) + SETB\\t%0, %1\\t%@ (*sto qi [e]r OK) + SETB\\t%0, %1\\t%@ (*sto qi [f]r OK) + SETB\\t%0, %1\\t%@ (*sto qi [h]r OK) + SETB\\t%0, %1\\t%@ (*sto qi [l]r OK)" + [(set_attr "type" "fast")]) + +(define_insn "*sto_qi_1_1_reg_indirect" + [(set (mem:QI (match_operand:SI 0 "metag_reg_nofloat_op" "da")) + (match_operand:QI 1 "metag_reg_nofloat_op" "da"))] + "TARGET_COND_EXEC_OPTIMIZE && TARGET_METAC_1_1" + "SETB%?\\t[%0], %1\\t%@ (*sto qi [r]r OK)" + [(set_attr "type" "fast") + (set_attr "cond" "yes") + (set_attr "predicable" "yes")]) + +(define_insn "*sto_qi_1_1_off12" + [(set (mem:QI (plus:SI (match_operand:SI 0 "metag_reg12bit_op" "da,Yr") + (match_operand:SI 1 "metag_offset12_qi" "O1,Z1"))) + (match_operand:QI 2 "metag_reg_nofloat_op" "da,da"))] + "TARGET_METAC_1_1" + "SETB\\t[%0+%1], %2" + [(set_attr "type" "fast")]) + +(define_insn "*sto_qi_1_1_off6" + [(set (mem:QI (plus:SI (match_operand:SI 0 "metag_reg_nofloat_op" "da") + (match_operand:SI 1 "metag_offset6_qi" "O1"))) + (match_operand:QI 2 "metag_reg_nofloat_op" "da"))] + "TARGET_METAC_1_1" + "SETB\\t[%0+%1], %2" + [(set_attr "type" "fast")]) + +(define_insn "*sto_qi_1_1" + [(set (match_operand:QI 0 "memory_operand" "=Tr,Te,Tf,Th,Tl,!*m") + (match_operand:QI 1 "metag_reg_nofloat_op" "r, t, u, y, z, !*da"))] + "TARGET_METAC_1_1 && !reload_completed" + "@ + SETB\\t%0, %1\\t%@ (*sto qi [r]r OK) + SETB\\t%0, %1\\t%@ (*sto qi [e]r OK) + SETB\\t%0, %1\\t%@ (*sto qi [f]r OK) + SETB\\t%0, %1\\t%@ (*sto qi [h]r OK) + SETB\\t%0, %1\\t%@ (*sto qi [l]r OK) + SETB\\t%0, %1\\t%@ (*sto qi [m]r OK)" + [(set_attr "type" "fast,fast,fast,fast,fast,invalid")]) + +(define_insn "*sto_qi_1_1_postreload" + [(set (match_operand:QI 0 "memory_operand" "=Tr,Te,Tf,Th,Tl") + (match_operand:QI 1 "metag_reg_nofloat_op" "r, t, u, y, z"))] + "TARGET_METAC_1_1 && reload_completed" + "@ + SETB\\t%0, %1\\t%@ (*sto qi [r]r OK) + SETB\\t%0, %1\\t%@ (*sto qi [e]r OK) + SETB\\t%0, %1\\t%@ (*sto qi [f]r OK) + SETB\\t%0, %1\\t%@ (*sto qi [h]r OK) + SETB\\t%0, %1\\t%@ (*sto qi [l]r OK)" + [(set_attr "type" "fast")]) + +;; spillqi - register to memory (stores) from source/dest in same bank +(define_split + [(set (match_operand:QI 0 "memory_operand" "") + (match_operand:QI 1 "metag_register_op" ""))] + "!TARGET_METAC_1_1 + && reload_completed + && metag_slow_store (operands[0], operands[1])" + [(set (match_dup 2) + (match_dup 1)) + (set (match_dup 0) + (match_dup 2))] + { + operands[2] = metag_gen_safe_temp (QImode, operands[1]); + } +) + +;; ----------------------------------------------------------------------------- +;; | Matching QI load post/pre_inc/dec/modify and emitting ASM | +;; ----------------------------------------------------------------------------- + +(define_insn "*lod_qi_post_inc" + [(set (match_operand:QI 0 "metag_reg_nofloat_op" "=da") + (mem:QI (post_inc:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da"))))] + "TARGET_METAC_1_1" + "GETB\\t%0, [%1++]\\t%@ (*load QI post_inc OK)" + [(set_attr "type" "load")]) + +(define_insn "*lod_qi_post_dec" + [(set (match_operand:QI 0 "metag_reg_nofloat_op" "=da") + (mem:QI (post_dec:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da"))))] + "TARGET_METAC_1_1" + "GETB\\t%0, [%1--]\\t%@ (*load QI post_dec OK)" + [(set_attr "type" "load")]) + +(define_insn "*lod_qi_pre_inc" + [(set (match_operand:QI 0 "metag_reg_nofloat_op" "=da") + (mem:QI (pre_inc:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da"))))] + "TARGET_METAC_1_1" + "GETB\\t%0, [++%1]\\t%@ (*load QI pre_inc OK)" + [(set_attr "type" "load")]) + +(define_insn "*lod_qi_pre_dec" + [(set (match_operand:QI 0 "metag_reg_nofloat_op" "=da") + (mem:QI (pre_dec:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da"))))] + "TARGET_METAC_1_1" + "GETB\\t%0, [--%1]\\t%@ (*load QI pre_dec OK)" + [(set_attr "type" "load")]) + +(define_insn "*lod_qi_post_modify_disp" + [(set (match_operand:QI 0 "metag_register_op" "=da") + (mem:QI (post_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+da") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_offset6_qi" "O1")))))] + "" + "GETB\\t%0, [%1+%2++]\\t%@ (*load QI post_modify_disp OK)" + [(set_attr "type" "load")]) + +(define_insn "*lod_qi_post_modify_reg" + [(set (match_operand:QI 0 "metag_reg_nofloat_op" "=da,da,da,da") + (mem:QI (post_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+e, f, h, l") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_reg_nofloat_op" "e, f, h, l")))))] + "" + "GETB\\t%0, [%1+%2++]\\t%@ (*load QI post_modify_reg OK)" + [(set_attr "type" "load")]) + +(define_insn "*lod_qi_pre_modify_disp" + [(set (match_operand:QI 0 "metag_reg_nofloat_op" "=da") + (mem:QI (pre_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+da") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_offset6_qi" "O1")))))] + "" + "GETB\\t%0, [%1++%2]\\t%@ (*load QI pre_modify_disp OK)" + [(set_attr "type" "load")]) + +(define_insn "*lod_qi_pre_modify_reg" + [(set (match_operand:QI 0 "metag_reg_nofloat_op" "=da,da,da,da") + (mem:QI (pre_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+e, f, h, l") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_reg_nofloat_op" "e, f, h, l")))))] + "" + "GETB\\t%0, [%1++%2]\\t%@ (*load QI pre_modify_reg OK)" + [(set_attr "type" "load")]) + +;; ----------------------------------------------------------------------------- + +;; ----------------------------------------------------------------------------- +;; | Non-side effecting base+offset load QI and catchall load QI | +;; ----------------------------------------------------------------------------- + +(define_insn "*lod_qi" + [(set (match_operand:QI 0 "metag_reg_nofloat_op" "=da") + (mem:QI (match_operand:SI 1 "metag_reg_nofloat_op" "da")))] + "" + "GETB\\t%0, [%1]\\t%@ (*lod qi rma OK)" + [(set_attr "type" "load")]) + +;; movqi - base+index memory to register (loads) +(define_insn "*lod_qi_rma" + [(set (match_operand:QI 0 "metag_reg_nofloat_op" "=da,da,da,da") + (mem:QI (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "e, f, h, l") + (match_operand:SI 2 "metag_regnofrm_op" "e, f, h, l"))))] + "" + "GETB\\t%0, [%1+%2]\\t%@ (*lod qi rma OK)" + [(set_attr "type" "load")]) + +(define_insn "*lod_qi_off12" + [(set (match_operand:QI 0 "metag_reg_nofloat_op" "=da,da") + (mem:QI (plus:SI (match_operand:SI 1 "metag_reg12bit_op" "da,Yr") + (match_operand:SI 2 "metag_offset12_qi" "O1,Z1"))))] + "" + "GETB\\t%0, [%1+%2]" + [(set_attr "type" "load")]) + +(define_insn "*lod_qi_off" + [(set (match_operand:QI 0 "metag_reg_nofloat_op" "=da") + (mem:QI (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "da") + (match_operand:SI 2 "metag_offset6_qi" "O1"))))] + "" + "GETB\\t%0, [%1+%2]" + [(set_attr "type" "load")]) + +(define_insn "*lod_qi_mem" + [(set (match_operand:QI 0 "metag_reg_nofloat_op" "=da") + (match_operand:QI 1 "memory_operand" "m"))] + "" + "GETB\\t%0, %1" + [(set_attr "type" "load")]) + +;; ----------------------------------------------------------------------------- + +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +;; movsf is made up of many parts.. ;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +(define_expand "movsf" + [(set (match_operand:SF 0 "nonimmediate_operand" "") + (match_operand:SF 1 "general_operand" ""))] + "" + { + if (MEM_P (operands[0])) + { + /* All except mem = const or mem = mem can be done quickly */ + operands[1] = force_reg (SFmode, operands[1]); + } + } +) + +;; movsf - all the register to register moves +(define_insn "*mov_sf" + [(set (match_operand:SF 0 "metag_register_op" "=cx,cx,d ,d,a,da") + (match_operand:SF 1 "metag_register_op" "cx,d, cx,d,a,da"))] + "" + "MOV%?\\t%0, %1\\t\\t%@ (*mov sf rr OK)" + [(set_attr "type" "fast,slow,slow,fast,fast,slow") + (set_attr "cond" "yes") + (set_attr "predicable" "yes")]) + +;; movsf - all the immediate to register sets +(define_insn_and_split "*set_sf" + [(set (match_operand:SF 0 "metag_register_op" "=da,cx") + (match_operand:SF 1 "immediate_operand" "i, ci"))] + "" + "@ + # + F\\tMOV\\t%0,#%h1" + "&& reload_completed + && (!METAG_FPC_REG_P (REGNO (operands[0])) + || !metag_fphalf_imm_op (operands[1], SFmode))" + [(const_int 0)] + { + metag_split_movsf_immediate (operands); + DONE; + } + [(set_attr "type" "two")]) + +;; movsf - register to memory (stores) some are fast, rest match spillsf below +(define_insn "*sto_sf_reg_indirect" + [(set (mem:SF (match_operand:SI 0 "metag_reg_nofloat_op" "e,f,h,l,!*da")) + (match_operand:SF 1 "metag_register_op" "t,u,y,z, *da"))] + "TARGET_COND_EXEC_OPTIMIZE && !TARGET_METAC_1_1" + "@ + SETD%?\\t[%0], %1\\t%@ (*sto sf [e]t OK) + SETD%?\\t[%0], %1\\t%@ (*sto sf [f]u OK) + SETD%?\\t[%0], %1\\t%@ (*sto sf [h]y OK) + SETD%?\\t[%0], %1\\t%@ (*sto sf [l]z OK) + #" + [(set_attr "type" "fast,fast,fast,fast,invalid") + (set_attr "cond" "yes,yes,yes,yes,no")]) + +(define_insn "*sto_sf_post_inc" + [(set (mem:SF (post_inc:SI (match_operand:SI 0 "metag_reg_nofloat_op" "+da"))) + (match_operand:SF 1 "metag_register_op" "cr"))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETD\\t[%0++], %1\\t%@ (*store SF post_inc OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[1])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +(define_insn "*sto_sf_post_dec" + [(set (mem:SF (post_dec:SI (match_operand:SI 0 "metag_reg_nofloat_op" "+da"))) + (match_operand:SF 1 "metag_register_op" "cr"))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETD\\t[%0--], %1\\t%@ (*store SF post_dec OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[1])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +(define_insn "*sto_sf_pre_inc" + [(set (mem:SF (pre_inc:SI (match_operand:SI 0 "metag_reg_nofloat_op" "+da"))) + (match_operand:SF 1 "metag_register_op" "cr"))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETD\\t[++%0], %1\\t%@ (*store SF pre_inc OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[1])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +(define_insn "*sto_sf_pre_dec" + [(set (mem:SF (pre_dec:SI (match_operand:SI 0 "metag_reg_nofloat_op" "+da"))) + (match_operand:SF 1 "metag_reg_nofloat_op" "cr"))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETD\\t[--%0], %1\\t%@ (*store SF pre_dec OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[1])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +(define_insn "*sto_sf_post_modify_disp" + [(set (mem:SF (post_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+e, f, h, l") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_sf" "O4,O4,O4,O4")))) + (match_operand:SF 2 "metag_register_op" "t, u, y, z"))] + "!TARGET_METAC_1_1" + "SETD\\t[%0+%1++], %2\\t%@ (*store SF post_modify_disp OK)" + [(set_attr "type" "fast")]) + +(define_insn "*sto_sf_post_modify_disp_1_1" + [(set (mem:SF (post_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+da") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_sf" "O4")))) + (match_operand:SF 2 "metag_register_op" "cr"))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETD\\t[%0+%1++], %2\\t%@ (*store SF post_modify_disp OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[2])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +(define_insn "*sto_sf_post_modify_reg" + [(set (mem:SF (post_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+e, f, h, l ") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_reg_nofloat_op" "e, f, h, l")))) + (match_operand:SF 2 "metag_register_op" "ct,cu,cy,cz"))] + "" + { + static const char fmt[] = "F\\tSETD\\t[%0+%1++], %2\\t%@ (*store SF post_modify_reg OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[2])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +(define_insn "*sto_sf_pre_modify_disp" + [(set (mem:SF (pre_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+e, f, h, l") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_sf" "O4,O4,O4,O4")))) + (match_operand:SF 2 "metag_reg_nofloat_op" "t, u, y, z"))] + "!TARGET_METAC_1_1" + "SETD\\t[%0++%1], %2\\t%@ (*store SF pre_modify_disp OK)" + [(set_attr "type" "fast,fast,fast,fast")]) + +(define_insn "*sto_sf_pre_modify_disp_1_1" + [(set (mem:SF (pre_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+da") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_sf" "O4")))) + (match_operand:SF 2 "metag_register_op" "cr"))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETD\\t[%0++%1], %2\\t%@ (*store SF pre_modify_disp OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[2])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +(define_insn "*sto_sf_pre_modify_reg" + [(set (mem:SF (pre_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+e, f, h, l") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_reg_nofloat_op" "e, f, h, l")))) + (match_operand:SF 2 "metag_register_op" "ct,cu,cy,cz"))] + "" + { + static const char fmt[] = "F\\tSETD\\t[%0++%1], %2\\t%@ (*store SF pre_modify_reg OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[2])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +;; ----------------------------------------------------------------------------- + +;; movsf - register to memory (stores) some are fast, rest match spillsf below +(define_insn "*sto_sf" + [(set (match_operand:SF 0 "memory_operand" "=Tr,Te,Tf,Th,Tl,!*m") + (match_operand:SF 1 "metag_reg_nofloat_op" "da,t, u, y, z, !*da"))] + "!TARGET_METAC_1_1 && !reload_completed" + "@ + SETD\\t%0, %1\\t%@ (*sto sf [r]da OK) + SETD\\t%0, %1\\t%@ (*sto sf [e]t OK) + SETD\\t%0, %1\\t%@ (*sto sf [f]u OK) + SETD\\t%0, %1\\t%@ (*sto sf [h]y OK) + SETD\\t%0, %1\\t%@ (*sto sf [l]z OK) + SETD\\t%0, %1\\t%@ (*sto sf [m]da OK)" + [(set_attr "type" "fast,fast,fast,fast,fast,invalid")]) + +(define_insn "*sto_sf_postreload" + [(set (match_operand:SF 0 "memory_operand" "=Tr,Te,Tf,Th,Tl") + (match_operand:SF 1 "metag_reg_nofloat_op" "da,t, u, y, z"))] + "!TARGET_METAC_1_1 && reload_completed" + "@ + SETD\\t%0, %1\\t%@ (*sto sf [r]da OK) + SETD\\t%0, %1\\t%@ (*sto sf [e]t OK) + SETD\\t%0, %1\\t%@ (*sto sf [f]u OK) + SETD\\t%0, %1\\t%@ (*sto sf [h]y OK) + SETD\\t%0, %1\\t%@ (*sto sf [l]z OK)" + [(set_attr "type" "fast")]) + +(define_insn "*sto_sf_1_1_reg_indirect" + [(set (mem:SF (match_operand:SI 0 "metag_reg_nofloat_op" "da")) + (match_operand:SF 1 "metag_register_op" "cr"))] + "TARGET_COND_EXEC_OPTIMIZE && TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETD%?\\t[%0], %1\\t%@ (*sto sf [r]r OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[1])) ? 0 : 2]; + } + [(set_attr "type" "fast") + (set_attr "cond" "yes") + (set_attr "predicable" "yes")]) + +(define_insn "*sto_sf_1_1_off12" + [(set (mem:SF (plus:SI (match_operand:SI 0 "metag_reg12bit_op" "da,Yr") + (match_operand:SI 1 "metag_offset12_sf" "O4,Z4"))) + (match_operand:SF 2 "metag_reg_nofloat_op" "da,da"))] + "TARGET_METAC_1_1" + "SETD\\t[%0+%1], %2" + [(set_attr "type" "fast")]) + +(define_insn "*sto_sf_1_1_off6" + [(set (mem:SF (plus:SI (match_operand:SI 0 "metag_reg_nofloat_op" "da") + (match_operand:SI 1 "metag_offset6_sf" "O4"))) + (match_operand:SF 2 "metag_register_op" "cr"))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETD\\t[%0+%1], %2"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[2])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +(define_insn "*sto_sf_1_1" + [(set (match_operand:SF 0 "memory_operand" "=Tr,Te,Tf,Th,Tl,!*m") + (match_operand:SF 1 "metag_register_op" "da,t ,u, y, z, !*da"))] + "TARGET_METAC_1_1 && !reload_completed" + "SETD\\t%0, %1\\t%@ (*sto sf [m]r OK)" + [(set_attr "type" "fast,fast,fast,fast,fast,invalid")]) + +(define_insn "*sto_sf_1_1_postreload" + [(set (match_operand:SF 0 "memory_operand" "=Tr,Te,Tf,Th,Tl") + (match_operand:SF 1 "metag_register_op" "da,t, u, y, z"))] + "TARGET_METAC_1_1 && reload_completed" + "SETD\\t%0, %1\\t%@ (*sto sf [m]r OK)" + [(set_attr "type" "fast")]) + +;; spillsf - register to memory (stores) from source/dest in same bank +(define_split + [(set (match_operand:SF 0 "memory_operand" "") + (match_operand:SF 1 "metag_register_op" ""))] + "!TARGET_METAC_1_1 + && reload_completed + && metag_slow_store (operands[0], operands[1])" + [(set (match_dup 2) + (match_dup 1)) + (set (match_dup 0) + (match_dup 2))] + { + operands[2] = metag_gen_safe_temp (SFmode, operands[1]); + } +) + +;; ----------------------------------------------------------------------------- +;; | Matching SF load post/pre_inc/dec/modify and emitting ASM | +;; ----------------------------------------------------------------------------- + +(define_insn "*lod_sf_post_inc" + [(set (match_operand:SF 0 "metag_register_op" "=cr") + (mem:SF (post_inc:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da"))))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tGETD\\t%0, [%1++]\\t%@ (*load SF post_inc OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lod_sf_post_dec" + [(set (match_operand:SF 0 "metag_register_op" "=cr") + (mem:SF (post_dec:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da"))))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tGETD\\t%0, [%1--]\\t%@ (*load SF post_dec OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lod_sf_pre_inc" + [(set (match_operand:SF 0 "metag_register_op" "=cr") + (mem:SF (pre_inc:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da"))))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tGETD\\t%0, [++%1]\\t%@ (*load SF pre_inc OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lod_sf_pre_dec" + [(set (match_operand:SF 0 "metag_register_op" "=cr") + (mem:SF (pre_dec:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da"))))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tGETD\\t%0, [--%1]\\t%@ (*load SF pre_dec OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lod_sf_post_modify_disp" + [(set (match_operand:SF 0 "metag_register_op" "=cr") + (mem:SF (post_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+da") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_offset6_sf" "O4")))))] + "" + { + static const char fmt[] = "F\\tGETD\\t%0, [%1+%2++]\\t%@ (*load SF post_modify_disp OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lod_sf_post_modify_reg" + [(set (match_operand:SF 0 "metag_register_op" "=cr,cr,cr,cr") + (mem:SF (post_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+e, f, h, l") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_reg_nofloat_op" "e, f, h, l")))))] + "" + { + static const char fmt[] = "F\\tGETD\\t%0, [%1+%2++]\\t%@ (*load SF post_modify_reg OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lod_sf_pre_modify_disp" + [(set (match_operand:SF 0 "metag_register_op" "=cr") + (mem:SF (pre_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+da") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_offset6_sf" "O4")))))] + "" + { + static const char fmt[] = "F\\tGETD\\t%0, [%1++%2]\\t%@ (*load SF pre_modify_disp OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lod_sf_pre_modify_reg" + [(set (match_operand:SF 0 "metag_register_op" "=cr,cr,cr,cr") + (mem:SF (pre_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+e, f, h, l") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_reg_nofloat_op" "e, f, h, l")))))] + "" + { + static const char fmt[] = "F\\tGETD\\t%0, [%1++%2]\\t%@ (*load SF pre_modify_reg OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +;; ----------------------------------------------------------------------------- + +;; movsf - memory to register (loads) +(define_insn "*lod_sf_rma" + [(set (match_operand:SF 0 "metag_register_op" "=cr,cr,cr,cr") + (mem:SF (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "e, f, h, l") + (match_operand:SI 2 "metag_regnofrm_op" "e, f, h, l"))))] + "" + { + static const char fmt[] = "F\\tGETD\\t%0, [%1+%2]"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lod_sf_off12" + [(set (match_operand:SF 0 "metag_reg_nofloat_op" "=da,da") + (mem:SF (plus:SI (match_operand:SI 1 "metag_reg12bit_op" "da,Yr") + (match_operand:SI 2 "metag_offset12_sf" "O4,Z4"))))] + "" + "GETD\\t%0, [%1+%2]" + [(set_attr "type" "load")]) + +(define_insn "*lod_sf_off" + [(set (match_operand:SF 0 "metag_register_op" "=cr") + (mem:SF (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "da") + (match_operand:SI 2 "metag_offset6_sf" "O4"))))] + "" + { + static const char fmt[] = "F\\tGETD\\t%0, [%1+%2]"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lod_sf" + [(set (match_operand:SF 0 "metag_register_op" "=cr") + (mem:SF (match_operand:SI 1 "metag_reg_nofloat_op" "da")))] + "" + { + static const char fmt[] = "F\\tGETD\\t%0, [%1]"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lod_sf_mem" + [(set (match_operand:SF 0 "metag_reg_nofloat_op" "=da") + (match_operand:SF 1 "memory_operand" "m"))] + "" + "GETD\\t%0, %1\\t%@ (*lod sf rm OK)" + [(set_attr "type" "load")]) + +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +;; movdi is made up of many parts.. ;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +(define_expand "movdi" + [(set (match_operand:DI 0 "nonimmediate_operand" "") + (match_operand:DI 1 "general_operand" ""))] + "" + { + if (MEM_P (operands[0])) + { + if (!no_new_pseudos) + { + /* All except mem = const or mem = mem can be done quickly */ + operands[1] = force_reg (DImode, operands[1]); + } + } + } +) + +;; movdi - register to register forms +(define_insn_and_split "*mov_di" + [(set (match_operand:DI 0 "metag_register_op" "=d,a,d, cx,cx,?da") + (match_operand:DI 1 "metag_register_op" "d,a,cx,d, cx,?da"))] + "" + { + switch (which_alternative) + { + case 0: + case 1: + case 5: + return "#"; + case 2: + case 3: + case 4: + if (metag_fpu_single) + return "#"; + else + return "FD\\tMOV\\t%0,%1"; + default: + gcc_unreachable(); + } + } + "reload_completed" + [(const_int 0)] + { + /* WORK NEEDED: When in hard-float mode, FL MOV will do a dual + unit MOV to FCC regs */ + if (TARGET_DSP + && metag_datareg_p (REGNO (operands[0])) + && metag_datareg_p (REGNO (operands[1]))) + { + operands[0] = gen_rtx_REG (V2SImode, REGNO (operands[0])); + operands[1] = gen_rtx_REG (V2SImode, REGNO (operands[1])); + emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1])); + } + else + metag_split_movdi (operands); + DONE; + } + [(set_attr "type" "two,two,two,two,two,slowslow") + (set_attr "cond" "yes,yes,yes,yes,yes,yes") + (set_attr "predicable" "yes")]) + +(define_insn_and_split "*set_di" + [(set (match_operand:DI 0 "metag_reg_nofloat_op" "=d,a") + (match_operand:DI 1 "immediate_operand" "i,i"))] + "" + "#" + "reload_completed" + [(const_int 0)] + { + metag_split_movdi_immediate (operands); + DONE; + } + [(set_attr "type" "four")]) + + +;; ----------------------------------------------------------------------------- +;; | Matching DI store post/pre_inc/dec/modify and emitting ASM | +;; ----------------------------------------------------------------------------- + +(define_insn "*sto_di_post_inc_concat" + [(set (mem:DI (post_inc:SI (match_operand:SI 0 "metag_reg_nofloat_op" "+da,da"))) + (unspec:DI [(match_operand:SI 1 "metag_reg_nofloat_op" "e, h") + (match_operand:SI 2 "metag_reg_nofloat_op" "f, l")] UNSPEC_CONCAT))] + "TARGET_METAC_1_1" + "SETL\\t[%0++], %1, %2" + [(set_attr "type" "fast")]) + +(define_insn "*sto_di_post_inc" + [(set (mem:DI (post_inc:SI (match_operand:SI 0 "metag_reg_nofloat_op" "+da"))) + (match_operand:DI 1 "metag_register_op" "cr"))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETL\\t[%0++], %1, %t1\\t%@ (*store DI post_inc OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[1])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +(define_insn "*sto_di_post_dec" + [(set (mem:DI (post_dec:SI (match_operand:SI 0 "metag_reg_nofloat_op" "+da"))) + (match_operand:DI 1 "metag_register_op" "cr"))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETL\\t[%0--], %1, %t1\\t%@ (*store DI post_dec OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[1])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +(define_insn "*sto_di_pre_inc" + [(set (mem:DI (pre_inc:SI (match_operand:SI 0 "metag_reg_nofloat_op" "+da"))) + (match_operand:DI 1 "metag_register_op" "cr"))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETL\\t[++%0], %1, %t1\\t%@ (*store DI pre_inc OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[1])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +(define_insn "*sto_di_pre_dec" + [(set (mem:DI (pre_dec:SI (match_operand:SI 0 "metag_reg_nofloat_op" "+da"))) + (match_operand:DI 1 "metag_register_op" "cr"))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETL\\t[--%0], %1, %t1\\t%@ (*store DI pre_dec OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[1])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +(define_insn "*sto_di_post_modify_disp" + [(set (mem:DI (post_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+d, a") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_di" "O8,O8")))) + (match_operand:DI 2 "metag_register_op" "a, d"))] + "!TARGET_METAC_1_1" + "SETL\\t[%0+%1++], %2, %t2\\t%@ (*store DI post_modify_disp OK)" + [(set_attr "type" "fast")]) + +(define_insn "*sto_di_post_modify_disp_1_1" + [(set (mem:DI (post_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+da") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_di" "O8")))) + (match_operand:DI 2 "metag_register_op" "cr"))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETL\\t[%0+%1++], %2, %t2\\t%@ (*store DI post_modify_disp_1_1 OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[2])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +(define_insn "*sto_di_post_modify_reg" + [(set (mem:DI (post_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+e, f, h, l") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_reg_nofloat_op" "e, f, h, l")))) + (match_operand:DI 2 "metag_register_op" "ca,ca,cd,cd"))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETL\\t[%0+%1++], %2, %t2\\t%@ (*store DI post_modify_reg OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[2])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +(define_insn "*sto_di_pre_modify_disp" + [(set (mem:DI (pre_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+d, a") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_di" "O8,O8")))) + (match_operand:DI 2 "metag_reg_nofloat_op" "a, d"))] + "!TARGET_METAC_1_1" + "SETL\\t[%0++%1], %2, %t2\\t%@ (*store DI pre_modify_disp OK)" + [(set_attr "type" "fast")]) + +(define_insn "*sto_di_pre_modify_disp_1_1" + [(set (mem:DI (pre_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+da") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_di" "O8")))) + (match_operand:DI 2 "metag_reg_nofloat_op" "cr"))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETL\\t[%0++%1], %2, %t2\\t%@ (*store DI pre_modify_disp_1_1 OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[2])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +(define_insn "*sto_di_pre_modify_reg" + [(set (mem:DI (pre_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+e, f, h, l") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_reg_nofloat_op" "e, f, h, l")))) + (match_operand:DI 2 "metag_register_op" "ca,ca,cd,cd"))] + "" + { + static const char fmt[] = "F\\tSETL\\t[%0++%1], %2, %t2\\t%@ (*store DI pre_modify_reg OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[2])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +;; ----------------------------------------------------------------------------- + +;; ----------------------------------------------------------------------------- +;; | Non-side effecting base+offset store DI and catchall store DI cases | +;; ----------------------------------------------------------------------------- + +;; movdi - register to memory (stores) some are fast, rest match spilldi below +(define_insn "*sto_di_cond_exec_concat" + [(set (mem:DI (match_operand:SI 0 "metag_reg_nofloat_op" "a,d,!da")) + (unspec:DI [(match_operand:SI 1 "metag_reg_nofloat_op" "d,a, da") + (match_operand:SI 2 "metag_reg_nofloat_op" "d,a, da")] UNSPEC_CONCAT))] + "TARGET_COND_EXEC_OPTIMIZE + && !TARGET_METAC_1_1 + && reload_completed + && !( metag_regno_same_unit_p (REGNO (operands[0]), REGNO (operands[1])) + || metag_regno_same_unit_p (REGNO (operands[0]), REGNO (operands[2])))" + "SETL%?\\t[%0], %1, %2\\t%@ (*sto di OK)" + [(set_attr "type" "fast") + (set_attr "cond" "yes") + (set_attr "predicable" "yes")]) + +(define_insn "*sto_di_cond_exec" + [(set (mem:DI (match_operand:SI 0 "metag_reg_nofloat_op" "a,d,!da")) + (match_operand:DI 1 "metag_reg_nofloat_op" "d,a, da"))] + "TARGET_COND_EXEC_OPTIMIZE + && !TARGET_METAC_1_1 + && reload_completed + && !( metag_regno_same_unit_p (REGNO (operands[0]), REGNO (operands[1])) + || metag_regno_same_unit_p (REGNO (operands[0]), REGNO (operands[1]) + 1))" + "SETL%?\\t[%0], %1, %t1\\t%@ (*sto di OK)" + [(set_attr "type" "fast") + (set_attr "cond" "yes") + (set_attr "predicable" "yes")]) + +(define_insn "*sto_di_concat" + [(set (match_operand:DI 0 "memory_operand" "=Tr,Te,Tf,Th,Tl,!m") + (unspec:DI [(match_operand:SI 1 "metag_reg_nofloat_op" "r, a, a, d, d, da") + (match_operand:SI 2 "metag_reg_nofloat_op" "r, a, a, d, d, da")] UNSPEC_CONCAT))] + "!TARGET_METAC_1_1" + "SETL\\t%0, %1, %2" + [(set_attr "type" "fast")]) + +(define_insn "*sto_di_off12" + [(set (mem:DI (plus:SI (match_operand:SI 0 "metag_reg12bit_op" "e, f, h, l, Ye,Yf,Yh,Yl") + (match_operand:SI 1 "metag_offset12_di" "O8,O8,O8,O8,Z8,Z8,Z8,Z8"))) + (match_operand:DI 2 "metag_reg_nofloat_op" "a, a, d, d, a, a, d, d"))] + "!TARGET_METAC_1_1" + "SETL\\t[%0+%1], %2, %t2" + [(set_attr "type" "fast")]) + +(define_insn "*sto_di_off6" + [(set (mem:DI (plus:SI (match_operand:SI 0 "metag_reg_nofloat_op" "e, f, h, l") + (match_operand:SI 1 "metag_offset6_di" "O8,O8,O8,O8"))) + (match_operand:DI 2 "metag_register_op" "a, a, d, d"))] + "!TARGET_METAC_1_1" + "SETL\\t[%0+%1], %2, %t2" + [(set_attr "type" "fast")]) + +(define_insn "*sto_di" + [(set (match_operand:DI 0 "memory_operand" "=Tr,Te,Tf,Th,Tl,!*m") + (match_operand:DI 1 "metag_reg_nofloat_op" "r, a, a, d, d, !*da"))] + "!TARGET_METAC_1_1 && !reload_completed" + "SETL\\t%0, %1, %t1" + [(set_attr "type" "fast,fast,fast,fast,fast,invalid")]) + +(define_insn "*sto_di_postreload" + [(set (match_operand:DI 0 "memory_operand" "=Tr,Te,Tf,Th,Tl") + (match_operand:DI 1 "metag_reg_nofloat_op" "r, a, a, d, d"))] + "!TARGET_METAC_1_1 && reload_completed" + "SETL\\t%0, %1, %t1" + [(set_attr "type" "fast")]) + +;; movdi - base+index register to memory (stores) +(define_insn "*sto_di_mar" + [(set (mem:DI (plus:SI (match_operand:SI 0 "metag_regnofrm_op" "%e, f, h, l") + (match_operand:SI 1 "metag_regnofrm_op" " e, f, h, l"))) + (match_operand:DI 2 "metag_register_op" "ca,ca,cd,cd"))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETL\\t[%0+%1], %2, %t2\\t\\t%@ (*sto di mar OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[1])) ? 0 : 2]; + } + [(set_attr "type" "fast") + (set_attr "length" "4,4,4,4")]) + +(define_insn "*sto_di_reg_indirect_concat_1_1" + [(set (mem:DI (match_operand:SI 0 "metag_reg_nofloat_op" "da")) + (unspec:DI [(match_operand:SI 1 "metag_reg_nofloat_op" "da") + (match_operand:SI 2 "metag_reg_nofloat_op" "da")] UNSPEC_CONCAT))] + "TARGET_COND_EXEC_OPTIMIZE && TARGET_METAC_1_1" + "SETL%?\\t[%0], %1, %2\\t%@ (*sto di OK)" + [(set_attr "type" "fast") + (set_attr "cond" "yes") + (set_attr "predicable" "yes")]) + +(define_insn "*sto_di_reg_indirect_1_1" + [(set (mem:DI (match_operand:SI 0 "metag_reg_nofloat_op" "da")) + (match_operand:DI 1 "metag_reg_nofloat_op" "da"))] + "TARGET_COND_EXEC_OPTIMIZE && TARGET_METAC_1_1" + "SETL%?\\t[%0], %1, %t1\\t%@ (*sto di OK)" + [(set_attr "type" "fast") + (set_attr "cond" "yes") + (set_attr "predicable" "yes")]) + +(define_insn "*sto_di_concat_1_1" + [(set (match_operand:DI 0 "memory_operand" "=m, m") + (unspec:DI [(match_operand:SI 1 "metag_register_op" "da,cx") + (match_operand:SI 2 "metag_register_op" "da,cx")] UNSPEC_CONCAT))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETL\\t%0, %1, %2\\t\\t%@ (*sto di [r]r OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[1])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +(define_insn "*sto_di_1_1_off12" + [(set (mem:DI (plus:SI (match_operand:SI 0 "metag_reg12bit_op" "da,Yr") + (match_operand:SI 1 "metag_offset12_di" "O8,Z8"))) + (match_operand:DI 2 "metag_reg_nofloat_op" "da,da"))] + "TARGET_METAC_1_1" + "SETL\\t[%0+%1], %2, %t2" + [(set_attr "type" "fast")]) + +(define_insn "*sto_di_1_1_off6" + [(set (mem:DI (plus:SI (match_operand:SI 0 "metag_reg_nofloat_op" "da") + (match_operand:SI 1 "metag_offset6_di" "O8"))) + (match_operand:DI 2 "metag_register_op" "cr"))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETL\\t[%0+%1], %2, %t2"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[2])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +(define_insn "*sto_di_1_1" + [(set (match_operand:DI 0 "memory_operand" "=Tr,Te,Tf,Th,Tl,!*m") + (match_operand:DI 1 "metag_reg_nofloat_op" "r, a, a, d, d, !*da"))] + "TARGET_METAC_1_1 && !reload_completed" + "SETL\\t%0, %1, %t1\\t\\t%@ (*sto di [r]r OK)" + [(set_attr "type" "fast,fast,fast,fast,fast,invalid")]) + +(define_insn "*sto_di_1_1_postreload" + [(set (match_operand:DI 0 "memory_operand" "=Tr,Te,Tf,Th,Tl") + (match_operand:DI 1 "metag_reg_nofloat_op" "r, a, a, d, d"))] + "TARGET_METAC_1_1 && reload_completed" + "SETL\\t%0, %1, %t1\\t\\t%@ (*sto di [r]r OK)" + [(set_attr "type" "fast")]) + +;; spilldi - register to memory (stores) from source/dest in same bank +(define_split + [(set (match_operand:DI 0 "memory_operand" "") + (match_operand:DI 1 "metag_register_op" ""))] + "!TARGET_METAC_1_1 + && reload_completed + && metag_slow_store (operands[0], operands[1])" + [(set (match_dup 2) + (match_dup 1)) + (set (match_dup 0) + (match_dup 2))] + { + operands[2] = metag_gen_safe_temp (DImode, operands[1]); + } +) + +;; ----------------------------------------------------------------------------- + +;; movdi - memory to register (loads) + +;; ----------------------------------------------------------------------------- +;; | Matching DI store [post/pre]_[inc/dec/modify] and emitting ASM | +;; ----------------------------------------------------------------------------- + +(define_insn "*lod_di_concat_post_inc" + [(set (unspec:DI [(match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (match_operand:SI 1 "metag_reg_nofloat_op" "=da")] UNSPEC_CONCAT) + (mem:DI (post_inc:SI (match_operand:SI 2 "metag_reg_nofloat_op" "+da"))))] + "TARGET_METAC_1_1" + "GETL\\t%0, %1, [%2++]\\t%@ (*load DI post_inc OK)" + [(set_attr "type" "load")]) + +(define_insn "*lod_di_post_inc" + [(set (match_operand:DI 0 "metag_register_op" "=cr") + (mem:DI (post_inc:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da"))))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tGETL\\t%0, %t0, [%1++]\\t%@ (*load DI post_inc OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lod_di_post_dec" + [(set (match_operand:DI 0 "metag_register_op" "=cr") + (mem:DI (post_dec:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da"))))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tGETL\\t%0, %t0, [%1--]\\t%@ (*load DI post_dec OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lod_di_pre_inc" + [(set (match_operand:DI 0 "metag_register_op" "=cr") + (mem:DI (pre_inc:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da"))))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tGETL\\t%0, %t0, [++%1]\\t%@ (*load DI pre_inc OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lod_di_pre_dec" + [(set (match_operand:DI 0 "metag_register_op" "=cr") + (mem:DI (pre_dec:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da"))))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tGETL\\t%0, %t0, [--%1]\\t%@ (*load DI pre_dec OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lod_di_post_modify_disp" + [(set (match_operand:DI 0 "metag_register_op" "=cr") + (mem:DI (post_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+da") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_offset6_di" "O8")))))] + "" + { + static const char fmt[] = "F\\tGETL\\t%0, %t0, [%1+%2++]\\t%@ (*load DI post_modify_disp OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lod_di_post_modify_reg" + [(set (match_operand:DI 0 "metag_register_op" "=cr,cr,cr,cr") + (mem:DI (post_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+e, f, h, l") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_reg_nofloat_op" "e, f, h, l")))))] + "" + { + static const char fmt[] = "F\\tGETL\\t%0, %t0, [%1+%2++]\\t%@ (*load DI post_modify_reg OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lod_di_pre_modify_disp" + [(set (match_operand:DI 0 "metag_register_op" "=cr") + (mem:DI (pre_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+da") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_offset6_di" "O8")))))] + "" + { + static const char fmt[] = "F\\tGETL\\t%0, %t0, [%1++%2]\\t%@ (*load DI pre_modify_disp OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lod_di_pre_modify_reg" + [(set (match_operand:DI 0 "metag_register_op" "=cr,cr,cr,cr") + (mem:DI (pre_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+e, f, h, l") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_reg_nofloat_op" "e, f, h, l")))))] + "" + { + static const char fmt[] = "F\\tGETL\\t%0, %t0, [%1++%2]\\t%@ (*load DI pre_modify_reg OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +;; ----------------------------------------------------------------------------- + +;; ----------------------------------------------------------------------------- +;; | Non-side effecting base+offset load DI and catchall load DI | +;; ----------------------------------------------------------------------------- + +(define_insn "*lod_di" + [(set (match_operand:DI 0 "metag_register_op" "=cr") + (mem:DI (match_operand:SI 1 "metag_regnofrm_op" "da")))] + "" + { + static const char fmt[] = "F\\tGETL\\t%0, %t0, [%1]\\t%@ (*lod di rma OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +;; movdi - base+index memory to register (loads) +(define_insn "*lod_di_rma" + [(set (match_operand:DI 0 "metag_register_op" "=cr,cr,cr,cr") + (mem:DI (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "%e, f, h, l") + (match_operand:SI 2 "metag_regnofrm_op" "e, f, h, l"))))] + "" + { + static const char fmt[] = "F\\tGETL\\t%0, %t0, [%1+%2]\\t%@ (*lod qi rma OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lod_di_concat" + [(set (unspec:DI [(match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (match_operand:SI 1 "metag_reg_nofloat_op" "=da")] UNSPEC_CONCAT) + (match_operand:DI 2 "memory_operand" "m"))] + "" + "GETL\\t%0, %1, %2" + [(set_attr "type" "load")]) + +(define_insn "*lod_di_off12" + [(set (match_operand:DI 0 "metag_reg_nofloat_op" "=da,da") + (mem:DI (plus:SI (match_operand:SI 1 "metag_reg12bit_op" "da,Yr") + (match_operand:SI 2 "metag_offset12_di" "O8,Z8"))))] + "" + "GETL\\t%0, %t0, [%1+%2]" + [(set_attr "type" "load")]) + +(define_insn "*lod_di_off6" + [(set (match_operand:DI 0 "metag_register_op" "=cr") + (mem:DI (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "da") + (match_operand:SI 2 "metag_offset6_di" "O8"))))] + "" + { + static const char fmt[] = "F\\tGETL\\t%0, %t0, [%1+%2]"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lod_di_mem" + [(set (match_operand:DI 0 "metag_reg_nofloat_op" "=da") + (match_operand:DI 1 "memory_operand" "m"))] + "" + "GETL\\t%0, %t0, %1\\t%@ (*lod di rm)" + [(set_attr "type" "load")]) + +;; ----------------------------------------------------------------------------- + +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +;; movdf is made up of many parts.. ;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +(define_expand "movdf" + [(set (match_operand:DF 0 "nonimmediate_operand" "") + (match_operand:DF 1 "general_operand" ""))] + "" + { + if (MEM_P (operands[0])) + { + /* All except mem = const or mem = mem can be done quickly */ + operands[1] = force_reg (DFmode, operands[1]); + } + + if (metag_fpu_single + && REG_P (operands[0]) + && METAG_FPC_REG_P (REGNO (operands[0])) + && CONST_DOUBLE_P (operands[1])) + FAIL; + } +) + +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +;; and these are the movdf parts.. ;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; + +;; movdf - register to register forms +(define_insn_and_split "*mov_df" + [(set (match_operand:DF 0 "metag_register_op" "=cx,d, cx,d,a,da") + (match_operand:DF 1 "metag_register_op" "cx,cx,d, d,a,da"))] + "" + { + switch (which_alternative) + { + case 0: + if (!metag_fpu_single) + return "FL\\tMOV%?\\t%0,%1"; + else + return "#"; + case 1: + case 2: + return "F\\tMOVL\\t%0,%1"; + case 3: + if (TARGET_DSP) + return "DL\\tMOV\\t%0, %1"; + /* Fall through */ + case 4: + case 5: + return "#"; + default: + gcc_unreachable(); + } + } + "&& reload_completed" + [(const_int 0)] + { + metag_split_movdf (operands); + DONE; + } + [(set_attr "type" "fast,fast,fast,two,two,slowslow") + (set_attr "cond" "yes,no,no,yes,yes,yes") + (set_attr "predicable" "no")]) + +;; movdf - immediate to register forms +(define_insn_and_split "*set_df" + [(set (match_operand:DF 0 "metag_register_op" "=d,a,cx") + (match_operand:DF 1 "immediate_operand" "i,i,ci"))] + "!metag_fpu_single" + { + switch (which_alternative) + { + case 0: + case 1: + return "#"; + case 2: + return "FD\\tMOV\\t%0,#%h1"; + default: + gcc_unreachable(); + } + } + "&& reload_completed + && (!METAG_FPC_REG_P (REGNO (operands[0])) + || !metag_fphalf_imm_op (operands[1], DFmode))" + [(const_int 0)] + { + metag_split_movdf_immediate (operands); + DONE; + } + [(set_attr "type" "four")]) + +(define_insn_and_split "*set_df_fpu_single" + [(set (match_operand:DF 0 "metag_register_op" "=d,a") + (match_operand:DF 1 "immediate_operand" "i,i"))] + "metag_fpu_single" + "#" + "&& reload_completed" + [(const_int 0)] + { + metag_split_movdf_immediate (operands); + DONE; + } + [(set_attr "type" "four")]) + +;; ----------------------------------------------------------------------------- + +(define_insn "*sto_df_post_inc" + [(set (mem:DF (post_inc:SI (match_operand:SI 0 "metag_reg_nofloat_op" "+da"))) + (match_operand:DF 1 "metag_register_op" "cr"))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETL\\t[%0++], %1, %t1\\t%@ (*store DF post_inc OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[1])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +(define_insn "*sto_df_post_dec" + [(set (mem:DF (post_dec:SI (match_operand:SI 0 "metag_reg_nofloat_op" "+da"))) + (match_operand:DF 1 "metag_register_op" "cr"))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETL\\t[%0--], %1, %t1\\t%@ (*store DF post_dec OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[1])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +(define_insn "*sto_df_pre_inc" + [(set (mem:DF (pre_inc:SI (match_operand:SI 0 "metag_reg_nofloat_op" "+da"))) + (match_operand:DF 1 "metag_register_op" "cr"))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETL\\t[++%0], %1, %t1\\t%@ (*store DF pre_inc OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[1])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +(define_insn "*sto_df_pre_dec" + [(set (mem:DF (pre_dec:SI (match_operand:SI 0 "metag_reg_nofloat_op" "+da"))) + (match_operand:DF 1 "metag_register_op" "cr"))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETL\\t[--%0], %1, %t1\\t%@ (*store DF pre_dec OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[1])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +(define_insn "*sto_df_post_modify_disp" + [(set (mem:DF (post_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+d, a") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_df" "O8,O8")))) + (match_operand:DF 2 "metag_register_op" "a, d"))] + "!TARGET_METAC_1_1" + "SETL\\t[%0+%1++], %2, %t2\\t%@ (*store DF post_modify_disp OK)" + [(set_attr "type" "fast")]) + +(define_insn "*sto_df_post_modify_disp_1_1" + [(set (mem:DF (post_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+da") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_df" "O8")))) + (match_operand:DF 2 "metag_register_op" "cr"))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETL\\t[%0+%1++], %2, %t2\\t%@ (*store DF post_modify_disp_1_1 OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[2])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +(define_insn "*sto_df_post_modify_reg" + [(set (mem:DF (post_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+e, f, h, l") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_reg_nofloat_op" "e, f, h, l")))) + (match_operand:DF 2 "metag_register_op" "ca,ca,cd,cd"))] + "" + { + static const char fmt[] = "F\\tSETL\\t[%0+%1++], %2, %t2\\t%@ (*store DF post_modify_reg OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[2])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +(define_insn "*sto_df_pre_modify_disp" + [(set (mem:DF (pre_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+d, a") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_df" "O8,O8")))) + (match_operand:DF 2 "metag_reg_nofloat_op" "a, d"))] + "!TARGET_METAC_1_1" + "SETL\\t[%0++%1], %2, %t2\\t%@ (*store DF pre_modify_disp OK)" + [(set_attr "type" "fast")]) + +(define_insn "*sto_df_pre_modify_disp_1_1" + [(set (mem:DF (pre_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+da") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_df" "O8")))) + (match_operand:DF 2 "metag_register_op" "cr"))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETL\\t[%0++%1], %2, %t2\\t%@ (*store DF pre_modify_disp_1_1 OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[2])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +(define_insn "*sto_df_pre_modify_reg" + [(set (mem:DF (pre_modify:SI + (match_operand:SI 0 "metag_reg_nofloat_op" "+e, f, h, l") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_reg_nofloat_op" "e, f, h, l")))) + (match_operand:DF 2 "metag_register_op" "ca,ca,cd,cd"))] + "" + { + static const char fmt[] = "F\\tSETL\\t[%0++%1], %2, %t2\\t%@ (*store DF pre_modify_reg OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[2])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +;; ----------------------------------------------------------------------------- + +;; movdf - register to memory forms (stores) +(define_insn "*sto_df_reg_indirect" + [(set (mem:DF (match_operand:SI 0 "metag_reg_nofloat_op" "a,d,ad,!da")) + (match_operand:DF 1 "metag_register_op" "d,a,cx, da"))] + "TARGET_COND_EXEC_OPTIMIZE + && !TARGET_METAC_1_1 + && reload_completed + && !( metag_regno_same_unit_p (REGNO (operands[0]), REGNO (operands[1])) + || metag_regno_same_unit_p (REGNO (operands[0]), REGNO (operands[1]) + 1))" + { + static const char fmt[] = "F\\tSETL%?\\t[%0], %1, %t1\\t%@ (*sto df OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[1])) ? 0 : 2]; + } + [(set_attr "type" "fast") + (set_attr "cond" "yes") + (set_attr "predicable" "yes")]) + +(define_insn "*sto_df" + [(set (match_operand:DF 0 "memory_operand" "=Tr,Te,Tf,Th,Tl,!*m") + (match_operand:DF 1 "metag_register_op" "da,a, a, d, d, !*da"))] + "!TARGET_METAC_1_1 && !reload_completed" + "SETL\\t%0, %1, %t1" + [(set_attr "type" "fast,fast,fast,fast,fast,invalid")]) + +(define_insn "*sto_df_postreload" + [(set (match_operand:DF 0 "memory_operand" "=Tr,Te,Tf,Th,Tl") + (match_operand:DF 1 "metag_register_op" "da,a, a, d, d"))] + "!TARGET_METAC_1_1 && reload_completed" + "SETL\\t%0, %1, %t1" + [(set_attr "type" "fast")]) + +(define_insn "*sto_df_1_1_reg_indirect" + [(set (mem:DF (match_operand:SI 0 "metag_reg_nofloat_op" "da")) + (match_operand:DF 1 "metag_register_op" "cr"))] + "TARGET_COND_EXEC_OPTIMIZE && TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETL%?\\t[%0], %1, %t1\\t%@ (*sto df [r]r OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[1])) ? 0 : 2]; + } + [(set_attr "type" "fast") + (set_attr "cond" "yes") + (set_attr "predicable" "yes")]) + +(define_insn "*sto_df_1_1_off12" + [(set (mem:DF (plus:SI (match_operand:SI 0 "metag_reg12bit_op" "da,Yr") + (match_operand:SI 1 "metag_offset12_df" "O8,Z8"))) + (match_operand:DF 2 "metag_reg_nofloat_op" "da,da"))] + "TARGET_METAC_1_1" + "SETL\\t[%0+%1], %2, %t2" + [(set_attr "type" "fast")]) + +(define_insn "*sto_df_1_1_off6" + [(set (mem:DF (plus:SI (match_operand:SI 0 "metag_reg_nofloat_op" "da") + (match_operand:SI 1 "metag_offset6_df" "O8"))) + (match_operand:DF 2 "metag_register_op" "cr"))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tSETL\\t[%0+%1], %2, %t2"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[2])) ? 0 : 2]; + } + [(set_attr "type" "fast")]) + +;; movdf - register to memory forms (stores) +(define_insn "*sto_df_1_1" + [(set (match_operand:DF 0 "memory_operand" "=Tr,Te,Tf,Th,Tl,!*m") + (match_operand:DF 1 "metag_reg_nofloat_op" "da, a, a, d, d,!*da"))] + "TARGET_METAC_1_1 && !reload_completed" + "SETL\\t%0, %1, %t1\\t\\t%@ (*sto df [r]r OK)" + [(set_attr "type" "fast,fast,fast,fast,fast,invalid")]) + +(define_insn "*sto_df_1_1_postreload" + [(set (match_operand:DF 0 "memory_operand" "=Tr,Te,Tf,Th,Tl") + (match_operand:DF 1 "metag_reg_nofloat_op" "da, a, a, d, d"))] + "TARGET_METAC_1_1 && reload_completed" + "SETL\\t%0, %1, %t1\\t\\t%@ (*sto df [r]r OK)" + [(set_attr "type" "fast")]) + +;; spilldf - register to memory (stores) from source/dest in same bank +(define_split + [(set (match_operand:DF 0 "memory_operand" "") + (match_operand:DF 1 "metag_register_op" ""))] + "!TARGET_METAC_1_1 + && reload_completed + && metag_slow_store (operands[0], operands[1])" + [(set (match_dup 2) + (match_dup 1)) + (set (match_dup 0) + (match_dup 2))] + { + operands[2] = metag_gen_safe_temp (DFmode, operands[1]); + } +) + +;; ----------------------------------------------------------------------------- + +;; movdf - memory to register (loads) + +;; ----------------------------------------------------------------------------- +;; | Matching DF store [post/pre]_[inc/dec/modify] +;; ----------------------------------------------------------------------------- + +(define_insn "*lod_df_post_inc" + [(set (match_operand:DF 0 "metag_register_op" "=da,cx") + (mem:DF (post_inc:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da,da"))))] + "TARGET_METAC_1_1" + "@ + GETL\\t%0, %t0, [%1++]\\t%@ (*load DF post_inc OK) + F\\tGETL\\t%0, %t0, [%1++]\\t%@ (*load DF post_inc OK)" + [(set_attr "type" "load")]) + +(define_insn "*lod_df_post_dec" + [(set (match_operand:DF 0 "metag_register_op" "=da,cx") + (mem:DF (post_dec:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da,da"))))] + "TARGET_METAC_1_1" + "@ + GETL\\t%0, %t0, [%1--]\\t%@ (*load DF post_dec OK) + F\\tGETL\\t%0, %t0, [%1--]\\t%@ (*load DF post_dec OK)" + [(set_attr "type" "load")]) + +(define_insn "*lod_df_pre_inc" + [(set (match_operand:DF 0 "metag_register_op" "=da,cx") + (mem:DF (pre_inc:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da,da"))))] + "TARGET_METAC_1_1" + "@ + GETL\\t%0, %t0, [++%1]\\t%@ (*load DF pre_inc OK) + F\\tGETL\\t%0, %t0, [++%1]\\t%@ (*load DF pre_inc OK)" + [(set_attr "type" "load")]) + +(define_insn "*lod_df_pre_dec" + [(set (match_operand:DF 0 "metag_register_op" "=da,cx") + (mem:DF (pre_dec:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da,da"))))] + "TARGET_METAC_1_1" + "@ + GETL\\t%0, %t0, [--%1]\\t%@ (*load DF pre_dec OK) + F\\tGETL\\t%0, %t0, [--%1]\\t%@ (*load DF pre_dec OK)" + [(set_attr "type" "load")]) + +(define_insn "*lod_df_post_modify_disp" + [(set (match_operand:DF 0 "metag_register_op" "=da,cx") + (mem:DF (post_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+da,da") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_offset6_df" "O8,O8")))))] + "" + "@ + GETL\\t%0, %t0, [%1+%2++]\\t%@ (*load DF post_modify_disp OK) + F\\tGETL\\t%0, %t0, [%1+%2++]\\t%@ (*load DF post_modify_disp OK)" + [(set_attr "type" "load")]) + +(define_insn "*lod_df_post_modify_reg" + [(set (match_operand:DF 0 "metag_register_op" "=da,da,da,da,cx,cx,cx,cx") + (mem:DF (post_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+e, f, h, l, e, f, h, l") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_reg_nofloat_op" "e, f, h, l, e, f, h, l")))))] + "" + "@ + GETL\\t%0, %t0, [%1+%2++]\\t%@ (*load DF post_modify_reg OK) + GETL\\t%0, %t0, [%1+%2++]\\t%@ (*load DF post_modify_reg OK) + GETL\\t%0, %t0, [%1+%2++]\\t%@ (*load DF post_modify_reg OK) + GETL\\t%0, %t0, [%1+%2++]\\t%@ (*load DF post_modify_reg OK) + F\\tGETL\\t%0, %t0, [%1+%2++]\\t%@ (*load DF post_modify_reg OK) + F\\tGETL\\t%0, %t0, [%1+%2++]\\t%@ (*load DF post_modify_reg OK) + F\\tGETL\\t%0, %t0, [%1+%2++]\\t%@ (*load DF post_modify_reg OK) + F\\tGETL\\t%0, %t0, [%1+%2++]\\t%@ (*load DF post_modify_reg OK)" + [(set_attr "type" "load")]) + +(define_insn "*lod_df_pre_modify_disp" + [(set (match_operand:DF 0 "metag_register_op" "=da,cx") + (mem:DF (pre_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+da,da") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_offset6_df" "O8,O8")))))] + "" + "@ + GETL\\t%0, %t0, [%1++%2]\\t%@ (*load DF pre_modify_disp OK) + F\\tGETL\\t%0, %t0, [%1++%2]\\t%@ (*load DF pre_modify_disp OK)" + [(set_attr "type" "load")]) + +(define_insn "*lod_df_pre_modify_reg" + [(set (match_operand:DF 0 "metag_register_op" "=da,da,da,da,cx,cx,cx,cx") + (mem:DF (pre_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+e, f, h, l, e, f, h, l") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_reg_nofloat_op" "e, f, h, l, e, f, h, l")))))] + "" + "@ + GETL\\t%0, %t0, [%1++%2]\\t%@ (*load DF pre_modify_reg OK) + GETL\\t%0, %t0, [%1++%2]\\t%@ (*load DF pre_modify_reg OK) + GETL\\t%0, %t0, [%1++%2]\\t%@ (*load DF pre_modify_reg OK) + GETL\\t%0, %t0, [%1++%2]\\t%@ (*load DF pre_modify_reg OK) + F\\tGETL\\t%0, %t0, [%1++%2]\\t%@ (*load DF pre_modify_reg OK) + F\\tGETL\\t%0, %t0, [%1++%2]\\t%@ (*load DF pre_modify_reg OK) + F\\tGETL\\t%0, %t0, [%1++%2]\\t%@ (*load DF pre_modify_reg OK) + F\\tGETL\\t%0, %t0, [%1++%2]\\t%@ (*load DF pre_modify_reg OK)" + [(set_attr "type" "load")]) + +;; ----------------------------------------------------------------------------- + +(define_insn "*lod_df_concat" + [(set (unspec:DF [(match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (match_operand:SI 1 "metag_reg_nofloat_op" "=da")] UNSPEC_CONCAT) + (match_operand:DF 2 "memory_operand" "m"))] + "" + "GETL\\t%0, %1, %2" + [(set_attr "type" "load")]) + +(define_insn "*lod_df_off12" + [(set (match_operand:DF 0 "metag_reg_nofloat_op" "=da,da") + (mem:DF (plus:SI (match_operand:SI 1 "metag_reg12bit_op" "da,Yr") + (match_operand:SI 2 "metag_offset12_df" "O8,Z8"))))] + "" + "GETL\\t%0, %t0, [%1+%2]" + [(set_attr "type" "load")]) + +(define_insn "*lod_df_off6" + [(set (match_operand:DF 0 "metag_register_op" "=da,cx") + (mem:DF (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "da,da") + (match_operand:SI 2 "metag_offset6_df" "O8,O8"))))] + "" + "@ + GETL\\t%0, %t0, [%1+%2] + F\\tGETL\\t%0, %t0, [%1+%2]" + [(set_attr "type" "load")]) + +(define_insn "*lod_df" + [(set (match_operand:DF 0 "metag_register_op" "=cr") + (mem:DF (match_operand:SI 1 "metag_reg_nofloat_op" "da")))] + "" + { + static const char fmt[] = "F\\tGETL\\t%0, %t0, [%1]"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lod_df_mem" + [(set (match_operand:DF 0 "metag_reg_nofloat_op" "=da") + (match_operand:DF 1 "memory_operand" "m"))] + "" + "GETL\\t%0, %t0, %1\\t%@ (*lod df rm OK)" + [(set_attr "type" "load")]) + +;; Memory bloc xfer insn + +(define_expand "movmemqi" + [(match_operand:BLK 0 "general_operand" "") + (match_operand:BLK 1 "general_operand" "") + (match_operand:SI 2 "const_int_operand" "") + (match_operand:SI 3 "const_int_operand" "")] + "" + { + if (metag_gen_movmemqi (operands)) + DONE; + FAIL; + } +) + +;; Transfer instructions 64-bit and 32-bit + +;; loads DImode + +(define_insn "*ldmdi_7" + [(match_parallel 0 "load_multiop" + [(set (match_operand:SI 1 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 2 "metag_reg_nofloat_op" "1") + (const_int 56))) + (set (match_operand:DI 3 "metag_hard_datareg_op" "=d") + (mem:DI (match_dup 2))) + (set (match_operand:DI 4 "metag_hard_datareg_op" "=d") + (mem:DI (plus:SI (match_dup 2) + (const_int 8)))) + (set (match_operand:DI 5 "metag_hard_datareg_op" "=d") + (mem:DI (plus:SI (match_dup 2) + (const_int 16)))) + (set (match_operand:DI 6 "metag_hard_datareg_op" "=d") + (mem:DI (plus:SI (match_dup 2) + (const_int 24)))) + (set (match_operand:DI 7 "metag_hard_datareg_op" "=d") + (mem:DI (plus:SI (match_dup 2) + (const_int 32)))) + (set (match_operand:DI 8 "metag_hard_datareg_op" "=d") + (mem:DI (plus:SI (match_dup 2) + (const_int 40)))) + (set (match_operand:DI 9 "metag_hard_datareg_op" "=d") + (mem:DI (plus:SI (match_dup 2) + (const_int 48))))])] + "XVECLEN (operands[0], 0) == 7 + 1" + "MGETL\\t%3, %4, %5, %6, %7, %8, %9, [%1++]\\t%@ (lodmr di OK)" + [(set_attr "type" "fivex") + (set_attr "memaccess" "load") + (set_attr "rename" "no")]) + +(define_insn "*ldmdi_6" + [(match_parallel 0 "load_multiop" + [(set (match_operand:SI 1 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 2 "metag_reg_nofloat_op" "1") + (const_int 48))) + (set (match_operand:DI 3 "metag_hard_datareg_op" "=d") + (mem:DI (match_dup 2))) + (set (match_operand:DI 4 "metag_hard_datareg_op" "=d") + (mem:DI (plus:SI (match_dup 2) + (const_int 8)))) + (set (match_operand:DI 5 "metag_hard_datareg_op" "=d") + (mem:DI (plus:SI (match_dup 2) + (const_int 16)))) + (set (match_operand:DI 6 "metag_hard_datareg_op" "=d") + (mem:DI (plus:SI (match_dup 2) + (const_int 24)))) + (set (match_operand:DI 7 "metag_hard_datareg_op" "=d") + (mem:DI (plus:SI (match_dup 2) + (const_int 32)))) + (set (match_operand:DI 8 "metag_hard_datareg_op" "=d") + (mem:DI (plus:SI (match_dup 2) + (const_int 40))))])] + "XVECLEN (operands[0], 0) == 6 + 1" + "MGETL\\t%3, %4, %5, %6, %7, %8, [%1++]\\t%@ (lodmr di OK)" + [(set_attr "type" "fivex") + (set_attr "memaccess" "load") + (set_attr "rename" "no")]) + +(define_insn "*ldmdi_5" + [(match_parallel 0 "load_multiop" + [(set (match_operand:SI 1 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 2 "metag_reg_nofloat_op" "1") + (const_int 40))) + (set (match_operand:DI 3 "metag_hard_datareg_op" "=d") + (mem:DI (match_dup 2))) + (set (match_operand:DI 4 "metag_hard_datareg_op" "=d") + (mem:DI (plus:SI (match_dup 2) + (const_int 8)))) + (set (match_operand:DI 5 "metag_hard_datareg_op" "=d") + (mem:DI (plus:SI (match_dup 2) + (const_int 16)))) + (set (match_operand:DI 6 "metag_hard_datareg_op" "=d") + (mem:DI (plus:SI (match_dup 2) + (const_int 24)))) + (set (match_operand:DI 7 "metag_hard_datareg_op" "=d") + (mem:DI (plus:SI (match_dup 2) + (const_int 32))))])] + "XVECLEN (operands[0], 0) == 5 + 1" + "MGETL\\t%3, %4, %5, %6, %7, [%1++]\\t%@ (lodmr di OK)" + [(set_attr "type" "fivex") + (set_attr "memaccess" "load") + (set_attr "rename" "no")]) + +(define_insn "*ldmdi_4" + [(match_parallel 0 "load_multiop" + [(set (match_operand:SI 1 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 2 "metag_reg_nofloat_op" "1") + (const_int 32))) + (set (match_operand:DI 3 "metag_hard_datareg_op" "=d") + (mem:DI (match_dup 2))) + (set (match_operand:DI 4 "metag_hard_datareg_op" "=d") + (mem:DI (plus:SI (match_dup 2) + (const_int 8)))) + (set (match_operand:DI 5 "metag_hard_datareg_op" "=d") + (mem:DI (plus:SI (match_dup 2) + (const_int 16)))) + (set (match_operand:DI 6 "metag_hard_datareg_op" "=d") + (mem:DI (plus:SI (match_dup 2) + (const_int 24))))])] + "XVECLEN (operands[0], 0) == 4 + 1" + "MGETL\\t%3, %4, %5, %6, [%1++]\\t%@ (lodmr di OK)" + [(set_attr "type" "fourx") + (set_attr "memaccess" "load") + (set_attr "rename" "no")]) + +(define_insn "*ldmdi_3" + [(match_parallel 0 "load_multiop" + [(set (match_operand:SI 1 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 2 "metag_reg_nofloat_op" "1") + (const_int 24))) + (set (match_operand:DI 3 "metag_hard_datareg_op" "=d") + (mem:DI (match_dup 2))) + (set (match_operand:DI 4 "metag_hard_datareg_op" "=d") + (mem:DI (plus:SI (match_dup 2) + (const_int 8)))) + (set (match_operand:DI 5 "metag_hard_datareg_op" "=d") + (mem:DI (plus:SI (match_dup 2) + (const_int 16))))])] + "XVECLEN (operands[0], 0) == 3 + 1" + "MGETL\\t%3, %4, %5, [%1++]\\t%@ (lodmr di OK)" + [(set_attr "type" "threex") + (set_attr "memaccess" "load") + (set_attr "rename" "no")]) + +(define_insn "*ldmdi_2" + [(match_parallel 0 "load_multiop" + [(set (match_operand:SI 1 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 2 "metag_reg_nofloat_op" "1") + (const_int 16))) + (set (match_operand:DI 3 "metag_hard_datareg_op" "=d") + (mem:DI (match_dup 2))) + (set (match_operand:DI 4 "metag_hard_datareg_op" "=d") + (mem:DI (plus:SI (match_dup 2) + (const_int 8))))])] + "XVECLEN (operands[0], 0) == 2 + 1" + "MGETL\\t%3, %4, [%1++]\\t%@ (lodmr di OK)" + [(set_attr "type" "twox") + (set_attr "memaccess" "load") + (set_attr "rename" "no")]) + +;; Loads SImode + +(define_insn "*ldmsi_7" + [(match_parallel 0 "load_multiop" + [(set (match_operand:SI 1 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 2 "metag_reg_nofloat_op" "1") + (const_int 28))) + (set (match_operand:SI 3 "metag_hard_datareg_op" "=d") + (mem:SI (match_dup 2))) + (set (match_operand:SI 4 "metag_hard_datareg_op" "=d") + (mem:SI (plus:SI (match_dup 2) + (const_int 4)))) + (set (match_operand:SI 5 "metag_hard_datareg_op" "=d") + (mem:SI (plus:SI (match_dup 2) + (const_int 8)))) + (set (match_operand:SI 6 "metag_hard_datareg_op" "=d") + (mem:SI (plus:SI (match_dup 2) + (const_int 12)))) + (set (match_operand:SI 7 "metag_hard_datareg_op" "=d") + (mem:SI (plus:SI (match_dup 2) + (const_int 16)))) + (set (match_operand:SI 8 "metag_hard_datareg_op" "=d") + (mem:SI (plus:SI (match_dup 2) + (const_int 20)))) + (set (match_operand:SI 9 "metag_hard_datareg_op" "=d") + (mem:SI (plus:SI (match_dup 2) + (const_int 24))))])] + "XVECLEN (operands[0], 0) == 7 + 1" + "MGETD\\t%3, %4, %5, %6, %7, %8, %9, [%1]\\t%@ (lodmr si OK)" + [(set_attr "type" "fivex") + (set_attr "memaccess" "load") + (set_attr "rename" "no")]) + +(define_insn "*ldmsi_6" + [(match_parallel 0 "load_multiop" + [(set (match_operand:SI 1 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 2 "metag_reg_nofloat_op" "1") + (const_int 24))) + (set (match_operand:SI 3 "metag_hard_datareg_op" "=d") + (mem:SI (match_dup 2))) + (set (match_operand:SI 4 "metag_hard_datareg_op" "=d") + (mem:SI (plus:SI (match_dup 2) + (const_int 4)))) + (set (match_operand:SI 5 "metag_hard_datareg_op" "=d") + (mem:SI (plus:SI (match_dup 2) + (const_int 8)))) + (set (match_operand:SI 6 "metag_hard_datareg_op" "=d") + (mem:SI (plus:SI (match_dup 2) + (const_int 12)))) + (set (match_operand:SI 7 "metag_hard_datareg_op" "=d") + (mem:SI (plus:SI (match_dup 2) + (const_int 16)))) + (set (match_operand:SI 8 "metag_hard_datareg_op" "=d") + (mem:SI (plus:SI (match_dup 2) + (const_int 20))))])] + "XVECLEN (operands[0], 0) == 6 + 1" + "MGETD\\t%3, %4, %5, %6, %7, [%1]\\t%@ (lodmr si OK)" + [(set_attr "type" "fivex") + (set_attr "memaccess" "load") + (set_attr "rename" "no")]) + +(define_insn "*ldmsi_5" + [(match_parallel 0 "load_multiop" + [(set (match_operand:SI 1 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 2 "metag_reg_nofloat_op" "1") + (const_int 20))) + (set (match_operand:SI 3 "metag_hard_datareg_op" "=d") + (mem:SI (match_dup 2))) + (set (match_operand:SI 4 "metag_hard_datareg_op" "=d") + (mem:SI (plus:SI (match_dup 2) + (const_int 4)))) + (set (match_operand:SI 5 "metag_hard_datareg_op" "=d") + (mem:SI (plus:SI (match_dup 2) + (const_int 8)))) + (set (match_operand:SI 6 "metag_hard_datareg_op" "=d") + (mem:SI (plus:SI (match_dup 2) + (const_int 12)))) + (set (match_operand:SI 7 "metag_hard_datareg_op" "=d") + (mem:SI (plus:SI (match_dup 2) + (const_int 16))))])] + "XVECLEN (operands[0], 0) == 5 + 1" + "MGETD\\t%3, %4, %5, %6, %7, [%1]\\t%@ (lodmr si OK)" + [(set_attr "type" "fivex") + (set_attr "memaccess" "load") + (set_attr "rename" "no")]) + +(define_insn "*ldmsi_4" + [(match_parallel 0 "load_multiop" + [(set (match_operand:SI 1 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 2 "metag_reg_nofloat_op" "1") + (const_int 16))) + (set (match_operand:SI 3 "metag_hard_datareg_op" "=d") + (mem:SI (match_dup 2))) + (set (match_operand:SI 4 "metag_hard_datareg_op" "=d") + (mem:SI (plus:SI (match_dup 2) + (const_int 4)))) + (set (match_operand:SI 5 "metag_hard_datareg_op" "=d") + (mem:SI (plus:SI (match_dup 2) + (const_int 8)))) + (set (match_operand:SI 6 "metag_hard_datareg_op" "=d") + (mem:SI (plus:SI (match_dup 2) + (const_int 12))))])] + "XVECLEN (operands[0], 0) == 4 + 1" + "MGETD\\t%3, %4, %5, %6, [%1]\\t%@ (lodmr si OK)" + [(set_attr "type" "fourx") + (set_attr "memaccess" "load") + (set_attr "rename" "no")]) + +(define_insn "*ldmsi_3" + [(match_parallel 0 "load_multiop" + [(set (match_operand:SI 1 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 2 "metag_reg_nofloat_op" "1") + (const_int 12))) + (set (match_operand:SI 3 "metag_hard_datareg_op" "=d") + (mem:SI (match_dup 2))) + (set (match_operand:SI 4 "metag_hard_datareg_op" "=d") + (mem:SI (plus:SI (match_dup 2) + (const_int 4)))) + (set (match_operand:SI 5 "metag_hard_datareg_op" "=d") + (mem:SI (plus:SI (match_dup 2) + (const_int 8))))])] + "XVECLEN (operands[0], 0) == 3 + 1" + "MGETD\\t%3, %4, %5, [%1]\\t%@ (lodmr si OK)" + [(set_attr "type" "threex") + (set_attr "memaccess" "load") + (set_attr "rename" "no")]) + +(define_insn "*ldmsi_2" + [(match_parallel 0 "load_multiop" + [(set (match_operand:SI 1 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 2 "metag_reg_nofloat_op" "1") + (const_int 8))) + (set (match_operand:SI 3 "metag_hard_datareg_op" "=d") + (mem:SI (match_dup 2))) + (set (match_operand:SI 4 "metag_hard_datareg_op" "=d") + (mem:SI (plus:SI (match_dup 2) + (const_int 4))))])] + "XVECLEN (operands[0], 0) == 2 + 1" + "MGETD\\t%3, %4, [%1]\\t%@ (lodmr si OK)" + [(set_attr "type" "twox") + (set_attr "memaccess" "load") + (set_attr "rename" "no")]) + +;; stores DImode +(define_insn "*stmdi_8" + [(match_parallel 0 "store_multiop" + [(set (match_operand:SI 1 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 2 "metag_reg_nofloat_op" "1") + (const_int 64))) + (set (mem:DI (match_dup 2)) + (match_operand:DI 3 "metag_hard_datareg_op" "d")) + (set (mem:DI (plus:SI (match_dup 2) + (const_int 8))) + (match_operand:DI 4 "metag_hard_datareg_op" "d")) + (set (mem:DI (plus:SI (match_dup 2) + (const_int 16))) + (match_operand:DI 5 "metag_hard_datareg_op" "d")) + (set (mem:DI (plus:SI (match_dup 2) + (const_int 24))) + (match_operand:DI 6 "metag_hard_datareg_op" "d")) + (set (mem:DI (plus:SI (match_dup 2) + (const_int 32))) + (match_operand:DI 7 "metag_hard_datareg_op" "d")) + (set (mem:DI (plus:SI (match_dup 2) + (const_int 40))) + (match_operand:DI 8 "metag_hard_datareg_op" "d")) + (set (mem:DI (plus:SI (match_dup 2) + (const_int 48))) + (match_operand:DI 9 "metag_hard_datareg_op" "d")) + (set (mem:DI (plus:SI (match_dup 2) + (const_int 56))) + (match_operand:DI 10 "metag_hard_datareg_op" "d"))])] + "XVECLEN (operands[0], 0) == 8 + 1" + "MSETL\\t[%1++], %3, %4, %5, %6, %7, %8, %9, %10\\t%@ (*stomr di OK)" + [(set_attr "type" "fivex") + (set_attr "memaccess" "store") + (set_attr "rename" "no")]) + +(define_insn "*stmdi_7" + [(match_parallel 0 "store_multiop" + [(set (match_operand:SI 1 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 2 "metag_reg_nofloat_op" "1") + (const_int 56))) + (set (mem:DI (match_dup 2)) + (match_operand:DI 3 "metag_hard_datareg_op" "d")) + (set (mem:DI (plus:SI (match_dup 2) + (const_int 8))) + (match_operand:DI 4 "metag_hard_datareg_op" "d")) + (set (mem:DI (plus:SI (match_dup 2) + (const_int 16))) + (match_operand:DI 5 "metag_hard_datareg_op" "d")) + (set (mem:DI (plus:SI (match_dup 2) + (const_int 24))) + (match_operand:DI 6 "metag_hard_datareg_op" "d")) + (set (mem:DI (plus:SI (match_dup 2) + (const_int 32))) + (match_operand:DI 7 "metag_hard_datareg_op" "d")) + (set (mem:DI (plus:SI (match_dup 2) + (const_int 40))) + (match_operand:DI 8 "metag_hard_datareg_op" "d")) + (set (mem:DI (plus:SI (match_dup 2) + (const_int 48))) + (match_operand:DI 9 "metag_hard_datareg_op" "d"))])] + "XVECLEN (operands[0], 0) == 7 + 1" + "MSETL\\t[%1++], %3, %4, %5, %6, %7, %8, %9\\t%@ (*stomr di OK)" + [(set_attr "type" "fivex") + (set_attr "memaccess" "store") + (set_attr "rename" "no")]) + +(define_insn "*stmdi_6" + [(match_parallel 0 "store_multiop" + [(set (match_operand:SI 1 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 2 "metag_reg_nofloat_op" "1") + (const_int 48))) + (set (mem:DI (match_dup 2)) + (match_operand:DI 3 "metag_hard_datareg_op" "d")) + (set (mem:DI (plus:SI (match_dup 2) + (const_int 8))) + (match_operand:DI 4 "metag_hard_datareg_op" "d")) + (set (mem:DI (plus:SI (match_dup 2) + (const_int 16))) + (match_operand:DI 5 "metag_hard_datareg_op" "d")) + (set (mem:DI (plus:SI (match_dup 2) + (const_int 24))) + (match_operand:DI 6 "metag_hard_datareg_op" "d")) + (set (mem:DI (plus:SI (match_dup 2) + (const_int 32))) + (match_operand:DI 7 "metag_hard_datareg_op" "d")) + (set (mem:DI (plus:SI (match_dup 2) + (const_int 40))) + (match_operand:DI 8 "metag_hard_datareg_op" "d"))])] + "XVECLEN (operands[0], 0) == 6 + 1" + "MSETL\\t[%1++], %3, %4, %5, %6, %7, %8\\t%@ (*stomr di OK)" + [(set_attr "type" "fivex") + (set_attr "memaccess" "store") + (set_attr "rename" "no")]) + +(define_insn "*stmdi_5" + [(match_parallel 0 "store_multiop" + [(set (match_operand:SI 1 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 2 "metag_reg_nofloat_op" "1") + (const_int 40))) + (set (mem:DI (match_dup 2)) + (match_operand:DI 3 "metag_hard_datareg_op" "d")) + (set (mem:DI (plus:SI (match_dup 2) + (const_int 8))) + (match_operand:DI 4 "metag_hard_datareg_op" "d")) + (set (mem:DI (plus:SI (match_dup 2) + (const_int 16))) + (match_operand:DI 5 "metag_hard_datareg_op" "d")) + (set (mem:DI (plus:SI (match_dup 2) + (const_int 24))) + (match_operand:DI 6 "metag_hard_datareg_op" "d")) + (set (mem:DI (plus:SI (match_dup 2) + (const_int 32))) + (match_operand:DI 7 "metag_hard_datareg_op" "d"))])] + "XVECLEN (operands[0], 0) == 5 + 1" + "MSETL\\t[%1++], %3, %4, %5, %6, %7\\t%@ (*stomr di OK)" + [(set_attr "type" "fivex") + (set_attr "memaccess" "store") + (set_attr "rename" "no")]) + +(define_insn "*stmdi_4" + [(match_parallel 0 "store_multiop" + [(set (match_operand:SI 1 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 2 "metag_reg_nofloat_op" "1") + (const_int 32))) + (set (mem:DI (match_dup 2)) + (match_operand:DI 3 "metag_hard_datareg_op" "d")) + (set (mem:DI (plus:SI (match_dup 2) + (const_int 8))) + (match_operand:DI 4 "metag_hard_datareg_op" "d")) + (set (mem:DI (plus:SI (match_dup 2) + (const_int 16))) + (match_operand:DI 5 "metag_hard_datareg_op" "d")) + (set (mem:DI (plus:SI (match_dup 2) + (const_int 24))) + (match_operand:DI 6 "metag_hard_datareg_op" "d"))])] + "XVECLEN (operands[0], 0) == 4 + 1" + "MSETL\\t[%1++], %3, %4, %5, %6\\t%@ (*stomr di OK)" + [(set_attr "type" "fourx") + (set_attr "memaccess" "store") + (set_attr "rename" "no")]) + +(define_insn "*stmdi_3" + [(match_parallel 0 "store_multiop" + [(set (match_operand:SI 1 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 2 "metag_reg_nofloat_op" "1") + (const_int 24))) + (set (mem:DI (match_dup 2)) + (match_operand:DI 3 "metag_hard_datareg_op" "d")) + (set (mem:DI (plus:SI (match_dup 2) + (const_int 8))) + (match_operand:DI 4 "metag_hard_datareg_op" "d")) + (set (mem:DI (plus:SI (match_dup 2) + (const_int 16))) + (match_operand:DI 5 "metag_hard_datareg_op" "d"))])] + "XVECLEN (operands[0], 0) == 3 + 1" + "MSETL\\t[%1++], %3, %4, %5\\t%@ (*stomr di OK)" + [(set_attr "type" "threex") + (set_attr "memaccess" "store") + (set_attr "rename" "no")]) + +(define_insn "*stmdi_2" + [(match_parallel 0 "store_multiop" + [(set (match_operand:SI 1 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 2 "metag_reg_nofloat_op" "1") + (const_int 16))) + (set (mem:DI (match_dup 2)) + (match_operand:DI 3 "metag_hard_datareg_op" "d")) + (set (mem:DI (plus:SI (match_dup 2) + (const_int 8))) + (match_operand:DI 4 "metag_hard_datareg_op" "d"))])] + "XVECLEN (operands[0], 0) == 2 + 1" + "MSETL\\t[%1++], %3, %4\\t%@ (*stomr di OK)" + [(set_attr "type" "twox") + (set_attr "memaccess" "store") + (set_attr "rename" "no")]) + +;; Stores SImode + +(define_insn "*stmsi_5" + [(match_parallel 0 "store_multiop" + [(set (match_operand:SI 1 "metag_addrreg_op" "=a") + (plus:SI (match_operand:SI 2 "metag_addrreg_op" "1") + (const_int 20))) + (set (mem:SI (match_dup 2)) + (match_operand:SI 3 "metag_hard_datareg_op" "d")) + (set (mem:SI (plus:SI (match_dup 2) + (const_int 4))) + (match_operand:SI 4 "metag_hard_datareg_op" "d")) + (set (mem:SI (plus:SI (match_dup 2) + (const_int 8))) + (match_operand:SI 5 "metag_hard_datareg_op" "d")) + (set (mem:SI (plus:SI (match_dup 2) + (const_int 12))) + (match_operand:SI 6 "metag_hard_datareg_op" "d")) + (set (mem:SI (plus:SI (match_dup 2) + (const_int 16))) + (match_operand:SI 7 "metag_hard_datareg_op" "d"))])] + "XVECLEN (operands[0], 0) == 5 + 1" + "MSETD\\t[%1], %3, %4, %5, %6, %7\\t%@ (*stomr si OK)" + [(set_attr "type" "fivex") + (set_attr "memaccess" "store") + (set_attr "rename" "no")]) + +(define_insn "*stmsi_4" + [(match_parallel 0 "store_multiop" + [(set (match_operand:SI 1 "metag_addrreg_op" "=a") + (plus:SI (match_operand:SI 2 "metag_addrreg_op" "1") + (const_int 16))) + (set (mem:SI (match_dup 2)) + (match_operand:SI 3 "metag_hard_datareg_op" "d")) + (set (mem:SI (plus:SI (match_dup 2) + (const_int 4))) + (match_operand:SI 4 "metag_hard_datareg_op" "d")) + (set (mem:SI (plus:SI (match_dup 2) + (const_int 8))) + (match_operand:SI 5 "metag_hard_datareg_op" "d")) + (set (mem:SI (plus:SI (match_dup 2) + (const_int 12))) + (match_operand:SI 6 "metag_hard_datareg_op" "d"))])] + "XVECLEN (operands[0], 0) == 4 + 1" + "MSETD\\t[%1], %3, %4, %5, %6\\t%@ (*stomr si OK)" + [(set_attr "type" "fourx") + (set_attr "memaccess" "store") + (set_attr "rename" "no")]) + +(define_insn "*stmsi_3" + [(match_parallel 0 "store_multiop" + [(set (match_operand:SI 1 "metag_addrreg_op" "=a") + (plus:SI (match_operand:SI 2 "metag_addrreg_op" "1") + (const_int 12))) + (set (mem:SI (match_dup 2)) + (match_operand:SI 3 "metag_hard_datareg_op" "d")) + (set (mem:SI (plus:SI (match_dup 2) + (const_int 4))) + (match_operand:SI 4 "metag_hard_datareg_op" "d")) + (set (mem:SI (plus:SI (match_dup 2) + (const_int 8))) + (match_operand:SI 5 "metag_hard_datareg_op" "d"))])] + "XVECLEN (operands[0], 0) == 3 + 1" + "MSETD\\t[%1], %3, %4, %5\\t%@ (*stomr si OK)" + [(set_attr "type" "threex") + (set_attr "memaccess" "store") + (set_attr "rename" "no")]) + +(define_insn "*stmsi_2" + [(match_parallel 0 "store_multiop" + [(set (match_operand:SI 1 "metag_addrreg_op" "=a") + (plus:SI (match_operand:SI 2 "metag_addrreg_op" "1") + (const_int 8))) + (set (mem:SI (match_dup 2)) + (match_operand:SI 3 "metag_hard_datareg_op" "d")) + (set (mem:SI (plus:SI (match_dup 2) + (const_int 4))) + (match_operand:SI 4 "metag_hard_datareg_op" "d"))])] + "XVECLEN (operands[0], 0) == 2 + 1" + "MSETD\\t[%1], %3, %4\\t%@ (*stomr si OK)" + [(set_attr "type" "twox") + (set_attr "memaccess" "store") + (set_attr "rename" "no")]) + +;; add instructions + +;; Addition insns. + +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +;; adddi3 ;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +(define_expand "adddi3" + [(parallel + [(set (match_operand:DI 0 "metag_reg_nofloat_op" "") + (plus:DI (match_operand:DI 1 "metag_reg_nofloat_op" "") + (match_operand:DI 2 "metag_reg_nofloat_op" ""))) + (clobber (reg:CC CC_REG))])] + "" + "") + +(define_insn "*adddi3_dsp" + [(set (match_operand:DI 0 "metag_datareg_op" "=d") + (plus:DI (match_operand:DI 1 "metag_datareg_op" "%d") + (match_operand:DI 2 "metag_datareg_op" "d"))) + (clobber (reg:CC CC_REG))] + "TARGET_DSP" + "DL\\tADDS\\t%0, %1, %2\\t%@ (*ADD\\t%t0, %t1, %t2)\;ADDCS\\t%t0, %t0, #1" + [(set_attr "type" "two") + (set_attr "ccstate" "ccx")]) + +(define_insn_and_split "*adddi3" + [(set (match_operand:DI 0 "metag_datareg_op" "=d") + (plus:DI (match_operand:DI 1 "metag_datareg_op" "%d") + (match_operand:DI 2 "metag_datareg_op" "d"))) + (clobber (reg:CC CC_REG))] + "" + "#" + "SPLIT_EARLY" + [(parallel + [(set (reg:CC_NOOV CC_REG) + (compare:CC_NOOV + (plus:SI (match_dup 5) + (match_dup 7)) + (const_int 0))) + (set (match_dup 3) + (plus:SI (match_dup 5) + (match_dup 7)))]) + (set (match_dup 4) + (plus:SI (match_dup 6) + (match_dup 8))) + (set (match_dup 4) + (if_then_else:SI (ltu (reg:CC_NOOV CC_REG) + (const_int 0)) + (plus:SI (match_dup 4) + (const_int 1)) + (match_dup 4)))] + { + if (reload_completed) + { + operands[3] = gen_rtx_REG (SImode, REGNO (operands[0])); + operands[4] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + + operands[5] = gen_rtx_REG (SImode, REGNO (operands[1])); + operands[6] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1); + + operands[7] = gen_rtx_REG (SImode, REGNO (operands[2])); + operands[8] = gen_rtx_REG (SImode, REGNO (operands[2]) + 1); + } + else + { + operands[3] = gen_rtx_SUBREG (SImode, operands[0], 0); + operands[4] = gen_rtx_SUBREG (SImode, operands[0], UNITS_PER_WORD); + + operands[5] = gen_rtx_SUBREG (SImode, operands[1], 0); + operands[6] = gen_rtx_SUBREG (SImode, operands[1], UNITS_PER_WORD); + + operands[7] = gen_rtx_SUBREG (SImode, operands[2], 0); + operands[8] = gen_rtx_SUBREG (SImode, operands[2], UNITS_PER_WORD); + } + } + [(set_attr "type" "three") + (set_attr "ccstate" "ccx")]) + +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +;; addsi3 is made up of many parts.. ;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +(define_expand "addsi3" + [(set (match_operand:SI 0 "metag_register_op" "") + (plus:SI (match_operand:SI 1 "metag_register_op" "") + (match_operand:SI 2 "metag_regorint_op" "")))] + "" + { + if (metag_frame_related_rtx (operands[2])) + { + /* Put the magic frame registers first */ + rtx temp = operands[1]; + + operands[1] = operands[2]; + operands[2] = temp; + } + + if (!reload_completed + && !reload_in_progress + && metag_frame_related_rtx (operands[1])) + { + /* Ensure reg+reg adds do not combine regs that may be eliminated */ + operands[1] = force_reg (SImode, operands[1]); + } + } +) + +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +;; these are the addsi3 parts.. ;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; + +;; control register = datareg + smallint +(define_insn "*add_si_cdi" + [(set (match_operand:SI 0 "metag_txrpt_op" "=Wx,Wx") + (plus:SI (match_operand:SI 1 "metag_datareg_op" "%d, d") + (match_operand:SI 2 "metag_smallint_op" "K, P")))] + "" + "@ + ADD\\t%0, %1, %2\\t%@ (*add si cdK OK) + SUB\\t%0, %1, #%n2\\t%@ (*add si cdP OK)" + [(set_attr "type" "slow,slow")]) + +;; control register = reg +/- reg +(define_insn "*sub_si_crr" + [(set (match_operand:SI 0 "metag_txrpt_op" "=Wx,Wx,Wx,Wx") + (minus:SI (match_operand:SI 1 "metag_regnofrm_op" "e, f, h, l") + (match_operand:SI 2 "metag_regnofrm_op" "e, f, h, l")))] + "" + "SUB\\t%0, %1, %2\\t%@ (*sub si crr OK)" + [(set_attr "type" "slow,slow,slow,slow")]) + +(define_insn "*add_si_crr" + [(set (match_operand:SI 0 "metag_txrpt_op" "=Wx,Wx,Wx,Wx") + (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "%e, f, h, l") + (match_operand:SI 2 "metag_regnofrm_op" "e, f, h, l")))] + "" + "ADD\\t%0, %1, %2\\t%@ (*add si crr OK)" + [(set_attr "type" "slow,slow,slow,slow")]) + +;; register + register ops - generic case +(define_insn "*add_si_rrr" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=e,f,h,l,da,da,da,da") + (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "%e,f,h,l,e, f, h, l") + (match_operand:SI 2 "metag_regnofrm_op" "e,f,h,l,e, f, h, l")))] + "!TARGET_METAC_1_1" + "ADD%?\\t%0, %1, %2" + [(set_attr "type" "fast,fast,fast,fast,slow,slow,slow,slow") + (set_attr "cond" "yes,yes,yes,yes,yes,yes,yes,yes") + (set_attr "predicable" "yes")]) + +;; register + register ops - v1.1 case +(define_insn "*add_si_rrb_1_1" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=e, f, h, l, da,da,da,da") + (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "%e, f, h, l, e, f, h, l") + (match_operand:SI 2 "metag_regnofrm_op" "be,bf,bh,bl,be,bf,bh,bl")))] + "TARGET_METAC_1_1 && !TARGET_MINIM_CORE" + "ADD%?\\t%0, %1, %2" + [(set_attr "type" "fast,fast,fast,fast,slow,slow,slow,slow") + (set_attr "cond" "yes,yes,yes,yes,yes,yes,yes,yes") + (set_attr "predicable" "yes")]) + +(define_insn "*add_si_rrb_1_1_if_" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=e, f, h, l, da,da,da,da") + (if_then_else:SI (match_operator 1 "comparison_operator" + [(match_operand:CCALL 2 "metag__reg" "") + (const_int 0)]) + (plus:SI (match_operand:SI 3 "metag_regnofrm_op" "%e, f, h, l, e, f, h, l") + (match_operand:SI 4 "metag_regnofrm_op" "be,bf,bh,bl,be,bf,bh,bl")) + (match_operand:SI 5 "metag_reg_nofloat_op" "0, 0, 0, 0, 0, 0, 0, 0")))] + "TARGET_METAC_1_1 && !TARGET_MINIM_CORE" + "ADD%z1\\t%0, %3, %4" + [(set_attr "type" "fast,fast,fast,fast,slow,slow,slow,slow") + (set_attr "ccstate" "xcc")]) + +;; register + register ops - minim case +(define_insn "*add_si_rrb_minim" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=e,!e, f,!f, h,!h, l,!l, da,!da,da,!da,da,!da,da,!da") + (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "%e, e, f, f, h, h, l, l, e, e, f, f, h, h, l, l") + (match_operand:SI 2 "metag_regnofrm_op" "e, be,f, bf,h, bh,l, bl,e, be,f, bf,h, bh,l, bl")))] + "TARGET_METAC_1_1 && TARGET_MINIM_CORE" + "ADD%?\\t%0, %1, %2" + [(set_attr "type" "fast,fast,fast,fast,fast,fast,fast,fast,slow,slow,slow,slow,slow,slow,slow,slow") + (set_attr "cond" "yes") + (set_attr "predicable" "yes")]) + +(define_insn "*add_si_rrb_minim_if_" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=e,!e, f,!f, h,!h, l,!l, da,!da,da,!da,da,!da,da,!da") + (if_then_else:SI (match_operator 1 "comparison_operator" + [(match_operand:CCALL 2 "metag__reg" "") + (const_int 0)]) + (plus:SI (match_operand:SI 3 "metag_regnofrm_op" "%e, e, f, f, h, h, l, l, e, e, f, f, h, h, l, l") + (match_operand:SI 4 "metag_regnofrm_op" "e, be,f, bf,h, bh,l, bl,e, be,f, bf,h, bh,l, bl")) + (match_operand:SI 5 "metag_reg_nofloat_op" "0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0")))] + "TARGET_METAC_1_1 && TARGET_MINIM_CORE" + "ADD%z1\\t%0, %3, %4" + [(set_attr "type" "fast,fast,fast,fast,fast,fast,fast,fast,slow,slow,slow,slow,slow,slow,slow,slow") + (set_attr "ccstate" "xcc")]) + +;; Seperate stack frame related register+register adds +(define_insn "*add_si_index_frame" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=h,da,!da") + (plus:SI (match_operand:SI 1 "metag_regframe_op" "%h,h, h") + (match_operand:SI 2 "metag_regnofrm_op" "h,h, bh")))] + "!TARGET_METAC_1_1" + "ADD%?\\t%0, %1, %2\\t%@ (*add si rfrmh OK)" + [(set_attr "type" "fast,slow,three") + (set_attr "cond" "yes,yes,yes") + (set_attr "predicable" "yes")]) + +;; Sadly instantiate_virtual_regs can be really dumb some times +(define_insn "*add_si_index_frame2" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=h,da,!da") + (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "%h,h, h") + (match_operand:SI 2 "metag_regframe_op" "h,h, bh")))] + "!TARGET_METAC_1_1" + "ADD%?\\t%0, %1, %2\\t%@ (*add si rhfrm OK)" + [(set_attr "type" "fast,slow,three") + (set_attr "cond" "yes,yes,yes") + (set_attr "predicable" "yes")]) + +;; Seperate stack frame related register+register adds - v1.1 case +(define_insn "*add_si_index_frame_1_1" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=h, da") + (plus:SI (match_operand:SI 1 "metag_regframe_op" "%h, h") + (match_operand:SI 2 "metag_regnofrm_op" "bh,bh")))] + "TARGET_METAC_1_1 && !TARGET_MINIM_CORE" + "ADD%?\\t%0, %1, %2\\t%@ (*add si rfrmb OK)" + [(set_attr "type" "fast,slow") + (set_attr "cond" "yes,yes") + (set_attr "predicable" "yes")]) + +;; Seperate stack frame related register+register adds - minim case +(define_insn "*add_si_index_frame_minim" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=h,!h, da,!da") + (plus:SI (match_operand:SI 1 "metag_regframe_op" "%h, h, h, h") + (match_operand:SI 2 "metag_regnofrm_op" "h, bh,h, bh")))] + "TARGET_METAC_1_1 && TARGET_MINIM_CORE" + "ADD%?\\t%0, %1, %2\\t%@ (*add si rfrmb OK)" + [(set_attr "type" "fast,fast,slow,slow") + (set_attr "cond" "yes") + (set_attr "predicable" "yes")]) + +;; Sadly instantiate_virtual_regs can be really dumb some times - v1.1 case +(define_insn "*add_si_index_frame2_1_1" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=h, da") + (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "%h, h") + (match_operand:SI 2 "metag_regframe_op" "bh,bh")))] + "TARGET_METAC_1_1 && !TARGET_MINIM_CORE" + "ADD%?\\t%0, %1, %2\\t%@ (*add si rbfrm OK)" + [(set_attr "type" "fast,slow") + (set_attr "cond" "yes,yes") + (set_attr "predicable" "yes")]) + +;; Sadly instantiate_virtual_regs can be really dumb some times - minim case +(define_insn "*add_si_index_frame2_minim" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=h,!h, da,!da") + (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "%h, h, h, h") + (match_operand:SI 2 "metag_regframe_op" "h, bh,h, bh")))] + "TARGET_METAC_1_1 && TARGET_MINIM_CORE" + "ADD%?\\t%0, %1, %2\\t%@ (*add si rbfrm OK)" + [(set_attr "type" "fast,fast,slow,slow") + (set_attr "cond" "yes") + (set_attr "predicable" "yes")]) + +;; spill_frame - cannot really add frame value to something else +(define_split + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "") + (plus:SI (match_operand:SI 1 "metag_regframe_op" "") + (match_operand:SI 2 "metag_reg_nofloat_op" "")))] + "!TARGET_METAC_1_1 + && reload_completed + && METAG_REGNO_REG_CLASS (REGNO (operands[2])) != A0_REGS" + [(set (match_dup 3) + (match_dup 2)) + (set (match_dup 0) + (plus:SI (match_dup 1) + (match_dup 3)))] + { + gcc_assert (A0_SCRATCH != INVALID_REGNUM && fixed_regs[A0_SCRATCH]); + operands[3] = gen_rtx_REG (SImode, A0_SCRATCH); + } +) + +(define_split + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "") + (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "") + (match_operand:SI 2 "metag_regframe_op" "")))] + "!TARGET_METAC_1_1 + && reload_completed + && METAG_REGNO_REG_CLASS (REGNO (operands[1])) != A0_REGS" + [(set (match_dup 3) + (match_dup 1)) + (set (match_dup 0) + (plus:SI (match_dup 3) + (match_dup 2)))] + { + gcc_assert (A0_SCRATCH != INVALID_REGNUM && fixed_regs[A0_SCRATCH]); + operands[3] = gen_rtx_REG (SImode, A0_SCRATCH); + } +) + +;; register + immediate ops +(define_insn "*add_si_rri" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=e,e,f,f,h,h,l,l,da,da,da,da,da,da,da,da") + (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "%e,e,f,f,h,h,l,l,d, d, a, a, 0, 0, 0, 0") + (match_operand:SI 2 "const_int_operand" "K,P,K,P,K,P,K,P,K, P, K, P, I, J, O3,i")))] + "!TARGET_MINIM_CORE" + "@ + ADD%?\\t%0, %1, %2\\t\\t%@ (*add si eeK OK) + SUB%?\\t%0, %1, #%n2\\t\\t%@ (*add si eeP) + ADD%?\\t%0, %1, %2\\t\\t%@ (*add si ffK OK) + SUB%?\\t%0, %1, #%n2\\t\\t%@ (*add si ffP) + ADD%?\\t%0, %1, %2\\t\\t%@ (*add si hhK OK) + SUB%?\\t%0, %1, #%n2\\t\\t%@ (*add si hhP OK) + ADD%?\\t%0, %1, %2\\t\\t%@ (*add si llK OK) + SUB%?\\t%0, %1, #%n2\\t\\t%@ (*add si llP OK) + ADD\\t%0, %1, %2\\t\\t%@ (*add si rdK OK) + SUB\\t%0, %1, #%n2\\t\\t%@ (*add si rdP OK) + ADD\\t%0, %1, %2\\t\\t%@ (*add si daaK OK) + SUB\\t%0, %1, #%n2\\t\\t%@ (*add si daaP OK) + ADD\\t%0, %1, %2\\t%@ (*add si da0I OK) + ADDT\\t%0, %1, #HI(%c2)\\t%@ (*add si da0J OK) + ADDT\\t%0, %1, #LO(%c2)\\t%@ (*add si da03 OK) + #" + [(set_attr "type" "fast,fast,fast,fast,fast,fast,fast,fast,slow,slow,slow,slow,fast,fast,fast,two") + (set_attr "cond" "yes,yes,yes,yes,yes,yes,yes,yes,no,no,no,no,no,no,no,no")]) + +;; register + immediate ops +(define_insn "*add_si_rri" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da,da,!e,!e,!f,!f,!h,!h,!l,!l,da,da,da,da,da,da,da,da") + (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "%0, 0, e, e, f, f, h, h, l, l,d, d, a, a, 0, 0, 0, 0") + (match_operand:SI 2 "const_int_operand" "K, P, K, P, K, P, K, P, K, P,K, P, K, P, I, J, O3,i")))] + "TARGET_MINIM_CORE" + "@ + ADD%?\\t%0, %1, %2\\t\\t%@ (*add si r0K OK) + SUB%?\\t%0, %1, #%n2\\t\\t%@ (*add si r0P) + ADD%?\\t%0, %1, %2\\t\\t%@ (*add si eeK OK) + SUB%?\\t%0, %1, #%n2\\t\\t%@ (*add si eeP) + ADD%?\\t%0, %1, %2\\t\\t%@ (*add si ffK OK) + SUB%?\\t%0, %1, #%n2\\t\\t%@ (*add si ffP) + ADD%?\\t%0, %1, %2\\t\\t%@ (*add si hhK OK) + SUB%?\\t%0, %1, #%n2\\t\\t%@ (*add si hhP OK) + ADD%?\\t%0, %1, %2\\t\\t%@ (*add si llK OK) + SUB%?\\t%0, %1, #%n2\\t\\t%@ (*add si llP OK) + ADD\\t%0, %1, %2\\t\\t%@ (*add si rdK OK) + SUB\\t%0, %1, #%n2\\t\\t%@ (*add si rdP OK) + ADD\\t%0, %1, %2\\t\\t%@ (*add si daaK OK) + SUB\\t%0, %1, #%n2\\t\\t%@ (*add si daaP OK) + ADD\\t%0, %1, %2\\t%@ (*add si da0I OK) + ADDT\\t%0, %1, #HI(%c2)\\t%@ (*add si da0J OK) + ADDT\\t%0, %1, #LO(%c2)\\t%@ (*add si da03 OK) + #" + [(set_attr "type" "fast,fast,fast,fast,fast,fast,fast,fast,fast,fast,slow,slow,slow,slow,fast,fast,fast,two") + (set_attr "cond" "yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,no,no,no,no,no,no,no,no")]) + +;; Split the above add_si_rri if it needs more than one insn +(define_split + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "") + (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "") + (match_operand:SI 2 "const_int_operand" "")))] + "reload_completed + && REGNO (operands[0]) == REGNO (operands[1]) && !METAG_CONST_OK_FOR_LETTERS_KPIJO3 (operands[2])" + [(set (match_dup 0) + (plus:SI (match_dup 1) + (match_dup 3))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_dup 4)))] + { + HOST_WIDE_INT value = INTVAL (operands[2]); + HOST_WIDE_INT ival; + + ival = trunc_int_for_mode (value & 0xFFFF0000, SImode); + operands[3] = GEN_INT (ival); + + ival = trunc_int_for_mode (value & 0x0000FFFF, SImode); + operands[4] = GEN_INT (ival); + } +) + +;; conditional version for specific cases of add_si_rri +(define_insn "*cond__add_si_rri" + [(cond_exec + (match_operator 3 "comparison_operator" + [(match_operand:CCALL 4 "metag__reg" "") + (const_int 0)]) + (set (match_operand:SI 0 "metag_hard_genreg_op" "=e,e,f,f,h,h,l,l") + (plus:SI (match_operand:SI 1 "metag_hard_genreg_op" "%e,e,f,f,h,h,l,l") + (match_operand:SI 2 "metag_KP_operand" "K,P,K,P,K,P,K,P"))))] + "reload_completed + && metag_same_regclass_p (operands[0], operands[1])" + "@ + ADD%?\\t%0, %1, %2\\t\\t%@ (*add si eeK OK) + SUB%?\\t%0, %1, #%n2\\t\\t%@ (*add si eeP) + ADD%?\\t%0, %1, %2\\t\\t%@ (*add si ffK OK) + SUB%?\\t%0, %1, #%n2\\t\\t%@ (*add si ffP) + ADD%?\\t%0, %1, %2\\t\\t%@ (*add si hhK OK) + SUB%?\\t%0, %1, #%n2\\t\\t%@ (*add si hhP OK) + ADD%?\\t%0, %1, %2\\t\\t%@ (*add si llK OK) + SUB%?\\t%0, %1, #%n2\\t\\t%@ (*add si llP OK)" + [(set_attr "type" "fast,fast,fast,fast,fast,fast,fast,fast") + (set_attr "cond" "no")]) + +(define_insn_and_split"*adds_si_neg__rr" + [(set (reg: CC_REG) + (compare:CCZNC + (match_operand:SI 1 "metag_datareg_op" "e, f, e, f") + (neg:SI (match_operand:SI 2 "metag_reg_nofloat_op" "be,bf,be,bf")))) + (clobber (match_scratch:SI 0 "=e, f, r, r"))] + "TARGET_METAC_1_1" + "#" + "&& reload_completed" + [(parallel + [(set (reg: CC_REG) + (compare: + (plus:SI (match_dup 1) + (match_dup 2)) + (const_int 0))) + (set (match_dup 0) + (plus:SI (match_dup 1) + (match_dup 2)))])] + "" + [(set_attr "type" "fast") + (set_attr "ccstate" "set")]) + +;; register + register|immediate ops that set the flags +(define_insn "*adds__si_rrr" + [(set (reg: CC_REG) + (compare:CCZNC + (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "%e,f,e,f") + (match_operand:SI 2 "metag_regnofrm_op" "e,f,e,f")) + (const_int 0))) + (set (match_operand:SI 0 "metag_register_op" "=e,f,r,r") + (plus:SI (match_dup 1) + (match_dup 2)))] + "!TARGET_METAC_1_1" + "ADDS\\t%0, %1, %2\\t%@ (*adds si rrr OK)" + [(set_attr "type" "fast,fast,slow,slow") + (set_attr "ccstate" "set,set,set,set")]) + +;; register + register|immediate ops that set the flags - v1.1 case +(define_insn "*adds__si_rrr_1_1" + [(set (reg: CC_REG) + (compare:CCZNC + (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "%e, f, e, f") + (match_operand:SI 2 "metag_regnofrm_op" "be,bf,be,bf")) + (const_int 0))) + (set (match_operand:SI 0 "metag_register_op" "=e, f, r, r") + (plus:SI (match_dup 1) + (match_dup 2)))] + "TARGET_METAC_1_1" + "ADDS\\t%0, %1, %2\\t%@ (*adds si rrr OK)" + [(set_attr "type" "fast,fast,slow,slow") + (set_attr "ccstate" "set,set,set,set")]) + +(define_insn_and_split "*adds_si_r__symglobal_1_1" + [(set (reg: CC_REG) + (compare:CCZNC + (match_operand:SI 1 "metag_symglobal_op" "") + (const_int 0))) + (set (match_operand:SI 0 "metag_datareg_op" "=d") + (match_dup 1))] + "TARGET_METAC_1_1" + "#" + "&& reload_completed" + [(set (match_dup 0) + (high:SI (match_dup 1))) + (parallel + [(set (reg: CC_REG) + (compare: + (lo_sum:SI (match_dup 0) + (match_dup 1)) + (const_int 0))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (match_dup 1)))])] + "" + [(set_attr "type" "fast") + (set_attr "ccstate" "set")]) + +(define_insn "*adds__si_txrpt_ri" + [(set (reg: CC_REG) + (compare:CCZNC + (plus:SI (match_operand:SI 1 "metag_datareg_op" "%d, d") + (match_operand:SI 2 "metag_smallint_op" "K, P")) + (const_int 0))) + (set (match_operand:SI 0 "metag_txrpt_op" "=Wx,Wx") + (plus:SI (match_dup 1) + (match_dup 2)))] + "reload_completed" + "@ + ADDS\\t%0, %1, #%2 + SUBS\\t%0, %1, #%n2" + [(set_attr "type" "fast,fast") + (set_attr "ccstate" "set,set")]) + +(define_insn "*adds__si_rri" + [(set (reg: CC_REG) + (compare:CCZNC + (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "%e,e,f,f,d,d,0,0,0, 0") + (match_operand:SI 2 "const_int_operand" "K,P,K,P,K,P,I,J,O3,i")) + (const_int 0))) + (set (match_operand:SI 0 "metag_register_op" "=e,e,f,f,r,r,d,d,d, d") + (plus:SI (match_dup 1) + (match_dup 2)))] + "" + "@ + ADDS\\t%0, %1, %2\\t\\t%@ (*adds si eeK OK) + SUBS\\t%0, %1, #%n2\\t\\t%@ (*adds si eeP OK) + ADDS\\t%0, %1, %2\\t\\t%@ (*adds si ffK OK) + SUBS\\t%0, %1, #%n2\\t\\t%@ (*adds si ffP OK) + ADDS\\t%0, %1, %2\\t\\t%@ (*adds si rdK OK) + SUBS\\t%0, %1, #%n2\\t\\t%@ (*adds si rdP OK) + ADDS\\t%0, %1, %2\\t%@ (*adds si d0I OK) + ADDST\\t%0, %1, #HI(%c2)\\t%@ (*adds si d0J OK) + ADDS\\t%0, %1, #LO(%c2)\\t%@ (*adds si d0O3 OK) + #" + [(set_attr "type" "fast,fast,fast,fast,slow,slow,fast,fast,fast,two") + (set_attr "ccstate" "set,set,set,set,set,set,set,set,set,fastset")]) + +;; Split the above insn if it needs more than one insn +(define_split + [(set (reg: CC_REG) + (compare:CCZNC + (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "") + (match_operand:SI 2 "const_int_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "metag_reg_nofloat_op" "") + (plus:SI (match_dup 1) + (match_dup 2)))] + "reload_completed + && REGNO (operands[0]) == REGNO (operands[1]) && !METAG_CONST_OK_FOR_LETTERS_KPIJO3 (operands[2])" + [(set (match_dup 0) + (plus:SI (match_dup 1) + (match_dup 3))) + (parallel + [(set (reg: CC_REG) + (compare: + (plus:SI (match_dup 0) + (match_dup 4)) + (const_int 0))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_dup 4)))])] + { + HOST_WIDE_INT value = INTVAL (operands[2]); + HOST_WIDE_INT ival; + + ival = trunc_int_for_mode (value & 0xFFFF0000, SImode); + operands[3] = GEN_INT (ival); + + ival = trunc_int_for_mode (value & 0x0000FFFF, SImode); + operands[4] = GEN_INT (ival); + } +) + +;; register + register|immediate ops that set the flags using a scratch +(define_insn "*tadds__si_rrr" + [(set (reg: CC_REG) + (compare:CCZNC + (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "%e,f,e,f") + (match_operand:SI 2 "metag_regnofrm_op" "e,f,e,f")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=e,f,r,r"))] + "!TARGET_METAC_1_1" + "ADDS\\t%0, %1, %2\\t%@ (*tadd si rrr OK)" + [(set_attr "type" "fast,fast,slow,slow") + (set_attr "ccstate" "set,set,set,set")]) + +;; register + register|immediate ops that set the flags using a scratch - v1.1 +(define_insn "*tadds__si_rrr_1_1" + [(set (reg: CC_REG) + (compare:CCZNC + (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "%e, f, e, f") + (match_operand:SI 2 "metag_regnofrm_op" "be,bf,be,bf")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=e, f, r, r"))] + "TARGET_METAC_1_1" + "ADDS\\t%0, %1, %2\\t%@ (*tadd si rrb OK)" + [(set_attr "type" "fast,fast,slow,slow") + (set_attr "ccstate" "set,set,set,set")]) + +(define_insn "*tadds_rr_cc_noov_address_1_1" + [(set (reg: CC_REG) + (compare:CCZNC + (lo_sum:SI (match_operand:SI 1 "metag_datareg_op" "0") + (match_operand:SI 2 "code_address" "")) + (const_int 0))) + (set (match_operand:SI 0 "metag_datareg_op" "=d") + (lo_sum:SI (match_dup 1) + (match_dup 2)))] + "TARGET_METAC_1_1" + "ADDS\\t%0, %1, #LO(%c2)" + [(set_attr "type" "fast") + (set_attr "ccstate" "set")]) + +(define_insn_and_split "*tadds_si_cc_noov_address" + [(set (reg: CC_REG) + (compare:CCZNC + (match_operand:SI 1 "code_address" "") + (const_int 0))) + (clobber (match_scratch:SI 0 "=d"))] + "TARGET_METAC_1_1 && 1" + "#" + "&& reload_completed" + [(set (match_dup 0) + (high:SI (match_dup 1))) + (parallel + [(set (reg: CC_REG) + (compare:CCZNC + (lo_sum:SI (match_dup 0) + (match_dup 1)) + (const_int 0))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (match_dup 1)))])] + "" + [(set_attr "type" "two") + (set_attr "ccstate" "set")]) + +(define_insn "*tadds_rr__symglobal_1_1" + [(set (reg: CC_REG) + (compare:CCZNC + (lo_sum:SI (match_operand:SI 1 "metag_datareg_op" "0") + (match_operand:SI 2 "metag_symglobal_op" "")) + (const_int 0))) + (set (match_operand:SI 0 "metag_datareg_op" "=d") + (lo_sum:SI (match_dup 1) + (match_dup 2)))] + "TARGET_METAC_1_1" + "ADDS\\t%0, %1, #LO(%c2)" + [(set_attr "type" "fast") + (set_attr "ccstate" "set")]) + +(define_insn_and_split "*tadds__si_symglobal_1_1" + [(set (reg: CC_REG) + (compare:CCZNC + (match_operand:SI 1 "metag_symglobal_op" "") + (const_int 0))) + (clobber (match_scratch:SI 0 "=d"))] + "TARGET_METAC_1_1 && 0" + "#" + "&& reload_completed" + [(set (match_dup 0) + (high:SI (match_dup 1))) + (parallel + [(set (reg: CC_REG) + (compare:CCZNC + (lo_sum:SI (match_dup 0) + (match_dup 1)) + (const_int 0))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (match_dup 1)))])] + "" + [(set_attr "type" "fast") + (set_attr "ccstate" "set")]) + +(define_insn "*tadds_si_cc_rri" + [(set (reg: CC_REG) + (compare:CCZNC + (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "%e,e,f,f,d,d,0,0,0, 0") + (match_operand:SI 2 "const_int_operand" "K,P,K,P,K,P,I,J,O3,i")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=e,e,f,f,r,r,d,d,d, d"))] + "" + "@ + ADDS\\t%0, %1, %2\\t\\t%@ (*tadd si eeK OK) + SUBS\\t%0, %1, #%n2\\t\\t%@ (*tadd si eeP OK) + ADDS\\t%0, %1, %2\\t\\t%@ (*tadd si ffK OK) + SUBS\\t%0, %1, #%n2\\t\\t%@ (*tadd si ffP OK) + ADDS\\t%0, %1, %2\\t\\t%@ (*tadd si rdK OK) + SUBS\\t%0, %1, #%n2\\t\\t%@ (*tadd si rdP OK) + ADDS\\t%0, %1, %2\\t%@ (*tadd si d0I OK) + ADDST\\t%0, %1, #HI(%c2)\\t%@ (*tadd si d0J OK) + ADDS\\t%0, %1, #LO(%c2)\\t%@ (*tadd si d0O3 OK) + #" + [(set_attr "type" "fast,fast,fast,fast,slow,slow,fast,fast,fast,two") + (set_attr "ccstate" "set,set,set,set,set,set,set,set,set,fastset")]) + +;; Split the above insn if it needs more that one insn. +(define_split + [(set (reg: CC_REG) + (compare:CCZNC + (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "") + (match_operand:SI 2 "const_int_operand" "")) + (const_int 0))) + (clobber (match_scratch:SI 0 ""))] + "reload_completed + && REGNO (operands[0]) == REGNO (operands[1]) && !METAG_CONST_OK_FOR_LETTERS_KPIJO3 (operands[2])" + [(set (match_dup 0) + (plus:SI (match_dup 1) + (match_dup 3))) + (parallel + [(set (reg: CC_REG) + (compare: + (plus:SI (match_dup 0) + (match_dup 4)) + (const_int 0))) + (clobber (match_dup 0))])] + { + HOST_WIDE_INT value = INTVAL (operands[2]); + HOST_WIDE_INT ival; + + ival = trunc_int_for_mode (value & 0xFFFF0000, SImode); + operands[3] = GEN_INT (ival); + + ival = trunc_int_for_mode (value & 0x0000FFFF, SImode); + operands[4] = GEN_INT (ival); + } +) + +;; subtract instructions + +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +;; subdi3 expander ;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +(define_expand "subdi3" + [(parallel + [(set (match_operand:DI 0 "metag_reg_nofloat_op" "") + (minus:DI (match_operand:DI 1 "metag_reg_nofloat_op" "") + (match_operand:DI 2 "metag_reg_nofloat_op" ""))) + (clobber (reg:CC CC_REG))])] + "" + "") + +(define_insn "*subdi3_dsp" + [(set (match_operand:DI 0 "metag_datareg_op" "=d") + (minus:DI (match_operand:DI 1 "metag_datareg_op" "d") + (match_operand:DI 2 "metag_datareg_op" "d"))) + (clobber (reg:CC CC_REG))] + "TARGET_DSP" + "DL\\tSUBS\\t%0, %1, %2\\t%@ (*SUB\\t%t0, %t1, %t2)\;SUBCS\\t%t0, %t0, #1" + [(set_attr "type" "two") + (set_attr "ccstate" "ccx")]) + +(define_insn_and_split "*subdi3" + [(set (match_operand:DI 0 "metag_datareg_op" "=d") + (minus:DI (match_operand:DI 1 "metag_datareg_op" "d") + (match_operand:DI 2 "metag_datareg_op" "d"))) + (clobber (reg:CC CC_REG))] + "" + "#" + "SPLIT_EARLY" + [(parallel + [(set (reg:CC_NOOV CC_REG) + (compare:CC_NOOV + (minus:SI (match_dup 5) + (match_dup 7)) + (const_int 0))) + (set (match_dup 3) + (minus:SI (match_dup 5) + (match_dup 7)))]) + (set (match_dup 4) + (minus:SI (match_dup 6) + (match_dup 8))) + (set (match_dup 4) + (if_then_else:SI (ltu (reg:CC_NOOV CC_REG) + (const_int 0)) + (plus:SI (match_dup 4) + (const_int -1)) + (match_dup 4)))] + { + if (reload_completed) + { + operands[3] = gen_rtx_REG (SImode, REGNO (operands[0])); + operands[4] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + + operands[5] = gen_rtx_REG (SImode, REGNO (operands[1])); + operands[6] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1); + + operands[7] = gen_rtx_REG (SImode, REGNO (operands[2])); + operands[8] = gen_rtx_REG (SImode, REGNO (operands[2]) + 1); + } + else + { + operands[3] = gen_rtx_SUBREG (SImode, operands[0], 0); + operands[4] = gen_rtx_SUBREG (SImode, operands[0], UNITS_PER_WORD); + + operands[5] = gen_rtx_SUBREG (SImode, operands[1], 0); + operands[6] = gen_rtx_SUBREG (SImode, operands[1], UNITS_PER_WORD); + + operands[7] = gen_rtx_SUBREG (SImode, operands[2], 0); + operands[8] = gen_rtx_SUBREG (SImode, operands[2], UNITS_PER_WORD); + } + } + [(set_attr "type" "three") + (set_attr "ccstate" "ccx")]) + +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +;; subsi3 is made up of many parts.. ;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +(define_expand "subsi3" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "") + (minus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "") + (match_operand:SI 2 "metag_reg_nofloat_op" "")))] + "" + { + if (!reload_completed + && !reload_in_progress + && REG_P (operands[2])) + { + if (metag_frame_related_rtx (operands[1])) + { + /* Ensure reg-reg adds do not combine regs that may be eliminated */ + rtx reg = gen_reg_rtx (SImode); + + emit_move_insn (reg, operands[1]); + operands[1] = force_reg (SImode, reg); + } + else if (metag_frame_related_rtx (operands[2])) + { + /* Ensure reg-reg adds do not combine regs that may be eliminated */ + rtx reg = gen_reg_rtx (SImode); + + emit_move_insn (reg, operands[2]); + operands[2] = force_reg (SImode, reg); + } + } + } +) + +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +;; and these are the subsi3 parts.. ;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; + +;; register - register ops +(define_insn "*sub_si_rrr" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=e,f,h,l,da,da,da,da") + (minus:SI (match_operand:SI 1 "metag_regnofrm_op" "e,f,h,l,e, f, h, l") + (match_operand:SI 2 "metag_regnofrm_op" "e,f,h,l,e, f, h, l")))] + "!TARGET_METAC_1_1" + "SUB%?\\t%0, %1, %2\\t%@ (*sub si rrr OK)" + [(set_attr "type" "fast,fast,fast,fast,slow,slow,slow,slow") + (set_attr "cond" "yes,yes,yes,yes,yes,yes,yes,yes") + (set_attr "predicable" "yes")]) + +;; register - register ops - v1.1 case +(define_insn "*sub_si_rrr_1_1" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=e, f, h, l, da,da,da,da") + (minus:SI (match_operand:SI 1 "metag_regnofrm_op" "e, f, h, l, e, f, h, l") + (match_operand:SI 2 "metag_regnofrm_op" "be,bf,bh,bl,be,bf,bh,bl")))] + "TARGET_METAC_1_1 && !TARGET_MINIM_CORE" + "SUB%?\\t%0, %1, %2\\t%@ (*sub si rrb OK)" + [(set_attr "type" "fast,fast,fast,fast,slow,slow,slow,slow") + (set_attr "cond" "yes,yes,yes,yes,yes,yes,yes,yes") + (set_attr "predicable" "yes")]) + +;; register - register ops - minim case +(define_insn "*sub_si_rrr_minim" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=e,!e, f,!f, h,!h, l,!l, da,!da, da,!da, da,!da, da,!da") + (minus:SI (match_operand:SI 1 "metag_regnofrm_op" "e, e, f, f, h, h, l, l, e, e, f, f, h, h, l, l") + (match_operand:SI 2 "metag_regnofrm_op" "e, be,f, bf,h, bh,l, bl,e, be, f, bf, h, bh, l, bl")))] + "TARGET_METAC_1_1 && TARGET_MINIM_CORE" + "SUB%?\\t%0, %1, %2\\t%@ (*sub si rrb OK)" + [(set_attr "type" "fast,fast,fast,fast,fast,fast,fast,fast,slow,slow,slow,slow,slow,slow,slow,slow") + (set_attr "cond" "yes") + (set_attr "predicable" "yes")]) + +;; Seperate stack frame related register-register subs +(define_insn "*sub_si_index_frame" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=h,da,!da") + (minus:SI (match_operand:SI 1 "metag_regframe_op" "h,h, h") + (match_operand:SI 2 "metag_regnofrm_op" "h,h, bh")))] + "!TARGET_METAC_1_1" + "SUB%?\\t%0, %1, %2\\t%@ (*sub si rfrmh OK)" + [(set_attr "type" "fast,slow,three") + (set_attr "cond" "yes,yes,yes") + (set_attr "predicable" "yes")]) + +;; Subs are not commutative so second case required +(define_insn "*sub_si_index_frame2" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=h,da,!da") + (minus:SI (match_operand:SI 1 "metag_regnofrm_op" "h,h, h") + (match_operand:SI 2 "metag_regframe_op" "h,h, bh")))] + "!TARGET_METAC_1_1" + "SUB%?\\t%0, %1, %2\\t%@ (*sub si rhfrm OK)" + [(set_attr "type" "fast,slow,three") + (set_attr "cond" "yes,yes,yes") + (set_attr "predicable" "yes")]) + +;; Seperate stack frame related register-register subs - v1.1 case +(define_insn "*sub_si_index_frame_1_1" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=h, da") + (minus:SI (match_operand:SI 1 "metag_regframe_op" "h, h") + (match_operand:SI 2 "metag_regnofrm_op" "bh,bh")))] + "TARGET_METAC_1_1 && !TARGET_MINIM_CORE" + "SUB%?\\t%0, %1, %2\\t%@ (*sub si rfrmb OK)" + [(set_attr "type" "fast,slow") + (set_attr "cond" "yes,yes") + (set_attr "predicable" "yes")]) + +;; Seperate stack frame related register-register subs - minim case +(define_insn "*sub_si_index_frame_minim" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=h,!h, da,!da") + (minus:SI (match_operand:SI 1 "metag_regframe_op" "h, h, h, h") + (match_operand:SI 2 "metag_regnofrm_op" "h, bh,h, bh")))] + "TARGET_METAC_1_1 && TARGET_MINIM_CORE" + "SUB%?\\t%0, %1, %2\\t%@ (*sub si rfrmb OK)" + [(set_attr "type" "fast,fast,slow,slow") + (set_attr "cond" "yes") + (set_attr "predicable" "yes")]) + +;; Subs are not commutative so second case required - v1.1 case +(define_insn "*sub_si_index_frame2_1_1" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=h, da") + (minus:SI (match_operand:SI 1 "metag_regnofrm_op" "h, h") + (match_operand:SI 2 "metag_regframe_op" "bh,bh")))] + "TARGET_METAC_1_1 && !TARGET_MINIM_CORE" + "SUB%?\\t%0, %1, %2\\t%@ (*sub si rbfrm OK)" + [(set_attr "type" "fast,slow") + (set_attr "cond" "yes,yes") + (set_attr "predicable" "yes")]) + +;; Subs are not commutative so second case required - minim case +(define_insn "*sub_si_index_frame2_minim" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=h,!h, da,!da") + (minus:SI (match_operand:SI 1 "metag_regnofrm_op" "h, h, h, h") + (match_operand:SI 2 "metag_regframe_op" "h, bh,h, bh")))] + "TARGET_METAC_1_1 && TARGET_MINIM_CORE" + "SUB%?\\t%0, %1, %2\\t%@ (*sub si rbfrm OK)" + [(set_attr "type" "fast,fast,slow,slow") + (set_attr "cond" "yes") + (set_attr "predicable" "yes")]) + +;; spill_frame - cannot really sub frame value to something else +(define_split + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "") + (minus:SI (match_operand:SI 1 "metag_regframe_op" "") + (match_operand:SI 2 "metag_reg_nofloat_op" "")))] + "!TARGET_METAC_1_1 + && reload_completed + && METAG_REGNO_REG_CLASS (REGNO (operands[2])) != A0_REGS" + [(set (match_dup 3) + (match_dup 2)) + (set (match_dup 0) + (minus:SI (match_dup 1) + (match_dup 3)))] + { + gcc_assert (A0_SCRATCH != INVALID_REGNUM && fixed_regs[A0_SCRATCH]); + operands[3] = gen_rtx_REG (SImode, A0_SCRATCH); + } +) + +(define_split + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "") + (minus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "") + (match_operand:SI 2 "metag_regframe_op" "")))] + "!TARGET_METAC_1_1 + && reload_completed + && METAG_REGNO_REG_CLASS (REGNO (operands[1])) != A0_REGS" + [(set (match_dup 3) + (match_dup 1)) + (set (match_dup 0) + (minus:SI (match_dup 3) + (match_dup 2)))] + { + gcc_assert (A0_SCRATCH != INVALID_REGNUM && fixed_regs[A0_SCRATCH]); + operands[3] = gen_rtx_REG (SImode, A0_SCRATCH); + } +) + +;; register - register|immediate ops that set the flags +(define_insn "*subs__si_rrr" + [(set (reg: CC_REG) + (compare:CCZNC + (minus:SI (match_operand:SI 1 "metag_datareg_op" "e,f,e,f") + (match_operand:SI 2 "metag_datareg_op" "e,f,e,f")) + (const_int 0))) + (set (match_operand:SI 0 "metag_register_op" "=e,f,r,r") + (minus:SI (match_dup 1) + (match_dup 2)))] + "!TARGET_METAC_1_1" + "SUBS\\t%0, %1, %2\\t%@ (*subs si rrr OK)" + [(set_attr "type" "fast,fast,slow,slow") + (set_attr "ccstate" "set,set,set,set")]) + +;; register - register|immediate ops that set the flags - v1.1 case +(define_insn "*subs__si_rrr_1_1" + [(set (reg: CC_REG) + (compare:CCZNC + (minus:SI (match_operand:SI 1 "metag_datareg_op" "e, f, e, f") + (match_operand:SI 2 "metag_reg_nofloat_op" "be,bf,be,bf")) + (const_int 0))) + (set (match_operand:SI 0 "metag_register_op" "=e, f, r, r") + (minus:SI (match_dup 1) + (match_dup 2)))] + "TARGET_METAC_1_1" + "SUBS\\t%0, %1, %2\\t%@ (*subs si rrb OK)" + [(set_attr "type" "fast,fast,slow,slow") + (set_attr "ccstate" "set,set,set,set") + (set_attr "o2rhint" "op2op1")]) + +;; register - register|immediate ops that set the flags only -> compares +(define_insn "*tsub__si_rrr" + [(set (reg: CC_REG) + (compare:CCZNC + (minus:SI (match_operand:SI 0 "metag_datareg_op" "e,f") + (match_operand:SI 1 "metag_datareg_op" "e,f")) + (const_int 0)))] + "!TARGET_METAC_1_1" + "CMP\\t%0, %1\\t%@ (*tsub si dd OK)" + [(set_attr "type" "fast,fast") + (set_attr "ccstate" "set,set")]) + +;; register - register ops that set the flags only -> compares - v1.1 case +(define_insn "*tsub__si_rrr_1_1" + [(set (reg: CC_REG) + (compare:CCZNC + (minus:SI (match_operand:SI 0 "metag_datareg_op" "e, f") + (match_operand:SI 1 "metag_datareg_op" "be,bf")) + (const_int 0)))] + "TARGET_METAC_1_1" + "CMP\\t%0, %1\\t%@ (*tsub si db OK)" + [(set_attr "type" "fast,fast") + (set_attr "ccstate" "set,set") + (set_attr "o2rhint" "op1op0")]) + +;; signed multiply instructions + +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +;; mulsi3 is made up of many parts.. ;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +(define_expand "mulsi3" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "") + (mult:SI (match_operand:SI 1 "metag_reg_nofloat_op" "") + (match_operand:SI 2 "metag_regorint_op" "")))] + "" + { + if (metag_frame_related_rtx (operands[2])) + { + /* Put the magic frame registers first */ + rtx temp = operands[1]; + + operands[1] = operands[2]; + operands[2] = temp; + } + + if (!TARGET_METAC_1_1 && !reload_completed && !reload_in_progress) + { + if (CONST_INT_P (operands[2]) + && metag_frame_related_rtx (operands[1])) + { + /* Ensure reg*const do not combine reg that may be eliminated */ + rtx reg = gen_reg_rtx (SImode); + + emit_move_insn (reg, operands[1]); + operands[1] = force_reg (SImode, reg); + } + } + + if (!CONST_INT_P (operands[2]) + || ( !satisfies_constraint_I (operands[2]) + && !satisfies_constraint_J (operands[2]) + && !satisfies_constraint_K (operands[2]) + && !satisfies_constraint_P (operands[2]) + && !satisfies_constraint_O3(operands[2]))) + { + /* All except reg = (reg * bigconst) can be done quickly */ + operands[2] = force_reg (SImode, operands[2]); + } + } +) + +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +;; and these are the mulsi3 parts.. ;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; + +;; register * register ops - v1.0 bug disables MULD Dn.x, Dm.x, Dm.y +(define_insn "*mul_si_rrr" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=e,f,a,a") + (mult:SI (match_operand:SI 1 "metag_reg_nofloat_op" "%e,f,e,f") + (match_operand:SI 2 "metag_reg_nofloat_op" "e,f,e,f")))] + "!TARGET_METAC_1_1" + "MULD\\t%0, %1, %2\\t%@ (*mul si rrr OK)" + [(set_attr "type" "mult,mult,slowslow,slowslow")]) + +;; register * register ops v1.1 +(define_insn "*mul_si_rrr_1_1" + [(set (match_operand:SI 0 "metag_register_op" "=e, f, r, r") + (mult:SI (match_operand:SI 1 "metag_reg_nofloat_op" "%e, f, e, f") + (match_operand:SI 2 "metag_reg_nofloat_op" "be,bf,be,bf")))] + "TARGET_METAC_1_1 && !TARGET_MINIM_CORE" + "MULD\\t%0, %1, %2\\t%@ (*mul si rrr OK)" + [(set_attr "type" "mult,mult,slowslow,slowslow") + (set_attr "o2rhint" "op2op1")]) + +;; register * register ops minim +(define_insn "*mul_si_rrr_minim" + [(set (match_operand:SI 0 "metag_register_op" "=e,!e, f,!f, r,!r, r,!r") + (mult:SI (match_operand:SI 1 "metag_reg_nofloat_op" "%e, e, f, f, e, e, f, f") + (match_operand:SI 2 "metag_reg_nofloat_op" "e, be,f, bf,e, be,f, bf")))] + "TARGET_METAC_1_1 && TARGET_MINIM_CORE" + "MULD\\t%0, %1, %2\\t%@ (*mul si rrr OK)" + [(set_attr "type" "mult,mult,mult,mult,slowslow,slowslow,slowslow,slowslow") + (set_attr "o2rhint" "op2op1")]) + +;; register * immediate ops - v1.0 bug disables MULD Dn.x, Dm.x, #0xnn +(define_insn "*mul_si_rri" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=e,f,d, d,d, a,a,&e,&f") + (mult:SI (match_operand:SI 1 "metag_regnofrm_op" "e,f,0, 0,0, e,f, e, f") + (match_operand:SI 2 "metag_int_operand" "K,K,IP,J,O3,K,K, i, i")))] + "!TARGET_METAC_1_1" + "@ + MULD\\t%0, %1, %2\\t\\t%@ (*mul si eeK OK) + MULD\\t%0, %1, %2\\t\\t%@ (*mul si ffK OK) + MULD\\t%0, %1, %2\\t%@ (*mul si d0I OK) + MULDT\\t%0, %1, #HI(%c2)\\t%@ (*mul si d0J OK) + MULD\\t%0, %1, #LO(%c2)\\t%@ (*mul si d0O3 OK) + MULD\\t%0, %1, %2\\t\\t%@ (*mul si reK OK) + MULD\\t%0, %1, %2\\t\\t%@ (*mul si rfK OK) + # + #" + [(set_attr "type" "mult,mult,mult,mult,mult,slowslow,slowslow,four,four")]) + +;; Split the above insn if it needs more than one insn +(define_split + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "") + (mult:SI (match_operand:SI 1 "metag_reg_nofloat_op" "") + (match_operand:SI 2 "metag_int_operand" "")))] + "!TARGET_METAC_1_1 + && reload_completed + && REGNO (operands[0]) == REGNO (operands[1]) && !METAG_CONST_OK_FOR_LETTERS_KPIJO3 (operands[2])" + [(set (match_dup 0) + (match_dup 3)) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_dup 4))) + (set (match_dup 0) + (mult:SI (match_dup 1) + (match_dup 0)))] + { + HOST_WIDE_INT value = INTVAL (operands[2]); + HOST_WIDE_INT ival; + + ival = trunc_int_for_mode (value & 0xFFFF0000, SImode); + operands[3] = GEN_INT (ival); + + ival = trunc_int_for_mode (value & 0x0000FFFF, SImode); + operands[4] = GEN_INT (ival); + } +) + +;; register * immediate ops +(define_insn "*mul_si_rri_1_1" + [(set (match_operand:SI 0 "metag_register_op" "=r,d, d,d, &e,&f") + (mult:SI (match_operand:SI 1 "metag_reg_nofloat_op" "d,0, 0,0, e, f") + (match_operand:SI 2 "metag_int_operand" "K,IP,J,O3, i, i")))] + "TARGET_METAC_1_1" + "@ + MULD\\t%0, %1, %2\\t\\t%@ (*mul si rdK OK) + MULD\\t%0, %1, %2\\t%@ (*mul si d0I OK) + MULDT\\t%0, %1, #HI(%c2)\\t%@ (*mul si d0J OK) + MULD \\t%0, %1, #LO(%c2)\\t%@ (*mul si d0J OK) + # + #" + [(set_attr "type" "slowslow,mult,mult,mult,four,four")]) + +;; Split the above insn if it needs more than one insn +(define_split + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "") + (mult:SI (match_operand:SI 1 "metag_reg_nofloat_op" "") + (match_operand:SI 2 "metag_int_operand" "")))] + "TARGET_METAC_1_1 + && reload_completed + && REGNO (operands[0]) != REGNO (operands[1]) && !satisfies_constraint_K (operands[2])" + [(set (match_dup 0) + (match_dup 3)) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_dup 4))) + (set (match_dup 0) + (mult:SI (match_dup 1) + (match_dup 0)))] + { + HOST_WIDE_INT value = INTVAL (operands[2]); + HOST_WIDE_INT ival; + + ival = trunc_int_for_mode (value & 0xFFFF0000, SImode); + operands[3] = GEN_INT (ival); + + ival = trunc_int_for_mode (value & 0x0000FFFF, SImode); + operands[4] = GEN_INT (ival); + } +) + +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +;; umulhisi3 is made up of many parts.. ;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +(define_expand "umulhisi3" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "") + (mult:SI (zero_extend:SI (match_operand:HI 1 "metag_reg_nofloat_op" "")) + (zero_extend:SI (match_operand:HI 2 "metag_regorint_op" ""))))] + "" + { + if (CONST_INT_P (operands[2])) + { + /* Mask off the unsigned immediate to zero extend */ + HOST_WIDE_INT ival = INTVAL (operands[2]) & GET_MODE_MASK (HImode); + + emit_move_insn (operands[0], + gen_rtx_MULT (SImode, + gen_rtx_ZERO_EXTEND (SImode, operands[1]), + GEN_INT (ival))); + DONE; + } + } +) + +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +;; and these are the umulhisi3 parts.. ;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; + +;; register * register ops +(define_insn "*umul_hisi_rrr" + [(set (match_operand:SI 0 "metag_register_op" "=e,f,r,r") + (mult:SI (zero_extend:SI + (match_operand:HI 1 "metag_reg_nofloat_op" "%e,f,e,f")) + (zero_extend:SI + (match_operand:HI 2 "metag_reg_nofloat_op" "e,f,e,f"))))] + "!TARGET_METAC_1_1" + "MULW%?\\t%0, %1, %2\\t%@ (*umul hisi rrr OK)" + [(set_attr "type" "fast,fast,slow,slow") + (set_attr "cond" "yes,yes,yes,yes") + (set_attr "predicable" "yes")]) + +;; register * register ops - v1.1 case +(define_insn "*umul_hisi_rrr_1_1" + [(set (match_operand:SI 0 "metag_register_op" "=e, f, r, r") + (mult:SI (zero_extend:SI + (match_operand:HI 1 "metag_reg_nofloat_op" "%e, f, e, f")) + (zero_extend:SI + (match_operand:HI 2 "metag_reg_nofloat_op" "be,bf,be,bf"))))] + "TARGET_METAC_1_1 && !TARGET_MINIM_CORE" + "MULW%?\\t%0, %1, %2\\t%@ (*umul hisi rrr OK)" + [(set_attr "type" "fast,fast,slow,slow") + (set_attr "cond" "yes,yes,yes,yes") + (set_attr "predicable" "yes") + (set_attr "o2rhint" "op2op1")]) + +;; register * register ops - minim case +(define_insn "*umul_hisi_rrr_minim" + [(set (match_operand:SI 0 "metag_register_op" "=e,!e, f,!f, r,!r, r,!r") + (mult:SI (zero_extend:SI + (match_operand:HI 1 "metag_reg_nofloat_op" "%e, e, f, f, e, e, f, f")) + (zero_extend:SI + (match_operand:HI 2 "metag_reg_nofloat_op" "e, be,f, bf,e, be,f, bf"))))] + "TARGET_METAC_1_1 && TARGET_MINIM_CORE" + "MULW%?\\t%0, %1, %2\\t%@ (*umul hisi rrr OK)" + [(set_attr "type" "fast,fast,fast,fast,slow,slow,slow,slow") + (set_attr "cond" "yes") + (set_attr "predicable" "yes") + (set_attr "o2rhint" "op2op1")]) + +;; register * immediate ops +(define_insn "*umul_hisi_rri" + [(set (match_operand:SI 0 "metag_register_op" "=e,f,r,d") + (mult:SI (zero_extend:SI + (match_operand:HI 1 "metag_reg_nofloat_op" "e,f,d,0")) + (match_operand:SI 2 "metag_int_operand" "K,K,K,IP")))] + "" + "@ + MULW%?\\t%0, %1, %2\\t\\t%@ (*umul hisi eeK OK) + MULW%?\\t%0, %1, %2\\t\\t%@ (*umul hisi ffK OK) + MULW\\t%0, %1, %2\\t\\t%@ (*umul hisi rdK OK) + MULW\\t%0, %1, %2\\t%@ (*umul hisi d0I OK)" + [(set_attr "type" "fast,fast,slow,fast") + (set_attr "cond" "yes,yes,no,no")]) + +;; conditional version for specific cases of umul_hisi_rri +(define_insn "*cond__umul_hisi_rri" + [(cond_exec + (match_operator 3 "comparison_operator" + [(match_operand:CCALL 4 "metag__reg" "") + (const_int 0)]) + (set (match_operand:SI 0 "metag_datareg_op" "=e,f") + (mult:SI (zero_extend:SI + (match_operand:HI 1 "metag_datareg_op" "e,f")) + (match_operand:SI 2 "metag_K_operand" "K,K"))))] + "reload_completed + && metag_same_regclass_p (operands[0], operands[1])" + "@ + MULW%?\\t%0, %1, %2\\t\\t%@ (*umul hisi eeK OK) + MULW%?\\t%0, %1, %2\\t\\t%@ (*umul hisi ffK OK)" + [(set_attr "type" "fast") + (set_attr "cond" "no")]) + +;; signed divide instructions + +; we don't have one.. + +;; signed modulus instruction + +; we don't have one.. + +;; unsigned divide instruction + +; we don't have one.. + +;; logical-and instructions + +(define_insn "*anddi3_dsp" + [(set (match_operand:DI 0 "metag_register_op" "=d") + (and:DI (match_dup 0) + (match_operand:DI 1 "metag_16bit_op" "KIP")))] + "TARGET_DSP" + "DL\\tAND\\t%0, %0, %1\\t%@ (*AND\\t%t0, %t0, %1)" + [(set_attr "type" "fast")]) + +(define_insn "*anddi3" + [(set (match_operand:DI 0 "metag_register_op" "=d") + (and:DI (match_operand:DI 1 "metag_register_op" "d") + (match_operand:DI 2 "metag_register_op" "d")))] + "TARGET_DSP" + "DL\\tAND\\t%0, %1, %2\\t%@ (*AND\\t%t0, %t1, %t2)" + [(set_attr "type" "fast")]) + +(define_expand "anddi3" + [(set (match_operand:DI 0 "metag_register_op" "=d") + (and:DI (match_operand:DI 1 "metag_register_op" "d") + (match_operand:DI 2 "metag_register_op" "d")))] + "" + { + if (!TARGET_DSP) + FAIL; + } + ) + + +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +;; andsi3 is made up of many parts.. ;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +(define_expand "andsi3" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "") + (and:SI (match_operand:SI 1 "metag_reg_nofloat_op" "") + (match_operand:SI 2 "metag_regorint_op" "")))] + "" + { + if (CONST_INT_P (operands[2]) + && METAG_LETTER_FOR_CONST (operands[2]) == 0) + { + /* Need to use M,N cases to implement op */ + rtx temp = (reload_in_progress || reload_completed) + ? operands[0] : gen_reg_rtx (SImode); + HOST_WIDE_INT value = INTVAL (operands[2]); + HOST_WIDE_INT ival; + + ival = trunc_int_for_mode (value | 0xFFFF0000, SImode); + emit_insn (gen_rtx_SET (VOIDmode, temp, + gen_rtx_AND (SImode, operands[1], + GEN_INT (ival)))); + ival = trunc_int_for_mode (value | 0x0000FFFF, SImode); + emit_insn (gen_rtx_SET (VOIDmode, operands[0], + gen_rtx_AND (SImode, temp, + GEN_INT (ival)))); + DONE; + } + } +) + +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +;; and these are the andsi3 parts.. ;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; + +;; register & register ops +(define_insn "*and_si_rrr" + [(set (match_operand:SI 0 "metag_register_op" "=e,f,r,r") + (and:SI (match_operand:SI 1 "metag_reg_nofloat_op" "%e,f,e,f") + (match_operand:SI 2 "metag_reg_nofloat_op" "e,f,e,f")))] + "!TARGET_METAC_1_1 || TARGET_MTX" + "AND%?\\t%0, %1, %2\\t%@ (*and si rrr OK)" + [(set_attr "type" "fast,fast,slow,slow") + (set_attr "cond" "yes,yes,yes,yes") + (set_attr "predicable" "yes")]) + +;; register & register ops - v1.1 case +(define_insn "*and_si_rrr_1_1" + [(set (match_operand:SI 0 "metag_register_op" "=e, f, r, r") + (and:SI (match_operand:SI 1 "metag_reg_nofloat_op" "%e, f, e, f") + (match_operand:SI 2 "metag_reg_nofloat_op" "be,bf,be,bf")))] + "TARGET_METAC_1_1 && !TARGET_MINIM_CORE && !TARGET_MTX" + "AND%?\\t%0, %1, %2\\t%@ (*and si rrr OK)" + [(set_attr "type" "fast,fast,slow,slow") + (set_attr "cond" "yes,yes,yes,yes") + (set_attr "predicable" "yes") + (set_attr "o2rhint" "op2op1")]) + +;; register & register ops - minim case +(define_insn "*and_si_rrr_minim" + [(set (match_operand:SI 0 "metag_register_op" "=e,!e, f,!f, r,!r, r,!r") + (and:SI (match_operand:SI 1 "metag_reg_nofloat_op" "%e, e, f, f, e, e, f, f") + (match_operand:SI 2 "metag_reg_nofloat_op" "e, be,f, bf,e, be,f, bf")))] + "TARGET_METAC_1_1 && TARGET_MINIM_CORE && !TARGET_MTX" + "AND%?\\t%0, %1, %2\\t%@ (*and si rrr OK)" + [(set_attr "type" "fast,fast,fast,fast,slow,slow,slow,slow") + (set_attr "cond" "yes") + (set_attr "predicable" "yes") + (set_attr "o2rhint" "op2op1")]) + +;; register & immediate ops +(define_insn "*and_si_rri" + [(set (match_operand:SI 0 "metag_register_op" "=d, d,d,d,e,f,r") + (and:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0, 0,0,0,e,f,d") + (match_operand:SI 2 "metag_int_operand" "IP,J,M,N,K,K,K")))] + "!TARGET_MINIM_CORE" + "@ + AND\\t%0, %1, %2\\t%@ (*and si r0I OK) + ANDT\\t%0, %1, #HI(%c2)\\t%@ (*and si d0J OK) + ANDMB\\t%0, %1, #LO(%c2)\\t%@ (*and si d0M OK) + ANDMT\\t%0, %1, #HI(%c2)\\t%@ (*and si d0N OK) + AND%?\\t%0, %1, %2\\t\\t%@ (*and si eeK OK) + AND%?\\t%0, %1, %2\\t\\t%@ (*and si ffK OK) + AND\\t%0, %1, %2\\t\\t%@ (*and si rdK OK)" + [(set_attr "type" "fast,fast,fast,fast,fast,fast,slow") + (set_attr "cond" "no,no,no,no,yes,yes,no")]) + +;; register & immediate ops +(define_insn "*and_si_rri" + [(set (match_operand:SI 0 "metag_register_op" "=d, d,d,d,d,!e,!f,!r") + (and:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0, 0,0,0,0, e, f, d") + (match_operand:SI 2 "metag_int_operand" "IP,J,M,N,K, K, K, K")))] + "TARGET_MINIM_CORE" + "@ + AND\\t%0, %1, %2\\t%@ (*and si r0I OK) + ANDT\\t%0, %1, #HI(%c2)\\t%@ (*and si d0J OK) + ANDMB\\t%0, %1, #LO(%c2)\\t%@ (*and si d0M OK) + ANDMT\\t%0, %1, #HI(%c2)\\t%@ (*and si d0N OK) + AND%?\\t%0, %1, %2\\t\\t%@ (*and si d0K OK) + AND%?\\t%0, %1, %2\\t\\t%@ (*and si eeK OK) + AND%?\\t%0, %1, %2\\t\\t%@ (*and si ffK OK) + AND\\t%0, %1, %2\\t\\t%@ (*and si rdK OK)" + [(set_attr "type" "fast,fast,fast,fast,fast,fast,fast,slow") + (set_attr "cond" "no,no,no,no,yes,yes,yes,no")]) + +;; conditional version for specific cases of and_si_rri +(define_insn "*cond__and_si_rri" + [(cond_exec + (match_operator 3 "comparison_operator" + [(match_operand:CCALL 4 "metag__reg" "") + (const_int 0)]) + (set (match_operand:SI 0 "metag_datareg_op" "=e,f") + (and:SI (match_operand:SI 1 "metag_datareg_op" "e,f") + (match_operand:SI 2 "metag_K_operand" "K,K"))))] + "reload_completed + && metag_same_regclass_p (operands[0], operands[1])" + "@ + AND%?\\t%0, %1, %2\\t\\t%@ (*and si eeK OK) + AND%?\\t%0, %1, %2\\t\\t%@ (*and si ffK OK)" + [(set_attr "type" "fast") + (set_attr "cond" "no")]) + +;; test register ops setting the NOOV flags +(define_insn "*tst__si_rr" + [(set (reg: CC_REG) + (compare:CCZNC + (and:SI (match_operand:SI 0 "metag_datareg_op" "%e,f") + (match_operand:SI 1 "metag_datareg_op" "e,f")) + (const_int 0)))] + "!TARGET_METAC_1_1" + "TST\\t%0, %1\\t%@ (*tst si dd OK)" + [(set_attr "type" "fast,fast") + (set_attr "ccstate" "set,set")]) + +;; test register ops setting the NOOV flags - v1.1 case +(define_insn "*tst__si_rr_1_1" + [(set (reg: CC_REG) + (compare:CCZNC + (and:SI (match_operand:SI 0 "metag_datareg_op" "%e, f") + (match_operand:SI 1 "metag_reg_nofloat_op" "be,bf")) + (const_int 0)))] + "TARGET_METAC_1_1 && !TARGET_MINIM_CORE" + "TST\\t%0, %1\\t%@ (*tst si db OK)" + [(set_attr "type" "fast,fast") + (set_attr "ccstate" "set,set") + (set_attr "o2rhint" "op1op0")]) + +;; test register ops setting the NOOV flags - minim case +(define_insn "*tst__si_rr_minim" + [(set (reg: CC_REG) + (compare:CCZNC + (and:SI (match_operand:SI 0 "metag_datareg_op" "%e,!e, f,!f") + (match_operand:SI 1 "metag_register_op" "e, be,f, bf")) + (const_int 0)))] + "TARGET_METAC_1_1 && TARGET_MINIM_CORE" + "TST\\t%0, %1\\t%@ (*tst si db OK)" + [(set_attr "type" "fast,fast,fast,fast") + (set_attr "ccstate" "set") + (set_attr "o2rhint" "op1op0")]) + +(define_insn "*tst__si_ri" + [(set (reg: CC_REG) + (compare:CCZNC + (and:SI (match_operand:SI 0 "metag_reg_nofloat_op" "d,d, d,d,d") + (match_operand:SI 1 "metag_int_operand" "K,IP,J,M,N")) + (const_int 0)))] + "" + "@ + TST\\t%0, %1\\t%@ (*tst si dI OK) + TST\\t%0, %1\\t%@ (*tst si dI OK) + TSTT\\t%0, %1\\t%@ (*tst si dJ OK) + TSTMB\\t%0, #LO(%c1)\\t%@ (*tst si dM OK) + TSTMT\\t%0, #HI(%c1)\\t%@ (*tst si dN OK)" + [(set_attr "type" "fast,fast,fast,fast,fast") + (set_attr "ccstate" "set,set,set,set,set")]) + +;; and register ops combined with test cases +(define_insn "*ands_si_rrr" + [(set (reg: CC_REG) + (compare:CCZNC + (and:SI (match_operand:SI 1 "metag_reg_nofloat_op" "%e,f,e,f") + (match_operand:SI 2 "metag_reg_nofloat_op" "e,f,e,f")) + (const_int 0))) + (set (match_operand:SI 0 "metag_register_op" "=e,f,r,r") + (and:SI (match_dup 1) + (match_dup 2)))] + "!TARGET_METAC_1_1 || TARGET_MTX" + "ANDS\\t%0, %1, %2\\t%@ (*ands si xdd OK)" + [(set_attr "type" "fast,fast,slow,slow") + (set_attr "ccstate" "set,set,set,set")]) + +(define_insn "*ands__si_rri" + [(set (reg: CC_REG) + (compare:CCZNC + (and:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0, 0,0,0,e,f,d") + (match_operand:SI 2 "metag_int_operand" "IP,J,M,N,K,K,K")) + (const_int 0))) + (set (match_operand:SI 0 "metag_register_op" "=d, d,d,d,e,f,r") + (and:SI (match_dup 1) + (match_dup 2)))] + "" + "@ + ANDS\\t%0, %1, %2\\t%@ (*ands si r0I OK) + ANDST\\t%0, %1, #HI(%c2)\\t%@ (*ands si r0J OK) + ANDSMB\\t%0, %1, #LO(%c2)\\t%@ (*ands si r0M OK) + ANDSMT\\t%0, %1, #HI(%c2)\\t%@ (*ands si r0N OK) + ANDS\\t%0, %1, %2\\t\\t%@ (*ands si eeK OK) + ANDS\\t%0, %1, %2\\t\\t%@ (*ands si ffK OK) + ANDS\\t%0, %1, %2\\t\\t%@ (*ands si ddK OK)" + [(set_attr "type" "fast,fast,fast,fast,fast,fast,slow") + (set_attr "ccstate" "set,set,set,set,set,set,set")]) + +;; and register ops combined with test cases - v1.1 case +(define_insn "*ands_si_rrr_1_1" + [(set (reg: CC_REG) + (compare:CCZNC + (and:SI (match_operand:SI 1 "metag_reg_nofloat_op" "%e, f, e, f") + (match_operand:SI 2 "metag_reg_nofloat_op" "be,bf,be,bf")) + (const_int 0))) + (set (match_operand:SI 0 "metag_register_op" "=e, f, r, r") + (and:SI (match_dup 1) + (match_dup 2)))] + "TARGET_METAC_1_1 && !TARGET_MTX" + "ANDS\\t%0, %1, %2\\t%@ (*ands si xdb OK)" + [(set_attr "type" "fast,fast,slow,slow") + (set_attr "ccstate" "set,set,set,set") + (set_attr "o2rhint" "op2op1")]) + +;; bitextract - matched during combine +(define_insn_and_split "*zeroextractsi__compare0" + [(set (reg: CC_REG) + (compare:CCZNC + (zero_extract:SI (match_operand:SI 0 "metag_reg_nofloat_op" "") + (match_operand 1 "const_int_operand" "") + (match_operand 2 "const_int_operand" "")) + (const_int 0)))] + "metag_zeroextract_mask_p (operands[1], operands[2])" + "#" + "" + [(set (reg: CC_REG) + (compare:CCZNC + (and:SI (match_dup 0) + (match_dup 3)) + (const_int 0)))] + { + operands[3] = GEN_INT (((1 << INTVAL (operands[1])) -1) << INTVAL (operands[2])); + } + [(set_attr "type" "fast") + (set_attr "ccstate" "set")]) + +;; inclusive-or instructions + +(define_insn "iordi3" + [(set (match_operand:DI 0 "metag_register_op" "=d") + (ior:DI (match_operand:DI 1 "metag_register_op" "d") + (match_operand:DI 2 "metag_register_op" "d")))] + "TARGET_DSP" + "DL\\tOR\\t%0, %1, %2\\t%@ (*OR\\t%t0, %t1, %t2)" + [(set_attr "type" "fast")]) + +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +;; iorsi3 is made up of many parts.. ;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +(define_expand "iorsi3" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "") + (ior:SI (match_operand:SI 1 "metag_reg_nofloat_op" "") + (match_operand:SI 2 "metag_regorint_op" "")))] + "" + { + if (CONST_INT_P (operands[2]) + && METAG_LETTER_FOR_CONST (operands[2]) == 0) + { + /* Need to use I,J cases to implement op */ + rtx temp = (reload_in_progress || reload_completed) + ? operands[0] : gen_reg_rtx (SImode); + HOST_WIDE_INT value = INTVAL (operands[2]); + HOST_WIDE_INT ival; + + ival = trunc_int_for_mode (value & 0xFFFF0000, SImode); + emit_insn (gen_rtx_SET (VOIDmode, temp, + gen_rtx_IOR (SImode, operands[1], + GEN_INT (ival)))); + + ival = trunc_int_for_mode (value & 0x0000FFFF, SImode); + emit_insn (gen_rtx_SET (VOIDmode, operands[0], + gen_rtx_IOR (SImode, temp, + GEN_INT (ival)))); + DONE; + } + } +) + +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +;; and these are the iorsi3 parts.. ;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; + +;; register | register ops +(define_insn "*ior_si_rrr" + [(set (match_operand:SI 0 "metag_register_op" "=e,f,r,r") + (ior:SI (match_operand:SI 1 "metag_reg_nofloat_op" "%e,f,e,f") + (match_operand:SI 2 "metag_reg_nofloat_op" "e,f,e,f")))] + "!TARGET_METAC_1_1 || TARGET_MTX" + "OR%?\\t%0, %1, %2\\t%@ (*ior si xdd OK)" + [(set_attr "type" "fast,fast,slow,slow") + (set_attr "cond" "yes,yes,yes,yes") + (set_attr "predicable" "yes")]) + +;; register | register ops - v1.1 case +(define_insn "*ior_si_rrr_1_1" + [(set (match_operand:SI 0 "metag_register_op" "=e, f, r, r") + (ior:SI (match_operand:SI 1 "metag_reg_nofloat_op" "%e, f, e, f") + (match_operand:SI 2 "metag_reg_nofloat_op" "be,bf,be,bf")))] + "TARGET_METAC_1_1 && !TARGET_MINIM_CORE && !TARGET_MTX" + "OR%?\\t%0, %1, %2\\t%@ (*ior si xdb OK)" + [(set_attr "type" "fast,fast,slow,slow") + (set_attr "cond" "yes,yes,yes,yes") + (set_attr "predicable" "yes") + (set_attr "o2rhint" "op2op1")]) + +;; register | register ops - minim case +(define_insn "*ior_si_rrr_minim" + [(set (match_operand:SI 0 "metag_register_op" "=e,!e, f,!f, r,!r, r,!r") + (ior:SI (match_operand:SI 1 "metag_reg_nofloat_op" "%e, e, f, f, e, e, f, f") + (match_operand:SI 2 "metag_reg_nofloat_op" "e, be,f, bf,e, be,f, bf")))] + "TARGET_METAC_1_1 && TARGET_MINIM_CORE && !TARGET_MTX" + "OR%?\\t%0, %1, %2\\t%@ (*ior si xdb OK)" + [(set_attr "type" "fast,fast,fast,fast,slow,slow,slow,slow") + (set_attr "cond" "yes") + (set_attr "predicable" "yes") + (set_attr "o2rhint" "op2op1")]) + +;; register | immediate ops +(define_insn "*ior_si_rri" + [(set (match_operand:SI 0 "metag_register_op" "=d, d,d,d,e,f,r") + (ior:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0, 0,0,0,e,f,d") + (match_operand:SI 2 "metag_int_operand" "IP,J,M,N,K,K,K")))] + "!TARGET_MINIM_CORE" + "@ + OR\\t%0, %1, %2\\t%@ (*ior si r0I OK) + ORT\\t%0, %1, #HI(%c2)\\t%@ (*ior si r0J OK) + ORMB\\t%0, %1, #LO(%c2)\\t%@ (*ior si r0M OK) + ORMT\\t%0, %1, #HI(%c2)\\t%@ (*ior si r0N OK) + OR%?\\t%0, %1, %2\\t\\t%@ (*ior si eeK OK) + OR%?\\t%0, %1, %2\\t\\t%@ (*ior si ffK OK) + OR\\t%0, %1, %2\\t\\t%@ (*ior si rdK OK)" + [(set_attr "type" "fast,fast,fast,fast,fast,fast,slow") + (set_attr "cond" "no,no,no,no,yes,yes,no")]) + +;; register | immediate ops +(define_insn "*ior_si_rri" + [(set (match_operand:SI 0 "metag_register_op" "=d, d,d,d,d,!e,!f,!r") + (ior:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0, 0,0,0,0, e, f, d") + (match_operand:SI 2 "metag_int_operand" "IP,J,M,N,K, K, K, K")))] + "TARGET_MINIM_CORE" + "@ + OR\\t%0, %1, %2\\t%@ (*ior si r0I OK) + ORT\\t%0, %1, #HI(%c2)\\t%@ (*ior si r0J OK) + ORMB\\t%0, %1, #LO(%c2)\\t%@ (*ior si r0M OK) + ORMT\\t%0, %1, #HI(%c2)\\t%@ (*ior si r0N OK) + OR%?\\t%0, %1, %2\\t\\t%@ (*ior si d0K OK) + OR%?\\t%0, %1, %2\\t\\t%@ (*ior si eeK OK) + OR%?\\t%0, %1, %2\\t\\t%@ (*ior si ffK OK) + OR\\t%0, %1, %2\\t\\t%@ (*ior si rdK OK)" + [(set_attr "type" "fast,fast,fast,fast,fast,fast,fast,slow") + (set_attr "cond" "no,no,no,no,yes,yes,yes,no")]) + +;; conditional version for specific cases of ior_si_rri +(define_insn "*cond__ior_si_rri" + [(cond_exec + (match_operator 3 "comparison_operator" + [(match_operand:CCALL 4 "metag__reg" "") + (const_int 0)]) + (set (match_operand:SI 0 "metag_datareg_op" "=e,f") + (ior:SI (match_operand:SI 1 "metag_datareg_op" "e,f") + (match_operand:SI 2 "metag_K_operand" "K,K"))))] + "reload_completed + && metag_same_regclass_p (operands[0], operands[1])" + "@ + OR%?\\t%0, %1, %2\\t\\t%@ (*ior si eeK OK) + OR%?\\t%0, %1, %2\\t\\t%@ (*ior si ffK OK)" + [(set_attr "type" "fast") + (set_attr "cond" "no")]) + +;; ior register ops combined with test cases +(define_insn "*iors__si_rrr" + [(set (reg: CC_REG) + (compare:CCZNC + (ior:SI (match_operand:SI 1 "metag_datareg_op" "%e,f,e,f") + (match_operand:SI 2 "metag_datareg_op" "e,f,e,f")) + (const_int 0))) + (set (match_operand:SI 0 "metag_register_op" "=e,f,r,r") + (ior:SI (match_dup 1) + (match_dup 2)))] + "!TARGET_METAC_1_1 || TARGET_MTX" + "ORS\\t%0, %1, %2\\t%@ (*iors si xdd OK)" + [(set_attr "type" "fast,fast,slow,slow") + (set_attr "ccstate" "set,set,set,set")]) + +(define_insn "*iors__si_rri" + [(set (reg: CC_REG) + (compare:CCZNC + (ior:SI (match_operand:SI 1 "metag_datareg_op" "0, 0,0,0,e,f,d") + (match_operand:SI 2 "metag_int_operand" "IP,J,M,N,K,K,K")) + (const_int 0))) + (set (match_operand:SI 0 "metag_register_op" "=d, d,d,d,e,f,r") + (ior:SI (match_dup 1) + (match_dup 2)))] + "" + "@ + ORS\\t%0, %1, %2\\t%@ (*iors si d0I OK) + ORST\\t%0, %1, #HI(%c2)\\t%@ (*ands si d0J OK) + ORSMB\\t%0, %1, #LO(%c2)\\t%@ (*iors si d0M OK) + ORSMT\\t%0, %1, #HI(%c2)\\t%@ (*ands si d0N OK) + ORS\\t%0, %1, %2\\t\\t%@ (*iors si eeK OK) + ORS\\t%0, %1, %2\\t\\t%@ (*iors si ffK OK) + ORS\\t%0, %1, %2\\t\\t%@ (*iors si ddK OK)" + [(set_attr "type" "fast,fast,fast,fast,fast,fast,slow") + (set_attr "ccstate" "set,set,set,set,set,set,set")]) + +;; ior register ops combined with test cases - v1.1 case +(define_insn "*iors__si_rrr_1_1" + [(set (reg: CC_REG) + (compare:CCZNC + (ior:SI (match_operand:SI 1 "metag_reg_nofloat_op" "%e, f, e, f") + (match_operand:SI 2 "metag_reg_nofloat_op" "be,bf,be,bf")) + (const_int 0))) + (set (match_operand:SI 0 "metag_register_op" "=e, f, r, r") + (ior:SI (match_dup 1) + (match_dup 2)))] + "TARGET_METAC_1_1 && !TARGET_MTX" + "ORS\\t%0, %1, %2\\t%@ (*iors si xdb OK)" + [(set_attr "type" "fast,fast,slow,slow") + (set_attr "ccstate" "set,set,set,set") + (set_attr "o2rhint" "op2op1")]) + +;; scratch ior register ops setting the NOOV flags - needed to enable combines +(define_insn "*tior__si_rr" + [(set (reg: CC_REG) + (compare:CCZNC + (ior:SI (match_operand:SI 1 "metag_reg_nofloat_op" "%e,f,e,f") + (match_operand:SI 2 "metag_reg_nofloat_op" "e,f,e,f")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=e,f,r,r"))] + "!TARGET_METAC_1_1 || TARGET_MTX" + "ORS\\t%0, %1, %2\\t%@ (*tior si xdd OK)" + [(set_attr "type" "fast,fast,slow,slow") + (set_attr "ccstate" "set,set,set,set")]) + +(define_insn "*tior__si_ri" + [(set (reg: CC_REG) + (compare:CCZNC + (ior:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0, 0,0,0,e,f") + (match_operand:SI 2 "metag_int_operand" "IP,J,M,N,K,K")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=d, d,d,d,e,f"))] + "" + "@ + ORS\\t%0, %1, %2\\t%@ (*tior si dI OK) + ORST\\t%0, %1, #HI(%c2)\\t%@ (*tior si dJ OK) + ORSMB\\t%0, %1, #LO(%c2)\\t%@ (*tior si dM OK) + ORSMT\\t%0, %1, #HI(%c2)\\t%@ (*tior si dN OK) + ORS\\t%0, %1, %2\\t\\t%@ (*tior si eK OK) + ORS\\t%0, %1, %2\\t\\t%@ (*tior si fK OK)" + [(set_attr "type" "fast,fast,fast,fast,fast,fast") + (set_attr "ccstate" "set,set,set,set,set,set")]) + +;; scratch ior register ops setting the NOOV flags - v1.1 case +(define_insn "*tior__si_rr_1_1" + [(set (reg: CC_REG) + (compare:CCZNC + (ior:SI (match_operand:SI 1 "metag_reg_nofloat_op" "%e, f, e, f") + (match_operand:SI 2 "metag_reg_nofloat_op" "be,bf,be,bf")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=e, f, r, r"))] + "TARGET_METAC_1_1 && !TARGET_MTX" + "ORS\\t%0, %1, %2\\t%@ (*tior si xdb OK)" + [(set_attr "type" "fast,fast,slow,slow") + (set_attr "ccstate" "set,set,set,set") + (set_attr "o2rhint" "op2op1")]) + +;; exclusive-or instructions + +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +;; and these are the xordi3 parts.. ;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; + +(define_insn "*xordi3_rri" + [(set (match_operand:DI 0 "metag_register_op" "+d") + (xor:DI (match_dup 0) + (match_operand:DI 1 "metag_16bit_op" "KIP")))] + "TARGET_DSP" + "DL\\tXOR\\t%0, %0, %1\\t%@ (*OR\\t%t0, %t0, %1)" + [(set_attr "type" "fast")]) + +(define_insn "xordi3" + [(set (match_operand:DI 0 "metag_register_op" "=d") + (xor:DI (match_operand:DI 1 "metag_register_op" "d") + (match_operand:DI 2 "metag_register_op" "d")))] + "TARGET_DSP" + "DL\\tXOR\\t%0, %1, %2\\t%@ (*OR\\t%t0, %t1, %t2)" + [(set_attr "type" "fast")]) + +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +;; xorsi3 is made up of many parts.. ;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +(define_expand "xorsi3" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "") + (xor:SI (match_operand:SI 1 "metag_reg_nofloat_op" "") + (match_operand:SI 2 "metag_regorint_op" "")))] + "" + { + if (CONST_INT_P (operands[2]) + && METAG_LETTER_FOR_CONST (operands[2]) == 0) + { + /* Need to use I,J cases to implement op */ + rtx temp = (reload_in_progress || reload_completed) + ? operands[0] : gen_reg_rtx (SImode); + HOST_WIDE_INT value = INTVAL (operands[2]); + HOST_WIDE_INT ival; + + ival = trunc_int_for_mode (value & 0xFFFF0000, SImode); + emit_insn (gen_rtx_SET (VOIDmode, temp, + gen_rtx_XOR (SImode, operands[1], + GEN_INT (ival)))); + + ival = trunc_int_for_mode (value & 0x0000FFFF, SImode); + emit_insn (gen_rtx_SET (VOIDmode, operands[0], + gen_rtx_XOR (SImode, temp, + GEN_INT (ival)))); + DONE; + } + } +) + +;; register ^ register ops + +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +;; and these are the xorsi3 parts.. ;; +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; + +;; register ^ register ops +(define_insn "*xor_si_rrr" + [(set (match_operand:SI 0 "metag_register_op" "=e,f,r,r") + (xor:SI (match_operand:SI 1 "metag_reg_nofloat_op" "%e,f,e,f") + (match_operand:SI 2 "metag_reg_nofloat_op" "e,f,e,f")))] + "!TARGET_METAC_1_1 || TARGET_MTX" + "XOR%?\\t%0, %1, %2\\t%@ (*xor si xdd OK)" + [(set_attr "type" "fast,fast,slow,slow") + (set_attr "cond" "yes,yes,yes,yes") + (set_attr "predicable" "yes")]) + +;; register ^ register ops - v1.1 case +(define_insn "*xor_si_rrr_1_1" + [(set (match_operand:SI 0 "metag_register_op" "=e, f, r, r") + (xor:SI (match_operand:SI 1 "metag_reg_nofloat_op" "%e, f, e, f") + (match_operand:SI 2 "metag_reg_nofloat_op" "be,bf,be,bf")))] + "TARGET_METAC_1_1 && !TARGET_MINIM_CORE && !TARGET_MTX" + "XOR%?\\t%0, %1, %2\\t%@ (*xor si xdb OK)" + [(set_attr "type" "fast,fast,slow,slow") + (set_attr "cond" "yes,yes,yes,yes") + (set_attr "predicable" "yes") + (set_attr "o2rhint" "op2op1")]) + +;; register ^ register ops - minim case +(define_insn "*xor_si_rrr_minim" + [(set (match_operand:SI 0 "metag_register_op" "=e,!e, f,!f, r,!r, r,!r") + (xor:SI (match_operand:SI 1 "metag_reg_nofloat_op" "%e, e, f, f, e, e, f, f") + (match_operand:SI 2 "metag_reg_nofloat_op" "e, be,f, bf,e, be,f, bf")))] + "TARGET_METAC_1_1 && TARGET_MINIM_CORE && !TARGET_MTX" + "XOR%?\\t%0, %1, %2\\t%@ (*xor si xdb OK)" + [(set_attr "type" "fast,fast,fast,fast,slow,slow,slow,slow") + (set_attr "cond" "yes") + (set_attr "predicable" "yes") + (set_attr "o2rhint" "op2op1")]) + +;; same register ^ immediate ops +(define_insn "*xor_si_rri" + [(set (match_operand:SI 0 "metag_register_op" "=d, d,d,d,e,f,r") + (xor:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0, 0,0,0,e,f,d") + (match_operand:SI 2 "metag_int_operand" "IP,J,M,N,K,K,K")))] + "!TARGET_MINIM_CORE" + "@ + XOR\\t%0, %1, %2\\t%@ (*xor si d0I OK) + XORT\\t%0, %1, #HI(%c2)\\t%@ (*xor si d0J OK) + XORMB\\t%0, %1, #LO(%c2)\\t%@ (*xor si d0M OK) + XORMT\\t%0, %1, #HI(%c2)\\t%@ (*xor si d0N OK) + XOR%?\\t%0, %1, %2\\t\\t%@ (*xor si eeK OK) + XOR%?\\t%0, %1, %2\\t\\t%@ (*xor si ffK OK) + XOR\\t%0, %1, %2\\t\\t%@ (*xor si rdK OK)" + [(set_attr "type" "fast,fast,fast,fast,fast,fast,slow") + (set_attr "cond" "no,no,no,no,yes,yes,no")]) + +;; same register ^ immediate ops +(define_insn "*xor_si_rri" + [(set (match_operand:SI 0 "metag_register_op" "=d, d,d,d,d,e,f,r") + (xor:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0, 0,0,0,0,e,f,d") + (match_operand:SI 2 "metag_int_operand" "IP,J,M,N,K,K,K,K")))] + "TARGET_MINIM_CORE" + "@ + XOR\\t%0, %1, %2\\t%@ (*xor si d0I OK) + XORT\\t%0, %1, #HI(%c2)\\t%@ (*xor si d0J OK) + XORMB\\t%0, %1, #LO(%c2)\\t%@ (*xor si d0M OK) + XORMT\\t%0, %1, #HI(%c2)\\t%@ (*xor si d0N OK) + XOR%?\\t%0, %1, %2\\t\\t%@ (*xor si d0K OK) + XOR%?\\t%0, %1, %2\\t\\t%@ (*xor si eeK OK) + XOR%?\\t%0, %1, %2\\t\\t%@ (*xor si ffK OK) + XOR\\t%0, %1, %2\\t\\t%@ (*xor si rdK OK)" + [(set_attr "type" "fast,fast,fast,fast,fast,fast,fast,slow") + (set_attr "cond" "no,no,no,no,yes,yes,yes,no")]) + +;; conditional version for specific cases of xor_si_rri +(define_insn "*cond__xor_si_rri" + [(cond_exec + (match_operator 3 "comparison_operator" + [(match_operand:CCALL 4 "metag__reg" "") + (const_int 0)]) + (set (match_operand:SI 0 "metag_datareg_op" "=e,f") + (xor:SI (match_operand:SI 1 "metag_datareg_op" "e,f") + (match_operand:SI 2 "metag_K_operand" "K,K"))))] + "reload_completed + && metag_same_regclass_p (operands[0], operands[1])" + "@ + XOR%?\\t%0, %1, %2\\t\\t%@ (*xor si eeK OK) + XOR%?\\t%0, %1, %2\\t\\t%@ (*xor si ffK OK)" + [(set_attr "type" "fast") + (set_attr "cond" "no")]) + +;; xor register ops combined with test cases +(define_insn "*xors__si_rrr" + [(set (reg: CC_REG) + (compare:CCZNC + (xor:SI (match_operand:SI 1 "metag_reg_nofloat_op" "%e,f,e,f") + (match_operand:SI 2 "metag_reg_nofloat_op" "e,f,e,f")) + (const_int 0))) + (set (match_operand:SI 0 "metag_register_op" "=e,f,r,r") + (xor:SI (match_dup 1) + (match_dup 2)))] + "!TARGET_METAC_1_1 || TARGET_MTX" + "XORS\\t%0, %1, %2\\t%@ (*xors si xdd OK)" + [(set_attr "type" "fast,fast,slow,slow") + (set_attr "ccstate" "set,set,set,set")]) + +(define_insn "*xors__si_rri" + [(set (reg: CC_REG) + (compare:CCZNC + (xor:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0, 0,0,0,e,f,d") + (match_operand:SI 2 "metag_int_operand" "IP,J,M,N,K,K,K")) + (const_int 0))) + (set (match_operand:SI 0 "metag_register_op" "=d, d,d,d,e,f,r") + (xor:SI (match_dup 1) + (match_dup 2)))] + "" + "@ + XORS\\t%0, %1, %2\\t%@ (*xors si d0I OK) + XORST\\t%0, %1, #HI(%c2)\\t%@ (*xors si d0J OK) + XORSMB\\t%0, %1, #LO(%c2)\\t%@ (*xors si d0M OK) + XORSMT\\t%0, %1, #HI(%c2)\\t%@ (*xors si d0N OK) + XORS\\t%0, %1, %2\\t\\t%@ (*xors si eeK OK) + XORS\\t%0, %1, %2\\t\\t%@ (*xors si ffK OK) + XORS\\t%0, %1, %2\\t\\t%@ (*xors si rdK OK)" + [(set_attr "type" "fast,fast,fast,fast,fast,fast,slow") + (set_attr "ccstate" "set,set,set,set,set,set,set")]) + +;; xor register ops combined with test cases - v1.1 case +(define_insn "*xors__si_rrr_1_1" + [(set (reg: CC_REG) + (compare:CCZNC + (xor:SI (match_operand:SI 1 "metag_reg_nofloat_op" "%e, f, e, f") + (match_operand:SI 2 "metag_reg_nofloat_op" "be,bf,be,bf")) + (const_int 0))) + (set (match_operand:SI 0 "metag_register_op" "=e, f, r, r") + (xor:SI (match_dup 1) + (match_dup 2)))] + "TARGET_METAC_1_1 && !TARGET_MTX" + "XORS\\t%0, %1, %2\\t%@ (*xors si xdb OK)" + [(set_attr "type" "fast,fast,slow,slow") + (set_attr "ccstate" "set,set,set,set") + (set_attr "o2rhint" "op2op1")]) + +;; scratch xor register ops setting the NOOV flags - needed to enable combines +(define_insn "*txor__si_rr" + [(set (reg: CC_REG) + (compare:CCZNC + (xor:SI (match_operand:SI 1 "metag_reg_nofloat_op" "%e,f,e,f") + (match_operand:SI 2 "metag_reg_nofloat_op" "e,f,e,f")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=e,f,r,r"))] + "!TARGET_METAC_1_1 || TARGET_MTX" + "XORS\\t%0, %1, %2\\t%@ (*txor si xdd OK)" + [(set_attr "type" "fast,fast,slow,slow") + (set_attr "ccstate" "set,set,set,set")]) + +(define_insn "*txor__si_ri" + [(set (reg: CC_REG) + (compare:CCZNC + (xor:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0, 0,0,0,e,f") + (match_operand:SI 2 "metag_int_operand" "IP,J,M,N,K,K")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=d, d,d,d,e,f"))] + "" + "@ + XORS\\t%0, %1, %2\\t%@ (*txor si dI OK) + XORST\\t%0, %1, #HI(%c2)\\t%@ (*txor si dJ OK) + XORSMB\\t%0, %1, #LO(%c2)\\t%@ (*txor si dM OK) + XORSMT\\t%0, %1, #HI(%c2)\\t%@ (*txor si dN OK) + XORS\\t%0, %1, %2\\t\\t%@ (*txor si eK OK) + XORS\\t%0, %1, %2\\t\\t%@ (*txor si fK OK)" + [(set_attr "type" "fast,fast,fast,fast,fast,fast") + (set_attr "ccstate" "set,set,set,set,set,set")]) + +;; scratch xor register ops setting the NOOV flags - v1.1 case +(define_insn "*txor__si_rr_1_1" + [(set (reg: CC_REG) + (compare:CCZNC + (xor:SI (match_operand:SI 1 "metag_reg_nofloat_op" "%e, f, e, f") + (match_operand:SI 2 "metag_reg_nofloat_op" "be,bf,be,bf")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=e, f, r, r"))] + "TARGET_METAC_1_1 && !TARGET_MTX" + "XORS\\t%0, %1, %2\\t%@ (*txor si xdd OK)" + [(set_attr "type" "fast,fast,slow,slow") + (set_attr "ccstate" "set,set,set,set") + (set_attr "o2rhint" "op2op1")]) + +;; rotate instructions +(define_insn "rotsi2_16" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=d,e,f") + (rotate:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0,e,f") + (const_int 16)))] + "" + "RTDW\\t%0, %1" + [(set_attr "type" "fast,fast,fast")]) + +(define_insn "parallel_rotsi2_16" + [(parallel + [(set (subreg:SI (match_operand:DI 0 "metag_datareg_op" "=d") 0) + (rotate:SI (subreg:SI (match_operand:DI 1 "metag_datareg_op" "d") 0) + (const_int 16))) + (set (subreg:SI (match_dup 0) 4) + (rotate:SI (subreg:SI (match_dup 1) 4) + (const_int 16)))])] + "TARGET_DSP" + "DL\\tRTDW\\t%0, %1" + [(set_attr "type" "fast")]) + +;; arithmetic shift instructions + +(define_expand "ashlsi3" + [(set (match_operand:SI 0 "metag_register_op" "") + (ashift:SI (match_operand:SI 1 "metag_register_op" "") + (match_operand:SI 2 "metag_regorint_op" "")))] + "" + "") + +(define_insn "*ashlsi3" + [(set (match_operand:SI 0 "metag_register_op" "=e,e,f,f,r,r,r,r") + (ashift:SI (match_operand:SI 1 "metag_reg_nofloat_op" "e,e,f,f,e,e,f,f") + (match_operand:SI 2 "metag_regorint_op" "e,L,f,L,e,L,f,L")))] + "!TARGET_MINIM_CORE" + "LSL%?\\t%0, %1, %2\\t%@ (*ashl si rrx OK)" + [(set_attr "type" "fast,fast,fast,fast,slow,slow,slow,slow") + (set_attr "cond" "yes,yes,yes,yes,no,no,no,no")]) + +(define_insn "*ashlsi3_minim" + [(set (match_operand:SI 0 "metag_register_op" "=e,e,!e,f,f,!f,r,r,r,r") + (ashift:SI (match_operand:SI 1 "metag_reg_nofloat_op" "e,0, e,f,0, f,e,e,f,f") + (match_operand:SI 2 "metag_regorint_op" "e,L, L,f,L, L,e,L,f,L")))] + "TARGET_MINIM_CORE" + "LSL%?\\t%0, %1, %2\\t%@ (*ashl si rrx OK)" + [(set_attr "type" "fast,fast,fast,fast,fast,fast,slow,slow,slow,slow") + (set_attr "cond" "yes,yes,yes,yes,yes,yes,no,no,no,no")]) + +;; conditional version for specific cases of ashlsi3 +(define_insn "*cond__ashlsi3_rrr" + [(cond_exec + (match_operator 3 "comparison_operator" + [(match_operand:CCALL 4 "metag__reg" "") + (const_int 0)]) + (set (match_operand:SI 0 "metag_datareg_op" "=e,f") + (ashift:SI (match_operand:SI 1 "metag_datareg_op" "e,f") + (match_operand:SI 2 "metag_datareg_op" "e,f"))))] + "reload_completed + && metag_same_regclass_p (operands[0], operands[1]) + && metag_same_regclass_p (operands[0], operands[2])" + "@ + LSL%?\\t%0, %1, %2\\t%@ (*ashl si eee OK) + LSL%?\\t%0, %1, %2\\t%@ (*ashl si fff OK)" + [(set_attr "type" "fast,fast") + (set_attr "cond" "no")]) + +(define_insn "*cond__ashlsi3_rrL" + [(cond_exec + (match_operator 3 "comparison_operator" + [(match_operand:CCALL 4 "metag__reg" "") + (const_int 0)]) + (set (match_operand:SI 0 "metag_datareg_op" "=e,f") + (ashift:SI (match_operand:SI 1 "metag_datareg_op" "e,f") + (match_operand:SI 2 "metag_L_operand" "L,L"))))] + "reload_completed + && metag_same_regclass_p (operands[0], operands[1])" + "@ + LSL%?\\t%0, %1, %2\\t%@ (*ashl si eeL OK) + LSL%?\\t%0, %1, %2\\t%@ (*ashl si ffL OK)" + [(set_attr "type" "fast,fast") + (set_attr "cond" "no")]) + +(define_expand "ashrsi3" + [(set (match_operand:SI 0 "metag_register_op" "=e,e,f,f,r,r,r,r") + (ashiftrt:SI (match_operand:SI 1 "metag_datareg_op" "e,e,f,f,e,e,f,f") + (match_operand:SI 2 "metag_regorint_op" "e,L,f,L,e,L,f,L")))] + "" + "") + +(define_insn "*ashrsi3" + [(set (match_operand:SI 0 "metag_register_op" "=e,e,f,f,r,r,r,r") + (ashiftrt:SI (match_operand:SI 1 "metag_datareg_op" "e,e,f,f,e,e,f,f") + (match_operand:SI 2 "metag_regorint_op" "e,L,f,L,e,L,f,L")))] + "!TARGET_MINIM_CORE" + "ASR%?\\t%0, %1, %2\\t%@ (*ashr si rrx OK)" + [(set_attr "type" "fast,fast,fast,fast,slow,slow,slow,slow") + (set_attr "cond" "yes,yes,yes,yes,no,no,no,no")]) + +(define_insn "*ashrsi3_minim" + [(set (match_operand:SI 0 "metag_register_op" "=e,e,!e,f,f,!f,r,r,r,r") + (ashiftrt:SI (match_operand:SI 1 "metag_datareg_op" "e,0, e,f,0, f,e,e,f,f") + (match_operand:SI 2 "metag_regorint_op" "e,L, L,f,L, L,e,L,f,L")))] + "TARGET_MINIM_CORE" + "ASR%?\\t%0, %1, %2\\t%@ (*ashr si rrx OK)" + [(set_attr "type" "fast,fast,fast,fast,fast,fast,slow,slow,slow,slow") + (set_attr "cond" "yes,yes,yes,yes,yes,yes,no,no,no,no")]) + +;; conditional version for specific cases of ashrsi3 +(define_insn "*cond__ashrsi3_rrr" + [(cond_exec + (match_operator 3 "comparison_operator" + [(match_operand:CCALL 4 "metag__reg" "") + (const_int 0)]) + (set (match_operand:SI 0 "metag_datareg_op" "=e,f") + (ashiftrt:SI (match_operand:SI 1 "metag_datareg_op" "e,f") + (match_operand:SI 2 "metag_datareg_op" "e,f"))))] + "reload_completed + && metag_same_regclass_p (operands[0], operands[1]) + && metag_same_regclass_p (operands[0], operands[2])" + "@ + ASR%?\\t%0, %1, %2\\t%@ (*ashr si eee OK) + ASR%?\\t%0, %1, %2\\t%@ (*ashr si fff OK)" + [(set_attr "type" "fast,fast") + (set_attr "cond" "no")]) + +(define_insn "*cond__ashrsi3_rrL" + [(cond_exec + (match_operator 3 "comparison_operator" + [(match_operand:CCALL 4 "metag__reg" "") + (const_int 0)]) + (set (match_operand:SI 0 "metag_datareg_op" "=e,f") + (ashiftrt:SI (match_operand:SI 1 "metag_datareg_op" "e,f") + (match_operand:SI 2 "metag_L_operand" "L,L"))))] + "reload_completed + && metag_same_regclass_p (operands[0], operands[1])" + "@ + ASR%?\\t%0, %1, %2\\t%@ (*ashr si eeL OK) + ASR%?\\t%0, %1, %2\\t%@ (*ashr si ffL OK)" + [(set_attr "type" "fast,fast") + (set_attr "cond" "no")]) + +(define_insn_and_split "*ashrdi3_32" + [(set (match_operand:DI 0 "metag_reg_nofloat_op" "=d,a") + (ashiftrt:DI (match_operand:DI 1 "metag_datareg_op" "d,d") + (const_int 32)))] + "" + "#" + "SPLIT_EARLY" + [(set (match_dup 2) + (match_dup 4)) + (set (match_dup 3) + (ashiftrt:SI (match_dup 4) + (const_int 31)))] + { + if (reload_completed) + { + operands[2] = gen_rtx_REG (SImode, REGNO (operands[0])); + operands[3] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + + operands[4] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1); + } + else + { + operands[2] = gen_rtx_SUBREG (SImode, operands[0], 0); + operands[3] = gen_rtx_SUBREG (SImode, operands[0], UNITS_PER_WORD); + + operands[4] = gen_rtx_SUBREG (SImode, operands[1], UNITS_PER_WORD); + } + } + [(set_attr "type" "two,slowslow")]) + +;; logical shift instructions + +(define_expand "lshrsi3" + [(set (match_operand:SI 0 "metag_register_op" "=e,e,f,f,r,r,r,r") + (lshiftrt:SI (match_operand:SI 1 "metag_reg_nofloat_op" "e,e,f,f,e,e,f,f") + (match_operand:SI 2 "metag_regorint_op" "e,L,f,L,e,L,f,L")))] + "" + "") + +(define_insn "*lshrsi3" + [(set (match_operand:SI 0 "metag_register_op" "=e,e,f,f,r,r,r,r") + (lshiftrt:SI (match_operand:SI 1 "metag_reg_nofloat_op" "e,e,f,f,e,e,f,f") + (match_operand:SI 2 "metag_regorint_op" "e,L,f,L,e,L,f,L")))] + "!TARGET_MINIM_CORE" + "LSR%?\\t%0, %1, %2\\t%@ (lshr si rrx OK)" + [(set_attr "type" "fast,fast,fast,fast,slow,slow,slow,slow") + (set_attr "cond" "yes,yes,yes,yes,no,no,no,no")]) + +(define_insn "*lshrsi3_minim" + [(set (match_operand:SI 0 "metag_register_op" "=e,e,!e,f,f,!f,r,r,r,r") + (lshiftrt:SI (match_operand:SI 1 "metag_reg_nofloat_op" "e,0, e,f,0, f,e,e,f,f") + (match_operand:SI 2 "metag_regorint_op" "e,L, L,f,L, L,e,L,f,L")))] + "TARGET_MINIM_CORE" + "LSR%?\\t%0, %1, %2\\t%@ (lshr si rrx OK)" + [(set_attr "type" "fast,fast,fast,fast,fast,fast,slow,slow,slow,slow") + (set_attr "cond" "yes,yes,yes,yes,yes,yes,no,no,no,no")]) + +;; conditional version for specific cases of lshrsi3 +(define_insn "*cond__lshrsi3_rrr" + [(cond_exec + (match_operator 3 "comparison_operator" + [(match_operand:CCALL 4 "metag__reg" "") + (const_int 0)]) + (set (match_operand:SI 0 "metag_datareg_op" "=e,f") + (lshiftrt:SI (match_operand:SI 1 "metag_datareg_op" "e,f") + (match_operand:SI 2 "metag_datareg_op" "e,f"))))] + "reload_completed + && metag_same_regclass_p (operands[0], operands[1]) + && metag_same_regclass_p (operands[0], operands[2])" + "@ + LSR%?\\t%0, %1, %2\\t%@ (lshr si eee OK) + LSR%?\\t%0, %1, %2\\t%@ (lshr si fff OK)" + [(set_attr "type" "fast,fast") + (set_attr "cond" "no")]) + +(define_insn "*cond__lshrsi3_rrL" + [(cond_exec + (match_operator 3 "comparison_operator" + [(match_operand:CCALL 4 "metag__reg" "") + (const_int 0)]) + (set (match_operand:SI 0 "metag_datareg_op" "=e,f") + (lshiftrt:SI (match_operand:SI 1 "metag_datareg_op" "e,f") + (match_operand:SI 2 "metag_L_operand" "L,L"))))] + "reload_completed + && metag_same_regclass_p (operands[0], operands[1])" + "@ + LSR%?\\t%0, %1, %2\\t%@ (lshr si eeL OK) + LSR%?\\t%0, %1, %2\\t%@ (lshr si ffL OK)" + [(set_attr "type" "fast,fast") + (set_attr "cond" "no")]) + +;; shift instructions combined with setting NOOV flags + +(define_insn "*ashls__si_rrx" + [(set (reg: CC_REG) + (compare:CCZNC + (ashift:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "e,e,f,f,e,e,f,f") + (match_operand:SI 2 "metag_regorint_op" "e,L,f,L,e,L,f,L")) + (const_int 0))) + (set (match_operand:SI 0 "metag_register_op" "=e,e,f,f,r,r,r,r") + (ashift:SI (match_dup 1) + (match_dup 2)))] + "" + "LSLS\\t%0, %1, %2\\t%@ (*ashls si rrx OK)" + [(set_attr "type" "fast,fast,fast,fast,slow,slow,slow,slow") + (set_attr "ccstate" "set,set,set,set,set,set,set,set")]) + +(define_insn "*ashrs__si_rrx" + [(set (reg: CC_REG) + (compare:CCZNC + (ashiftrt:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "e,e,f,f,e,e,f,f") + (match_operand:SI 2 "metag_regorint_op" "e,L,f,L,e,L,f,L")) + (const_int 0))) + (set (match_operand:SI 0 "metag_register_op" "=e,e,f,f,r,r,r,r") + (ashiftrt:SI (match_dup 1) + (match_dup 2)))] + "" + "ASRS\\t%0, %1, %2\\t%@ (*ashrs si rrx OK)" + [(set_attr "type" "fast,fast,fast,fast,slow,slow,slow,slow") + (set_attr "ccstate" "set,set,set,set,set,set,set,set")]) + +(define_insn "*lshrs__si_rrx" + [(set (reg: CC_REG) + (compare:CCZNC + (lshiftrt:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "e,e,f,f,e,e,f,f") + (match_operand:SI 2 "metag_regorint_op" "e,L,f,L,e,L,f,L")) + (const_int 0))) + (set (match_operand:SI 0 "metag_register_op" "=e,e,f,f,r,r,r,r") + (lshiftrt:SI (match_dup 1) + (match_dup 2)))] + "" + "LSRS\\t%0, %1, %2\\t%@ (lshrs si rrx OK)" + [(set_attr "type" "fast,fast,fast,fast,slow,slow,slow,slow") + (set_attr "ccstate" "set,set,set,set,set,set,set,set")]) + +;; shift instructions setting NOOV flags using scratch +(define_insn "*tashls__si_rrx" + [(set (reg: CC_REG) + (compare:CCZNC + (ashift:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "e,e,f,f,e,e,f,f") + (match_operand:SI 2 "metag_regorint_op" "e,L,f,L,e,L,f,L")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=e,e,f,f,r,r,r,r"))] + "" + "LSLS\\t%0, %1, %2\\t%@ (tashls si rrx OK)" + [(set_attr "type" "fast,fast,fast,fast,slow,slow,slow,slow") + (set_attr "ccstate" "set,set,set,set,set,set,set,set")]) + +(define_insn "*tashrs__si_rrx" + [(set (reg: CC_REG) + (compare:CCZNC + (ashiftrt:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "e,e,f,f,e,e,f,f") + (match_operand:SI 2 "metag_regorint_op" "e,L,f,L,e,L,f,L")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=e,e,f,f,r,r,r,r"))] + "" + "ASRS\\t%0, %1, %2\\t%@ (tashrs si rrx OK)" + [(set_attr "type" "fast,fast,fast,fast,slow,slow,slow,slow") + (set_attr "ccstate" "set,set,set,set,set,set,set,set")]) + +(define_insn "*tlshrs__si_rrx" + [(set (reg: CC_REG) + (compare:CCZNC + (lshiftrt:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "e,e,f,f,e,e,f,f") + (match_operand:SI 2 "metag_regorint_op" "e,L,f,L,e,L,f,L")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=e,e,f,f,r,r,r,r"))] + "" + "LSRS\\t%0, %1, %2\\t%@ (tlshrs si rrx OK)" + [(set_attr "type" "fast,fast,fast,fast,slow,slow,slow,slow") + (set_attr "ccstate" "set,set,set,set,set,set,set,set")]) + +;; negate instructions + +;; DImode negate +(define_expand "negdi2" + [(parallel + [(set (match_operand:DI 0 "metag_reg_nofloat_op" "") + (neg:DI (match_operand:DI 1 "metag_reg_nofloat_op" ""))) + (clobber (reg:CC CC_REG))])] + "" + "") + +(define_insn_and_split "*negdi2" + [(set (match_operand:DI 0 "metag_reg_nofloat_op" "=d") + (neg:DI (match_operand:DI 1 "metag_reg_nofloat_op" "d"))) + (clobber (reg:CC CC_REG))] + "" + "#" + "SPLIT_EARLY" + [(parallel + [(set (reg:CC_Z CC_REG) + (compare:CC_Z (neg:SI (match_dup 5)) + (const_int 0))) + (set (match_dup 3) + (neg:SI (match_dup 5)))]) + (set (match_dup 4) + (neg:SI (match_dup 6))) + (set (match_dup 4) + (if_then_else:SI (ne (reg:CC_Z CC_REG) + (const_int 0)) + (plus:SI (match_dup 4) + (const_int -1)) + (match_dup 4)))] + { + if (reload_completed) + { + operands[3] = gen_rtx_REG (SImode, REGNO (operands[0])); + operands[4] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + + operands[5] = gen_rtx_REG (SImode, REGNO (operands[1])); + operands[6] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1); + } + else + { + operands[3] = gen_rtx_SUBREG (SImode, operands[0], 0); + operands[4] = gen_rtx_SUBREG (SImode, operands[0], UNITS_PER_WORD); + + operands[5] = gen_rtx_SUBREG (SImode, operands[1], 0); + operands[6] = gen_rtx_SUBREG (SImode, operands[1], UNITS_PER_WORD); + } + } + [(set_attr "type" "three") + (set_attr "ccstate" "ccx")]) + +;; SImode negate +(define_expand "negsi2" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "") + (neg:SI (match_operand:SI 1 "metag_reg_nofloat_op" "")))] + "" + "") + +(define_insn "*negsi2" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=e,f") + (neg:SI (match_operand:SI 1 "metag_reg_nofloat_op" "e,f")))] + "!TARGET_METAC_1_1" + "NEG\\t%0, %1\\t\\t%@ (neg si dd OK)" + [(set_attr "type" "fast,fast")]) + +(define_insn "*negs__si_rr" + [(set (reg: CC_REG) + (compare:CCZNC + (neg:SI (match_operand:SI 1 "metag_reg_nofloat_op" "e,f")) + (const_int 0))) + (set (match_operand:SI 0 "metag_reg_nofloat_op" "=e,f") + (neg:SI (match_dup 1)))] + "!TARGET_METAC_1_1" + "NEGS\\t%0, %1\\t\\t%@ (negs si dd OK)" + [(set_attr "type" "fast,fast") + (set_attr "ccstate" "set,set")]) + +(define_insn "*tneg__si_rr" + [(set (reg: CC_REG) + (compare:CCZNC + (neg:SI (match_operand:SI 1 "metag_reg_nofloat_op" "e,f")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=e,f"))] + "!TARGET_METAC_1_1" + "NEGS\\t%0, %1\\t\\t%@ (tneg si dd OK)" + [(set_attr "type" "fast,fast") + (set_attr "ccstate" "set,set")]) + +;; negate instructions - v1.1 case +(define_insn "*negsi2_1_1" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=e, f") + (neg:SI (match_operand:SI 1 "metag_reg_nofloat_op" "be,bf")))] + "TARGET_METAC_1_1 && !TARGET_MINIM_CORE" + "NEG\\t%0, %1\\t\\t%@ (neg si db OK)" + [(set_attr "type" "fast,fast") + (set_attr "o2rhint" "op1op0")]) + +;; negate instructions - minim case +(define_insn "*negsi2_minim" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=e,!e, f,!f") + (neg:SI (match_operand:SI 1 "metag_reg_nofloat_op" "e, be,f, bf")))] + "TARGET_METAC_1_1 && TARGET_MINIM_CORE" + "NEG\\t%0, %1\\t\\t%@ (neg si db OK)" + [(set_attr "type" "fast,fast,fast,fast") + (set_attr "o2rhint" "op1op0")]) + +(define_insn "*negs__si_rr_1_1" + [(set (reg: CC_REG) + (compare:CCZNC + (neg:SI (match_operand:SI 1 "metag_reg_nofloat_op" "be,bf")) + (const_int 0))) + (set (match_operand:SI 0 "metag_reg_nofloat_op" "=e, f") + (neg:SI (match_dup 1)))] + "TARGET_METAC_1_1" + "NEGS\\t%0, %1\\t\\t%@ (negs si db OK)" + [(set_attr "type" "fast,fast") + (set_attr "ccstate" "set,set") + (set_attr "o2rhint" "op1op0")]) + +(define_insn "*tneg__si_rr_1_1" + [(set (reg: CC_REG) + (compare:CCZNC + (neg:SI (match_operand:SI 1 "metag_reg_nofloat_op" "be,bf")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=e, f"))] + "TARGET_METAC_1_1" + "NEGS\\t%0, %1\\t\\t%@ (tneg si dx OK)" + [(set_attr "type" "fast,fast") + (set_attr "ccstate" "set,set") + (set_attr "o2rhint" "op1op0")]) + +;; complement instructions +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=e,f,&e,&f") + (not:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0,0, e, f")))] + "" + "@ + XOR\\t%0, %1, #-1\\t%@ (not si e0 OK) + XOR\\t%0, %1, #-1\\t%@ (not si f0 OK) + # + #" + [(set_attr "type" "fast,fast,two,two")]) + +;; Split the above insn if it needs more than one insn +(define_split + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "") + (not:SI (match_operand:SI 1 "metag_reg_nofloat_op" "")))] + "reload_completed + && REGNO (operands[0]) != REGNO (operands[1])" + [(set (match_dup 0) + (const_int -1)) + (set (match_dup 0) + (xor:SI (match_dup 0) + (match_dup 1)))] + "") + +(define_insn "*nots__si_rr" + [(set (reg: CC_REG) + (compare:CCZNC + (not:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0,0, e, f")) + (const_int 0))) + (set (match_operand:SI 0 "metag_reg_nofloat_op" "=e,f,&e,&f") + (not:SI (match_dup 1)))] + "" + "@ + XORS\\t%0, %1, #-1\\t%@ (nots si e0 OK) + XORS\\t%0, %1, #-1\\t%@ (nots si f0 OK) + # + #" + [(set_attr "type" "fast,fast,two,two") + (set_attr "ccstate" "set,set,fastset,fastset")]) + +;; Split the above insn if it needs more than one insn +(define_split + [(set (reg: CC_REG) + (compare:CCZNC + (not:SI (match_operand:SI 1 "metag_reg_nofloat_op" "")) + (const_int 0))) + (set (match_operand:SI 0 "metag_reg_nofloat_op" "") + (not:SI (match_dup 1)))] + "reload_completed + && REGNO (operands[0]) != REGNO (operands[1])" + [(set (match_dup 0) + (const_int -1)) + (parallel + [(set (reg: CC_REG) + (compare: + (xor:SI (match_dup 0) + (match_dup 1)) + (const_int 0))) + (set (match_dup 0) + (xor:SI (match_dup 0) + (match_dup 1)))])] + "") + +(define_insn "*tnot__si_rr" + [(set (reg: CC_REG) + (compare:CCZNC + (not:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0,0, e, f")) + (const_int 0))) + (clobber (match_scratch:SI 0 "=e,f,&e,&f"))] + "" + "@ + XORS\\t%0, %1, #-1\\t%@ (tnot si e0 OK) + XORS\\t%0, %1, #-1\\t%@ (tnot si f0 OK) + # + #" + [(set_attr "type" "fast,fast,two,two") + (set_attr "ccstate" "set,set,fastset,fastset")]) + +;; Split the above insn if it needs more than one insn. +(define_split + [(set (reg: CC_REG) + (compare:CCZNC + (not:SI (match_operand:SI 1 "metag_reg_nofloat_op" "")) + (const_int 0))) + (clobber (match_scratch:SI 0 ""))] + "reload_completed + && REGNO (operands[0]) != REGNO (operands[1])" + [(set (match_dup 0) + (const_int -1)) + (parallel + [(set (reg: CC_REG) + (compare: + (xor:SI (match_dup 0) + (match_dup 1)) + (const_int 0))) + (set (match_dup 0) + (xor:SI (match_dup 0) + (match_dup 1)))])] + "") + + +;; Comparison operations + +(define_expand "cmpsi" + [(match_operand:SI 0 "metag_reg_nofloat_op" "") + (match_operand:SI 1 "metag_regorint_op" "")] + "" + { + /* These are processed via the conditional branch define_expand's later */ + metag_compare_op0 = operands[0]; + metag_compare_op1 = operands[1]; + + if (CONST_INT_P (operands[1]) + && METAG_LETTER_FOR_CONST (operands[1]) == 0) + { + /* Have to do register to register comparison for big constants */ + metag_compare_op1 = force_reg (SImode, operands[1]); + } + + DONE; + } +) + +;; compare si instruction +(define_insn "*cmpsi__rr" + [(set (reg: CC_REG) + (compare:CCANY + (match_operand:SI 0 "metag_reg_nofloat_op" "e,f") + (match_operand:SI 1 "metag_reg_nofloat_op" "e,f")))] + "!TARGET_METAC_1_1" + "@ + CMP\\t%0, %1\\t\\t%@ (*cmpsi ee OK) + CMP\\t%0, %1\\t\\t%@ (*cmpsi ff OK)" + [(set_attr "type" "fast,fast") + (set_attr "ccstate" "set,set")]) + +(define_insn "*cmpsi__ri" + [(set (reg: CC_REG) + (compare:CCANY + (match_operand:SI 0 "metag_reg_nofloat_op" "d,d, d,d,d") + (match_operand:SI 1 "metag_int_operand" "K,IP,J,M,N")))] + "" + "@ + CMP\\t%0, %1\\t\\t%@ (*cmpsi dI OK) + CMP\\t%0, %1\\t\\t%@ (*cmpsi dI OK) + CMPT\\t%0, #HI(%c1)\\t\\t%@ (*cmpsi dJ OK) + CMPMB\\t%0, #LO(%c1)\\t\\t%@ (*cmpsi dM OK) + CMPMT\\t%0, #HI(%c1)\\t\\t%@ (*cmpsi dN OK)" + [(set_attr "type" "fast,fast,fast,fast,fast") + (set_attr "ccstate" "set,set,set,set,set")]) + +;; compare si instruction - v1.1 case +(define_insn "*cmpsi_rr_1_1" + [(set (reg: CC_REG) + (compare:CCANY + (match_operand:SI 0 "metag_reg_nofloat_op" "e, f") + (match_operand:SI 1 "metag_reg_nofloat_op" "be,bf")))] + "TARGET_METAC_1_1" + "@ + CMP\\t%0, %1\\t\\t%@ (*cmpsi eb OK) + CMP\\t%0, %1\\t\\t%@ (*cmpsi fb OK)" + [(set_attr "type" "fast,fast") + (set_attr "ccstate" "set,set") + (set_attr "o2rhint" "op1op0")]) + +;; compare hi instruction for zero flag +(define_insn "*tst_zhi" + [(set (reg:CC_Z CC_REG) + (compare:CC_Z + (match_operand:HI 0 "metag_datareg_op" "d") + (const_int 0)))] + "" + "TST\\t%0, #0xFFFF\\t%@ (*tst zhi d OK)" + [(set_attr "type" "fast") + (set_attr "ccstate" "set")]) + +;; compare qi instruction for zero flag +(define_insn "*tst_zqi" + [(set (reg:CC_Z CC_REG) + (compare:CC_Z + (match_operand:QI 0 "metag_datareg_op" "d") + (const_int 0)))] + "" + "TST\\t%0, #255\\t%@ (*tst zqi d OK)" + [(set_attr "type" "fast") + (set_attr "ccstate" "set")]) + +;; Copy and compare combines the flag setup with a move +;; Note MOVS/ADDS for DU -> FX is allowed but FX -> DU is not +(define_insn "*cmpsi_movsi__eq0" + [(set (reg: CC_REG) + (compare:CCZNC + (match_operand:SI 1 "metag_datareg_op" "e,f,d") + (const_int 0))) + (set (match_operand:SI 0 "metag_reg_nofloat_op" "=e,f,da") + (match_dup 1))] + "" + "ADDS\\t%0, %1, #0\\t\\t%@ (*movs si rr OK)" + [(set_attr "type" "fast,fast,slow") + (set_attr "ccstate" "set")]) + +(define_insn "*cmpsi_movsi_cc_eq0" + [(set (reg:CC CC_REG) + (compare:CC + (match_operand:SI 1 "metag_datareg_op" "e,f,d") + (const_int 0))) + (set (match_operand:SI 0 "metag_reg_nofloat_op" "=e,f,da") + (match_dup 1))] + "" + "SUBS\\t%0, %1, #0\\t\\t%@ (*movs si rr OK)" + [(set_attr "type" "fast,fast,slow") + (set_attr "ccstate" "set")]) + +;; min instruction + +(define_insn "sminsi3" + [(set (match_operand:SI 0 "metag_datareg_op" "=e,f") + (smin:SI (match_operand:SI 1 "metag_datareg_op" "%e,f") + (match_operand:SI 2 "metag_datareg_op" "e,f"))) + (clobber (reg:CC CC_REG))] + "!TARGET_METAC_0_1" + "MIN\\t%0, %1, %2\\t%@ (*min si ddd OK)" + [(set_attr "type" "fast") + (set_attr "ccstate" "ccx")]) + +;; max instruction + +(define_insn "smaxsi3" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=e,f") + (smax:SI (match_operand:SI 1 "metag_reg_nofloat_op" "%e,f") + (match_operand:SI 2 "metag_reg_nofloat_op" "e,f"))) + (clobber (reg:CC CC_REG))] + "!TARGET_METAC_0_1" + "MAX\\t%0, %1, %2\\t%@ (*max si ddd OK)" + [(set_attr "type" "fast") + (set_attr "ccstate" "ccx")]) + +;; abs instruction + +(define_insn "abssi2" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=e,f") + (abs:SI (match_operand:SI 1 "metag_reg_nofloat_op" "e,f"))) + (clobber (reg:CC CC_REG))] + "!TARGET_METAC_0_1" + "ABS\\t%0, %1\\t%@ (*abs si dd OK)" + [(set_attr "type" "fast") + (set_attr "ccstate" "ccx")]) + +;; Conditional move support +(define_expand "movsicc" + [(set (match_operand:SI 0 "metag_register_op" "") + (if_then_else:SI (match_operand 1 "comparison_operator" "") + (match_operand:SI 2 "metag_regorint_op" "") + (match_operand:SI 3 "metag_regorint_op" "")))] + "" + { + enum rtx_code code = GET_CODE (operands[1]); + enum machine_mode mode; + rtx ccreg; + + if (CONST_INT_P (operands[2]) && CONST_INT_P (operands[3])) + { + /* Can only support -255 to 255 delta between constants */ + HOST_WIDE_INT op2_mi_op3 = INTVAL (operands[2]) - INTVAL (operands[3]); + rtx value = GEN_INT (op2_mi_op3); + + if (satisfies_constraint_P (value) + || satisfies_constraint_K (value)) + { + rtx temp = (reload_in_progress || reload_completed) + ? operands[0] : gen_reg_rtx (SImode); + + emit_move_insn (temp, operands[3]); + operands[2] = gen_rtx_PLUS (SImode, temp, value); + operands[3] = temp; + } + } + + if (CONST_INT_P (operands[3])) + { + /* Make second source operand a register */ + operands[3] = force_reg (SImode, operands[3]); + } + + if (CONST_INT_P (operands[2])) + { + /* Make first source operand a register! */ + operands[2] = force_reg (SImode, operands[2]); + } + + /* Generate correct comparison insn */ + mode = SELECT_CC_MODE (code, metag_compare_op0, metag_compare_op1); + ccreg = gen_rtx_REG (mode, CC_REG); + emit_insn (gen_rtx_SET (VOIDmode, ccreg, + gen_rtx_COMPARE (mode, metag_compare_op0, metag_compare_op1))); + + /* Expand condition to act on result */ + operands[1] = gen_rtx_fmt_ee (code, VOIDmode, ccreg, const0_rtx); + } +) + +(define_insn "*mov_if__rr0" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=e,f,h,l,da") + (if_then_else:SI (match_operator 1 "comparison_operator" + [(match_operand:CCALL 2 "metag__reg" "") + (const_int 0)]) + (match_operand:SI 3 "metag_reg_nofloat_op" "e,f,h,l,da") + (match_operand:SI 4 "metag_reg_nofloat_op" "0,0,0,0,0")))] + "" + "MOV%z1\\t%0, %3\\t%@ (*mov if rr0 OK)" + [(set_attr "type" "fast,fast,fast,fast,slow") + (set_attr "ccstate" "xcc,xcc,xcc,xcc,xcc")]) + +;; Conditional add is targeted by expansion of if_then_else(const, const) +(define_insn "*add_if__r0KP" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=e,f,h,l,e,f,h,l") + (if_then_else:SI (match_operator 1 "comparison_operator" + [(match_operand:CCALL 2 "metag__reg" "") + (const_int 0)]) + (plus:SI (match_operand:SI 3 "metag_regnofrm_op" "e,f,h,l,e,f,h,l") + (match_operand:SI 4 "metag_smallint_op" "K,K,K,K,P,P,P,P")) + (match_operand:SI 5 "metag_reg_nofloat_op" "0,0,0,0,0,0,0,0")))] + "" + "@ + ADD%z1\\t%0, %3, %4\\t\\t%@ (*add if eeK OK) + ADD%z1\\t%0, %3, %4\\t\\t%@ (*add if ffK OK) + ADD%z1\\t%0, %3, %4\\t\\t%@ (*add if hhK OK) + ADD%z1\\t%0, %3, %4\\t\\t%@ (*add if llK OK) + SUB%z1\\t%0, %3, #%n4\\t\\t%@ (*sub if eeP OK) + SUB%z1\\t%0, %3, #%n4\\t\\t%@ (*sub if ffP OK) + SUB%z1\\t%0, %3, #%n4\\t\\t%@ (*sub if hhP OK) + SUB%z1\\t%0, %3, #%n4\\t\\t%@ (*sub if llP OK)" + [(set_attr "type" "fast,fast,fast,fast,fast,fast,fast,fast") + (set_attr "ccstate" "xcc,xcc,xcc,xcc,xcc,xcc,xcc,xcc")]) + + +;; zero/sign extend instructions + +(define_insn_and_split "zero_extendsidi2" + [(set (match_operand:DI 0 "metag_reg_nofloat_op" "=da") + (zero_extend:DI + (match_operand:SI 1 "metag_reg_nofloat_op" "da")))] + "" + "#" + "SPLIT_EARLY" + [(set (match_dup 2) + (match_dup 1)) + (set (match_dup 3) + (const_int 0))] + { + if (reload_completed) + { + operands[2] = gen_rtx_REG (SImode, REGNO (operands[0])); + operands[3] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + } + else + { + operands[2] = gen_rtx_SUBREG (SImode, operands[0], 0); + operands[3] = gen_rtx_SUBREG (SImode, operands[0], UNITS_PER_WORD); + } + } + [(set_attr "type" "two")] +) + +(define_expand "zero_extendhisi2" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "") + (zero_extend:SI + (match_operand:HI 1 "metag_datareg_op" "")))] + "" + { + } +) + +(define_insn_and_split "*zero_extendhisi2" + [(set (match_operand:SI 0 "metag_datareg_op" "=d") + (zero_extend:SI + (match_operand:HI 1 "metag_datareg_op" "0")))] + "" + "#" + "SPLIT_EARLY" + [(set (match_dup 0) + (and:SI (match_dup 1) + (match_dup 2)))] + { + operands[1] = gen_lowpart (SImode, operands[1]); + operands[2] = gen_int_mode (0xFFFF, SImode); + }) + +(define_expand "zero_extendqisi2" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "") + (zero_extend:SI + (match_operand:QI 1 "metag_datareg_op" "")))] + "" + { + } +) + +(define_insn_and_split "*zero_extendqisi2" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (zero_extend:SI + (match_operand:QI 1 "metag_datareg_op" "d")))] + "" + "#" + "SPLIT_EARLY" + [(set (match_dup 0) + (and:SI (match_dup 1) + (match_dup 2)))] + { + operands[1] = gen_lowpart (SImode, operands[1]); + operands[2] = gen_int_mode (0xFF, SImode); + }) + +(define_insn_and_split "extendsidi2" + [(set (match_operand:DI 0 "metag_reg_nofloat_op" "=d,d,a") + (sign_extend:DI + (match_operand:SI 1 "metag_datareg_op" "f,e,d")))] + "" + "#" + "SPLIT_EARLY" + [(set (match_dup 2) + (match_dup 1)) + (set (match_dup 3) + (ashiftrt:SI (match_dup 1) + (const_int 31)))] + { + if (reload_completed) + { + operands[2] = gen_rtx_REG (SImode, REGNO (operands[0])); + operands[3] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + } + else + { + operands[2] = gen_rtx_SUBREG (SImode, operands[0], 0); + operands[3] = gen_rtx_SUBREG (SImode, operands[0], UNITS_PER_WORD); + } + } + [(set_attr "type" "two,slowslow,slowslow")] +) + +(define_expand "extendhisi2" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "") + (sign_extend:SI + (match_operand:HI 1 "metag_datareg_op" "")))] + "" + { + } +) + +(define_expand "extendqisi2" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "") + (sign_extend:SI + (match_operand:QI 1 "metag_datareg_op" "")))] + "" + { + } +) + +;; ----------------------------------------------------------------------------- +;; | Matching zero extends loads to HI post/pre_inc/dec/modify +;; ----------------------------------------------------------------------------- + +(define_insn "*lodz_hi_post_inc" + [(set (match_operand:HI 0 "metag_register_op" "=cr") + (zero_extend:HI + (mem:EXTHI + (post_inc:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da")))))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tGET\\t%0, [%1++]\\t%@ (*lodz HI post_inc OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lodz_hi_post_dec" + [(set (match_operand:HI 0 "metag_register_op" "=cr") + (zero_extend:HI + (mem:EXTHI + (post_dec:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da")))))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tGET\\t%0, [%1--]\\t%@ (*lodz HI post_dec OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lodz_hi_pre_inc" + [(set (match_operand:HI 0 "metag_register_op" "=cr") + (zero_extend:HI + (mem:EXTHI + (pre_inc:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da")))))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tGET\\t%0, [++%1]\\t%@ (*lodz HI pre_inc OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lodz_hi_pre_dec" + [(set (match_operand:HI 0 "metag_register_op" "=cr") + (zero_extend:HI + (mem:EXTHI + (pre_dec:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da")))))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tGET\\t%0, [--%1]\\t%@ (*lodz HI pre_dec OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lodz_hi_post_modify_disp" + [(set (match_operand:HI 0 "metag_register_op" "=cr") + (zero_extend:HI + (mem:EXTHI + (post_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+da") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_offset6_" ""))))))] + "" + { + static const char fmt[] = "F\\tGET\\t%0, [%1+%2++]\\t%@ (*load HI post_modify_disp OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lodz_hi_post_modify_reg" + [(set (match_operand:HI 0 "metag_register_op" "=cr,cr,cr,cr") + (zero_extend:HI + (mem:EXTHI + (post_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+e, f, h, l") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_reg_nofloat_op" "e, f, h, l"))))))] + "" + { + static const char fmt[] = "F\\tGET\\t%0, [%1+%2++]\\t%@ (*lodz HI post_modify_reg OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lodz_hi_pre_modify_disp" + [(set (match_operand:HI 0 "metag_reg_nofloat_op" "=da") + (zero_extend:HI + (mem:EXTHI + (pre_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+da") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_offset6_" ""))))))] + "" + "GET\\t%0, [%1++%2]\\t%@ (*lodz HI pre_modify_disp OK)" + [(set_attr "type" "load")]) + +(define_insn "*lodz_hi_pre_modify_reg" + [(set (match_operand:HI 0 "metag_register_op" "=cr,cr,cr,cr") + (zero_extend:HI + (mem:EXTHI + (pre_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+e, f, h, l") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_reg_nofloat_op" "e, f, h, l"))))))] + "" + { + static const char fmt[] = "F\\tGET\\t%0, [%1++%2]\\t%@ (*lodz HI pre_modify_reg OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +;; ----------------------------------------------------------------------------- + +;; zero_extend loads to SI from EXTSI mode using base+index +(define_insn "*lodz_si_rma" + [(set (match_operand:SI 0 "metag_register_op" "=cr,cr,cr,cr") + (zero_extend:SI + (mem:EXTSI + (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "e, f, h, l") + (match_operand:SI 2 "metag_regnofrm_op" "e, f, h, l")))))] + "" + { + static const char fmt[] = "F\\tGET\\t%0, [%1+%2]\\t%@ (*lodz SI rma OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +;; zero_extend loads to SI from EXTSI mode using base+offset6 +(define_insn "*lodz_si_rmi" + [(set (match_operand:SI 0 "metag_register_op" "=cr") + (zero_extend:SI + (mem:EXTSI + (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "da") + (match_operand:SI 2 "metag_offset6_" "")))))] + "" + { + static const char fmt[] = "F\\tGET\\t%0, [%1+%2]\\t%@ (*lodz SI rmi OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +;; zero_extend loads to SI from EXTSI mode using base+offset12 +(define_insn "*lodz_si_rmi" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da, da") + (zero_extend:SI + (mem:EXTSI + (plus:SI (match_operand:SI 1 "metag_reg12bit_op" "da, Yr") + (match_operand:SI 2 "metag_offset12_" ",")))))] + "" + "GET\\t%0, [%1+%2]\\t%@ (*lodz SI rmi OK)" + [(set_attr "type" "load")]) + +;; zero_extend loads to SI from EXTSI mode using base++index +(define_insn "*lodz_si_rmab" + [(set (match_operand:SI 3 "metag_register_op" "=cr,cr,cr,cr") + (zero_extend:SI + (mem:EXTSI + (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "%0, 0, 0, 0") + (match_operand:SI 2 "metag_regnofrm_op" "e, f, h, l"))))) + (set (match_operand:SI 0 "metag_regnofrm_op" "=e, f, h, l") + (plus:SI (match_dup 1) + (match_dup 2)))] + "0" + { + static const char fmt[] = "F\\tGET\\t%3, [%1++%2]\\t%@ (*lodz SI rmab OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[3])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +;; zero_extend loads to SI from EXTSI mode using base++increment +(define_insn "*lodz_si_rmib" + [(set (match_operand:SI 3 "metag_register_op" "=cr") + (zero_extend:SI + (mem:EXTSI + (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "0") + (match_operand:SI 2 "metag_offset6_" ""))))) + (set (match_operand:SI 0 "metag_regnofrm_op" "=da") + (plus:SI (match_dup 1) + (match_dup 2)))] + "0" + { + static const char fmt[] = "F\\tGET\\t%3, [%1++%2]\\t%@ (*lodz SI rmib OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[3])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +;; ----------------------------------------------------------------------------- + +;; ----------------------------------------------------------------------------- +;; | Matching zero extend loads to SI post/pre_inc/dec/modify | +;; ----------------------------------------------------------------------------- + +(define_insn "*lodz_si_post_inc" + [(set (match_operand:SI 0 "metag_register_op" "=cr") + (zero_extend:SI (mem:EXTSI + (post_inc:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da")))))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tGET\\t%0, [%1++]\\t%@ (*lodz SI post_inc OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lodz_si_post_dec" + [(set (match_operand:SI 0 "metag_register_op" "=cr") + (zero_extend:SI (mem:EXTSI + (post_dec:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da")))))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tGET\\t%0, [%1--]\\t%@ (*lodz SI post_dec OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lodz_si_pre_inc" + [(set (match_operand:SI 0 "metag_register_op" "=cr") + (zero_extend:SI (mem:EXTSI + (pre_inc:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da")))))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tGET\\t%0, [++%1]\\t%@ (*lodz SI pre_inc OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lodz_si_pre_dec" + [(set (match_operand:SI 0 "metag_register_op" "=cr") + (zero_extend:SI (mem:EXTSI + (pre_dec:SI (match_operand:SI 1 "metag_reg_nofloat_op" "+da")))))] + "TARGET_METAC_1_1" + { + static const char fmt[] = "F\\tGET\\t%0, [--%1]\\t%@ (*lodz SI pre_dec OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lodz_si_post_modify_disp" + [(set (match_operand:SI 0 "metag_register_op" "=r") + (zero_extend:SI (mem:EXTSI + (post_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+da") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_offset6_" ""))))))] + "" + "GET\\t%0, [%1+%2++]\\t%@ (*lodz SI post_modify_disp OK)" + [(set_attr "type" "load")]) + +(define_insn "*lodz_si_post_modify_reg" + [(set (match_operand:SI 0 "metag_register_op" "=cr,cr,cr,cr") + (zero_extend:SI (mem:EXTSI + (post_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+e, f, h, l") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_reg_nofloat_op" "e, f, h, l"))))))] + "" + { + static const char fmt[] = "F\\tGET\\t%0, [%1+%2++]\\t%@ (*lodz SI post_modify_reg OK)"; + + return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2]; + } + [(set_attr "type" "load")]) + +(define_insn "*lodz_si_pre_modify_disp" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (zero_extend:SI (mem:EXTSI + (pre_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+da") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_offset6_" ""))))))] + "" + "GET\\t%0, [%1++%2]\\t%@ (*load SI pre_modify_disp OK)" + [(set_attr "type" "load")]) + +(define_insn "*lodz_si_pre_modify_reg" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da,da,da,da") + (zero_extend:SI (mem:EXTSI + (pre_modify:SI + (match_operand:SI 1 "metag_reg_nofloat_op" "+e, f, h, l") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_reg_nofloat_op" "e, f, h, l"))))))] + "" + "GET\\t%0, [%1++%2]\\t%@ (*loadz SI pre_modify_reg OK)" + [(set_attr "type" "load")]) + +;; zero_extend loads to SI from EXTSI mode - rest expanded as AND operations +(define_insn "*lodz_si" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (zero_extend:SI (match_operand:EXTSI 1 "memory_operand" "m")))] + "" + "GET\\t%0, %1\\t%@ (*lodz SI rm OK)" + [(set_attr "type" "load")]) + +;; ----------------------------------------------------------------------------- + +;; Sign extend register to SI mode register moves +(define_insn "*sign_extend_si" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=d,e,f") + (sign_extend:SI (match_operand:EXTSI 1 "metag_reg_nofloat_op" "0,e,f")))] + "" + "@ + XSD\\t%0, %1\\t\\t%@ (*ext SI d0 OK) + XSD\\t%0, %1\\t\\t%@ (*ext SI ee OK) + XSD\\t%0, %1\\t\\t%@ (*ext SI ff OK)" + [(set_attr "type" "fast,fast,fast")]) + +(define_insn "*sign_extend_hisi_" + [(set (reg: CC_REG) + (compare:CCZNC + (sign_extend:SI (match_operand:HI 1 "metag_datareg_op" "0,e,f")) + (const_int 0))) + (set (match_operand:SI 0 "metag_datareg_op" "=d,e,f") + (sign_extend:SI (match_dup 1)))] + "" + "XSDSW\\t%0, %1\\t\\t%@ (*exts HI SI dd OK)" + [(set_attr "type" "fast") + (set_attr "ccstate" "set")]) + +(define_insn "*sign_extend_qisi_" + [(set (reg: CC_REG) + (compare:CCZNC + (sign_extend:SI (match_operand:QI 1 "metag_datareg_op" "0,e,f")) + (const_int 0))) + (set (match_operand:SI 0 "metag_datareg_op" "=d,e,f") + (sign_extend:SI (match_dup 1)))] + "" + "XSDSB\\t%0, %1\\t\\t%@ (*exts QI SI dd OK)" + [(set_attr "type" "fast") + (set_attr "ccstate" "set")]) + +;; bit field instructions + + +;; Low overhead loop support +;; operand 0 is the loop count pseudo register +;; operand 1 is the number of loop iterations or 0 if it is unknown +;; operand 2 is the maximum number of loop iterations or -1 if unknown +;; operand 3 is the number of levels of enclosed loops +;; operand 4 is the label to jump to at the top of the loop +(define_expand "doloop_end" + [(use (match_operand 0 "" "")) + (use (match_operand:SI 1 "const_int_operand" "")) + (use (match_operand:SI 2 "const_int_operand" "")) + (use (match_operand:SI 3 "const_int_operand" "")) + (use (label_ref (match_operand 4 "" "")))] + "" + { + enum machine_mode mode = GET_MODE (operands[0]); + + if (mode == SImode && INTVAL (operands[3]) != -1) + { + unsigned HOST_WIDE_INT mask = GET_MODE_MASK (mode); + unsigned HOST_WIDE_INT num_iterations = INTVAL (operands[1]) & mask; + unsigned HOST_WIDE_INT max_iterations = INTVAL (operands[2]) & mask; + unsigned HOST_WIDE_INT limit = INTVAL (gen_int_mode (0xFFFFFFFF, SImode)) & mask; + + if (!(num_iterations > limit || (num_iterations == 0 && max_iterations > limit))) + { + emit_jump_insn (gen_br_si_txrpt (operands[4], operands[0])); + DONE; + } + } + + FAIL; + } +) + +(define_insn "br_si_txrpt" + [(set (pc) + (if_then_else (ne (match_operand:SI 1 "metag_txrpt_op" "+Wx") + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (const_int -1))) + (clobber (reg:CC_NOOV CC_REG))] + "" + "BR\\t%c0" + [(set_attr "type" "branch") + (set_attr "ccstate" "ccx")]) + + +;; conditional branch instruction generators; expand previous compare + +(define_expand "b" + [(set (pc) + (if_then_else (CCANYCOND (match_dup 1) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + { + if (!gen_metag_compare (, operands, 1)) + FAIL; + } +) + +;; patterns to match conditional branch insns + +(define_insn "*b" + [(set (pc) + (if_then_else (match_operator 1 "comparison_operator" + [(match_operand:CCALL 2 "metag__reg" "") + (const_int 0)]) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + { + if (metag_consume_branch (insn)) + return ""; + + return "B%z1\\t%c0\\t\\t\\t%@ (*b OK)"; + } + [(set_attr "type" "branch") + (set_attr "ccstate" "xcc")]) + +(define_insn "*b_reversed" + [(set (pc) + (if_then_else (match_operator 1 "comparison_operator" + [(match_operand:CCALL 2 "metag__reg" "") + (const_int 0)]) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + { + if (metag_consume_branch (insn)) + return ""; + + return "B%Z1\\t%c0\\t\\t\\t%@ (*b rev OK)"; + } + [(set_attr "type" "branch") + (set_attr "ccstate" "xcc")]) + +;; condition status evaluation +(define_expand "s" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "") + (CCANYCOND:SI (match_dup 1) + (const_int 0)))] + "" + { + if (!gen_metag_compare (, operands, 1)) + FAIL; + } +) + +;; patterns to match condition status insns +(define_insn_and_split "*movsi_m" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (match_operator:SI 1 "comparison_operator" + [(match_operand:CCALL 2 "metag__reg" "") + (const_int 0)]))] + "" + "#" + "reload_completed" + [(set (match_dup 0) + (const_int 0)) + (set (match_dup 0) + (if_then_else:SI (match_op_dup 1 [(match_dup 2) + (const_int 0)]) + (plus:SI (match_dup 0) + (const_int 1)) + (match_dup 0)))] + "" + [(set_attr "type" "two") + (set_attr "ccstate" "xcc")]) + +(define_insn_and_split "*movsi_negm" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (neg:SI (match_operator:SI 1 "comparison_operator" + [(match_operand:CCALL 2 "metag__reg" "") + (const_int 0)])))] + "" + "#" + "reload_completed" + [(set (match_dup 0) + (const_int 0)) + (set (match_dup 0) + (if_then_else:SI (match_op_dup 1 [(match_dup 2) + (const_int 0)]) + (plus:SI (match_dup 0) + (const_int -1)) + (match_dup 0)))] + "" + [(set_attr "type" "two") + (set_attr "ccstate" "xcc")]) + +(define_insn_and_split "*movsi_notm" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (not:SI (match_operator:SI 1 "comparison_operator" + [(match_operand:CCALL 2 "metag__reg" "") + (const_int 0)])))] + "" + "#" + "reload_completed" + [(set (match_dup 0) + (const_int 0)) + (set (match_dup 0) + (if_then_else:SI (match_op_dup 1 [(match_dup 2) + (const_int 0)]) + (plus:SI (match_dup 0) + (const_int -2)) + (match_dup 0)))] + "" + [(set_attr "type" "two") + (set_attr "ccstate" "xcc")]) + +;; call instructions - can handle call to symbol hence special predicate +(define_expand "sibcall" + [(parallel [(call (match_operand:QI 0 "metag_call_addr" "") + (match_operand 1 "" "")) + (unspec [(const_int 0)] UNSPEC_SIBCALL)])] + "" + { + if (GET_CODE (operands[0]) != MEM) + { + rtx tmp = gen_rtx_REG (SImode, D0Re0_REG); + + emit_move_insn (tmp, operands[0]); + operands[0] = tmp; + } + } +) + +(define_expand "call" + [(call (match_operand:QI 0 "metag_call_addr" "") + (match_operand 1 "" ""))] + "" + "") + +(define_expand "call_value" + [(set (match_operand 0 "metag_reg_nofloat_op" "") + (call (match_operand:QI 1 "metag_call_addr" "") + (match_operand 2 "" "")))] + "" + "") + +(define_expand "sibcall_value" + [(parallel [(set (match_operand 0 "metag_reg_nofloat_op" "") + (call (match_operand:QI 1 "metag_call_addr" "") + (match_operand 2 "" ""))) + (unspec [(const_int 0)] UNSPEC_SIBCALL_VALUE)])] + "" + { + if (GET_CODE (operands[1]) != MEM) + { + rtx tmp = gen_rtx_REG (SImode, D1Re0_REG); + + emit_move_insn (tmp, operands[1]); + operands[1] = tmp; + } + } +) + +(define_insn "*sibcall_reg" + [(call (mem:QI (match_operand:SI 0 "metag_addrreg_op" "a")) + (match_operand:SI 1 "immediate_operand" "")) + (unspec [(const_int 0)] UNSPEC_SIBCALL)] + "" + "MOV\\tPC, %0" + [(set_attr "type" "unknown")]) + +(define_insn "*call_reg" + [(call (mem:QI (match_operand:SI 0 "metag_reg_nofloat_op" "da")) + (match_operand:SI 1 "immediate_operand" ""))] + "" + "* + return output_call (operands, 0);" + [(set_attr "type" "unknown") + (set_attr "length" "8")]) + +(define_insn "*sibcall_value_reg" + [(set (match_operand 0 "metag_reg_nofloat_op" "=da") + (call (mem:QI (match_operand:SI 1 "metag_addrreg_op" "a")) + (match_operand:SI 2 "immediate_operand" ""))) + (unspec [(const_int 0)] UNSPEC_SIBCALL_VALUE)] + "" + "MOV\\tPC, %1" + [(set_attr "type" "unknown")]) + +(define_insn "*call_value_reg" + [(set (match_operand 0 "metag_reg_nofloat_op" "=da") + (call (mem:QI (match_operand:SI 1 "metag_reg_nofloat_op" "da")) + (match_operand:SI 2 "immediate_operand" "")))] + "" + "* + return output_call (operands, 1);" + [(set_attr "type" "unknown") + (set_attr "length" "8")]) + +(define_insn "*sibcall_sym" + [(call (mem:QI (match_operand:SI 0 "symbolic_operand" "")) + (match_operand:SI 1 "immediate_operand" "")) + (unspec [(const_int 0)] UNSPEC_SIBCALL)] + "" + "* + return output_sibcall (operands, 0);" + [(set_attr "type" "branch") + (set_attr "length" "8")]) + +(define_insn "*call_sym" + [(call (mem:QI (match_operand:SI 0 "symbolic_operand" "")) + (match_operand:SI 1 "immediate_operand" ""))] + "" + "* + return output_call (operands, 0);" + [(set_attr "type" "unknown") + (set (attr "length") + (if_then_else + (eq (symbol_ref "metag_tbiassert_p (operands[0])") (const_int 0)) + (const_int 8) + (const_int 12)))]) + +(define_insn "*sibcall_value_sym" + [(set (match_operand 0 "metag_reg_nofloat_op" "=da") + (call (mem:QI (match_operand:SI 1 "symbolic_operand" "")) + (match_operand:SI 2 "immediate_operand" ""))) + (unspec [(const_int 0)] UNSPEC_SIBCALL_VALUE)] + "" + "* + return output_sibcall (operands, 1);" + [(set_attr "type" "branch") + (set_attr "length" "8")]) + +(define_insn "*call_value_sym" + [(set (match_operand 0 "metag_reg_nofloat_op" "=da") + (call (mem:QI (match_operand:SI 1 "symbolic_operand" "")) + (match_operand:SI 2 "immediate_operand" "")))] + "" + "* + return output_call (operands, 1);" + [(set_attr "type" "unknown") + (set (attr "length") + (if_then_else + (eq (symbol_ref "metag_tbiassert_p (operands[1])") (const_int 0)) + (const_int 8) + (const_int 12)))]) + +;; Return instruction +(define_insn "return_internal" + [(use (reg:SI D1RtP_REG)) + (return)] + "" + { + /* META 2 and unconditional return and no return stub emitted */ + if (!metag_cond_exec_p () + && current_insn_predicate == NULL_RTX + && TARGET_METAC_2_1 + && cfun->machine->cond_return_state != METAG_COND_RETURN_DONE) + return metag_gen_cond_return_stub (); + else if (!TARGET_METAC_2_1 /* META 1.2 or unconditional returns */ + || (!metag_cond_exec_p () + && current_insn_predicate == NULL_RTX)) + return "MOV%?\\tPC, D1RtP"; + else + return metag_gen_cond_return_branch ("B%%?\\t$LX%d %%@\\t(* cond return stub)"); + } + [(set_attr "type" "unknown") + (set_attr "cond" "yes")]) + +(define_insn "return_internal_cond_" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand:CCANY 1 "metag__reg" "") + (unspec [(const_int 0)] UNSPEC_RET_COND)]) + (return) + (pc)))] + "" + { + if (!TARGET_METAC_2_1) + return "MOV%z0\\tPC, D1RtP"; + else + return metag_gen_cond_return_branch ("B%%z0\\t$LX%d %%@\\t(* cond return stub)"); + } + [(set_attr "type" "unknown")]) + +(define_insn "return_internal_cond_inverted_" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand:CCANY 1 "metag__reg" "") + (unspec [(const_int 0)] UNSPEC_RET_COND_INVERTED)]) + (pc) + (return)))] + "" + { + if (!TARGET_METAC_2_1) + return "MOV%Z0\\tPC, D1RtP"; + else + return metag_gen_cond_return_branch ("B%%Z0\\t$LX%d %%@\\t(* cond return stub)"); + } + [(set_attr "type" "unknown") + (set_attr "cond" "yes")]) + +(define_insn_and_split "return" + [(return)] + "METAG_USE_RETURN_INSN (false)" + "#" + "&& TRUE" + [(const_int 0)] + { + metag_expand_epilogue (false); + emit_jump_insn (gen_return_internal ()); + DONE; + } + [(set_attr "type" "unknown")]) + +(define_insn_and_split "*cond__return" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand:CCANY 1 "metag__reg" "") + (const_int 0)]) + (return) + (pc)))] + "METAG_USE_RETURN_INSN (true)" + "#" + "&& TRUE" + [(const_int 0)] + { + metag_expand_epilogue (false); + emit_jump_insn (gen_return_internal_cond_ (operands[0], operands[1])); + DONE; + } + [(set_attr "type" "unknown") + (set_attr "ccstate" "xcc")]) + +(define_insn_and_split "*cond__return_inverted" + [(set (pc) + (if_then_else (match_operator 0 "comparison_operator" + [(match_operand:CCANY 1 "metag__reg" "") + (const_int 0)]) + (pc) + (return)))] + "METAG_USE_RETURN_INSN (true)" + "#" + "&& TRUE" + [(const_int 0)] + { + metag_expand_epilogue (false); + emit_jump_insn (gen_return_internal_cond_inverted_ (operands[0], operands[1])); + DONE; + } + [(set_attr "type" "unknown") + (set_attr "ccstate" "xcc")]) + +;; No-op instruction + +(define_insn "nop" + [(const_int 0)] + "" + "NOP\\t\\t! (*nop OK)" + [(set_attr "type" "nop")]) + +(define_expand "casesi" + [(match_operand:SI 0 "metag_reg_nofloat_op" "") ; index to jump on + (match_operand:SI 1 "const_int_operand" "") ; lower bound + (match_operand:SI 2 "const_int_operand" "") ; total range + (match_operand:SI 3 "" "") ; table label + (match_operand:SI 4 "" "")] ; Out of range label + "" + { + rtx op5 = gen_reg_rtx (SImode); + rtx op6 = gen_reg_rtx (SImode); + + emit_insn (gen_addsi3 (op5, operands[0], gen_int_mode (-INTVAL (operands[1]), SImode))); + emit_insn (gen_cmpsi (op5, operands[2])); + emit_jump_insn (gen_bgtu (operands[4])); + + /* This code is intricate... + MiniM code can behave in three ways with respect to jump tables: + 1) Automatic analysis and branch instruction sizing (default) + 2) Forced short branch instructions + 3) Forced long branch instructions + + META code looks like MiniM short branches have been used but they are in fact + long branches. + + The first part of the following if block deals with all META cases and all MiniM + cases, unless long branches have been forced on. + + The second part of the if block deals with MTX 0.1 and MTX 1.2 without MiniM + enabled (this is 'classic MiniM') and also MiniM cases where long branches have + been forced. + */ + + if ((TARGET_METAC_1_0 || TARGET_METAC_1_1) /* A Meta 1.0, 1.1, 1.2 or 2.1 */ + && !TARGET_METAC_0_1 /* Not an MTX 0.1 */ + /* MiniM code but with short or automatic branches */ + && (!TARGET_MINIM || metag_jump_table_branch != METAG_MINIM_JUMP_TABLE_BRANCH_LONG) + && (!TARGET_MTX || TARGET_MINIM)) /* Either not an MTX 1.2 + or is an MTX 1.2 with MiniM */ + { + int offset = 4; + + /* The instruction that is 'jumped over' ADD PC, CPCx, is + always long encoded (see casesi_jmp) and can't be short encoded + so the initial jump is 8 rather than 4 in MiniM mode */ + + if (TARGET_MINIM) + offset = 8; + + /* For automatic jump table analysis use the special ashlsi insn */ + if (TARGET_MINIM && metag_jump_table_branch == METAG_MINIM_JUMP_TABLE_BRANCH_AUTO) + emit_insn (gen_jump_table_check_ashlsi3 (op6, op5, GEN_INT (2))); + else + emit_move_insn (op6, + gen_rtx_ASHIFT (SImode, op5, GEN_INT (2))); + + emit_insn (gen_addsi3 (op6, op6, gen_int_mode (offset, SImode))); + } + /* An MTX 0.1 or MiniM code with long branches or an MTX 1.2 (without MiniM) */ + else if (TARGET_METAC_0_1 || TARGET_MINIM || TARGET_MTX) + { + emit_move_insn (op6, + gen_rtx_ASHIFT (SImode, op5, GEN_INT (3))); + emit_insn (gen_addsi3 (op6, op6, GEN_INT (8))); + } + else + gcc_unreachable (); + + emit_jump_insn (gen_casesi_jmp (op6, operands[3])); + + DONE; + } +) + +(define_insn "jump_table_check_ashlsi3" + [(set (match_operand:SI 0 "metag_register_op" "=e,e,f,f,r,r,r,r") + (ashift:SI (match_operand:SI 1 "metag_reg_nofloat_op" "e,e,f,f,e,e,f,f") + (unspec:SI [(match_operand:SI 2 "metag_regorint_op" "e,L,f,L,e,L,f,L")] UNSPEC_MINIM_JUMP_TABLE)))] + "TARGET_MINIM" + { + /* Detect if short branches are permitted in this function */ + /* WORK NEEDED: This only needs to take place once per function just + before emitting instructions */ + metag_can_use_short_branch (); + + operands[2] = GEN_INT (cfun->machine->can_use_short_branch ? 2 : 3); + + return "LSL%?\\t%0, %1, %2\\t%@ (*ashl si rrx OK)"; + } + [(set_attr "type" "fast,fast,fast,fast,slow,slow,slow,slow") + (set_attr "cond" "yes,yes,yes,yes,no,no,no,no")]) + +;; The USE in this pattern is needed to tell flow analysis that this is +;; a CASESI insn. It has no other purpose. +(define_insn "casesi_jmp" + [(parallel + [(set (pc) + (plus:SI (pc) + (match_operand:SI 0 "metag_addrreg_op" "h,l"))) + (use (label_ref (match_operand 1 "" "")))])] + "" + { + /* These instructions are guaranteed to be long encoded as there are + no possible short encodings. However for clarity they are forced + long */ + static const char* fmt; + + if (which_alternative == 0) + fmt = "XL\\tADD\\tPC, CPC0, %0\\t%@ ... OK)"; + else + fmt = "XL\\tADD\\tPC, CPC1, %0\\t%@ ... OK)"; + + return &fmt[TARGET_MINIM ? 0 : 3]; + } + [(set_attr "type" "branch")]) + +;; jump instructions +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + { + if (metag_consume_branch (insn)) + return ""; + + return "B%?\\t%c0\\t\\t\\t%@ (*b ... OK)"; + } + [(set_attr "type" "branch") + (set_attr "cond" "yes") + (set_attr "predicable" "yes")]) + +(define_expand "indirect_jump" + [(set (pc) + (match_operand:SI 0 "address_operand" "p"))] + "" + { + if (!REG_P (operands[0])) + { + /* Can only jump to register, see reg_jump below */ + rtx reg = gen_reg_rtx (SImode); + + emit_move_insn (reg, operands[0]); + operands[0] = reg; + } + } +) + +(define_insn "*reg_jump" + [(set (pc) + (match_operand:SI 0 "metag_register_op" "r"))] + "" + "MOV%?\\tPC, %0\\t\\t%@ (*j r OK)" + [(set_attr "type" "branch") + (set_attr "cond" "yes") + (set_attr "predicable" "yes")]) + +(define_insn "load_pic" + [(set (match_operand:SI 0 "register_operand" "=X") + (unspec:SI [(match_operand:SI 1 "register_operand" "X")] UNSPEC_PIC_BASE))] + "" + "ADDT\\t%0, %1, #HI(__GLOBAL_OFFSET_TABLE__)\\t\\n\\tADD\\t%0, %0, #LO(__GLOBAL_OFFSET_TABLE__ + 4)" + [(set_attr "type" "two") + (set_attr "ccstate" "ncc") + (set_attr "rename" "no")]) + +(include "vector.md") +(include "builtins.md") + +(include "peephole2.md") +(include "dsppeephole2.md") + +(include "peephole.md") +(include "dsppeephole.md") + +(include "combines.md") +(include "fp.md") + +(include "tls.md") + +;; The 6bit frame elimination insns below intentionally have 12bit predicates on +;; their operands in the hope that the sum 'reduces' this value to fit a 6bit +;; value + +;; stores +(define_insn_and_split "*store__via_frame_elimination_6bit" + [(set (mem:MODES (plus:SI (plus:SI (match_operand:SI 0 "metag_reg_nofloat_op" "da") + (match_operand:SI 1 "metag_offset12_" "")) + (match_operand:SI 2 "metag_offset12_" ""))) + (match_operand: 3 "metag_register_op" "r"))] + "(reload_in_progress || reload_completed) + && metag_offset6_ (GEN_INT (INTVAL (operands[1]) + INTVAL (operands[2])), SImode)" + "#" + "reload_completed" + [(set (mem: (plus:SI (match_dup 0) + (match_dup 4))) + (match_dup 3))] + { + operands[4] = GEN_INT (INTVAL (operands[1]) + INTVAL (operands[2])); + } +) + +(define_insn_and_split "*store__via_frame_elimination_12bit" + [(set (mem:MODES (plus:SI (plus:SI (match_operand:SI 0 "metag_reg12bit_op" "Yr") + (match_operand:SI 1 "metag_offset12_" "")) + (match_operand:SI 2 "metag_offset12_" ""))) + (match_operand: 3 "metag_register_op" "r"))] + "(reload_in_progress || reload_completed) + && metag_offset12_ (GEN_INT (INTVAL (operands[1]) + INTVAL (operands[2])), SImode)" + "#" + "reload_completed" + [(set (mem: (plus:SI (match_dup 0) + (match_dup 4))) + (match_dup 3))] + { + operands[4] = GEN_INT (INTVAL (operands[1]) + INTVAL (operands[2])); + } +) + +;; loads + +(define_insn_and_split "*load__frame_elimination_6bit" + [(set (match_operand: 0 "metag_register_op" "=r") + (mem:MODES (plus:SI (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "da") + (match_operand:SI 2 "metag_offset12_" "")) + (match_operand:SI 3 "metag_offset12_" ""))))] + "(reload_in_progress || reload_completed) + && metag_offset6_ (GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3])), SImode)" + "#" + "reload_completed" + [(set (match_dup 0) + (mem: (plus:SI (match_dup 1) + (match_dup 4))))] + { + operands[4] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3])); + } +) + +(define_insn_and_split "*load__frame_elimination_12bit" + [(set (match_operand: 0 "metag_register_op" "=r") + (mem:MODES (plus:SI (plus:SI (match_operand:SI 1 "metag_reg12bit_op" "Yr") + (match_operand:SI 2 "metag_offset12_" "")) + (match_operand:SI 3 "metag_offset12_" ""))))] + "(reload_in_progress || reload_completed) + && metag_offset12_ (GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3])), SImode)" + "#" + "reload_completed" + [(set (match_dup 0) + (mem: (plus:SI (match_dup 1) + (match_dup 4))))] + { + operands[4] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3])); + } +) + +;; load zero extend to SI +(define_insn_and_split "*loadz_si_frame_elimination_6bit" + [(set (match_operand:SI 0 "metag_register_op" "=r") + (zero_extend:SI + (mem:EXTSI (plus:SI (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "da") + (match_operand:SI 2 "metag_offset12_" "")) + (match_operand:SI 3 "metag_offset12_" "")))))] + "(reload_in_progress || reload_completed) + && metag_offset6_ (GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3])), SImode)" + "#" + "reload_completed" + [(set (match_dup 0) + (zero_extend:SI + (mem: (plus:SI (match_dup 1) + (match_dup 4)))))] + { + operands[4] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3])); + } +) + +(define_insn_and_split "*loadz_si_frame_elimination_12bit" + [(set (match_operand:SI 0 "metag_register_op" "=r") + (zero_extend:SI + (mem:EXTSI (plus:SI (plus:SI (match_operand:SI 1 "metag_reg12bit_op" "Yr") + (match_operand:SI 2 "metag_offset12_" "")) + (match_operand:SI 3 "metag_offset12_" "")))))] + "(reload_in_progress || reload_completed) + && metag_offset12_ (GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3])), SImode)" + "#" + "reload_completed" + [(set (match_dup 0) + (zero_extend:SI + (mem: (plus:SI (match_dup 1) + (match_dup 4)))))] + { + operands[4] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3])); + } +) + +;; load zero extend to HI +(define_insn_and_split "*loadz_hi_frame_elimination_6bit" + [(set (match_operand:HI 0 "metag_register_op" "=r") + (zero_extend:HI + (mem:EXTHI (plus:SI (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "da") + (match_operand:SI 2 "metag_offset12_" "")) + (match_operand:SI 3 "metag_offset12_" "")))))] + "(reload_in_progress || reload_completed) + && metag_offset6_ (GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3])), SImode)" + "#" + "reload_completed" + [(set (match_dup 0) + (zero_extend:HI + (mem: (plus:SI (match_dup 1) + (match_dup 4)))))] + { + operands[4] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3])); + } +) + +(define_insn_and_split "*loadz_hi_frame_elimination_12bit" + [(set (match_operand:HI 0 "metag_register_op" "=r") + (zero_extend:HI + (mem:EXTHI (plus:SI (plus:SI (match_operand:SI 1 "metag_reg12bit_op" "Yr") + (match_operand:SI 2 "metag_offset12_" "")) + (match_operand:SI 3 "metag_offset12_" "")))))] + "(reload_in_progress || reload_completed) + && metag_offset12_ (GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3])), SImode)" + "#" + "reload_completed" + [(set (match_dup 0) + (zero_extend:HI + (mem: (plus:SI (match_dup 1) + (match_dup 4)))))] + { + operands[4] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3])); + } +) + +(define_insn "*sto__reload" + [(set (mem:MODES (plus:SI (match_operand:SI 0 "metag_reg_nofloat_op" "e,f,h,l") + (match_operand:SI 1 "const_int_operand" "n,n,n,n"))) + (match_operand: 2 "metag_register_op" "t,u,y,z"))] + "!TARGET_METAC_1_1 && reload_in_progress && REGNO (operands[0]) == FRAME_POINTER_REGNUM" + "#" + [(set_attr "type" "fast")]) + +(define_insn "*sto__1_1_reload" + [(set (mem:MODES (plus:SI (match_operand:SI 0 "metag_reg_nofloat_op" "da") + (match_operand:SI 1 "const_int_operand" "n"))) + (match_operand: 2 "metag_register_op" "r"))] + "TARGET_METAC_1_1 && reload_in_progress && REGNO (operands[0]) == FRAME_POINTER_REGNUM" + "#" + [(set_attr "type" "fast")]) + +(define_insn "*load__reload" + [(set (match_operand: 0 "metag_register_op" "=r") + (mem:MODES (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "da") + (match_operand:SI 2 "const_int_operand" "n"))))] + "reload_in_progress && REGNO (operands[1]) == FRAME_POINTER_REGNUM" + "#" + [(set_attr "type" "load")]) + +(define_insn "*loadz_si_reload" + [(set (match_operand:SI 0 "metag_register_op" "=r") + (zero_extend:SI + (mem:EXTSI (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "da") + (match_operand:SI 2 "const_int_operand" "n")))))] + "reload_in_progress && REGNO (operands[1]) == FRAME_POINTER_REGNUM" + "#" + [(set_attr "type" "load")]) + +(define_insn "*loadz_hi_reload" + [(set (match_operand:HI 0 "metag_register_op" "=r") + (zero_extend:HI + (mem:EXTHI (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "da") + (match_operand:SI 2 "const_int_operand" "n")))))] + "reload_in_progress && REGNO (operands[1]) == FRAME_POINTER_REGNUM" + "#" + [(set_attr "type" "load")]) + +(define_cond_exec + [(match_operator 0 "comparison_operator" + [(match_operand:CC 1 "metag_cc_reg" "") + (const_int 0)])] + "!metag_cond_exec_p ()" + "") + +;; end of file diff -Nur gcc-4.2.4.orig/gcc/config/metag/metag-modes.def gcc-4.2.4/gcc/config/metag/metag-modes.def --- gcc-4.2.4.orig/gcc/config/metag/metag-modes.def 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/metag-modes.def 2015-07-03 18:46:05.749283542 -0500 @@ -0,0 +1,37 @@ +/* Definitions of target machine for GNU compiler, for META + Copyright (C) 2007, 2008 Imagination Technologies Ltd + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + + +/* CC_NOOV mode should be used with SImode integer equalities. + CC_Z mode should be used if only the Z zero flag is set correctly + CC_N mode should be used if only the N sign flag is set correctly + CC_O mode should be used if only the O overflow flag is set correctly + CC_C mode should be used if only the C carry flag is set correctly + CC mode should be used otherwise. */ + +CC_MODE (CC_NOOV); +CC_MODE (CC_Z); +CC_MODE (CC_N); +CC_MODE (CC_O); +CC_MODE (CC_C); +CC_MODE (CC_FP); +CC_MODE (CC_FP_Q); + +VECTOR_MODE (INT, SI, 2); +VECTOR_MODE (FLOAT, SF, 2); diff -Nur gcc-4.2.4.orig/gcc/config/metag/metag.opt gcc-4.2.4/gcc/config/metag/metag.opt --- gcc-4.2.4.orig/gcc/config/metag/metag.opt 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/metag.opt 2015-07-03 18:46:05.773283541 -0500 @@ -0,0 +1,135 @@ +; Copyright (C) 2007, 2008 Imagination Technologies Ltd + +; This file is part of GCC. + +; GCC is free software; you can redistribute it and/or modify it under +; the terms of the GNU General Public License as published by the Free +; Software Foundation; either version 3, or (at your option) any later +; version. + +; GCC is distributed in the hope that it will be useful, but WITHOUT ANY +; WARRANTY; without even the implied warranty of MERCHANTABILITY or +; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +; for more details. + +; You should have received a copy of the GNU General Public License +; along with GCC; see the file COPYING3. If not see +; . + + +; Conditional execution can be checked for using TARGET_COND_EXEC_OPTIMIZE +; This allows the optimize flag to be checked as well as the COND_EXEC +; flag + +mcond-exec +Target Mask(COND_EXEC) +Enable conditional instructions. + +mbr-txrpt +Target Var(flag_branch_on_count_reg) VarExists +Enable use of low overhead loop instructions +Default: Enabled + +mhwloop +Target Var(flag_branch_on_count_reg) VarExists +Enable use of low overhead loop instructions +Default: Enabled + +mcharset= +Target RejectNegative Joined Var(metag_charset_string) Init("") +Specify the character set used by strcmp + +mextreg= +Target RejectNegative Joined Var(metag_extreg_string) Init("") +Specify the allowed extended registers in each unit (D0D1A0A1) +Default: 0000 + +mmetac= +Target RejectNegative Joined Var(metag_cpu_string) Init("") +Select Meta Core (0.1,1.0,1.1,1.2,2.1) + +mtune= +Target RejectNegative Joined Var(metag_tune_string) +Schedule for Meta Core (0.1,1.0,1.1,1.2,2.1) + +mmtx +Target RejectNegative Mask(MTX) UnDocumented +Target the MTX core family + +mminim +Target Mask(MINIM) +Optimise toward the core 16 bit MiniM instruction set and apply jump compression + +mminim-optimise +Target Mask(MINIM_OPTIMISE) +Apply MiniM optimisations. + +mhard-float +Target JoinedOrMissing Mask(FPU) Negative(msoft-float) RejectNegative +Enable generation of FPU instructions +=D Double precision support (default) +=S Single precision support +Implies -mregs-float=16 + +mflush-to-zero +Target Mask(FLUSH_TO_ZERO) +Disable instructions flushing to zero + +msoft-float +Target InverseMask(FPU) Negative(mhard-float) +Disable generation of FPU instructions (default) + +msimd-float +Target Mask(FPU_SIMD) +Enable SIMD FPU instructions (dual single precision operations) +Only permitted with -mhard-float[=D] + +maccumfp +Target Mask(FPU_ACCUM) +Enable generation of FPU accumulator instructions +Meta GCC does not use the FPU accumulator regardless of this option + +mregs-float= +Target RejectNegative Joined Var(metag_fpureg_string) Init("") +Specify the allowed floating point registers +Default: 0 + +mdsp +Target Mask(DSP) +Enable SIMD instructions (Requires DSP hardware thread). +Implies -mextreg=8844 + +mwidth= +Target RejectNegative Joined Var(metag_width_string) Init("") +Specify maximum width of a single memory access (32|64) + +mjump-table-branch= +Target RejectNegative Joined Var(metag_jump_table_string) Init("auto") UnDocumented +Specify the default branch size for jump tables in MiniM code +Only permitted with -mminim + +mtbictxsave +Target Mask(ECH) +Enable extended context saving +Allows DSP resources to be preserved in pre-emptive environments + +mcpu-config= +Target RejectNegative Joined Var(metag_config_file) Init("") +Specify a configuration file for setting default options + +mextensions= +Target RejectNegative Joined Var(metag_extensions_string) Init("") +Specify the permitted extensions to the core instruction set + +mhwtrace +Target Mask(HWTRACE) +Enable H/W instrumented tracing. + +mhwtrace-retpc +Target Mask(HWTRACE_RETPC) +Enable H/W instrumented tracing, including return addresses + +mhwtrace-leaf +Target Mask(HWTRACE_LEAF) +Enable H/W instrumented tracing, for all functions + diff -Nur gcc-4.2.4.orig/gcc/config/metag/metag-protos.h gcc-4.2.4/gcc/config/metag/metag-protos.h --- gcc-4.2.4.orig/gcc/config/metag/metag-protos.h 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/metag-protos.h 2015-07-03 18:46:05.749283542 -0500 @@ -0,0 +1,265 @@ +/* Definitions of target machine for GNU compiler. + Imagination Technologies Meta version. + Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2010 + Imagination Technologies Ltd + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +#include "target.h" +#include "tree.h" +#include "cpplib.h" + +#ifdef HAVE_ATTR_metacore +extern enum attr_metacore metacore; +#endif + +extern void metag_split_movsi_immediate (rtx []); +extern void metag_split_movdi (rtx []); +extern void metag_split_movdi_immediate (rtx []); +extern void metag_split_movdf (rtx []); +extern void metag_split_movdf_immediate (rtx []); +extern void metag_split_movsf (rtx []); +extern void metag_split_movsf_immediate (rtx []); +extern void metag_abort (rtx val) ATTRIBUTE_NORETURN; +extern int metag_search_rhs (rtx); +extern bool metag_cheap_return (bool); +extern int debug_metag_md (void); +extern unsigned int metag_mem_base (rtx); +extern bool metag_mem_base_p (rtx, enum reg_class); +extern void metag_override_options (void); +extern bool metag_valid_machine_decl_attribute (tree, tree, tree, tree); +extern bool metag_cond_exec_p (void); +extern void metag_print_cc_if_conditional (FILE *); +extern void metag_ccexec_label (const char *); +extern bool metag_consume_branch (rtx); + +extern void metag_init_expanders (void); + +extern bool metag_legitimate_reg_p (rtx, bool); + +extern bool metag_legitimate_regno_p (unsigned int, bool); + +extern bool metag_regs_ok_for_base_offset_p (rtx, rtx, bool); +extern bool metag_reg_ok_for_index_p (rtx, bool); + +extern bool metag_reg_ok_for_base_p (rtx, bool); +extern bool metag_reg_ok_for_offset_p (rtx, bool); + +extern bool metag_legitimate_address_p (rtx, enum machine_mode, bool); + +extern bool metag_legitimate_post_incdec_p (rtx, enum machine_mode, bool); +extern bool metag_legitimate_pre_incdec_p (rtx, enum machine_mode, bool); + +extern bool metag_legitimate_off_p (rtx, rtx, enum machine_mode, bool); + +extern bool metag_legitimate_twin_p (rtx, rtx, enum machine_mode, bool); + +extern bool metag_return_in_memory (tree); + +extern void output_fn_prologue (FILE *, int); +extern void output_fn_epilogue (FILE *, int); + +extern bool output_call_addr (rtx, enum machine_mode); +extern const char * output_sibcall (rtx [], unsigned int); +extern const char * output_call (rtx [], unsigned int); +extern bool metag_slow_store (rtx, rtx); +extern rtx metag_gen_safe_temp (enum machine_mode, rtx); +#ifdef RTX_CODE +extern enum machine_mode metag_select_cc_mode (RTX_CODE, rtx, rtx); +extern bool gen_metag_compare (RTX_CODE, rtx[], int); +#endif + +extern rtx metag_gen_load_multiple (unsigned int, unsigned int, enum machine_mode, rtx, bool, rtx, HOST_WIDE_INT *); +extern rtx metag_gen_store_multiple (unsigned int, unsigned int, enum machine_mode, rtx, bool, rtx, HOST_WIDE_INT *); +extern bool metag_gen_movmemqi (rtx []); + +extern void metag_final_prescan_insn (rtx); +extern int metag_initial_elimination_offset (int, int); +#ifdef CUMULATIVE_ARGS +extern void metag_function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode, tree, bool); +extern rtx metag_function_arg (CUMULATIVE_ARGS *, enum machine_mode, tree, bool); +#endif + +extern long metag_const_double_to_hp (rtx op, bool *inexact); + +extern void metag_function_profiler (FILE *); +#ifdef RTX_CODE +extern void metag_print_operand (FILE *, rtx, RTX_CODE); +#endif +extern void metag_print_operand_address (FILE *, rtx); + +extern void metag_asm_output_opcode (FILE *, const char *); + +extern bool metag_frame_related_rtx (rtx); +extern bool metag_symbolic_reference_mentioned_p (rtx); +extern bool metag_legitimate_pic_address_disp_p (rtx); +extern rtx metag_legitimize_pic_address (rtx, rtx); +extern rtx metag_legitimize_address (rtx, rtx, enum machine_mode); +extern int metag_letter_for_const (rtx); +extern bool metag_const_ok_for_letters_p (rtx, const char []); +extern bool metag_datareg_p (unsigned int); +extern bool metag_addrreg_p (unsigned int); +extern bool metag_fpcreg_p (unsigned int); +extern bool metag_fppreg_p (unsigned int); +extern bool metag_legitimate_modify_p (rtx, enum machine_mode, bool); + +extern bool metag_same_regclass_p (rtx, rtx); + +extern bool metag_regno_same_unit_p (unsigned int, unsigned int); + +extern bool metag_zeroextract_mask_p (rtx, rtx); + +extern rtx metag_return_addr_rtx (int, rtx); + +extern HOST_WIDE_INT metag_function_arg_boundary (enum machine_mode, tree); + +extern int metag_first_parm_offset (tree); + +extern bool metag_consumer_is_cond_p (rtx, rtx); + +extern bool metag_bypass_before_reload_p (rtx, rtx); + +extern bool metag_hard_regno_rename_ok_p (rtx, unsigned int, unsigned int); + +extern void metag_expand_prologue (void); +extern void metag_expand_epilogue (bool); + +extern enum reg_class metag_regno_reg_class_minimal (unsigned int); + +extern enum reg_class metag_regno_reg_class_unit (unsigned int); + +extern bool metag_use_return_insn (bool); + +extern bool metag_frame_pointer_required (void); + +extern void metag_setup_frame_addresses (void); + +extern void metag_expand_set_return_address (rtx); + +extern bool metag_doloop_loop_nest_optimized(struct loop *, struct doloopnest *); + +extern bool metag_doloop_check_any_nest_optimized (struct loop *, struct doloopnest *); + +extern void metag_doloop_mark_nests_optimized (struct loop *, struct doloopnest **); + +extern bool metag_current_function_loads_pic_register (void); + +extern rtx metag_legitimize_reload_address (rtx, enum machine_mode, int, int, int); + +extern bool metag_offset6_mode (rtx, enum machine_mode); + +extern bool metag_offset12_mode (rtx, enum machine_mode); + +extern bool metag_regno12bit_p (unsigned int); + +extern bool metag_split_early (void); + +extern bool metag_split_hi_lo_sum_early (void); + +extern bool metag_hard_regno_mode_ok (unsigned int, enum machine_mode); + +extern void metag_override_options_per_os (void); +extern bool metag_handle_option_per_os (size_t, const char *, int); +extern bool metag_function_ok_for_sibcall_per_os (tree, tree); + +/* These functions are part of a framework to allow the support of OS + specific builtin functions within GCC. */ +extern void metag_init_builtins_per_os (void); +extern rtx metag_expand_builtin_per_os (tree, rtx); +extern void metag_pad_function_call (rtx); +extern bool metag_tbiassert_p (rtx); + +extern void metag_internal_label (FILE *, const char *, unsigned long); +extern void metag_function_prologue (FILE *, HOST_WIDE_INT); +extern void metag_function_end_prologue (FILE *); +extern void metag_function_begin_epilogue (FILE *); +extern void metag_function_epilogue (FILE *, HOST_WIDE_INT); +extern void metag_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, + tree); +extern bool metag_can_output_mi_thunk (tree, HOST_WIDE_INT, HOST_WIDE_INT, + tree); +extern int metag_sched_adjust_cost (rtx, rtx, rtx, int); +extern bool metag_handle_option (size_t, const char *, int); +extern tree metag_merge_decl_attributes (tree, tree); +extern tree metag_merge_type_attributes (tree, tree); +extern const struct attribute_spec metag_attribute_table[]; +extern int metag_comp_type_attributes (tree, tree); +extern void metag_init_builtins (void); +extern rtx metag_expand_builtin (tree, rtx, rtx, enum machine_mode, int); +extern bool metag_function_ok_for_sibcall (tree, tree); +extern void metag_encode_section_info (tree, rtx, int); +extern bool metag_scalar_mode_supported_p (enum machine_mode); +extern bool metag_rtx_costs (rtx, int, int, int *); +extern int metag_address_cost (rtx); +extern void metag_machine_dependent_reorg (void); +extern tree metag_gimplify_va_arg_expr (tree, tree, tree *, tree *); +extern const char * metag_invalid_within_doloop (rtx); +extern bool metag_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode, tree, + bool); +extern void metag_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode, + tree, int *, int); +extern bool metag_must_pass_in_stack (enum machine_mode, tree); +extern int metag_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode, tree, + bool); +extern enum reg_class metag_secondary_reload (bool, rtx, enum reg_class, + enum machine_mode, + secondary_reload_info *); +extern bool metag_vector_mode_supported_p (enum machine_mode); +extern enum reg_class metag_secondary_reload_class (enum reg_class, + enum machine_mode, + rtx, bool); + +extern bool metag_output_addr_const_extra (FILE *, rtx); + +extern bool metag_dsp_ri16_operands (rtx[]); +extern bool metag_dsp_ri5_operands (rtx[]); +extern bool metag_dsp_rrr_operands (rtx[], bool); +extern bool metag_dsp_cmp_rrr_operands (rtx[], bool); +extern bool metag_dsp_cmp_ri16_operands (rtx[]); +extern bool metag_dsp_rrr_mov_operands (rtx[], bool); +extern bool metag_dsp_rri5_operands (rtx[]); +extern bool metag_dsp_rr_operands (rtx[]); +extern bool metag_dsp_cmp_rri5_operands (rtx[]); +extern bool metag_dsp_rr_rr_mov_operands (rtx[]); + +extern void metag_dsp_peephole2_rr_convert (rtx[]); +extern void metag_dsp_peephole2_rr_mov_convert (rtx[]); +extern void metag_dsp_peephole2_rrr_convert (rtx[]); +extern void metag_dsp_peephole2_rrr_mov_convert (rtx[]); +extern void metag_dsp_peephole2_ri16_convert (rtx[]); +extern void metag_dsp_peephole2_rri5_convert (rtx[]); + +extern bool metag_move_valid_p (rtx, rtx); +extern void metag_cpu_cpp_builtins (cpp_reader *); + +extern void metag_expand_didf2 (rtx, rtx); + +/* Handle the jump_table_branch pragma */ +extern void metag_pragma_jump_table_branch (struct cpp_reader *); +/* Handle the hwtrace_function pragma */ +extern void metag_pragma_hwtrace_function (struct cpp_reader *); + +extern bool metag_meta2_bex_enabled; +extern void metag_can_use_short_branch (void); +extern void metag_emit_move_sequence (rtx[], enum machine_mode); + +extern rtx metag_libcall_value (enum machine_mode); +extern rtx metag_function_value (tree, tree, bool); + +extern bool tls_symbolic_operand_p (rtx); +extern bool metag_bfd_tls_referenced_p (rtx); +extern rtx metag_bfd_legitimize_tls_address (rtx); diff -Nur gcc-4.2.4.orig/gcc/config/metag/peephole2.md gcc-4.2.4/gcc/config/metag/peephole2.md --- gcc-4.2.4.orig/gcc/config/metag/peephole2.md 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/peephole2.md 2015-07-03 18:46:05.773283541 -0500 @@ -0,0 +1,1324 @@ +;; Machine description for GNU compiler, +;; Imagination Technologies Meta version. +;; Copyright (C) 2007 +;; Imagination Technologies Ltd + +;; This file is part of GCC. + +;; GCC is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 3, or (at your option) any later +;; version. + +;; GCC is distributed in the hope that it will be useful, but WITHOUT ANY +;; WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; . + + +;; ====PRE_INC + +;; ---------------------------------------------------------------------------- +;; Recognising DI/SI/HI/QI store pre-inc/dec/modify +;; ---------------------------------------------------------------------------- + +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_register_op" ""))) + (set (match_operand:MODES 2 "memory_operand" "") + (match_operand: 3 "metag_register_op" ""))] + "metag_same_regclass_p (operands[0], operands[1]) + && !metag_same_regclass_p (operands[0], operands[3]) + && rtx_equal_p (operands[0], XEXP (operands[2], 0)) + && (GET_MODE_SIZE (mode) <= UNITS_PER_WORD + || !metag_same_regclass_p (operands[0], gen_rtx_REG (SImode, REGNO (operands[3]) + 1)))" + [(const_int 0)] + { + rtx plus = gen_rtx_PLUS (SImode, operands[0], operands[1]); + rtx pre_modify = gen_rtx_PRE_MODIFY (SImode, operands[0], plus); + rtx mem = gen_rtx_MEM (mode, pre_modify); + rtx insn = emit_insn (gen_rtx_SET (VOIDmode, mem, operands[3])); + + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[2]); + if (auto_inc_p (pre_modify)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (pre_modify, 0), REG_NOTES (insn)); + DONE; + } +) + +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_" ""))) + (set (match_operand:MODES 2 "memory_operand" "") + (match_operand: 3 "metag_register_op" ""))] + "rtx_equal_p (operands[0], XEXP (operands[2], 0))" + [(const_int 0)] + { + rtx pre, mem, insn; + + if (INTVAL (operands[1]) == GET_MODE_SIZE (mode)) + pre = gen_rtx_PRE_INC (SImode, operands[0]); + else if (INTVAL (operands[1]) == -GET_MODE_SIZE (mode)) + pre = gen_rtx_PRE_DEC (SImode, operands[0]); + else + { + rtx plus = gen_rtx_PLUS (SImode, operands[0], operands[1]); + + pre = gen_rtx_PRE_MODIFY (SImode, operands[0], plus); + } + + mem = gen_rtx_MEM (mode, pre); + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[2]); + insn = emit_insn (gen_rtx_SET (VOIDmode, mem, operands[3])); + + if (auto_inc_p (pre)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (pre, 0), REG_NOTES (insn)); + DONE; + } +) + +;; ---------------------------------------------------------------------------- + +;; ---------------------------------------------------------------------------- +;; Recognising DI/SI/HI/QI load pre-inc/dec/modify +;; ---------------------------------------------------------------------------- + +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_register_op" ""))) + (set (match_operand: 2 "metag_register_op" "") + (match_operand:MODES 3 "memory_operand" ""))] + "metag_same_regclass_p (operands[0], operands[1]) + && rtx_equal_p (operands[0], XEXP (operands[3], 0))" + [(const_int 0)] + { + rtx plus = gen_rtx_PLUS (SImode, operands[0], operands[1]); + rtx pre_modify = gen_rtx_PRE_MODIFY (SImode, operands[0], plus); + rtx mem = gen_rtx_MEM (mode, pre_modify); + rtx insn = emit_insn (gen_rtx_SET (VOIDmode, operands[2], mem)); + + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[3]); + + if (auto_inc_p (pre_modify)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (pre_modify, 0), REG_NOTES (insn)); + DONE; + } +) + +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_" ""))) + (set (match_operand: 2 "metag_register_op" "") + (match_operand:MODES 3 "memory_operand" ""))] + "rtx_equal_p (operands[0], XEXP (operands[3], 0))" + [(const_int 0)] + { + rtx pre, mem, insn; + + if (INTVAL (operands[1]) == GET_MODE_SIZE (mode)) + pre = gen_rtx_PRE_INC (SImode, operands[0]); + else if (INTVAL (operands[1]) == -GET_MODE_SIZE (mode)) + pre = gen_rtx_PRE_DEC (SImode, operands[0]); + else + { + rtx plus = gen_rtx_PLUS (SImode, operands[0], operands[1]); + + pre = gen_rtx_PRE_MODIFY (SImode, operands[0], plus); + } + + mem = gen_rtx_MEM (mode, pre); + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[3]); + insn = emit_insn (gen_rtx_SET (VOIDmode, operands[2], mem)); + + if (auto_inc_p (pre)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (pre, 0), REG_NOTES (insn)); + DONE; + } +) + +;; ---------------------------------------------------------------------------- + +;; ---------------------------------------------------------------------------- +;; Recognising zero extend SI load pre-inc/dec/modify +;; ---------------------------------------------------------------------------- + +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_register_op" ""))) + (set (match_operand:SI 2 "metag_register_op" "") + (zero_extend:SI + (match_operand:EXTSI 3 "memory_operand" "")))] + "metag_same_regclass_p (operands[0], operands[1]) + && rtx_equal_p (operands[0], XEXP (operands[3], 0))" + [(const_int 0)] + { + rtx plus = gen_rtx_PLUS (SImode, operands[0], operands[1]); + rtx pre_modify = gen_rtx_PRE_MODIFY (SImode, operands[0], plus); + rtx mem = gen_rtx_MEM (mode, pre_modify); + rtx zextend = gen_rtx_ZERO_EXTEND (SImode, mem); + rtx insn = emit_insn (gen_rtx_SET (VOIDmode, operands[2], zextend)); + + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[3]); + + if (auto_inc_p (pre_modify)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (pre_modify, 0), REG_NOTES (insn)); + DONE; + } +) + +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_" ""))) + (set (match_operand:SI 2 "metag_register_op" "") + (zero_extend:SI + (match_operand:EXTSI 3 "memory_operand" "")))] + "rtx_equal_p (operands[0], XEXP (operands[3], 0))" + [(const_int 0)] + { + rtx pre, mem, zextend, insn; + + if (INTVAL (operands[1]) == GET_MODE_SIZE (mode)) + pre = gen_rtx_PRE_INC (SImode, operands[0]); + else if (INTVAL (operands[1]) == -GET_MODE_SIZE (mode)) + pre = gen_rtx_PRE_DEC (SImode, operands[0]); + else + { + rtx plus = gen_rtx_PLUS (SImode, operands[0], operands[1]); + + pre = gen_rtx_PRE_MODIFY (SImode, operands[0], plus); + } + + mem = gen_rtx_MEM (mode, pre); + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[3]); + zextend = gen_rtx_ZERO_EXTEND (SImode, mem); + insn = emit_insn (gen_rtx_SET (VOIDmode, operands[2], zextend)); + + if (auto_inc_p (pre)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (pre, 0), REG_NOTES (insn)); + DONE; + } +) + +;; ---------------------------------------------------------------------------- +;; Recognising zero extend HI load pre-inc/dec/modify +;; ---------------------------------------------------------------------------- + +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_register_op" ""))) + (set (match_operand:HI 2 "metag_register_op" "") + (zero_extend:HI + (match_operand:EXTHI 3 "memory_operand" "")))] + "metag_same_regclass_p (operands[0], operands[1]) + && rtx_equal_p (operands[0], XEXP (operands[3], 0))" + [(const_int 0)] + { + rtx plus = gen_rtx_PLUS (SImode, operands[0], operands[1]); + rtx pre_modify = gen_rtx_PRE_MODIFY (SImode, operands[0], plus); + rtx mem = gen_rtx_MEM (mode, pre_modify); + rtx zextend = gen_rtx_ZERO_EXTEND (HImode, mem); + rtx insn = emit_insn (gen_rtx_SET (VOIDmode, operands[2], zextend)); + + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[3]); + + if (auto_inc_p (pre_modify)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (pre_modify, 0), REG_NOTES (insn)); + DONE; + } +) + +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_" ""))) + (set (match_operand:HI 2 "metag_register_op" "") + (zero_extend:HI + (match_operand:EXTHI 3 "memory_operand" "")))] + "rtx_equal_p (operands[0], XEXP (operands[3], 0))" + [(const_int 0)] + { + rtx pre, mem, zextend, insn; + + if (INTVAL (operands[1]) == GET_MODE_SIZE (mode)) + pre = gen_rtx_PRE_INC (SImode, operands[0]); + else if (INTVAL (operands[1]) == -GET_MODE_SIZE (mode)) + pre = gen_rtx_PRE_DEC (SImode, operands[0]); + else + { + rtx plus = gen_rtx_PLUS (SImode, operands[0], operands[1]); + + pre = gen_rtx_PRE_MODIFY (SImode, operands[0], plus); + } + + mem = gen_rtx_MEM (mode, pre); + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[3]); + zextend = gen_rtx_ZERO_EXTEND (HImode, mem); + insn = emit_insn (gen_rtx_SET (VOIDmode, operands[2], zextend)); + + if (auto_inc_p (pre)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (pre, 0), REG_NOTES (insn)); + DONE; + } +) +;; ====PRE_INC + +;; ====POST_INC + +;; ---------------------------------------------------------------------------- +;; Recognising DF/SF/DI/SI/HI/QI store post-inc/dec/modify +;; ---------------------------------------------------------------------------- + +(define_peephole2 + [(set (match_operand:MODES 0 "memory_operand" "") + (match_operand: 1 "metag_register_op" "")) + (set (match_operand:SI 2 "metag_register_op" "") + (plus:SI (match_dup 2) + (match_operand:SI 3 "metag_register_op" "")))] + "metag_same_regclass_p (operands[3], operands[2]) + && !metag_same_regclass_p (operands[2], operands[1]) + && rtx_equal_p (operands[2], XEXP (operands[0], 0)) + && (GET_MODE_SIZE (mode) <= UNITS_PER_WORD + || !metag_same_regclass_p (operands[2], gen_rtx_REG (SImode, REGNO (operands[1]) + 1)))" + [(const_int 0)] + { + rtx plus = gen_rtx_PLUS (SImode, operands[2], operands[3]); + rtx post_modify = gen_rtx_POST_MODIFY (SImode, operands[2], plus); + rtx mem = gen_rtx_MEM (mode, post_modify); + rtx insn = emit_insn (gen_rtx_SET (VOIDmode, mem, operands[1])); + + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[0]); + + if (auto_inc_p (post_modify)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (post_modify, 0), REG_NOTES (insn)); + DONE; + } +) + +(define_peephole2 + [(set (match_operand:MODES 0 "memory_operand" "") + (match_operand: 1 "metag_register_op" "")) + (set (match_operand:SI 2 "metag_register_op" "") + (plus:SI (match_dup 2) + (match_operand:SI 3 "metag_offset6_" "")))] + "rtx_equal_p (operands[2], XEXP (operands[0], 0))" + [(const_int 0)] + { + rtx post, mem, insn; + + if (INTVAL (operands[3]) == GET_MODE_SIZE (mode)) + post = gen_rtx_POST_INC (SImode, operands[2]); + else if (INTVAL (operands[3]) == -GET_MODE_SIZE (mode)) + post = gen_rtx_POST_DEC (SImode, operands[2]); + else + { + rtx plus = gen_rtx_PLUS (SImode, operands[2], operands[3]); + + post = gen_rtx_POST_MODIFY (SImode, operands[2], plus); + } + + mem = gen_rtx_MEM (mode, post); + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[0]); + insn = emit_insn (gen_rtx_SET (VOIDmode, mem, operands[1])); + + if (auto_inc_p (post)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (post, 0), REG_NOTES (insn)); + DONE; + } +) + +;; ---------------------------------------------------------------------------- + +;; ---------------------------------------------------------------------------- +;; Recognising DI/SI/HI/QI load post-inc/dec/modify +;; ---------------------------------------------------------------------------- + +(define_peephole2 + [(set (match_operand: 0 "metag_register_op" "") + (match_operand:MODES 1 "memory_operand" "")) + (set (match_operand:SI 2 "metag_register_op" "") + (plus:SI (match_dup 2) + (match_operand:SI 3 "metag_register_op" "")))] + "metag_same_regclass_p (operands[3], operands[2]) + && rtx_equal_p (operands[2], XEXP (operands[1], 0)) + && REGNO (operands[0]) != REGNO (operands[3]) + && REGNO (operands[0]) != REGNO (operands[2])" + [(const_int 0)] + { + rtx plus = gen_rtx_PLUS (SImode, operands[2], operands[3]); + rtx post_modify = gen_rtx_POST_MODIFY (SImode, operands[2], plus); + rtx mem = gen_rtx_MEM (mode, post_modify); + rtx insn = emit_insn (gen_rtx_SET (VOIDmode, operands[0], mem)); + + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[1]); + + if (auto_inc_p (post_modify)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (post_modify, 0), REG_NOTES (insn)); + DONE; + } +) + +(define_peephole2 + [(set (match_operand: 0 "metag_register_op" "") + (match_operand:MODES 1 "memory_operand" "")) + (set (match_operand:SI 2 "metag_register_op" "") + (plus:SI (match_dup 2) + (match_operand:SI 3 "metag_offset6_" "")))] + "REGNO (operands[0]) != REGNO (operands[2]) + && rtx_equal_p (operands[2], XEXP (operands[1], 0))" + [(const_int 0)] + { + rtx post, mem, insn; + + if (INTVAL (operands[3]) == GET_MODE_SIZE (mode)) + post = gen_rtx_POST_INC (SImode, operands[2]); + else if (INTVAL (operands[3]) == -GET_MODE_SIZE (mode)) + post = gen_rtx_POST_DEC (SImode, operands[2]); + else + { + rtx plus = gen_rtx_PLUS (SImode, operands[2], operands[3]); + + post = gen_rtx_POST_MODIFY (SImode, operands[2], plus); + } + + mem = gen_rtx_MEM (mode, post); + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[1]); + insn = emit_insn (gen_rtx_SET (VOIDmode, operands[0], mem)); + + if (auto_inc_p (post)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (post, 0), REG_NOTES (insn)); + DONE; + } +) + +;; ---------------------------------------------------------------------------- + +;; ---------------------------------------------------------------------------- +;; Recognising zero extend SI load post-modify +;; ---------------------------------------------------------------------------- + +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (zero_extend:SI + (match_operand:EXTSI 1 "memory_operand" ""))) + (set (match_operand:SI 2 "metag_register_op" "") + (plus:SI (match_dup 2) + (match_operand:SI 3 "metag_register_op" "")))] + "metag_same_regclass_p (operands[3], operands[2]) + && REGNO (operands[0]) != REGNO (operands[3]) + && REGNO (operands[0]) != REGNO (operands[2]) + && rtx_equal_p (operands[2], XEXP (operands[1], 0))" + [(const_int 0)] + { + rtx plus = gen_rtx_PLUS (SImode, operands[2], operands[3]); + rtx post_modify = gen_rtx_POST_MODIFY (SImode, operands[2], plus); + rtx mem = gen_rtx_MEM (mode, post_modify); + rtx zextend = gen_rtx_ZERO_EXTEND (SImode, mem); + rtx insn = emit_insn (gen_rtx_SET (VOIDmode, operands[0], zextend)); + + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[1]); + + if (auto_inc_p (post_modify)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (post_modify, 0), REG_NOTES (insn)); + DONE; + } +) + +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (zero_extend:SI + (match_operand:EXTSI 1 "memory_operand" ""))) + (set (match_operand:SI 2 "metag_register_op" "") + (plus:SI (match_dup 2) + (match_operand:SI 3 "metag_offset6_" "")))] + "REGNO (operands[0]) != REGNO (operands[2]) + && rtx_equal_p (operands[2], XEXP (operands[1], 0))" + [(const_int 0)] + { + rtx post, mem, zextend, insn; + + if (INTVAL (operands[3]) == GET_MODE_SIZE (mode)) + post = gen_rtx_POST_INC (SImode, operands[2]); + else if (INTVAL (operands[3]) == -GET_MODE_SIZE (mode)) + post = gen_rtx_POST_DEC (SImode, operands[2]); + else + { + rtx plus = gen_rtx_PLUS (SImode, operands[2], operands[3]); + + post = gen_rtx_POST_MODIFY (SImode, operands[2], plus); + } + + mem = gen_rtx_MEM (mode, post); + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[1]); + zextend = gen_rtx_ZERO_EXTEND (SImode, mem); + insn = emit_insn (gen_rtx_SET (VOIDmode, operands[0], zextend)); + + if (auto_inc_p (post)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (post, 0), REG_NOTES (insn)); + DONE; + } +) + +;; ---------------------------------------------------------------------------- +;; Recognising zero extend HI load post-inc/dec/modify +;; ---------------------------------------------------------------------------- + +(define_peephole2 + [(set (match_operand:HI 0 "metag_register_op" "") + (zero_extend:HI + (match_operand:EXTHI 1 "memory_operand" ""))) + (set (match_operand:SI 2 "metag_register_op" "") + (plus:SI (match_dup 2) + (match_operand:SI 3 "metag_register_op" "")))] + "metag_same_regclass_p (operands[3], operands[2]) + && REGNO (operands[0]) != REGNO (operands[3]) + && REGNO (operands[0]) != REGNO (operands[2]) + && rtx_equal_p (operands[2], XEXP (operands[1], 0))" + [(const_int 0)] + { + rtx plus = gen_rtx_PLUS (SImode, operands[2], operands[3]); + rtx post_modify = gen_rtx_POST_MODIFY (SImode, operands[2], plus); + rtx mem = gen_rtx_MEM (mode, post_modify); + rtx zextend = gen_rtx_ZERO_EXTEND (HImode, mem); + rtx insn = emit_insn (gen_rtx_SET (VOIDmode, operands[0], zextend)); + + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[1]); + + if (auto_inc_p (post_modify)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (post_modify, 0), REG_NOTES (insn)); + DONE; + } +) + +(define_peephole2 + [(set (match_operand:HI 0 "metag_register_op" "") + (zero_extend:HI + (match_operand:EXTHI 1 "memory_operand" ""))) + (set (match_operand:SI 2 "metag_register_op" "") + (plus:SI (match_dup 2) + (match_operand:SI 3 "metag_offset6_" "")))] + "REGNO (operands[0]) != REGNO (operands[2]) + && rtx_equal_p (operands[2], XEXP (operands[1], 0))" + [(const_int 0)] + { + rtx post, mem, zextend, insn; + + if (INTVAL (operands[3]) == GET_MODE_SIZE (mode)) + post = gen_rtx_POST_INC (SImode, operands[2]); + else if (INTVAL (operands[3]) == -GET_MODE_SIZE (mode)) + post = gen_rtx_POST_DEC (SImode, operands[2]); + else + { + rtx plus = gen_rtx_PLUS (SImode, operands[2], operands[3]); + + post = gen_rtx_POST_MODIFY (SImode, operands[2], plus); + } + + mem = gen_rtx_MEM (mode, post); + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[1]); + zextend = gen_rtx_ZERO_EXTEND (HImode, mem); + insn = emit_insn (gen_rtx_SET (VOIDmode, operands[0], zextend)); + + if (auto_inc_p (post)) + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC, XEXP (post, 0), REG_NOTES (insn)); + DONE; + } +) + +;; ====POST_INC + +;; ---------------------------------------------------------------------------- +;; Fixup some obvious reg alloc losage for loads +;; ---------------------------------------------------------------------------- + +(define_peephole2 + [(set (match_operand:MEMOP 0 "metag_register_op" "") + (match_operand: 1 "memory_operand" "")) + (set (match_operand: 2 "metag_reg_nofloat_op" "") + (match_dup 0))] + "peep2_reg_dead_p (2, operands[0])" + [(set (match_dup 2) + (match_dup 1))] + "") + +;; ---------------------------------------------------------------------------- + +;; misc peephole2s + +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (match_operand:SI 1 "metag_datareg_op" "")) + (set (reg:CCANY CC_REG) + (compare: + (match_dup 0) + (match_operand:SI 2 "metag_int_operand" "")))] + "peep2_reg_dead_p (2, operands[0])" + [(set (reg: CC_REG) + (compare: + (match_dup 1) + (match_dup 2)))] + "") + +;; +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (match_operand:SI 1 "metag_datareg_op" "")) + (set (reg:CCANY CC_REG) + (compare: + (match_dup 0) + (match_operand:SI 2 "metag_datareg_op" "")))] + "peep2_reg_dead_p (2, operands[0]) + && metag_same_regclass_p (operands[0], operands[1]) + && !rtx_equal_p (operands[0], operands[2])" + [(set (reg: CC_REG) + (compare: + (match_dup 1) + (match_dup 2)))] + "") + +;; SImode swap +(define_peephole2 + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "") + (match_operand:SI 1 "metag_reg_nofloat_op" "")) + (set (match_dup 1) + (match_operand:SI 2 "metag_reg_nofloat_op" "")) + (set (match_dup 2) + (match_dup 0))] + "!metag_same_regclass_p (operands[1], operands[2]) + && peep2_reg_dead_p (3, operands[0])" + [(parallel + [(set (match_dup 1) + (match_dup 2)) + (set (match_dup 2) + (match_dup 1))])] + "") + +;; DImode swap +(define_peephole2 + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "") + (match_operand:SI 1 "metag_reg_nofloat_op" "")) + (set (match_operand:SI 2 "metag_reg_nofloat_op" "") + (match_operand:SI 3 "metag_reg_nofloat_op" "")) + (set (match_dup 1) + (match_operand:SI 4 "metag_reg_nofloat_op" "")) + (set (match_dup 3) + (match_operand:SI 5 "metag_reg_nofloat_op" "")) + (set (match_dup 4) + (match_dup 0)) + (set (match_dup 5) + (match_dup 2))] + " !metag_same_regclass_p (operands[3], operands[4]) + && !metag_same_regclass_p (operands[1], operands[5]) + && !metag_same_regclass_p (operands[4], operands[5]) + && !metag_same_regclass_p (operands[1], operands[3]) + && peep2_reg_dead_p (5, operands[0]) + && peep2_reg_dead_p (6, operands[2])" + [(parallel + [(set (match_dup 3) + (match_dup 4)) + (set (match_dup 4) + (match_dup 3))]) + (parallel + [(set (match_dup 1) + (match_dup 5)) + (set (match_dup 5) + (match_dup 1))]) + (parallel + [(set (match_dup 4) + (match_dup 5)) + (set (match_dup 5) + (match_dup 4))]) + (parallel + [(set (match_dup 1) + (match_dup 3)) + (set (match_dup 3) + (match_dup 1))])] + "") + +(define_peephole2 + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "") + (match_operand:SI 1 "metag_reg_nofloat_op" "")) + (set (match_dup 1) + (match_operand:SI 2 "metag_reg_nofloat_op" "")) + (set (match_dup 2) + (match_dup 0))] + "!metag_same_regclass_p (operands[1], operands[2])" + [(set (match_dup 0) + (match_dup 1)) + (parallel + [(set (match_dup 1) + (match_dup 2)) + (set (match_dup 2) + (match_dup 1))])] + "") + +;; set full condition flags during move, flags from source value +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (match_operand:SI 1 "metag_datareg_op" "")) + (set (reg:CCANY CC_REG) + (compare: + (match_dup 1) + (const_int 0)))] + "REGNO (operands[0]) <= LAST_ADDR_REG" + [(parallel + [(set (reg: CC_REG) + (compare: + (match_dup 1) + (const_int 0))) + (set (match_dup 0) + (match_dup 1))])] + "") + +;; set full condition flags during move, flags from dest value +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (match_operand:SI 1 "metag_datareg_op" "")) + (set (reg:CCANY CC_REG) + (compare: + (match_dup 0) + (const_int 0)))] + "REGNO (operands[0]) <= LAST_ADDR_REG" + [(parallel + [(set (reg: CC_REG) + (compare: + (match_dup 1) + (const_int 0))) + (set (match_dup 0) + (match_dup 1))])] + "") + +;; set condition flags during sign extension of a hi value +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (sign_extend:SI (match_operand:HI 1 "metag_register_op" ""))) + (set (reg:CCZNC CC_REG) + (compare: + (match_dup 0) + (const_int 0)))] + "" + [(parallel + [(set (reg: CC_REG) + (compare: + (sign_extend:SI (match_dup 1)) + (const_int 0))) + (set (match_dup 0) + (sign_extend:SI (match_dup 1)))])] + "") + +;; set condition flags during sign extension of a qi value +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (sign_extend:SI (match_operand:QI 1 "metag_register_op" ""))) + (set (reg:CCZNC CC_REG) + (compare: + (match_dup 0) + (const_int 0)))] + "" + [(parallel + [(set (reg: CC_REG) + (compare: + (sign_extend:SI (match_dup 1)) + (const_int 0))) + (set (match_dup 0) + (sign_extend:SI (match_dup 1)))])] + "") + +;; eliminate redundant move +(define_peephole2 + [(set (match_operand:MEMOP 0 "metag_register_op" "") + (match_operand: 1 "metag_regorint_op" "")) + (set (match_operand: 2 "metag_register_op" "") + (match_dup 0))] + "peep2_reg_dead_p (2, operands[0]) + && metag_move_valid_p (operands[2], operands[1])" + [(set (match_dup 2) + (match_dup 1))] + "") + +;; +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (plus:SI (match_operand:SI 1 "metag_datareg_op" "") + (match_operand:SI 2 "metag_register_op" ""))) + (set (reg:CCZNC CC_REG) + (compare: + (match_dup 0) + (const_int 0)))] + "" + [(parallel + [(set (reg: CC_REG) + (compare: + (plus:SI (match_dup 1) + (match_dup 2)) + (const_int 0))) + (set (match_dup 0) + (plus:SI (match_dup 1) + (match_dup 2)))])] + "") + +;; +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (minus:SI (match_operand:SI 1 "metag_datareg_op" "") + (match_operand:SI 2 "metag_register_op" ""))) + (set (reg:CCZNC CC_REG) + (compare: + (match_dup 0) + (const_int 0)))] + "" + [(parallel + [(set (reg: CC_REG) + (compare: + (minus:SI (match_dup 1) + (match_dup 2)) + (const_int 0))) + (set (match_dup 0) + (minus:SI (match_dup 1) + (match_dup 2)))])] + "") +;; +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (plus:SI (match_operand:SI 1 "metag_datareg_op" "") + (match_operand:SI 2 "metag_smallint_op" ""))) + (set (reg:CCZNC CC_REG) + (compare: + (match_dup 0) + (const_int 0)))] + "" + [(parallel + [(set (reg: CC_REG) + (compare: + (plus:SI (match_dup 1) + (match_dup 2)) + (const_int 0))) + (set (match_dup 0) + (plus:SI (match_dup 1) + (match_dup 2)))])] + "") + +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (high:SI (match_operand:SI 1 "metag_symglobal_op" ""))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (match_dup 1))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_operand:SI 2 "const_int_operand" "")))] + "!METAG_FLAG_PIC" + [(set (match_dup 0) + (high:SI (match_dup 3))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (match_dup 3)))] + "operands[3] = gen_rtx_CONST (SImode, + gen_rtx_PLUS (SImode, + operands[1], + operands[2]));") + +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (high:SI (const:SI (plus:SI (match_operand:SI 1 "metag_symglobal_op" "") + (match_operand:SI 2 "const_int_operand" ""))))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (const:SI (plus:SI (match_dup 1) + (match_dup 2))))) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_operand:SI 3 "const_int_operand" "")))] + "!METAG_FLAG_PIC" + [(set (match_dup 0) + (high:SI (match_dup 4))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (match_dup 4)))] + "operands[4] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3])); + operands[4] = gen_rtx_CONST (SImode, + gen_rtx_PLUS (SImode, + operands[1], + operands[4]));") + +;; Combine a load/store with pre address arithmetic into +;; a load/store with base + offset addressing. +;; Where the intermidiate address register dies in the load/store + +;; loads +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (plus:SI (match_operand:SI 1 "metag_register_op" "") + (match_operand:SI 2 "metag_offset6_" ""))) + (set (match_operand: 3 "metag_register_op" "") + (match_operand:MEMOP 4 "memory_operand" ""))] + "peep2_reg_dead_p (2, operands[0]) + && rtx_equal_p (operands[0], XEXP (operands[4], 0))" + [(const_int 0)] + { + rtx plus = gen_rtx_PLUS (SImode, operands[1], operands[2]); + rtx mem = gen_rtx_MEM (mode, plus); + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[4]); + emit_insn (gen_rtx_SET (VOIDmode, operands[3], mem)); + + DONE; + } +) + +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (plus:SI (match_operand:SI 1 "metag_reg12bit_op" "") + (match_operand:SI 2 "metag_offset12_" ""))) + (set (match_operand: 3 "metag_reg_nofloat_op" "") + (match_operand:MEMOP 4 "memory_operand" ""))] + "peep2_reg_dead_p (2, operands[0]) + && rtx_equal_p (operands[0], XEXP (operands[4], 0))" + [(const_int 0)] + { + rtx plus = gen_rtx_PLUS (SImode, operands[1], operands[2]); + rtx mem = gen_rtx_MEM (mode, plus); + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[4]); + emit_insn (gen_rtx_SET (VOIDmode, operands[3], mem)); + + DONE; + } +) + +;; load zero_extend HI +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (plus:SI (match_operand:SI 1 "metag_register_op" "") + (match_operand:SI 2 "metag_offset6_" ""))) + (set (match_operand:HI 3 "metag_register_op" "") + (zero_extend:HI + (match_operand:EXTHI 4 "memory_operand" "")))] + "peep2_reg_dead_p (2, operands[0]) + && rtx_equal_p (operands[0], XEXP (operands[4], 0))" + [(const_int 0)] + { + rtx plus = gen_rtx_PLUS (SImode, operands[1], operands[2]); + rtx mem = gen_rtx_MEM (mode, plus); + rtx zextend = gen_rtx_ZERO_EXTEND (HImode, mem); + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[4]); + emit_insn (gen_rtx_SET (VOIDmode, operands[3], zextend)); + + DONE; + } +) + +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (plus:SI (match_operand:SI 1 "metag_reg12bit_op" "") + (match_operand:SI 2 "metag_offset12_" ""))) + (set (match_operand:HI 3 "metag_reg_nofloat_op" "") + (zero_extend:HI + (match_operand:EXTHI 4 "memory_operand" "")))] + "peep2_reg_dead_p (2, operands[0]) + && rtx_equal_p (operands[0], XEXP (operands[4], 0))" + [(const_int 0)] + { + rtx plus = gen_rtx_PLUS (SImode, operands[1], operands[2]); + rtx mem = gen_rtx_MEM (mode, plus); + rtx zextend = gen_rtx_ZERO_EXTEND (HImode, mem); + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[4]); + emit_insn (gen_rtx_SET (VOIDmode, operands[3], zextend)); + + DONE; + } +) + +;; load zero_extend SI +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (plus:SI (match_operand:SI 1 "metag_register_op" "") + (match_operand:SI 2 "metag_offset6_" ""))) + (set (match_operand:SI 3 "metag_register_op" "") + (zero_extend:SI + (match_operand:EXTSI 4 "memory_operand" "")))] + "peep2_reg_dead_p (2, operands[0]) + && rtx_equal_p (operands[0], XEXP (operands[4], 0))" + [(const_int 0)] + { + rtx plus = gen_rtx_PLUS (SImode, operands[1], operands[2]); + rtx mem = gen_rtx_MEM (mode, plus); + rtx zextend = gen_rtx_ZERO_EXTEND (SImode, mem); + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[4]); + emit_insn (gen_rtx_SET (VOIDmode, operands[3], zextend)); + + DONE; + } +) + +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (plus:SI (match_operand:SI 1 "metag_reg12bit_op" "") + (match_operand:SI 2 "metag_offset12_" ""))) + (set (match_operand:SI 3 "metag_reg_nofloat_op" "") + (zero_extend:SI + (match_operand:EXTSI 4 "memory_operand" "")))] + "peep2_reg_dead_p (2, operands[0]) + && rtx_equal_p (operands[0], XEXP (operands[4], 0))" + [(const_int 0)] + { + rtx plus = gen_rtx_PLUS (SImode, operands[1], operands[2]); + rtx mem = gen_rtx_MEM (mode, plus); + rtx zextend = gen_rtx_ZERO_EXTEND (SImode, mem); + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[4]); + emit_insn (gen_rtx_SET (VOIDmode, operands[3], zextend)); + + DONE; + } +) + +;; store QI/HI/SI +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (plus:SI (match_operand:SI 1 "metag_register_op" "") + (match_operand:SI 2 "metag_offset6_" ""))) + (set (match_operand:MEMOP 3 "memory_operand" "") + (match_operand: 4 "metag_register_op" ""))] + "peep2_reg_dead_p (2, operands[0]) + && REGNO (operands[0]) != REGNO (operands[4]) + && rtx_equal_p (operands[0], XEXP (operands[3], 0))" + [(const_int 0)] + { + rtx plus = gen_rtx_PLUS (SImode, operands[1], operands[2]); + rtx mem = gen_rtx_MEM (mode, plus); + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[3]); + emit_insn (gen_rtx_SET (VOIDmode, mem, operands[4])); + + DONE; + } +) + +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (plus:SI (match_operand:SI 1 "metag_reg12bit_op" "") + (match_operand:SI 2 "metag_offset12_" ""))) + (set (match_operand:MEMOP 3 "memory_operand" "") + (match_operand: 4 "metag_reg_nofloat_op" ""))] + "peep2_reg_dead_p (2, operands[0]) + && REGNO (operands[0]) != REGNO (operands[4]) + && rtx_equal_p (operands[0], XEXP (operands[3], 0))" + [(const_int 0)] + { + rtx plus = gen_rtx_PLUS (SImode, operands[1], operands[2]); + rtx mem = gen_rtx_MEM (mode, plus); + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[3]); + emit_insn (gen_rtx_SET (VOIDmode, mem, operands[4])); + + DONE; + } +) + +;; QI/HI->SI zero_extend load removing unneccessary temporary + +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (high:SI (match_operand:SI 1 "metag_symglobal_op" ""))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (match_dup 1))) + (set (match_operand:SI 2 "metag_register_op" "") + (plus:SI (match_dup 2) + (match_dup 0))) + (set (match_operand:SI 3 "metag_register_op" "") + (zero_extend:SI + (match_operand:EXTSI 4 "memory_operand" "")))] + "!METAG_FLAG_PIC + && peep2_reg_dead_p (4, operands[2]) + && peep2_reg_dead_p (3, operands[0]) + && GET_MODE (XEXP (operands[4], 0)) == SImode + && GET_CODE (XEXP (operands[4], 0)) == PLUS + && rtx_equal_p (operands[2], XEXP (XEXP (operands[4], 0), 0)) + && const_int_operand (XEXP (XEXP (operands[4], 0), 1), SImode) + && metag_regno_same_unit_p (REGNO (operands[2]), REGNO (operands[0]))" + + [(const_int 0)] + { + rtx plus, mem, zextend; + operands[5] = XEXP (XEXP (operands[4], 0), 1); + operands[6] = gen_rtx_CONST (SImode, + gen_rtx_PLUS (SImode, + operands[1], + operands[5])); + + emit_insn (gen_rtx_SET (VOIDmode, + operands[0], + gen_rtx_HIGH (SImode, + operands[6]))); + + emit_insn (gen_rtx_SET (VOIDmode, + operands[0], + gen_rtx_LO_SUM (SImode, + operands[0], + operands[6]))); + + plus = gen_rtx_PLUS (SImode, operands[2], operands[0]); + mem = gen_rtx_MEM (mode, plus); + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[4]); + zextend = gen_rtx_ZERO_EXTEND (SImode, mem); + emit_insn (gen_rtx_SET (VOIDmode, operands[3], zextend)); + DONE; + } +) + +;; QI->HI zero_extend load removing unneccessary temporary + +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (high:SI (match_operand:SI 1 "metag_symglobal_op" ""))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (match_dup 1))) + (set (match_operand:SI 2 "metag_register_op" "") + (plus:SI (match_dup 2) + (match_dup 0))) + (set (match_operand:HI 3 "metag_register_op" "") + (zero_extend:HI + (match_operand:EXTHI 4 "memory_operand" "")))] + "!METAG_FLAG_PIC + && peep2_reg_dead_p (4, operands[2]) + && peep2_reg_dead_p (3, operands[0]) + && GET_MODE (XEXP (operands[4], 0)) == SImode + && GET_CODE (XEXP (operands[4], 0)) == PLUS + && rtx_equal_p (operands[2], XEXP (XEXP (operands[4], 0), 0)) + && const_int_operand (XEXP (XEXP (operands[4], 0), 1), SImode) + && metag_regno_same_unit_p (REGNO (operands[2]), REGNO (operands[0]))" + [(const_int 0)] + { + rtx plus, mem, zextend; + operands[5] = XEXP (XEXP (operands[4], 0), 1); + operands[6] = gen_rtx_CONST (SImode, + gen_rtx_PLUS (SImode, + operands[1], + operands[5])); + + emit_insn (gen_rtx_SET (VOIDmode, + operands[0], + gen_rtx_HIGH (SImode, + operands[6]))); + + emit_insn (gen_rtx_SET (VOIDmode, + operands[0], + gen_rtx_LO_SUM (SImode, + operands[0], + operands[6]))); + + plus = gen_rtx_PLUS (SImode, operands[2], operands[0]); + mem = gen_rtx_MEM (mode, plus); + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[4]); + zextend = gen_rtx_ZERO_EXTEND (HImode, mem); + emit_insn (gen_rtx_SET (VOIDmode, operands[3], zextend)); + DONE; + } +) + +;; QI, HI and SI mode load, removing unneccessary temporary + +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (high:SI (match_operand:SI 1 "metag_symglobal_op" ""))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (match_dup 1))) + (set (match_operand:SI 2 "metag_register_op" "") + (plus:SI (match_dup 2) + (match_dup 0))) + (set (match_operand: 3 "metag_register_op" "") + (match_operand:MEMOP 4 "memory_operand" ""))] + "!METAG_FLAG_PIC + && peep2_reg_dead_p (4, operands[2]) + && peep2_reg_dead_p (3, operands[0]) + && GET_MODE (XEXP (operands[4], 0)) == SImode + && GET_CODE (XEXP (operands[4], 0)) == PLUS + && rtx_equal_p (operands[2], XEXP (XEXP (operands[4], 0), 0)) + && const_int_operand (XEXP (XEXP (operands[4], 0), 1), SImode) + && metag_regno_same_unit_p (REGNO (operands[2]), REGNO (operands[0]))" + [(const_int 0)] + { + rtx plus, mem; + operands[5] = XEXP (XEXP (operands[4], 0), 1); + operands[6] = gen_rtx_CONST (SImode, + gen_rtx_PLUS (SImode, + operands[1], + operands[5])); + + emit_insn (gen_rtx_SET (VOIDmode, + operands[0], + gen_rtx_HIGH (SImode, + operands[6]))); + + emit_insn (gen_rtx_SET (VOIDmode, + operands[0], + gen_rtx_LO_SUM (SImode, + operands[0], + operands[6]))); + + plus = gen_rtx_PLUS (SImode, operands[2], operands[0]); + mem = gen_rtx_MEM (mode, plus); + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[4]); + emit_insn (gen_rtx_SET (VOIDmode, operands[3], mem)); + DONE; + } +) + +;; QI/HI->SI zero_extend when result register same as temporary address register + +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (high:SI (match_operand:SI 1 "metag_symglobal_op" ""))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (match_dup 1))) + (set (match_operand:SI 2 "metag_register_op" "") + (plus:SI (match_dup 2) + (match_dup 0))) + (set (match_dup 2) + (zero_extend:SI + (match_operand:EXTSI 3 "memory_operand" "")))] + "!METAG_FLAG_PIC + && peep2_reg_dead_p (3, operands[0]) + && GET_MODE (XEXP (operands[3], 0)) == SImode + && GET_CODE (XEXP (operands[3], 0)) == PLUS + && rtx_equal_p (operands[2], XEXP (XEXP (operands[3], 0), 0)) + && const_int_operand (XEXP (XEXP (operands[3], 0), 1), SImode) + && metag_regno_same_unit_p (REGNO (operands[2]), REGNO (operands[0]))" + [(const_int 0)] + { + rtx plus, mem, zextend; + operands[4] = XEXP (XEXP (operands[3], 0), 1); + operands[5] = gen_rtx_CONST (SImode, + gen_rtx_PLUS (SImode, + operands[1], + operands[4])); + + emit_insn (gen_rtx_SET (VOIDmode, + operands[0], + gen_rtx_HIGH (SImode, + operands[5]))); + + emit_insn (gen_rtx_SET (VOIDmode, + operands[0], + gen_rtx_LO_SUM (SImode, + operands[0], + operands[5]))); + + plus = gen_rtx_PLUS (SImode, operands[2], operands[0]); + mem = gen_rtx_MEM (mode, plus); + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[3]); + zextend = gen_rtx_ZERO_EXTEND (SImode, mem); + emit_insn (gen_rtx_SET (VOIDmode, operands[2], zextend)); + DONE; + } +) + +;; result register same as temporary address. + +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (high:SI (match_operand:SI 1 "metag_symglobal_op" ""))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (match_dup 1))) + (set (match_operand:SI 2 "metag_register_op" "") + (plus:SI (match_dup 2) + (match_dup 0))) + (set (match_operand: 3 "metag_register_op" "") + (match_operand:MEMOP 4 "memory_operand" ""))] + + "!METAG_FLAG_PIC + && peep2_reg_dead_p (3, operands[0]) + && REGNO (operands[3]) == REGNO (operands[2]) + && GET_MODE (XEXP (operands[4], 0)) == SImode + && GET_CODE (XEXP (operands[4], 0)) == PLUS + && rtx_equal_p (operands[2], XEXP (XEXP (operands[4], 0), 0)) + && const_int_operand (XEXP (XEXP (operands[4], 0), 1), SImode) + && metag_regno_same_unit_p (REGNO (operands[2]), REGNO (operands[0]))" + [(const_int 0)] + { + rtx plus, mem; + operands[5] = XEXP (XEXP (operands[4], 0), 1); + operands[6] = gen_rtx_CONST (SImode, + gen_rtx_PLUS (SImode, + operands[1], + operands[5])); + operands[7] = gen_rtx_REG (mode, REGNO (operands[2])); + + emit_insn (gen_rtx_SET (VOIDmode, + operands[0], + gen_rtx_HIGH (SImode, + operands[6]))); + + emit_insn (gen_rtx_SET (VOIDmode, + operands[0], + gen_rtx_LO_SUM (SImode, + operands[0], + operands[6]))); + + plus = gen_rtx_PLUS (SImode, operands[2], operands[0]); + mem = gen_rtx_MEM (mode, plus); + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[4]); + emit_insn (gen_rtx_SET (VOIDmode, operands[7], mem)); + DONE; + } +) + +;; QI, HI and SI mode store, removing unneccessary temporary + +(define_peephole2 + [(set (match_operand:SI 0 "metag_register_op" "") + (high:SI (match_operand:SI 1 "metag_symglobal_op" ""))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (match_dup 1))) + (set (match_operand:SI 2 "metag_register_op" "") + (plus:SI (match_dup 2) + (match_dup 0))) + (set (match_operand:MEMOP 3 "memory_operand" "") + (match_operand: 4 "metag_register_op" "") )] + "!METAG_FLAG_PIC + && peep2_reg_dead_p (4, operands[2]) + && peep2_reg_dead_p (3, operands[0]) + && GET_MODE (XEXP (operands[3], 0)) == SImode + && GET_CODE (XEXP (operands[3], 0)) == PLUS + && rtx_equal_p (operands[2], XEXP (XEXP (operands[3], 0), 0)) + && const_int_operand (XEXP (XEXP (operands[3], 0), 1), SImode) + && metag_regno_same_unit_p (REGNO (operands[2]), REGNO (operands[0])) + && !metag_regno_same_unit_p (REGNO (operands[2]), REGNO (operands[4]))" + [(const_int 0)] + { + operands[5] = XEXP (XEXP (operands[3], 0), 1); + operands[6] = gen_rtx_CONST (SImode, + gen_rtx_PLUS (SImode, + operands[1], + operands[5])); + + emit_insn (gen_rtx_SET (VOIDmode, + operands[0], + gen_rtx_HIGH (SImode, + operands[6]))); + + emit_insn (gen_rtx_SET (VOIDmode, + operands[0], + gen_rtx_LO_SUM (SImode, + operands[0], + operands[6]))); + + rtx plus = gen_rtx_PLUS (SImode, operands[2], operands[0]); + rtx mem = gen_rtx_MEM (mode, plus); + MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (operands[3]); + emit_insn (gen_rtx_SET (VOIDmode, mem, operands[4])); + DONE; + } +) diff -Nur gcc-4.2.4.orig/gcc/config/metag/peephole.md gcc-4.2.4/gcc/config/metag/peephole.md --- gcc-4.2.4.orig/gcc/config/metag/peephole.md 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/peephole.md 2015-07-03 18:46:05.773283541 -0500 @@ -0,0 +1,491 @@ +;; Machine description for GNU compiler, +;; Imagination Technologies Meta version. +;; Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 +;; Imagination Technologies Ltd + +;; This file is part of GCC. + +;; GCC is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 3, or (at your option) any later +;; version. + +;; GCC is distributed in the hope that it will be useful, but WITHOUT ANY +;; WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; . + +;;- peephole patterns + +;; set full condition flags during move, flags from source value +(define_peephole + [(set (match_operand:SI 0 "metag_register_op" "") + (match_operand:SI 1 "metag_datareg_op" "")) + (set (reg: CC_REG) + (compare:CCANY + (match_dup 1) + (const_int 0)))] + "!metag_cond_exec_p () + && REGNO (operands[0]) <= LAST_ADDR_REG + && METAG_DATA_REG_P (REGNO (operands[1]))" + "SUBS\\t%0, %1, #0\\t\\t%@ (*movs rd 1 OK)" + [(set_attr "type" "fast") + (set_attr "ccstate" "set")]) + +;; set full condition flags during move, flags from dest value +(define_peephole + [(set (match_operand:SI 0 "metag_register_op" "") + (match_operand:SI 1 "metag_datareg_op" "")) + (set (reg: CC_REG) + (compare:CCANY + (match_dup 0) + (const_int 0)))] + "!metag_cond_exec_p () + && REGNO (operands[0]) <= LAST_ADDR_REG + && METAG_DATA_REG_P (REGNO (operands[1]))" + "SUBS\\t%0, %1, #0\\t\\t%@ (*movs rd 0 OK)" + [(set_attr "type" "fast") + (set_attr "ccstate" "set")]) + +;; set condition flags during sign extension of a hi value +(define_peephole + [(set (match_operand:SI 0 "metag_datareg_op" "") + (sign_extend:SI (match_operand:HI 1 "metag_datareg_op" ""))) + (set (reg:CCZNC CC_REG) + (compare: + (match_dup 0) + (const_int 0)))] + "!metag_cond_exec_p ()" + "XSDSW\\t%0, %1\\t\\t%@ (*exts hisi dd OK)" + [(set_attr "type" "fast") + (set_attr "ccstate" "set")]) + +;; set condition flags during sign extension of a qi value +(define_peephole + [(set (match_operand:SI 0 "metag_datareg_op" "") + (sign_extend:SI (match_operand:QI 1 "metag_datareg_op" ""))) + (set (reg:CCZNC CC_REG) + (compare: + (match_dup 0) + (const_int 0)))] + "!metag_cond_exec_p ()" + "XSDSB\\t%0, %1\\t\\t%@ (*exts qisi dd OK)" + [(set_attr "type" "fast") + (set_attr "ccstate" "set")]) + +;; Detect oppurtunities for post-increments of DI mode stores +(define_peephole + [(set (mem:DI (match_operand:SI 0 "metag_register_op" "")) + (match_operand:DI 1 "metag_register_op" "")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_operand:SI 2 "metag_offset6_di" "")))] + "TARGET_METAC_1_1 && !metag_cond_exec_p ()" + "SETL\\t[%0+%2++], %1, %t1\\t%@ (*store DI post_inc OK)" + [(set_attr "type" "fast")]) + +(define_peephole + [(set (match_operand:SI 0 "metag_register_op" "") + (plus:SI (match_dup 0) + (match_operand:SI 2 "metag_offset6_di" ""))) + (set (mem:DI (match_dup 0)) + (match_operand:DI 1 "metag_register_op" ""))] + "TARGET_METAC_1_1 && !metag_cond_exec_p ()" + "SETL\\t[%0++%2], %1, %t1\\t%@ (*store DI pre_inc OK)" + [(set_attr "type" "fast")]) + +;; Detect oppurtunities for post-increments of stores - not 1_1 +(define_peephole + [(set (mem:SI (match_operand:SI 0 "metag_register_op" "")) + (match_operand:SI 2 "metag_register_op" "")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_register_op" "")))] + "0 && !metag_cond_exec_p () + && !TARGET_METAC_1_1" + "SETD\\t[%0+%1++], %2\\t%@ (*sto si maar OK)" + [(set_attr "type" "fast")]) + +(define_peephole + [(set (mem:SI (match_operand:SI 0 "metag_register_op" "")) + (match_operand:SI 2 "metag_register_op" "")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_si" "")))] + "0 && !metag_cond_exec_p () + && !TARGET_METAC_1_1" + "SETD\\t[%0+%1++], %2\\t%@ (*sto si miar OK)" + [(set_attr "type" "fast")]) + +(define_peephole + [(set (mem:HI (match_operand:SI 0 "metag_register_op" "")) + (match_operand:HI 2 "metag_register_op" "")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_register_op" "")))] + "0 && !metag_cond_exec_p () + && !TARGET_METAC_1_1" + "SETW\\t[%0+%1++], %2\\t%@ (*sto hi maar OK)" + [(set_attr "type" "fast")]) + +(define_peephole + [(set (mem:HI (match_operand:SI 0 "metag_register_op" "")) + (match_operand:HI 2 "metag_register_op" "")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_hi" "")))] + "0 && !metag_cond_exec_p () + && !TARGET_METAC_1_1" + "SETW\\t[%0+%1++], %2\\t%@ (*sto hi miar OK)" + [(set_attr "type" "fast")]) + +(define_peephole + [(set (mem:QI (match_operand:SI 0 "metag_register_op" "")) + (match_operand:QI 2 "metag_register_op" "")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_register_op" "")))] + "0 && !metag_cond_exec_p () + && !TARGET_METAC_1_1" + "SETB\\t[%0+%1++], %2\\t%@ (*sto qi maar OK)" + [(set_attr "type" "fast")]) + +(define_peephole + [(set (mem:QI (match_operand:SI 0 "metag_register_op" "")) + (match_operand:QI 2 "metag_register_op" "")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_qi" "")))] + "0 && !metag_cond_exec_p () + && !TARGET_METAC_1_1" + "SETB\\t[%0+%1++], %2\\t%@ (*sto qi miar OK)" + [(set_attr "type" "fast")]) + +;; Detect oppurtunities for post-increments of stores - 1_1 +(define_peephole + [(set (mem:SI (match_operand:SI 0 "metag_register_op" "")) + (match_operand:SI 2 "metag_register_op" "")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_register_op" "")))] + "!metag_cond_exec_p () + && TARGET_METAC_1_1 + && metag_same_regclass_p (operands[0], operands[1]) + && !metag_same_regclass_p (operands[0], operands[2])" + "SETD\\t[%0+%1++], %2\\t%@ (*sto si maar OK)" + [(set_attr "type" "fast")]) + +(define_peephole + [(set (mem:SI (match_operand:SI 0 "metag_register_op" "")) + (match_operand:SI 2 "metag_register_op" "")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_si" "")))] + "!metag_cond_exec_p () + && TARGET_METAC_1_1" + "SETD\\t[%0+%1++], %2\\t%@ (*sto si miar OK)" + [(set_attr "type" "fast")]) + +(define_peephole + [(set (mem:HI (match_operand:SI 0 "metag_register_op" "")) + (match_operand:HI 2 "metag_register_op" "")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_register_op" "")))] + "!metag_cond_exec_p () + && TARGET_METAC_1_1 + && metag_same_regclass_p (operands[0], operands[1]) + && !metag_same_regclass_p (operands[0], operands[2])" + "SETW\\t[%0+%1++], %2\\t%@ (*sto hi maar OK)" + [(set_attr "type" "fast")]) + +(define_peephole + [(set (mem:HI (match_operand:SI 0 "metag_register_op" "")) + (match_operand:HI 2 "metag_register_op" "")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_hi" "")))] + "!metag_cond_exec_p () + && TARGET_METAC_1_1" + "SETW\\t[%0+%1++], %2\\t%@ (*sto hi miar OK)" + [(set_attr "type" "fast")]) + +(define_peephole + [(set (mem:QI (match_operand:SI 0 "metag_register_op" "")) + (match_operand:QI 2 "metag_register_op" "")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_register_op" "")))] + "!metag_cond_exec_p () + && TARGET_METAC_1_1 + && metag_same_regclass_p (operands[0], operands[1]) + && !metag_same_regclass_p (operands[0], operands[2])" + "SETB\\t[%0+%1++], %2\\t%@ (*sto qi maar OK)" + [(set_attr "type" "fast")]) + +(define_peephole + [(set (mem:QI (match_operand:SI 0 "metag_register_op" "")) + (match_operand:QI 2 "metag_register_op" "")) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_operand:SI 1 "metag_offset6_qi" "")))] + "!metag_cond_exec_p () + && TARGET_METAC_1_1" + "SETB\\t[%0+%1++], %2\\t%@ (*sto qi miar OK)" + [(set_attr "type" "fast")]) + +;; Detect oppurtunities for post-increments of loads + +(define_peephole + [(set (match_operand:DI 0 "metag_register_op" "") + (mem:DI (match_operand:SI 1 "metag_register_op" ""))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_offset6_di" "")))] + "!metag_cond_exec_p ()" + "GETL\\t%0, %t0, [%1+%2++]\\t%@ (*load DI post_inc OK)" + [(set_attr "type" "load")]) + +(define_peephole + [(set (match_operand:SI 1 "metag_register_op" "") + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_offset6_di" ""))) + (set (match_operand:DI 0 "metag_register_op" "") + (mem:DI (match_dup 1)))] + "!metag_cond_exec_p ()" + "GETL\\t%0, %t0, [%1++%2]\\t%@ (*load DI pre_inc OK)" + [(set_attr "type" "load")]) + +(define_peephole + [(set (match_operand:SI 0 "metag_register_op" "") + (mem:SI (match_operand:SI 1 "metag_register_op" ""))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_register_op" "")))] + "!metag_cond_exec_p () + && REGNO (operands[0]) != REGNO (operands[1]) + && REGNO (operands[0]) != REGNO (operands[2]) + && metag_same_regclass_p (operands[1], operands[2])" + "GETD\\t%0, [%1+%2++]\\t%@ (*lod si rmaa OK)" + [(set_attr "type" "load")]) + +(define_peephole + [(set (match_operand:SI 0 "metag_register_op" "") + (mem:SI (match_operand:SI 1 "metag_register_op" ""))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_offset6_si" "")))] + "!metag_cond_exec_p () + && REGNO (operands[0]) != REGNO (operands[1])" + "GETD\\t%0, [%1+%2++]\\t%@ (*lod si rmia OK)" + [(set_attr "type" "load")]) + +(define_peephole + [(set (match_operand:HI 0 "metag_register_op" "") + (mem:HI (match_operand:SI 1 "metag_register_op" ""))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_register_op" "")))] + "!metag_cond_exec_p () + && REGNO (operands[0]) != REGNO (operands[1]) + && REGNO (operands[0]) != REGNO (operands[2]) + && metag_same_regclass_p (operands[1], operands[2])" + "GETW\\t%0, [%1+%2++]\\t%@ (*lod hi rmaa OK)" + [(set_attr "type" "load")]) + +(define_peephole + [(set (match_operand:HI 0 "metag_register_op" "") + (mem:HI (match_operand:SI 1 "metag_register_op" ""))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_offset6_hi" "")))] + "!metag_cond_exec_p () + && REGNO (operands[0]) != REGNO (operands[1])" + "GETW\\t%0, [%1+%2++]\\t%@ (*lod hi rmia OK)" + [(set_attr "type" "load")]) + +(define_peephole + [(set (match_operand:SI 0 "metag_register_op" "") + (zero_extend:SI + (mem:HI (match_operand:SI 1 "metag_register_op" "")))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_register_op" "")))] + "!metag_cond_exec_p () + && REGNO (operands[0]) != REGNO (operands[1]) + && REGNO (operands[0]) != REGNO (operands[2]) + && metag_same_regclass_p (operands[1], operands[2])" + "GETW\\t%0, [%1+%2++]\\t%@ (*lodz hi rmaa OK)" + [(set_attr "type" "load")]) + +(define_peephole + [(set (match_operand:SI 0 "metag_register_op" "") + (zero_extend:SI + (mem:HI (match_operand:SI 1 "metag_register_op" "")))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_offset6_hi" "")))] + "!metag_cond_exec_p () + && REGNO (operands[0]) != REGNO (operands[1])" + "GETW\\t%0, [%1+%2++]\\t%@ (*lodz hi rmia OK)" + [(set_attr "type" "load")]) + +(define_peephole + [(set (match_operand:QI 0 "metag_register_op" "") + (mem:QI (match_operand:SI 1 "metag_register_op" ""))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_register_op" "")))] + "!metag_cond_exec_p () + && REGNO (operands[0]) != REGNO (operands[1]) + && REGNO (operands[0]) != REGNO (operands[2]) + && metag_same_regclass_p (operands[1], operands[2])" + "GETB\\t%0, [%1+%2++]\\t%@ (*lod qi rmaa OK)" + [(set_attr "type" "load")]) + +(define_peephole + [(set (match_operand:QI 0 "metag_register_op" "") + (mem:QI (match_operand:SI 1 "metag_register_op" ""))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_offset6_qi" "")))] + "!metag_cond_exec_p () + && REGNO (operands[0]) != REGNO (operands[1])" + "GETB\\t%0, [%1+%2++]\\t%@ (*lod qi rmia OK)" + [(set_attr "type" "load")]) + +(define_peephole + [(set (match_operand:SI 0 "metag_register_op" "") + (zero_extend:SI + (mem:QI (match_operand:SI 1 "metag_register_op" "")))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_register_op" "")))] + "!metag_cond_exec_p () + && REGNO (operands[0]) != REGNO (operands[1]) + && REGNO (operands[0]) != REGNO (operands[2]) + && metag_same_regclass_p (operands[1], operands[2])" + "GETB\\t%0, [%1+%2++]\\t%@ (*lodz qi rmaa OK)" + [(set_attr "type" "load")]) + +(define_peephole + [(set (match_operand:SI 0 "metag_register_op" "") + (zero_extend:SI + (mem:QI (match_operand:SI 1 "metag_register_op" "")))) + (set (match_dup 1) + (plus:SI (match_dup 1) + (match_operand:SI 2 "metag_offset6_qi" "")))] + "!metag_cond_exec_p () + && REGNO (operands[0]) != REGNO (operands[1])" + "GETB\\t%0, [%1+%2++]\\t%@ (*lodz qi rmia OK)" + [(set_attr "type" "load")]) + +(define_peephole + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "") + (match_operand:SI 1 "metag_reg_nofloat_op" "")) + (set (match_dup 1) + (match_operand:SI 2 "metag_reg_nofloat_op" "")) + (set (match_dup 2) + (match_dup 0))] + "!metag_same_regclass_p (operands[1], operands[2]) + && dead_or_set_p (insn, operands[0])" + "SWAP%?\\t%1, %2" + [(set_attr "type" "fast") + (set_attr "cond" "yes")]) + +(define_peephole + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "") + (match_operand:SI 1 "metag_reg_nofloat_op" "")) + (set (match_dup 1) + (match_operand:SI 2 "metag_reg_nofloat_op" "")) + (set (match_dup 2) + (match_dup 0))] + "!metag_same_regclass_p (operands[1], operands[2])" + "SWAP%?\\t%1, %2\\t\;MOV%?\\t%0, %2" + [(set_attr "type" "two") + (set_attr "cond" "yes")]) + +;; Fixup some obvious reg alloc losage for loads + +(define_peephole + [(set (match_operand:QI 0 "metag_register_op" "") + (match_operand:QI 1 "memory_operand" "")) + (set (match_operand:QI 2 "metag_reg_nofloat_op" "") + (match_dup 0))] + "!metag_cond_exec_p () + && dead_or_set_p (insn, operands[0])" + "GETB\\t%2, %1" + [(set_attr "type" "load")]) + +(define_peephole + [(set (match_operand:HI 0 "metag_register_op" "") + (match_operand:HI 1 "memory_operand" "")) + (set (match_operand:HI 2 "metag_reg_nofloat_op" "") + (match_dup 0))] + "!metag_cond_exec_p () + && dead_or_set_p (insn, operands[0])" + "GETW\\t%2, %1" + [(set_attr "type" "load")]) + +(define_peephole + [(set (match_operand:SI 0 "metag_register_op" "") + (match_operand:SI 1 "memory_operand" "")) + (set (match_operand:SI 2 "metag_reg_nofloat_op" "") + (match_dup 0))] + "!metag_cond_exec_p () + && dead_or_set_p (insn, operands[0])" + "GETD\\t%2, %1" + [(set_attr "type" "load")]) + +;; misc peepholes +(define_peephole + [(set (match_operand:SI 0 "metag_register_op" "") + (match_operand:SI 1 "metag_datareg_op" "")) + (set (reg: CC_REG) + (compare:CCANY + (match_dup 0) + (match_operand:SI 2 "metag_int_operand" "")))] + "dead_or_set_p (insn, operands[0])" + "CMP%?\\t%1, %2" + [(set_attr "type" "fast") + (set_attr "cond" "yes")]) + +(define_peephole + [(set (match_operand:SI 0 "metag_register_op" "") + (match_operand:SI 1 "metag_datareg_op" "")) + (set (reg: CC_REG) + (compare:CCANY + (match_dup 0) + (match_operand:SI 2 "metag_datareg_op" "")))] + "dead_or_set_p (insn, operands[0]) + && metag_same_regclass_p (operands[0], operands[1])" + "CMP%?\\t%1, %2" + [(set_attr "type" "fast") + (set_attr "cond" "yes")]) + +;; This is an EVIL peephole. We should delete it! +(define_peephole + [(set (match_operand:SI 0 "metag_register_op" "") + (match_operand:SI 1 "metag_regorint_op" "")) + (set (match_operand:SI 2 "metag_register_op" "") + (match_dup 0))] + "!metag_cond_exec_p () + && dead_or_set_p (insn, operands[0]) + && metag_move_valid_p (operands[2], operands[1])" + { + if ((REG_P (operands[1]) && metag_fpcreg_p (REGNO (operands[1]))) + || metag_fpcreg_p (REGNO (operands[2]))) + return "F\\tMOV%?\\t%2, %1"; + else if (metag_J_operand (operands[1], SImode)) + return "MOVT%?\\t%2, %1"; + else + return "MOV%?\\t%2, %1"; + } + [(set_attr "type" "fast") + (set_attr "cond" "yes")]) + +;; end of file diff -Nur gcc-4.2.4.orig/gcc/config/metag/pipeline.md gcc-4.2.4/gcc/config/metag/pipeline.md --- gcc-4.2.4.orig/gcc/config/metag/pipeline.md 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/pipeline.md 2015-07-03 18:46:05.773283541 -0500 @@ -0,0 +1,335 @@ +;; Machine description for GNU compiler, +;; Imagination Technologies Meta version. +;; Copyright (C) 2007 +;; Imagination Technologies Ltd + +;; This file is part of GCC. + +;; GCC is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 3, or (at your option) any later +;; version. + +;; GCC is distributed in the hope that it will be useful, but WITHOUT ANY +;; WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; . + +(define_automaton "metag") + +;; The UI and U2U instuctions have different ports to write results +(define_cpu_unit "UI_port, U2U_port, load_port" "metag") + +;; The FPU ports to write results +(define_cpu_unit "FP_port1, FP_port2" "metag") + +;; The FPU pipeline +(define_cpu_unit "mas1, mas2, mas3, mas4, mas5, recip1, recip2, recip3" "metag") + +;; All instructions have to be fetched! +(define_cpu_unit "issue" "metag") + +;; Multi-cycle operation stages +(define_cpu_unit "opfetch, execute" "metag") + +(define_cpu_unit "branch, load, read, mult" "metag") + +;; Simple case, single cycle operations +(define_insn_reservation "UI" 1 + (eq_attr "type" "fast") + "issue, UI_port") + +;; WORK NEEDED: This needs checking, does a swap need to write each register on separate cycles? +(define_insn_reservation "UIswap" 1 + (eq_attr "type" "swap") + "issue, UI_port, UI_port") + +;; Unknown type insns are user supplied ASM, invalid should not occur and nop is... +(define_insn_reservation "UIother" 1 + (eq_attr "type" "unknown, invalid, nop, block") + "issue, UI_port") + +;; Multiply has 2 cycle latency (only MULD comes through here) +(define_insn_reservation "UImult" 2 + (eq_attr "type" "mult") + "issue, mult, UI_port") + +;; Multiple UI instruction have a complex latency +(define_insn_reservation "UIUI" 2 + (eq_attr "type" "two") + "issue, issue + UI_port, UI_port") + +(define_insn_reservation "UIUIUI" 3 + (eq_attr "type" "three") + "issue, issue + UI_port, issue + UI_port, UI_port") + +(define_insn_reservation "UIUIUIUI" 4 + (eq_attr "type" "four") + "issue, issue + UI_port, issue + UI_port, issue + UI_port, UI_port") + +(define_insn_reservation "UIUIUIUIUI" 5 + (eq_attr "type" "five") + "issue, issue + UI_port, issue + UI_port, issue + UI_port, issue + UI_port, UI_port") + +;; Inter unit operations +;; Results are written on 3rd cycle but are ready to be used on 2nd cycle using feedback path +(define_insn_reservation "U2U" 2 + (eq_attr "type" "slow") + "issue, opfetch, execute, U2U_port") + +(define_insn_reservation "U2UU2U" 3 + (eq_attr "type" "slowslow") + "issue, issue + opfetch, opfetch + execute, execute + U2U_port, U2U_port") + +;; META 2 FPU + +(define_reservation "FP_ports" "FP_port1 | FP_port2") +(define_reservation "mas" "mas1, mas2, mas3, mas4, mas5") +(define_reservation "recip" "recip1, recip2, recip3") + +(define_insn_reservation "FP" 1 + (eq_attr "type" "FPfast") + "issue, FP_ports") + +(define_insn_reservation "FPmas" 5 + (eq_attr "type" "FPmas") + "issue, mas, FP_ports") + +(define_insn_reservation "FPrecip" 3 + (eq_attr "type" "FPrecip") + "issue, recip, FP_ports") + +(define_insn_reservation "FPrecipmas" 8 + (eq_attr "type" "FPrecipmas") + "issue, recip, FP_ports + issue, mas, FP_ports") + +;; META 2_1 +(define_insn_reservation "branch_2_1" 5 + (and (eq_attr "metacore" "metac_2_1") + (eq_attr "type" "branch")) + "issue, branch*3, UI_port") + +(define_insn_reservation "load_2_1" 3 + (and (eq_attr "metacore" "metac_2_1") + (eq_attr "type" "load")) + "issue, load, load_port") + +(define_insn_reservation "read_2_1" 3 + (and (eq_attr "metacore" "metac_2_1") + (eq_attr "type" "read")) + "issue, read, load_port") + +;; META 1_2 +(define_insn_reservation "branch_1_2" 5 + (and (eq_attr "metacore" "metac_1_2") + (eq_attr "type" "branch")) + "issue, branch*3, UI_port") + +(define_insn_reservation "load_1_2" 3 + (and (eq_attr "metacore" "metac_1_2") + (eq_attr "type" "load")) + "issue, load, load_port") + +(define_insn_reservation "read_1_2" 3 + (and (eq_attr "metacore" "metac_1_2") + (eq_attr "type" "read")) + "issue, read, load_port") +;; META 1_1 +(define_insn_reservation "branch_1_1" 6 + (and (eq_attr "metacore" "metac_1_1") + (eq_attr "type" "branch")) + "issue, branch*4, UI_port") + +(define_insn_reservation "load_1_1" 8 + (and (eq_attr "metacore" "metac_1_1") + (eq_attr "type" "load")) + "issue, load, load_port") + +(define_insn_reservation "read_1_1" 8 + (and (eq_attr "metacore" "metac_1_1") + (eq_attr "type" "read")) + "issue, read, load_port") +;; META 1_0 +(define_insn_reservation "branch_1_0" 7 + (and (eq_attr "metacore" "metac_1_0") + (eq_attr "type" "branch")) + "issue, branch*5, UI_port") + +(define_insn_reservation "load_1_0" 10 + (and (eq_attr "metacore" "metac_1_0") + (eq_attr "type" "load")) + "issue, load, load_port") + +(define_insn_reservation "read_1_0" 9 + (and (eq_attr "metacore" "metac_1_0") + (eq_attr "type" "read")) + "issue, read, load_port") + +;; MGET latencies are complex... The minimum latency is specified here +;; and the more complex work is done in metag_sched_adjust_cost + +;; META 1_2 and 2_1 +(define_insn_reservation "UI2xld_2_1" 1 + (and (ior (eq_attr "metacore" "metac_1_2") + (eq_attr "metacore" "metac_2_1")) + (and (eq_attr "type" "twox") + (eq_attr "memaccess" "load"))) + "issue, issue, load_port, load_port") + +(define_insn_reservation "UI3xld_2_1" 1 + (and (ior (eq_attr "metacore" "metac_1_2") + (eq_attr "metacore" "metac_2_1")) + (and (eq_attr "type" "threex") + (eq_attr "memaccess" "load"))) + "issue, issue, issue + load_port, load_port, load_port") + +(define_insn_reservation "UI4xld_2_1" 1 + (and (ior (eq_attr "metacore" "metac_1_2") + (eq_attr "metacore" "metac_2_1")) + (and (eq_attr "type" "fourx") + (eq_attr "memaccess" "load"))) + "issue, issue, issue + load_port, issue + load_port, load_port, load_port") + +(define_insn_reservation "UI5xld_2_1" 1 + (and (ior (eq_attr "metacore" "metac_1_2") + (eq_attr "metacore" "metac_2_1")) + (and (eq_attr "type" "fivex") + (eq_attr "memaccess" "load"))) + "issue, issue, issue + load_port, issue + load_port, issue + load_port, load_port, load_port") + +;; META 1_1 - The stalls are not accurately modelled here +(define_insn_reservation "UI2xld_1_1" 7 + (and (eq_attr "metacore" "metac_1_1") + (and (eq_attr "type" "twox") + (eq_attr "memaccess" "load"))) + "issue, issue, load*5, load_port, load_port") + +(define_insn_reservation "UI3xld_1_1" 7 + (and (eq_attr "metacore" "metac_1_1") + (and (eq_attr "type" "threex") + (eq_attr "memaccess" "load"))) + "issue, issue, issue, load *4, load_port, load_port, load_port") + +(define_insn_reservation "UI4xld_1_1" 7 + (and (eq_attr "metacore" "metac_1_1") + (and (eq_attr "type" "fourx") + (eq_attr "memaccess" "load"))) + "issue, issue, issue, issue, load*3, load_port, load_port, load_port, load_port") + +(define_insn_reservation "UI5xld_1_1" 7 + (and (eq_attr "metacore" "metac_1_1") + (and (eq_attr "type" "fivex") + (eq_attr "memaccess" "load"))) + "issue, issue, issue, issue, issue, load*2, load_port, load_port, load_port, load_port, load_port") + +;; META 1_0 - The stalls are not accurately modelled here +(define_insn_reservation "UI2xld_1_0" 9 + (and (eq_attr "metacore" "metac_1_0") + (and (eq_attr "type" "twox") + (eq_attr "memaccess" "load"))) + "issue, issue, load*8, load_port, load_port") + +(define_insn_reservation "UI3xld_1_0" 9 + (and (eq_attr "metacore" "metac_1_0") + (and (eq_attr "type" "threex") + (eq_attr "memaccess" "load"))) + "issue, issue, issue, load*7, load_port, load_port, load_port") + +(define_insn_reservation "UI4xld_1_0" 9 + (and (eq_attr "metacore" "metac_1_0") + (and (eq_attr "type" "fourx") + (eq_attr "memaccess" "load"))) + "issue, issue, issue, issue, load*6, load_port, load_port, load_port, load_port") + +(define_insn_reservation "UI5xld_1_0" 9 + (and (eq_attr "metacore" "metac_1_0") + (and (eq_attr "type" "fivex") + (eq_attr "memaccess" "load"))) + "issue, issue, issue, issue, issue, load*5, load_port, load_port, load_port, load_port, load_port") + +(define_insn_reservation "UI2xst" 1 + (and (eq_attr "type" "twox") + (eq_attr "memaccess" "store")) + "issue, issue") + +(define_insn_reservation "UI3xst" 1 + (and (eq_attr "type" "threex") + (eq_attr "memaccess" "store")) + "issue, issue, issue") + +(define_insn_reservation "UI4xst" 1 + (and (eq_attr "type" "fourx") + (eq_attr "memaccess" "store")) + "issue, issue, issue, issue") + +(define_insn_reservation "UI5xst" 1 + (and (eq_attr "type" "fivex") + (eq_attr "memaccess" "store")) + "issue, issue, issue, issue, issue") + +;; Catch all the cond_exec cases that will cause single cycle ops to become 3 cycle +;; WORK NEEDED: optimize those cases where the condition is ALWAYS or NONE or if the +;; condition value is known at issue (no updates to CC in the pipeline). +;; In such cases the instruction becomes UI (if it were UI to start with). +(define_bypass 2 "UI, FP" + "UIother,UI,UIswap,UImult, \ + UIUI,UIUIUI,UIUIUIUI,UIUIUIUIUI,U2U,U2UU2U, \ + branch_2_1,load_2_1,read_2_1, \ + branch_1_2,load_1_2,read_1_2, \ + branch_1_1,load_1_1,read_1_1, \ + branch_1_0,load_1_0,read_1_0, \ + UI2xld_2_1,UI3xld_2_1,UI4xld_2_1,UI5xld_2_1, \ + UI2xld_1_1,UI3xld_1_1,UI4xld_1_1,UI5xld_1_1, \ + UI2xld_1_0,UI3xld_1_0,UI4xld_1_0,UI5xld_1_0, \ + UI2xst,UI3xst,UI4xst,UI5xst,\ + FP, FPmas, FPrecip, FPrecipmas" + "metag_consumer_is_cond_p") + +;; SWAP has to write two registers so in effect takes 2 cycles rather than one so it is +;; a slightly slower case. +(define_bypass 4 "UIswap" + "UIother,UI,UIswap,UImult, \ + UIUI,UIUIUI,UIUIUIUI,UIUIUIUIUI,U2U,U2UU2U, \ + branch_2_1,load_2_1,read_2_1, \ + branch_1_2,load_1_2,read_1_2, \ + branch_1_1,load_1_1,read_1_1, \ + branch_1_0,load_1_0,read_1_0, \ + UI2xld_2_1,UI3xld_2_1,UI4xld_2_1,UI5xld_2_1, \ + UI2xld_1_1,UI3xld_1_1,UI4xld_1_1,UI5xld_1_1, \ + UI2xld_1_0,UI3xld_1_0,UI4xld_1_0,UI5xld_1_0, \ + UI2xst,UI3xst,UI4xst,UI5xst, \ + FP, FPmas, FPrecip, FPrecipmas" + "metag_consumer_is_cond_p") + +;; Regalloc/reload needs registers to have the shortest possible lifetime in order to +;; successfully allocate registers. D0Re0, D1Re0, D1Ar6, D0Ar5 are very popular +;; especially with modes that require 2 registers, load/store multiops, +;; base + 12bit offset memory operations, argument registers, return registers... + +;; The automata is very pessimistic when it comes across insns with multiple opcodes +;; it assumes that they will never be split. In reality almost all are split and +;; therefore scheduling them as one block before reload has a negative effect on +;; the associated registers lifetime (it increases). To counter this we bypass the +;; automata prior to reload to say that multi opcode insns actually have no latency, +;; i.e. ignore them completely, there is nothing that can be inferred. +;; After reload they are treated as proper insns. + +;; The reduced lifetime gives the register allocator and reload more scope to fulfil +;; insns constraints. +(define_bypass 0 "UIUI,UIUIUI,UIUIUIUI,UIUIUIUIUI,U2U,U2UU2U" + "UI,UIswap,UIother,UImult,UIUI,UIUIUI,UIUIUIUI,UIUIUIUIUI, \ + U2U,U2UU2U,FP,FPmas,FPrecip,FPrecipmas, \ + branch_2_1,load_2_1,read_2_1, \ + branch_1_2,load_1_2,read_1_2, \ + branch_1_1,load_1_1,read_1_1, \ + branch_1_0,load_1_0,read_1_0, \ + UI2xld_2_1,UI3xld_2_1,UI4xld_2_1,UI5xld_2_1, \ + UI2xld_1_1,UI3xld_1_1,UI4xld_1_1,UI5xld_1_1, \ + UI2xld_1_0,UI3xld_1_0,UI4xld_1_0,UI5xld_1_0, \ + UI2xst,UI3xst,UI4xst,UI5xst" + "metag_bypass_before_reload_p") + diff -Nur gcc-4.2.4.orig/gcc/config/metag/predicates.md gcc-4.2.4/gcc/config/metag/predicates.md --- gcc-4.2.4.orig/gcc/config/metag/predicates.md 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/predicates.md 2015-07-03 18:46:05.773283541 -0500 @@ -0,0 +1,815 @@ +;; Predicate definitions for META +;; Copyright (C) 2007, 2010 Imagination Technologies Ltd + +;; This file is part of GCC. + +;; GCC is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 3, or (at your option) any later +;; version. + +;; GCC is distributed in the hope that it will be useful, but WITHOUT ANY +;; WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; . + +(define_predicate "metag_register_op" +(match_code "subreg,reg") +{ + if (!register_operand (op, mode)) + return false; + + if (SUBREG_P (op)) + op = SUBREG_REG (op); + + return !REG_P (op) || (REGNO (op) != TXRPT_REG + && REGNO (op) != TTREC_REG); +}) + +(define_predicate "metag_reg_nofloat_op" +(match_code "subreg,reg") +{ + if (!register_operand (op, mode)) + return false; + + if (SUBREG_P (op)) + op = SUBREG_REG (op); + + return (!REG_P (op) || (REGNO (op) != TXRPT_REG + && REGNO (op) != TTREC_REG)) + && !METAG_FPC_REG_P (REGNO (op)); +}) + +;; Any hard data register +(define_predicate "metag_hard_datareg_op" +(match_code "reg") +{ + unsigned int regno = REGNO (op); + + return mode == GET_MODE (op) + && METAG_DATA_REG_P (regno); +}) + +;; Any hard address register +(define_predicate "metag_hard_addrreg_op" +(match_code "reg") +{ + unsigned int regno = REGNO (op); + + return mode == GET_MODE (op) + && METAG_ADDR_REG_P (regno); +}) + +;; Any hard gen register +(define_predicate "metag_hard_genreg_op" +(ior (match_operand 0 "metag_hard_datareg_op") + (match_operand 0 "metag_hard_addrreg_op"))) + +(define_predicate "metag_regnofrm_op" +(match_code "subreg,reg") +{ + if (metag_reg_nofloat_op (op, mode)) + { + /* Subreg can hide a lot of non-reg things that we don't want! */ + if (SUBREG_P (op)) + op = SUBREG_REG (op); + + /* Reject all stack frame related pointers. */ + return !metag_frame_related_rtx (op); + } + + return false; +}) + + +(define_predicate "metag_regframe_op" +(match_code "subreg,reg") +{ + if (metag_register_op (op, mode)) + { + /* Subreg can hide a lot of non-reg things that we don't want! */ + if (SUBREG_P (op)) + op = SUBREG_REG (op); + + /* Accept only stack relasted pointers */ + return metag_frame_related_rtx (op); + } + + return false; +}) + +(define_predicate "metag_regorint_op" +(match_code "subreg,reg,const_int") +{ + /* Integer constants are allowed */ + if (CONST_INT_P (op)) + return true; + + return metag_register_op (op, mode); +}) + +(define_predicate "metag_okbindex_op" +(and (match_code "const_int") + (match_test "satisfies_constraint_O1 (op)"))) + +(define_predicate "metag_okwindex_op" +(and (match_code "const_int") + (match_test "satisfies_constraint_O2 (op)"))) + +(define_predicate "metag_okdindex_op" +(and (match_code "const_int") + (match_test "satisfies_constraint_O4 (op)"))) + +(define_predicate "metag_oklindex_op" +(and (match_code "const_int") + (match_test "satisfies_constraint_O8 (op)"))) + +(define_predicate "metag_int_operand" +(and (match_code "const_int") + (match_test "METAG_LETTER_FOR_CONST (op) != 0"))) + +(define_predicate "metag_smallint_op" +(and (match_code "const_int") + (match_test "(INTVAL (op) >= -255 && INTVAL (op) <= 255)"))) + +(define_predicate "metag_bigint_op" +(match_code "const_int")) + +(define_predicate "symbolic_operand" +(match_code "symbol_ref")) + +(define_predicate "metag_symsmall_op" +(and (match_code "symbol_ref") + (match_test "METAG_SYMBOL_FLAG_SMALL_P (op)"))) + +(define_predicate "metag_symlarge_op" +(and (match_code "symbol_ref") + (match_test "METAG_SYMBOL_FLAG_LARGE_P (op)"))) + +(define_predicate "metag_symglobal_op" +(and (match_code "symbol_ref") + (match_test "METAG_SYMBOL_FLAG_GLOBAL_P (op)"))) + +(define_predicate "metag_symdirect_op" +(and (match_code "symbol_ref") + (match_test "METAG_SYMBOL_FLAG_DIRECT_P (op)"))) + +(define_predicate "metag_call_addr" +(and (match_code "mem") + (ior (match_test "SYMBOL_REF_P (XEXP (op, 0))") + (match_test "REG_P (XEXP (op, 0))")))) + +(define_predicate "code_address" +(match_code "label_ref,symbol_ref") +{ + /* Label references are the easy bit */ + if (LABEL_REF_P (op)) + return true; + + if (METAG_FLAG_PIC) + return false; + + return SYMBOL_REF_P (op) + && !METAG_SYMBOL_FLAG_SMALL_P (op) + && !METAG_SYMBOL_FLAG_LARGE_P (op) + && !METAG_SYMBOL_FLAG_GLOBAL_P (op) + && (SYMBOL_REF_TLS_MODEL (op) == TLS_MODEL_NONE); +}) + +(define_predicate "metag_cc_reg" +(match_code "reg") +{ + if (mode == VOIDmode) + { + mode = GET_MODE (op); + if (GET_MODE_CLASS (mode) != MODE_CC) + return false; + } + + return (mode == GET_MODE (op) + && REG_P (op) + && REGNO (op) == MCC_REGNUM); +}) + +(define_predicate "metag_cc_noov_reg" +(match_code "reg") +{ + if (mode == VOIDmode) + { + mode = GET_MODE (op); + if (GET_MODE_CLASS (mode) != MODE_CC) + return false; + } + + return (mode == GET_MODE (op) + && REG_P (op) + && REGNO (op) == MCC_REGNUM); +}) + +(define_predicate "metag_cc_z_reg" +(match_code "reg") +{ + if (mode == VOIDmode) + { + mode = GET_MODE (op); + if (GET_MODE_CLASS (mode) != MODE_CC) + return false; + } + + return (mode == GET_MODE (op) + && REG_P (op) + && REGNO (op) == MCC_REGNUM); +}) + +(define_predicate "metag_cc_fp_reg" +(match_code "reg") +{ + if (mode == VOIDmode) + { + mode = GET_MODE (op); + if (GET_MODE_CLASS (mode) != MODE_CC) + return false; + } + + return (mode == GET_MODE (op) + && REG_P (op) + && REGNO (op) == MCC_REGNUM); +}) + +(define_predicate "metag_cc_fp_q_reg" +(match_code "reg") +{ + if (mode == VOIDmode) + { + mode = GET_MODE (op); + if (GET_MODE_CLASS (mode) != MODE_CC) + return false; + } + + return (mode == GET_MODE (op) + && REG_P (op) + && REGNO (op) == MCC_REGNUM); +}) + +(define_predicate "load_multiop" +(match_code "parallel") +{ + HOST_WIDE_INT count = XVECLEN (op, 0); + unsigned int dst_regno; + enum machine_mode xfer_mode; + unsigned int word_size; + unsigned int lastreg; + rtx src_addr; + enum reg_class dst_regclass; + HOST_WIDE_INT i; + rtx elt; + rtx src; + rtx dst; + + elt = XVECEXP (op, 0, 0); + if (count < 2 || count > 8 || GET_CODE (elt) != SET) + return false; + + src = SET_SRC (elt); + dst = SET_DEST (elt); + + if (GET_CODE (src) != PLUS) + return false; + + elt = XVECEXP (op, 0, 1); + if (GET_CODE (elt) != SET) + return false; + + /* Work out if this is SImode or DImode case */ + xfer_mode = GET_MODE (SET_SRC (elt)); + word_size = GET_MODE_SIZE (xfer_mode); + + if (word_size == 4 && count <= 2) + return false; + + /* Now check it more carefully */ + if (!REG_P (dst) + || !REG_P (XEXP (src, 0)) + || REGNO (XEXP (src, 0)) != REGNO (dst) + || !CONST_INT_P (XEXP (src, 1)) + || INTVAL (XEXP (src, 1)) != (HOST_WIDE_INT)((count - 1) * word_size)) + return false; + + src = SET_SRC (elt); + dst = SET_DEST (elt); + + /* Perform a quick check so we don't blow up below. */ + if (!REG_P (dst) || !MEM_P (src)) + return false; + + lastreg = REGNO (dst); + dst_regno = REGNO (dst); + src_addr = XEXP (src, 0); + dst_regclass = METAG_REGNO_REG_CLASS (dst_regno); + + for (i = 2; i < count; i++) + { + elt = XVECEXP (op, 0, i); + if (GET_CODE (elt) != SET) + return false; + + src = SET_SRC (elt); + dst = SET_DEST (elt); + + if (!REG_P (dst) + || GET_MODE (dst) != xfer_mode + || REGNO (dst) - dst_regno > 2 * word_size + || REGNO (dst) <= lastreg + || METAG_REGNO_REG_CLASS (REGNO (dst)) != dst_regclass + || !MEM_P (src) + || GET_MODE (src) != xfer_mode + || GET_CODE (XEXP (src, 0)) != PLUS + || !rtx_equal_p (XEXP (XEXP (src, 0), 0), src_addr) + || !CONST_INT_P (XEXP (XEXP (src, 0), 1)) + || INTVAL (XEXP (XEXP (src, 0), 1)) != (HOST_WIDE_INT)((i - 1) * word_size)) + return false; + + lastreg = REGNO (dst); + } + + return true; +}) + +(define_predicate "store_multiop" +(match_code "parallel") +{ + HOST_WIDE_INT count = XVECLEN (op, 0); + unsigned int src_regno; + enum machine_mode xfer_mode; + unsigned int word_size; + unsigned int lastreg; + enum reg_class src_regclass; + rtx dst_addr; + HOST_WIDE_INT i; + rtx elt; + rtx src; + rtx dst; + + elt = XVECEXP (op, 0, 0); + if (count <= 2 || count > 9 || GET_CODE (elt) != SET) + return false; + + dst = SET_DEST (elt); + src = SET_SRC (elt); + + if (GET_CODE (src) != PLUS) + return false; + + elt = XVECEXP (op, 0, 1); + if (GET_CODE (elt) != SET) + return false; + + /* Work out if this is SImode or DImode case */ + xfer_mode = GET_MODE (SET_DEST (elt)); + word_size = GET_MODE_SIZE (xfer_mode); + + /* Now check it more carefully */ + if (!REG_P (dst) + || !REG_P (XEXP (src, 0)) + || REGNO (XEXP (src, 0)) != REGNO (dst) + || !CONST_INT_P (XEXP (src, 1)) + || INTVAL (XEXP (src, 1)) != (HOST_WIDE_INT)((count - 1) * word_size)) + return false; + + src = SET_SRC (elt); + dst = SET_DEST (elt); + + /* Perform a quick check so we don't blow up below. */ + if (!MEM_P (dst) || !REG_P (src)) + return false; + + lastreg = REGNO (src); + src_regno = REGNO (src); + dst_addr = XEXP (dst, 0); + src_regclass = METAG_REGNO_REG_CLASS (src_regno); + + for (i = 2; i < count; i++) + { + elt = XVECEXP (op, 0, i); + if (GET_CODE (elt) != SET) + return false; + + src = SET_SRC (elt); + dst = SET_DEST (elt); + + if (!REG_P (src) + || GET_MODE (src) != xfer_mode + || REGNO (src) - src_regno > 2 * word_size + || REGNO (src) <= lastreg + || METAG_REGNO_REG_CLASS (REGNO (src)) != src_regclass + || !MEM_P (dst) + || GET_MODE (dst) != xfer_mode + || GET_CODE (XEXP (dst, 0)) != PLUS + || !rtx_equal_p (XEXP (XEXP (dst, 0), 0), dst_addr) + || !CONST_INT_P (XEXP (XEXP (dst, 0), 1)) + || INTVAL (XEXP (XEXP (dst, 0), 1)) != (HOST_WIDE_INT)((i - 1) * word_size)) + return false; + + lastreg = REGNO (src); + } + + return true; +}) + +(define_predicate "metag_datareg_op" +(and (match_code "subreg,reg") + (match_operand 0 "metag_register_op")) +{ + unsigned int regno; + + if (SUBREG_P (op)) + op = SUBREG_REG (op); + + /* A subreg may refer to a mem before reload, metag_register_op ensures + that reload has not completed if it is a mem */ + if (!REG_P (op)) + return true; + + regno = REGNO (op); + + if (regno >= FIRST_PSEUDO_REGISTER) + return true; + + return METAG_DATA_REG_P (regno); +}) + +(define_predicate "metag_addrreg_op" +(and (match_code "subreg,reg") + (match_operand 0 "metag_register_op")) +{ + unsigned int regno; + + if (SUBREG_P (op)) + op = SUBREG_REG (op); + + /* A subreg may refer to a mem before reload, metag_register_op ensures + that reload has not completed if it is a mem */ + if (!REG_P (op)) + return true; + + regno = REGNO (op); + + if (regno >= FIRST_PSEUDO_REGISTER) + return true; + + return METAG_ADDR_REG_P (regno); +}) + +(define_predicate "metag_fpreg_op" +(and (match_code "subreg,reg") + (match_operand 0 "metag_register_op")) +{ + unsigned int regno; + + if (SUBREG_P (op)) + op = SUBREG_REG (op); + + /* A subreg may refer to a mem before reload, metag_register_op ensures + that reload has not completed if it is a mem */ + if (!REG_P (op)) + return true; + + regno = REGNO (op); + + if (regno >= FIRST_PSEUDO_REGISTER) + return true; + + return METAG_FPC_REG_P (regno); +}) + +(define_predicate "metag_fpreg_or_dreg_op" +(and (match_code "subreg,reg") + (match_operand 0 "metag_register_op")) +{ + unsigned int regno; + + if (SUBREG_P (op)) + op = SUBREG_REG (op); + + /* A subreg may refer to a mem before reload, metag_register_op ensures + that reload has not completed if it is a mem */ + if (!REG_P (op)) + return true; + + regno = REGNO (op); + + if (regno >= FIRST_PSEUDO_REGISTER) + return true; + + return METAG_FPC_REG_P (regno) || METAG_DATA_REG_P (regno); +}) + +(define_predicate "metag_txrpt_op" +(and (match_code "reg") + (match_test "REGNO (op) == TXRPT_REGNUM"))) + +(define_predicate "metag_ttrec_op" +(and (match_code "reg") + (match_test "REGNO (op) == TTREC_REGNUM"))) + +;; Return true if OP is a valid TXRPT_REGNUM +;; source operand that can be loaded quickly for the given mode +(define_predicate "metag_txrpt_src_op" +(ior (and (match_code "const_int") + (match_test "satisfies_constraint_I (op) + || satisfies_constraint_K (op) + || satisfies_constraint_P (op) + || satisfies_constraint_J (op)")) + (match_code "reg"))) + +(define_predicate "metag_16bit_op" +(and (match_code "const_int") + (match_test "-32768 <= INTVAL (op) && INTVAL (op) <= 32767"))) + +(define_predicate "metag_vector_float_op" +(match_code "const_vector") +{ + int nunits = GET_MODE_NUNITS (mode); + + if (GET_CODE (op) == CONST_VECTOR + && CONST_VECTOR_NUNITS (op) == nunits) + { + int i; + for (i = 0; i < nunits; ++i) + { + rtx x = CONST_VECTOR_ELT (op, i); + if (!metag_fphalf_imm_op (x, GET_MODE_INNER (mode))) + return false; + } + return true; + } + return false; +}) + +(define_predicate "metag_vector_int_op" +(match_code "const_vector") +{ + int nunits = GET_MODE_NUNITS (mode); + + if (GET_CODE (op) == CONST_VECTOR + && CONST_VECTOR_NUNITS (op) == nunits) + { + int i; + for (i = 0; i < nunits; ++i) + { + rtx x = CONST_VECTOR_ELT (op, i); + if (!CONST_INT_P (x)) + return false; + } + return true; + } + return false; +}) + +(define_predicate "metag_vector_16bit_op" + (match_code "const_vector") +{ + int nunits = GET_MODE_NUNITS (mode); + + if (GET_CODE (op) == CONST_VECTOR + && CONST_VECTOR_NUNITS (op) == nunits) + { + int i; + HOST_WIDE_INT val = INTVAL (CONST_VECTOR_ELT (op, 0)); + for (i = 0; i < nunits; ++i) + { + rtx x = CONST_VECTOR_ELT (op, i); + if (!metag_16bit_op (x, GET_MODE_INNER (mode))) + return false; + if (val != INTVAL (x)) + return false; + } + return true; + } + return false; +}) + +(define_predicate "metag_5bit_op" +(and (match_code "const_int") + (match_test "0 <= INTVAL (op) && INTVAL (op) <= 31"))) + +(define_predicate "metag_vector_5bit_op" + (match_code "const_vector") +{ + int nunits = GET_MODE_NUNITS (mode); + + if (GET_CODE (op) == CONST_VECTOR + && CONST_VECTOR_NUNITS (op) == nunits) + { + int i; + HOST_WIDE_INT val = INTVAL (CONST_VECTOR_ELT (op, 0)); + for (i = 0; i < nunits; ++i) + { + rtx x = CONST_VECTOR_ELT (op, i); + if (!metag_5bit_op (x, GET_MODE_INNER (mode))) + return false; + if (val != INTVAL (x)) + return false; + } + return true; + } + return false; +}) + +(define_predicate "metag_K_operand" +(and (match_code "const_int") + (match_test "satisfies_constraint_K (op)"))) + +(define_predicate "metag_L_operand" +(and (match_code "const_int") + (match_test "satisfies_constraint_L (op)"))) + +(define_predicate "metag_J_operand" +(and (match_code "const_int") + (match_test "satisfies_constraint_J (op)"))) + +(define_predicate "metag_O0_operand" +(and (match_code "const_int") + (match_test "satisfies_constraint_O0 (op)"))) + +(define_predicate "metag_O3_operand" +(and (match_code "const_int") + (match_test "satisfies_constraint_O3 (op)"))) + +(define_predicate "metag_P_operand" +(and (match_code "const_int") + (match_test "satisfies_constraint_P (op)"))) + +(define_predicate "metag_KP_operand" +(and (match_code "const_int") + (ior (match_test "satisfies_constraint_K (op)") + (match_test "satisfies_constraint_P (op)")))) + +(define_predicate "metag_KIP_operand" +(and (match_code "const_int") + (ior (match_test "satisfies_constraint_K (op)") + (ior (match_test "satisfies_constraint_P (op)") + (match_test "satisfies_constraint_I (op)"))))) + +(define_predicate "metag_pic_reg" +(and (match_code "reg") + (ior (match_test "op == pic_offset_table_rtx") + (and (match_code "reg") + (match_test "REGNO (op) == PIC_OFFSET_TABLE_REGNUM"))))) + +(define_predicate "metag_offset12_qi" +(and (match_code "const_int") + (match_test "satisfies_constraint_Z1 (op)"))) + +(define_predicate "metag_offset12_hi" +(and (match_code "const_int") + (match_test "satisfies_constraint_Z2 (op)"))) + +(define_predicate "metag_offset12_si" +(and (match_code "const_int") + (match_test "satisfies_constraint_Z4 (op)"))) + +(define_predicate "metag_offset12_di" +(and (match_code "const_int") + (match_test "satisfies_constraint_Z8 (op)"))) + +(define_predicate "metag_offset12_sf" +(and (match_code "const_int") + (match_test "satisfies_constraint_Z4 (op)"))) + +(define_predicate "metag_offset12_df" +(and (match_code "const_int") + (match_test "satisfies_constraint_Z8 (op)"))) + +(define_predicate "metag_offset12_v2si" +(and (match_code "const_int") + (match_test "satisfies_constraint_Z8 (op)"))) + +(define_predicate "metag_offset12_v2sf" +(and (match_code "const_int") + (match_test "satisfies_constraint_Z8 (op)"))) + +(define_predicate "metag_offset6_qi" +(and (match_code "const_int") + (match_test "satisfies_constraint_O1 (op)"))) + +(define_predicate "metag_offset6_hi" +(and (match_code "const_int") + (match_test "satisfies_constraint_O2 (op)"))) + +(define_predicate "metag_offset6_si" +(and (match_code "const_int") + (match_test "satisfies_constraint_O4 (op)"))) + +(define_predicate "metag_offset6_di" +(and (match_code "const_int") + (match_test "satisfies_constraint_O8 (op)"))) + +(define_predicate "metag_offset6_sf" +(and (match_code "const_int") + (match_test "satisfies_constraint_O4 (op)"))) + +(define_predicate "metag_offset6_df" +(and (match_code "const_int") + (match_test "satisfies_constraint_O8 (op)"))) + +(define_predicate "metag_offset6_v2si" +(and (match_code "const_int") + (match_test "satisfies_constraint_O8 (op)"))) + +(define_predicate "metag_offset6_v2sf" +(and (match_code "const_int") + (match_test "satisfies_constraint_O8 (op)"))) + +(define_predicate "metag_reg12bit_op" +(match_code "subreg,reg") +{ + if (metag_register_op (op, mode)) + { + if (SUBREG_P (op)) + op = SUBREG_REG (op); + + if (REG_P (op)) + { + unsigned regno = REGNO (op); + + if (regno == INVALID_REGNUM) + return false; + else if (regno >= FIRST_PSEUDO_REGISTER) + return !reload_completed; + else if (metag_regno12bit_p (regno)) + return true; + else if (!reload_completed && !reload_in_progress) + return (regno == FRAME_REG || regno == ARGP_REG); + } + } + + return false; +}) + +(define_predicate "metag_fphalf_imm_op" +(match_code "const_double") +{ + bool inexact = false; + + if (mode != SFmode && mode != DFmode) + return false; + + metag_const_double_to_hp (op, &inexact); + return !inexact; +}) + +(define_predicate "metag_fpreg_or_imm_op" +(ior (and (match_code "subreg,reg") + (match_operand 0 "metag_register_op")) + (match_code "const_double")) +{ + if (SUBREG_P (op)) + op = SUBREG_REG (op); + + if (REG_P(op)) + { + unsigned int regno = REGNO (op); + + if (regno >= FIRST_PSEUDO_REGISTER) + return true; + + return METAG_FPC_REG_P (regno); + } + else + return GET_CODE (op) == CONST_DOUBLE + && GET_MODE_CLASS (mode) == MODE_FLOAT; +}) + +(define_predicate "metag_fpreg_or_fpzero_imm_op" +(ior (and (match_code "subreg,reg") + (match_operand 0 "metag_register_op")) + (match_code "const_double")) +{ + if (SUBREG_P (op)) + op = SUBREG_REG (op); + + if (REG_P (op)) + { + unsigned int regno = REGNO (op); + + if (regno >= FIRST_PSEUDO_REGISTER) + return true; + + return METAG_FPC_REG_P (regno); + } + else + return GET_CODE (op) == CONST_DOUBLE + && GET_MODE_CLASS (mode) == MODE_FLOAT + && op == CONST0_RTX (mode); +}) + +(define_predicate "metag_fpone_imm_op" + (match_code "const_double") +{ + return satisfies_constraint_H (op); +}) diff -Nur gcc-4.2.4.orig/gcc/config/metag/t-linux gcc-4.2.4/gcc/config/metag/t-linux --- gcc-4.2.4.orig/gcc/config/metag/t-linux 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/t-linux 2015-07-03 18:46:05.773283541 -0500 @@ -0,0 +1,46 @@ +# t-linux +# Copyright (C) 2011 Imagination Technologies Ltd + +# This file is part of GCC. + +# GCC is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3, or (at your option) any later +# version. +# +# GCC is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . + +# Don't run fixproto +STMP_FIXPROTO = + +# Don't install "assert.h" in gcc. We use the one in uClibc. +INSTALL_ASSERT_H = + +# Compile crtbeginS.o and crtendS.o with pic. +CRTSTUFF_T_CFLAGS_S = -fPIC + +# Compile crtbegin.o and crtend.o without pic. +CRTSTUFF_T_CFLAGS = + +# Compile libgcc2.a +TARGET_LIBGCC2_CFLAGS = -fomit-frame-pointer -fPIC +LIBGCC2_DEBUG_CFLAGS = -g0 + +CROSS_LIBGCC1 = libgcc1-asm.a +LIBGCC1 = libgcc1-asm.a +LIB1ASMSRC = metag/lib1funcs.asm +LIB1ASMFUNCS = _udivsi3 \ + _divsi3 \ + _umodsi3 \ + _modsi3 \ + +# Don't make libgcc1-test since it will fail because it tries to link with liblow.a which doesn't exist for linux toolchain! +LIBGCC1_TEST = + diff -Nur gcc-4.2.4.orig/gcc/config/metag/t-linux-2.1 gcc-4.2.4/gcc/config/metag/t-linux-2.1 --- gcc-4.2.4.orig/gcc/config/metag/t-linux-2.1 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/t-linux-2.1 2015-07-03 18:46:05.773283541 -0500 @@ -0,0 +1,20 @@ +# t-linux-2.1 +# Copyright (C) 2012 Imagination Technologies Ltd + +# This file is part of GCC. + +# GCC is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3, or (at your option) any later +# version. +# +# GCC is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . + +LIB2FUNCS_STATIC_EXTRA += $(srcdir)/config/metag/linux-atomic.asm diff -Nur gcc-4.2.4.orig/gcc/config/metag/tls.md gcc-4.2.4/gcc/config/metag/tls.md --- gcc-4.2.4.orig/gcc/config/metag/tls.md 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/tls.md 2015-07-03 18:46:05.773283541 -0500 @@ -0,0 +1,205 @@ +;; Machine description for Thread-Local Storage, +;; Imagination Technologies Meta version. +;; Copyright (C) 2009, 2010 +;; Imagination Technologies Ltd + +;; This file is part of GCC. + +;; GCC is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 3, or (at your option) any later +;; version. + +;; GCC is distributed in the hope that it will be useful, but WITHOUT ANY +;; WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; . + +;;Global dynamic insns to set up the call to __tls_get_addr +;;These insns will generate the same code for PIC and non PIC cases +(define_insn "*tls_gd_sum" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0") + (const:SI (unspec [(match_operand:SI 2 "tgd_symbolic_operand" "")] UNSPEC_TLSGD))))] + "METAG_HAVE_TLS" + "ADD\\t%0, %1, #(%c2@TLSGD)" + [(set_attr "type" "fast")]) + +(define_insn_and_split "tls_gd" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 1 "metag_pic_reg" "a") + (const:SI (unspec [(match_operand:SI 2 "tgd_symbolic_operand" "")] UNSPEC_TLSGD))))] + "METAG_HAVE_TLS && operands[1] == pic_offset_table_rtx" + "#" + "&& SPLIT_HI_LO_SUM_EARLY" + [(set (match_dup 0) + (match_dup 1)) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const:SI (unspec [(match_dup 2)] UNSPEC_TLSGD))))] + "" + []) + +;;Local dynamic insns to set up the call to __tls_get_addr to get the address of the start of the current module. +;;These insns will generate the same code for PIC and non PIC cases +(define_insn "*tls_ldm_sum" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0") + (const:SI (unspec [(match_operand:SI 2 "tld_symbolic_operand" "")] UNSPEC_TLSLDM))))] + "METAG_HAVE_TLS" + "ADD\\t%0, %1, #(%c2@TLSLDM)" + [(set_attr "type" "fast")]) + +(define_insn_and_split "tls_ldm" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 1 "metag_pic_reg" "a") + (const:SI (unspec [(match_operand:SI 2 "tld_symbolic_operand" "")] UNSPEC_TLSLDM))))] + "METAG_HAVE_TLS && operands[1] == pic_offset_table_rtx" + "#" + "&& SPLIT_HI_LO_SUM_EARLY" + [(set (match_dup 0) + (match_dup 1)) + (set (match_dup 0) + (plus:SI (match_dup 0) + (const:SI (unspec [(match_dup 2)] UNSPEC_TLSLDM))))] + "" + []) + +;;Local dynamic insns to compute the location of the TLS object from the start of the current TLS block. +(define_insn "*tls_ldo_high" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0") + (high:SI (const:SI (unspec [(match_operand:SI 2 "tld_symbolic_operand" "")] UNSPEC_TLSLDO)))))] + "METAG_HAVE_TLS" + "ADDT\\t%0, %1, #HI(%c2@TLSLDO)" + [(set_attr "type" "fast")]) + +(define_insn "*tls_ldo_lo_sum" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (lo_sum:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0") + (const:SI (unspec [(match_operand:SI 2 "tld_symbolic_operand" "")] UNSPEC_TLSLDO))))] + "METAG_HAVE_TLS" + "ADD\\t%0, %1, #LO(%c2@TLSLDO)" + [(set_attr "type" "fast")]) + +(define_insn_and_split "tls_ldo" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "da") + (const:SI (unspec [(match_operand:SI 2 "tld_symbolic_operand" "")] UNSPEC_TLSLDO))))] + "METAG_HAVE_TLS" + "#" + "&& SPLIT_HI_LO_SUM_EARLY" + [(set (match_dup 0) + (match_dup 1)) + (set (match_dup 0) + (plus:SI (match_dup 0) + (high:SI (const:SI (unspec [(match_dup 2)] UNSPEC_TLSLDO))))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (const:SI (unspec [(match_dup 2)] UNSPEC_TLSLDO))))] + "" + []) + +;;Initial exec insn for PIC. +(define_insn "tls_ie" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (mem:SI (plus:SI (match_operand:SI 1 "metag_pic_reg" "a") + (const:SI (unspec [(match_operand:SI 2 "tie_symbolic_operand" "")] UNSPEC_TLSIE)))))] + "METAG_HAVE_TLS && METAG_FLAG_PIC && operands[1] == pic_offset_table_rtx" + "GETD\t%0, [A1LbP+#(%c2@TLSIE)]") + +;;Initial exec insns for non-PIC. +(define_insn "*tls_non_pic_ie_high" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (high:SI (const:SI (unspec [(match_operand:SI 1 "tie_symbolic_operand" "")] UNSPEC_TLSIE))))] + "METAG_HAVE_TLS" + "MOVT\\t%0, #HI(%c1@TLSIENONPIC)" + [(set_attr "type" "fast")]) + +(define_insn "*tls_non_pic_ie_lo_sum" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (lo_sum:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0") + (const:SI (unspec [(match_operand:SI 2 "tie_symbolic_operand" "")] UNSPEC_TLSIE))))] + "METAG_HAVE_TLS" + "ADD\\t%0, %1, #LO(%c2@TLSIENONPIC)" + [(set_attr "type" "fast")]) + +(define_insn_and_split "tls_non_pic_ie" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (const:SI (unspec [(match_operand:SI 1 "tie_symbolic_operand" "")] UNSPEC_TLSIE)))] + "METAG_HAVE_TLS" + "#" + "&& SPLIT_HI_LO_SUM_EARLY" + [(set (match_dup 0) + (high:SI (const:SI (unspec [(match_dup 1)] UNSPEC_TLSIE)))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (const:SI (unspec [(match_dup 1)] UNSPEC_TLSIE))))] + "" + []) + +;;Local exec insns +(define_insn "*tls_le_high" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0") + (high:SI (const:SI (unspec [(match_operand:SI 2 "tle_symbolic_operand" "")] UNSPEC_TLSLE)))))] + "METAG_HAVE_TLS" + "ADDT\\t%0, %1, #HI(%c2@TLSLE)" + [(set_attr "type" "fast")]) + +(define_insn "*tls_le_lo_sum" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (lo_sum:SI (match_operand:SI 1 "metag_reg_nofloat_op" "0") + (const:SI (unspec [(match_operand:SI 2 "tle_symbolic_operand" "")] UNSPEC_TLSLE))))] + "METAG_HAVE_TLS" + "ADD\\t%0, %1, #LO(%c2@TLSLE)" + [(set_attr "type" "fast")]) + +(define_insn_and_split "tls_le" + [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da") + (plus:SI (match_operand:SI 1 "metag_reg_nofloat_op" "da") + (const:SI (unspec [(match_operand:SI 2 "tle_symbolic_operand" "")] UNSPEC_TLSLE))))] + "METAG_HAVE_TLS" + "#" + "&& SPLIT_HI_LO_SUM_EARLY" + [(set (match_dup 0) + (match_dup 1)) + (set (match_dup 0) + (plus:SI (match_dup 0) + (high:SI (const:SI (unspec [(match_dup 2)] UNSPEC_TLSLE))))) + (set (match_dup 0) + (lo_sum:SI (match_dup 0) + (const:SI (unspec [(match_dup 2)] UNSPEC_TLSLE))))] + "" + []) + +;; +;; Predicates +;; + +;; Return true if OP is a symbolic operand for the TLS Global Dynamic model. +(define_predicate "tgd_symbolic_operand" + (and (match_code "symbol_ref") + (match_test "SYMBOL_REF_TLS_MODEL (op) == TLS_MODEL_GLOBAL_DYNAMIC"))) + +;; Return true if OP is a symbolic operand for the TLS Local Dynamic model. +(define_predicate "tld_symbolic_operand" + (and (match_code "symbol_ref") + (match_test "SYMBOL_REF_TLS_MODEL (op) == TLS_MODEL_LOCAL_DYNAMIC"))) + +;; Return true if OP is a symbolic operand for the TLS Initial Exec model. +(define_predicate "tie_symbolic_operand" + (and (match_code "symbol_ref") + (match_test "SYMBOL_REF_TLS_MODEL (op) == TLS_MODEL_INITIAL_EXEC"))) + +;; Return true if OP is a symbolic operand for the TLS Local Exec model. +(define_predicate "tle_symbolic_operand" + (and (match_code "symbol_ref") + (match_test "SYMBOL_REF_TLS_MODEL (op) == TLS_MODEL_LOCAL_EXEC"))) + +;; end of file + diff -Nur gcc-4.2.4.orig/gcc/config/metag/t-metag gcc-4.2.4/gcc/config/metag/t-metag --- gcc-4.2.4.orig/gcc/config/metag/t-metag 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/t-metag 2015-07-03 18:46:05.773283541 -0500 @@ -0,0 +1,39 @@ +# Rules common to all metag targets +# Copyright (C) 2011 Imagination Technologies Ltd + +# This file is part of GCC. + +# GCC is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3, or (at your option) any later +# version. +# +# GCC is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . + +MD_INCLUDES=$(srcdir)/config/metag/constants.md \ + $(srcdir)/config/metag/predicates.md \ + $(srcdir)/config/metag/peephole2.md \ + $(srcdir)/config/metag/dsppeephole2.md \ + $(srcdir)/config/metag/constraints.md \ + $(srcdir)/config/metag/pipeline.md \ + $(srcdir)/config/metag/builtins.md \ + $(srcdir)/config/metag/peephole.md \ + $(srcdir)/config/metag/dsppeephole.md \ + $(srcdir)/config/metag/combines.md \ + $(srcdir)/config/metag/fp.md \ + $(srcdir)/config/metag/vector.md + +s-config s-conditions s-flags s-codes s-constants s-emit s-recog s-preds \ + s-opinit s-extract s-peep s-attr s-attrtab s-output: $(MD_INCLUDES) + +$(out_object_file): s-gtype + +driver-metag.o : $(srcdir)/config/metag/driver-metag.c + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< diff -Nur gcc-4.2.4.orig/gcc/config/metag/t-metag-linux gcc-4.2.4/gcc/config/metag/t-metag-linux --- gcc-4.2.4.orig/gcc/config/metag/t-metag-linux 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/t-metag-linux 2015-07-03 18:46:05.773283541 -0500 @@ -0,0 +1,44 @@ +# t-metag-linux +# Copyright (C) 2011 Imagination Technologies Ltd + +# This file is part of GCC. + +# GCC is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3, or (at your option) any later +# version. +# +# GCC is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . + +# WORK NEEDED: We have to have minim versions of libraries but will also need +# hardfloat variants +MULTILIB_OPTIONS= mminim +MULTILIB_DIRNAMES= minim +MULTILIB_EXCEPTIONS= +MULTILIB_MATCHES= + +# We want fine grained libraries, so use the new code to build the +# floating point emulation libraries. +FPBIT = fp-bit.c +DPBIT = dp-bit.c + +fp-bit.c: $(srcdir)/config/fp-bit.c + echo '#define FLOAT' >> fp-bit.c + cat $(srcdir)/config/fp-bit.c >> fp-bit.c + +dp-bit.c: $(srcdir)/config/fp-bit.c + cat $(srcdir)/config/fp-bit.c >> dp-bit.c + +metag-linux.o: $(srcdir)/config/metag/metag-linux.c $(CONFIG_H) $(SYSTEM_H) \ + coretypes.h $(TM_H) $(RTL_H) output.h flags.h $(TREE_H) \ + expr.h toplev.h $(TM_P_H) + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/metag/metag-linux.c + diff -Nur gcc-4.2.4.orig/gcc/config/metag/t-metag-slibgcc-elf-ver gcc-4.2.4/gcc/config/metag/t-metag-slibgcc-elf-ver --- gcc-4.2.4.orig/gcc/config/metag/t-metag-slibgcc-elf-ver 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/t-metag-slibgcc-elf-ver 2015-07-03 18:46:05.773283541 -0500 @@ -0,0 +1,37 @@ +# Build a shared libgcc library for ELF with symbol versioning +# with the GNU linker. + +SHLIB_EXT = .so +SHLIB_SOLINK = @shlib_base_name@.so +SHLIB_SOVERSION = 1 +SHLIB_SONAME = @shlib_base_name@.so.$(SHLIB_SOVERSION) +SHLIB_MAP = @shlib_map_file@ +SHLIB_OBJS = @shlib_objs@ +SHLIB_DIR = @multilib_dir@ +SHLIB_SLIBDIR_QUAL = @shlib_slibdir_qual@ +SHLIB_LC = -lc + +SHLIB_LINK = $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) -shared -nodefaultlibs \ + -Wl,--soname=$(SHLIB_SONAME) \ + -Wl,--version-script=$(SHLIB_MAP) \ + -o $(SHLIB_DIR)/$(SHLIB_SONAME).tmp @multilib_flags@ \ + $(SHLIB_OBJS) $(SHLIB_LC) && \ + rm -f $(SHLIB_DIR)/$(SHLIB_SOLINK) && \ + if [ -f $(SHLIB_DIR)/$(SHLIB_SONAME) ]; then \ + mv -f $(SHLIB_DIR)/$(SHLIB_SONAME) \ + $(SHLIB_DIR)/$(SHLIB_SONAME).backup; \ + else true; fi && \ + mv $(SHLIB_DIR)/$(SHLIB_SONAME).tmp $(SHLIB_DIR)/$(SHLIB_SONAME) && \ + $(LN_S) $(SHLIB_SONAME) $(SHLIB_DIR)/$(SHLIB_SOLINK) +# $(slibdir) double quoted to protect it from expansion while building +# libgcc.mk. We want this delayed until actual install time. +SHLIB_INSTALL = \ + $$(mkinstalldirs) $$(DESTDIR)$$(slibdir)$(SHLIB_SLIBDIR_QUAL); \ + $(INSTALL_DATA) $(SHLIB_DIR)/$(SHLIB_SONAME) \ + $$(DESTDIR)$$(slibdir)$(SHLIB_SLIBDIR_QUAL)/$(SHLIB_SONAME); \ + rm -f $$(DESTDIR)$$(slibdir)$(SHLIB_SLIBDIR_QUAL)/$(SHLIB_SOLINK); \ + $(LN_S) $(SHLIB_SONAME) \ + $$(DESTDIR)$$(slibdir)$(SHLIB_SLIBDIR_QUAL)/$(SHLIB_SOLINK) +SHLIB_MKMAP = $(srcdir)/mkmap-symver.awk +SHLIB_MKMAP_OPTS = -v leading_underscore=1 -v no_show_underscore=1 +SHLIB_MAPFILES = $(srcdir)/libgcc-std.ver diff -Nur gcc-4.2.4.orig/gcc/config/metag/vector.md gcc-4.2.4/gcc/config/metag/vector.md --- gcc-4.2.4.orig/gcc/config/metag/vector.md 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/vector.md 2015-07-03 18:46:05.773283541 -0500 @@ -0,0 +1,282 @@ +;; Machine description for GNU compiler, +;; Imagination Technologies Meta version. +;; Copyright (C) 2008 +;; Imagination Technologies Ltd + +;; This file is part of GCC. + +;; GCC is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 3, or (at your option) any later +;; version. + +;; GCC is distributed in the hope that it will be useful, but WITHOUT ANY +;; WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GCC; see the file COPYING3. If not see +;; . + +;; See comment at the top of dsppeephole.md for information about +;; dual unit DSP support in the metag backend. + +(define_insn "*movv2sirr" + [(set (match_operand:V2SI 0 "metag_datareg_op" "=d") + (match_operand:V2SI 1 "metag_datareg_op" "d"))] + "TARGET_DSP" + "DL\\tMOV\\t%0,%1\\t%@ (*mov v2si rr)" + [(set_attr "type" "fast")]) + +(define_insn_and_split "*movv2siri" + [(set (match_operand:V2SI 0 "metag_datareg_op" "=d") + (match_operand:V2SI 1 "metag_vector_int_op" "vci"))] + "TARGET_DSP + && !reload_completed + && !reload_in_progress" + "#" + "" + [(set (match_dup 2) + (match_dup 4)) + (set (match_dup 3) + (match_dup 5))] + { + operands[2] = gen_rtx_SUBREG (SImode, operands[0], 0); + operands[3] = gen_rtx_SUBREG (SImode, operands[0], UNITS_PER_WORD); + operands[4] = XVECEXP (operands[1], 0, 0); + operands[5] = XVECEXP (operands[1], 0, 1); + } + [(set_attr "type" "fast")]) + +(define_expand "movv2si" + [(set (match_operand:V2SI 0 "nonimmediate_operand" "") + (match_operand:V2SI 1 "general_operand" ""))] + "TARGET_DSP" + { + if (MEM_P (operands[0]) && !REG_P (operands[1])) + { + /* All except mem = const, mem = mem, or mem = addr can be done quickly */ + if (!no_new_pseudos) + operands[1] = force_reg (V2SImode, operands[1]); + } + + } +) + +(define_insn "*lod_v2si" + [(set (match_operand:V2SI 0 "metag_datareg_op" "=d") + (match_operand:V2SI 1 "memory_operand" "m"))] + "TARGET_DSP" + "GETL\\t%0, %t0, %1\\t%@ (*lod v2si rm OK)" + [(set_attr "memaccess" "load")]) + +(define_insn "*sto_v2si" + [(set (match_operand:V2SI 0 "memory_operand" "=Tr,Te,Tf,Th,Tl,!*m") + (match_operand:V2SI 1 "metag_datareg_op" "r, a, a, d, d, !*da"))] + "TARGET_DSP && !reload_completed" + "SETL\\t%0, %1, %t1\\t%@ (*sto v2si rm OK)" + [(set_attr "type" "fast,fast,fast,fast,fast,invalid")]) + +(define_insn "*sto_v2si_postreload" + [(set (match_operand:V2SI 0 "memory_operand" "=Tr,Te,Tf,Th,Tl") + (match_operand:V2SI 1 "metag_datareg_op" "r, a, a, d, d"))] + "TARGET_DSP && reload_completed" + "SETL\\t%0, %1, %t1\\t%@ (*sto v2si rm OK)" + [(set_attr "type" "fast")]) + +(define_expand "vec_setv2si" + [(match_operand:V2SI 0 "metag_datareg_op" "=d") + (match_operand:SI 1 "metag_register_op" "da") + (match_operand 2 "const_int_operand" "i")] + "TARGET_DSP" + { + rtx tmp = gen_reg_rtx (SImode); + + rtx tmp2 = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (1, GEN_INT (1 - INTVAL (operands[2])))); + tmp2 = gen_rtx_VEC_SELECT (SImode, operands[0], tmp2); + emit_insn (gen_rtx_SET (VOIDmode, tmp, tmp2)); + + if (INTVAL (operands[2]) == 0) + tmp = gen_rtx_VEC_CONCAT (V2SImode, tmp, operands[1]); + else + tmp = gen_rtx_VEC_CONCAT (V2SImode, operands[1], tmp); + emit_insn (gen_rtx_SET (VOIDmode, operands[0], tmp)); + DONE; + }) + +(define_insn_and_split "*vec_concatv2si" + [(set (match_operand:V2SI 0 "metag_register_op" "=d") + (vec_concat:V2SI (match_operand:SI 1 "metag_register_op" "d") + (match_operand:SI 2 "metag_register_op" "d")))] + "TARGET_DSP" + "#" + "&& reload_completed" + [(set (match_dup 0) + (match_dup 1)) + (set (match_dup 3) + (match_dup 2))] + { + operands[3] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1); + operands[0] = gen_rtx_REG (SImode, REGNO (operands[0])); + } + [(set_attr "type" "two")]) + +(define_expand "vec_extractv2si" + [(match_operand:SI 0 "metag_register_op" "=da") + (match_operand:V2SI 1 "metag_register_op" "d") + (match_operand 2 "const_int_operand" "i")] + "TARGET_DSP" + { + rtx tmp = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (1, operands[2])); + tmp = gen_rtx_VEC_SELECT (SImode, operands[1], tmp); + emit_insn (gen_rtx_SET (VOIDmode, operands[0], tmp)); + DONE; + }) + +(define_insn "*vec_selectv2si" + [(set (match_operand:SI 0 "metag_register_op" "=r") + (vec_select:SI (match_operand:V2SI 1 "metag_datareg_op" "d") + (parallel [(match_operand 2 "const_int_operand" "i")])))] + "TARGET_DSP" + { + switch (INTVAL (operands[2])) + { + case 0: + return "MOV\\t%0, %1\\t%@ (*vec_select v2si 0)"; + case 1: + return "MOV\\t%0, %t1\\t%@ (*vec_select v2si 1)"; + default: + gcc_unreachable (); + } + } + [(set_attr "type" "fast")]) + +(define_expand "vec_initv2si" + [(match_operand:V2SI 0 "metag_datareg_op" "=d") + (match_operand 1 "" "")] + "TARGET_DSP" + { + rtx val0 = force_reg (SImode, XVECEXP (operands[1], 0, 0)); + rtx val1 = force_reg (SImode, XVECEXP (operands[1], 0, 1)); + rtx tmp = gen_rtx_VEC_CONCAT (V2SImode, val0, val1); + emit_insn (gen_rtx_SET (VOIDmode, operands[0], tmp)); + DONE; + }) + +(define_insn "*v2siddi16" + [(set (match_operand:V2SI 0 "metag_datareg_op" "+d") + (3OPIMM16:V2SI (match_dup 0) + (match_operand:V2SI 1 "metag_vector_16bit_op" "v16")))] + "TARGET_DSP" + "DL\\t\\t\\t%0,%0,%1\\t%@(* v2si ddi)" + [(set_attr "type" "fast")]) + +(define_insn "*v2siddi5" + [(set (match_operand:V2SI 0 "metag_datareg_op" "=d") + (3OPIMM5:V2SI (match_operand:V2SI 1 "metag_datareg_op" "d") + (match_operand:V2SI 2 "metag_vector_5bit_op" "vc5")))] + "TARGET_DSP" + "DL\\t\\t\\t%0,%1,%2\\t%@(* v2si ddi)" + [(set_attr "type" "fast")]) + +(define_insn "v2si3" + [(set (match_operand:V2SI 0 "metag_datareg_op" "=d") + (3OPREG:V2SI (match_operand:V2SI 1 "metag_datareg_op" "d") + (match_operand:V2SI 2 "metag_datareg_op" "d")))] + "TARGET_DSP" + "DL\\t\\t\\t%0,%1,%2\\t%@(* v2si ddd)" + [(set_attr "type" "fast")]) + +(define_insn "absv2si2" + [(set (match_operand:V2SI 0 "metag_datareg_op" "=d") + (abs:V2SI (match_operand:V2SI 1 "metag_datareg_op" "d"))) + (clobber (reg:CC CC_REG))] + "TARGET_DSP" + "DL\\tABS\\t\\t%0,%1\\t%@(*abs v2si dd)" + [(set_attr "type" "fast") + (set_attr "ccstate" "ccx")]) + +(define_insn "negv2si2" + [(set (match_operand:V2SI 0 "metag_datareg_op" "=d") + (neg:V2SI (match_operand:V2SI 1 "metag_datareg_op" "d")))] + "TARGET_DSP" + "DL\\tNEG\\t\\t%0,%1\\t%@(*neg v2si dd)" + [(set_attr "type" "fast")]) + +(define_insn "v2si3" + [(set (match_operand:V2SI 0 "metag_datareg_op" "=d") + (MINMAX:V2SI (match_operand:V2SI 1 "metag_datareg_op" "d") + (match_operand:V2SI 2 "metag_datareg_op" "d"))) + (clobber (reg:CC CC_REG))] + "TARGET_DSP" + "DL\\t\\t\\t%0,%1,%2\\t%@(* v2si ddd)" + [(set_attr "type" "fast") + (set_attr "ccstate" "ccx")]) + +;; OP + flag set + +(define_insn "*sv2siddi16" + [(set (reg:CC_NOOV CC_REG) + (compare:CC_NOOV + (3OPIMM16:SI (match_operand:SI 2 "metag_datareg_op" "d") + (match_operand:SI 3 "metag_16bit_op" "KIP")) + (const_int 0))) + (set (match_operand:V2SI 0 "metag_datareg_op" "+d") + (3OPIMM16:V2SI (match_dup 0) + (match_operand:V2SI 1 "metag_vector_16bit_op" "v16")))] + "TARGET_DSP + && (REGNO (operands[2]) == REGNO (operands[0]) + || (REGNO (operands[2]) == REGNO (operands[0]) + 1)) + && INTVAL (operands[3]) == INTVAL (CONST_VECTOR_ELT (operands[1], 0))" + { + if (REGNO (operands[3]) == REGNO (operands[1])) + return "DL\\tS\\t\\t%0,%0,%1\\t%@(*S v2si ddi)"; + else + return "DL\\tS\\t\\t%t0,%t0,%t1\\t%@(*S v2si ddi)"; + } + [(set_attr "type" "fast")]) + +(define_insn "*sv2siddi5" + [(set (reg:CC_NOOV CC_REG) + (compare:CC_NOOV + (3OPIMM5:SI (match_operand:SI 3 "metag_datareg_op" "d") + (match_operand:SI 4 "metag_5bit_op" "L")) + (const_int 0))) + (set (match_operand:V2SI 0 "metag_datareg_op" "=d") + (3OPIMM5:V2SI (match_operand:V2SI 1 "metag_datareg_op" "d") + (match_operand:V2SI 2 "metag_vector_5bit_op" "v16")))] + "TARGET_DSP + && (REGNO (operands[3]) == REGNO (operands[1]) + || (REGNO (operands[3]) == REGNO (operands[1]) + 1)) + && INTVAL (operands[4]) == INTVAL (CONST_VECTOR_ELT (operands[2], 0))" + { + if (REGNO (operands[3]) == REGNO (operands[1])) + return "DL\\tS\\t\\t%0,%1,%2\\t%@(*S v2si di)"; + else + return "DL\\tS\\t\\t%t0,%t1,%t2\\t%@(*S v2si di)"; + } + [(set_attr "type" "fast")]) + +(define_insn "*sv2si3" + [(set (reg:CC_NOOV CC_REG) + (compare:CC_NOOV + (3OPREG:SI (match_operand:SI 3 "metag_datareg_op" "d") + (match_operand:SI 4 "metag_datareg_op" "d")) + (const_int 0))) + (set (match_operand:V2SI 0 "metag_datareg_op" "=d") + (3OPREG:V2SI (match_operand:V2SI 1 "metag_datareg_op" "d") + (match_operand:V2SI 2 "metag_datareg_op" "d")))] + "TARGET_DSP + && ((REGNO (operands[3]) == REGNO (operands[1]) + && REGNO (operands[4]) == REGNO (operands[2])) + || (REGNO (operands[3]) == REGNO (operands[1]) + 1 + && REGNO (operands[4]) == REGNO (operands[2]) + 1))" + { + if (REGNO (operands[3]) == REGNO (operands[1])) + return "DL\\tS\\t\\t%0,%1,%2\\t%@(*S v2si ddd)"; + else + return "DL\\tS\\t\\t%t0,%t1,%t2\\t%@(*S v2si ddd)"; + } + [(set_attr "type" "fast")]) + diff -Nur gcc-4.2.4.orig/gcc/config/metag/x-metag-linux gcc-4.2.4/gcc/config/metag/x-metag-linux --- gcc-4.2.4.orig/gcc/config/metag/x-metag-linux 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/x-metag-linux 2015-07-03 18:46:05.773283541 -0500 @@ -0,0 +1,20 @@ +# Configuration for GNU C-compiler. +# Imagination Technologies Meta version. +# Copyright (C) 2001, 2004, 2007 Imagination Technologies Ltd + +# This file is part of GCC. + +# GCC is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3, or (at your option) any later +# version. + +# GCC is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. + +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . + diff -Nur gcc-4.2.4.orig/gcc/config/metag/xm-metag-linux gcc-4.2.4/gcc/config/metag/xm-metag-linux --- gcc-4.2.4.orig/gcc/config/metag/xm-metag-linux 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/config/metag/xm-metag-linux 2015-07-03 18:46:05.773283541 -0500 @@ -0,0 +1,20 @@ +# Configuration for GNU C-compiler. +# Imagination Technologies Meta version. +# Copyright (C) 2001, 2004, 2007 Imagination Technologies Ltd + +# This file is part of GCC. + +# GCC is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 3, or (at your option) any later +# version. + +# GCC is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. + +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . + diff -Nur gcc-4.2.4.orig/gcc/config.gcc gcc-4.2.4/gcc/config.gcc --- gcc-4.2.4.orig/gcc/config.gcc 2008-03-13 14:11:43.000000000 -0500 +++ gcc-4.2.4/gcc/config.gcc 2015-07-03 18:46:05.717283542 -0500 @@ -291,6 +291,9 @@ m68k-*-*) extra_headers=math-68881.h ;; +metag*-*-*) + cpu_type=metag + ;; mips*-*-*) cpu_type=mips need_64bit_hwint=yes @@ -332,6 +335,74 @@ ;; esac +case ${cpu_type} in +metag) + tm_defines="${tm_defines} METAG_EXEC_PREFIX=\\\"\$(exec_prefix)/\\\"" + + # Set the default core if with_cpu is not defined + if test x${with_cpu} = x + then + if test x${cpu_type} = xmetag + then + with_cpu=2.1 + else + with_cpu=1.2 + fi + fi + + # Set the default tune if with_tune is not defined + if test x${with_tune} = x + then + if test x${cpu_type} = xmetag + then + with_tune=2.1 + fi + fi + + # Set the default fpu if with_fpu is not defined + if test x${with_fpu} = x + then + if test x${cpu_type} = xmetag + then + with_fpu=none + fi + fi + + case x${with_cpu} in + x2.1) + tm_defines="${tm_defines} METAC_DEFAULT=\\\"2.1\\\" METAC_DEFAULT_AS=\\\"METAC_2_1\\\"" + ;; + x1.2) + tm_defines="${tm_defines} METAC_DEFAULT=\\\"1.2\\\" METAC_DEFAULT_AS=\\\"METAC_1_2\\\"" + ;; + x1.1) + tm_defines="${tm_defines} METAC_DEFAULT=\\\"1.1\\\" METAC_DEFAULT_AS=\\\"METAC_1_1\\\"" + ;; + x1.0) + tm_defines="${tm_defines} METAC_DEFAULT=\\\"1.0\\\" METAC_DEFAULT_AS=\\\"METAC_1_0\\\"" + ;; + x0.1) + tm_defines="${tm_defines} METAC_DEFAULT=\\\"0.1\\\" METAC_DEFAULT_AS=\\\"METAC_0_1\\\"" + ;; + x*) + echo "--with-cpu=\"${with_cpu}\" not recognised", + exit 1; + ;; + esac + + case x${enable_meta_default} in + xyes) + # Nothing + ;; + x*) + # When not explicitly META, enable MiniM + tm_defines="${tm_defines} MINIM_DEFAULT" + ;; + esac + ;; +esac + + tm_file=${cpu_type}/${cpu_type}.h if test -f ${srcdir}/config/${cpu_type}/${cpu_type}-protos.h then @@ -481,6 +552,15 @@ # Assume that glibc or uClibc are being used and so __cxa_atexit is provided. default_use_cxa_atexit=yes ;; +metag*-linux-uclibc*) + gas=yes + gnu_ld=yes + case ${enable_threads} in + "" | yes | posix) thread_file='posix' ;; + esac + # uClibc provides __cxa_atexit + default_use_cxa_atexit=yes + ;; *-*-gnu*) # On the Hurd, the setup is just about the same on # each different CPU. The specific machines that we @@ -1518,6 +1598,31 @@ tmake_file=mcore/t-mcore-pe use_fixproto=yes ;; +metag*-linux-uclibc*) + tm_file="dbxelf.h elfos.h metag/metag.h metag/metag-linux.h linux.h metag/linux.h metag/elf.h metag/linux-elf.h" + tmake_file="metag/t-metag-slibgcc-elf-ver metag/t-metag metag/t-metag-linux metag/t-linux" + target_cpu_default="" + tm_defines="${tm_defines} METAG_BFD" + extra_gcc_objs="driver-metag.o" + out_file=metag/metag.c + use_fixproto=no + use_collect2=no + extra_objs="metag-linux.o" + extra_options="${extra_options} metag/metag-linux.opt" + extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o" + + case x${enable_link_global} in + xyes) + tm_defines="${tm_defines} METAG_LINK_GLOBAL" + ;; + esac + + case x${with_cpu} in + x2.1) + tmake_file="${tmake_file} metag/t-linux-2.1" + ;; + esac + ;; mips-sgi-irix[56]*) tm_file="elfos.h ${tm_file} mips/iris.h" tmake_file="mips/t-iris mips/t-slibgcc-irix" @@ -2757,6 +2862,46 @@ esac ;; + metag*) + supported_defaults="cpu tune fpu" + case "$with_cpu" in + "" | 1.0 | 1.1 | 1.2 | 2.1 | 0.1) + # OK + ;; + *) + echo "Unknown CPU used in --with-cpu=$with_cpu, known values:" 1>&2 + echo "1.0 1.1 1.2 2.1 0.1" 1>&2 + exit 1 + ;; + esac + + case "$with_tune" in + "" | 1.0 | 1.1 | 1.2 | 2.1 | 0.1) + # OK + ;; + *) + echo "Unknown CPU used in --with-tune=$with_tune, known values:" 1>&2 + echo "1.0 1.1 1.2 2.1 0.1" 1>&2 + exit 1 + ;; + esac + + case "$with_fpu" in + none | S | D) + # OK + ;; + yes) + with_fpu=D + ;; + *) + echo "Unknown FPU precision used in --with-fpu=$with_fpu, known values:" 1>&2 + echo "S D" 1>&2 + exit 1 + ;; + esac + + ;; + hppa*-*-* | parisc*-*-*) supported_defaults="arch schedule" diff -Nur gcc-4.2.4.orig/gcc/crtstuff.c gcc-4.2.4/gcc/crtstuff.c --- gcc-4.2.4.orig/gcc/crtstuff.c 2006-05-15 22:49:57.000000000 -0500 +++ gcc-4.2.4/gcc/crtstuff.c 2015-07-03 18:46:05.717283542 -0500 @@ -207,7 +207,7 @@ = { }; #endif /* USE_EH_FRAME_REGISTRY */ -#ifdef JCR_SECTION_NAME +#if TARGET_USE_JCR_SECTION && defined(JCR_SECTION_NAME) /* Stick a label at the beginning of the java class registration info so we can register them properly. */ STATIC void *__JCR_LIST__[] @@ -242,6 +242,20 @@ extern void __cxa_finalize (void *) TARGET_ATTRIBUTE_WEAK; /* Run all the global destructors on exit from the program. */ + +#ifndef DO_GLOBAL_DTORS_AUX_BODY +#define DO_GLOBAL_DTORS_AUX_BODY \ +do { \ + static func_ptr *p = __DTOR_LIST__ + 1; \ + func_ptr f; \ + \ + while ((f = *p)) \ + { \ + p++; \ + f (); \ + } \ +} while (0) +#endif /* Some systems place the number of pointers in the first word of the table. On SVR4 however, that word is -1. In all cases, the table is @@ -263,10 +277,6 @@ static void __attribute__((used)) __do_global_dtors_aux (void) { -#ifndef FINI_ARRAY_SECTION_ASM_OP - static func_ptr *p = __DTOR_LIST__ + 1; - func_ptr f; -#endif /* !defined(FINI_ARRAY_SECTION_ASM_OP) */ static _Bool completed; if (__builtin_expect (completed, 0)) @@ -281,11 +291,7 @@ /* If we are using .fini_array then destructors will be run via that mechanism. */ #else /* !defined (FINI_ARRAY_SECTION_ASM_OP) */ - while ((f = *p)) - { - p++; - f (); - } + DO_GLOBAL_DTORS_AUX_BODY; #endif /* !defined(FINI_ARRAY_SECTION_ASM_OP) */ #ifdef USE_EH_FRAME_REGISTRY @@ -312,7 +318,7 @@ = { __do_global_dtors_aux }; #endif /* !defined(FINI_SECTION_ASM_OP) */ -#if defined(USE_EH_FRAME_REGISTRY) || defined(JCR_SECTION_NAME) +#if defined(USE_EH_FRAME_REGISTRY) || (TARGET_USE_JCR_SECTION && defined(JCR_SECTION_NAME)) /* Stick a call to __register_frame_info into the .init section. For some reason calls with no arguments work more reliably in .init, so stick the call in another function. */ @@ -333,7 +339,7 @@ __register_frame_info (__EH_FRAME_BEGIN__, &object); #endif /* CRT_GET_RFIB_DATA */ #endif /* USE_EH_FRAME_REGISTRY */ -#ifdef JCR_SECTION_NAME +#if TARGET_USE_JCR_SEVTION && defined(JCR_SECTION_NAME) if (__JCR_LIST__[0]) { void (*register_classes) (void *) = _Jv_RegisterClasses; @@ -397,6 +403,15 @@ extern void __do_global_dtors (void); +#ifndef DO_GLOBAL_DTORS_BODY +#define DO_GLOBAL_DTORS_BODY \ +do { \ + func_ptr *p, f; \ + for (p = __DTOR_LIST__ + 1; (f = *p); p++) \ + f (); \ +} while (0) +#endif + /* This case is used by the Irix 6 port, which supports named sections but not an SVR4-style .fini section. __do_global_dtors can be non-static in this case because we protect it with -hidden_symbol. */ @@ -404,9 +419,7 @@ void __do_global_dtors (void) { - func_ptr *p, f; - for (p = __DTOR_LIST__ + 1; (f = *p); p++) - f (); + DO_GLOBAL_DTORS_BODY; #ifdef USE_EH_FRAME_REGISTRY if (__deregister_frame_info) @@ -414,7 +427,7 @@ #endif } -#if defined(USE_EH_FRAME_REGISTRY) || defined(JCR_SECTION_NAME) +#if defined(USE_EH_FRAME_REGISTRY) || (TARGET_USE_JCR_SECTION && defined(JCR_SECTION_NAME)) /* A helper function for __do_global_ctors, which is in crtend.o. Here in crtbegin.o, we can reference a couple of symbols not visible there. Plus, since we're before libgcc.a, we have no problems referencing @@ -427,7 +440,7 @@ if (__register_frame_info) __register_frame_info (__EH_FRAME_BEGIN__, &object); #endif -#ifdef JCR_SECTION_NAME +#if TARGET_USE_JCR_SECTION && defined (JCR_SECTION_NAME) if (__JCR_LIST__[0]) { void (*register_classes) (void *) = _Jv_RegisterClasses; @@ -498,7 +511,7 @@ = { 0 }; #endif /* EH_FRAME_SECTION_NAME */ -#ifdef JCR_SECTION_NAME +#if TARGET_USE_JCR_SECTION && defined(JCR_SECTION_NAME) /* Null terminate the .jcr section array. */ STATIC void *__JCR_END__[1] __attribute__ ((unused, section(JCR_SECTION_NAME), @@ -513,12 +526,20 @@ #elif defined(INIT_SECTION_ASM_OP) #ifdef OBJECT_FORMAT_ELF + +#ifndef DO_GLOBAL_CTORS_AUX_BODY +#define DO_GLOBAL_CTORS_AUX_BODY \ +do { \ + func_ptr *p; \ + for (p = __CTOR_END__ - 1; *p != (func_ptr) -1; p--) \ + (*p)(); \ +} while (0) +#endif + static void __attribute__((used)) __do_global_ctors_aux (void) { - func_ptr *p; - for (p = __CTOR_END__ - 1; *p != (func_ptr) -1; p--) - (*p) (); + DO_GLOBAL_CTORS_AUX_BODY; } /* Stick a call to __do_global_ctors_aux into the .init section. */ @@ -561,6 +582,16 @@ #elif defined(HAS_INIT_SECTION) /* ! INIT_SECTION_ASM_OP */ +#ifndef DO_GLOBAL_CTORS_BODY +#define DO_GLOBAL_CTORS_BODY \ +do { \ + func_ptr *p; \ + \ + for (p = __CTOR_END__ - 1; *p != (func_ptr) -1; p--) \ + (*p) (); \ +} while (0) +#endif + extern void __do_global_ctors (void); /* This case is used by the Irix 6 port, which supports named sections but @@ -573,8 +604,7 @@ #if defined(USE_EH_FRAME_REGISTRY) || defined(JCR_SECTION_NAME) __do_global_ctors_1(); #endif - for (p = __CTOR_END__ - 1; *p != (func_ptr) -1; p--) - (*p) (); + DO_GLOBAL_CTORS_BODY; } #else /* ! INIT_SECTION_ASM_OP && ! HAS_INIT_SECTION */ diff -Nur gcc-4.2.4.orig/gcc/cse.c gcc-4.2.4/gcc/cse.c --- gcc-4.2.4.orig/gcc/cse.c 2008-01-14 06:18:30.000000000 -0600 +++ gcc-4.2.4/gcc/cse.c 2015-07-03 18:46:05.721283542 -0500 @@ -4881,6 +4881,17 @@ } } +#ifdef AUTO_INC_DEC + /* Invalidate all AUTO inc registers. */ + { + rtx link; + + for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) + if (REG_NOTE_KIND (link) == REG_INC) + invalidate (XEXP (link, 0), VOIDmode); + } +#endif + if (GET_CODE (x) == SET) { sets = alloca (sizeof (struct set)); diff -Nur gcc-4.2.4.orig/gcc/expr.c gcc-4.2.4/gcc/expr.c --- gcc-4.2.4.orig/gcc/expr.c 2008-02-04 16:03:09.000000000 -0600 +++ gcc-4.2.4/gcc/expr.c 2015-07-03 18:46:05.721283542 -0500 @@ -3652,9 +3652,23 @@ /* USED is now the # of bytes we need not copy to the stack because registers will take care of them. */ - if (partial != 0) - xinner = adjust_address (xinner, BLKmode, used); + { +#ifdef METAG_PARTIAL_ARGS + if (GET_CODE (size) == CONST_INT) + { + HOST_WIDE_INT onstack = INTVAL (size) - partial; + + onstack = (onstack + (STACK_BOUNDARY_BYTES - 1)) & ~(STACK_BOUNDARY_BYTES - 1); + + size = GEN_INT (onstack + partial); + } + else + gcc_unreachable (); +#else + xinner = adjust_address (xinner, BLKmode, used); +#endif + } /* If the partial register-part of the arg counts in its stack size, skip the part of stack space corresponding to the registers. @@ -3765,6 +3779,8 @@ int offset = partial % (PARM_BOUNDARY / BITS_PER_UNIT); int args_offset = INTVAL (args_so_far); int skip; + int begin_on_stack; + int end_on_stack; /* Push padding now if padding above and stack grows down, or if padding below and stack grows up. @@ -3784,11 +3800,19 @@ not_stack = (partial - offset) / UNITS_PER_WORD; offset /= UNITS_PER_WORD; +#ifdef METAG_PARTIAL_ARGS + begin_on_stack = 0; + end_on_stack = size - not_stack; +#else + begin_on_stack = not_stack; + end_on_stack = size; +#endif + /* If the partial register-part of the arg counts in its stack size, skip the part of stack space corresponding to the registers. Otherwise, start copying to the beginning of the stack space, by setting SKIP to 0. */ - skip = (reg_parm_stack_space == 0) ? 0 : not_stack; + skip = (reg_parm_stack_space == 0) ? 0 : begin_on_stack; if (CONSTANT_P (x) && ! LEGITIMATE_CONSTANT_P (x)) x = validize_mem (force_const_mem (mode, x)); @@ -3803,15 +3827,15 @@ /* We can do it by words, because any scalar bigger than a word has a size a multiple of a word. */ #ifndef PUSH_ARGS_REVERSED - for (i = not_stack; i < size; i++) + for (i = begin_on_stack; i < end_on_stack; i++) #else - for (i = size - 1; i >= not_stack; i--) + for (i = end_on_stack - 1; i >= begin_on_stack; i--) #endif - if (i >= not_stack + offset) + if (i >= begin_on_stack + offset) emit_push_insn (operand_subword_force (x, i, mode), word_mode, NULL_TREE, NULL_RTX, align, 0, NULL_RTX, 0, args_addr, - GEN_INT (args_offset + ((i - not_stack + skip) + GEN_INT (args_offset + ((i - begin_on_stack + skip) * UNITS_PER_WORD)), reg_parm_stack_space, alignment_pad); } @@ -3867,8 +3891,32 @@ emit_group_load (reg, x, type, -1); else { + xinner = x; + +#ifdef METAG_PARTIAL_ARGS + if (mode != BLKmode) + size = GEN_INT (GET_MODE_SIZE (mode) - partial); + + gcc_assert (size && GET_CODE (size) == CONST_INT); + + if (GET_CODE (xinner) == CONCAT) + { + xinner = XEXP (xinner, 1); + mode = GET_MODE (xinner); + + gcc_assert (INTVAL (size) == GET_MODE_SIZE (mode)); + } + else if (GET_CODE (xinner) == MEM) + { + gcc_assert ((INTVAL (size) & (STACK_BOUNDARY_BYTES - 1)) == 0); + xinner = adjust_address (xinner, mode, INTVAL (size) ); + } + else + gcc_unreachable (); +#endif + gcc_assert (partial % UNITS_PER_WORD == 0); - move_block_to_reg (REGNO (reg), x, partial / UNITS_PER_WORD, mode); + move_block_to_reg (REGNO (reg), xinner, partial / UNITS_PER_WORD, mode); } } @@ -4779,7 +4827,14 @@ case UNION_TYPE: case QUAL_UNION_TYPE: - return -1; + { + /* Ho hum. How in the world do we guess here? Clearly it isn't + right to count the fields. Guess based on the number of words. */ + HOST_WIDE_INT n = int_size_in_bytes (type); + if (n < 0) + return -1; + return n / UNITS_PER_WORD; + } case COMPLEX_TYPE: return 2; diff -Nur gcc-4.2.4.orig/gcc/function.c gcc-4.2.4/gcc/function.c --- gcc-4.2.4.orig/gcc/function.c 2007-09-01 10:28:30.000000000 -0500 +++ gcc-4.2.4/gcc/function.c 2015-07-03 18:46:05.721283542 -0500 @@ -2245,7 +2245,11 @@ gcc_assert (!all->extra_pretend_bytes && !all->pretend_args_size); pretend_bytes = partial; +#ifdef METAG_PARTIAL_ARGS + all->pretend_args_size = pretend_bytes; +#else all->pretend_args_size = CEIL_ROUND (pretend_bytes, STACK_BYTES); +#endif /* We want to align relative to the actual stack pointer, so don't include this in the stack size until later. */ @@ -2259,8 +2263,13 @@ /* Adjust offsets to include the pretend args. */ pretend_bytes = all->extra_pretend_bytes - pretend_bytes; - data->locate.slot_offset.constant += pretend_bytes; - data->locate.offset.constant += pretend_bytes; +#ifdef METAG_PARTIAL_ARGS + if (data->partial != 0) +#endif + { + data->locate.slot_offset.constant += pretend_bytes; + data->locate.offset.constant += pretend_bytes; + } data->entry_parm = entry_parm; } @@ -2369,8 +2378,10 @@ else { gcc_assert (data->partial % UNITS_PER_WORD == 0); +#ifndef METAG_PARTIAL_ARGS move_block_from_reg (REGNO (entry_parm), validize_mem (stack_parm), data->partial / UNITS_PER_WORD); +#endif } entry_parm = stack_parm; @@ -3062,8 +3073,10 @@ /* We have aligned all the args, so add space for the pretend args. */ current_function_pretend_args_size = all.pretend_args_size; +#ifndef METAG_PARTIAL_ARGS all.stack_args_size.constant += all.extra_pretend_bytes; current_function_args_size = all.stack_args_size.constant; +#endif /* Adjust function incoming argument size for alignment and minimum length. */ diff -Nur gcc-4.2.4.orig/gcc/genattrtab.c gcc-4.2.4/gcc/genattrtab.c --- gcc-4.2.4.orig/gcc/genattrtab.c 2007-09-01 10:28:30.000000000 -0500 +++ gcc-4.2.4/gcc/genattrtab.c 2015-07-03 18:46:05.721283542 -0500 @@ -4582,7 +4582,6 @@ printf ("#include \"coretypes.h\"\n"); printf ("#include \"tm.h\"\n"); printf ("#include \"rtl.h\"\n"); - printf ("#include \"tm_p.h\"\n"); printf ("#include \"insn-config.h\"\n"); printf ("#include \"recog.h\"\n"); printf ("#include \"regs.h\"\n"); @@ -4592,6 +4591,7 @@ printf ("#include \"toplev.h\"\n"); printf ("#include \"flags.h\"\n"); printf ("#include \"function.h\"\n"); + printf ("#include \"tm_p.h\"\n"); printf ("\n"); printf ("#define operands recog_data.operand\n\n"); diff -Nur gcc-4.2.4.orig/gcc/genmodes.c gcc-4.2.4/gcc/genmodes.c --- gcc-4.2.4.orig/gcc/genmodes.c 2007-09-01 10:28:30.000000000 -0500 +++ gcc-4.2.4/gcc/genmodes.c 2015-07-03 18:46:05.725283542 -0500 @@ -785,8 +785,7 @@ /* Output routines. */ #define tagged_printf(FMT, ARG, TAG) do { \ - int count_; \ - printf (" " FMT ",%n", ARG, &count_); \ + int count_ = printf (" " FMT ",", ARG); \ printf ("%*s/* %s */\n", 27 - count_, "", TAG); \ } while (0) @@ -820,8 +819,7 @@ for (c = 0; c < MAX_MODE_CLASS; c++) for (m = modes[c]; m; m = m->next) { - int count_; - printf (" %smode,%n", m->name, &count_); + int count_ = printf (" %smode,", m->name); printf ("%*s/* %s:%d */\n", 27 - count_, "", trim_filename (m->file), m->line); } diff -Nur gcc-4.2.4.orig/gcc/genopinit.c gcc-4.2.4/gcc/genopinit.c --- gcc-4.2.4.orig/gcc/genopinit.c 2007-09-01 10:28:30.000000000 -0500 +++ gcc-4.2.4/gcc/genopinit.c 2015-07-03 18:46:05.725283542 -0500 @@ -1,6 +1,7 @@ /* Generate code to initialize optabs from machine description. Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, - 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. + 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2010 + Free Software Foundation, Inc. This file is part of GCC. @@ -414,7 +415,8 @@ printf ("#include \"recog.h\"\n"); printf ("#include \"expr.h\"\n"); printf ("#include \"optabs.h\"\n"); - printf ("#include \"reload.h\"\n\n"); + printf ("#include \"reload.h\"\n"); + printf ("#include \"toplev.h\"\n\n"); printf ("void\ninit_all_optabs (void)\n{\n"); diff -Nur gcc-4.2.4.orig/gcc/loop-doloop.c gcc-4.2.4/gcc/loop-doloop.c --- gcc-4.2.4.orig/gcc/loop-doloop.c 2007-09-01 10:28:30.000000000 -0500 +++ gcc-4.2.4/gcc/loop-doloop.c 2015-07-03 18:46:05.725283542 -0500 @@ -65,6 +65,10 @@ #ifdef HAVE_doloop_end +#ifndef DECREMENT_AND_BRANCH_REG +#define DECREMENT_AND_BRANCH_REG(MODE) gen_reg_rtx (MODE) +#endif + /* Return the loop termination condition for PATTERN or zero if it is not a decrement and branch jump insn. */ @@ -358,6 +362,10 @@ if (increment_count) count = simplify_gen_binary (PLUS, mode, count, const1_rtx); + /* CONST_INT's must be correctly sign-extended for mode. */ + if (CONST_INT_P (count)) + count = gen_int_mode (INTVAL (count), mode); + /* Insert initialization of the count register into the loop header. */ start_sequence (); tmp = force_operand (count, counter_reg); @@ -544,7 +552,7 @@ to modify the loop since there is some aspect the back-end does not like. */ start_label = block_label (desc->in_edge->dest); - doloop_reg = gen_reg_rtx (mode); + doloop_reg = DECREMENT_AND_BRANCH_REG (mode); doloop_seq = gen_doloop_end (doloop_reg, iterations, iterations_max, GEN_INT (level), start_label); @@ -612,6 +620,18 @@ return true; } +#ifndef DOLOOP_OPTIMIZE_INIT +#define DOLOOP_OPTIMIZE_INIT() +#endif + +#ifndef DOLOOP_OPTIMIZE_LOOP +#define DOLOOP_OPTIMIZE_LOOP(LOOP) doloop_optimize (LOOP) +#endif + +#ifndef DOLOOP_OPTIMIZE_FINI +#define DOLOOP_OPTIMIZE_FINI() +#endif + /* This is the main entry point. Process all LOOPS using doloop_optimize. */ void @@ -620,15 +640,19 @@ unsigned i; struct loop *loop; + DOLOOP_OPTIMIZE_INIT (); + for (i = 1; i < loops->num; i++) { loop = loops->parray[i]; if (!loop) continue; - doloop_optimize (loop); + DOLOOP_OPTIMIZE_LOOP (loop); } + DOLOOP_OPTIMIZE_FINI (); + iv_analysis_done (); #ifdef ENABLE_CHECKING diff -Nur gcc-4.2.4.orig/gcc/mkmap-symver.awk gcc-4.2.4/gcc/mkmap-symver.awk --- gcc-4.2.4.orig/gcc/mkmap-symver.awk 2007-09-01 10:28:30.000000000 -0500 +++ gcc-4.2.4/gcc/mkmap-symver.awk 2015-07-03 18:46:05.725283542 -0500 @@ -21,8 +21,13 @@ BEGIN { state = "nm"; sawsymbol = 0; + showprefix = "_"; if (leading_underscore) + { + if (no_show_underscore) + showprefix = ""; prefix = "_"; + } else prefix = ""; } @@ -81,7 +86,7 @@ } { - sym = prefix $1; + sym = $1; if (thislib != "%exclude") ver[sym] = thislib; else @@ -108,7 +113,7 @@ empty=1 for (sym in ver) - if ((ver[sym] == lib) && (sym in def)) + if (((ver[sym]) == lib) && ((prefix sym) in def)) { if (empty) { @@ -116,7 +121,7 @@ printf(" global:\n"); empty = 0; } - printf("\t%s;\n", sym); + printf("\t%s;\n", showprefix sym); } if (empty) diff -Nur gcc-4.2.4.orig/gcc/output.h gcc-4.2.4/gcc/output.h --- gcc-4.2.4.orig/gcc/output.h 2007-09-01 10:28:30.000000000 -0500 +++ gcc-4.2.4/gcc/output.h 2015-07-03 18:46:05.725283542 -0500 @@ -490,7 +490,7 @@ /* The callback used to switch to the section, and the data that should be passed to the callback. */ unnamed_section_callback GTY ((skip)) callback; - const void *GTY ((skip)) data; + const char *GTY (()) data; /* The next entry in the chain of unnamed sections. */ section *next; @@ -557,6 +557,9 @@ extern void place_block_symbol (rtx); extern rtx get_section_anchor (struct object_block *, HOST_WIDE_INT, enum tls_model); +extern section *mergeable_string_section (tree, + unsigned HOST_WIDE_INT, + unsigned int); extern section *mergeable_constant_section (enum machine_mode, unsigned HOST_WIDE_INT, unsigned int); diff -Nur gcc-4.2.4.orig/gcc/print-rtl.c gcc-4.2.4/gcc/print-rtl.c --- gcc-4.2.4.orig/gcc/print-rtl.c 2007-09-01 10:28:30.000000000 -0500 +++ gcc-4.2.4/gcc/print-rtl.c 2015-07-03 18:46:05.725283542 -0500 @@ -428,11 +428,11 @@ const char *name; #ifndef GENERATOR_FILE - if (REG_P (in_rtx) && value < FIRST_PSEUDO_REGISTER) + if (REG_P (in_rtx) && (unsigned)value < FIRST_PSEUDO_REGISTER) fprintf (outfile, " %d %s", REGNO (in_rtx), reg_names[REGNO (in_rtx)]); else if (REG_P (in_rtx) - && value <= LAST_VIRTUAL_REGISTER) + && (unsigned)value <= LAST_VIRTUAL_REGISTER) { if (value == VIRTUAL_INCOMING_ARGS_REGNUM) fprintf (outfile, " %d virtual-incoming-args", value); diff -Nur gcc-4.2.4.orig/gcc/regmove.c gcc-4.2.4/gcc/regmove.c --- gcc-4.2.4.orig/gcc/regmove.c 2007-09-01 10:28:30.000000000 -0500 +++ gcc-4.2.4/gcc/regmove.c 2015-07-03 18:46:05.725283542 -0500 @@ -80,6 +80,10 @@ static int regclass_compatible_p (int, int); static int replacement_quality (rtx); static int fixup_match_2 (rtx, rtx, rtx, rtx); +#ifdef AUTO_INC_DEC +static void update_auto_inc_notes (rtx); +static void remove_auto_inc_notes (rtx); +#endif /* Return nonzero if registers with CLASS1 and CLASS2 can be merged without causing too much register allocation problems. */ @@ -1043,6 +1047,52 @@ return 0; } +#ifdef AUTO_INC_DEC +/* Remove all REG_INC notes from INSN. */ + +static void +remove_auto_inc_notes (rtx insn) +{ + rtx prev = NULL_RTX; + rtx link; + + gcc_assert (insn); + + link = REG_NOTES (insn); + while (link) + { + rtx next = XEXP (link, 1); + + if (REG_NOTE_KIND (link) == REG_INC) + { + if (link == REG_NOTES (insn)) + REG_NOTES (insn) = next; + else + XEXP (prev, 1) = next; + } + + prev = link; + link = next; + } +} + +/* Updates REG_INC notes for all insns in the sequence starting at FIRST. */ + +static void +update_auto_inc_notes (rtx first) +{ + rtx insn; + + for (insn = first; insn; insn = NEXT_INSN (insn)) + if (INSN_P (insn)) + { + remove_auto_inc_notes (insn); + + add_auto_inc_notes (insn, PATTERN (insn)); + } +} +#endif + /* Main entry for the register move optimization. F is the first instruction. NREGS is one plus the highest pseudo-reg number used in the instruction. @@ -2491,6 +2541,11 @@ rest_of_handle_regmove (void) { regmove_optimize (get_insns (), max_reg_num ()); +#ifdef AUTO_INC_DEC + /* The regmove optimization may invalidate existing REG_INC notes + so update the REG_INC note afterwards. */ + update_auto_inc_notes (get_insns ()); +#endif cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_UPDATE_LIFE); return 0; } diff -Nur gcc-4.2.4.orig/gcc/regrename.c gcc-4.2.4/gcc/regrename.c --- gcc-4.2.4.orig/gcc/regrename.c 2007-09-01 10:28:30.000000000 -0500 +++ gcc-4.2.4/gcc/regrename.c 2015-07-03 18:46:05.725283542 -0500 @@ -182,6 +182,11 @@ } } +#if !defined(HARD_REGNO_RENAME_OK_FOR_INSN) && defined(HARD_REGNO_RENAME_OK) +#define HARD_REGNO_RENAME_OK_FOR_INSN(INSN, FROM, TOO) \ + HARD_REGNO_RENAME_OK (FROM, TOO) +#endif + /* Perform register renaming on the current function. */ static void @@ -303,8 +308,8 @@ || (current_function_is_leaf && !LEAF_REGISTERS[new_reg + i]) #endif -#ifdef HARD_REGNO_RENAME_OK - || ! HARD_REGNO_RENAME_OK (reg + i, new_reg + i) +#ifdef HARD_REGNO_RENAME_OK_FOR_INSN + || ! HARD_REGNO_RENAME_OK_FOR_INSN (this->insn, reg + i, new_reg + i) #endif ) break; @@ -1546,13 +1551,13 @@ case PRE_INC: case PRE_DEC: case PRE_MODIFY: - return false; + return changed; case MEM: - return replace_oldest_value_mem (x, insn, vd); + return changed | replace_oldest_value_mem (x, insn, vd); case REG: - return replace_oldest_value_reg (loc, cl, insn, vd); + return changed | replace_oldest_value_reg (loc, cl, insn, vd); default: break; @@ -1674,14 +1679,18 @@ if (REG_P (SET_DEST (set))) { new = find_oldest_value_reg (REGNO_REG_CLASS (regno), src, vd); - if (new && validate_change (insn, &SET_SRC (set), new, 0)) + if (new) { - if (dump_file) - fprintf (dump_file, - "insn %u: replaced reg %u with %u\n", - INSN_UID (insn), regno, REGNO (new)); - changed = true; - goto did_replacement; + if (validate_change (insn, &SET_SRC (set), new, 0)) + { + if (dump_file) + fprintf (dump_file, + "insn %u: replaced reg %u with %u\n", + INSN_UID (insn), regno, REGNO (new)); + changed = true; + goto did_replacement; + } + extract_insn (insn); } } @@ -1704,6 +1713,7 @@ changed = true; goto did_replacement; } + extract_insn (insn); } } } @@ -1711,6 +1721,8 @@ any_replacements = false; + gcc_assert (n_ops == recog_data.n_operands); + /* For each input operand, replace a hard register with the eldest live copy that's in an appropriate register class. */ for (i = 0; i < n_ops; i++) diff -Nur gcc-4.2.4.orig/gcc/reload1.c gcc-4.2.4/gcc/reload1.c --- gcc-4.2.4.orig/gcc/reload1.c 2007-09-01 10:28:30.000000000 -0500 +++ gcc-4.2.4/gcc/reload1.c 2015-07-03 18:46:05.725283542 -0500 @@ -438,9 +438,6 @@ static void delete_address_reloads (rtx, rtx); static void delete_address_reloads_1 (rtx, rtx, rtx); static rtx inc_for_reload (rtx, rtx, rtx, int); -#ifdef AUTO_INC_DEC -static void add_auto_inc_notes (rtx, rtx); -#endif static void copy_eh_notes (rtx, rtx); static int reloads_conflict (int, int); static rtx gen_reload (rtx, rtx, int, enum reload_type); @@ -653,6 +650,10 @@ struct elim_table *ep; basic_block bb; +#ifdef ENABLE_CHECKING + verify_auto_inc_notes_p (first); +#endif + /* Make sure even insns with volatile mem refs are recognizable. */ init_recog (); @@ -8296,34 +8297,6 @@ return store; } -#ifdef AUTO_INC_DEC -static void -add_auto_inc_notes (rtx insn, rtx x) -{ - enum rtx_code code = GET_CODE (x); - const char *fmt; - int i, j; - - if (code == MEM && auto_inc_p (XEXP (x, 0))) - { - REG_NOTES (insn) - = gen_rtx_EXPR_LIST (REG_INC, XEXP (XEXP (x, 0), 0), REG_NOTES (insn)); - return; - } - - /* Scan all the operand sub-expressions. */ - fmt = GET_RTX_FORMAT (code); - for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) - { - if (fmt[i] == 'e') - add_auto_inc_notes (insn, XEXP (x, i)); - else if (fmt[i] == 'E') - for (j = XVECLEN (x, i) - 1; j >= 0; j--) - add_auto_inc_notes (insn, XVECEXP (x, i, j)); - } -} -#endif - /* Copy EH notes from an insn to its reloads. */ static void copy_eh_notes (rtx insn, rtx x) diff -Nur gcc-4.2.4.orig/gcc/rtlanal.c gcc-4.2.4/gcc/rtlanal.c --- gcc-4.2.4.orig/gcc/rtlanal.c 2007-09-01 10:28:30.000000000 -0500 +++ gcc-4.2.4/gcc/rtlanal.c 2015-07-03 18:46:05.729283542 -0500 @@ -1042,6 +1042,11 @@ a special insn which should not be considered a no-op. */ if (find_reg_note (insn, REG_RETVAL, NULL_RTX)) return 0; + + /* Extract the code of a cond_exec as a conditional noop is no + more useful than a noop itself */ + if (GET_CODE (pat) == COND_EXEC) + pat = COND_EXEC_CODE (pat); if (GET_CODE (pat) == SET && set_noop_p (pat)) return 1; @@ -2832,6 +2837,74 @@ return 0; } +/* If X has autoincrement side effects then add required REG_INC notes. */ +void +add_auto_inc_notes (rtx insn, rtx x) +{ + enum rtx_code code = GET_CODE (x); + const char *fmt; + int i, j; + + if (code == MEM && auto_inc_p (XEXP (x, 0))) + { + REG_NOTES (insn) + = gen_rtx_EXPR_LIST (REG_INC, XEXP (XEXP (x, 0), 0), REG_NOTES (insn)); + return; + } + + /* Scan all the operand sub-expressions. */ + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'e') + add_auto_inc_notes (insn, XEXP (x, i)); + else if (fmt[i] == 'E') + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + add_auto_inc_notes (insn, XVECEXP (x, i, j)); + } +} + +/* Verify if INSN has required REG_INC notes. */ + +void +verify_auto_inc_notes_for_insn_p (rtx insn, rtx x) +{ + enum rtx_code code = GET_CODE (x); + const char *fmt; + int i, j; + + if (code == MEM && auto_inc_p (XEXP (x, 0))) + { + if (find_reg_note (insn, REG_INC, XEXP (XEXP (x, 0), 0)) == NULL_RTX) + fatal_insn ("Insn missing REG_INC note:", insn); + } + + /* Scan all the operand sub-expressions. */ + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + { + if (fmt[i] == 'e') + verify_auto_inc_notes_for_insn_p (insn, XEXP (x, i)); + else if (fmt[i] == 'E') + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + verify_auto_inc_notes_for_insn_p (insn, XVECEXP (x, i, j)); + } + + return; +} + +/* Verify that all insns in the sequence starting at FIRST + have required REG_INC notes. */ +void +verify_auto_inc_notes_p (rtx first) +{ + rtx insn; + + for (insn = first; insn; insn = NEXT_INSN (insn)) + if (INSN_P (insn)) + verify_auto_inc_notes_for_insn_p (insn, PATTERN (insn)); +} + /* Return nonzero if IN contains a piece of rtl that has the address LOC. */ int loc_mentioned_in_p (rtx *loc, rtx in) diff -Nur gcc-4.2.4.orig/gcc/rtl.h gcc-4.2.4/gcc/rtl.h --- gcc-4.2.4.orig/gcc/rtl.h 2007-11-07 14:48:38.000000000 -0600 +++ gcc-4.2.4/gcc/rtl.h 2015-07-03 18:46:05.729283542 -0500 @@ -1722,6 +1722,9 @@ extern int for_each_rtx (rtx *, rtx_function, void *); extern rtx regno_use_in (unsigned int, rtx); extern int auto_inc_p (rtx); +extern void add_auto_inc_notes (rtx, rtx); +extern void verify_auto_inc_notes_p (rtx); +extern void verify_auto_inc_notes_for_insn_p (rtx, rtx); extern int in_expr_list_p (rtx, rtx); extern void remove_node_from_expr_list (rtx, rtx *); extern int loc_mentioned_in_p (rtx *, rtx); diff -Nur gcc-4.2.4.orig/gcc/testsuite/gcc.c-torture/execute/builtins/lib/chk.c gcc-4.2.4/gcc/testsuite/gcc.c-torture/execute/builtins/lib/chk.c --- gcc-4.2.4.orig/gcc/testsuite/gcc.c-torture/execute/builtins/lib/chk.c 2005-06-27 07:17:39.000000000 -0500 +++ gcc-4.2.4/gcc/testsuite/gcc.c-torture/execute/builtins/lib/chk.c 2015-07-03 18:46:05.777283542 -0500 @@ -448,6 +448,10 @@ return ret; } +/* This doesn't work on a target which uses uclibc. + This is because in uclibc vsprint is implemented by use vsnprintf + so this code will end up recusing itself to death. */ +#ifndef __metag__ int vsnprintf (char *str, __SIZE_TYPE__ len, const char *fmt, va_list ap) { @@ -470,3 +474,4 @@ } return ret; } +#endif diff -Nur gcc-4.2.4.orig/gcc/testsuite/gcc.c-torture/execute/pr36093.x gcc-4.2.4/gcc/testsuite/gcc.c-torture/execute/pr36093.x --- gcc-4.2.4.orig/gcc/testsuite/gcc.c-torture/execute/pr36093.x 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/testsuite/gcc.c-torture/execute/pr36093.x 2015-07-03 18:46:05.777283542 -0500 @@ -0,0 +1,10 @@ +# The META and MTX linkers require data aligned more than 64 bytes to be +# placed in a named section. +if { [istarget "metag*-local"] } { + set torture_compile_xfail "metag*-local" +} + +if { [istarget "mtxg*-local"] } { + set torture_compile_xfail "mtxg*-local" +} +return 0 diff -Nur gcc-4.2.4.orig/gcc/testsuite/gcc.dg/20020312-2.c gcc-4.2.4/gcc/testsuite/gcc.dg/20020312-2.c --- gcc-4.2.4.orig/gcc/testsuite/gcc.dg/20020312-2.c 2006-04-13 18:14:25.000000000 -0500 +++ gcc-4.2.4/gcc/testsuite/gcc.dg/20020312-2.c 2015-07-03 18:46:05.789283541 -0500 @@ -72,6 +72,8 @@ /* No pic register. */ #elif defined(__m32c__) /* No pic register. */ +#elif defined(__metag__) +# define PIC_REG "A1LbP" #else # error "Modify the test for your target." #endif diff -Nur gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/condret1.c gcc-4.2.4/gcc/testsuite/gcc.target/metag/condret1.c --- gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/condret1.c 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/testsuite/gcc.target/metag/condret1.c 2015-07-03 18:46:05.789283541 -0500 @@ -0,0 +1,38 @@ +/* { dg-options "-mmetac=2.1 -O2" } */ +/* { dg-skip-if "" { *-*-* } { "-mmetac=1.2" } { "" } } */ +/* { dg-skip-if "" { mtxg*-local } { "*" } { "" } } */ + +/* + * Check that conditional returns are not used + * for META 2 code + */ + +extern int bar; +extern int bar2; +extern int zee(int); +int mainly(int foo) +{ + if (bar2 == 0) + { + return 0; + } + if (foo >5) + { + foo+=bar; + return foo; + } + else if (foo >2) + { + foo+=bar2; + return foo+34; + } + else + { + foo-=bar; + return zee(foo); + } +} + +/* { dg-final { scan-assembler-times "\\\$LX\[0-9\]\+:" 1 } }*/ +/* { dg-final { scan-assembler-times "MOV\tPC, D1RtP" 2 } }*/ +/* { dg-final { scan-assembler-not "MOV\[A-Z\]\[A-Z\]\tPC, D1RtP" } }*/ diff -Nur gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/condret2.c gcc-4.2.4/gcc/testsuite/gcc.target/metag/condret2.c --- gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/condret2.c 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/testsuite/gcc.target/metag/condret2.c 2015-07-03 18:46:05.789283541 -0500 @@ -0,0 +1,37 @@ +/* { dg-options "-mmetac=1.2 -O2" } */ +/* { dg-skip-if "" { *-*-* } { "-mmetac=2.1" } { "" } } */ + +/* + * Check that conditional returns are used + * for META 1 code + */ + +extern int bar; +extern int bar2; +extern int zee(int); +int mainly(int foo) +{ + if (bar2 == 0) + { + return 0; + } + if (foo >5) + { + foo+=bar; + return foo; + } + else if (foo >2) + { + foo+=bar2; + return foo+34; + } + else + { + foo-=bar; + return zee(foo); + } +} + +/* { dg-final { scan-assembler-not "\\\$LX\[0-9\]+:" } }*/ +/* { dg-final { scan-assembler-times "MOV\tPC, D1RtP" 1 } }*/ +/* { dg-final { scan-assembler-times "MOV\[A-Z\]\[A-Z\]\tPC, D1RtP" 2 } }*/ diff -Nur gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/condret3.c gcc-4.2.4/gcc/testsuite/gcc.target/metag/condret3.c --- gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/condret3.c 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/testsuite/gcc.target/metag/condret3.c 2015-07-03 18:46:05.789283541 -0500 @@ -0,0 +1,21 @@ +/* { dg-options "-mmetac=2.1 -O2" } */ +/* { dg-skip-if "" { *-*-* } { "-mmetac=1.2" } { "" } } */ +/* { dg-skip-if "" { mtxg*-local } { "*" } { "" } } */ + +/* + * Check that conditional returns are not used + * for META 2 code + */ + +typedef void (*my_func)(int); +int cond; + +int no_unconditional_return (my_func *f) +{ + if (cond) + (*f) (3); +} + +/* { dg-final { scan-assembler-times "\\\$LX\[0-9\]+:" 1 } }*/ +/* { dg-final { scan-assembler-times "MOV\tPC, D1RtP" 1 } }*/ +/* { dg-final { scan-assembler-not "MOV\[A-Z\]\[A-Z\]\tPC, D1RtP" } }*/ diff -Nur gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/condret4.c gcc-4.2.4/gcc/testsuite/gcc.target/metag/condret4.c --- gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/condret4.c 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/testsuite/gcc.target/metag/condret4.c 2015-07-03 18:46:05.789283541 -0500 @@ -0,0 +1,19 @@ +/* { dg-options "-mmetac=1.2 -O2" } */ +/* { dg-skip-if "" { *-*-* } { "-mmetac=2.1" } { "" } } */ + +/* + * Check that conditional returns are not used + * for META 1 code + */ + +typedef void (*my_func)(int); +int cond; + +int no_unconditional_return (my_func *f) +{ + if (cond) + (*f) (3); +} + +/* { dg-final { scan-assembler-not "\\\$LX\[0-9\]+:" } }*/ +/* { dg-final { scan-assembler-times "MOV\[A-Z\]\[A-Z\]\tPC, D1RtP" 1 } }*/ diff -Nur gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/ech1.c gcc-4.2.4/gcc/testsuite/gcc.target/metag/ech1.c --- gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/ech1.c 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/testsuite/gcc.target/metag/ech1.c 2015-07-03 18:46:05.789283541 -0500 @@ -0,0 +1,16 @@ +/* { dg-options "-O2" } */ +/* { dg-skip-if "" { mtxg*-local } { "*" } { "" } } */ + +/* + * Check that ECH is not used when no dsp resources are enabled + * ECH is implemented using D0.8 so it will not be referred to + * when ECH is disabled + */ +int glob; + +void test_func() +{ + glob++; +} + +/* { dg-final { scan-assembler-not "D0.8" } }*/ diff -Nur gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/ech2.c gcc-4.2.4/gcc/testsuite/gcc.target/metag/ech2.c --- gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/ech2.c 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/testsuite/gcc.target/metag/ech2.c 2015-07-03 18:46:05.789283541 -0500 @@ -0,0 +1,15 @@ +/* { dg-options "-O2 -mdsp" } */ +/* { dg-skip-if "" { mtxg*-local } { "*" } { "" } } */ + +/* + * Check that ECH status is not changed by a function that uses no + * dsp resources + */ +int glob; + +void test_func() +{ + glob++; +} + +/* { dg-final { scan-assembler-not "D0.8" } }*/ diff -Nur gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/ech3.c gcc-4.2.4/gcc/testsuite/gcc.target/metag/ech3.c --- gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/ech3.c 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/testsuite/gcc.target/metag/ech3.c 2015-07-03 18:46:05.789283541 -0500 @@ -0,0 +1,15 @@ +/* { dg-options "-O2 -mdsp" } */ +/* { dg-skip-if "" { mtxg*-local } { "*" } { "" } } */ + +/* + * Check that ECH status is set when a dsp register is used + */ +int glob; + +void test_func() +{ + glob++; + asm ("":::"D0.9"); +} + +/* { dg-final { scan-assembler "MOVT\tD0.8, #4384" } }*/ diff -Nur gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/ech4.c gcc-4.2.4/gcc/testsuite/gcc.target/metag/ech4.c --- gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/ech4.c 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/testsuite/gcc.target/metag/ech4.c 2015-07-03 18:46:05.789283541 -0500 @@ -0,0 +1,16 @@ +/* { dg-options "-O2 -mdsp -mno-tbictxsave" } */ +/* { dg-skip-if "" { mtxg*-local } { "*" } { "" } } */ + +/* + * Check that ECH is disabled when requested even if DSP resources + * are used + */ +int glob; + +void test_func() +{ + glob++; + asm ("":::"D0.9"); +} + +/* { dg-final { scan-assembler-not "D0.8" } }*/ diff -Nur gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/ech5.c gcc-4.2.4/gcc/testsuite/gcc.target/metag/ech5.c --- gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/ech5.c 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/testsuite/gcc.target/metag/ech5.c 2015-07-03 18:46:05.789283541 -0500 @@ -0,0 +1,17 @@ +/* { dg-options "-O2 -mdsp" } */ +/* { dg-skip-if "" { mtxg*-local } { "*" } { "" } } */ + +/* + * Check that ECH status is set when a dsp register is used from + * both A and D units + */ +int glob; + +void test_func() +{ + glob++; + asm ("":::"D0.9"); + asm ("":::"A0.4"); +} + +/* { dg-final { scan-assembler "MOVT\tD0.8, #4896" } }*/ diff -Nur gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/ech6.c gcc-4.2.4/gcc/testsuite/gcc.target/metag/ech6.c --- gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/ech6.c 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/testsuite/gcc.target/metag/ech6.c 2015-07-03 18:46:05.789283541 -0500 @@ -0,0 +1,17 @@ +/* { dg-options "-O2 -mdsp" } */ +/* { dg-skip-if "" { mtxg*-local } { "*" } { "" } } */ + +/* + * Check that ECH status is set when a dsp register is used from + * just A unit. This should also result in D registers being saved + * as D0.8 is in that range. + */ +int glob; + +void test_func() +{ + glob++; + asm ("":::"A0.4"); +} + +/* { dg-final { scan-assembler "MOVT\tD0.8, #4896" } }*/ diff -Nur gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/metag.exp gcc-4.2.4/gcc/testsuite/gcc.target/metag/metag.exp --- gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/metag.exp 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/testsuite/gcc.target/metag/metag.exp 2015-07-03 18:46:05.789283541 -0500 @@ -0,0 +1,41 @@ +# Copyright (C) 2010 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 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 GCC; see the file COPYING3. If not see +# . + +# GCC testsuite that uses the `dg.exp' driver. + +# Exit immediately if this isn't an METAG target. +if ![istarget metag*-*-*] then { + return +} + +# Load support procs. +load_lib gcc-dg.exp + +# If a testcase doesn't have special options, use these. +global DEFAULT_CFLAGS +if ![info exists DEFAULT_CFLAGS] then { + set DEFAULT_CFLAGS " -ansi -pedantic-errors" +} + +# Initialize `dg'. +dg-init + +# Main loop. +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cCS\]]] \ + "" $DEFAULT_CFLAGS + +# All done. +dg-finish diff -Nur gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/strcmpbcs.c gcc-4.2.4/gcc/testsuite/gcc.target/metag/strcmpbcs.c --- gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/strcmpbcs.c 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/testsuite/gcc.target/metag/strcmpbcs.c 2015-07-03 18:46:05.789283541 -0500 @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-options "-mcharset=basic" } */ +#include + +char c [100]; +char f [100]; + +int main(void) +{ + if(strcmp (c,f) == 0) + { + return 1; + } + else + { + return 0; + } +} + +/* { dg-final { scan-assembler "strcmpbcs" } } */ diff -Nur gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/thread_pointer_builtin.c gcc-4.2.4/gcc/testsuite/gcc.target/metag/thread_pointer_builtin.c --- gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/thread_pointer_builtin.c 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/testsuite/gcc.target/metag/thread_pointer_builtin.c 2015-07-03 18:46:05.789283541 -0500 @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fpic" } */ +/* { dg-require-effective-target tls } */ + +void *foo(void) +{ + return __builtin_thread_pointer(); +} + +/* { dg-final { scan-assembler-times "___metag_load_tp@PLT" 1 } } */ +/* { dg-final { scan-assembler-not "___metag_load_tp$" } } */ diff -Nur gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/thread_pointer_builtin-non-pic.c gcc-4.2.4/gcc/testsuite/gcc.target/metag/thread_pointer_builtin-non-pic.c --- gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/thread_pointer_builtin-non-pic.c 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/testsuite/gcc.target/metag/thread_pointer_builtin-non-pic.c 2015-07-03 18:46:05.789283541 -0500 @@ -0,0 +1,11 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-require-effective-target tls } */ + +void *foo(void) +{ + return __builtin_thread_pointer(); +} + +/* { dg-final { scan-assembler-not "___metag_load_tp@PLT" } } */ +/* { dg-final { scan-assembler-times "___metag_load_tp" 1 } } */ diff -Nur gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/tls.c gcc-4.2.4/gcc/testsuite/gcc.target/metag/tls.c --- gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/tls.c 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/testsuite/gcc.target/metag/tls.c 2015-07-03 18:46:05.789283541 -0500 @@ -0,0 +1,47 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fpic" } */ +/* { dg-require-effective-target tls } */ + +extern __thread int a __attribute__ ((tls_model ("global-dynamic"))); +static __thread int b __attribute__ ((tls_model ("local-dynamic"))); +extern __thread int c __attribute__ ((tls_model ("initial-exec"))); +static __thread int d __attribute__ ((tls_model ("local-exec"))); + +int* +test (void) +{ + a=a+7; + return &a; +} + +int* +test2 (void) +{ + b=b+10; + return &b; +} + +int* +test3 (void) +{ + c=c+7; + return &c; +} + +int* +test4 (void) +{ + d=d+10; + return &d; +} + +/* { dg-final { scan-assembler-times "\\(_a@TLSGD\\)" 1 } } */ +/* { dg-final { scan-assembler-times "\\(_b@TLSLDM\\)" 1 } } */ +/* { dg-final { scan-assembler-times "#HI\\(_b@TLSLDO\\)" 1 } } */ +/* { dg-final { scan-assembler-times "#LO\\(_b@TLSLDO\\)" 1 } } */ +/* { dg-final { scan-assembler-times "\\(_c@TLSIE\\)" 1 } } */ +/* { dg-final { scan-assembler-times "#HI\\(_d@TLSLE\\)" 1 } } */ +/* { dg-final { scan-assembler-times "#LO\\(_d@TLSLE\\)" 1 } } */ +/* { dg-final { scan-assembler-times "___metag_load_tp@PLT" 2 } } */ +/* { dg-final { scan-assembler-times "___tls_get_addr@PLT" 2 } } */ +/* { dg-final { scan-assembler-not "_c@TLSIENONPIC\\)" } } */ diff -Nur gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/tls-non-pic.c gcc-4.2.4/gcc/testsuite/gcc.target/metag/tls-non-pic.c --- gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/tls-non-pic.c 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/testsuite/gcc.target/metag/tls-non-pic.c 2015-07-03 18:46:05.789283541 -0500 @@ -0,0 +1,50 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-require-effective-target tls } */ + +extern __thread int a __attribute__ ((tls_model ("global-dynamic"))); +static __thread int b __attribute__ ((tls_model ("local-dynamic"))); +extern __thread int c __attribute__ ((tls_model ("initial-exec"))); +static __thread int d __attribute__ ((tls_model ("local-exec"))); + +int* +test (void) +{ + a=a+7; + return &a; +} + +int* +test2 (void) +{ + b=b+10; + return &b; +} + +int* +test3 (void) +{ + c=c+7; + return &c; +} + +int* +test4 (void) +{ + d=d+10; + return &d; +} + +/* { dg-final { scan-assembler-not "_c@TLSIE\\)" } } */ +/* { dg-final { scan-assembler-times "#HI\\(_c@TLSIENONPIC\\)" 1 } } */ +/* { dg-final { scan-assembler-times "#LO\\(_c@TLSIENONPIC\\)" 1 } } */ +/* { dg-final { scan-assembler-times "\\(_a@TLSGD\\)" 1 } } */ +/* { dg-final { scan-assembler-times "\\(_b@TLSLDM\\)" 1 } } */ +/* { dg-final { scan-assembler-times "#HI\\(_b@TLSLDO\\)" 1 } } */ +/* { dg-final { scan-assembler-times "#LO\\(_b@TLSLDO\\)" 1 } } */ +/* { dg-final { scan-assembler-times "#HI\\(_d@TLSLE\\)" 1 } } */ +/* { dg-final { scan-assembler-times "#LO\\(_d@TLSLE\\)" 1 } } */ +/* { dg-final { scan-assembler-not "___metag_load_tp@PLT" } } */ +/* { dg-final { scan-assembler-not "___tls_get_addr@PLT" } } */ +/* { dg-final { scan-assembler-times "___metag_load_tp" 2 } } */ +/* { dg-final { scan-assembler-times "___tls_get_addr" 2 } } */ diff -Nur gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/txrpt-clobber.c gcc-4.2.4/gcc/testsuite/gcc.target/metag/txrpt-clobber.c --- gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/txrpt-clobber.c 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/testsuite/gcc.target/metag/txrpt-clobber.c 2015-07-03 18:46:05.789283541 -0500 @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +int wibble() +{ + int i; + for (i = 0 ; i < 100 ; i++) + { + asm volatile ("foo":::"TXRPT"); + } +} + +/* { dg-final { scan-assembler-not "BR" } } */ diff -Nur gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/umulhisi1.c gcc-4.2.4/gcc/testsuite/gcc.target/metag/umulhisi1.c --- gcc-4.2.4.orig/gcc/testsuite/gcc.target/metag/umulhisi1.c 1969-12-31 18:00:00.000000000 -0600 +++ gcc-4.2.4/gcc/testsuite/gcc.target/metag/umulhisi1.c 2015-07-03 18:46:05.789283541 -0500 @@ -0,0 +1,18 @@ +/* { dg-options "-O2" } */ +/* { dg-final { scan-assembler-times "47662" 1 } }*/ + +/* + * Check that the unsigned 16 bit multiply by constant + * optimisation copes with numbers greater than 2^15 + */ + +#define CONSTANT (47662) + +unsigned int +test(unsigned short in) +{ + unsigned int out = 0; + out = (in * CONSTANT); + return out; +} + diff -Nur gcc-4.2.4.orig/gcc/testsuite/g++.dg/other/PR23205.C gcc-4.2.4/gcc/testsuite/g++.dg/other/PR23205.C --- gcc-4.2.4.orig/gcc/testsuite/g++.dg/other/PR23205.C 2005-10-05 19:47:21.000000000 -0500 +++ gcc-4.2.4/gcc/testsuite/g++.dg/other/PR23205.C 2015-07-03 18:46:05.777283542 -0500 @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-skip-if "No stabs" { mmix-*-* *-*-aix* *-*-netware* alpha*-*-* hppa*64*-*-* ia64-*-* } { "*" } { "" } } */ +/* { dg-skip-if "No stabs" { mmix-*-* *-*-aix* *-*-netware* alpha*-*-* hppa*64*-*-* ia64-*-* metag*-*-* } { "*" } { "" } } */ /* { dg-options "-gstabs+ -fno-eliminate-unused-debug-types" } */ const int foobar = 4; diff -Nur gcc-4.2.4.orig/gcc/testsuite/lib/file-format.exp gcc-4.2.4/gcc/testsuite/lib/file-format.exp --- gcc-4.2.4.orig/gcc/testsuite/lib/file-format.exp 2007-08-31 03:27:50.000000000 -0500 +++ gcc-4.2.4/gcc/testsuite/lib/file-format.exp 2015-07-03 18:46:05.789283541 -0500 @@ -39,6 +39,9 @@ } else { set gcc_target_object_format_saved som } + } elseif { [string match "metag*-linux-uclibc*" $target_triplet] } { + # META we deduce the object format from the target_triplet, so hand-code it. + set gcc_target_object_format_saved elf } else { set objdump_name [find_binutils_prog objdump] set open_file [open objfmtst.c w] diff -Nur gcc-4.2.4.orig/gcc/testsuite/lib/target-supports.exp gcc-4.2.4/gcc/testsuite/lib/target-supports.exp --- gcc-4.2.4.orig/gcc/testsuite/lib/target-supports.exp 2008-01-08 22:47:27.000000000 -0600 +++ gcc-4.2.4/gcc/testsuite/lib/target-supports.exp 2015-07-03 18:46:05.789283541 -0500 @@ -332,6 +332,13 @@ return 0 } + # uClibc does not have gcrt1.o + if { [check_effective_target_uclibc] + && ([lindex $test_what 1] == "-p" + || [lindex $test_what 1] == "-pg") } { + return 0 + } + # Now examine the cache variable. if {![info exists profiling_available_saved]} { # Some targets don't have any implementation of __bb_init_func or are @@ -346,6 +353,7 @@ || [istarget cris-*-*] || [istarget h8300-*-*] || [istarget m32c-*-elf] + || [istarget metag-*-uclibc] || [istarget m68k-*-elf] || [istarget mips*-*-elf] || [istarget xtensa-*-elf] @@ -1900,6 +1908,17 @@ return $et_sync_char_short_saved } +# Return true if this is a uClibc target. + +proc check_effective_target_uclibc {} { + return [check_no_compiler_messages uclibc object { + #include + #if !defined (__UCLIBC__) + #error FOO + #endif + }] +} + # Return 1 if the target matches the effective target 'arg', 0 otherwise. # This can be used with any check_* proc that takes no argument and # returns only 1 or 0. It could be used with check_* procs that take diff -Nur gcc-4.2.4.orig/gcc/toplev.c gcc-4.2.4/gcc/toplev.c --- gcc-4.2.4.orig/gcc/toplev.c 2007-09-01 10:28:30.000000000 -0500 +++ gcc-4.2.4/gcc/toplev.c 2015-07-03 18:46:05.741283542 -0500 @@ -1787,12 +1787,6 @@ } } - if (flag_function_sections && profile_flag) - { - warning (0, "-ffunction-sections disabled; it makes profiling impossible"); - flag_function_sections = 0; - } - #ifndef HAVE_prefetch if (flag_prefetch_loop_arrays) { diff -Nur gcc-4.2.4.orig/gcc/tree-ssa-loop-ivopts.c gcc-4.2.4/gcc/tree-ssa-loop-ivopts.c --- gcc-4.2.4.orig/gcc/tree-ssa-loop-ivopts.c 2007-10-12 17:26:47.000000000 -0500 +++ gcc-4.2.4/gcc/tree-ssa-loop-ivopts.c 2015-07-03 18:46:05.741283542 -0500 @@ -3377,6 +3377,7 @@ HOST_WIDE_INT s_offset; unsigned HOST_WIDE_INT mask; unsigned bits; + int start_offset = (STRICT_ALIGNMENT ? GET_MODE_SIZE (Pmode) : 1); if (!initialized) { @@ -3391,7 +3392,7 @@ reg1 = gen_raw_REG (Pmode, LAST_VIRTUAL_REGISTER + 1); addr = gen_rtx_fmt_ee (PLUS, Pmode, reg1, NULL_RTX); - for (i = 1; i <= 1 << 20; i <<= 1) + for (i = start_offset; i <= 1 << 20; i <<= 1) { XEXP (addr, 1) = gen_int_mode (i, Pmode); if (!memory_address_p (Pmode, addr)) @@ -3400,7 +3401,7 @@ max_offset = i >> 1; off = max_offset; - for (i = 1; i <= 1 << 20; i <<= 1) + for (i = start_offset; i <= 1 << 20; i <<= 1) { XEXP (addr, 1) = gen_int_mode (-i, Pmode); if (!memory_address_p (Pmode, addr)) @@ -3541,7 +3542,8 @@ cost = 0; offset_p = (s_offset != 0 - && min_offset <= s_offset && s_offset <= max_offset); + && min_offset <= s_offset && s_offset <= max_offset + && (s_offset <= -start_offset || s_offset >= start_offset)); ratio_p = (ratio != 1 && multiplier_allowed_in_address_p (ratio)); diff -Nur gcc-4.2.4.orig/gcc/unwind-dw2.c gcc-4.2.4/gcc/unwind-dw2.c --- gcc-4.2.4.orig/gcc/unwind-dw2.c 2007-01-25 01:13:44.000000000 -0600 +++ gcc-4.2.4/gcc/unwind-dw2.c 2015-07-03 18:46:05.741283542 -0500 @@ -56,6 +56,11 @@ #define PRE_GCC3_DWARF_FRAME_REGISTERS DWARF_FRAME_REGISTERS #endif +/* Table to map Dwarf registers to unwind column. */ +#ifdef DWARF_REG_TO_UNWIND_COLUMN_TABLE +DWARF_REG_TO_UNWIND_COLUMN_TABLE; +#endif + #ifndef DWARF_REG_TO_UNWIND_COLUMN #define DWARF_REG_TO_UNWIND_COLUMN(REGNO) (REGNO) #endif @@ -153,23 +158,22 @@ /* Get the value of register INDEX as saved in CONTEXT. */ -inline _Unwind_Word -_Unwind_GetGR (struct _Unwind_Context *context, int index) +static inline _Unwind_Word +_Unwind_ByColumn_GetGR (struct _Unwind_Context *context, int column) { int size; void *ptr; #ifdef DWARF_ZERO_REG - if (index == DWARF_ZERO_REG) + if (column == DWARF_REG_TO_UNWIND_COLUMN (DWARF_ZERO_REG)) return 0; #endif - index = DWARF_REG_TO_UNWIND_COLUMN (index); - gcc_assert (index < (int) sizeof(dwarf_reg_size_table)); - size = dwarf_reg_size_table[index]; - ptr = context->reg[index]; + gcc_assert (0 <= column && column < (int) sizeof(dwarf_reg_size_table)); + size = dwarf_reg_size_table[column]; + ptr = context->reg[column]; - if (_Unwind_IsExtendedContext (context) && context->by_value[index]) + if (_Unwind_IsExtendedContext (context) && context->by_value[column]) return (_Unwind_Word) (_Unwind_Internal_Ptr) ptr; /* This will segfault if the register hasn't been saved. */ @@ -182,6 +186,15 @@ } } +/* Get the value of register INDEX as saved in CONTEXT. */ + +inline _Unwind_Word +_Unwind_GetGR (struct _Unwind_Context *context, int index) +{ + gcc_assert (0 <= index && index < FIRST_PSEUDO_REGISTER + 1); + return _Unwind_ByColumn_GetGR (context, DWARF_REG_TO_UNWIND_COLUMN (index)); +} + static inline void * _Unwind_GetPtr (struct _Unwind_Context *context, int index) { @@ -198,23 +211,22 @@ /* Overwrite the saved value for register INDEX in CONTEXT with VAL. */ -inline void -_Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val) +static inline void +_Unwind_ByColumn_SetGR (struct _Unwind_Context *context, int column, _Unwind_Word val) { int size; void *ptr; - index = DWARF_REG_TO_UNWIND_COLUMN (index); - gcc_assert (index < (int) sizeof(dwarf_reg_size_table)); - size = dwarf_reg_size_table[index]; + gcc_assert (0 <= column && column < (int) sizeof(dwarf_reg_size_table)); + size = dwarf_reg_size_table[column]; - if (_Unwind_IsExtendedContext (context) && context->by_value[index]) + if (_Unwind_IsExtendedContext (context) && context->by_value[column]) { - context->reg[index] = (void *) (_Unwind_Internal_Ptr) val; + context->reg[column] = (void *) (_Unwind_Internal_Ptr) val; return; } - ptr = context->reg[index]; + ptr = context->reg[column]; if (size == sizeof(_Unwind_Ptr)) * (_Unwind_Ptr *) ptr = val; @@ -225,15 +237,44 @@ } } +/* Overwrite the saved value for register INDEX in CONTEXT with VAL. */ + +inline void +_Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val) +{ + gcc_assert (0 <= index && index < FIRST_PSEUDO_REGISTER + 1); + return _Unwind_ByColumn_SetGR (context, DWARF_REG_TO_UNWIND_COLUMN (index), val); +} + +/* Get the pointer to a register COLUMN as saved in CONTEXT. */ + +static inline void * +_Unwind_ByColumn_GetGRPtr (struct _Unwind_Context *context, int column) +{ + gcc_assert (0 <= column && column < DWARF_FRAME_REGISTERS + 1); + if (_Unwind_IsExtendedContext (context) && context->by_value[column]) + return &context->reg[column]; + return context->reg[column]; +} + /* Get the pointer to a register INDEX as saved in CONTEXT. */ static inline void * _Unwind_GetGRPtr (struct _Unwind_Context *context, int index) { - index = DWARF_REG_TO_UNWIND_COLUMN (index); - if (_Unwind_IsExtendedContext (context) && context->by_value[index]) - return &context->reg[index]; - return context->reg[index]; + gcc_assert (0 <= index && index < FIRST_PSEUDO_REGISTER + 1); + return _Unwind_ByColumn_GetGRPtr (context, DWARF_REG_TO_UNWIND_COLUMN (index)); +} + +/* Set the pointer to a register COLUMN as saved in CONTEXT. */ + +static inline void +_Unwind_ByColumn_SetGRPtr (struct _Unwind_Context *context, int column, void *p) +{ + gcc_assert (0 <= column && column < DWARF_FRAME_REGISTERS + 1); + if (_Unwind_IsExtendedContext (context)) + context->by_value[column] = 0; + context->reg[column] = p; } /* Set the pointer to a register INDEX as saved in CONTEXT. */ @@ -241,24 +282,41 @@ static inline void _Unwind_SetGRPtr (struct _Unwind_Context *context, int index, void *p) { - index = DWARF_REG_TO_UNWIND_COLUMN (index); - if (_Unwind_IsExtendedContext (context)) - context->by_value[index] = 0; - context->reg[index] = p; + gcc_assert (0 <= index && index < FIRST_PSEUDO_REGISTER + 1); + _Unwind_ByColumn_SetGRPtr (context, DWARF_REG_TO_UNWIND_COLUMN (index), p); } +/* Overwrite the saved value for register COLUMN in CONTEXT with VAL. */ + +static inline void +_Unwind_ByColumn_SetGRValue (struct _Unwind_Context *context, int column, + _Unwind_Word val) +{ + gcc_assert (0 <= column && column < (int) sizeof(dwarf_reg_size_table)); + gcc_assert (dwarf_reg_size_table[column] == sizeof (_Unwind_Ptr)); + + context->by_value[column] = 1; + context->reg[column] = (void *) (_Unwind_Internal_Ptr) val; +} /* Overwrite the saved value for register INDEX in CONTEXT with VAL. */ static inline void _Unwind_SetGRValue (struct _Unwind_Context *context, int index, _Unwind_Word val) { - index = DWARF_REG_TO_UNWIND_COLUMN (index); - gcc_assert (index < (int) sizeof(dwarf_reg_size_table)); - gcc_assert (dwarf_reg_size_table[index] == sizeof (_Unwind_Ptr)); + gcc_assert (0 <= index && index < FIRST_PSEUDO_REGISTER + 1); + _Unwind_ByColumn_SetGRValue (context, DWARF_REG_TO_UNWIND_COLUMN (index), val); +} + +/* Return nonzero if register COLUMN is stored by value rather than + by reference. */ + +static inline int +_Unwind_ByColumn_GRByValue (struct _Unwind_Context *context, int column) +{ - context->by_value[index] = 1; - context->reg[index] = (void *) (_Unwind_Internal_Ptr) val; + gcc_assert (0 <= column && column < DWARF_FRAME_REGISTERS + 1); + return context->by_value[column]; } /* Return nonzero if register INDEX is stored by value rather than @@ -267,8 +325,8 @@ static inline int _Unwind_GRByValue (struct _Unwind_Context *context, int index) { - index = DWARF_REG_TO_UNWIND_COLUMN (index); - return context->by_value[index]; + gcc_assert (0 <= index && index < FIRST_PSEUDO_REGISTER + 1); + return _Unwind_ByColumn_GRByValue (context, DWARF_REG_TO_UNWIND_COLUMN (index)); } /* Retrieve the return address for CONTEXT. */ @@ -1225,8 +1283,12 @@ _Unwind_SetSpColumn (struct _Unwind_Context *context, void *cfa, _Unwind_SpTmp *tmp_sp) { - int size = dwarf_reg_size_table[__builtin_dwarf_sp_column ()]; - + int column = DWARF_REG_TO_UNWIND_COLUMN (__builtin_dwarf_sp_column ()); + int size; + + gcc_assert (0 <= column && column < (int)sizeof (dwarf_reg_size_table)); + + size = dwarf_reg_size_table[column]; if (size == sizeof(_Unwind_Ptr)) tmp_sp->ptr = (_Unwind_Ptr) cfa; else @@ -1234,7 +1296,8 @@ gcc_assert (size == sizeof(_Unwind_Word)); tmp_sp->word = (_Unwind_Ptr) cfa; } - _Unwind_SetGRPtr (context, __builtin_dwarf_sp_column (), tmp_sp); + + _Unwind_ByColumn_SetGRPtr (context, column, tmp_sp); } static void @@ -1299,19 +1362,19 @@ break; case REG_SAVED_OFFSET: - _Unwind_SetGRPtr (context, i, + _Unwind_ByColumn_SetGRPtr (context, i, (void *) (cfa + fs->regs.reg[i].loc.offset)); break; case REG_SAVED_REG: if (_Unwind_GRByValue (&orig_context, fs->regs.reg[i].loc.reg)) - _Unwind_SetGRValue (context, i, - _Unwind_GetGR (&orig_context, - fs->regs.reg[i].loc.reg)); + _Unwind_ByColumn_SetGRValue (context, i, + _Unwind_GetGR (&orig_context, + fs->regs.reg[i].loc.reg)); else - _Unwind_SetGRPtr (context, i, - _Unwind_GetGRPtr (&orig_context, - fs->regs.reg[i].loc.reg)); + _Unwind_ByColumn_SetGRPtr (context, i, + _Unwind_GetGRPtr (&orig_context, + fs->regs.reg[i].loc.reg)); break; case REG_SAVED_EXP: @@ -1323,14 +1386,14 @@ exp = read_uleb128 (exp, &len); val = execute_stack_op (exp, exp + len, &orig_context, (_Unwind_Ptr) cfa); - _Unwind_SetGRPtr (context, i, (void *) val); + _Unwind_ByColumn_SetGRPtr (context, i, (void *) val); } break; case REG_SAVED_VAL_OFFSET: - _Unwind_SetGRValue (context, i, - (_Unwind_Internal_Ptr) - (cfa + fs->regs.reg[i].loc.offset)); + _Unwind_ByColumn_SetGRValue (context, i, + (_Unwind_Internal_Ptr) + (cfa + fs->regs.reg[i].loc.offset)); break; case REG_SAVED_VAL_EXP: @@ -1342,7 +1405,7 @@ exp = read_uleb128 (exp, &len); val = execute_stack_op (exp, exp + len, &orig_context, (_Unwind_Ptr) cfa); - _Unwind_SetGRValue (context, i, val); + _Unwind_ByColumn_SetGRValue (context, i, val); } break; } diff -Nur gcc-4.2.4.orig/gcc/varasm.c gcc-4.2.4/gcc/varasm.c --- gcc-4.2.4.orig/gcc/varasm.c 2008-02-01 19:42:03.000000000 -0600 +++ gcc-4.2.4/gcc/varasm.c 2015-07-03 18:46:05.741283542 -0500 @@ -58,6 +58,22 @@ declarations for e.g. AIX 4.x. */ #endif + +/* Hooks to allow target specific control over the start/end of each + function or variable definition */ +#ifndef ASSEMBLE_START_FUNCTION +#define ASSEMBLE_START_FUNCTION(DECL,FNNAME) +#endif +#ifndef ASSEMBLE_END_FUNCTION +#define ASSEMBLE_END_FUNCTION(DECL,FNNAME) +#endif +#ifndef ASSEMBLE_START_VARIABLE +#define ASSEMBLE_START_VARIABLE(DECL) +#endif +#ifndef ASSEMBLE_END_VARIABLE +#define ASSEMBLE_END_VARIABLE(DECL) +#endif + /* The (assembler) name of the first globally-visible object output. */ extern GTY(()) const char *first_global_object_name; extern GTY(()) const char *weak_global_object_name; @@ -649,7 +665,7 @@ /* Return the section to use for string merging. */ -static section * +section * mergeable_string_section (tree decl ATTRIBUTE_UNUSED, unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED, unsigned int flags ATTRIBUTE_UNUSED) @@ -1416,6 +1432,9 @@ in_cold_section_p = first_function_block_is_cold; + /* Prepare to emit a function */ + ASSEMBLE_START_FUNCTION (decl, fnname); + /* Switch to the correct text section for the start of the function. */ switch_to_section (function_section (decl)); @@ -1508,6 +1527,9 @@ ASM_OUTPUT_LABEL (asm_out_file, cfun->hot_section_end_label); switch_to_section (save_text_section); } + + /* Clean up after outputting a function */ + ASSEMBLE_END_FUNCTION (decl, fnname); } /* Assemble code to leave SIZE bytes of zeros. */ @@ -1826,6 +1848,9 @@ if (sect && (sect->common.flags & SECTION_CODE) != 0) DECL_IN_TEXT_SECTION (decl) = 1; + /* Prepare to output a variable */ + ASSEMBLE_START_VARIABLE (decl); + /* If the decl is part of an object_block, make sure that the decl has been positioned within its block, but do not write out its definition yet. output_object_blocks will do that later. */ @@ -1843,6 +1868,9 @@ ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DECL_ALIGN_UNIT (decl))); assemble_variable_contents (decl, name, dont_output_data); } + + /* Clean up after outputting a variable */ + ASSEMBLE_END_VARIABLE (decl); } /* Return 1 if type TYPE contains any pointers. */ @@ -5872,10 +5900,9 @@ else if (DECL_WEAK (exp)) local_p = false; /* If PIC, then assume that any global name can be overridden by - symbols resolved from other modules, unless we are compiling with - -fwhole-program, which assumes that names are local. */ + symbols resolved from other modules. */ else if (shlib) - local_p = flag_whole_program; + local_p = false; /* Uninitialized COMMON variable may be unified with symbols resolved from other modules. */ else if (DECL_COMMON (exp) diff -Nur gcc-4.2.4.orig/gcc/var-tracking.c gcc-4.2.4/gcc/var-tracking.c --- gcc-4.2.4.orig/gcc/var-tracking.c 2007-11-07 14:48:38.000000000 -0600 +++ gcc-4.2.4/gcc/var-tracking.c 2015-07-03 18:46:05.741283542 -0500 @@ -105,6 +105,7 @@ #include "expr.h" #include "timevar.h" #include "tree-pass.h" +#include "tm_p.h" /* Type of micro operation. */ enum micro_operation_type diff -Nur gcc-4.2.4.orig/gcc/version.c gcc-4.2.4/gcc/version.c --- gcc-4.2.4.orig/gcc/version.c 2005-03-16 00:04:10.000000000 -0600 +++ gcc-4.2.4/gcc/version.c 2015-07-03 18:46:05.741283542 -0500 @@ -1,4 +1,5 @@ #include "version.h" +#include "../ccs_version.h" /* This is the trailing component of the string reported as the version number by all components of the compiler. For an official @@ -8,7 +9,23 @@ in parentheses. You may also wish to include a number indicating the revision of your modified compiler. */ -#define VERSUFFIX "" +#ifndef CCS_BRANCH0_VN +#define CCS_BRANCH0_VN 0 +#endif + +#ifndef CCS_STEP0_VN +#define CCS_STEP0_VN 0 +#endif + +#define LIT(S) #S +#define STR(N) LIT(N) + +#define VERSUFFIX " (IMG-" STR (CCS_MAJOR_VN) "." \ + STR (CCS_MINOR_VN) "." \ + STR (CCS_RELEASE_VN) "." \ + STR (CCS_BUILD_VN) \ + STR (CCS_BRANCH0_VN) \ + STR (CCS_STEP0_VN) ")" /* This is the location of the online document giving instructions for reporting bugs. If you distribute a modified version of GCC, @@ -17,7 +34,7 @@ forward us bugs reported to you, if you determine that they are not bugs in your modifications.) */ -const char bug_report_url[] = ""; +const char bug_report_url[] = "toolkit@metagence.com"; /* The complete version string, assembled from several pieces. BASEVER, DATESTAMP, and DEVPHASE are defined by the Makefile. */ diff -Nur gcc-4.2.4.orig/gcc/web.c gcc-4.2.4/gcc/web.c --- gcc-4.2.4.orig/gcc/web.c 2007-09-01 10:28:30.000000000 -0500 +++ gcc-4.2.4/gcc/web.c 2015-07-03 18:46:05.741283542 -0500 @@ -106,20 +106,20 @@ { rtx insn = DF_REF_INSN (use); struct df_link *link = DF_REF_CHAIN (use); - struct df_ref *use_link; - struct df_ref *def_link; + struct df_ref *USE_link; + struct df_ref *DEF_link; rtx set; if (insn) { - use_link = DF_INSN_USES (df, insn); - def_link = DF_INSN_DEFS (df, insn); + USE_link = DF_INSN_USES (df, insn); + DEF_link = DF_INSN_DEFS (df, insn); set = single_set (insn); } else { - use_link = NULL; - def_link = NULL; + USE_link = NULL; + DEF_link = NULL; set = NULL; } @@ -128,14 +128,35 @@ invalid instructions, so union all uses of the same operand for each insn. */ - while (use_link) - { - if (use != use_link - && DF_REF_REAL_REG (use) == DF_REF_REAL_REG (use_link)) - (*fun) (use_entry + DF_REF_ID (use), + /* First handle any uses that are match_dup's of this use ... */ + { + struct df_ref *use_link = USE_link; + + while (use_link) + { + if (use != use_link + && DF_REF_REAL_REG (use) == DF_REF_REAL_REG (use_link)) + (*fun) (use_entry + DF_REF_ID (use), use_entry + DF_REF_ID (use_link)); - use_link = use_link->next_ref; - } + + use_link = use_link->next_ref; + } + } + + /* then handle any defs that are match_dup's of this use ... */ + { + struct df_ref *def_link = DEF_link; + + while (def_link) + { + if (use != def_link + && DF_REF_REAL_REG (use) == DF_REF_REAL_REG (def_link)) + (*fun) (use_entry + DF_REF_ID (use), + def_entry + DF_REF_ID (def_link)); + + def_link = def_link->next_ref; + } + } /* Recognize trivial noop moves and attempt to keep them as noop. While most of noop moves should be removed, we still keep some @@ -145,6 +166,8 @@ && SET_SRC (set) == DF_REF_REG (use) && SET_SRC (set) == SET_DEST (set)) { + struct df_ref *def_link = DEF_link; + while (def_link) { if (DF_REF_REAL_REG (use) == DF_REF_REAL_REG (def_link)) @@ -153,6 +176,7 @@ def_link = def_link->next_ref; } } + while (link) { (*fun) (use_entry + DF_REF_ID (use), @@ -236,6 +260,7 @@ if (dump_file) fprintf (dump_file, "Updating insn %i (%i->%i)\n", INSN_UID (DF_REF_INSN (ref)), REGNO (oldreg), REGNO (reg)); + *loc = reg; } @@ -273,6 +298,7 @@ for (i = 0; i < DF_USES_SIZE (df); i++) replace_ref (DF_USES_GET (df, i), entry_register (use_entry + i, DF_USES_GET (df, i), used)); + for (i = 0; i < DF_DEFS_SIZE (df); i++) replace_ref (DF_DEFS_GET (df, i), entry_register (def_entry + i, DF_DEFS_GET (df, i), used)); diff -Nur gcc-4.2.4.orig/libstdc++-v3/configure.host gcc-4.2.4/libstdc++-v3/configure.host --- gcc-4.2.4.orig/libstdc++-v3/configure.host 2006-07-14 17:41:43.000000000 -0500 +++ gcc-4.2.4/libstdc++-v3/configure.host 2015-07-03 18:46:05.789283541 -0500 @@ -97,6 +97,9 @@ m680[246]0) try_cpu=m68k ;; + metag*) + try_cpu=metag + ;; powerpc* | rs6000) try_cpu=powerpc ;; @@ -231,6 +234,9 @@ atomicity_dir=os/irix atomic_word_dir=os/irix ;; + metag*) + os_include_dir="os/generic" + ;; mingw32*) os_include_dir="os/mingw32" ;; @@ -297,6 +303,9 @@ fi esac ;; + metag*) + atomicity_dir="cpu/generic" + ;; mips*-*-*) case "${host_os}" in gnu* | linux* | irix*) diff -Nur gcc-4.2.4.orig/libstdc++-v3/include/c_std/std_cstring.h gcc-4.2.4/libstdc++-v3/include/c_std/std_cstring.h --- gcc-4.2.4.orig/libstdc++-v3/include/c_std/std_cstring.h 2006-12-07 03:33:51.000000000 -0600 +++ gcc-4.2.4/libstdc++-v3/include/c_std/std_cstring.h 2015-07-03 18:46:05.789283541 -0500 @@ -75,6 +75,8 @@ #undef strerror #undef strlen +#undef index + _GLIBCXX_BEGIN_NAMESPACE(std) using ::memcpy; diff -Nur gcc-4.2.4.orig/libstdc++-v3/include/Makefile.in gcc-4.2.4/libstdc++-v3/include/Makefile.in --- gcc-4.2.4.orig/libstdc++-v3/include/Makefile.in 2007-07-05 06:46:00.000000000 -0500 +++ gcc-4.2.4/libstdc++-v3/include/Makefile.in 2015-07-03 18:46:05.789283541 -0500 @@ -974,6 +974,7 @@ ${host_builddir}/gthr.h \ ${host_builddir}/gthr-single.h \ ${host_builddir}/gthr-posix.h \ + ${host_builddir}/gthr-posix95.h \ ${host_builddir}/gthr-tpf.h \ ${host_builddir}/gthr-default.h @@ -1413,6 +1414,14 @@ -e 's/\(${uppercase}*USE_WEAK\)/_GLIBCXX_\1/g' \ < ${toplevel_srcdir}/gcc/gthr-posix.h > $@ +${host_builddir}/gthr-posix95.h: ${toplevel_srcdir}/gcc/gthr-posix95.h \ + stamp-${host_alias} + sed -e 's/\(UNUSED\)/_GLIBCXX_\1/g' \ + -e 's/\(GCC${uppercase}*_H\)/_GLIBCXX_\1/g' \ + -e 's/SUPPORTS_WEAK/__GXX_WEAK__/g' \ + -e 's/\(${uppercase}*USE_WEAK\)/_GLIBCXX_\1/g' \ + < ${toplevel_srcdir}/gcc/gthr-posix95.h > $@ + ${host_builddir}/gthr-tpf.h: ${toplevel_srcdir}/gcc/gthr-tpf.h \ stamp-${host_alias} sed -e 's/\(UNUSED\)/_GLIBCXX_\1/g' \