diff options
Diffstat (limited to 'toolchain')
-rw-r--r-- | toolchain/Makefile | 2 | ||||
-rw-r--r-- | toolchain/gcc/Makefile | 22 | ||||
-rw-r--r-- | toolchain/gcc/Makefile.inc | 8 | ||||
-rw-r--r-- | toolchain/gcc/patches/4.2.4/metag-gcc.patch | 36286 |
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' \ |