summaryrefslogtreecommitdiff
path: root/toolchain
diff options
context:
space:
mode:
Diffstat (limited to 'toolchain')
-rw-r--r--toolchain/Makefile2
-rw-r--r--toolchain/gcc/Makefile22
-rw-r--r--toolchain/gcc/Makefile.inc8
-rw-r--r--toolchain/gcc/patches/4.2.4/metag-gcc.patch36286
4 files changed, 36314 insertions, 4 deletions
diff --git a/toolchain/Makefile b/toolchain/Makefile
index 0f17d1051..cee9bab27 100644
--- a/toolchain/Makefile
+++ b/toolchain/Makefile
@@ -40,7 +40,7 @@ ELF2FLT:=elf2flt-install
endif
# disable gdb for arc
-ifeq ($(ADK_TARGET_ARCH_ARC),)
+ifeq ($(ADK_TARGET_ARCH_ARC)$(ADK_TARGET_ARCH_METAG),)
TARGETS+=gdb
GDB:=gdb-install
endif
diff --git a/toolchain/gcc/Makefile b/toolchain/gcc/Makefile
index 93ef6fcf4..24b871025 100644
--- a/toolchain/gcc/Makefile
+++ b/toolchain/gcc/Makefile
@@ -60,12 +60,12 @@ GCC_FINAL_CONFOPTS:=
ifeq ($(ADK_TARGET_WITH_NPTL),y)
ifeq ($(ADK_TARGET_LIB_WITHOUT_THREADS),)
-GCC_CONFOPTS+= --enable-tls --enable-threads --enable-libatomic
+GCC_FINAL_CONFOPTS+= --enable-tls --enable-threads --enable-libatomic
else
-GCC_CONFOPTS+= --disable-tls --disable-threads --disable-libatomic
+GCC_FINAL_CONFOPTS+= --disable-tls --disable-threads --disable-libatomic
endif
else
-GCC_CONFOPTS+= --disable-tls --disable-threads --disable-libatomic
+GCC_FINAL_CONFOPTS+= --disable-tls --disable-threads --disable-libatomic
endif
ifeq ($(ADK_TARGET_BINFMT_FLAT)$(ADK_TARGET_USE_STATIC_LIBS),y)
@@ -114,6 +114,10 @@ ifeq ($(ADK_TARGET_ARCH_ARM_WITH_THUMB),y)
GCC_CONFOPTS+= --with-mode=thumb
endif
+ifeq ($(ADK_TARGET_ARCH_METAG),y)
+GCC_CONFOPTS+= --enable-meta-default
+endif
+
ifeq ($(ADK_CPU_CF),y)
GCC_CONFOPTS+= --enable-multilib --with-arch=cf
endif
@@ -214,6 +218,8 @@ endif
--enable-languages=c \
--disable-libssp \
--disable-shared \
+ --disable-threads \
+ --disable-multilib \
--without-headers
touch $@
@@ -242,6 +248,15 @@ $(GCC_BUILD_DIR_INITIAL)/.configured:
--with-sysroot=$(STAGING_TARGET_DIR)
touch $@
+ifeq ($(ADK_TOOLCHAIN_GCC_4_2_4),y)
+$(GCC_BUILD_DIR_INITIAL)/.compiled: $(GCC_BUILD_DIR_INITIAL)/.configured
+ PATH='$(TARGET_PATH)' $(MAKE) ${GCC_MAKEOPTS} -C $(GCC_BUILD_DIR_INITIAL) all-gcc
+ touch $@
+
+$(WRKBUILD)/.configured: $(GCC_BUILD_DIR_INITIAL)/.compiled
+ PATH='$(TARGET_PATH)' $(MAKE) -C $(GCC_BUILD_DIR_INITIAL) install-gcc
+ touch $@
+else
$(GCC_BUILD_DIR_INITIAL)/.compiled: $(GCC_BUILD_DIR_INITIAL)/.configured
PATH='$(TARGET_PATH)' $(MAKE) ${GCC_MAKEOPTS} -C $(GCC_BUILD_DIR_INITIAL) all-gcc all-target-libgcc
touch $@
@@ -249,6 +264,7 @@ $(GCC_BUILD_DIR_INITIAL)/.compiled: $(GCC_BUILD_DIR_INITIAL)/.configured
$(WRKBUILD)/.configured: $(GCC_BUILD_DIR_INITIAL)/.compiled
PATH='$(TARGET_PATH)' $(MAKE) -C $(GCC_BUILD_DIR_INITIAL) install-gcc install-target-libgcc
touch $@
+endif
$(GCC_BUILD_DIR_FINAL)/.configured:
mkdir -p $(GCC_BUILD_DIR_FINAL)
diff --git a/toolchain/gcc/Makefile.inc b/toolchain/gcc/Makefile.inc
index 17df0c38b..2c5d22ac7 100644
--- a/toolchain/gcc/Makefile.inc
+++ b/toolchain/gcc/Makefile.inc
@@ -67,6 +67,14 @@ PKG_RELEASE:= 1
DISTFILES:= ${PKG_NAME}-${PKG_VERSION}.tar.gz
LIBSTDCXXVER:= 19
endif
+ifeq ($(ADK_TOOLCHAIN_GCC_4_2_4),y)
+PKG_VERSION:= 4.2.4
+PKG_HASH:= 7cb75c5183bd18f415860084440377016dc78feeee2852227b831f2e4fcaa5d6
+PKG_SITES:= http://gcc.cybermirror.org/releases/gcc-${PKG_VERSION}/
+PKG_RELEASE:= 1
+DISTFILES:= ${PKG_NAME}-${PKG_VERSION}.tar.gz
+LIBSTDCXXVER:= 19
+endif
ifeq ($(ADK_TOOLCHAIN_GCC_GIT),y)
PKG_VERSION:= git
PKG_SITES:= git://gcc.gnu.org/git/gcc.git
diff --git a/toolchain/gcc/patches/4.2.4/metag-gcc.patch b/toolchain/gcc/patches/4.2.4/metag-gcc.patch
new file mode 100644
index 000000000..8b351a1f6
--- /dev/null
+++ b/toolchain/gcc/patches/4.2.4/metag-gcc.patch
@@ -0,0 +1,36286 @@
+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 <http://www.gnu.org/licenses/>.
+ #
+ # 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 <per@bothner.com>.
+-# Please send patches to <config-patches@gnu.org>. 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 <features.h>
++ #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 <stdlib.h>
++ #include <unistd.h>
++
++ int main ()
++ {
++ #if defined(_SC_KERNEL_BITS)
++ long bits = sysconf(_SC_KERNEL_BITS);
++ #endif
++ long cpu = sysconf (_SC_CPU_VERSION);
+
+- #define _HPUX_SOURCE
+- #include <stdlib.h>
+- #include <unistd.h>
+-
+- 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 <features.h>
+- #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 <Richard.M.Bartel@ccMail.Census.GOV>
+- echo i586-unisys-sysv4
+- exit ;;
++ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
++ # says <Richard.M.Bartel@ccMail.Census.GOV>
++ echo i586-unisys-sysv4
++ exit ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # 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 <<EOF
+-#ifdef _SEQUENT_
+-# include <sys/types.h>
+-# include <sys/utsname.h>
+-#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 <sys/param.h>
+- 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 <sys/param.h>
+-# 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 <<EOF
+ $0: unable to guess system type
+@@ -1458,9 +1378,9 @@
+ the operating system you are using. It is advised that you
+ download the most up to date version of the config scripts from
+
+- http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess
++ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+ and
+- http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub
++ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+ If the version you run ($0) is already up to date, please
+ send the following data and any information you think might be
+diff -Nur gcc-4.2.4.orig/config-ml.in gcc-4.2.4/config-ml.in
+--- gcc-4.2.4.orig/config-ml.in 2006-06-13 15:48:23.000000000 -0500
++++ gcc-4.2.4/config-ml.in 2015-07-03 18:46:05.717283542 -0500
+@@ -1,8 +1,8 @@
+ # Configure fragment invoked in the post-target section for subdirs
+ # wanting multilib support.
+ #
+-# Copyright (C) 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+-# Free Software Foundation, Inc.
++# Copyright (C) 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
++# 2005, 2006, 2007 Free Software Foundation, Inc.
+ #
+ # This file is free software; you can redistribute it and/or modify
+ # it under the terms of the GNU General Public License as published by
+@@ -108,6 +108,11 @@
+ ml_verbose=--verbose
+ for option in ${ac_configure_args}
+ do
++ # strip single quotes surrounding individual options
++ case $option in
++ \'*\') eval option=$option ;;
++ esac
++
+ case $option in
+ --*) ;;
+ -*) option=-$option ;;
+@@ -535,7 +540,7 @@
+ else \
+ rootpre=`${PWD_COMMAND}`/; export rootpre; \
+ srcrootpre=`cd $(srcdir); ${PWD_COMMAND}`/; export srcrootpre; \
+- lib=`echo $${rootpre} | sed -e 's,^.*/\([^/][^/]*\)/$$,\1,'`; \
++ lib=`echo "$${rootpre}" | sed -e 's,^.*/\([^/][^/]*\)/$$,\1,'`; \
+ compiler="$(CC)"; \
+ for i in `$${compiler} --print-multi-lib 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 <<EOF
++ if [ -f ../\$\${dir}/\$\${lib}/${Makefile} ]; then \\
++EOF
++cat >>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 <http://www.gnu.org/licenses/>.
+ #
+ # 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 <config-patches@gnu.org>. 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
++;; <http://www.gnu.org/licenses/>.
++
++;;- 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
++;; <http://www.gnu.org/licenses/>.
++
++;; -----------------------------------------------------------------------------
++;; | Recognising SI/HI/QI store pre-inc/dec/modify |
++;; -----------------------------------------------------------------------------
++
++(define_insn_and_split "*sto_<mode>_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_<mode>" "<O>")))
++ (match_operand:<MODE> 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>mode))
++ pre = gen_rtx_PRE_INC (SImode, operands[0]);
++ else if (INTVAL (operands[1]) == -GET_MODE_SIZE (<MODE>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>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_<mode>_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:<MODE> 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>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_<mode>_post_inc_dec_modify_disp_split"
++ [(set (mem:MEMOP (match_operand:SI 0 "metag_regnofrm_op" "+efhl"))
++ (match_operand:<MODE> 1 "metag_register_op" "r"))
++ (set (match_dup 0)
++ (plus:SI (match_dup 0)
++ (match_operand:SI 2 "metag_offset6_<mode>" "<O>")))]
++ "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>mode))
++ post = gen_rtx_POST_INC (SImode, operands[0]);
++ else if (INTVAL (operands[2]) == -GET_MODE_SIZE (<MODE>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>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_<mode>_post_modify_reg_split"
++ [(set (mem:MEMOP (match_operand:SI 0 "metag_regnofrm_op" "+e,f,h,l"))
++ (match_operand:<MODE> 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>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_<mode>_pre_inc_dec_modify_disp_split"
++ [(set (match_operand:<MODE> 0 "metag_register_op" "=r")
++ (mem:MEMOP (plus:SI (match_operand:SI 1 "metag_regnofrm_op" "+efhl")
++ (match_operand:SI 2 "metag_offset6_<mode>" "<O>"))))
++ (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>mode))
++ pre = gen_rtx_PRE_INC (SImode, operands[1]);
++ else if (INTVAL (operands[2]) == -GET_MODE_SIZE (<MODE>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>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_<mode>_pre_modify_reg_split"
++ [(set (match_operand:<MODE> 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>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_<mode>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_<mode>" "<O>")))))
++ (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>mode))
++ pre = gen_rtx_PRE_INC (SImode, operands[1]);
++ else if (INTVAL (operands[2]) == -GET_MODE_SIZE (<MODE>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>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_<mode>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>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_<mode>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_<mode>" "<O>")))))
++ (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>mode))
++ pre = gen_rtx_PRE_INC (SImode, operands[1]);
++ else if (INTVAL (operands[2]) == -GET_MODE_SIZE (<MODE>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>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_<mode>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>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
++;; <http://www.gnu.org/licenses/>.
++
++;; 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
++;; <http://www.gnu.org/licenses/>.
++
++;; 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
++<http://www.gnu.org/licenses/>. */
++
++#include <string.h>
++#include <stdlib.h>
++#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 %<S construct. It will do the same for
++ hard-float taking in to account that soft-float is the inverse
++ and also dealing with simd-float */
++
++enum fpu_state
++{
++ FPU_SOFT_FLOAT,
++ FPU_HARD_FLOAT,
++ FPU_HARD_FLOAT_DOUBLE,
++ FPU_HARD_FLOAT_SINGLE
++};
++
++const char *
++metag_reduce_options (int argc, const char **argv)
++{
++ /* Default FPU mode is soft float */
++ enum fpu_state fpu_state = FPU_SOFT_FLOAT;
++
++ /* Default META core is 2.1 (though this will always be overriden so it does not matter) */
++ int metac_state = 21;
++
++ /* SIMD FPU is not enabled by default */
++ int simd_float = 0;
++
++ /* 'i' is always useful */
++ int i;
++
++ /* 140 is the total length of all possible options that will be emitted with a null
++ terminator at the end */
++ char* buf = (char*)xmalloc(159);
++
++ for (i = 0 ; i < argc ; i++)
++ {
++ if (strcmp (argv[i], "mhard-float=D") == 0)
++ {
++ fpu_state = FPU_HARD_FLOAT_DOUBLE;
++ simd_float = 0;
++ }
++ else if (strcmp (argv[i], "mhard-float=S") == 0)
++ {
++ fpu_state = FPU_HARD_FLOAT_SINGLE;
++ simd_float = 0;
++ }
++ else if (strcmp (argv[i], "mhard-float") == 0)
++ {
++ fpu_state = FPU_HARD_FLOAT;
++ simd_float = 0;
++ }
++ else if (strcmp (argv[i], "msoft-float") == 0 || strcmp (argv[i], "mhard-float=none") == 0)
++ {
++ fpu_state = FPU_SOFT_FLOAT;
++ simd_float = 0;
++ }
++ else if (strcmp (argv[i], "msimd-float") == 0)
++ simd_float = 1;
++ else if (strncmp (argv[i], "mmetac=", 7) == 0)
++ if (strlen (argv[i]) == 10)
++ {
++ metac_state = (argv[i][7] - '0') * 10;
++ metac_state += (argv[i][9] - '0');
++ }
++ }
++
++ /* Point to the start of the buffer */
++ i = 0;
++
++ /* Strip various duplicated/overridden options */
++ strncpy (&buf[i], "%<mhard-float=none ", 19);
++ i += 19;
++
++ if (simd_float == 0)
++ {
++ strncpy (&buf[i], "%<msimd-float ", 14);
++ i += 14;
++ }
++
++ if (fpu_state != FPU_SOFT_FLOAT)
++ {
++ strncpy (&buf[i], "%<msoft-float ", 14);
++ i += 14;
++ }
++
++ if (fpu_state != FPU_HARD_FLOAT)
++ {
++ strncpy (&buf[i], "%<mhard-float ", 14);
++ i += 14;
++ }
++
++ if (fpu_state != FPU_HARD_FLOAT_DOUBLE)
++ {
++ strncpy (&buf[i], "%<mhard-float=D ", 16);
++ i += 16;
++ }
++
++ if (fpu_state != FPU_HARD_FLOAT_SINGLE)
++ {
++ strncpy (&buf[i], "%<mhard-float=S ", 16);
++ i += 16;
++ }
++
++ if (metac_state != 1)
++ {
++ strncpy (&buf[i], "%<mmetac=0.1 ", 13);
++ i += 13;
++ }
++
++ if (metac_state != 10)
++ {
++ strncpy (&buf[i], "%<mmetac=1.0 ", 13);
++ i += 13;
++ }
++
++ if (metac_state != 11)
++ {
++ strncpy (&buf[i], "%<mmetac=1.1 ", 13);
++ i += 13;
++ }
++
++ if (metac_state != 12)
++ {
++ strncpy (&buf[i], "%<mmetac=1.2 ", 13);
++ i += 13;
++ }
++
++ if (metac_state != 21)
++ {
++ strncpy (&buf[i], "%<mmetac=2.1 ", 13);
++ i += 13;
++ }
++
++ buf[i] = 0;
++
++ return buf;
++}
++
++/* This will be called by the spec parser in gcc.c when it sees
++ a %:meta_preprocessor(args) construct.
++
++ It returns a string containing new command line parameters to be
++ passed to the assembler. This is for transforming -Dwhatever
++ into --defwhatever. The spec will do the translation of -D
++ to --def but this code removes all definitions that have
++ assignments as the embedded assembler cannot cope with these
++
++ ARGC and ARGV are set depending on the actual arguments given
++ in the spec. */
++const char *
++metag_emb_asm_preprocessor (int argc, const char **argv)
++{
++ char * cmd_args = NULL;
++ char * current_pos = NULL;
++ int args_size = 0;
++ int i;
++
++ for (i = 0 ; i < argc ; i++)
++ {
++ if (strchr (argv[i], '=') == NULL)
++ args_size += strlen (argv[i]) + 1;
++ }
++
++ if (args_size == 0)
++ return NULL;
++
++ cmd_args = (char *)malloc (args_size);
++ current_pos = cmd_args;
++
++ for (i = 0 ; i < argc ; i++)
++ {
++ if (strchr (argv[i], '=') == NULL)
++ {
++ int length = strlen (argv[i]);
++
++ strcpy (current_pos, argv[i]);
++ *(current_pos+length) = ' ';
++ current_pos += length + 1;
++ }
++ }
++ *(current_pos-1) = 0;
++
++ return cmd_args;
++}
++
++const char *
++metag_emb_onlylast (int argc, const char **argv)
++{
++ if (argc != 0)
++ return argv[argc-1];
++ else
++ return NULL;
++}
++
++const char *
++metag_emb_change_suffix (int argc, const char **argv)
++{
++ const char * old_filename = NULL;
++ char * new_filename = NULL;
++ unsigned int old_length = 0;
++ unsigned int new_length = 0;
++ const char * suffix = NULL;
++ int new_suffix_length = 0;
++ int dot_pos = 0;
++ int has_dot = 0;
++
++ if (argc < 2)
++ {
++ fprintf (stderr, "Not enough arguments given to the meta_change_suffix function!\n");
++ exit (1);
++ }
++ else
++ {
++ suffix = argv[0];
++ /* If multiple -o switches are used on the command line the last one is used */
++ old_filename = argv[argc - 1];
++ old_length = strlen (old_filename);
++ new_suffix_length = strlen (suffix);
++
++ /* Find the location of the . in the filename */
++ dot_pos = old_length;
++ while (dot_pos-- && !IS_DIR_SEPARATOR (old_filename[dot_pos]))
++ {
++ if (old_filename[dot_pos] == '.')
++ {
++ has_dot = 1;
++ break;
++ }
++ }
++
++ /* Deal with the case where there is no dot in the filename */
++ if (!has_dot)
++ dot_pos = old_length;
++
++ /* Compute the length of the string to hold the filename with the new suffix. */
++ new_length = dot_pos + new_suffix_length + 1;
++
++ /* Create a new string to hold the filename, and initialise
++ it with the old filename excluding the dot and suffix (if applicable) */
++ new_filename = (char *)malloc (new_length + 1);
++ strncpy (new_filename, old_filename, dot_pos + 1);
++
++ /* Add the dot and new suffix to the filename */
++ new_filename[dot_pos] = '.';
++ strcpy (&new_filename[dot_pos + 1], suffix);
++
++ return new_filename;
++ }
++}
+diff -Nur gcc-4.2.4.orig/gcc/config/metag/dsppeephole2.md gcc-4.2.4/gcc/config/metag/dsppeephole2.md
+--- gcc-4.2.4.orig/gcc/config/metag/dsppeephole2.md 1969-12-31 18:00:00.000000000 -0600
++++ gcc-4.2.4/gcc/config/metag/dsppeephole2.md 2015-07-03 18:46:05.745283542 -0500
+@@ -0,0 +1,394 @@
++;; 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
++;; <http://www.gnu.org/licenses/>.
++
++;; 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, <commutative>)"
++ [(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)
++ <dualunitimmcondition>"
++ [(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)
++ <dualunitimmcondition>"
++ [(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, <commutative>)"
++ [(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, <commutative>)"
++ [(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)
++ <dualunitimmcondition>"
++ [(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)
++ <dualunitimmcondition>"
++ [(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)
++ <dualunitimmcondition>"
++ [(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)
++ <dualunitimmcondition>"
++ [(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, <commutative>)
++ && 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, <commutative>)
++ && 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
++;; <http://www.gnu.org/licenses/>.
++
++;; 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:
++
++;; <commutative>
++;; Indicates if an insn code has commutative input operands.
++;; <dualunitimmcondition>
++;; Special immediate conditions for dual unit operations.
++;; <expander>
++;; The name of the insn suitable for use in rtl generation.
++;; <MNEMONIC>
++;; 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, <commutative>)"
++ "DL\\t<MNEMONIC>\\t%0, %1, %2\\t%@ (*<MNEMONIC>\\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, <commutative>)"
++ "DL\\t<MNEMONIC>\\t%3, %4, %5\\t%@ (*<MNEMONIC>\\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)
++ <dualunitimmcondition>"
++ "DL\\t<MNEMONIC>\\t%0, %0, %1\\t%@ (*<MNEMONIC>\\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)
++ <dualunitimmcondition>"
++ "DL\\t<MNEMONIC>\\t%0, %1, %2\\t%@ (*<MNEMONIC>\\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<MNEMONIC>\\t%0, %1, %2\\t%@ (*<MNEMONIC>\\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, <commutative>)"
++ "DL\\t<MNEMONIC>S\\t%0, %1, %2\\t%@ (*<MNEMONIC>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, <commutative>)"
++ "DL\\t<MNEMONIC>S\\t%0, %1, %2\\t%@ (*<MNEMONIC>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, <commutative>)"
++ "DL\\t<MNEMONIC>S\\t%3, %4, %5\\t%@ (*<MNEMONIC>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)
++ <dualunitimmcondition>"
++ "DL\\t<MNEMONIC>S\\t%0, %0, %1\\t%@ (*<MNEMONIC>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)
++ <dualunitimmcondition>"
++ "DL\\t<MNEMONIC>S\\t%0, %1, %2\\t%@ (*<MNEMONIC>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)
++ <dualunitimmcondition>"
++ "DL\\t<MNEMONIC>S\\t%0, %0, %1\\t%@ (*<MNEMONIC>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)
++ <dualunitimmcondition>"
++ "DL\\t<MNEMONIC>S\\t%0, %1, %2\\t%@ (*<MNEMONIC>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)
++ <dualunitimmcondition>"
++ "DL\\t<MNEMONIC>S\\t%2, %2, %1\\t%@ (*<MNEMONIC>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)
++ <dualunitimmcondition>"
++ "DL\\t<MNEMONIC>S\\t%3, %4, %2\\t%@ (*<MNEMONIC>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)
++ <dualunitimmcondition>"
++ "DL\\t<MNEMONIC>S\\t%2, %2, %1\\t%@ (*<MNEMONIC>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)
++ <dualunitimmcondition>"
++ "DL\\t<MNEMONIC>S\\t%3, %4, %2\\t%@ (*<MNEMONIC>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, <commutative>)
++ && dead_or_set_p (PREV_INSN (insn), operands[0])
++ && dead_or_set_p (insn, operands[3])"
++ "DL\\t<MNEMONIC>\\t%6, %1, %2\\t%@ (*<MNEMONIC>\\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, <commutative>)
++ && dead_or_set_p (PREV_INSN (PREV_INSN (insn)), operands[0])
++ && dead_or_set_p (insn, operands[3])"
++ "DL\\t<MNEMONIC>\\t%6, %1, %2\\t%@ (*<MNEMONIC>\\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
++<http://www.gnu.org/licenses/>. */
++
++#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
++<http://www.gnu.org/licenses/>. */
++
++/* 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<b -> -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)| a<b(-1)
++ -------+--------+--------
++ -inf(1)| a>b(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
++;; <http://www.gnu.org/licenses/>.
++
++;;- 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 "abs<mode>2"
++ [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx")
++ (abs:<MODE> (match_operand:<MODE> 1 "metag_fpreg_op" "cx")))]
++ "<fcondition>"
++ "F<FW>\\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_<mode>_imm"
++ [(set (match_operand:FMODES 0 "metag_fpreg_op" "=cx")
++ (match_operand:<MODE> 1 "metag_fphalf_imm_op" "ci"))]
++ "<fcondition>"
++ "F<FW>\\tMOV\\t%0,#%h1"
++ [(set_attr "type" "FPfast")])
++
++(define_insn "neg<mode>2"
++ [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx")
++ (neg:<MODE> (match_operand:<MODE> 1 "metag_fpreg_op" "cx")))]
++ "<fcondition>"
++ "F<FW>\\tNEG%?\\t%0,%1"
++ [(set_attr "type" "FPmas")
++ (set_attr "predicable" "yes")])
++
++; TODO: PACK
++; TODO: SWAP
++
++; Comparison Operations
++
++(define_expand "cmp<mode>"
++ [(match_operand:FMODES 0 "metag_fpreg_op" "")
++ (match_operand:<MODE> 1 "metag_fpreg_or_imm_op" "")]
++ "<fcondition>"
++ {
++ 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<CCFP:mode>"
++ [(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<CCQ>\\tCMP%?\\t%0,%1
++ F<CCQ>\\tCMP%?\\t%0,#%h1"
++ [(set_attr "type" "FPfast")])
++
++(define_insn "*cmpdf<CCFP:mode>"
++ [(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<CCQ>\\tCMP%?\\t%0,%1
++ FD<CCQ>\\tCMP%?\\t%0,#%h1"
++ [(set_attr "type" "FPfast")])
++
++(define_insn "*abscmpsf<CCFP:mode>2"
++ [(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<CCQ>\\tCMP%?\\t%0,%1
++ FA<CCQ>\\tCMP%?\\t%0,#%h1"
++ [(set_attr "type" "FPmas")])
++
++(define_insn "*abscmpdf<CCFP:mode>2"
++ [(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<CCQ>\\tCMP%?\\t%0,%1
++ FDA<CCQ>\\tCMP%?\\t%0,#%h1"
++ [(set_attr "type" "FPmas")
++ (set_attr "predicable" "yes")])
++
++(define_insn "smax<mode>3"
++ [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx")
++ (smax:<MODE> (match_operand:<MODE> 1 "metag_fpreg_op" "cx")
++ (match_operand:<MODE> 2 "metag_fpreg_op" "cx")))
++ (clobber (reg:CC CC_REG))]
++ "<fcondition>"
++ "F<FW>\\tMAX%?\\t%0,%1,%2"
++ [(set_attr "type" "FPmas")
++ (set_attr "predicable" "yes")
++ (set_attr "ccstate" "ccx")])
++
++(define_insn "smin<mode>3"
++ [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx")
++ (smin:<MODE> (match_operand:<MODE> 1 "metag_fpreg_op" "cx")
++ (match_operand:<MODE> 2 "metag_fpreg_op" "cx")))
++ (clobber (reg:CC CC_REG))]
++ "<fcondition>"
++ "F<FW>\\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_trunc<mode>si2"
++ [(set (match_operand:SI 0 "metag_fpreg_op" "=cx")
++ (fix:SI (match_operand:FSMODES 1 "metag_fpreg_op" "cx")))]
++ "<fcondition>"
++ "FZ\\t<FT>TOI%?\\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 "floatsi<mode>2"
++ [(set (match_operand:FSMODES 0 "metag_fpreg_op" "=cx")
++ (float:<MODE> (match_operand:SI 1 "metag_fpreg_op" "cx")))]
++ "<fcondition>"
++ "F\\tITO<FT>%?\\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 "floatunshi<mode>2"
++ [(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:<MODE> (match_dup 2)))]
++ "<fcondition>"
++ {
++ 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 "add<mode>3"
++ [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx")
++ (plus:<MODE> (match_operand:<MODE> 1 "metag_fpreg_op" "cx")
++ (match_operand:<MODE> 2 "metag_fpreg_op" "cx")))]
++ "<fcondition>"
++ "F<FW>\\tADD%?\\t%0,%1,%2"
++ [(set_attr "type" "FPmas")
++ (set_attr "predicable" "yes")])
++
++(define_insn "*add<FMODES:mode>_if_<CCALL:mode>_cxcxcxcx"
++ [(set (match_operand:FMODES 0 "metag_fpreg_op" "=cx")
++ (if_then_else:FMODES (match_operator 1 "comparison_operator"
++ [(match_operand:CCALL 2 "metag_<mode>_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")))]
++ "<fcondition>"
++ "F<FMODES:FW>\\tADD%z1\\t%0,%3,%4"
++ [(set_attr "type" "FPmas")
++ (set_attr "ccstate" "xcc")])
++
++(define_insn "*nadd<mode>3"
++ [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx")
++ (neg:<MODE>
++ (plus:<MODE> (match_operand:<MODE> 1 "metag_fpreg_op" "cx")
++ (match_operand:<MODE> 2 "metag_fpreg_op" "cx"))))]
++ "<fcondition>"
++ "F<FW>I\\tADD%?\\t%0,%1,%2"
++ [(set_attr "type" "FPmas")
++ (set_attr "predicable" "yes")])
++
++(define_insn "mul<mode>3"
++ [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx")
++ (mult:<MODE> (match_operand:<MODE> 1 "metag_fpreg_op" "cx")
++ (match_operand:<MODE> 2 "metag_fpreg_op" "cx")))]
++ "<fcondition>"
++ "F<FW>\\tMUL%?\\t%0,%1,%2"
++ [(set_attr "type" "FPmas")
++ (set_attr "predicable" "yes")])
++
++(define_insn "*nmul<mode>3"
++ [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx")
++ (neg:<MODE>
++ (mult:<MODE> (match_operand:<MODE> 1 "metag_fpreg_op" "cx")
++ (match_operand:<MODE> 2 "metag_fpreg_op" "cx"))))]
++ "<fcondition>"
++ "F<FW>I\\tMUL%?\\t%0,%1,%2"
++ [(set_attr "type" "FPmas")
++ (set_attr "predicable" "yes")])
++
++(define_insn "sub<mode>3"
++ [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx")
++ (minus:<MODE> (match_operand:<MODE> 1 "metag_fpreg_op" "cx")
++ (match_operand:<MODE> 2 "metag_fpreg_op" "cx")))]
++ "<fcondition>"
++ "F<FW>\\tSUB%?\\t%0,%1,%2"
++ [(set_attr "type" "FPmas")
++ (set_attr "predicable" "yes")])
++
++(define_insn "*sub<FMODES:mode>_if_<CCALL:mode>_cxcxcxcx"
++ [(set (match_operand:FMODES 0 "metag_fpreg_op" "=cx")
++ (if_then_else:FMODES (match_operator 1 "comparison_operator"
++ [(match_operand:CCALL 2 "metag_<mode>_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")))]
++ "<fcondition>"
++ "F<FMODES:FW>\\tSUB%z1\\t%0,%3,%4"
++ [(set_attr "type" "FPmas")
++ (set_attr "ccstate" "xcc")])
++
++(define_insn "*nsub<mode>3"
++ [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx")
++ (neg:<MODE>
++ (minus:<MODE> (match_operand:<MODE> 1 "metag_fpreg_op" "cx")
++ (match_operand:<MODE> 2 "metag_fpreg_op" "cx"))))]
++ "<fcondition>"
++ "F<FW>I\\tSUB%?\\t%0,%1,%2"
++ [(set_attr "type" "FPmas")
++ (set_attr "predicable" "yes")])
++
++
++; Extended Floating Point Insn's
++; SFmode
++
++; TODO MUZ
++(define_insn "*muladd<mode>3_fused"
++ [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx")
++ (plus:<MODE>
++ (mult:<MODE> (match_operand:<MODE> 1 "metag_fpreg_op" "cx")
++ (match_operand:<MODE> 2 "metag_fpreg_op" "cx"))
++ (match_operand:<MODE> 3 "metag_fpreg_op" "0")))]
++ "<fcondition>"
++ "F<FW>\\tMUZ\\t%0,%1,%2"
++ [(set_attr "type" "FPmas")])
++
++(define_insn "*muladd1<mode>3_fused"
++ [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx")
++ (plus:<MODE>
++ (mult:<MODE> (match_operand:<MODE> 1 "metag_fpreg_op" "cx")
++ (match_operand:<MODE> 2 "metag_fpreg_op" "cx"))
++ (match_operand:<MODE> 3 "metag_fpone_imm_op" "H")))]
++ "<fcondition>"
++ "F<FW>\\tMUZ1\\t%0,%1,%2"
++ [(set_attr "type" "FPmas")])
++
++(define_insn "*mulsub<mode>3_fused"
++ [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx")
++ (minus:<MODE>
++ (mult:<MODE> (match_operand:<MODE> 1 "metag_fpreg_op" "cx")
++ (match_operand:<MODE> 2 "metag_fpreg_op" "cx"))
++ (match_operand:<MODE> 3 "metag_fpreg_op" "0")))]
++ "<fcondition>"
++ "F<FW>\\tMUZS\\t%0,%1,%2"
++ [(set_attr "type" "FPmas")])
++
++(define_insn "*mulsub1<mode>3_fused"
++ [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx")
++ (minus:<MODE>
++ (mult:<MODE> (match_operand:<MODE> 1 "metag_fpreg_op" "cx")
++ (match_operand:<MODE> 2 "metag_fpreg_op" "cx"))
++ (match_operand:<MODE> 3 "metag_fpone_imm_op" "H")))]
++ "<fcondition>"
++ "F<FW>\\tMUZS1\\t%0,%1,%2"
++ [(set_attr "type" "FPmas")])
++
++(define_insn "*nmuladd<mode>3_fused"
++ [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx")
++ (neg:<MODE>
++ (plus:<MODE>
++ (mult:<MODE> (match_operand:<MODE> 1 "metag_fpreg_op" "cx")
++ (match_operand:<MODE> 2 "metag_fpreg_op" "cx"))
++ (match_operand:<MODE> 3 "metag_fpreg_op" "0"))))]
++ "<fcondition>"
++ "F<FW>I\\tMUZ\\t%0,%1,%2"
++ [(set_attr "type" "FPmas")])
++
++(define_insn "*nmuladd1<mode>3_fused"
++ [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx")
++ (neg:<MODE>
++ (plus:<MODE>
++ (mult:<MODE> (match_operand:<MODE> 1 "metag_fpreg_op" "cx")
++ (match_operand:<MODE> 2 "metag_fpreg_op" "cx"))
++ (match_operand:<MODE> 3 "metag_fpone_imm_op" "H"))))]
++ "<fcondition>"
++ "F<FW>I\\tMUZ1\\t%0,%1,%2"
++ [(set_attr "type" "FPmas")])
++
++(define_insn "*nmulsub<mode>3_fused"
++ [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx")
++ (neg:<MODE>
++ (minus:<MODE>
++ (mult:<MODE> (match_operand:<MODE> 1 "metag_fpreg_op" "cx")
++ (match_operand:<MODE> 2 "metag_fpreg_op" "cx"))
++ (match_operand:<MODE> 3 "metag_fpreg_op" "0"))))]
++ "<fcondition>"
++ "F<FW>I\\tMUZS\\t%0,%1,%2"
++ [(set_attr "type" "FPmas")])
++
++(define_insn "*nmulsub1<mode>3_fused"
++ [(set (match_operand:FLMODES 0 "metag_fpreg_op" "=cx")
++ (neg:<MODE>
++ (minus:<MODE>
++ (mult:<MODE> (match_operand:<MODE> 1 "metag_fpreg_op" "cx")
++ (match_operand:<MODE> 2 "metag_fpreg_op" "cx"))
++ (match_operand:<MODE> 3 "metag_fpone_imm_op" "H"))))]
++ "<fcondition>"
++ "F<FW>I\\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 "*div<mode>2_fast"
++ [(set (match_operand:FMODES 0 "metag_fpreg_op" "=&cx")
++ (div:<MODE> (match_operand:<MODE> 1 "metag_fpreg_op" "cx")
++ (match_operand:<MODE> 2 "metag_fpreg_op" "cx")))]
++ "<fcondition> && TARGET_FAST_MATH"
++ "#"
++ "&& 1"
++ [(const_int 0)]
++ {
++ emit_insn (gen_rcp<mode>2 (operands[0], CONST1_RTX (<MODE>mode), operands[2]));
++ emit_insn (gen_mul<mode>3 (operands[0], operands[0], operands[1]));
++ DONE;
++ }
++ [(set_attr "type" "FPrecipmas")])
++
++(define_insn "rcp<mode>2"
++ [(set (match_operand:FMODES 0 "metag_fpreg_op" "=cx")
++ (div:<MODE> (match_operand:<MODE> 1 "metag_fpone_imm_op" "H")
++ (match_operand:<MODE> 2 "metag_fpreg_op" "cx")))]
++ "<fcondition> && TARGET_FAST_MATH"
++ {
++ if (TARGET_FLUSH_TO_ZERO)
++ return "F<FW>Z\\tRCP\\t%0,%2";
++ else
++ return "F<FW>\\tRCP\\t%0,%2";
++ }
++ [(set_attr "type" "FPrecip")])
++
++(define_insn "*rsq<mode>2"
++ [(set (match_operand:FMODES 0 "metag_fpreg_op" "=cx")
++ (div:<MODE> (match_operand:<MODE> 1 "metag_fpone_imm_op" "H")
++ (sqrt:<MODE> (match_operand:<MODE> 2 "metag_fpreg_op" "cx"))))]
++ "<fcondition> && TARGET_FAST_MATH"
++ {
++ if (TARGET_FLUSH_TO_ZERO)
++ return "F<FW>Z\\tRSQ\\t%0,%2";
++ else
++ return "F<FW>\\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
++<http://www.gnu.org/licenses/>. */
++
++/* 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
++<http://www.gnu.org/licenses/>. */
++
++#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
++<http://www.gnu.org/licenses/>. */
++
++#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
++<http://www.gnu.org/licenses/>. */
++
++#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 <ctype.h>
++
++/* 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
++<http://www.gnu.org/licenses/>. */
++
++#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 <static-chain>
++ .long <function-address>
++ */
++
++/* 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
++<http://www.gnu.org/licenses/>. */
++
++#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
++<http://www.gnu.org/licenses/>. */
++
++#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
++; <http://www.gnu.org/licenses/>.
++
++
++; 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
++;; <http://www.gnu.org/licenses/>.
++
++;;- 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_<mode>_mov_si_zero"
++ [(cond_exec
++ (match_operator 1 "comparison_operator"
++ [(match_operand:CCALL 2 "metag_<mode>_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_<mode>"
++ [(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_<mode>_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_<mode>"
++ [(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_<mode>_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_<mode>_add_si_rri"
++ [(cond_exec
++ (match_operator 3 "comparison_operator"
++ [(match_operand:CCALL 4 "metag_<mode>_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_<mode>_rr"
++ [(set (reg:<MODE> 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:<MODE> CC_REG)
++ (compare:<MODE>
++ (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_<mode>_si_rrr"
++ [(set (reg:<MODE> 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_<mode>_si_rrr_1_1"
++ [(set (reg:<MODE> 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_<mode>_symglobal_1_1"
++ [(set (reg:<MODE> 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:<MODE> CC_REG)
++ (compare:<MODE>
++ (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_<mode>_si_txrpt_ri"
++ [(set (reg:<MODE> 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_<mode>_si_rri"
++ [(set (reg:<MODE> 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:<MODE> 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:<MODE> CC_REG)
++ (compare:<MODE>
++ (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_<mode>_si_rrr"
++ [(set (reg:<MODE> 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_<mode>_si_rrr_1_1"
++ [(set (reg:<MODE> 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:<MODE> 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:<MODE> 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:<MODE> 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_<mode>_symglobal_1_1"
++ [(set (reg:<MODE> 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_<mode>_si_symglobal_1_1"
++ [(set (reg:<MODE> 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:<MODE> 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:<MODE> 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:<MODE> 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:<MODE> CC_REG)
++ (compare:<MODE>
++ (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_<mode>_si_rrr"
++ [(set (reg:<MODE> 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_<mode>_si_rrr_1_1"
++ [(set (reg:<MODE> 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_<mode>_si_rrr"
++ [(set (reg:<MODE> 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_<mode>_si_rrr_1_1"
++ [(set (reg:<MODE> 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_<mode>_umul_hisi_rri"
++ [(cond_exec
++ (match_operator 3 "comparison_operator"
++ [(match_operand:CCALL 4 "metag_<mode>_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_<mode>_and_si_rri"
++ [(cond_exec
++ (match_operator 3 "comparison_operator"
++ [(match_operand:CCALL 4 "metag_<mode>_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_<mode>_si_rr"
++ [(set (reg:<MODE> 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_<mode>_si_rr_1_1"
++ [(set (reg:<MODE> 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_<mode>_si_rr_minim"
++ [(set (reg:<MODE> 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_<mode>_si_ri"
++ [(set (reg:<MODE> 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:<MODE> 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_<mode>_si_rri"
++ [(set (reg:<MODE> 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:<MODE> 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_<mode>_compare0"
++ [(set (reg:<MODE> 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:<MODE> 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_<mode>_ior_si_rri"
++ [(cond_exec
++ (match_operator 3 "comparison_operator"
++ [(match_operand:CCALL 4 "metag_<mode>_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_<mode>_si_rrr"
++ [(set (reg:<MODE> 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_<mode>_si_rri"
++ [(set (reg:<MODE> 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_<mode>_si_rrr_1_1"
++ [(set (reg:<MODE> 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_<mode>_si_rr"
++ [(set (reg:<MODE> 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_<mode>_si_ri"
++ [(set (reg:<MODE> 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_<mode>_si_rr_1_1"
++ [(set (reg:<MODE> 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_<mode>_xor_si_rri"
++ [(cond_exec
++ (match_operator 3 "comparison_operator"
++ [(match_operand:CCALL 4 "metag_<mode>_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_<mode>_si_rrr"
++ [(set (reg:<MODE> 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_<mode>_si_rri"
++ [(set (reg:<MODE> 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_<mode>_si_rrr_1_1"
++ [(set (reg:<MODE> 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_<mode>_si_rr"
++ [(set (reg:<MODE> 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_<mode>_si_ri"
++ [(set (reg:<MODE> 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_<mode>_si_rr_1_1"
++ [(set (reg:<MODE> 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_<mode>_ashlsi3_rrr"
++ [(cond_exec
++ (match_operator 3 "comparison_operator"
++ [(match_operand:CCALL 4 "metag_<mode>_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_<mode>_ashlsi3_rrL"
++ [(cond_exec
++ (match_operator 3 "comparison_operator"
++ [(match_operand:CCALL 4 "metag_<mode>_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_<mode>_ashrsi3_rrr"
++ [(cond_exec
++ (match_operator 3 "comparison_operator"
++ [(match_operand:CCALL 4 "metag_<mode>_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_<mode>_ashrsi3_rrL"
++ [(cond_exec
++ (match_operator 3 "comparison_operator"
++ [(match_operand:CCALL 4 "metag_<mode>_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_<mode>_lshrsi3_rrr"
++ [(cond_exec
++ (match_operator 3 "comparison_operator"
++ [(match_operand:CCALL 4 "metag_<mode>_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_<mode>_lshrsi3_rrL"
++ [(cond_exec
++ (match_operator 3 "comparison_operator"
++ [(match_operand:CCALL 4 "metag_<mode>_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_<mode>_si_rrx"
++ [(set (reg:<MODE> 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_<mode>_si_rrx"
++ [(set (reg:<MODE> 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_<mode>_si_rrx"
++ [(set (reg:<MODE> 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_<mode>_si_rrx"
++ [(set (reg:<MODE> 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_<mode>_si_rrx"
++ [(set (reg:<MODE> 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_<mode>_si_rrx"
++ [(set (reg:<MODE> 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_<mode>_si_rr"
++ [(set (reg:<MODE> 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_<mode>_si_rr"
++ [(set (reg:<MODE> 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_<mode>_si_rr_1_1"
++ [(set (reg:<MODE> 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_<mode>_si_rr_1_1"
++ [(set (reg:<MODE> 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_<mode>_si_rr"
++ [(set (reg:<MODE> 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:<MODE> 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:<MODE> CC_REG)
++ (compare:<MODE>
++ (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_<mode>_si_rr"
++ [(set (reg:<MODE> 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:<MODE> 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:<MODE> CC_REG)
++ (compare:<MODE>
++ (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_<mode>_rr"
++ [(set (reg:<MODE> 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_<mode>_ri"
++ [(set (reg:<MODE> 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:<MODE> 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_<mode>_eq0"
++ [(set (reg:<MODE> 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_<mode>_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_<mode>_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 <mode> 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_<mode>_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_<mode>_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_<mode>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<W>\\t%0, [%1++]\\t%@ (*lodz <MODE> HI post_inc OK)";
++
++ return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2];
++ }
++ [(set_attr "type" "load")])
++
++(define_insn "*lodz_<mode>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<W>\\t%0, [%1--]\\t%@ (*lodz <MODE> HI post_dec OK)";
++
++ return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2];
++ }
++ [(set_attr "type" "load")])
++
++(define_insn "*lodz_<mode>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<W>\\t%0, [++%1]\\t%@ (*lodz <MODE> HI pre_inc OK)";
++
++ return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2];
++ }
++ [(set_attr "type" "load")])
++
++(define_insn "*lodz_<mode>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<W>\\t%0, [--%1]\\t%@ (*lodz <MODE> HI pre_dec OK)";
++
++ return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2];
++ }
++ [(set_attr "type" "load")])
++
++(define_insn "*lodz_<mode>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_<mode>" "<O>"))))))]
++ ""
++ {
++ static const char fmt[] = "F\\tGET<W>\\t%0, [%1+%2++]\\t%@ (*load <MODE> HI post_modify_disp OK)";
++
++ return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2];
++ }
++ [(set_attr "type" "load")])
++
++(define_insn "*lodz_<mode>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<W>\\t%0, [%1+%2++]\\t%@ (*lodz <MODE> HI post_modify_reg OK)";
++
++ return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2];
++ }
++ [(set_attr "type" "load")])
++
++(define_insn "*lodz_<mode>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_<mode>" "<O>"))))))]
++ ""
++ "GET<W>\\t%0, [%1++%2]\\t%@ (*lodz <MODE> HI pre_modify_disp OK)"
++ [(set_attr "type" "load")])
++
++(define_insn "*lodz_<mode>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<W>\\t%0, [%1++%2]\\t%@ (*lodz <MODE> 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_<mode>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<W>\\t%0, [%1+%2]\\t%@ (*lodz <MODE> 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_<mode>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_<mode>" "<O>")))))]
++ ""
++ {
++ static const char fmt[] = "F\\tGET<W>\\t%0, [%1+%2]\\t%@ (*lodz <MODE> 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_<mode>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_<mode>" "<O>,<Z>")))))]
++ ""
++ "GET<W>\\t%0, [%1+%2]\\t%@ (*lodz <MODE> SI rmi OK)"
++ [(set_attr "type" "load")])
++
++;; zero_extend loads to SI from EXTSI mode using base++index
++(define_insn "*lodz_<mode>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<W>\\t%3, [%1++%2]\\t%@ (*lodz <MODE> 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_<mode>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_<mode>" "<O>")))))
++ (set (match_operand:SI 0 "metag_regnofrm_op" "=da")
++ (plus:SI (match_dup 1)
++ (match_dup 2)))]
++ "0"
++ {
++ static const char fmt[] = "F\\tGET<W>\\t%3, [%1++%2]\\t%@ (*lodz <MODE> 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_<mode>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<W>\\t%0, [%1++]\\t%@ (*lodz <MODE> SI post_inc OK)";
++
++ return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2];
++ }
++ [(set_attr "type" "load")])
++
++(define_insn "*lodz_<mode>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<W>\\t%0, [%1--]\\t%@ (*lodz <MODE> SI post_dec OK)";
++
++ return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2];
++ }
++ [(set_attr "type" "load")])
++
++(define_insn "*lodz_<mode>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<W>\\t%0, [++%1]\\t%@ (*lodz <MODE> SI pre_inc OK)";
++
++ return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2];
++ }
++ [(set_attr "type" "load")])
++
++(define_insn "*lodz_<mode>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<W>\\t%0, [--%1]\\t%@ (*lodz <MODE> SI pre_dec OK)";
++
++ return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2];
++ }
++ [(set_attr "type" "load")])
++
++(define_insn "*lodz_<mode>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_<mode>" "<O>"))))))]
++ ""
++ "GET<W>\\t%0, [%1+%2++]\\t%@ (*lodz <MODE> SI post_modify_disp OK)"
++ [(set_attr "type" "load")])
++
++(define_insn "*lodz_<mode>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<W>\\t%0, [%1+%2++]\\t%@ (*lodz <MODE> SI post_modify_reg OK)";
++
++ return &fmt[METAG_FPC_REG_P (REGNO (operands[0])) ? 0 : 2];
++ }
++ [(set_attr "type" "load")])
++
++(define_insn "*lodz_<mode>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_<mode>" "<O>"))))))]
++ ""
++ "GET<W>\\t%0, [%1++%2]\\t%@ (*load <MODE> SI pre_modify_disp OK)"
++ [(set_attr "type" "load")])
++
++(define_insn "*lodz_<mode>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<W>\\t%0, [%1++%2]\\t%@ (*loadz <MODE> 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_<mode>si"
++ [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da")
++ (zero_extend:SI (match_operand:EXTSI 1 "memory_operand" "m")))]
++ ""
++ "GET<W>\\t%0, %1\\t%@ (*lodz <MODE> SI rm OK)"
++ [(set_attr "type" "load")])
++
++;; -----------------------------------------------------------------------------
++
++;; Sign extend register to SI mode register moves
++(define_insn "*sign_extend_<mode>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<W>\\t%0, %1\\t\\t%@ (*ext <MODE> SI d0 OK)
++ XSD<W>\\t%0, %1\\t\\t%@ (*ext <MODE> SI ee OK)
++ XSD<W>\\t%0, %1\\t\\t%@ (*ext <MODE> SI ff OK)"
++ [(set_attr "type" "fast,fast,fast")])
++
++(define_insn "*sign_extend_hisi_<mode>"
++ [(set (reg:<MODE> 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_<mode>"
++ [(set (reg:<MODE> 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<code>"
++ [(set (pc)
++ (if_then_else (CCANYCOND (match_dup 1)
++ (const_int 0))
++ (label_ref (match_operand 0 "" ""))
++ (pc)))]
++ ""
++ {
++ if (!gen_metag_compare (<CODE>, operands, 1))
++ FAIL;
++ }
++)
++
++;; patterns to match conditional branch insns
++
++(define_insn "*b<mode>"
++ [(set (pc)
++ (if_then_else (match_operator 1 "comparison_operator"
++ [(match_operand:CCALL 2 "metag_<mode>_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<mode> OK)";
++ }
++ [(set_attr "type" "branch")
++ (set_attr "ccstate" "xcc")])
++
++(define_insn "*b<mode>_reversed"
++ [(set (pc)
++ (if_then_else (match_operator 1 "comparison_operator"
++ [(match_operand:CCALL 2 "metag_<mode>_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<mode> rev OK)";
++ }
++ [(set_attr "type" "branch")
++ (set_attr "ccstate" "xcc")])
++
++;; condition status evaluation
++(define_expand "s<code>"
++ [(set (match_operand:SI 0 "metag_reg_nofloat_op" "")
++ (CCANYCOND:SI (match_dup 1)
++ (const_int 0)))]
++ ""
++ {
++ if (!gen_metag_compare (<CODE>, operands, 1))
++ FAIL;
++ }
++)
++
++;; patterns to match condition status insns
++(define_insn_and_split "*movsi_m<mode>"
++ [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da")
++ (match_operator:SI 1 "comparison_operator"
++ [(match_operand:CCALL 2 "metag_<mode>_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<mode>"
++ [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da")
++ (neg:SI (match_operator:SI 1 "comparison_operator"
++ [(match_operand:CCALL 2 "metag_<mode>_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<mode>"
++ [(set (match_operand:SI 0 "metag_reg_nofloat_op" "=da")
++ (not:SI (match_operator:SI 1 "comparison_operator"
++ [(match_operand:CCALL 2 "metag_<mode>_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_<mode>"
++ [(set (pc)
++ (if_then_else (match_operator 0 "comparison_operator"
++ [(match_operand:CCANY 1 "metag_<mode>_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_<mode>"
++ [(set (pc)
++ (if_then_else (match_operator 0 "comparison_operator"
++ [(match_operand:CCANY 1 "metag_<mode>_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_<mode>_return"
++ [(set (pc)
++ (if_then_else (match_operator 0 "comparison_operator"
++ [(match_operand:CCANY 1 "metag_<mode>_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_<mode> (operands[0], operands[1]));
++ DONE;
++ }
++ [(set_attr "type" "unknown")
++ (set_attr "ccstate" "xcc")])
++
++(define_insn_and_split "*cond_<mode>_return_inverted"
++ [(set (pc)
++ (if_then_else (match_operator 0 "comparison_operator"
++ [(match_operand:CCANY 1 "metag_<mode>_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_<mode> (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, <reg|int> 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_<mode>_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_<mode>" "<Z>"))
++ (match_operand:SI 2 "metag_offset12_<mode>" "<Z>")))
++ (match_operand:<MODE> 3 "metag_register_op" "r"))]
++ "(reload_in_progress || reload_completed)
++ && metag_offset6_<mode> (GEN_INT (INTVAL (operands[1]) + INTVAL (operands[2])), SImode)"
++ "#"
++ "reload_completed"
++ [(set (mem:<MODE> (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_<mode>_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_<mode>" "<Z>"))
++ (match_operand:SI 2 "metag_offset12_<mode>" "<Z>")))
++ (match_operand:<MODE> 3 "metag_register_op" "r"))]
++ "(reload_in_progress || reload_completed)
++ && metag_offset12_<mode> (GEN_INT (INTVAL (operands[1]) + INTVAL (operands[2])), SImode)"
++ "#"
++ "reload_completed"
++ [(set (mem:<MODE> (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_<mode>_frame_elimination_6bit"
++ [(set (match_operand:<MODE> 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_<mode>" "<Z>"))
++ (match_operand:SI 3 "metag_offset12_<mode>" "<Z>"))))]
++ "(reload_in_progress || reload_completed)
++ && metag_offset6_<mode> (GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3])), SImode)"
++ "#"
++ "reload_completed"
++ [(set (match_dup 0)
++ (mem:<MODE> (plus:SI (match_dup 1)
++ (match_dup 4))))]
++ {
++ operands[4] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3]));
++ }
++)
++
++(define_insn_and_split "*load_<mode>_frame_elimination_12bit"
++ [(set (match_operand:<MODE> 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_<mode>" "<Z>"))
++ (match_operand:SI 3 "metag_offset12_<mode>" "<Z>"))))]
++ "(reload_in_progress || reload_completed)
++ && metag_offset12_<mode> (GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3])), SImode)"
++ "#"
++ "reload_completed"
++ [(set (match_dup 0)
++ (mem:<MODE> (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_<mode>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_<mode>" "<Z>"))
++ (match_operand:SI 3 "metag_offset12_<mode>" "<Z>")))))]
++ "(reload_in_progress || reload_completed)
++ && metag_offset6_<mode> (GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3])), SImode)"
++ "#"
++ "reload_completed"
++ [(set (match_dup 0)
++ (zero_extend:SI
++ (mem:<MODE> (plus:SI (match_dup 1)
++ (match_dup 4)))))]
++ {
++ operands[4] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3]));
++ }
++)
++
++(define_insn_and_split "*loadz_<mode>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_<mode>" "<Z>"))
++ (match_operand:SI 3 "metag_offset12_<mode>" "<Z>")))))]
++ "(reload_in_progress || reload_completed)
++ && metag_offset12_<mode> (GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3])), SImode)"
++ "#"
++ "reload_completed"
++ [(set (match_dup 0)
++ (zero_extend:SI
++ (mem:<MODE> (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_<mode>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_<mode>" "<Z>"))
++ (match_operand:SI 3 "metag_offset12_<mode>" "<Z>")))))]
++ "(reload_in_progress || reload_completed)
++ && metag_offset6_<mode> (GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3])), SImode)"
++ "#"
++ "reload_completed"
++ [(set (match_dup 0)
++ (zero_extend:HI
++ (mem:<MODE> (plus:SI (match_dup 1)
++ (match_dup 4)))))]
++ {
++ operands[4] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3]));
++ }
++)
++
++(define_insn_and_split "*loadz_<mode>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_<mode>" "<Z>"))
++ (match_operand:SI 3 "metag_offset12_<mode>" "<Z>")))))]
++ "(reload_in_progress || reload_completed)
++ && metag_offset12_<mode> (GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3])), SImode)"
++ "#"
++ "reload_completed"
++ [(set (match_dup 0)
++ (zero_extend:HI
++ (mem:<MODE> (plus:SI (match_dup 1)
++ (match_dup 4)))))]
++ {
++ operands[4] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3]));
++ }
++)
++
++(define_insn "*sto_<mode>_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:<MODE> 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_<mode>_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:<MODE> 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_<mode>_reload"
++ [(set (match_operand:<MODE> 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_<mode>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_<mode>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
++<http://www.gnu.org/licenses/>. */
++
++
++/* 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
++; <http://www.gnu.org/licenses/>.
++
++
++; 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
++<http://www.gnu.org/licenses/>. */
++
++#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
++;; <http://www.gnu.org/licenses/>.
++
++
++;; ====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:<MODE> 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>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>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_<mode>" "")))
++ (set (match_operand:MODES 2 "memory_operand" "")
++ (match_operand:<MODE> 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>mode))
++ pre = gen_rtx_PRE_INC (SImode, operands[0]);
++ else if (INTVAL (operands[1]) == -GET_MODE_SIZE (<MODE>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>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:<MODE> 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>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_<mode>" "")))
++ (set (match_operand:<MODE> 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>mode))
++ pre = gen_rtx_PRE_INC (SImode, operands[0]);
++ else if (INTVAL (operands[1]) == -GET_MODE_SIZE (<MODE>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>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>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_<mode>" "")))
++ (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>mode))
++ pre = gen_rtx_PRE_INC (SImode, operands[0]);
++ else if (INTVAL (operands[1]) == -GET_MODE_SIZE (<MODE>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>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>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_<mode>" "")))
++ (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>mode))
++ pre = gen_rtx_PRE_INC (SImode, operands[0]);
++ else if (INTVAL (operands[1]) == -GET_MODE_SIZE (<MODE>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>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:<MODE> 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>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>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:<MODE> 1 "metag_register_op" ""))
++ (set (match_operand:SI 2 "metag_register_op" "")
++ (plus:SI (match_dup 2)
++ (match_operand:SI 3 "metag_offset6_<mode>" "")))]
++ "rtx_equal_p (operands[2], XEXP (operands[0], 0))"
++ [(const_int 0)]
++ {
++ rtx post, mem, insn;
++
++ if (INTVAL (operands[3]) == GET_MODE_SIZE (<MODE>mode))
++ post = gen_rtx_POST_INC (SImode, operands[2]);
++ else if (INTVAL (operands[3]) == -GET_MODE_SIZE (<MODE>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>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:<MODE> 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>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:<MODE> 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_<mode>" "")))]
++ "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>mode))
++ post = gen_rtx_POST_INC (SImode, operands[2]);
++ else if (INTVAL (operands[3]) == -GET_MODE_SIZE (<MODE>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>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>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_<mode>" "")))]
++ "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>mode))
++ post = gen_rtx_POST_INC (SImode, operands[2]);
++ else if (INTVAL (operands[3]) == -GET_MODE_SIZE (<MODE>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>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>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_<mode>" "")))]
++ "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>mode))
++ post = gen_rtx_POST_INC (SImode, operands[2]);
++ else if (INTVAL (operands[3]) == -GET_MODE_SIZE (<MODE>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>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:<MODE> 1 "memory_operand" ""))
++ (set (match_operand:<MODE> 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:<MODE>
++ (match_dup 0)
++ (match_operand:SI 2 "metag_int_operand" "")))]
++ "peep2_reg_dead_p (2, operands[0])"
++ [(set (reg:<MODE> CC_REG)
++ (compare:<MODE>
++ (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:<MODE>
++ (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:<MODE> CC_REG)
++ (compare:<MODE>
++ (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:<MODE>
++ (match_dup 1)
++ (const_int 0)))]
++ "REGNO (operands[0]) <= LAST_ADDR_REG"
++ [(parallel
++ [(set (reg:<MODE> CC_REG)
++ (compare:<MODE>
++ (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:<MODE>
++ (match_dup 0)
++ (const_int 0)))]
++ "REGNO (operands[0]) <= LAST_ADDR_REG"
++ [(parallel
++ [(set (reg:<MODE> CC_REG)
++ (compare:<MODE>
++ (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:<MODE>
++ (match_dup 0)
++ (const_int 0)))]
++ ""
++ [(parallel
++ [(set (reg:<MODE> CC_REG)
++ (compare:<MODE>
++ (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:<MODE>
++ (match_dup 0)
++ (const_int 0)))]
++ ""
++ [(parallel
++ [(set (reg:<MODE> CC_REG)
++ (compare:<MODE>
++ (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:<MODE> 1 "metag_regorint_op" ""))
++ (set (match_operand:<MODE> 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:<MODE>
++ (match_dup 0)
++ (const_int 0)))]
++ ""
++ [(parallel
++ [(set (reg:<MODE> CC_REG)
++ (compare:<MODE>
++ (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:<MODE>
++ (match_dup 0)
++ (const_int 0)))]
++ ""
++ [(parallel
++ [(set (reg:<MODE> CC_REG)
++ (compare:<MODE>
++ (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:<MODE>
++ (match_dup 0)
++ (const_int 0)))]
++ ""
++ [(parallel
++ [(set (reg:<MODE> CC_REG)
++ (compare:<MODE>
++ (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_<mode>" "")))
++ (set (match_operand:<MODE> 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>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_<mode>" "")))
++ (set (match_operand:<MODE> 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>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_<mode>" "")))
++ (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>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_<mode>" "")))
++ (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>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_<mode>" "")))
++ (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>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_<mode>" "")))
++ (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>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_<mode>" "")))
++ (set (match_operand:MEMOP 3 "memory_operand" "")
++ (match_operand:<MODE> 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>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_<mode>" "")))
++ (set (match_operand:MEMOP 3 "memory_operand" "")
++ (match_operand:<MODE> 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>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>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>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:<MODE> 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>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>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:<MODE> 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>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>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:<MODE> 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>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
++;; <http://www.gnu.org/licenses/>.
++
++;;- 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:<MODE> 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:<MODE> 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:<MODE>
++ (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:<MODE>
++ (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:<MODE> 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:<MODE> 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
++;; <http://www.gnu.org/licenses/>.
++
++(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
++;; <http://www.gnu.org/licenses/>.
++
++(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
++# <http://www.gnu.org/licenses/>.
++
++# 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
++# <http://www.gnu.org/licenses/>.
++
++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
++;; <http://www.gnu.org/licenses/>.
++
++;;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
++# <http://www.gnu.org/licenses/>.
++
++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
++# <http://www.gnu.org/licenses/>.
++
++# 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
++;; <http://www.gnu.org/licenses/>.
++
++;; 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 "*<expander>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<MNEMONIC>\\t\\t%0,%0,%1\\t%@(*<MNEMONIC> v2si ddi)"
++ [(set_attr "type" "fast")])
++
++(define_insn "*<expander>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<MNEMONIC>\\t\\t%0,%1,%2\\t%@(*<MNEMONIC> v2si ddi)"
++ [(set_attr "type" "fast")])
++
++(define_insn "<expander>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<MNEMONIC>\\t\\t%0,%1,%2\\t%@(*<MNEMONIC> 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 "<expander>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<MNEMONIC>\\t\\t%0,%1,%2\\t%@(*<MNEMONIC> v2si ddd)"
++ [(set_attr "type" "fast")
++ (set_attr "ccstate" "ccx")])
++
++;; OP + flag set
++
++(define_insn "*<expander>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\\t<MNEMONIC>S\\t\\t%0,%0,%1\\t%@(*<MNEMONIC>S v2si ddi)";
++ else
++ return "DL\\t<MNEMONIC>S\\t\\t%t0,%t0,%t1\\t%@(*<MNEMONIC>S v2si ddi)";
++ }
++ [(set_attr "type" "fast")])
++
++(define_insn "*<expander>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\\t<MNEMONIC>S\\t\\t%0,%1,%2\\t%@(*<MNEMONIC>S v2si di)";
++ else
++ return "DL\\t<MNEMONIC>S\\t\\t%t0,%t1,%t2\\t%@(*<MNEMONIC>S v2si di)";
++ }
++ [(set_attr "type" "fast")])
++
++(define_insn "*<expander>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\\t<MNEMONIC>S\\t\\t%0,%1,%2\\t%@(*<MNEMONIC>S v2si ddd)";
++ else
++ return "DL\\t<MNEMONIC>S\\t\\t%t0,%t1,%t2\\t%@(*<MNEMONIC>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
++# <http://www.gnu.org/licenses/>.
++
+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
++# <http://www.gnu.org/licenses/>.
++
+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
++# <http://www.gnu.org/licenses/>.
++
++# 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 <stdio.h>
++
++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 <features.h>
++ #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[] = "<URL:http://gcc.gnu.org/bugs.html>";
++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' \