diff options
Diffstat (limited to 'recipes/gcc/gcc-4.1.2')
-rw-r--r-- | recipes/gcc/gcc-4.1.2/gcc-config-nios2.patch | 41 | ||||
-rw-r--r-- | recipes/gcc/gcc-4.1.2/gcc-nios2.patch | 11017 | ||||
-rw-r--r-- | recipes/gcc/gcc-4.1.2/nios2-lib-flags.patch | 10 |
3 files changed, 11068 insertions, 0 deletions
diff --git a/recipes/gcc/gcc-4.1.2/gcc-config-nios2.patch b/recipes/gcc/gcc-4.1.2/gcc-config-nios2.patch new file mode 100644 index 0000000000..1cd5a955d3 --- /dev/null +++ b/recipes/gcc/gcc-4.1.2/gcc-config-nios2.patch @@ -0,0 +1,41 @@ +Index: gcc-4.1.2/config.sub +=================================================================== +--- gcc-4.1.2.orig/config.sub 2010-05-27 15:30:45.069455792 +0200 ++++ gcc-4.1.2/config.sub 2010-05-27 15:36:32.868205558 +0200 +@@ -267,6 +267,7 @@ + | mn10200 | mn10300 \ + | mt \ + | msp430 \ ++ | nios2 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ +@@ -349,6 +350,7 @@ + | mmix-* \ + | mt-* \ + | msp430-* \ ++ | nios2-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ +Index: gcc-4.1.2/gcc/config.gcc +=================================================================== +--- gcc-4.1.2.orig/gcc/config.gcc 2010-05-27 15:30:45.039455207 +0200 ++++ gcc-4.1.2/gcc/config.gcc 2010-05-27 15:33:26.249455379 +0200 +@@ -1597,6 +1597,16 @@ + tm_file="dbxelf.h elfos.h svr4.h ${tm_file}" + tmake_file="${tmake_file} mt/t-mt" + ;; ++nios2-*-*) ++ tm_file="elfos.h ${tm_file}" ++ tmake_file="${tmake_file} nios2/t-nios2" ++ case ${target} in ++ nios2-*-linux*) ++ tm_file="${tm_file} linux.h nios2/linux.h" ++ tmake_file="${tmake_file} nios2/t-linux" ++ ;; ++ esac ++ ;; + ns32k-*-netbsdelf*) + echo "GCC does not yet support the ${target} target"; exit 1 + ;; diff --git a/recipes/gcc/gcc-4.1.2/gcc-nios2.patch b/recipes/gcc/gcc-4.1.2/gcc-nios2.patch new file mode 100644 index 0000000000..80a46b7751 --- /dev/null +++ b/recipes/gcc/gcc-4.1.2/gcc-nios2.patch @@ -0,0 +1,11017 @@ +Index: gcc-4.1.2/gcc/config/nios2/crti.asm +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gcc-4.1.2/gcc/config/nios2/crti.asm 2010-06-30 08:50:26.000000000 +0200 +@@ -0,0 +1,97 @@ ++/* NOT ASSIGNED TO FSF. COPYRIGHT ALTERA. */ ++/* ++ Copyright (C) 2003 ++ by Jonah Graham (jgraham@altera.com) ++ ++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, or (at your option) any ++later version. ++ ++In addition to the permissions in the GNU General Public License, the ++Free Software Foundation gives you unlimited permission to link the ++compiled version of this file with other programs, and to distribute ++those programs without any restriction coming from the use of this ++file. (The General Public License restrictions do apply in other ++respects; for example, they cover modification of the file, and ++distribution when not linked into another program.) ++ ++This file 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; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. ++ ++ As a special exception, if you link this library with files ++ compiled with GCC to produce an executable, this does not 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. ++ ++ ++This file just make a stack frame for the contents of the .fini and ++.init sections. Users may put any desired instructions in those ++sections. ++ ++ ++While technically any code can be put in the init and fini sections ++most stuff will not work other than stuff which obeys the call frame ++and ABI. All the call-preserved registers are saved, the call clobbered ++registers should have been saved by the code calling init and fini. ++ ++See crtstuff.c for an example of code that inserts itself in the ++init and fini sections. ++ ++See crt0.s for the code that calls init and fini. ++*/ ++ ++ .file "crti.asm" ++ ++ .section ".init" ++ .align 2 ++ .global _init ++_init: ++ addi sp, sp, -48 ++ stw ra, 44(sp) ++ stw r23, 40(sp) ++ stw r22, 36(sp) ++ stw r21, 32(sp) ++ stw r20, 28(sp) ++ stw r19, 24(sp) ++ stw r18, 20(sp) ++ stw r17, 16(sp) ++ stw r16, 12(sp) ++ stw fp, 8(sp) ++ addi fp, sp, 8 ++ nextpc r22 ++1: movhi r2, %hiadj(_GLOBAL_OFFSET_TABLE_ - 1b) ++ addi r2, r2, %lo(_GLOBAL_OFFSET_TABLE_ - 1b) ++ add r22, r22, r2 ++ ++ ++ .section ".fini" ++ .align 2 ++ .global _fini ++_fini: ++ addi sp, sp, -48 ++ stw ra, 44(sp) ++ stw r23, 40(sp) ++ stw r22, 36(sp) ++ stw r21, 32(sp) ++ stw r20, 28(sp) ++ stw r19, 24(sp) ++ stw r18, 20(sp) ++ stw r17, 16(sp) ++ stw r16, 12(sp) ++ stw fp, 8(sp) ++ addi fp, sp, 8 ++ nextpc r22 ++1: movhi r2, %hiadj(_GLOBAL_OFFSET_TABLE_ - 1b) ++ addi r2, r2, %lo(_GLOBAL_OFFSET_TABLE_ - 1b) ++ add r22, r22, r2 ++ ++ +Index: gcc-4.1.2/gcc/config/nios2/crtn.asm +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gcc-4.1.2/gcc/config/nios2/crtn.asm 2010-06-30 08:50:26.000000000 +0200 +@@ -0,0 +1,71 @@ ++/* NOT ASSIGNED TO FSF. COPYRIGHT ALTERA. */ ++/* ++ Copyright (C) 2003 ++ by Jonah Graham (jgraham@altera.com) ++ ++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, or (at your option) any ++later version. ++ ++In addition to the permissions in the GNU General Public License, the ++Free Software Foundation gives you unlimited permission to link the ++compiled version of this file with other programs, and to distribute ++those programs without any restriction coming from the use of this ++file. (The General Public License restrictions do apply in other ++respects; for example, they cover modification of the file, and ++distribution when not linked into another program.) ++ ++This file 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; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. ++ ++ As a special exception, if you link this library with files ++ compiled with GCC to produce an executable, this does not 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. ++ ++ ++This file just makes sure that the .fini and .init sections do in ++fact return. Users may put any desired instructions in those sections. ++This file is the last thing linked into any executable. ++*/ ++ .file "crtn.asm" ++ ++ ++ ++ .section ".init" ++ ldw ra, 44(sp) ++ ldw r23, 40(sp) ++ ldw r22, 36(sp) ++ ldw r21, 32(sp) ++ ldw r20, 28(sp) ++ ldw r19, 24(sp) ++ ldw r18, 20(sp) ++ ldw r17, 16(sp) ++ ldw r16, 12(sp) ++ ldw fp, 8(sp) ++ addi sp, sp, 48 ++ ret ++ ++ .section ".fini" ++ ldw ra, 44(sp) ++ ldw r23, 40(sp) ++ ldw r22, 36(sp) ++ ldw r21, 32(sp) ++ ldw r20, 28(sp) ++ ldw r19, 24(sp) ++ ldw r18, 20(sp) ++ ldw r17, 16(sp) ++ ldw r16, 12(sp) ++ ldw fp, 8(sp) ++ addi sp, sp, 48 ++ ret ++ +Index: gcc-4.1.2/gcc/config/nios2/lib2-divmod-hi.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gcc-4.1.2/gcc/config/nios2/lib2-divmod-hi.c 2010-06-30 08:50:26.000000000 +0200 +@@ -0,0 +1,133 @@ ++ ++/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is ++ supposedly valid even though this is a "target" file. */ ++#include "auto-host.h" ++#undef gid_t ++#undef pid_t ++#undef rlim_t ++#undef ssize_t ++#undef uid_t ++#undef vfork ++ ++ ++#include "tconfig.h" ++#include "tsystem.h" ++#include "coretypes.h" ++#include "tm.h" ++ ++ ++/* Don't use `fancy_abort' here even if config.h says to use it. */ ++#ifdef abort ++#undef abort ++#endif ++ ++ ++#ifdef HAVE_GAS_HIDDEN ++#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) ++#else ++#define ATTRIBUTE_HIDDEN ++#endif ++ ++#ifndef MIN_UNITS_PER_WORD ++#define MIN_UNITS_PER_WORD UNITS_PER_WORD ++#endif ++ ++#include "libgcc2.h" ++ ++extern HItype __modhi3 (HItype, HItype); ++extern HItype __divhi3 (HItype, HItype); ++extern UHItype __umodhi3 (UHItype, UHItype); ++extern UHItype __udivhi3 (UHItype, UHItype); ++ ++static UHItype udivmodhi4(UHItype, UHItype, word_type); ++ ++static UHItype ++udivmodhi4(UHItype num, UHItype den, word_type modwanted) ++{ ++ UHItype bit = 1; ++ UHItype res = 0; ++ ++ while (den < num && bit && !(den & (1L<<15))) ++ { ++ den <<=1; ++ bit <<=1; ++ } ++ while (bit) ++ { ++ if (num >= den) ++ { ++ num -= den; ++ res |= bit; ++ } ++ bit >>=1; ++ den >>=1; ++ } ++ if (modwanted) return num; ++ return res; ++} ++ ++ ++HItype ++__divhi3 (HItype a, HItype b) ++{ ++ word_type neg = 0; ++ HItype res; ++ ++ if (a < 0) ++ { ++ a = -a; ++ neg = !neg; ++ } ++ ++ if (b < 0) ++ { ++ b = -b; ++ neg = !neg; ++ } ++ ++ res = udivmodhi4 (a, b, 0); ++ ++ if (neg) ++ res = -res; ++ ++ return res; ++} ++ ++ ++HItype ++__modhi3 (HItype a, HItype b) ++{ ++ word_type neg = 0; ++ HItype res; ++ ++ if (a < 0) ++ { ++ a = -a; ++ neg = 1; ++ } ++ ++ if (b < 0) ++ b = -b; ++ ++ res = udivmodhi4 (a, b, 1); ++ ++ if (neg) ++ res = -res; ++ ++ return res; ++} ++ ++ ++UHItype ++__udivhi3 (UHItype a, UHItype b) ++{ ++ return udivmodhi4 (a, b, 0); ++} ++ ++ ++UHItype ++__umodhi3 (UHItype a, UHItype b) ++{ ++ return udivmodhi4 (a, b, 1); ++} ++ +Index: gcc-4.1.2/gcc/config/nios2/lib2-divmod.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gcc-4.1.2/gcc/config/nios2/lib2-divmod.c 2010-06-30 08:50:26.000000000 +0200 +@@ -0,0 +1,136 @@ ++ ++/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is ++ supposedly valid even though this is a "target" file. */ ++#include "auto-host.h" ++#undef gid_t ++#undef pid_t ++#undef rlim_t ++#undef ssize_t ++#undef uid_t ++#undef vfork ++ ++ ++#include "tconfig.h" ++#include "tsystem.h" ++#include "coretypes.h" ++#include "tm.h" ++ ++ ++/* Don't use `fancy_abort' here even if config.h says to use it. */ ++#ifdef abort ++#undef abort ++#endif ++ ++ ++#ifdef HAVE_GAS_HIDDEN ++#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) ++#else ++#define ATTRIBUTE_HIDDEN ++#endif ++ ++#ifndef MIN_UNITS_PER_WORD ++#define MIN_UNITS_PER_WORD UNITS_PER_WORD ++#endif ++ ++#include "libgcc2.h" ++ ++extern SItype __modsi3 (SItype, SItype); ++extern SItype __divsi3 (SItype, SItype); ++extern SItype __umodsi3 (SItype, SItype); ++extern SItype __udivsi3 (SItype, SItype); ++ ++static USItype udivmodsi4(USItype, USItype, word_type); ++ ++/* 16-bit SI divide and modulo as used in NIOS */ ++ ++ ++static USItype ++udivmodsi4(USItype num, USItype den, word_type modwanted) ++{ ++ USItype bit = 1; ++ USItype res = 0; ++ ++ while (den < num && bit && !(den & (1L<<31))) ++ { ++ den <<=1; ++ bit <<=1; ++ } ++ while (bit) ++ { ++ if (num >= den) ++ { ++ num -= den; ++ res |= bit; ++ } ++ bit >>=1; ++ den >>=1; ++ } ++ if (modwanted) return num; ++ return res; ++} ++ ++ ++SItype ++__divsi3 (SItype a, SItype b) ++{ ++ word_type neg = 0; ++ SItype res; ++ ++ if (a < 0) ++ { ++ a = -a; ++ neg = !neg; ++ } ++ ++ if (b < 0) ++ { ++ b = -b; ++ neg = !neg; ++ } ++ ++ res = udivmodsi4 (a, b, 0); ++ ++ if (neg) ++ res = -res; ++ ++ return res; ++} ++ ++ ++SItype ++__modsi3 (SItype a, SItype b) ++{ ++ word_type neg = 0; ++ SItype res; ++ ++ if (a < 0) ++ { ++ a = -a; ++ neg = 1; ++ } ++ ++ if (b < 0) ++ b = -b; ++ ++ res = udivmodsi4 (a, b, 1); ++ ++ if (neg) ++ res = -res; ++ ++ return res; ++} ++ ++ ++SItype ++__udivsi3 (SItype a, SItype b) ++{ ++ return udivmodsi4 (a, b, 0); ++} ++ ++ ++SItype ++__umodsi3 (SItype a, SItype b) ++{ ++ return udivmodsi4 (a, b, 1); ++} ++ +Index: gcc-4.1.2/gcc/config/nios2/lib2-divtable.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gcc-4.1.2/gcc/config/nios2/lib2-divtable.c 2010-06-30 08:50:26.000000000 +0200 +@@ -0,0 +1,52 @@ ++ ++/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is ++ supposedly valid even though this is a "target" file. */ ++#include "auto-host.h" ++#undef gid_t ++#undef pid_t ++#undef rlim_t ++#undef ssize_t ++#undef uid_t ++#undef vfork ++ ++ ++#include "tconfig.h" ++#include "tsystem.h" ++#include "coretypes.h" ++#include "tm.h" ++ ++ ++/* Don't use `fancy_abort' here even if config.h says to use it. */ ++#ifdef abort ++#undef abort ++#endif ++ ++ ++#ifdef HAVE_GAS_HIDDEN ++#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) ++#else ++#define ATTRIBUTE_HIDDEN ++#endif ++ ++#include "libgcc2.h" ++ ++UQItype __divsi3_table[] = ++{ ++ 0, 0/1, 0/2, 0/3, 0/4, 0/5, 0/6, 0/7, 0/8, 0/9, 0/10, 0/11, 0/12, 0/13, 0/14, 0/15, ++ 0, 1/1, 1/2, 1/3, 1/4, 1/5, 1/6, 1/7, 1/8, 1/9, 1/10, 1/11, 1/12, 1/13, 1/14, 1/15, ++ 0, 2/1, 2/2, 2/3, 2/4, 2/5, 2/6, 2/7, 2/8, 2/9, 2/10, 2/11, 2/12, 2/13, 2/14, 2/15, ++ 0, 3/1, 3/2, 3/3, 3/4, 3/5, 3/6, 3/7, 3/8, 3/9, 3/10, 3/11, 3/12, 3/13, 3/14, 3/15, ++ 0, 4/1, 4/2, 4/3, 4/4, 4/5, 4/6, 4/7, 4/8, 4/9, 4/10, 4/11, 4/12, 4/13, 4/14, 4/15, ++ 0, 5/1, 5/2, 5/3, 5/4, 5/5, 5/6, 5/7, 5/8, 5/9, 5/10, 5/11, 5/12, 5/13, 5/14, 5/15, ++ 0, 6/1, 6/2, 6/3, 6/4, 6/5, 6/6, 6/7, 6/8, 6/9, 6/10, 6/11, 6/12, 6/13, 6/14, 6/15, ++ 0, 7/1, 7/2, 7/3, 7/4, 7/5, 7/6, 7/7, 7/8, 7/9, 7/10, 7/11, 7/12, 7/13, 7/14, 7/15, ++ 0, 8/1, 8/2, 8/3, 8/4, 8/5, 8/6, 8/7, 8/8, 8/9, 8/10, 8/11, 8/12, 8/13, 8/14, 8/15, ++ 0, 9/1, 9/2, 9/3, 9/4, 9/5, 9/6, 9/7, 9/8, 9/9, 9/10, 9/11, 9/12, 9/13, 9/14, 9/15, ++ 0, 10/1, 10/2, 10/3, 10/4, 10/5, 10/6, 10/7, 10/8, 10/9, 10/10, 10/11, 10/12, 10/13, 10/14, 10/15, ++ 0, 11/1, 11/2, 11/3, 11/4, 11/5, 11/6, 11/7, 11/8, 11/9, 11/10, 11/11, 11/12, 11/13, 11/14, 11/15, ++ 0, 12/1, 12/2, 12/3, 12/4, 12/5, 12/6, 12/7, 12/8, 12/9, 12/10, 12/11, 12/12, 12/13, 12/14, 12/15, ++ 0, 13/1, 13/2, 13/3, 13/4, 13/5, 13/6, 13/7, 13/8, 13/9, 13/10, 13/11, 13/12, 13/13, 13/14, 13/15, ++ 0, 14/1, 14/2, 14/3, 14/4, 14/5, 14/6, 14/7, 14/8, 14/9, 14/10, 14/11, 14/12, 14/13, 14/14, 14/15, ++ 0, 15/1, 15/2, 15/3, 15/4, 15/5, 15/6, 15/7, 15/8, 15/9, 15/10, 15/11, 15/12, 15/13, 15/14, 15/15, ++}; ++ +Index: gcc-4.1.2/gcc/config/nios2/lib2-mul.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gcc-4.1.2/gcc/config/nios2/lib2-mul.c 2010-06-30 08:50:26.000000000 +0200 +@@ -0,0 +1,113 @@ ++/* while we are debugging (ie compile outside of gcc build) ++ disable gcc specific headers */ ++#ifndef DEBUG_MULSI3 ++ ++ ++/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is ++ supposedly valid even though this is a "target" file. */ ++#include "auto-host.h" ++#undef gid_t ++#undef pid_t ++#undef rlim_t ++#undef ssize_t ++#undef uid_t ++#undef vfork ++ ++ ++#include "tconfig.h" ++#include "tsystem.h" ++#include "coretypes.h" ++#include "tm.h" ++ ++ ++/* Don't use `fancy_abort' here even if config.h says to use it. */ ++#ifdef abort ++#undef abort ++#endif ++ ++ ++#ifdef HAVE_GAS_HIDDEN ++#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) ++#else ++#define ATTRIBUTE_HIDDEN ++#endif ++ ++#ifndef MIN_UNITS_PER_WORD ++#define MIN_UNITS_PER_WORD UNITS_PER_WORD ++#endif ++ ++#include "libgcc2.h" ++ ++#else ++#define SItype int ++#define USItype unsigned int ++#endif ++ ++ ++extern SItype __mulsi3 (SItype, SItype); ++ ++SItype ++__mulsi3 (SItype a, SItype b) ++{ ++ SItype res = 0; ++ USItype cnt = a; ++ ++ while (cnt) ++ { ++ if (cnt & 1) ++ { ++ res += b; ++ } ++ b <<= 1; ++ cnt >>= 1; ++ } ++ ++ return res; ++} ++/* ++TODO: Choose best alternative implementation. ++ ++SItype ++__divsi3 (SItype a, SItype b) ++{ ++ SItype res = 0; ++ USItype cnt = 0; ++ ++ while (cnt < 32) ++ { ++ if (a & (1L << cnt)) ++ { ++ res += b; ++ } ++ b <<= 1; ++ cnt++; ++ } ++ ++ return res; ++} ++*/ ++ ++ ++#ifdef DEBUG_MULSI3 ++ ++int ++main () ++{ ++ int i, j; ++ int error = 0; ++ ++ for (i = -1000; i < 1000; i++) ++ for (j = -1000; j < 1000; j++) ++ { ++ int expect = i * j; ++ int actual = A__divsi3 (i, j); ++ if (expect != actual) ++ { ++ printf ("error: %d * %d = %d not %d\n", i, j, expect, actual); ++ error = 1; ++ } ++ } ++ ++ return error; ++} ++#endif +Index: gcc-4.1.2/gcc/config/nios2/linux-atomic.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gcc-4.1.2/gcc/config/nios2/linux-atomic.c 2010-06-30 08:50:26.000000000 +0200 +@@ -0,0 +1,302 @@ ++/* Linux-specific atomic operations for Nios II Linux. ++ Copyright (C) 2008 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 2, or (at your option) any later ++version. ++ ++In addition to the permissions in the GNU General Public License, the ++Free Software Foundation gives you unlimited permission to link the ++compiled version of this file into combinations with other programs, ++and to distribute those combinations without any restriction coming ++from the use of this file. (The General Public License restrictions ++do apply in other respects; for example, they cover modification of ++the file, and distribution when not linked into a combine ++executable.) ++ ++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 COPYING. If not, write to the Free ++Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA ++02110-1301, USA. */ ++ ++#include <asm/unistd.h> ++#define EFAULT 14 ++#define EBUSY 16 ++#define ENOSYS 38 ++ ++/* We implement byte, short and int versions of each atomic operation ++ using the kernel helper defined below. There is no support for ++ 64-bit operations yet. */ ++ ++/* Crash a userspace program with SIGSEV. */ ++#define ABORT_INSTRUCTION asm ("stw zero, 0(zero)") ++ ++/* Kernel helper for compare-and-exchange a 32-bit value. */ ++static inline long ++__kernel_cmpxchg (int oldval, int newval, int *mem) ++{ ++ register int r2 asm ("r2") = __NR_nios2cmpxchg; ++ register unsigned long lws_mem asm("r4") = (unsigned long) (mem); ++ register int lws_old asm("r5") = oldval; ++ register int lws_new asm("r6") = newval; ++ register int err asm ("r7"); ++ asm volatile ("trap" ++ : "=r" (r2), "=r" (err) ++ : "r" (r2), "r" (lws_mem), "r" (lws_old), "r" (lws_new) ++ : "r1", "r3", "r8", "r9", "r10", "r11", "r12", "r13", "r14", ++ "r15", "r29", "memory"); ++ ++ /* If the kernel LWS call succeeded (err == 0), r2 contains the old value ++ from memory. If this value is equal to OLDVAL, the new value was written ++ to memory. If not, return EBUSY. */ ++ if (__builtin_expect (err, 0)) ++ { ++ if(__builtin_expect (r2 == EFAULT || r2 == ENOSYS,0)) ++ ABORT_INSTRUCTION; ++ } ++ else ++ { ++ if (__builtin_expect (r2 != oldval, 0)) ++ r2 = EBUSY; ++ else ++ r2 = 0; ++ } ++ ++ return r2; ++} ++ ++#define HIDDEN __attribute__ ((visibility ("hidden"))) ++ ++/* Big endian masks */ ++#define INVERT_MASK_1 24 ++#define INVERT_MASK_2 16 ++ ++#define MASK_1 0xffu ++#define MASK_2 0xffffu ++ ++#define FETCH_AND_OP_WORD(OP, PFX_OP, INF_OP) \ ++ int HIDDEN \ ++ __sync_fetch_and_##OP##_4 (int *ptr, int val) \ ++ { \ ++ int failure, tmp; \ ++ \ ++ do { \ ++ tmp = *ptr; \ ++ failure = __kernel_cmpxchg (tmp, PFX_OP tmp INF_OP val, ptr); \ ++ } while (failure != 0); \ ++ \ ++ return tmp; \ ++ } ++ ++FETCH_AND_OP_WORD (add, , +) ++FETCH_AND_OP_WORD (sub, , -) ++FETCH_AND_OP_WORD (or, , |) ++FETCH_AND_OP_WORD (and, , &) ++FETCH_AND_OP_WORD (xor, , ^) ++FETCH_AND_OP_WORD (nand, ~, &) ++ ++#define NAME_oldval(OP, WIDTH) __sync_fetch_and_##OP##_##WIDTH ++#define NAME_newval(OP, WIDTH) __sync_##OP##_and_fetch_##WIDTH ++ ++/* Implement both __sync_<op>_and_fetch and __sync_fetch_and_<op> for ++ subword-sized quantities. */ ++ ++#define SUBWORD_SYNC_OP(OP, PFX_OP, INF_OP, TYPE, WIDTH, RETURN) \ ++ TYPE HIDDEN \ ++ NAME##_##RETURN (OP, WIDTH) (TYPE *ptr, TYPE val) \ ++ { \ ++ int *wordptr = (int *) ((unsigned long) ptr & ~3); \ ++ unsigned int mask, shift, oldval, newval; \ ++ int failure; \ ++ \ ++ shift = (((unsigned long) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \ ++ mask = MASK_##WIDTH << shift; \ ++ \ ++ do { \ ++ oldval = *wordptr; \ ++ newval = ((PFX_OP ((oldval & mask) >> shift) \ ++ INF_OP (unsigned int) val) << shift) & mask; \ ++ newval |= oldval & ~mask; \ ++ failure = __kernel_cmpxchg (oldval, newval, wordptr); \ ++ } while (failure != 0); \ ++ \ ++ return (RETURN & mask) >> shift; \ ++ } ++ ++SUBWORD_SYNC_OP (add, , +, short, 2, oldval) ++SUBWORD_SYNC_OP (sub, , -, short, 2, oldval) ++SUBWORD_SYNC_OP (or, , |, short, 2, oldval) ++SUBWORD_SYNC_OP (and, , &, short, 2, oldval) ++SUBWORD_SYNC_OP (xor, , ^, short, 2, oldval) ++SUBWORD_SYNC_OP (nand, ~, &, short, 2, oldval) ++ ++SUBWORD_SYNC_OP (add, , +, char, 1, oldval) ++SUBWORD_SYNC_OP (sub, , -, char, 1, oldval) ++SUBWORD_SYNC_OP (or, , |, char, 1, oldval) ++SUBWORD_SYNC_OP (and, , &, char, 1, oldval) ++SUBWORD_SYNC_OP (xor, , ^, char, 1, oldval) ++SUBWORD_SYNC_OP (nand, ~, &, char, 1, oldval) ++ ++#define OP_AND_FETCH_WORD(OP, PFX_OP, INF_OP) \ ++ int HIDDEN \ ++ __sync_##OP##_and_fetch_4 (int *ptr, int val) \ ++ { \ ++ int tmp, failure; \ ++ \ ++ do { \ ++ tmp = *ptr; \ ++ failure = __kernel_cmpxchg (tmp, PFX_OP tmp INF_OP val, ptr); \ ++ } while (failure != 0); \ ++ \ ++ return PFX_OP tmp INF_OP val; \ ++ } ++ ++OP_AND_FETCH_WORD (add, , +) ++OP_AND_FETCH_WORD (sub, , -) ++OP_AND_FETCH_WORD (or, , |) ++OP_AND_FETCH_WORD (and, , &) ++OP_AND_FETCH_WORD (xor, , ^) ++OP_AND_FETCH_WORD (nand, ~, &) ++ ++SUBWORD_SYNC_OP (add, , +, short, 2, newval) ++SUBWORD_SYNC_OP (sub, , -, short, 2, newval) ++SUBWORD_SYNC_OP (or, , |, short, 2, newval) ++SUBWORD_SYNC_OP (and, , &, short, 2, newval) ++SUBWORD_SYNC_OP (xor, , ^, short, 2, newval) ++SUBWORD_SYNC_OP (nand, ~, &, short, 2, newval) ++ ++SUBWORD_SYNC_OP (add, , +, char, 1, newval) ++SUBWORD_SYNC_OP (sub, , -, char, 1, newval) ++SUBWORD_SYNC_OP (or, , |, char, 1, newval) ++SUBWORD_SYNC_OP (and, , &, char, 1, newval) ++SUBWORD_SYNC_OP (xor, , ^, char, 1, newval) ++SUBWORD_SYNC_OP (nand, ~, &, char, 1, newval) ++ ++int HIDDEN ++__sync_val_compare_and_swap_4 (int *ptr, int oldval, int newval) ++{ ++ int actual_oldval, fail; ++ ++ while (1) ++ { ++ actual_oldval = *ptr; ++ ++ if (oldval != actual_oldval) ++ return actual_oldval; ++ ++ fail = __kernel_cmpxchg (actual_oldval, newval, ptr); ++ ++ if (!fail) ++ return oldval; ++ } ++} ++ ++#define SUBWORD_VAL_CAS(TYPE, WIDTH) \ ++ TYPE HIDDEN \ ++ __sync_val_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval, \ ++ TYPE newval) \ ++ { \ ++ int *wordptr = (int *)((unsigned long) ptr & ~3), fail; \ ++ unsigned int mask, shift, actual_oldval, actual_newval; \ ++ \ ++ shift = (((unsigned long) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \ ++ mask = MASK_##WIDTH << shift; \ ++ \ ++ while (1) \ ++ { \ ++ actual_oldval = *wordptr; \ ++ \ ++ if (((actual_oldval & mask) >> shift) != (unsigned int) oldval) \ ++ return (actual_oldval & mask) >> shift; \ ++ \ ++ actual_newval = (actual_oldval & ~mask) \ ++ | (((unsigned int) newval << shift) & mask); \ ++ \ ++ fail = __kernel_cmpxchg (actual_oldval, actual_newval, \ ++ wordptr); \ ++ \ ++ if (!fail) \ ++ return oldval; \ ++ } \ ++ } ++ ++SUBWORD_VAL_CAS (short, 2) ++SUBWORD_VAL_CAS (char, 1) ++ ++typedef unsigned char bool; ++ ++bool HIDDEN ++__sync_bool_compare_and_swap_4 (int *ptr, int oldval, int newval) ++{ ++ int failure = __kernel_cmpxchg (oldval, newval, ptr); ++ return (failure == 0); ++} ++ ++#define SUBWORD_BOOL_CAS(TYPE, WIDTH) \ ++ bool HIDDEN \ ++ __sync_bool_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval, \ ++ TYPE newval) \ ++ { \ ++ TYPE actual_oldval \ ++ = __sync_val_compare_and_swap_##WIDTH (ptr, oldval, newval); \ ++ return (oldval == actual_oldval); \ ++ } ++ ++SUBWORD_BOOL_CAS (short, 2) ++SUBWORD_BOOL_CAS (char, 1) ++ ++int HIDDEN ++__sync_lock_test_and_set_4 (int *ptr, int val) ++{ ++ int failure, oldval; ++ ++ do { ++ oldval = *ptr; ++ failure = __kernel_cmpxchg (oldval, val, ptr); ++ } while (failure != 0); ++ ++ return oldval; ++} ++ ++#define SUBWORD_TEST_AND_SET(TYPE, WIDTH) \ ++ TYPE HIDDEN \ ++ __sync_lock_test_and_set_##WIDTH (TYPE *ptr, TYPE val) \ ++ { \ ++ int failure; \ ++ unsigned int oldval, newval, shift, mask; \ ++ int *wordptr = (int *) ((unsigned long) ptr & ~3); \ ++ \ ++ shift = (((unsigned long) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \ ++ mask = MASK_##WIDTH << shift; \ ++ \ ++ do { \ ++ oldval = *wordptr; \ ++ newval = (oldval & ~mask) \ ++ | (((unsigned int) val << shift) & mask); \ ++ failure = __kernel_cmpxchg (oldval, newval, wordptr); \ ++ } while (failure != 0); \ ++ \ ++ return (oldval & mask) >> shift; \ ++ } ++ ++SUBWORD_TEST_AND_SET (short, 2) ++SUBWORD_TEST_AND_SET (char, 1) ++ ++#define SYNC_LOCK_RELEASE(TYPE, WIDTH) \ ++ void HIDDEN \ ++ __sync_lock_release_##WIDTH (TYPE *ptr) \ ++ { \ ++ *ptr = 0; \ ++ } ++ ++SYNC_LOCK_RELEASE (int, 4) ++SYNC_LOCK_RELEASE (short, 2) ++SYNC_LOCK_RELEASE (char, 1) +Index: gcc-4.1.2/gcc/config/nios2/linux-unwind.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gcc-4.1.2/gcc/config/nios2/linux-unwind.h 2010-06-30 08:50:26.000000000 +0200 +@@ -0,0 +1,166 @@ ++/* DWARF2 EH unwinding support for NIOS2 Linux. ++ Copyright (C) 2008 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 2, or (at your option) ++any later version. ++ ++In addition to the permissions in the GNU General Public License, the ++Free Software Foundation gives you unlimited permission to link the ++compiled version of this file with other programs, and to distribute ++those programs without any restriction coming from the use of this ++file. (The General Public License restrictions do apply in other ++respects; for example, they cover modification of the file, and ++distribution when not linked into another program.) ++ ++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 COPYING. If not, write to ++the Free Software Foundation, 51 Franklin Street, Fifth Floor, ++Boston, MA 02110-1301, USA. */ ++ ++#ifndef inhibit_libc ++ ++/* Do code reading to identify a signal frame, and set the frame ++ state data appropriately. See unwind-dw2.c for the structs. */ ++ ++#include <signal.h> ++#include <asm/unistd.h> ++ ++/* Unfortunately the kernel headers define the wrong shape of the ++ register file, so we define our own version here. This problem has ++ been reported. */ ++ ++struct nios2_mcontext ++{ ++ int version; /* 2 */ ++ unsigned seq_regs[23]; /* regs 1..23 */ ++ unsigned ra; /* Return address, r31 */ ++ unsigned fp; /* Frame pointer, r28 */ ++ unsigned gp; /* Global pointer, r26 */ ++ unsigned pad1; ++ unsigned ea; /* Exception return address (pc) */ ++ unsigned sp; /* Stack pointer, r27 */ ++ unsigned pad2; ++ /* Note r24, r25, r29, r30 are reserved registers */ ++}; ++ ++/* The kernel's definition of this structure also doesn't match ++ reality. Again, this has been reported. */ ++ ++struct nios2_ucontext { ++ unsigned long uc_flags; ++ unsigned pad1; ++ void *uc_link; ++ stack_t uc_stack; ++ struct siginfo info; ++ struct nios2_mcontext uc_mcontext; ++}; ++ ++#define MD_FALLBACK_FRAME_STATE_FOR nios2_fallback_frame_state ++ ++static _Unwind_Reason_Code ++nios2_fallback_frame_state (struct _Unwind_Context *context, ++ _Unwind_FrameState *fs) ++{ ++ u_int32_t *pc = (u_int32_t *) context->ra; ++ _Unwind_Ptr new_cfa; ++ int i; ++ ++ /* movi r2,(sigreturn/rt_sigreturn) ++ trap */ ++ if (pc[1] != 0x003b683a) /* trap */ ++ return _URC_END_OF_STACK; ++ ++#define NIOS2_REG(NUM,NAME) \ ++ (fs->regs.reg[NUM].how = REG_SAVED_OFFSET, \ ++ fs->regs.reg[NUM].loc.offset = (_Unwind_Ptr)®s->NAME - new_cfa) ++ ++ if (pc[0] == (0x00800004 | (__NR_sigreturn << 6))) ++ { ++ struct sigframe { ++ u_int32_t trampoline[2]; ++ u_int32_t pad1; ++ u_int32_t pad2; ++ struct sigcontext ctx; ++ } *rt_ = context->ra; ++ struct pt_regs *regs = &rt_->ctx.regs; ++ ++ /* The CFA is the user's incoming stack pointer value. */ ++ new_cfa = (_Unwind_Ptr)regs->sp; ++ fs->cfa_how = CFA_REG_OFFSET; ++ fs->cfa_reg = STACK_POINTER_REGNUM; ++ fs->cfa_offset = new_cfa - (_Unwind_Ptr) context->cfa; ++ ++ /* Regs 1..15 */ ++ NIOS2_REG (1, r1); ++ NIOS2_REG (2, r2); ++ NIOS2_REG (3, r3); ++ NIOS2_REG (4, r4); ++ NIOS2_REG (5, r5); ++ NIOS2_REG (6, r6); ++ NIOS2_REG (7, r7); ++ NIOS2_REG (8, r8); ++ NIOS2_REG (9, r9); ++ NIOS2_REG (10, r10); ++ NIOS2_REG (11, r11); ++ NIOS2_REG (12, r12); ++ NIOS2_REG (13, r13); ++ NIOS2_REG (14, r14); ++ NIOS2_REG (15, r15); ++ ++ /* Regs 16..23 are not saved here. They are callee saved or ++ special. */ ++ ++ /* The random registers. */ ++ NIOS2_REG (RA_REGNO, ra); ++ NIOS2_REG (FP_REGNO, fp); ++ NIOS2_REG (GP_REGNO, gp); ++ NIOS2_REG (SIGNAL_UNWIND_RETURN_COLUMN, ea); ++ ++ fs->retaddr_column = SIGNAL_UNWIND_RETURN_COLUMN; ++ ++ return _URC_NO_REASON; ++ } ++ else if (pc[0] == (0x00800004 | (__NR_rt_sigreturn << 6))) ++ { ++ struct sigframe { ++ u_int32_t trampoline[2]; ++ struct nios2_ucontext sigctx; ++ } *rt_ = context->ra; ++ struct nios2_mcontext *regs = &rt_->sigctx.uc_mcontext; ++ ++ if (regs->version != 2) ++ return _URC_END_OF_STACK; ++ ++ /* The CFA is the user's incoming stack pointer value. */ ++ new_cfa = (_Unwind_Ptr)regs->sp; ++ fs->cfa_how = CFA_REG_OFFSET; ++ fs->cfa_reg = STACK_POINTER_REGNUM; ++ fs->cfa_offset = new_cfa - (_Unwind_Ptr) context->cfa; ++ ++ /* The sequential registers. */ ++ for (i = 1; i != 24; i++) ++ NIOS2_REG (i, seq_regs[i-1]); ++ ++ /* The random registers. */ ++ NIOS2_REG (RA_REGNO, ra); ++ NIOS2_REG (FP_REGNO, fp); ++ NIOS2_REG (GP_REGNO, gp); ++ NIOS2_REG (SIGNAL_UNWIND_RETURN_COLUMN, ea); ++ ++ fs->retaddr_column = SIGNAL_UNWIND_RETURN_COLUMN; ++ ++ return _URC_NO_REASON; ++ } ++#undef NIOS2_REG ++ return _URC_END_OF_STACK; ++} ++#endif +Index: gcc-4.1.2/gcc/config/nios2/linux.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gcc-4.1.2/gcc/config/nios2/linux.h 2010-06-30 08:50:26.000000000 +0200 +@@ -0,0 +1,58 @@ ++/* Definitions for Nios II running Linux-based GNU systems with ++ ELF format. ++ Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2008 ++ 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 2, 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 COPYING. If not, write to ++the Free Software Foundation, 51 Franklin Street, Fifth Floor, ++Boston, MA 02110-1301, USA. */ ++ ++#undef LIB_SPEC ++#define LIB_SPEC "-lc \ ++ %{pthread:-lpthread}" ++ ++#undef STARTFILE_SPEC ++#define STARTFILE_SPEC \ ++"%{!shared: crt1.o%s} \ ++ crti.o%s %{static:crtbeginT.o%s;shared|pie:crtbeginS.o%s;:crtbegin.o%s}" ++ ++#undef ENDFILE_SPEC ++#define ENDFILE_SPEC \ ++"%{shared|pie:crtendS.o%s;:crtend.o%s} crtn.o%s" ++ ++#define TARGET_OS_CPP_BUILTINS() \ ++ do \ ++ { \ ++ LINUX_TARGET_OS_CPP_BUILTINS(); \ ++ if (flag_pic) \ ++ { \ ++ builtin_define ("__PIC__"); \ ++ builtin_define ("__pic__"); \ ++ } \ ++ } \ ++ while (0) ++ ++#undef SYSROOT_SUFFIX_SPEC ++#define SYSROOT_SUFFIX_SPEC \ ++ "%{EB:/EB}" ++ ++#undef LINK_SPEC ++#define LINK_SPEC LINK_SPEC_ENDIAN \ ++ " %{shared:-shared} \ ++ %{static:-Bstatic} \ ++ %{rdynamic:-export-dynamic}" ++ ++#define MD_UNWIND_SUPPORT "config/nios2/linux-unwind.h" +Index: gcc-4.1.2/gcc/config/nios2/nios2-protos.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gcc-4.1.2/gcc/config/nios2/nios2-protos.h 2010-06-30 08:50:26.000000000 +0200 +@@ -0,0 +1,92 @@ ++/* NOT ASSIGNED TO FSF. COPYRIGHT ALTERA. */ ++/* Subroutines for assembler code output for Altera NIOS 2G NIOS2 version. ++ Copyright (C) 2003 Altera ++ Contributed by Jonah Graham (jgraham@altera.com). ++ ++This file is part of GNU CC. ++ ++GNU CC 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, or (at your option) ++any later version. ++ ++GNU CC 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 GNU CC; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++extern void dump_frame_size (FILE *); ++extern HOST_WIDE_INT compute_frame_size (void); ++extern int nios2_initial_elimination_offset (int, int); ++extern void override_options (void); ++extern void optimization_options (int, int); ++extern int nios2_can_use_return_insn (void); ++extern void expand_prologue (void); ++extern void expand_epilogue (bool); ++extern void function_profiler (FILE *, int); ++extern enum reg_class reg_class_from_constraint (char, const char *); ++extern void nios2_register_target_pragmas (void); ++ ++#ifdef RTX_CODE ++extern int nios2_legitimate_address (rtx, enum machine_mode, int); ++extern int nios2_legitimate_constant (rtx); ++extern void nios2_print_operand (FILE *, rtx, int); ++extern void nios2_print_operand_address (FILE *, rtx); ++extern rtx nios2_legitimize_address (rtx, rtx, enum machine_mode); ++extern bool nios2_legitimate_pic_operand_p (rtx); ++ ++extern int nios2_emit_move_sequence (rtx *, enum machine_mode); ++extern int nios2_emit_expensive_div (rtx *, enum machine_mode); ++extern void nios2_adjust_call_address (rtx *); ++ ++extern rtx nios2_get_return_address (int); ++extern void nios2_set_return_address (rtx, rtx); ++ ++extern void gen_int_relational (enum rtx_code, rtx, rtx, rtx, rtx); ++extern void gen_conditional_move (rtx *, enum machine_mode); ++extern const char *asm_output_opcode (FILE *, const char *); ++ ++/* predicates */ ++extern int call_operand (rtx, enum machine_mode); ++extern int arith_operand (rtx, enum machine_mode); ++extern int uns_arith_operand (rtx, enum machine_mode); ++extern int logical_operand (rtx, enum machine_mode); ++extern int shift_operand (rtx, enum machine_mode); ++extern int reg_or_0_operand (rtx, enum machine_mode); ++extern int equality_op (rtx, enum machine_mode); ++extern int custom_insn_opcode (rtx, enum machine_mode); ++extern int rdwrctl_operand (rtx, enum machine_mode); ++ ++/* custom fpu instruction output */ ++extern const char *nios2_output_fpu_insn_cmps (rtx, enum rtx_code); ++extern const char *nios2_output_fpu_insn_cmpd (rtx, enum rtx_code); ++ ++# ifdef HAVE_MACHINE_MODES ++# if defined TREE_CODE ++extern rtx function_arg (const CUMULATIVE_ARGS *, enum machine_mode, tree, int); ++extern bool nios2_must_pass_in_stack (enum machine_mode, tree); ++extern int function_arg_partial_nregs (const CUMULATIVE_ARGS *, ++ enum machine_mode, tree, int); ++extern void function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode, tree, ++ int); ++extern int nios2_function_arg_padding (enum machine_mode, tree); ++extern int nios2_function_arg_padding_upward (enum machine_mode, tree); ++extern int nios2_block_reg_padding (enum machine_mode, tree, int); ++extern int nios2_block_reg_padding_upward (enum machine_mode, tree, int); ++extern void init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree, int); ++extern void nios2_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode, ++ tree, int *, int); ++ ++# endif /* TREE_CODE */ ++# endif /* HAVE_MACHINE_MODES */ ++#endif ++ ++#ifdef TREE_CODE ++extern int nios2_return_in_memory (tree); ++ ++#endif /* TREE_CODE */ +Index: gcc-4.1.2/gcc/config/nios2/nios2.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gcc-4.1.2/gcc/config/nios2/nios2.c 2010-06-30 08:52:12.000000000 +0200 +@@ -0,0 +1,4937 @@ ++/* NOT ASSIGNED TO FSF. COPYRIGHT ALTERA. */ ++/* Subroutines for assembler code output for Altera NIOS 2G NIOS2 version. ++ Copyright (C) 2005 Altera ++ Contributed by Jonah Graham (jgraham@altera.com), Will Reece (wreece@altera.com), ++ and Jeff DaSilva (jdasilva@altera.com). ++ ++This file is part of GNU CC. ++ ++GNU CC 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, or (at your option) ++any later version. ++ ++GNU CC 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 GNU CC; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++ ++#include <stdio.h> ++#include "config.h" ++#include "system.h" ++#include "coretypes.h" ++#include "tm.h" ++#include "rtl.h" ++#include "tree.h" ++#include "tm_p.h" ++#include "regs.h" ++#include "hard-reg-set.h" ++#include "real.h" ++#include "insn-config.h" ++#include "conditions.h" ++#include "output.h" ++#include "insn-attr.h" ++#include "flags.h" ++#include "recog.h" ++#include "expr.h" ++#include "toplev.h" ++#include "basic-block.h" ++#include "function.h" ++#include "integrate.h" ++#include "ggc.h" ++#include "reload.h" ++#include "debug.h" ++#include "optabs.h" ++#include "target.h" ++#include "target-def.h" ++#include "c-pragma.h" /* For c_register_pragma. */ ++#include "cpplib.h" /* For CPP_NUMBER. */ ++#include "c-tree.h" /* For builtin_function. */ ++ ++/* Local prototypes. */ ++static bool nios2_rtx_costs (rtx, int, int, int *); ++ ++static void nios2_asm_function_prologue (FILE *, HOST_WIDE_INT); ++static int nios2_issue_rate (void); ++static struct machine_function *nios2_init_machine_status (void); ++static bool nios2_in_small_data_p (tree); ++static void save_reg (int, HOST_WIDE_INT); ++static void restore_reg (int, HOST_WIDE_INT); ++static unsigned int nios2_section_type_flags (tree, const char *, int); ++ ++/* 0 --> no #pragma seen ++ 1 --> in scope of #pragma reverse_bitfields ++ -1 --> in scope of #pragma no_reverse_bitfields. */ ++static int nios2_pragma_reverse_bitfields_flag = 0; ++static void nios2_pragma_reverse_bitfields (struct cpp_reader *); ++static void nios2_pragma_no_reverse_bitfields (struct cpp_reader *); ++static tree nios2_handle_struct_attribute (tree *, tree, tree, int, bool *); ++static void nios2_insert_attributes (tree, tree *); ++static void nios2_load_pic_register (void); ++static bool nios2_cannot_force_const_mem (rtx); ++bool nios2_legitimate_pic_operand_p (rtx x); ++static rtx nios2_legitimize_pic_address (rtx orig, enum machine_mode mode, ++ rtx reg); ++rtx nios2_legitimize_address (rtx x, rtx orig_x, enum machine_mode mode); ++static void nios2_init_builtins (void); ++static rtx nios2_expand_builtin (tree, rtx, rtx, enum machine_mode, int); ++static bool nios2_function_ok_for_sibcall (tree, tree); ++static int nios2_arg_partial_bytes (CUMULATIVE_ARGS *cum, ++ enum machine_mode mode, tree type, ++ bool named ATTRIBUTE_UNUSED); ++static bool nios2_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ tree type, bool named ATTRIBUTE_UNUSED); ++static void nios2_encode_section_info (tree, rtx, int); ++int nios2_function_arg_padding_upward (enum machine_mode mode, tree type); ++int nios2_block_reg_padding_upward (enum machine_mode mode, tree type, ++ int first ATTRIBUTE_UNUSED); ++static void nios2_output_dwarf_dtprel (FILE *fuke, int size, rtx x); ++ ++/* Initialize the GCC target structure. */ ++#undef TARGET_ASM_FUNCTION_PROLOGUE ++#define TARGET_ASM_FUNCTION_PROLOGUE nios2_asm_function_prologue ++ ++#undef TARGET_DEFAULT_TARGET_FLAGS ++#define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT ++ ++#undef TARGET_SCHED_ISSUE_RATE ++#define TARGET_SCHED_ISSUE_RATE nios2_issue_rate ++#undef TARGET_IN_SMALL_DATA_P ++#define TARGET_IN_SMALL_DATA_P nios2_in_small_data_p ++#undef TARGET_ENCODE_SECTION_INFO ++#define TARGET_ENCODE_SECTION_INFO nios2_encode_section_info ++#undef TARGET_SECTION_TYPE_FLAGS ++#define TARGET_SECTION_TYPE_FLAGS nios2_section_type_flags ++ ++#undef TARGET_INIT_BUILTINS ++#define TARGET_INIT_BUILTINS nios2_init_builtins ++#undef TARGET_EXPAND_BUILTIN ++#define TARGET_EXPAND_BUILTIN nios2_expand_builtin ++ ++#undef TARGET_FUNCTION_OK_FOR_SIBCALL ++#define TARGET_FUNCTION_OK_FOR_SIBCALL nios2_function_ok_for_sibcall ++ ++#undef TARGET_PASS_BY_REFERENCE ++#define TARGET_PASS_BY_REFERENCE nios2_pass_by_reference ++ ++#undef TARGET_ARG_PARTIAL_BYTES ++#define TARGET_ARG_PARTIAL_BYTES nios2_arg_partial_bytes ++ ++#undef TARGET_PROMOTE_PROTOTYPES ++#define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true ++ ++#undef TARGET_SETUP_INCOMING_VARARGS ++#define TARGET_SETUP_INCOMING_VARARGS nios2_setup_incoming_varargs ++ ++#undef TARGET_MUST_PASS_IN_STACK ++#define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size ++ ++#undef TARGET_RTX_COSTS ++#define TARGET_RTX_COSTS nios2_rtx_costs ++ ++#undef TARGET_HAVE_TLS ++#define TARGET_HAVE_TLS true ++ ++#undef TARGET_CANNOT_FORCE_CONST_MEM ++#define TARGET_CANNOT_FORCE_CONST_MEM nios2_cannot_force_const_mem ++ ++#undef TARGET_ASM_OUTPUT_DWARF_DTPREL ++#define TARGET_ASM_OUTPUT_DWARF_DTPREL nios2_output_dwarf_dtprel ++ ++const struct attribute_spec nios2_attribute_table[] = ++{ ++ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ ++ { "reverse_bitfields", 0, 0, false, false, false, ++ nios2_handle_struct_attribute }, ++ { "no_reverse_bitfields", 0, 0, false, false, false, ++ nios2_handle_struct_attribute }, ++ { NULL, 0, 0, false, false, false, NULL } ++}; ++ ++#undef TARGET_ATTRIBUTE_TABLE ++#define TARGET_ATTRIBUTE_TABLE nios2_attribute_table ++ ++#undef TARGET_INSERT_ATTRIBUTES ++#define TARGET_INSERT_ATTRIBUTES nios2_insert_attributes ++ ++/* ??? Might want to redefine TARGET_RETURN_IN_MSB here to handle ++ big-endian case; depends on what ABI we choose. */ ++ ++struct gcc_target targetm = TARGET_INITIALIZER; ++ ++ ++ ++/* Threshold for data being put into the small data/bss area, instead ++ of the normal data area (references to the small data/bss area take ++ 1 instruction, and use the global pointer, references to the normal ++ data area takes 2 instructions). */ ++unsigned HOST_WIDE_INT nios2_section_threshold = NIOS2_DEFAULT_GVALUE; ++ ++/* Structure to be filled in by compute_frame_size with register ++ save masks, and offsets for the current function. */ ++ ++struct nios2_frame_info ++GTY (()) ++{ ++ unsigned HOST_WIDE_INT save_mask; /* Mask of registers to save */ ++ long total_size; /* # bytes that the entire frame takes up. */ ++ long var_size; /* # bytes that variables take up. */ ++ long args_size; /* # bytes that outgoing arguments take up. */ ++ int save_reg_size; /* # bytes needed to store gp regs. */ ++ long save_regs_offset; /* Offset from new sp to store gp registers. */ ++ int initialized; /* != 0 if frame size already calculated. */ ++}; ++ ++struct machine_function ++GTY (()) ++{ ++ ++ /* Current frame information, calculated by compute_frame_size. */ ++ struct nios2_frame_info frame; ++}; ++ ++/* Supported TLS relocations. */ ++ ++enum tls_reloc { ++ TLS_GD16, ++ TLS_LDM16, ++ TLS_LDO16, ++ TLS_IE16, ++ TLS_LE16 ++}; ++ ++#define IS_UNSPEC_TLS(x) ((x)>=UNSPEC_TLS && (x)<=UNSPEC_ADD_TLS_LDO) ++ ++ ++ ++/*************************************** ++ * Register Classes ++ ***************************************/ ++ ++enum reg_class ++reg_class_from_constraint (char chr, const char *str) ++{ ++ if (chr == 'D' && ISDIGIT (str[1]) && ISDIGIT (str[2])) ++ { ++ int regno; ++ int ones = str[2] - '0'; ++ int tens = str[1] - '0'; ++ ++ regno = ones + (10 * tens); ++ if (regno < 0 || regno > 31) ++ return NO_REGS; ++ ++ return D00_REG + regno; ++ } ++ ++ return NO_REGS; ++} ++ ++ ++/*************************************** ++ * Stack Layout and Calling Conventions ++ ***************************************/ ++ ++ ++#define TOO_BIG_OFFSET(X) ((X) > ((1 << 15) - 1)) ++#define TEMP_REG_NUM 8 ++ ++static void ++nios2_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED) ++{ ++ if (flag_verbose_asm || flag_debug_asm) ++ { ++ compute_frame_size (); ++ dump_frame_size (file); ++ } ++} ++ ++static void ++save_reg (int regno, HOST_WIDE_INT offset) ++{ ++ rtx reg = gen_rtx_REG (SImode, regno); ++ rtx addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offset)); ++ ++ rtx pattern = gen_rtx_SET (SImode, gen_frame_mem (Pmode, addr), reg); ++ rtx insn = emit_insn (pattern); ++ RTX_FRAME_RELATED_P (insn) = 1; ++} ++ ++static void ++restore_reg (int regno, HOST_WIDE_INT offset) ++{ ++ rtx reg = gen_rtx_REG (SImode, regno); ++ rtx addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offset)); ++ ++ rtx pattern = gen_rtx_SET (SImode, reg, gen_frame_mem (Pmode, addr)); ++ emit_insn (pattern); ++} ++ ++ ++void ++expand_prologue (void) ++{ ++ int ix; ++ HOST_WIDE_INT total_frame_size = compute_frame_size (); ++ HOST_WIDE_INT sp_offset; /* offset from base_reg to final stack value */ ++ HOST_WIDE_INT fp_offset; /* offset from base_reg to final fp value */ ++ HOST_WIDE_INT save_offset; ++ rtx insn; ++ unsigned HOST_WIDE_INT save_mask; ++ ++ total_frame_size = compute_frame_size (); ++ ++ /* Decrement the stack pointer */ ++ if (TOO_BIG_OFFSET (total_frame_size)) ++ { ++ /* We need an intermediary point, this will point at the spill ++ block */ ++ insn = emit_insn ++ (gen_add3_insn (stack_pointer_rtx, ++ stack_pointer_rtx, ++ GEN_INT (cfun->machine->frame.save_regs_offset ++ - total_frame_size))); ++ RTX_FRAME_RELATED_P (insn) = 1; ++ ++ fp_offset = 0; ++ sp_offset = -cfun->machine->frame.save_regs_offset; ++ } ++ else if (total_frame_size) ++ { ++ insn = emit_insn (gen_add3_insn (stack_pointer_rtx, ++ stack_pointer_rtx, ++ GEN_INT (-total_frame_size))); ++ RTX_FRAME_RELATED_P (insn) = 1; ++ fp_offset = cfun->machine->frame.save_regs_offset; ++ sp_offset = 0; ++ } ++ else ++ fp_offset = sp_offset = 0; ++ ++ if (current_function_limit_stack) ++ emit_insn (gen_stack_overflow_detect_and_trap ()); ++ ++ save_offset = fp_offset + cfun->machine->frame.save_reg_size; ++ save_mask = cfun->machine->frame.save_mask; ++ ++ for (ix = 32; ix--;) ++ if (save_mask & ((unsigned HOST_WIDE_INT)1 << ix)) ++ { ++ save_offset -= 4; ++ save_reg (ix, save_offset); ++ } ++ ++ if (frame_pointer_needed) ++ { ++ insn = emit_insn (gen_add3_insn (hard_frame_pointer_rtx, ++ stack_pointer_rtx, ++ GEN_INT (fp_offset))); ++ ++ RTX_FRAME_RELATED_P (insn) = 1; ++ } ++ ++ if (sp_offset) ++ { ++ rtx tmp = gen_rtx_REG (Pmode, TEMP_REG_NUM); ++ emit_insn (gen_rtx_SET (Pmode, tmp, GEN_INT (sp_offset))); ++ ++ insn = emit_insn (gen_add3_insn (stack_pointer_rtx, stack_pointer_rtx, ++ tmp)); ++ if (!frame_pointer_needed) ++ { ++ /* Attache a note indicating what just happened */ ++ rtx note = gen_rtx_SET (Pmode, stack_pointer_rtx, ++ gen_rtx_PLUS (Pmode, stack_pointer_rtx, ++ GEN_INT (sp_offset))); ++ REG_NOTES (insn) = alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR, ++ note, REG_NOTES (insn)); ++ RTX_FRAME_RELATED_P (insn) = 1; ++ } ++ if (current_function_limit_stack) ++ emit_insn (gen_stack_overflow_detect_and_trap ()); ++ } ++ ++ /* Load the PIC register if needed. */ ++ if (current_function_uses_pic_offset_table) ++ nios2_load_pic_register (); ++ ++ /* If we are profiling, make sure no instructions are scheduled before ++ the call to mcount. */ ++ if (current_function_profile) ++ emit_insn (gen_blockage ()); ++} ++ ++void ++expand_epilogue (bool sibcall_p) ++{ ++ rtx insn; ++ int ix; ++ HOST_WIDE_INT total_frame_size = compute_frame_size (); ++ unsigned HOST_WIDE_INT save_mask; ++ HOST_WIDE_INT sp_adjust; ++ HOST_WIDE_INT save_offset; ++ ++ if (!sibcall_p && nios2_can_use_return_insn ()) ++ { ++ insn = emit_jump_insn (gen_return ()); ++ return; ++ } ++ ++ emit_insn (gen_blockage ()); ++ ++ if (frame_pointer_needed) ++ { ++ /* Recover the stack pointer. */ ++ emit_insn (gen_rtx_SET (Pmode, stack_pointer_rtx, ++ hard_frame_pointer_rtx)); ++ save_offset = 0; ++ sp_adjust = total_frame_size - cfun->machine->frame.save_regs_offset; ++ } ++ else if (TOO_BIG_OFFSET (total_frame_size)) ++ { ++ rtx tmp = gen_rtx_REG (Pmode, TEMP_REG_NUM); ++ ++ emit_insn ++ (gen_rtx_SET ++ (Pmode, tmp, GEN_INT (cfun->machine->frame.save_regs_offset))); ++ emit_insn (gen_add3_insn (stack_pointer_rtx, stack_pointer_rtx, tmp)); ++ save_offset = 0; ++ sp_adjust = total_frame_size - cfun->machine->frame.save_regs_offset; ++ } ++ else ++ { ++ save_offset = cfun->machine->frame.save_regs_offset; ++ sp_adjust = total_frame_size; ++ } ++ ++ save_mask = cfun->machine->frame.save_mask; ++ save_offset += cfun->machine->frame.save_reg_size; ++ ++ for (ix = 32; ix--;) ++ if (save_mask & ((unsigned HOST_WIDE_INT)1 << ix)) ++ { ++ save_offset -= 4; ++ restore_reg (ix, save_offset); ++ } ++ ++ if (sp_adjust) ++ emit_insn (gen_add3_insn (stack_pointer_rtx, stack_pointer_rtx, ++ GEN_INT (sp_adjust))); ++ ++ /* Add in the __builtin_eh_return stack adjustment. */ ++ if (current_function_calls_eh_return) ++ emit_insn (gen_add3_insn (stack_pointer_rtx, ++ stack_pointer_rtx, ++ EH_RETURN_STACKADJ_RTX)); ++ ++ if (!sibcall_p) ++ insn = emit_jump_insn ++ (gen_return_from_epilogue (gen_rtx_REG (Pmode, RA_REGNO))); ++} ++ ++/* Implement RETURN_ADDR_RTX. Note, we do not support moving ++ back to a previous frame. */ ++rtx ++nios2_get_return_address (int count) ++{ ++ if (count != 0) ++ return const0_rtx; ++ ++ return get_hard_reg_initial_val (Pmode, RA_REGNO); ++} ++ ++/* Emit code to change the current function's return address to ++ ADDRESS. SCRATCH is available as a scratch register, if needed. ++ ADDRESS and SCRATCH are both word-mode GPRs. */ ++ ++void ++nios2_set_return_address (rtx address, rtx scratch) ++{ ++ compute_frame_size (); ++ if ((cfun->machine->frame.save_mask >> RA_REGNO) & 1) ++ { ++ HOST_WIDE_INT offset = cfun->machine->frame.save_reg_size - 4; ++ rtx base; ++ ++ if (frame_pointer_needed) ++ base = hard_frame_pointer_rtx; ++ else ++ { ++ base = stack_pointer_rtx; ++ offset += cfun->machine->frame.save_regs_offset; ++ ++ if (TOO_BIG_OFFSET (offset)) ++ { ++ emit_insn (gen_rtx_SET (Pmode, scratch, GEN_INT (offset))); ++ emit_insn (gen_add3_insn (scratch, scratch, base)); ++ base = scratch; ++ offset = 0; ++ } ++ } ++ if (offset) ++ base = gen_rtx_PLUS (Pmode, base, GEN_INT (offset)); ++ emit_insn (gen_rtx_SET (Pmode, gen_rtx_MEM (Pmode, base), address)); ++ } ++ else ++ emit_insn (gen_rtx_SET (Pmode, gen_rtx_REG (Pmode, RA_REGNO), address)); ++} ++ ++bool ++nios2_function_ok_for_sibcall (tree a ATTRIBUTE_UNUSED, tree b ATTRIBUTE_UNUSED) ++{ ++ return true; ++} ++ ++ ++ ++ ++ ++/* ----------------------- * ++ * Profiling ++ * ----------------------- */ ++ ++void ++function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED) ++{ ++ fprintf (file, "\tmov\tr8, ra\n"); ++ if (flag_pic) ++ { ++ fprintf (file, "\tnextpc\tr2\n"); ++ fprintf (file, "\t1: movhi\tr3, %%hiadj(_GLOBAL_OFFSET_TABLE_ - 1b)\n"); ++ fprintf (file, "\taddi\tr3, r3, %%lo(_GLOBAL_OFFSET_TABLE_ - 1b)\n"); ++ fprintf (file, "\tadd\tr2, r2, r3\n"); ++ fprintf (file, "\tldw\tr2, %%call(_mcount)(r2)\n"); ++ fprintf (file, "\tcallr\tr2\n"); ++ } ++ else ++ fprintf (file, "\tcall\t_mcount\n"); ++ fprintf (file, "\tmov\tra, r8\n"); ++} ++ ++ ++/*************************************** ++ * Stack Layout ++ ***************************************/ ++ ++ ++void ++dump_frame_size (FILE *file) ++{ ++ fprintf (file, "\t%s Current Frame Info\n", ASM_COMMENT_START); ++ ++ fprintf (file, "\t%s total_size = %ld\n", ASM_COMMENT_START, ++ cfun->machine->frame.total_size); ++ fprintf (file, "\t%s var_size = %ld\n", ASM_COMMENT_START, ++ cfun->machine->frame.var_size); ++ fprintf (file, "\t%s args_size = %ld\n", ASM_COMMENT_START, ++ cfun->machine->frame.args_size); ++ fprintf (file, "\t%s save_reg_size = %d\n", ASM_COMMENT_START, ++ cfun->machine->frame.save_reg_size); ++ fprintf (file, "\t%s initialized = %d\n", ASM_COMMENT_START, ++ cfun->machine->frame.initialized); ++ fprintf (file, "\t%s save_regs_offset = %ld\n", ASM_COMMENT_START, ++ cfun->machine->frame.save_regs_offset); ++ fprintf (file, "\t%s current_function_is_leaf = %d\n", ASM_COMMENT_START, ++ current_function_is_leaf); ++ fprintf (file, "\t%s frame_pointer_needed = %d\n", ASM_COMMENT_START, ++ frame_pointer_needed); ++ fprintf (file, "\t%s pretend_args_size = %d\n", ASM_COMMENT_START, ++ current_function_pretend_args_size); ++ ++} ++ ++/* Return true if RENOG should be saved in a prologue. */ ++ ++static bool ++save_reg_p (unsigned regno) ++{ ++ gcc_assert (GP_REGNO_P (regno)); ++ ++ if (regs_ever_live[regno] && !call_used_regs[regno]) ++ return true; ++ ++ if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed) ++ return true; ++ ++ if (regno == PIC_OFFSET_TABLE_REGNUM ++ && current_function_uses_pic_offset_table) ++ return true; ++ ++ if (regno == RA_REGNO && regs_ever_live[RA_REGNO]) ++ return true; ++ ++ return false; ++} ++ ++/* Return the bytes needed to compute the frame pointer from the current ++ stack pointer. */ ++ ++HOST_WIDE_INT ++compute_frame_size (void) ++{ ++ unsigned int regno; ++ HOST_WIDE_INT var_size; /* # of var. bytes allocated */ ++ HOST_WIDE_INT total_size; /* # bytes that the entire frame takes up. */ ++ HOST_WIDE_INT save_reg_size; /* # bytes needed to store callee save regs. */ ++ HOST_WIDE_INT out_args_size; /* # bytes needed for outgoing args. */ ++ unsigned HOST_WIDE_INT save_mask = 0; ++ ++ if (cfun->machine->frame.initialized) ++ return cfun->machine->frame.total_size; ++ ++ save_reg_size = 0; ++ var_size = STACK_ALIGN (get_frame_size ()); ++ out_args_size = STACK_ALIGN (current_function_outgoing_args_size); ++ ++ total_size = var_size + out_args_size; ++ ++ /* Calculate space needed for gp registers. */ ++ for (regno = 0; GP_REGNO_P (regno); regno++) ++ if (save_reg_p (regno)) ++ { ++ save_mask |= (unsigned HOST_WIDE_INT)1 << regno; ++ save_reg_size += 4; ++ } ++ ++ /* If we call eh_return, we need to save the EH data registers. */ ++ if (current_function_calls_eh_return) ++ { ++ unsigned i; ++ unsigned r; ++ ++ for (i = 0; (r = EH_RETURN_DATA_REGNO (i)) != INVALID_REGNUM; i++) ++ if (!(save_mask & (1 << r))) ++ { ++ save_mask |= 1 << r; ++ save_reg_size += 4; ++ } ++ } ++ ++ save_reg_size = STACK_ALIGN (save_reg_size); ++ total_size += save_reg_size; ++ ++ total_size += STACK_ALIGN (current_function_pretend_args_size); ++ ++ /* Save other computed information. */ ++ cfun->machine->frame.save_mask = save_mask; ++ cfun->machine->frame.total_size = total_size; ++ cfun->machine->frame.var_size = var_size; ++ cfun->machine->frame.args_size = out_args_size; ++ cfun->machine->frame.save_reg_size = save_reg_size; ++ cfun->machine->frame.initialized = reload_completed; ++ ++ cfun->machine->frame.save_regs_offset = out_args_size + var_size; ++ ++ return total_size; ++} ++ ++ ++int ++nios2_initial_elimination_offset (int from, int to) ++{ ++ int offset; ++ ++ compute_frame_size (); ++ ++ /* Set OFFSET to the offset from the stack pointer. */ ++ switch (from) ++ { ++ case FRAME_POINTER_REGNUM: ++ offset = cfun->machine->frame.args_size; ++ break; ++ ++ case ARG_POINTER_REGNUM: ++ offset = cfun->machine->frame.total_size; ++ offset -= current_function_pretend_args_size; ++ break; ++ ++ default: ++ gcc_unreachable (); ++ } ++ ++ /* If we are asked for the frame pointer offset, then adjust OFFSET ++ by the offset from the frame pointer to the stack pointer. */ ++ if (to == HARD_FRAME_POINTER_REGNUM) ++ offset -= cfun->machine->frame.save_regs_offset; ++ ++ return offset; ++} ++ ++/* Return nonzero if this function is known to have a null epilogue. ++ This allows the optimizer to omit jumps to jumps if no stack ++ was created. */ ++int ++nios2_can_use_return_insn (void) ++{ ++ if (!reload_completed) ++ return 0; ++ ++ if (regs_ever_live[RA_REGNO] || current_function_profile) ++ return 0; ++ ++ if (cfun->machine->frame.initialized) ++ return cfun->machine->frame.total_size == 0; ++ ++ return compute_frame_size () == 0; ++} ++ ++ ++ ++ ++ ++/* Try to take a bit of tedium out of the __builtin_custom_<blah> ++ builtin functions, too. */ ++ ++#define NIOS2_FOR_ALL_CUSTOM_BUILTINS \ ++ NIOS2_DO_BUILTIN (N, n, n ) \ ++ NIOS2_DO_BUILTIN (NI, ni, nX ) \ ++ NIOS2_DO_BUILTIN (NF, nf, nX ) \ ++ NIOS2_DO_BUILTIN (NP, np, nX ) \ ++ NIOS2_DO_BUILTIN (NII, nii, nXX ) \ ++ NIOS2_DO_BUILTIN (NIF, nif, nXX ) \ ++ NIOS2_DO_BUILTIN (NIP, nip, nXX ) \ ++ NIOS2_DO_BUILTIN (NFI, nfi, nXX ) \ ++ NIOS2_DO_BUILTIN (NFF, nff, nXX ) \ ++ NIOS2_DO_BUILTIN (NFP, nfp, nXX ) \ ++ NIOS2_DO_BUILTIN (NPI, npi, nXX ) \ ++ NIOS2_DO_BUILTIN (NPF, npf, nXX ) \ ++ NIOS2_DO_BUILTIN (NPP, npp, nXX ) \ ++ NIOS2_DO_BUILTIN (IN, in, Xn ) \ ++ NIOS2_DO_BUILTIN (INI, ini, XnX ) \ ++ NIOS2_DO_BUILTIN (INF, inf, XnX ) \ ++ NIOS2_DO_BUILTIN (INP, inp, XnX ) \ ++ NIOS2_DO_BUILTIN (INII, inii, XnXX ) \ ++ NIOS2_DO_BUILTIN (INIF, inif, XnXX ) \ ++ NIOS2_DO_BUILTIN (INIP, inip, XnXX ) \ ++ NIOS2_DO_BUILTIN (INFI, infi, XnXX ) \ ++ NIOS2_DO_BUILTIN (INFF, inff, XnXX ) \ ++ NIOS2_DO_BUILTIN (INFP, infp, XnXX ) \ ++ NIOS2_DO_BUILTIN (INPI, inpi, XnXX ) \ ++ NIOS2_DO_BUILTIN (INPF, inpf, XnXX ) \ ++ NIOS2_DO_BUILTIN (INPP, inpp, XnXX ) \ ++ NIOS2_DO_BUILTIN (FN, fn, Xn ) \ ++ NIOS2_DO_BUILTIN (FNI, fni, XnX ) \ ++ NIOS2_DO_BUILTIN (FNF, fnf, XnX ) \ ++ NIOS2_DO_BUILTIN (FNP, fnp, XnX ) \ ++ NIOS2_DO_BUILTIN (FNII, fnii, XnXX ) \ ++ NIOS2_DO_BUILTIN (FNIF, fnif, XnXX ) \ ++ NIOS2_DO_BUILTIN (FNIP, fnip, XnXX ) \ ++ NIOS2_DO_BUILTIN (FNFI, fnfi, XnXX ) \ ++ NIOS2_DO_BUILTIN (FNFF, fnff, XnXX ) \ ++ NIOS2_DO_BUILTIN (FNFP, fnfp, XnXX ) \ ++ NIOS2_DO_BUILTIN (FNPI, fnpi, XnXX ) \ ++ NIOS2_DO_BUILTIN (FNPF, fnpf, XnXX ) \ ++ NIOS2_DO_BUILTIN (FNPP, fnpp, XnXX ) \ ++ NIOS2_DO_BUILTIN (PN, pn, Xn ) \ ++ NIOS2_DO_BUILTIN (PNI, pni, XnX ) \ ++ NIOS2_DO_BUILTIN (PNF, pnf, XnX ) \ ++ NIOS2_DO_BUILTIN (PNP, pnp, XnX ) \ ++ NIOS2_DO_BUILTIN (PNII, pnii, XnXX ) \ ++ NIOS2_DO_BUILTIN (PNIF, pnif, XnXX ) \ ++ NIOS2_DO_BUILTIN (PNIP, pnip, XnXX ) \ ++ NIOS2_DO_BUILTIN (PNFI, pnfi, XnXX ) \ ++ NIOS2_DO_BUILTIN (PNFF, pnff, XnXX ) \ ++ NIOS2_DO_BUILTIN (PNFP, pnfp, XnXX ) \ ++ NIOS2_DO_BUILTIN (PNPI, pnpi, XnXX ) \ ++ NIOS2_DO_BUILTIN (PNPF, pnpf, XnXX ) \ ++ NIOS2_DO_BUILTIN (PNPP, pnpp, XnXX ) ++ ++#undef NIOS2_FPU_INSN ++#define NIOS2_FPU_INSN(opt, insn, args) \ ++static const char *NIOS2_CONCAT (nios2_output_fpu_insn_, insn) (rtx); \ ++static void NIOS2_CONCAT (nios2_pragma_, insn) (struct cpp_reader *); \ ++static void NIOS2_CONCAT (nios2_pragma_no_, insn) (struct cpp_reader *); \ ++int NIOS2_CONCAT (nios2_custom_, opt) = -1; ++NIOS2_FOR_ALL_FPU_INSNS ++ ++nios2_fpu_info nios2_fpu_insns[nios2_fpu_max_insn] = { ++#undef NIOS2_FPU_INSN ++#define NIOS2_FPU_INSN(opt, insn, args) \ ++ { NIOS2_STRINGIFY (opt), \ ++ NIOS2_STRINGIFY (insn), \ ++ NIOS2_STRINGIFY (args), \ ++ -1, \ ++ NIOS2_CONCAT (nios2_output_fpu_insn_, insn), \ ++ "custom_" NIOS2_STRINGIFY (opt), \ ++ NIOS2_CONCAT (nios2_pragma_, insn), \ ++ "no_custom_" NIOS2_STRINGIFY (opt), \ ++ NIOS2_CONCAT (nios2_pragma_no_, insn), \ ++ 0, \ ++ 0, \ ++ 0, \ ++ 0, \ ++ 0, \ ++ &NIOS2_CONCAT (nios2_custom_, opt) }, ++ NIOS2_FOR_ALL_FPU_INSNS ++}; ++ ++const char *nios2_custom_fpu_cfg_string; ++ ++static const char *builtin_custom_seen[256]; ++ ++static void ++nios2_custom_switch (int parameter, int *value, const char *opt) ++{ ++ /* We only document values from 0-255, but we secretly allow -1 so ++ * that the -mno-custom-<opt> switches work. */ ++ if (parameter != -1) ++ { ++ if (parameter < -1 || parameter > 255) ++ error ("switch `-mcustom-%s' value %ld must be between 0 and 255", ++ opt, parameter); ++ *value = (int)parameter; ++ } ++} ++ ++static void ++nios2_custom_check_insns (int is_pragma) ++{ ++ int i; ++ int has_double = 0; ++ int errors = 0; ++ const char *ns[256]; ++ int ps[256]; ++ ++ for (i = 0; i < nios2_fpu_max_insn; i++) ++ if (nios2_fpu_insns[i].is_double && nios2_fpu_insns[i].N >= 0) ++ has_double = 1; ++ ++ if (has_double) ++ { ++ for (i = 0; i < nios2_fpu_max_insn; i++) ++ { ++ if (nios2_fpu_insns[i].needed_by_double ++ && nios2_fpu_insns[i].N < 0) ++ { ++ if (is_pragma) ++ error ("either switch `-mcustom-%s' or `#pragma custom_%s' is " ++ "required for double precision floating point", ++ nios2_fpu_insns[i].option, ++ nios2_fpu_insns[i].option); ++ else ++ error ("switch `-mcustom-%s' is required for double precision " ++ "floating point", ++ nios2_fpu_insns[i].option); ++ errors = 1; ++ } ++ } ++ } ++ ++ /* Warn if the user has certain exotic operations that won't get used ++ without -funsafe-math-optimizations, See expand_builtin () in ++ bulitins.c. */ ++ if (!flag_unsafe_math_optimizations) ++ { ++ for (i = 0; i < nios2_fpu_max_insn; i++) ++ { ++ if (nios2_fpu_insns[i].needs_unsafe && nios2_fpu_insns[i].N >= 0) ++ { ++ warning (0, "%s%s' has no effect unless " ++ "-funsafe-math-optimizations is specified", ++ is_pragma ? "`#pragma custom_" : "switch `-mcustom-", ++ nios2_fpu_insns[i].option); ++ /* Just one warning per function per compilation unit, please. */ ++ nios2_fpu_insns[i].needs_unsafe = 0; ++ } ++ } ++ } ++ ++ /* Warn if the user is trying to use -mcustom-fmins et. al, that won't ++ get used without -ffinite-math-only. See fold in fold () in ++ fold-const.c. */ ++ if (!flag_finite_math_only) ++ { ++ for (i = 0; i < nios2_fpu_max_insn; i++) ++ { ++ if (nios2_fpu_insns[i].needs_finite && nios2_fpu_insns[i].N >= 0) ++ { ++ warning (0, "%s%s' has no effect unless -ffinite-math-only " ++ "is specified", ++ is_pragma ? "`#pragma custom_" : "switch `-mcustom-", ++ nios2_fpu_insns[i].option); ++ /* Just one warning per function per compilation unit, please. */ ++ nios2_fpu_insns[i].needs_finite = 0; ++ } ++ } ++ } ++ ++ /* Warn the user about double precision divide braindamage until we ++ can fix it properly. See the RDIV_EXPR case of expand_expr_real in ++ expr.c. */ ++ { ++ static int warned = 0; ++ if (flag_unsafe_math_optimizations ++ && !optimize_size ++ && nios2_fpu_insns[nios2_fpu_divdf3].N >= 0 ++ && !warned) ++ { ++ warning (0, "%s%s' behaves poorly without -Os", ++ is_pragma ? "`#pragma custom_" : "switch `-mcustom-", ++ nios2_fpu_insns[nios2_fpu_divdf3].option); ++ warned = 1; ++ } ++ } ++ ++ /* The following bit of voodoo is lifted from the generated file ++ insn-opinit.c: to allow #pragmas to work properly, we have to tweak ++ the optab_table manually -- it only gets initialized once after the ++ switches are handled and before any #pragmas are seen. */ ++ if (is_pragma) ++ { ++ /* Only do this if the optabs have already been defined, not ++ when we're handling command line switches. */ ++ addv_optab->handlers[SFmode].insn_code = ++ add_optab->handlers[SFmode].insn_code = CODE_FOR_nothing; ++ addv_optab->handlers[DFmode].insn_code = ++ add_optab->handlers[DFmode].insn_code = CODE_FOR_nothing; ++ subv_optab->handlers[SFmode].insn_code = ++ sub_optab->handlers[SFmode].insn_code = CODE_FOR_nothing; ++ subv_optab->handlers[DFmode].insn_code = ++ sub_optab->handlers[DFmode].insn_code = CODE_FOR_nothing; ++ smulv_optab->handlers[SFmode].insn_code = ++ smul_optab->handlers[SFmode].insn_code = CODE_FOR_nothing; ++ smulv_optab->handlers[DFmode].insn_code = ++ smul_optab->handlers[DFmode].insn_code = CODE_FOR_nothing; ++ sdiv_optab->handlers[SFmode].insn_code = CODE_FOR_nothing; ++ sdiv_optab->handlers[DFmode].insn_code = CODE_FOR_nothing; ++ negv_optab->handlers[SFmode].insn_code = ++ neg_optab->handlers[SFmode].insn_code = CODE_FOR_nothing; ++ negv_optab->handlers[DFmode].insn_code = ++ neg_optab->handlers[DFmode].insn_code = CODE_FOR_nothing; ++ smin_optab->handlers[SFmode].insn_code = CODE_FOR_nothing; ++ smin_optab->handlers[DFmode].insn_code = CODE_FOR_nothing; ++ smax_optab->handlers[SFmode].insn_code = CODE_FOR_nothing; ++ smax_optab->handlers[DFmode].insn_code = CODE_FOR_nothing; ++ absv_optab->handlers[SFmode].insn_code = ++ abs_optab->handlers[SFmode].insn_code = CODE_FOR_nothing; ++ absv_optab->handlers[DFmode].insn_code = ++ abs_optab->handlers[DFmode].insn_code = CODE_FOR_nothing; ++ sqrt_optab->handlers[SFmode].insn_code = CODE_FOR_nothing; ++ sqrt_optab->handlers[DFmode].insn_code = CODE_FOR_nothing; ++ cos_optab->handlers[SFmode].insn_code = CODE_FOR_nothing; ++ cos_optab->handlers[DFmode].insn_code = CODE_FOR_nothing; ++ sin_optab->handlers[SFmode].insn_code = CODE_FOR_nothing; ++ sin_optab->handlers[DFmode].insn_code = CODE_FOR_nothing; ++ tan_optab->handlers[SFmode].insn_code = CODE_FOR_nothing; ++ tan_optab->handlers[DFmode].insn_code = CODE_FOR_nothing; ++ atan_optab->handlers[SFmode].insn_code = CODE_FOR_nothing; ++ atan_optab->handlers[DFmode].insn_code = CODE_FOR_nothing; ++ exp_optab->handlers[SFmode].insn_code = CODE_FOR_nothing; ++ exp_optab->handlers[DFmode].insn_code = CODE_FOR_nothing; ++ log_optab->handlers[SFmode].insn_code = CODE_FOR_nothing; ++ log_optab->handlers[DFmode].insn_code = CODE_FOR_nothing; ++ sfloat_optab->handlers[SFmode][SImode].insn_code = CODE_FOR_nothing; ++ sfloat_optab->handlers[DFmode][SImode].insn_code = CODE_FOR_nothing; ++ ufloat_optab->handlers[SFmode][SImode].insn_code = CODE_FOR_nothing; ++ ufloat_optab->handlers[DFmode][SImode].insn_code = CODE_FOR_nothing; ++ sfix_optab->handlers[SImode][SFmode].insn_code = CODE_FOR_nothing; ++ sfix_optab->handlers[SImode][DFmode].insn_code = CODE_FOR_nothing; ++ ufix_optab->handlers[SImode][SFmode].insn_code = CODE_FOR_nothing; ++ ufix_optab->handlers[SImode][DFmode].insn_code = CODE_FOR_nothing; ++ sext_optab->handlers[DFmode][SFmode].insn_code = CODE_FOR_nothing; ++ trunc_optab->handlers[SFmode][DFmode].insn_code = CODE_FOR_nothing; ++ cmp_optab->handlers[SFmode].insn_code = CODE_FOR_nothing; ++ cmp_optab->handlers[DFmode].insn_code = CODE_FOR_nothing; ++ ++ if (HAVE_addsf3) ++ addv_optab->handlers[SFmode].insn_code = ++ add_optab->handlers[SFmode].insn_code = CODE_FOR_addsf3; ++ if (HAVE_adddf3) ++ addv_optab->handlers[DFmode].insn_code = ++ add_optab->handlers[DFmode].insn_code = CODE_FOR_adddf3; ++ if (HAVE_subsf3) ++ subv_optab->handlers[SFmode].insn_code = ++ sub_optab->handlers[SFmode].insn_code = CODE_FOR_subsf3; ++ if (HAVE_subdf3) ++ subv_optab->handlers[DFmode].insn_code = ++ sub_optab->handlers[DFmode].insn_code = CODE_FOR_subdf3; ++ if (HAVE_mulsf3) ++ smulv_optab->handlers[SFmode].insn_code = ++ smul_optab->handlers[SFmode].insn_code = CODE_FOR_mulsf3; ++ if (HAVE_muldf3) ++ smulv_optab->handlers[DFmode].insn_code = ++ smul_optab->handlers[DFmode].insn_code = CODE_FOR_muldf3; ++ if (HAVE_divsf3) ++ sdiv_optab->handlers[SFmode].insn_code = CODE_FOR_divsf3; ++ if (HAVE_divdf3) ++ sdiv_optab->handlers[DFmode].insn_code = CODE_FOR_divdf3; ++ if (HAVE_negsf2) ++ negv_optab->handlers[SFmode].insn_code = ++ neg_optab->handlers[SFmode].insn_code = CODE_FOR_negsf2; ++ if (HAVE_negdf2) ++ negv_optab->handlers[DFmode].insn_code = ++ neg_optab->handlers[DFmode].insn_code = CODE_FOR_negdf2; ++ if (HAVE_minsf3) ++ smin_optab->handlers[SFmode].insn_code = CODE_FOR_minsf3; ++ if (HAVE_mindf3) ++ smin_optab->handlers[DFmode].insn_code = CODE_FOR_mindf3; ++ if (HAVE_maxsf3) ++ smax_optab->handlers[SFmode].insn_code = CODE_FOR_maxsf3; ++ if (HAVE_maxdf3) ++ smax_optab->handlers[DFmode].insn_code = CODE_FOR_maxdf3; ++ if (HAVE_abssf2) ++ absv_optab->handlers[SFmode].insn_code = ++ abs_optab->handlers[SFmode].insn_code = CODE_FOR_abssf2; ++ if (HAVE_absdf2) ++ absv_optab->handlers[DFmode].insn_code = ++ abs_optab->handlers[DFmode].insn_code = CODE_FOR_absdf2; ++ if (HAVE_sqrtsf2) ++ sqrt_optab->handlers[SFmode].insn_code = CODE_FOR_sqrtsf2; ++ if (HAVE_sqrtdf2) ++ sqrt_optab->handlers[DFmode].insn_code = CODE_FOR_sqrtdf2; ++ if (HAVE_cossf2) ++ cos_optab->handlers[SFmode].insn_code = CODE_FOR_cossf2; ++ if (HAVE_cosdf2) ++ cos_optab->handlers[DFmode].insn_code = CODE_FOR_cosdf2; ++ if (HAVE_sinsf2) ++ sin_optab->handlers[SFmode].insn_code = CODE_FOR_sinsf2; ++ if (HAVE_sindf2) ++ sin_optab->handlers[DFmode].insn_code = CODE_FOR_sindf2; ++ if (HAVE_tansf2) ++ tan_optab->handlers[SFmode].insn_code = CODE_FOR_tansf2; ++ if (HAVE_tandf2) ++ tan_optab->handlers[DFmode].insn_code = CODE_FOR_tandf2; ++ if (HAVE_atansf2) ++ atan_optab->handlers[SFmode].insn_code = CODE_FOR_atansf2; ++ if (HAVE_atandf2) ++ atan_optab->handlers[DFmode].insn_code = CODE_FOR_atandf2; ++ if (HAVE_expsf2) ++ exp_optab->handlers[SFmode].insn_code = CODE_FOR_expsf2; ++ if (HAVE_expdf2) ++ exp_optab->handlers[DFmode].insn_code = CODE_FOR_expdf2; ++ if (HAVE_logsf2) ++ log_optab->handlers[SFmode].insn_code = CODE_FOR_logsf2; ++ if (HAVE_logdf2) ++ log_optab->handlers[DFmode].insn_code = CODE_FOR_logdf2; ++ if (HAVE_floatsisf2) ++ sfloat_optab->handlers[SFmode][SImode].insn_code = CODE_FOR_floatsisf2; ++ if (HAVE_floatsidf2) ++ sfloat_optab->handlers[DFmode][SImode].insn_code = CODE_FOR_floatsidf2; ++ if (HAVE_floatunssisf2) ++ ufloat_optab->handlers[SFmode][SImode].insn_code = CODE_FOR_floatunssisf2; ++ if (HAVE_floatunssidf2) ++ ufloat_optab->handlers[DFmode][SImode].insn_code = CODE_FOR_floatunssidf2; ++ if (HAVE_fixsfsi2) ++ sfix_optab->handlers[SImode][SFmode].insn_code = CODE_FOR_fixsfsi2; ++ if (HAVE_fixdfsi2) ++ sfix_optab->handlers[SImode][DFmode].insn_code = CODE_FOR_fixdfsi2; ++ if (HAVE_fixunssfsi2) ++ ufix_optab->handlers[SImode][SFmode].insn_code = CODE_FOR_fixunssfsi2; ++ if (HAVE_fixunsdfsi2) ++ ufix_optab->handlers[SImode][DFmode].insn_code = CODE_FOR_fixunsdfsi2; ++ if (HAVE_extendsfdf2) ++ sext_optab->handlers[DFmode][SFmode].insn_code = CODE_FOR_extendsfdf2; ++ if (HAVE_truncdfsf2) ++ trunc_optab->handlers[SFmode][DFmode].insn_code = CODE_FOR_truncdfsf2; ++ if (HAVE_cmpsf) ++ cmp_optab->handlers[SFmode].insn_code = CODE_FOR_cmpsf; ++ if (HAVE_cmpdf) ++ cmp_optab->handlers[DFmode].insn_code = CODE_FOR_cmpdf; ++ } ++ ++ /* Check for duplicate values of N. */ ++ for (i = 0; i < 256; i++) ++ { ++ ns[i] = 0; ++ ps[i] = 0; ++ } ++ ++ for (i = 0; i < nios2_fpu_max_insn; i++) ++ { ++ int N = nios2_fpu_insns[i].N; ++ if (N >= 0) ++ { ++ if (ns[N]) ++ { ++ error ("%s%s' conflicts with %s%s'", ++ is_pragma ? "`#pragma custom_" : "switch `-mcustom-", ++ nios2_fpu_insns[i].option, ++ ps[N] ? "`#pragma custom_" : "switch `-mcustom-", ++ ns[N]); ++ errors = 1; ++ } ++ else if (builtin_custom_seen[N]) ++ { ++ error ("call to `%s' conflicts with %s%s'", ++ builtin_custom_seen[N], ++ (nios2_fpu_insns[i].pragma_seen ++ ? "`#pragma custom_" : "switch `-mcustom-"), ++ nios2_fpu_insns[i].option); ++ errors = 1; ++ } ++ else ++ { ++ ns[N] = nios2_fpu_insns[i].option; ++ ps[N] = nios2_fpu_insns[i].pragma_seen; ++ } ++ } ++ } ++ ++ if (errors) ++ fatal_error ("conflicting use of -mcustom switches, #pragmas, and/or " ++ "__builtin_custom_ functions"); ++} ++ ++static void ++nios2_handle_custom_fpu_cfg (const char *cfg, int is_pragma) ++{ ++#undef NIOS2_FPU_INSN ++#define NIOS2_FPU_INSN(opt, insn, args) \ ++ int opt = nios2_fpu_insns[NIOS2_CONCAT (nios2_fpu_, insn)].N; ++NIOS2_FOR_ALL_FPU_INSNS ++ ++ /* ++ * ??? These are just some sample possibilities. We'll change these ++ * at the last minute to match the capabilities of the actual fpu. ++ */ ++ if (!strcasecmp (cfg, "60-1")) ++ { ++ fmuls = 252; ++ fadds = 253; ++ fsubs = 254; ++ flag_single_precision_constant = 1; ++ } ++ else if (!strcasecmp (cfg, "60-2")) ++ { ++ fmuls = 252; ++ fadds = 253; ++ fsubs = 254; ++ fdivs = 255; ++ flag_single_precision_constant = 1; ++ } ++ else if (!strcasecmp (cfg, "72-3")) ++ { ++ floatus = 243; ++ fixsi = 244; ++ floatis = 245; ++ fcmpgts = 246; ++ fcmples = 249; ++ fcmpeqs = 250; ++ fcmpnes = 251; ++ fmuls = 252; ++ fadds = 253; ++ fsubs = 254; ++ fdivs = 255; ++ flag_single_precision_constant = 1; ++ } ++ else ++ warning (0, "ignoring unrecognized %sfpu-cfg' value `%s'", ++ is_pragma ? "`#pragma custom_" : "switch -mcustom-", cfg); ++ ++#undef NIOS2_FPU_INSN ++#define NIOS2_FPU_INSN(opt, insn, args) \ ++ nios2_fpu_insns[NIOS2_CONCAT (nios2_fpu_, insn)].N = opt; ++NIOS2_FOR_ALL_FPU_INSNS ++ ++ /* Guard against errors in the standard configurations. */ ++ nios2_custom_check_insns (is_pragma); ++} ++ ++void ++override_options (void) ++{ ++ int i; ++ ++ /* Function to allocate machine-dependent function status. */ ++ init_machine_status = &nios2_init_machine_status; ++ ++ nios2_section_threshold ++ = g_switch_set ? g_switch_value : NIOS2_DEFAULT_GVALUE; ++ ++ /* If we don't have mul, we don't have mulx either! */ ++ if (!TARGET_HAS_MUL && TARGET_HAS_MULX) ++ target_flags &= ~MASK_HAS_MULX; ++ ++ /* Set up for stack limit checking. */ ++ if (TARGET_STACK_CHECK) ++ stack_limit_rtx = gen_rtx_REG(SImode, ET_REGNO); ++ ++ for (i = 0; i < nios2_fpu_max_insn; i++) ++ { ++ nios2_fpu_insns[i].is_double = (nios2_fpu_insns[i].args[0] == 'd' ++ || nios2_fpu_insns[i].args[0] == 'd' ++ || nios2_fpu_insns[i].args[0] == 'd'); ++ nios2_fpu_insns[i].needed_by_double = (i == nios2_fpu_nios2_fwrx ++ || i == nios2_fpu_nios2_fwry ++ || i == nios2_fpu_nios2_frdxlo ++ || i == nios2_fpu_nios2_frdxhi ++ || i == nios2_fpu_nios2_frdy); ++ nios2_fpu_insns[i].needs_unsafe = (i == nios2_fpu_cossf2 ++ || i == nios2_fpu_cosdf2 ++ || i == nios2_fpu_sinsf2 ++ || i == nios2_fpu_sindf2 ++ || i == nios2_fpu_tansf2 ++ || i == nios2_fpu_tandf2 ++ || i == nios2_fpu_atansf2 ++ || i == nios2_fpu_atandf2 ++ || i == nios2_fpu_expsf2 ++ || i == nios2_fpu_expdf2 ++ || i == nios2_fpu_logsf2 ++ || i == nios2_fpu_logdf2); ++ nios2_fpu_insns[i].needs_finite = (i == nios2_fpu_minsf3 ++ || i == nios2_fpu_maxsf3 ++ || i == nios2_fpu_mindf3 ++ || i == nios2_fpu_maxdf3); ++ } ++ ++ /* We haven't seen any __builtin_custom functions yet. */ ++ for (i = 0; i < 256; i++) ++ builtin_custom_seen[i] = 0; ++ ++ /* Set up default handling for floating point custom instructions. ++ ++ Putting things in this order means that the -mcustom-fpu-cfg= ++ switch will always be overridden by individual -mcustom-fadds= ++ switches, regardless of the order in which they were specified ++ on the command line. ??? Remember to document this. */ ++ if (nios2_custom_fpu_cfg_string && *nios2_custom_fpu_cfg_string) ++ nios2_handle_custom_fpu_cfg (nios2_custom_fpu_cfg_string, 0); ++ ++ for (i = 0; i < nios2_fpu_max_insn; i++) ++ nios2_custom_switch (*nios2_fpu_insns[i].pN, ++ &nios2_fpu_insns[i].N, ++ nios2_fpu_insns[i].option); ++ ++ nios2_custom_check_insns (0); ++} ++ ++void ++optimization_options (int level, int size) ++{ ++ if (level || size) ++ target_flags |= MASK_INLINE_MEMCPY; ++ ++ if (level >= 3 && !size) ++ target_flags |= MASK_FAST_SW_DIV; ++} ++ ++/* Allocate a chunk of memory for per-function machine-dependent data. */ ++static struct machine_function * ++nios2_init_machine_status (void) ++{ ++ return ((struct machine_function *) ++ ggc_alloc_cleared (sizeof (struct machine_function))); ++} ++ ++ ++ ++/***************** ++ * Describing Relative Costs of Operations ++ *****************/ ++ ++/* 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. */ ++ ++ ++ ++static bool ++nios2_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total) ++{ ++ switch (code) ++ { ++ case CONST_INT: ++ if (INTVAL (x) == 0) ++ { ++ *total = COSTS_N_INSNS (0); ++ return true; ++ } ++ else if (SMALL_INT (INTVAL (x)) ++ || SMALL_INT_UNSIGNED (INTVAL (x)) ++ || UPPER16_INT (INTVAL (x))) ++ { ++ *total = COSTS_N_INSNS (2); ++ return true; ++ } ++ else ++ { ++ *total = COSTS_N_INSNS (4); ++ return true; ++ } ++ ++ case LABEL_REF: ++ case SYMBOL_REF: ++ /* ??? gp relative stuff will fit in here. */ ++ /* fall through */ ++ case CONST: ++ case CONST_DOUBLE: ++ { ++ *total = COSTS_N_INSNS (4); ++ return true; ++ } ++ ++ case MULT: ++ { ++ *total = COSTS_N_INSNS (1); ++ return false; ++ } ++ case SIGN_EXTEND: ++ { ++ *total = COSTS_N_INSNS (3); ++ return false; ++ } ++ case ZERO_EXTEND: ++ { ++ *total = COSTS_N_INSNS (1); ++ return false; ++ } ++ ++ default: ++ return false; ++ } ++} ++ ++ ++/*************************************** ++ * INSTRUCTION SUPPORT ++ * ++ * These functions are used within the Machine Description to ++ * handle common or complicated output and expansions from ++ * instructions. ++ ***************************************/ ++ ++/* Return TRUE if X references a SYMBOL_REF. */ ++static int ++symbol_mentioned_p (rtx x) ++{ ++ const char * fmt; ++ int i; ++ ++ if (GET_CODE (x) == SYMBOL_REF) ++ return 1; ++ ++ /* UNSPEC_TLS entries for a symbol include the SYMBOL_REF, but they ++ are constant offsets, not symbols. */ ++ if (GET_CODE (x) == UNSPEC && IS_UNSPEC_TLS (XINT (x, 1))) ++ return 0; ++ ++ fmt = GET_RTX_FORMAT (GET_CODE (x)); ++ ++ for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) ++ { ++ if (fmt[i] == 'E') ++ { ++ int j; ++ ++ for (j = XVECLEN (x, i) - 1; j >= 0; j--) ++ if (symbol_mentioned_p (XVECEXP (x, i, j))) ++ return 1; ++ } ++ else if (fmt[i] == 'e' && symbol_mentioned_p (XEXP (x, i))) ++ return 1; ++ } ++ ++ return 0; ++} ++ ++/* Return TRUE if X references a LABEL_REF. */ ++static int ++label_mentioned_p (rtx x) ++{ ++ const char * fmt; ++ int i; ++ ++ if (GET_CODE (x) == LABEL_REF) ++ return 1; ++ ++ /* UNSPEC_TLS entries for a symbol include a LABEL_REF for the referencing ++ instruction, but they are constant offsets, not symbols. */ ++ if (GET_CODE (x) == UNSPEC && IS_UNSPEC_TLS (XINT (x, 1))) ++ return 0; ++ ++ fmt = GET_RTX_FORMAT (GET_CODE (x)); ++ for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) ++ { ++ if (fmt[i] == 'E') ++ { ++ int j; ++ ++ for (j = XVECLEN (x, i) - 1; j >= 0; j--) ++ if (label_mentioned_p (XVECEXP (x, i, j))) ++ return 1; ++ } ++ else if (fmt[i] == 'e' && label_mentioned_p (XEXP (x, i))) ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static int ++tls_mentioned_p (rtx x) ++{ ++ switch (GET_CODE (x)) ++ { ++ case CONST: ++ return tls_mentioned_p (XEXP (x, 0)); ++ ++ case UNSPEC: ++ if (IS_UNSPEC_TLS (XINT (x, 1))) ++ return 1; ++ ++ default: ++ return 0; ++ } ++} ++ ++/* Helper for nios2_tls_referenced_p. */ ++ ++static int ++nios2_tls_operand_p_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 ++ && IS_UNSPEC_TLS (XINT (*x, 1))) ++ return -1; ++ ++ return 0; ++} ++ ++/* Return TRUE if X contains any TLS symbol references. */ ++ ++static bool ++nios2_tls_referenced_p (rtx x) ++{ ++ if (! TARGET_HAVE_TLS) ++ return false; ++ ++ return for_each_rtx (&x, nios2_tls_operand_p_1, NULL); ++} ++ ++static bool ++nios2_cannot_force_const_mem (rtx x) ++{ ++ return nios2_tls_referenced_p (x); ++} ++ ++/* Emit a call to __tls_get_addr. TI is the argument to this function. RET is ++ an RTX for the return value location. The entire insn sequence is ++ returned. */ ++ ++static GTY(()) rtx nios2_tls_symbol; ++ ++static rtx ++nios2_call_tls_get_addr (rtx ti) ++{ ++ rtx arg = gen_rtx_REG (Pmode, FIRST_ARG_REGNO); ++ rtx ret = gen_rtx_REG (Pmode, FIRST_RETVAL_REGNO); ++ rtx fn, insn; ++ ++ if (!nios2_tls_symbol) ++ nios2_tls_symbol = init_one_libfunc ("__tls_get_addr"); ++ ++ emit_insn (gen_rtx_SET (Pmode, arg, ti)); ++ fn = gen_rtx_MEM (QImode, nios2_tls_symbol); ++ insn = emit_call_insn (gen_call_value (ret, fn, const0_rtx)); ++ CONST_OR_PURE_CALL_P (insn) = 1; ++ use_reg (&CALL_INSN_FUNCTION_USAGE (insn), ret); ++ use_reg (&CALL_INSN_FUNCTION_USAGE (insn), arg); ++ ++ return ret; ++} ++ ++/* Generate the code to access LOC, a thread local SYMBOL_REF. The ++ return value will be a valid address and move_operand (either a REG ++ or a LO_SUM). */ ++ ++static rtx ++nios2_legitimize_tls_address (rtx loc) ++{ ++ rtx dest = gen_reg_rtx (Pmode); ++ rtx ret, tmp1; ++ enum tls_model model = SYMBOL_REF_TLS_MODEL (loc); ++ ++ switch (model) ++ { ++ case TLS_MODEL_GLOBAL_DYNAMIC: ++ tmp1 = gen_reg_rtx (Pmode); ++ emit_insn (gen_add_tls_gd (tmp1, pic_offset_table_rtx, loc)); ++ current_function_uses_pic_offset_table = 1; ++ ret = nios2_call_tls_get_addr (tmp1); ++ emit_insn (gen_rtx_SET (Pmode, dest, ret)); ++ break; ++ ++ case TLS_MODEL_LOCAL_DYNAMIC: ++ tmp1 = gen_reg_rtx (Pmode); ++ emit_insn (gen_add_tls_ldm (tmp1, pic_offset_table_rtx, loc)); ++ current_function_uses_pic_offset_table = 1; ++ ret = nios2_call_tls_get_addr (tmp1); ++ ++ emit_insn (gen_add_tls_ldo (dest, ret, loc)); ++ ++ break; ++ ++ case TLS_MODEL_INITIAL_EXEC: ++ tmp1 = gen_reg_rtx (Pmode); ++ emit_insn (gen_load_tls_ie (tmp1, pic_offset_table_rtx, loc)); ++ current_function_uses_pic_offset_table = 1; ++ emit_insn (gen_add3_insn (dest, ++ gen_rtx_REG (Pmode, THREAD_POINTER_REGNUM), ++ tmp1)); ++ break; ++ ++ case TLS_MODEL_LOCAL_EXEC: ++ emit_insn (gen_add_tls_le (dest, ++ gen_rtx_REG (Pmode, THREAD_POINTER_REGNUM), ++ loc)); ++ break; ++ ++ default: ++ gcc_unreachable (); ++ } ++ ++ return dest; ++} ++ ++int ++nios2_emit_move_sequence (rtx *operands, enum machine_mode mode) ++{ ++ rtx to = operands[0]; ++ rtx from = operands[1]; ++ ++ if (!register_operand (to, mode) && !reg_or_0_operand (from, mode)) ++ { ++ if (no_new_pseudos) ++ internal_error ("Trying to force_reg no_new_pseudos == 1"); ++ from = copy_to_mode_reg (mode, from); ++ } ++ ++ /* Recognize the case where from is a reference to thread-local ++ data and load its address to a register. */ ++ if (nios2_tls_referenced_p (from)) ++ { ++ rtx tmp = from; ++ rtx addend = NULL; ++ ++ 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 = nios2_legitimize_tls_address (tmp); ++ if (addend) ++ { ++ tmp = gen_rtx_PLUS (SImode, tmp, addend); ++ tmp = force_operand (tmp, to); ++ } ++ from = tmp; ++ } ++ else if (flag_pic && (CONSTANT_P (from) || symbol_mentioned_p (from) || ++ label_mentioned_p (from))) ++ from = nios2_legitimize_pic_address (from, SImode, ++ (no_new_pseudos ? to : 0)); ++ ++ operands[0] = to; ++ operands[1] = from; ++ return 0; ++} ++ ++/* Divide Support */ ++ ++/* ++ If -O3 is used, we want to output a table lookup for ++ divides between small numbers (both num and den >= 0 ++ and < 0x10). The overhead of this method in the worse ++ case is 40 bytes in the text section (10 insns) and ++ 256 bytes in the data section. Additional divides do ++ not incur additional penalties in the data section. ++ ++ Code speed is improved for small divides by about 5x ++ when using this method in the worse case (~9 cycles ++ vs ~45). And in the worse case divides not within the ++ table are penalized by about 10% (~5 cycles vs ~45). ++ However in the typical case the penalty is not as bad ++ because doing the long divide in only 45 cycles is ++ quite optimistic. ++ ++ ??? It would be nice to have some benchmarks other ++ than Dhrystone to back this up. ++ ++ This bit of expansion is to create this instruction ++ sequence as rtl. ++ or $8, $4, $5 ++ slli $9, $4, 4 ++ cmpgeui $3, $8, 16 ++ beq $3, $0, .L3 ++ or $10, $9, $5 ++ add $12, $11, divide_table ++ ldbu $2, 0($12) ++ br .L1 ++.L3: ++ call slow_div ++.L1: ++# continue here with result in $2 ++ ++ ??? Ideally I would like the emit libcall block to contain ++ all of this code, but I don't know how to do that. What it ++ means is that if the divide can be eliminated, it may not ++ completely disappear. ++ ++ ??? The __divsi3_table label should ideally be moved out ++ of this block and into a global. If it is placed into the ++ sdata section we can save even more cycles by doing things ++ gp relative. ++*/ ++int ++nios2_emit_expensive_div (rtx *operands, enum machine_mode mode) ++{ ++ rtx or_result, shift_left_result; ++ rtx lookup_value; ++ rtx lab1, lab3; ++ rtx insns; ++ rtx libfunc; ++ rtx final_result; ++ rtx tmp; ++ ++ /* It may look a little generic, but only SImode ++ is supported for now. */ ++ gcc_assert (mode == SImode); ++ ++ libfunc = sdiv_optab->handlers[(int) SImode].libfunc; ++ ++ ++ ++ lab1 = gen_label_rtx (); ++ lab3 = gen_label_rtx (); ++ ++ or_result = expand_simple_binop (SImode, IOR, ++ operands[1], operands[2], ++ 0, 0, OPTAB_LIB_WIDEN); ++ ++ emit_cmp_and_jump_insns (or_result, GEN_INT (15), GTU, 0, ++ GET_MODE (or_result), 0, lab3); ++ JUMP_LABEL (get_last_insn ()) = lab3; ++ ++ shift_left_result = expand_simple_binop (SImode, ASHIFT, ++ operands[1], GEN_INT (4), ++ 0, 0, OPTAB_LIB_WIDEN); ++ ++ lookup_value = expand_simple_binop (SImode, IOR, ++ shift_left_result, operands[2], ++ 0, 0, OPTAB_LIB_WIDEN); ++ ++ convert_move (operands[0], ++ gen_rtx_MEM (QImode, ++ gen_rtx_PLUS (SImode, ++ lookup_value, ++ gen_rtx_SYMBOL_REF (SImode, "__divsi3_table"))), ++ 1); ++ ++ ++ tmp = emit_jump_insn (gen_jump (lab1)); ++ JUMP_LABEL (tmp) = lab1; ++ emit_barrier (); ++ ++ emit_label (lab3); ++ LABEL_NUSES (lab3) = 1; ++ ++ start_sequence (); ++ final_result = emit_library_call_value (libfunc, NULL_RTX, ++ LCT_CONST, SImode, 2, ++ operands[1], SImode, ++ operands[2], SImode); ++ ++ ++ insns = get_insns (); ++ end_sequence (); ++ emit_libcall_block (insns, operands[0], final_result, ++ gen_rtx_DIV (SImode, operands[1], operands[2])); ++ ++ emit_label (lab1); ++ LABEL_NUSES (lab1) = 1; ++ return 1; ++} ++ ++/* The function with address *ADDR is being called. If the address ++ needs to be loaded from the GOT, emit the instruction to do so and ++ update *ADDR to point to the rtx for the loaded value. */ ++ ++void ++nios2_adjust_call_address (rtx *addr) ++{ ++ if (flag_pic ++ && (GET_CODE (*addr) == SYMBOL_REF || GET_CODE (*addr) == LABEL_REF)) ++ { ++ rtx addr_orig; ++ current_function_uses_pic_offset_table = 1; ++ addr_orig = *addr; ++ *addr = gen_reg_rtx (GET_MODE (addr_orig)); ++ emit_insn (gen_pic_load_call_addr (*addr, ++ pic_offset_table_rtx, addr_orig)); ++ } ++} ++ ++/* Branches/Compares. */ ++ ++/* The way of handling branches/compares ++ in gcc is heavily borrowed from MIPS. */ ++ ++enum internal_test ++{ ++ ITEST_EQ, ++ ITEST_NE, ++ ITEST_GT, ++ ITEST_GE, ++ ITEST_LT, ++ ITEST_LE, ++ ITEST_GTU, ++ ITEST_GEU, ++ ITEST_LTU, ++ ITEST_LEU, ++ ITEST_MAX ++}; ++ ++static enum internal_test map_test_to_internal_test (enum rtx_code); ++ ++/* Cached operands, and operator to compare for use in set/branch/trap ++ on condition codes. */ ++rtx branch_cmp[2]; ++enum cmp_type branch_type; ++ ++/* Make normal rtx_code into something we can index from an array. */ ++ ++static enum internal_test ++map_test_to_internal_test (enum rtx_code test_code) ++{ ++ enum internal_test test = ITEST_MAX; ++ ++ switch (test_code) ++ { ++ case EQ: ++ test = ITEST_EQ; ++ break; ++ case NE: ++ test = ITEST_NE; ++ break; ++ case GT: ++ test = ITEST_GT; ++ break; ++ case GE: ++ test = ITEST_GE; ++ break; ++ case LT: ++ test = ITEST_LT; ++ break; ++ case LE: ++ test = ITEST_LE; ++ break; ++ case GTU: ++ test = ITEST_GTU; ++ break; ++ case GEU: ++ test = ITEST_GEU; ++ break; ++ case LTU: ++ test = ITEST_LTU; ++ break; ++ case LEU: ++ test = ITEST_LEU; ++ break; ++ default: ++ break; ++ } ++ ++ return test; ++} ++ ++bool have_nios2_fpu_cmp_insn( enum rtx_code cond_t, enum cmp_type cmp_t ); ++enum rtx_code get_reverse_cond(enum rtx_code cond_t); ++ ++bool ++have_nios2_fpu_cmp_insn( enum rtx_code cond_t, enum cmp_type cmp_t ) ++{ ++ if (cmp_t == CMP_SF) ++ { ++ switch (cond_t) ++ { ++ case EQ: ++ return (nios2_fpu_insns[nios2_fpu_nios2_seqsf].N >= 0); ++ case NE: ++ return (nios2_fpu_insns[nios2_fpu_nios2_snesf].N >= 0); ++ case GT: ++ return (nios2_fpu_insns[nios2_fpu_nios2_sgtsf].N >= 0); ++ case GE: ++ return (nios2_fpu_insns[nios2_fpu_nios2_sgesf].N >= 0); ++ case LT: ++ return (nios2_fpu_insns[nios2_fpu_nios2_sltsf].N >= 0); ++ case LE: ++ return (nios2_fpu_insns[nios2_fpu_nios2_slesf].N >= 0); ++ default: ++ break; ++ } ++ } ++ else if (cmp_t == CMP_DF) ++ { ++ switch (cond_t) ++ { ++ case EQ: ++ return (nios2_fpu_insns[nios2_fpu_nios2_seqdf].N >= 0); ++ case NE: ++ return (nios2_fpu_insns[nios2_fpu_nios2_snedf].N >= 0); ++ case GT: ++ return (nios2_fpu_insns[nios2_fpu_nios2_sgtdf].N >= 0); ++ case GE: ++ return (nios2_fpu_insns[nios2_fpu_nios2_sgedf].N >= 0); ++ case LT: ++ return (nios2_fpu_insns[nios2_fpu_nios2_sltdf].N >= 0); ++ case LE: ++ return (nios2_fpu_insns[nios2_fpu_nios2_sledf].N >= 0); ++ default: ++ break; ++ } ++ } ++ ++ return false; ++} ++ ++/* Note that get_reverse_cond() is not the same as get_inverse_cond() ++ get_reverse_cond() means that if the operand order is reversed, ++ what is the operand that is needed to generate the same condition? */ ++enum rtx_code ++get_reverse_cond(enum rtx_code cond_t) ++{ ++ switch (cond_t) ++ { ++ case GT: return LT; ++ case GE: return LE; ++ case LT: return GT; ++ case LE: return GE; ++ case GTU: return LTU; ++ case GEU: return LEU; ++ case LTU: return GTU; ++ case LEU: return GEU; ++ default: break; ++ } ++ ++ return cond_t; ++} ++ ++ ++/* Generate the code to compare (and possibly branch) two integer values ++ TEST_CODE is the comparison code we are trying to emulate ++ (or implement directly) ++ RESULT is where to store the result of the comparison, ++ or null to emit a branch ++ CMP0 CMP1 are the two comparison operands ++ DESTINATION is the destination of the branch, or null to only compare. */ ++ ++void ++gen_int_relational (enum rtx_code test_code, /* Relational test (EQ, etc). */ ++ rtx result, /* Result to store comp. or 0 if branch. */ ++ rtx cmp0, /* First operand to compare. */ ++ rtx cmp1, /* Second operand to compare. */ ++ rtx destination) /* Destination of the branch, ++ or 0 if compare. */ ++{ ++ struct cmp_info ++ { ++ /* For register (or 0) compares. */ ++ enum rtx_code test_code_reg; /* Code to use in instruction (LT vs. LTU). */ ++ int reverse_regs; /* Reverse registers in test. */ ++ ++ /* for immediate compares */ ++ enum rtx_code test_code_const; /* Code to use in instruction (LT vs. LTU). */ ++ int const_low; /* Low bound of constant we can accept. */ ++ int const_high; /* High bound of constant we can accept. */ ++ int const_add; /* Constant to add. */ ++ ++ /* generic info */ ++ int unsignedp; /* != 0 for unsigned comparisons. */ ++ }; ++ ++ static const struct cmp_info info[(int) ITEST_MAX] = { ++ ++ {EQ, 0, EQ, -32768, 32767, 0, 0}, /* EQ */ ++ {NE, 0, NE, -32768, 32767, 0, 0}, /* NE */ ++ ++ {LT, 1, GE, -32769, 32766, 1, 0}, /* GT */ ++ {GE, 0, GE, -32768, 32767, 0, 0}, /* GE */ ++ {LT, 0, LT, -32768, 32767, 0, 0}, /* LT */ ++ {GE, 1, LT, -32769, 32766, 1, 0}, /* LE */ ++ ++ {LTU, 1, GEU, 0, 65534, 1, 0}, /* GTU */ ++ {GEU, 0, GEU, 0, 65535, 0, 0}, /* GEU */ ++ {LTU, 0, LTU, 0, 65535, 0, 0}, /* LTU */ ++ {GEU, 1, LTU, 0, 65534, 1, 0}, /* LEU */ ++ }; ++ ++ enum internal_test test; ++ enum machine_mode mode; ++ const struct cmp_info *p_info; ++ int branch_p; ++ ++ ++ test = map_test_to_internal_test (test_code); ++ gcc_assert (test != ITEST_MAX); ++ ++ p_info = &info[(int) test]; ++ ++ mode = GET_MODE (cmp0); ++ if (mode == VOIDmode) ++ mode = GET_MODE (cmp1); ++ ++ branch_p = (destination != 0); ++ ++ /* Handle floating point comparison directly. */ ++ if (branch_type == CMP_SF || branch_type == CMP_DF) ++ { ++ ++ bool reverse_operands = false; ++ ++ enum machine_mode float_mode = (branch_type == CMP_SF) ? SFmode : DFmode; ++ ++ gcc_assert (register_operand (cmp0, float_mode) && ++ register_operand (cmp1, float_mode)); ++ ++ if (branch_p) ++ { ++ test_code = p_info->test_code_reg; ++ reverse_operands = (p_info->reverse_regs); ++ } ++ ++ if (!have_nios2_fpu_cmp_insn(test_code, branch_type) && ++ have_nios2_fpu_cmp_insn(get_reverse_cond(test_code), branch_type) ) ++ { ++ test_code = get_reverse_cond(test_code); ++ reverse_operands = !reverse_operands; ++ } ++ ++ if (reverse_operands) ++ { ++ rtx temp = cmp0; ++ cmp0 = cmp1; ++ cmp1 = temp; ++ } ++ ++ if (branch_p) ++ { ++ rtx cond = gen_rtx_fmt_ee (test_code, SImode, cmp0, cmp1); ++ rtx label = gen_rtx_LABEL_REF (VOIDmode, destination); ++ rtx insn = gen_rtx_SET (VOIDmode, pc_rtx, ++ gen_rtx_IF_THEN_ELSE (VOIDmode, ++ cond, label, pc_rtx)); ++ emit_jump_insn (insn); ++ } ++ else ++ emit_move_insn (result, gen_rtx_fmt_ee (test_code, SImode, cmp0, ++ cmp1)); ++ return; ++ } ++ ++ /* We can't, under any circumstances, have const_ints in cmp0 ++ ??? Actually we could have const0. */ ++ if (GET_CODE (cmp0) == CONST_INT) ++ cmp0 = force_reg (mode, cmp0); ++ ++ /* If the comparison is against an int not in legal range ++ move it into a register. */ ++ if (GET_CODE (cmp1) == CONST_INT) ++ { ++ HOST_WIDE_INT value = INTVAL (cmp1); ++ ++ if (value < p_info->const_low || value > p_info->const_high) ++ cmp1 = force_reg (mode, cmp1); ++ } ++ ++ /* Comparison to constants, may involve adding 1 to change a GT into GE. ++ Comparison between two registers, may involve switching operands. */ ++ if (GET_CODE (cmp1) == CONST_INT) ++ { ++ if (p_info->const_add != 0) ++ { ++ HOST_WIDE_INT new = INTVAL (cmp1) + p_info->const_add; ++ ++ /* If modification of cmp1 caused overflow, ++ we would get the wrong answer if we follow the usual path; ++ thus, x > 0xffffffffU would turn into x > 0U. */ ++ gcc_assert ((p_info->unsignedp ++ ? (unsigned HOST_WIDE_INT) new > ++ (unsigned HOST_WIDE_INT) INTVAL (cmp1) ++ : new > INTVAL (cmp1)) == (p_info->const_add > 0)); ++ ++ cmp1 = GEN_INT (new); ++ } ++ } ++ ++ else if (p_info->reverse_regs) ++ { ++ rtx temp = cmp0; ++ cmp0 = cmp1; ++ cmp1 = temp; ++ } ++ ++ ++ ++ if (branch_p) ++ { ++ if (register_operand (cmp0, mode) && register_operand (cmp1, mode)) ++ { ++ rtx insn; ++ rtx cond = gen_rtx_fmt_ee (p_info->test_code_reg, mode, cmp0, cmp1); ++ rtx label = gen_rtx_LABEL_REF (VOIDmode, destination); ++ ++ insn = gen_rtx_SET (VOIDmode, pc_rtx, ++ gen_rtx_IF_THEN_ELSE (VOIDmode, ++ cond, label, pc_rtx)); ++ emit_jump_insn (insn); ++ } ++ else ++ { ++ rtx cond, label; ++ ++ result = gen_reg_rtx (mode); ++ ++ emit_move_insn (result, ++ gen_rtx_fmt_ee (p_info->test_code_const, mode, cmp0, ++ cmp1)); ++ ++ cond = gen_rtx_NE (mode, result, const0_rtx); ++ label = gen_rtx_LABEL_REF (VOIDmode, destination); ++ ++ emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, ++ gen_rtx_IF_THEN_ELSE (VOIDmode, ++ cond, ++ label, pc_rtx))); ++ } ++ } ++ else ++ { ++ if (register_operand (cmp0, mode) && register_operand (cmp1, mode)) ++ emit_move_insn (result, ++ gen_rtx_fmt_ee (p_info->test_code_reg, mode, cmp0, cmp1)); ++ else ++ emit_move_insn (result, ++ gen_rtx_fmt_ee (p_info->test_code_const, mode, cmp0, ++ cmp1)); ++ } ++ ++} ++ ++ ++/* ??? For now conditional moves are only supported ++ when the mode of the operands being compared are ++ the same as the ones being moved. */ ++ ++void ++gen_conditional_move (rtx *operands, enum machine_mode mode) ++{ ++ rtx insn, cond; ++ rtx cmp_reg = gen_reg_rtx (mode); ++ enum rtx_code cmp_code = GET_CODE (operands[1]); ++ enum rtx_code move_code = EQ; ++ ++ /* Emit a comparison if it is not "simple". ++ Simple comparisons are X eq 0 and X ne 0. */ ++ if ((cmp_code == EQ || cmp_code == NE) && branch_cmp[1] == const0_rtx) ++ { ++ cmp_reg = branch_cmp[0]; ++ move_code = cmp_code; ++ } ++ else if ((cmp_code == EQ || cmp_code == NE) && branch_cmp[0] == const0_rtx) ++ { ++ cmp_reg = branch_cmp[1]; ++ move_code = cmp_code == EQ ? NE : EQ; ++ } ++ else ++ gen_int_relational (cmp_code, cmp_reg, branch_cmp[0], branch_cmp[1], ++ NULL_RTX); ++ ++ cond = gen_rtx_fmt_ee (move_code, VOIDmode, cmp_reg, CONST0_RTX (mode)); ++ insn = gen_rtx_SET (mode, operands[0], ++ gen_rtx_IF_THEN_ELSE (mode, ++ cond, operands[2], operands[3])); ++ emit_insn (insn); ++} ++ ++/******************* ++ * Addressing Modes ++ *******************/ ++ ++int ++nios2_legitimate_constant (rtx x) ++{ ++ switch (GET_CODE (x)) ++ { ++ case SYMBOL_REF: ++ return !SYMBOL_REF_TLS_MODEL (x); ++ case CONST: ++ { ++ rtx op = XEXP (x, 0); ++ if (GET_CODE (op) != PLUS) ++ return false; ++ return nios2_legitimate_constant (XEXP (op, 0)) ++ && nios2_legitimate_constant (XEXP (op, 1)); ++ } ++ default: ++ return true; ++ } ++} ++ ++int ++nios2_legitimate_address (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED, ++ int strict) ++{ ++ int ret_val = 0; ++ ++ switch (GET_CODE (operand)) ++ { ++ /* direct. */ ++ case SYMBOL_REF: ++ if (SYMBOL_REF_TLS_MODEL (operand)) ++ break; ++ ++ if (SYMBOL_REF_IN_NIOS2_SMALL_DATA_P (operand)) ++ { ++ ret_val = 1; ++ break; ++ } ++ /* else, fall through */ ++ case LABEL_REF: ++ case CONST_INT: ++ case CONST: ++ case CONST_DOUBLE: ++ /* ??? In here I need to add gp addressing */ ++ ret_val = 0; ++ ++ break; ++ ++ /* Register indirect. */ ++ case REG: ++ ret_val = REG_OK_FOR_BASE_P2 (operand, strict); ++ break; ++ ++ /* Register indirect with displacement. */ ++ case PLUS: ++ { ++ rtx op0 = XEXP (operand, 0); ++ rtx op1 = XEXP (operand, 1); ++ ++ if (REG_P (op0) && REG_P (op1)) ++ ret_val = 0; ++ else if (REG_P (op0) && GET_CODE (op1) == CONST_INT) ++ ret_val = REG_OK_FOR_BASE_P2 (op0, strict) ++ && SMALL_INT (INTVAL (op1)); ++ else if (REG_P (op1) && GET_CODE (op0) == CONST_INT) ++ ret_val = REG_OK_FOR_BASE_P2 (op1, strict) ++ && SMALL_INT (INTVAL (op0)); ++ else ++ ret_val = 0; ++ } ++ break; ++ ++ default: ++ ret_val = 0; ++ break; ++ } ++ ++ return ret_val; ++} ++ ++/* Return true if EXP should be placed in the small data section. */ ++ ++static bool ++nios2_in_small_data_p (tree exp) ++{ ++ /* We want to merge strings, so we never consider them small data. */ ++ if (TREE_CODE (exp) == STRING_CST) ++ return false; ++ ++ if (TREE_CODE (exp) == VAR_DECL && DECL_SECTION_NAME (exp)) ++ { ++ const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (exp)); ++ /* ??? these string names need moving into ++ an array in some header file */ ++ if (nios2_section_threshold > 0 ++ && (strcmp (section, ".sbss") == 0 ++ || strncmp (section, ".sbss.", 6) == 0 ++ || strcmp (section, ".sdata") == 0 ++ || strncmp (section, ".sdata.", 7) == 0)) ++ return true; ++ } ++ else if (TREE_CODE (exp) == VAR_DECL) ++ { ++ HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp)); ++ ++ /* If this is an incomplete type with size 0, then we can't put it ++ in sdata because it might be too big when completed. */ ++ if (size > 0 && (unsigned HOST_WIDE_INT)size <= nios2_section_threshold) ++ return true; ++ } ++ ++ return false; ++} ++ ++static void ++nios2_encode_section_info (tree decl, rtx rtl, int first) ++{ ++ ++ rtx symbol; ++ int flags; ++ ++ default_encode_section_info (decl, rtl, first); ++ ++ /* Careful not to prod global register variables. */ ++ if (GET_CODE (rtl) != MEM) ++ return; ++ symbol = XEXP (rtl, 0); ++ if (GET_CODE (symbol) != SYMBOL_REF) ++ return; ++ ++ flags = SYMBOL_REF_FLAGS (symbol); ++ ++ /* We don't want weak variables to be addressed with gp in case they end up ++ with value 0 which is not within 2^15 of $gp. */ ++ if (DECL_P (decl) && DECL_WEAK (decl)) ++ flags |= SYMBOL_FLAG_WEAK_DECL; ++ ++ SYMBOL_REF_FLAGS (symbol) = flags; ++} ++ ++ ++static unsigned int ++nios2_section_type_flags (tree decl, const char *name, int reloc) ++{ ++ unsigned int flags; ++ ++ flags = default_section_type_flags (decl, name, reloc); ++ ++ if (strcmp (name, ".sbss") == 0 ++ || strncmp (name, ".sbss.", 6) == 0 ++ || strcmp (name, ".sdata") == 0 ++ || strncmp (name, ".sdata.", 7) == 0) ++ flags |= SECTION_SMALL; ++ ++ return flags; ++} ++ ++/* Handle a #pragma reverse_bitfields. */ ++static void ++nios2_pragma_reverse_bitfields (struct cpp_reader *pfile ATTRIBUTE_UNUSED) ++{ ++ nios2_pragma_reverse_bitfields_flag = 1; /* Reverse */ ++} ++ ++/* Handle a #pragma no_reverse_bitfields. */ ++static void ++nios2_pragma_no_reverse_bitfields (struct cpp_reader *pfile ATTRIBUTE_UNUSED) ++{ ++ nios2_pragma_reverse_bitfields_flag = -1; /* Forward */ ++} ++ ++/* Handle the various #pragma custom_<switch>s. */ ++static void ++nios2_pragma_fpu (int *value, const char *opt, int *seen) ++{ ++ tree t; ++ if (c_lex (&t) != CPP_NUMBER) ++ { ++ error ("`#pragma custom_%s' value must be a number between 0 and 255", ++ opt); ++ return; ++ } ++ ++ if (TREE_INT_CST_HIGH (t) == 0 ++ && TREE_INT_CST_LOW (t) <= 255) ++ { ++ *value = (int)TREE_INT_CST_LOW (t); ++ *seen = 1; ++ } ++ else ++ error ("`#pragma custom_%s' value must be between 0 and 255", opt); ++ nios2_custom_check_insns (1); ++} ++ ++/* Handle the various #pragma no_custom_<switch>s. */ ++static void ++nios2_pragma_no_fpu (int *value, const char *opt ATTRIBUTE_UNUSED) ++{ ++ *value = -1; ++ nios2_custom_check_insns (1); ++} ++ ++#undef NIOS2_FPU_INSN ++#define NIOS2_FPU_INSN(opt, insn, args) \ ++static void \ ++NIOS2_CONCAT (nios2_pragma_, insn) \ ++ (struct cpp_reader *pfile ATTRIBUTE_UNUSED) \ ++{ \ ++ nios2_fpu_info *inf = &(nios2_fpu_insns[NIOS2_CONCAT (nios2_fpu_, insn)]); \ ++ nios2_pragma_fpu (&(inf->N), inf->option, &(inf->pragma_seen)); \ ++} \ ++static void \ ++NIOS2_CONCAT (nios2_pragma_no_, insn) \ ++ (struct cpp_reader *pfile ATTRIBUTE_UNUSED) \ ++{ \ ++ nios2_fpu_info *inf = &(nios2_fpu_insns[NIOS2_CONCAT (nios2_fpu_, insn)]); \ ++ nios2_pragma_no_fpu (&(inf->N), inf->option); \ ++} ++NIOS2_FOR_ALL_FPU_INSNS ++ ++static void ++nios2_pragma_handle_custom_fpu_cfg (struct cpp_reader *pfile ATTRIBUTE_UNUSED) ++{ ++ tree t; ++ if (c_lex (&t) != CPP_STRING) ++ { ++ error ("`#pragma custom_fpu_cfg' value must be a string"); ++ return; ++ } ++ ++ if (TREE_STRING_LENGTH (t) > 0) ++ nios2_handle_custom_fpu_cfg (TREE_STRING_POINTER (t), 1); ++} ++ ++void ++nios2_register_target_pragmas (void) ++{ ++ int i; ++ ++ c_register_pragma (0, "reverse_bitfields", ++ nios2_pragma_reverse_bitfields); ++ c_register_pragma (0, "no_reverse_bitfields", ++ nios2_pragma_no_reverse_bitfields); ++ ++ for (i = 0; i < nios2_fpu_max_insn; i++) ++ { ++ nios2_fpu_info *inf = &(nios2_fpu_insns[i]); ++ c_register_pragma (0, inf->pname, inf->pragma); ++ c_register_pragma (0, inf->nopname, inf->nopragma); ++ } ++ ++ c_register_pragma (0, "custom_fpu_cfg", ++ nios2_pragma_handle_custom_fpu_cfg); ++} ++ ++/* Handle a "reverse_bitfields" or "no_reverse_bitfields" attribute. ++ ??? What do these attributes mean on a union? */ ++static tree ++nios2_handle_struct_attribute (tree *node, tree name, ++ tree args ATTRIBUTE_UNUSED, ++ int flags ATTRIBUTE_UNUSED, ++ bool *no_add_attrs) ++{ ++ tree *type = NULL; ++ if (DECL_P (*node)) ++ { ++ if (TREE_CODE (*node) == TYPE_DECL) ++ type = &TREE_TYPE (*node); ++ } ++ else ++ type = node; ++ ++ if (!(type && (TREE_CODE (*type) == RECORD_TYPE ++ || TREE_CODE (*type) == UNION_TYPE))) ++ { ++ warning (0, "`%s' attribute ignored", IDENTIFIER_POINTER (name)); ++ *no_add_attrs = true; ++ } ++ ++ else if ((is_attribute_p ("reverse_bitfields", name) ++ && lookup_attribute ("no_reverse_bitfields", ++ TYPE_ATTRIBUTES (*type))) ++ || ((is_attribute_p ("no_reverse_bitfields", name) ++ && lookup_attribute ("reverse_bitfields", ++ TYPE_ATTRIBUTES (*type))))) ++ { ++ warning (0, "`%s' incompatible attribute ignored", ++ IDENTIFIER_POINTER (name)); ++ *no_add_attrs = true; ++ } ++ ++ return NULL_TREE; ++} ++ ++/* Add __attribute__ ((pragma_reverse_bitfields)) when in the scope of a ++ #pragma reverse_bitfields, or __attribute__ ++ ((pragma_no_reverse_bitfields)) when in the scope of a #pragma ++ no_reverse_bitfields. This gets called before ++ nios2_handle_struct_attribute above, so we can't just reuse the same ++ attributes. */ ++static void ++nios2_insert_attributes (tree node, tree *attr_ptr) ++{ ++ tree type = NULL; ++ if (DECL_P (node)) ++ { ++ if (TREE_CODE (node) == TYPE_DECL) ++ type = TREE_TYPE (node); ++ } ++ else ++ type = node; ++ ++ if (!type ++ || (TREE_CODE (type) != RECORD_TYPE ++ && TREE_CODE (type) != UNION_TYPE)) ++ { ++ /* We can ignore things other than structs & unions. */ ++ return; ++ } ++ ++ if (lookup_attribute ("reverse_bitfields", TYPE_ATTRIBUTES (type)) ++ || lookup_attribute ("no_reverse_bitfields", TYPE_ATTRIBUTES (type))) ++ { ++ /* If an attribute is already set, it silently overrides the ++ current #pragma, if any. */ ++ return; ++ } ++ ++ if (nios2_pragma_reverse_bitfields_flag) ++ { ++ const char *id = (nios2_pragma_reverse_bitfields_flag == 1 ? ++ "pragma_reverse_bitfields" : ++ "pragma_no_reverse_bitfields"); ++ /* No attribute set, and we are in the scope of a #pragma. */ ++ *attr_ptr = tree_cons (get_identifier (id), NULL, *attr_ptr); ++ } ++} ++ ++/***************************************** ++ * Position Independent Code ++ *****************************************/ ++ ++/* Emit code to load the PIC register. */ ++ ++static void ++nios2_load_pic_register (void) ++{ ++ rtx tmp = gen_rtx_REG (Pmode, TEMP_REG_NUM); ++ ++ emit_insn (gen_load_got_register (pic_offset_table_rtx, tmp)); ++ emit_insn (gen_add3_insn (pic_offset_table_rtx, pic_offset_table_rtx, tmp)); ++} ++ ++/* 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. */ ++ ++bool ++nios2_legitimate_pic_operand_p (rtx x) ++{ ++ rtx inner; ++ ++ /* UNSPEC_TLS is always PIC. */ ++ if (tls_mentioned_p (x)) ++ return true; ++ ++ if (GET_CODE (x) == SYMBOL_REF) ++ return false; ++ if (GET_CODE (x) == LABEL_REF) ++ return false; ++ if (GET_CODE (x) == CONST) ++ { ++ inner = XEXP (x, 0); ++ if (GET_CODE (inner) == PLUS && ++ GET_CODE (XEXP (inner, 0)) == SYMBOL_REF && ++ GET_CODE (XEXP (inner, 1)) == CONST) ++ return false; ++ } ++ return true; ++} ++ ++rtx ++nios2_legitimize_pic_address (rtx orig, ++ enum machine_mode mode ATTRIBUTE_UNUSED, rtx reg) ++{ ++ if (GET_CODE (orig) == SYMBOL_REF ++ || GET_CODE (orig) == LABEL_REF) ++ { ++ if (reg == 0) ++ { ++ gcc_assert (!no_new_pseudos); ++ reg = gen_reg_rtx (Pmode); ++ } ++ ++ emit_insn (gen_pic_load_addr (reg, pic_offset_table_rtx, orig)); ++ ++ current_function_uses_pic_offset_table = 1; ++ ++ return reg; ++ } ++ else if (GET_CODE (orig) == CONST) ++ { ++ rtx base, offset; ++ ++ if (GET_CODE (XEXP (orig, 0)) == PLUS ++ && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx) ++ return orig; ++ ++ if (GET_CODE (XEXP (orig, 0)) == UNSPEC ++ && IS_UNSPEC_TLS (XINT (XEXP (orig, 0), 1))) ++ return orig; ++ ++ if (reg == 0) ++ { ++ gcc_assert (!no_new_pseudos); ++ reg = gen_reg_rtx (Pmode); ++ } ++ ++ gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS); ++ ++ base = nios2_legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, ++ reg); ++ offset = nios2_legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode, ++ base == reg ? 0 : reg); ++ ++ if (GET_CODE (offset) == CONST_INT) ++ return plus_constant (base, INTVAL (offset)); ++ ++ return gen_rtx_PLUS (Pmode, base, offset); ++ } ++ ++ return orig; ++} ++ ++/* Test for various thread-local symbols. */ ++ ++/* Return TRUE if X is a thread-local symbol. */ ++ ++static bool ++nios2_tls_symbol_p (rtx x) ++{ ++ if (! TARGET_HAVE_TLS) ++ return false; ++ ++ if (GET_CODE (x) != SYMBOL_REF) ++ return false; ++ ++ return SYMBOL_REF_TLS_MODEL (x) != 0; ++} ++ ++rtx ++nios2_legitimize_address (rtx x, rtx orig_x, enum machine_mode mode) ++{ ++ if (nios2_tls_symbol_p (x)) ++ return nios2_legitimize_tls_address (x); ++ ++ if (flag_pic) ++ { ++ /* We need to find and carefully transform any SYMBOL and LABEL ++ references; so go back to the original address expression. */ ++ rtx new_x = nios2_legitimize_pic_address (orig_x, mode, NULL_RTX); ++ ++ if (new_x != orig_x) ++ x = new_x; ++ } ++ ++ return x; ++} ++ ++/***************************************** ++ * Defining the Output Assembler Language ++ *****************************************/ ++ ++/* -------------- * ++ * Output of Data ++ * -------------- */ ++ ++ ++/* -------------------------------- * ++ * Output of Assembler Instructions ++ * -------------------------------- */ ++ ++ ++/* print the operand OP to file stream ++ FILE modified by LETTER. LETTER ++ can be one of: ++ i: print "i" if OP is an immediate, except 0 ++ o: print "io" if OP is volatile ++ ++ z: for const0_rtx print $0 instead of 0 ++ H: for %hiadj ++ L: for %lo ++ U: for upper half of 32 bit value ++ D: for the upper 32-bits of a 64-bit double value ++ */ ++ ++void ++nios2_print_operand (FILE *file, rtx op, int letter) ++{ ++ ++ switch (letter) ++ { ++ case 'i': ++ if (CONSTANT_P (op) && (op != const0_rtx)) ++ fprintf (file, "i"); ++ return; ++ ++ case 'o': ++ if (GET_CODE (op) == MEM && TARGET_BYPASS_CACHE) ++ fprintf (file, "io"); ++ return; ++ ++ default: ++ break; ++ } ++ ++ if (comparison_operator (op, VOIDmode)) ++ { ++ if (letter == 0) ++ { ++ fprintf (file, "%s", GET_RTX_NAME (GET_CODE (op))); ++ return; ++ } ++ } ++ ++ ++ switch (GET_CODE (op)) ++ { ++ case REG: ++ if (letter == 0 || letter == 'z') ++ { ++ fprintf (file, "%s", reg_names[REGNO (op)]); ++ return; ++ } ++ else if (letter == 'D') ++ { ++ fprintf (file, "%s", reg_names[REGNO (op)+1]); ++ return; ++ } ++ break; ++ ++ case CONST_INT: ++ if (INTVAL (op) == 0 && letter == 'z') ++ { ++ fprintf (file, "zero"); ++ return; ++ } ++ else if (letter == 'U') ++ { ++ HOST_WIDE_INT val = INTVAL (op); ++ rtx new_op; ++ val = (val / 65536) & 0xFFFF; ++ new_op = GEN_INT (val); ++ output_addr_const (file, new_op); ++ return; ++ } ++ ++ /* else, fall through. */ ++ case CONST: ++ case LABEL_REF: ++ case SYMBOL_REF: ++ case CONST_DOUBLE: ++ if (letter == 0 || letter == 'z') ++ { ++ output_addr_const (file, op); ++ return; ++ } ++ else if (letter == 'H') ++ { ++ fprintf (file, "%%hiadj("); ++ output_addr_const (file, op); ++ fprintf (file, ")"); ++ return; ++ } ++ else if (letter == 'L') ++ { ++ fprintf (file, "%%lo("); ++ output_addr_const (file, op); ++ fprintf (file, ")"); ++ return; ++ } ++ break; ++ ++ ++ case SUBREG: ++ case MEM: ++ if (letter == 0) ++ { ++ output_address (op); ++ return; ++ } ++ break; ++ ++ case CODE_LABEL: ++ if (letter == 0) ++ { ++ output_addr_const (file, op); ++ return; ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ fprintf (stderr, "Missing way to print (%c) ", letter); ++ debug_rtx (op); ++ gcc_unreachable (); ++} ++ ++static int gprel_constant (rtx); ++ ++static int ++gprel_constant (rtx op) ++{ ++ if (GET_CODE (op) == SYMBOL_REF ++ && SYMBOL_REF_IN_NIOS2_SMALL_DATA_P (op)) ++ return 1; ++ else if (GET_CODE (op) == CONST ++ && GET_CODE (XEXP (op, 0)) == PLUS) ++ return gprel_constant (XEXP (XEXP (op, 0), 0)); ++ else ++ return 0; ++} ++ ++void ++nios2_print_operand_address (FILE *file, rtx op) ++{ ++ switch (GET_CODE (op)) ++ { ++ case CONST: ++ case CONST_INT: ++ case LABEL_REF: ++ case CONST_DOUBLE: ++ case SYMBOL_REF: ++ if (gprel_constant (op)) ++ { ++ fprintf (file, "%%gprel("); ++ output_addr_const (file, op); ++ fprintf (file, ")(%s)", reg_names[GP_REGNO]); ++ return; ++ } ++ ++ break; ++ ++ case PLUS: ++ { ++ rtx op0 = XEXP (op, 0); ++ rtx op1 = XEXP (op, 1); ++ ++ if (REG_P (op0) && CONSTANT_P (op1)) ++ { ++ output_addr_const (file, op1); ++ fprintf (file, "(%s)", reg_names[REGNO (op0)]); ++ return; ++ } ++ else if (REG_P (op1) && CONSTANT_P (op0)) ++ { ++ output_addr_const (file, op0); ++ fprintf (file, "(%s)", reg_names[REGNO (op1)]); ++ return; ++ } ++ } ++ break; ++ ++ case REG: ++ fprintf (file, "0(%s)", reg_names[REGNO (op)]); ++ return; ++ ++ case MEM: ++ { ++ rtx base = XEXP (op, 0); ++ PRINT_OPERAND_ADDRESS (file, base); ++ return; ++ } ++ default: ++ break; ++ } ++ ++ fprintf (stderr, "Missing way to print address\n"); ++ debug_rtx (op); ++ gcc_unreachable (); ++} ++ ++ ++ ++/**************************** ++ * Debug information ++ ****************************/ ++ ++static void ++nios2_output_dwarf_dtprel (FILE *file, int size, rtx x) ++{ ++ gcc_assert (size == 4); ++ fputs ("\t.4byte\t%tls_ldo(", file); ++ output_addr_const (file, x); ++ fputs (")", file); ++} ++ ++ ++/**************************** ++ * Predicates ++ ****************************/ ++ ++/* An operand to a call or sibcall. This must be an immediate operand ++ or a register. */ ++int ++call_operand (rtx x, enum machine_mode mode) ++{ ++ return (immediate_operand (x, mode) ++ || register_operand (x, mode)); ++} ++ ++int ++arith_operand (rtx op, enum machine_mode mode) ++{ ++ if (GET_CODE (op) == CONST_INT && SMALL_INT (INTVAL (op))) ++ return 1; ++ ++ return register_operand (op, mode); ++} ++ ++int ++uns_arith_operand (rtx op, enum machine_mode mode) ++{ ++ if (GET_CODE (op) == CONST_INT && SMALL_INT_UNSIGNED (INTVAL (op))) ++ return 1; ++ ++ return register_operand (op, mode); ++} ++ ++int ++logical_operand (rtx op, enum machine_mode mode) ++{ ++ if (GET_CODE (op) == CONST_INT ++ && (SMALL_INT_UNSIGNED (INTVAL (op)) || UPPER16_INT (INTVAL (op)))) ++ return 1; ++ ++ return register_operand (op, mode); ++} ++ ++int ++shift_operand (rtx op, enum machine_mode mode) ++{ ++ if (GET_CODE (op) == CONST_INT && SHIFT_INT (INTVAL (op))) ++ return 1; ++ ++ return register_operand (op, mode); ++} ++ ++int ++rdwrctl_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) ++{ ++ return GET_CODE (op) == CONST_INT && RDWRCTL_INT (INTVAL (op)); ++} ++ ++/* Return truth value of whether OP is a register or the constant 0. */ ++ ++int ++reg_or_0_operand (rtx op, enum machine_mode mode) ++{ ++ switch (GET_CODE (op)) ++ { ++ case CONST_INT: ++ return INTVAL (op) == 0; ++ ++ case CONST_DOUBLE: ++ return op == CONST0_RTX (mode); ++ ++ default: ++ break; ++ } ++ ++ return register_operand (op, mode); ++} ++ ++ ++int ++equality_op (rtx op, enum machine_mode mode) ++{ ++ if (mode != GET_MODE (op)) ++ return 0; ++ ++ return GET_CODE (op) == EQ || GET_CODE (op) == NE; ++} ++ ++int ++custom_insn_opcode (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) ++{ ++ return GET_CODE (op) == CONST_INT && CUSTOM_INSN_OPCODE (INTVAL (op)); ++} ++ ++ ++ ++ ++/***************************************************************************** ++** ++** custom fpu instruction output ++** ++*****************************************************************************/ ++ ++static const char *nios2_custom_fpu_insn_zdz (rtx, int, const char *); ++static const char *nios2_custom_fpu_insn_zsz (rtx, int, const char *); ++static const char *nios2_custom_fpu_insn_szz (rtx, int, const char *); ++static const char *nios2_custom_fpu_insn_sss (rtx, int, const char *); ++static const char *nios2_custom_fpu_insn_ssz (rtx, int, const char *); ++static const char *nios2_custom_fpu_insn_iss (rtx, int, const char *); ++static const char *nios2_custom_fpu_insn_ddd (rtx, int, const char *); ++static const char *nios2_custom_fpu_insn_ddz (rtx, int, const char *); ++static const char *nios2_custom_fpu_insn_idd (rtx, int, const char *); ++static const char *nios2_custom_fpu_insn_siz (rtx, int, const char *); ++static const char *nios2_custom_fpu_insn_suz (rtx, int, const char *); ++static const char *nios2_custom_fpu_insn_diz (rtx, int, const char *); ++static const char *nios2_custom_fpu_insn_duz (rtx, int, const char *); ++static const char *nios2_custom_fpu_insn_isz (rtx, int, const char *); ++static const char *nios2_custom_fpu_insn_usz (rtx, int, const char *); ++static const char *nios2_custom_fpu_insn_idz (rtx, int, const char *); ++static const char *nios2_custom_fpu_insn_udz (rtx, int, const char *); ++static const char *nios2_custom_fpu_insn_dsz (rtx, int, const char *); ++static const char *nios2_custom_fpu_insn_sdz (rtx, int, const char *); ++ ++static const char * ++nios2_custom_fpu_insn_zdz (rtx insn, int N, const char *opt) ++{ ++ static char buf[1024]; ++ ++ if (N < 0) ++ fatal_insn ("attempt to use disabled fpu instruction", insn); ++ if (snprintf (buf, sizeof (buf), ++ "custom\t%d, zero, %%0, %%D0 # %s %%0", ++ N, opt) >= (int)sizeof (buf)) ++ fatal_insn ("buffer overflow", insn); ++ return buf; ++} ++ ++static const char * ++nios2_custom_fpu_insn_zsz (rtx insn, int N, const char *opt) ++{ ++ static char buf[1024]; ++ ++ if (N < 0) ++ fatal_insn ("attempt to use disabled fpu instruction", insn); ++ if (snprintf (buf, sizeof (buf), ++ "custom\t%d, zero, %%0, zero # %s %%0", ++ N, opt) >= (int)sizeof (buf)) ++ fatal_insn ("buffer overflow", insn); ++ return buf; ++} ++ ++static const char * ++nios2_custom_fpu_insn_szz (rtx insn, int N, const char *opt) ++{ ++ static char buf[1024]; ++ ++ if (N < 0) ++ fatal_insn ("attempt to use disabled fpu instruction", insn); ++ if (snprintf (buf, sizeof (buf), ++ "custom\t%d, %%0, zero, zero # %s %%0", ++ N, opt) >= (int)sizeof (buf)) ++ fatal_insn ("buffer overflow", insn); ++ return buf; ++} ++ ++static const char * ++nios2_custom_fpu_insn_sss (rtx insn, int N, const char *opt) ++{ ++ static char buf[1024]; ++ ++ if (N < 0) ++ fatal_insn ("attempt to use disabled fpu instruction", insn); ++ if (snprintf (buf, sizeof (buf), ++ "custom\t%d, %%0, %%1, %%2 # %s %%0, %%1, %%2", ++ N, opt) >= (int)sizeof (buf)) ++ fatal_insn ("buffer overflow", insn); ++ return buf; ++} ++ ++static const char * ++nios2_custom_fpu_insn_ssz (rtx insn, int N, const char *opt) ++{ ++ static char buf[1024]; ++ ++ if (N < 0) ++ fatal_insn ("attempt to use disabled fpu instruction", insn); ++ if (snprintf (buf, sizeof (buf), ++ "custom\t%d, %%0, %%1, zero # %s %%0, %%1", ++ N, opt) >= (int)sizeof (buf)) ++ fatal_insn ("buffer overflow", insn); ++ return buf; ++} ++ ++static const char * ++nios2_custom_fpu_insn_iss (rtx insn, int N, const char *opt) ++{ ++ return nios2_custom_fpu_insn_sss (insn, N, opt); ++} ++ ++static const char * ++nios2_custom_fpu_insn_ddd (rtx insn, int N, const char *opt) ++{ ++ static char buf[1024]; ++ ++ if (N < 0 ++ || nios2_fpu_insns[nios2_fpu_nios2_frdy].N < 0 ++ || nios2_fpu_insns[nios2_fpu_nios2_fwrx].N < 0) ++ fatal_insn ("attempt to use disabled fpu instruction", insn); ++ if (snprintf (buf, sizeof (buf), ++ "custom\t%d, zero, %%1, %%D1 # fwrx %%1\n\t" ++ "custom\t%d, %%D0, %%2, %%D2 # %s %%0, %%1, %%2\n\t" ++ "custom\t%d, %%0, zero, zero # frdy %%0", ++ nios2_fpu_insns[nios2_fpu_nios2_fwrx].N, ++ N, opt, ++ nios2_fpu_insns[nios2_fpu_nios2_frdy].N) >= (int)sizeof (buf)) ++ fatal_insn ("buffer overflow", insn); ++ return buf; ++} ++ ++static const char * ++nios2_custom_fpu_insn_ddz (rtx insn, int N, const char *opt) ++{ ++ static char buf[1024]; ++ ++ if (N < 0 || nios2_fpu_insns[nios2_fpu_nios2_frdy].N < 0) ++ fatal_insn ("attempt to use disabled fpu instruction", insn); ++ if (snprintf (buf, sizeof (buf), ++ "custom\t%d, %%D0, %%1, %%D1 # %s %%0, %%1\n\t" ++ "custom\t%d, %%0, zero, zero # frdy %%0", ++ N, opt, ++ nios2_fpu_insns[nios2_fpu_nios2_frdy].N) >= (int)sizeof (buf)) ++ fatal_insn ("buffer overflow", insn); ++ return buf; ++} ++ ++static const char * ++nios2_custom_fpu_insn_idd (rtx insn, int N, const char *opt) ++{ ++ static char buf[1024]; ++ ++ if (N < 0 || nios2_fpu_insns[nios2_fpu_nios2_fwrx].N < 0) ++ fatal_insn ("attempt to use disabled fpu instruction", insn); ++ if (snprintf (buf, sizeof (buf), ++ "custom\t%d, zero, %%1, %%D1 # fwrx %%1\n\t" ++ "custom\t%d, %%0, %%2, %%D2 # %s %%0, %%1, %%2", ++ nios2_fpu_insns[nios2_fpu_nios2_fwrx].N, ++ N, opt) >= (int)sizeof (buf)) ++ fatal_insn ("buffer overflow", insn); ++ return buf; ++} ++ ++static const char * ++nios2_custom_fpu_insn_siz (rtx insn, int N, const char *opt) ++{ ++ return nios2_custom_fpu_insn_ssz (insn, N, opt); ++} ++ ++static const char * ++nios2_custom_fpu_insn_suz (rtx insn, int N, const char *opt) ++{ ++ return nios2_custom_fpu_insn_ssz (insn, N, opt); ++} ++ ++static const char * ++nios2_custom_fpu_insn_diz (rtx insn, int N, const char *opt) ++{ ++ return nios2_custom_fpu_insn_dsz (insn, N, opt); ++} ++ ++static const char * ++nios2_custom_fpu_insn_duz (rtx insn, int N, const char *opt) ++{ ++ return nios2_custom_fpu_insn_dsz (insn, N, opt); ++} ++ ++static const char * ++nios2_custom_fpu_insn_isz (rtx insn, int N, const char *opt) ++{ ++ return nios2_custom_fpu_insn_ssz (insn, N, opt); ++} ++ ++static const char * ++nios2_custom_fpu_insn_usz (rtx insn, int N, const char *opt) ++{ ++ return nios2_custom_fpu_insn_ssz (insn, N, opt); ++} ++ ++static const char * ++nios2_custom_fpu_insn_idz (rtx insn, int N, const char *opt) ++{ ++ return nios2_custom_fpu_insn_sdz (insn, N, opt); ++} ++ ++static const char * ++nios2_custom_fpu_insn_udz (rtx insn, int N, const char *opt) ++{ ++ return nios2_custom_fpu_insn_sdz (insn, N, opt); ++} ++ ++static const char * ++nios2_custom_fpu_insn_dsz (rtx insn, int N, const char *opt) ++{ ++ static char buf[1024]; ++ ++ if (N < 0 || nios2_fpu_insns[nios2_fpu_nios2_frdy].N < 0) ++ fatal_insn ("attempt to use disabled fpu instruction", insn); ++ if (snprintf (buf, sizeof (buf), ++ "custom\t%d, %%D0, %%1, zero # %s %%0, %%1\n\t" ++ "custom\t%d, %%0, zero, zero # frdy %%0", ++ N, opt, ++ nios2_fpu_insns[nios2_fpu_nios2_frdy].N) >= (int)sizeof (buf)) ++ fatal_insn ("buffer overflow", insn); ++ return buf; ++} ++ ++static const char * ++nios2_custom_fpu_insn_sdz (rtx insn, int N, const char *opt) ++{ ++ static char buf[1024]; ++ ++ if (N < 0) ++ fatal_insn ("attempt to use disabled fpu instruction", insn); ++ if (snprintf (buf, sizeof (buf), ++ "custom\t%d, %%0, %%1, %%D1 # %s %%0, %%1", ++ N, opt) >= (int)sizeof (buf)) ++ fatal_insn ("buffer overflow", insn); ++ return buf; ++} ++ ++#undef NIOS2_FPU_INSN ++#define NIOS2_FPU_INSN(opt, insn, args) \ ++static const char * \ ++NIOS2_CONCAT (nios2_output_fpu_insn_, insn) (rtx i) \ ++{ \ ++ return NIOS2_CONCAT (nios2_custom_fpu_insn_, args) \ ++ (i, \ ++ nios2_fpu_insns[NIOS2_CONCAT (nios2_fpu_, insn)].N, \ ++ nios2_fpu_insns[NIOS2_CONCAT (nios2_fpu_, insn)].option); \ ++} ++NIOS2_FOR_ALL_FPU_INSNS ++ ++ ++ ++const char * ++nios2_output_fpu_insn_cmps (rtx insn, enum rtx_code cond) ++{ ++ static char buf[1024]; ++ int N; ++ const char *opt; ++ ++ int operandL = 2; ++ int operandR = 3; ++ ++ if (!have_nios2_fpu_cmp_insn(cond, CMP_SF) && ++ have_nios2_fpu_cmp_insn(get_reverse_cond(cond), CMP_SF) ) { ++ ++ int temp = operandL; ++ operandL = operandR; ++ operandR = temp; ++ ++ cond = get_reverse_cond(cond); ++ } ++ ++ switch (cond) ++ { ++ case EQ: ++ N = nios2_fpu_insns[nios2_fpu_nios2_seqsf].N; ++ opt = "fcmpeqs"; ++ break; ++ case NE: ++ N = nios2_fpu_insns[nios2_fpu_nios2_snesf].N; ++ opt = "fcmpnes"; ++ break; ++ case GT: ++ N = nios2_fpu_insns[nios2_fpu_nios2_sgtsf].N; ++ opt = "fcmpgts"; ++ break; ++ case GE: ++ N = nios2_fpu_insns[nios2_fpu_nios2_sgesf].N; ++ opt = "fcmpges"; ++ break; ++ case LT: ++ N = nios2_fpu_insns[nios2_fpu_nios2_sltsf].N; ++ opt = "fcmplts"; ++ break; ++ case LE: ++ N = nios2_fpu_insns[nios2_fpu_nios2_slesf].N; ++ opt = "fcmples"; break; ++ default: ++ fatal_insn ("bad single compare", insn); ++ } ++ ++ if (N < 0) ++ fatal_insn ("attempt to use disabled fpu instruction", insn); ++ ++ /* ??? This raises the whole vexing issue of how to handle ++ out-of-range branches. Punt for now, seeing as how nios2-elf-as ++ doesn't even _try_ to handle out-of-range branches yet! */ ++ if (snprintf (buf, sizeof (buf), ++ ".set\tnoat\n\t" ++ "custom\t%d, at, %%%d, %%%d # %s at, %%%d, %%%d\n\t" ++ "bne\tat, zero, %%l1\n\t" ++ ".set\tat", ++ N, operandL, operandR, opt, operandL, operandR ++ ) >= (int)sizeof (buf)) ++ fatal_insn ("buffer overflow", insn); ++ return buf; ++} ++ ++const char * ++nios2_output_fpu_insn_cmpd (rtx insn, enum rtx_code cond) ++{ ++ static char buf[1024]; ++ int N; ++ const char *opt; ++ ++ int operandL = 2; ++ int operandR = 3; ++ ++ if ( !have_nios2_fpu_cmp_insn(cond, CMP_DF) && ++ have_nios2_fpu_cmp_insn(get_reverse_cond(cond), CMP_DF) ) ++ { ++ ++ int temp = operandL; ++ operandL = operandR; ++ operandR = temp; ++ ++ cond = get_reverse_cond(cond); ++ } ++ ++ switch (cond) ++ { ++ case EQ: ++ N = nios2_fpu_insns[nios2_fpu_nios2_seqdf].N; ++ opt = "fcmpeqd"; ++ break; ++ case NE: ++ N = nios2_fpu_insns[nios2_fpu_nios2_snedf].N; ++ opt = "fcmpned"; ++ break; ++ case GT: ++ N = nios2_fpu_insns[nios2_fpu_nios2_sgtdf].N; ++ opt = "fcmpgtd"; ++ break; ++ case GE: ++ N = nios2_fpu_insns[nios2_fpu_nios2_sgedf].N; ++ opt = "fcmpged"; ++ break; ++ case LT: ++ N = nios2_fpu_insns[nios2_fpu_nios2_sltdf].N; ++ opt = "fcmpltd"; ++ break; ++ case LE: ++ N = nios2_fpu_insns[nios2_fpu_nios2_sledf].N; ++ opt = "fcmpled"; ++ break; ++ default: ++ fatal_insn ("bad double compare", insn); ++ } ++ ++ if (N < 0 || nios2_fpu_insns[nios2_fpu_nios2_fwrx].N < 0) ++ fatal_insn ("attempt to use disabled fpu instruction", insn); ++ if (snprintf (buf, sizeof (buf), ++ ".set\tnoat\n\t" ++ "custom\t%d, zero, %%%d, %%D%d # fwrx %%%d\n\t" ++ "custom\t%d, at, %%%d, %%D%d # %s at, %%%d, %%%d\n\t" ++ "bne\tat, zero, %%l1\n\t" ++ ".set\tat", ++ nios2_fpu_insns[nios2_fpu_nios2_fwrx].N, operandL, operandL, ++ operandL, N, operandR, operandR, opt, operandL, operandR ++ ) >= (int)sizeof (buf)) ++ fatal_insn ("buffer overflow", insn); ++ return buf; ++} ++ ++ ++ ++ ++/***************************************************************************** ++** ++** Instruction scheduler ++** ++*****************************************************************************/ ++static int ++nios2_issue_rate (void) ++{ ++#ifdef MAX_DFA_ISSUE_RATE ++ return MAX_DFA_ISSUE_RATE; ++#else ++ return 1; ++#endif ++} ++ ++ ++const char * ++asm_output_opcode (FILE *file ATTRIBUTE_UNUSED, ++ const char *ptr ATTRIBUTE_UNUSED) ++{ ++ const char *p; ++ ++ p = ptr; ++ return ptr; ++} ++ ++ ++ ++/***************************************************************************** ++** ++** Function arguments ++** ++*****************************************************************************/ ++ ++void ++init_cumulative_args (CUMULATIVE_ARGS *cum, ++ tree fntype ATTRIBUTE_UNUSED, ++ rtx libname ATTRIBUTE_UNUSED, ++ tree fndecl ATTRIBUTE_UNUSED, ++ int n_named_args ATTRIBUTE_UNUSED) ++{ ++ cum->regs_used = 0; ++} ++ ++ ++/* 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). */ ++rtx ++function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode, ++ tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED) ++{ ++ rtx return_rtx = NULL_RTX; ++ ++ if (cum->regs_used < NUM_ARG_REGS) ++ return_rtx = gen_rtx_REG (mode, FIRST_ARG_REGNO + cum->regs_used); ++ ++ return return_rtx; ++} ++ ++/* Return number of bytes, at the beginning of the argument, that must be ++ put in registers. 0 is the argument is entirely in registers or entirely ++ in memory. */ ++ ++static int ++nios2_arg_partial_bytes (CUMULATIVE_ARGS *cum, ++ enum machine_mode mode, tree type, ++ bool named ATTRIBUTE_UNUSED) ++{ ++ HOST_WIDE_INT param_size; ++ ++ if (mode == BLKmode) ++ { ++ param_size = int_size_in_bytes (type); ++ if (param_size < 0) ++ internal_error ++ ("Do not know how to handle large structs or variable length types"); ++ } ++ else ++ param_size = GET_MODE_SIZE (mode); ++ ++ /* Convert to words (round up). */ ++ param_size = (3 + param_size) / 4; ++ ++ if (cum->regs_used < NUM_ARG_REGS ++ && cum->regs_used + param_size > NUM_ARG_REGS) ++ return (NUM_ARG_REGS - cum->regs_used) * UNITS_PER_WORD; ++ else ++ return 0; ++} ++ ++static bool ++nios2_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ tree type ATTRIBUTE_UNUSED, ++ bool named ATTRIBUTE_UNUSED) ++{ ++ return false; ++} ++ ++ ++/* 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.) */ ++ ++void ++function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, ++ tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED) ++{ ++ HOST_WIDE_INT param_size; ++ ++ if (mode == BLKmode) ++ { ++ param_size = int_size_in_bytes (type); ++ if (param_size < 0) ++ internal_error ++ ("Do not know how to handle large structs or variable length types"); ++ } ++ else ++ param_size = GET_MODE_SIZE (mode); ++ ++ /* Convert to words (round up). */ ++ param_size = (3 + param_size) / 4; ++ ++ if (cum->regs_used + param_size > NUM_ARG_REGS) ++ cum->regs_used = NUM_ARG_REGS; ++ else ++ cum->regs_used += param_size; ++ ++ return; ++} ++ ++int ++nios2_function_arg_padding_upward (enum machine_mode mode, tree type) ++{ ++ /* On little-endian targets, the first byte of every stack argument ++ is passed in the first byte of the stack slot. */ ++ if (!BYTES_BIG_ENDIAN) ++ return 1; ++ ++ /* Otherwise, integral types are padded downward: the last byte of a ++ stack argument is passed in the last byte of the stack slot. */ ++ if (type != 0 ++ ? INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type) ++ : GET_MODE_CLASS (mode) == MODE_INT) ++ return 0; ++ ++ /* Arguments smaller than a stack slot are padded downward. */ ++ if (mode != BLKmode) ++ return (GET_MODE_BITSIZE (mode) >= PARM_BOUNDARY) ? 1 : 0; ++ else ++ return ((int_size_in_bytes (type) >= (PARM_BOUNDARY / BITS_PER_UNIT)) ++ ? 1 : 0); ++} ++ ++int ++nios2_block_reg_padding_upward (enum machine_mode mode, tree type, ++ int first ATTRIBUTE_UNUSED) ++{ ++ /* ??? Do we need to treat floating point specially, ala MIPS? */ ++ return nios2_function_arg_padding_upward (mode, type); ++} ++ ++int ++nios2_return_in_memory (tree type) ++{ ++ int res = ((int_size_in_bytes (type) > (2 * UNITS_PER_WORD)) ++ || (int_size_in_bytes (type) == -1)); ++ ++ return res; ++} ++ ++/* ??? It may be possible to eliminate the copyback and implement ++ my own va_arg type, but that is more work for now. */ ++void ++nios2_setup_incoming_varargs (CUMULATIVE_ARGS *cum, ++ enum machine_mode mode, tree type, ++ int *pretend_size, int second_time) ++{ ++ CUMULATIVE_ARGS local_cum; ++ int regs_to_push; ++ int pret_size; ++ ++ local_cum = *cum; ++ FUNCTION_ARG_ADVANCE (local_cum, mode, type, 1); ++ ++ regs_to_push = NUM_ARG_REGS - local_cum.regs_used; ++ ++ if (!second_time) ++ { ++ if (regs_to_push > 0) ++ { ++ rtx ptr, mem; ++ ++ ptr = virtual_incoming_args_rtx; ++ mem = gen_rtx_MEM (BLKmode, ptr); ++ ++ /* va_arg is an array access in this case, which causes ++ it to get MEM_IN_STRUCT_P set. We must set it here ++ so that the insn scheduler won't assume that these ++ stores can't possibly overlap with the va_arg loads. */ ++ MEM_SET_IN_STRUCT_P (mem, 1); ++ ++ emit_insn (gen_blockage ()); ++ move_block_from_reg (local_cum.regs_used + FIRST_ARG_REGNO, mem, ++ regs_to_push); ++ emit_insn (gen_blockage ()); ++ } ++ } ++ ++ pret_size = regs_to_push * UNITS_PER_WORD; ++ ++ if (pret_size) ++ *pretend_size = pret_size; ++} ++ ++ ++ ++/***************************************************************************** ++** ++** builtins ++** ++** This method for handling builtins is from CSP where _many_ more types of ++** expanders have already been written. Check there first before writing ++** new ones. ++** ++*****************************************************************************/ ++ ++enum nios2_builtins ++{ ++ NIOS2_BUILTIN_LDBIO, ++ NIOS2_BUILTIN_LDBUIO, ++ NIOS2_BUILTIN_LDHIO, ++ NIOS2_BUILTIN_LDHUIO, ++ NIOS2_BUILTIN_LDWIO, ++ NIOS2_BUILTIN_STBIO, ++ NIOS2_BUILTIN_STHIO, ++ NIOS2_BUILTIN_STWIO, ++ NIOS2_BUILTIN_SYNC, ++ NIOS2_BUILTIN_RDCTL, ++ NIOS2_BUILTIN_WRCTL, ++ ++#undef NIOS2_DO_BUILTIN ++#define NIOS2_DO_BUILTIN(upper, lower, handler) \ ++ NIOS2_CONCAT (NIOS2_BUILTIN_CUSTOM_, upper), ++NIOS2_FOR_ALL_CUSTOM_BUILTINS ++ ++ NIOS2_FIRST_FPU_INSN, ++ ++#undef NIOS2_FPU_INSN ++#define NIOS2_FPU_INSN(opt, insn, args) \ ++ NIOS2_CONCAT (NIOS2_BUILTIN_FPU_, opt), ++NIOS2_FOR_ALL_FPU_INSNS ++ ++ NIOS2_LAST_FPU_INSN, ++ ++ LIM_NIOS2_BUILTINS ++}; ++ ++struct builtin_description ++{ ++ const enum insn_code icode; ++ const char *const name; ++ const enum nios2_builtins code; ++ const tree *type; ++ rtx (* expander) (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++}; ++ ++static rtx nios2_expand_STXIO (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_LDXIO (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_sync (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_rdctl (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_wrctl (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++ ++static rtx nios2_expand_custom_n (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_Xn (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_nX (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_XnX (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_nXX (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_XnXX (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++ ++static rtx nios2_expand_custom_zdz (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_zsz (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_szz (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_sss (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_ssz (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_iss (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_ddd (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_ddz (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_idd (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_siz (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_suz (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_diz (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_duz (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_isz (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_usz (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_idz (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_udz (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_dsz (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_sdz (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++ ++static tree endlink; ++ ++/* int fn (volatile const void *) ++ */ ++static tree int_ftype_volatile_const_void_p; ++ ++/* int fn (int) ++ */ ++static tree int_ftype_int; ++ ++/* void fn (int, int) ++ */ ++static tree void_ftype_int_int; ++ ++/* void fn (volatile void *, int) ++ */ ++static tree void_ftype_volatile_void_p_int; ++ ++/* void fn (void) ++ */ ++static tree void_ftype_void; ++ ++#undef NIOS2_DO_BUILTIN ++#define NIOS2_DO_BUILTIN(upper, lower, handler) \ ++ static tree NIOS2_CONCAT (custom_, lower); ++NIOS2_FOR_ALL_CUSTOM_BUILTINS ++ ++static tree custom_zdz; ++static tree custom_zsz; ++static tree custom_szz; ++static tree custom_sss; ++static tree custom_ssz; ++static tree custom_iss; ++static tree custom_ddd; ++static tree custom_ddz; ++static tree custom_idd; ++static tree custom_siz; ++static tree custom_suz; ++static tree custom_diz; ++static tree custom_duz; ++static tree custom_isz; ++static tree custom_usz; ++static tree custom_idz; ++static tree custom_udz; ++static tree custom_dsz; ++static tree custom_sdz; ++ ++static const struct builtin_description bdesc[] = { ++ {CODE_FOR_ldbio, "__builtin_ldbio", NIOS2_BUILTIN_LDBIO, ++ &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, ++ {CODE_FOR_ldbuio, "__builtin_ldbuio", NIOS2_BUILTIN_LDBUIO, ++ &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, ++ {CODE_FOR_ldhio, "__builtin_ldhio", NIOS2_BUILTIN_LDHIO, ++ &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, ++ {CODE_FOR_ldhuio, "__builtin_ldhuio", NIOS2_BUILTIN_LDHUIO, ++ &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, ++ {CODE_FOR_ldwio, "__builtin_ldwio", NIOS2_BUILTIN_LDWIO, ++ &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, ++ ++ {CODE_FOR_stbio, "__builtin_stbio", NIOS2_BUILTIN_STBIO, ++ &void_ftype_volatile_void_p_int, nios2_expand_STXIO}, ++ {CODE_FOR_sthio, "__builtin_sthio", NIOS2_BUILTIN_STHIO, ++ &void_ftype_volatile_void_p_int, nios2_expand_STXIO}, ++ {CODE_FOR_stwio, "__builtin_stwio", NIOS2_BUILTIN_STWIO, ++ &void_ftype_volatile_void_p_int, nios2_expand_STXIO}, ++ ++ {CODE_FOR_sync, "__builtin_sync", NIOS2_BUILTIN_SYNC, ++ &void_ftype_void, nios2_expand_sync}, ++ {CODE_FOR_rdctl, "__builtin_rdctl", NIOS2_BUILTIN_RDCTL, ++ &int_ftype_int, nios2_expand_rdctl}, ++ {CODE_FOR_wrctl, "__builtin_wrctl", NIOS2_BUILTIN_WRCTL, ++ &void_ftype_int_int, nios2_expand_wrctl}, ++ ++#undef NIOS2_DO_BUILTIN ++#define NIOS2_DO_BUILTIN(upper, lower, handler) \ ++ {NIOS2_CONCAT (CODE_FOR_custom_, lower), \ ++ "__builtin_custom_" NIOS2_STRINGIFY (lower), \ ++ NIOS2_CONCAT (NIOS2_BUILTIN_CUSTOM_, upper), \ ++ &NIOS2_CONCAT (custom_, lower), \ ++ NIOS2_CONCAT (nios2_expand_custom_, handler)}, ++NIOS2_FOR_ALL_CUSTOM_BUILTINS ++ ++#undef NIOS2_FPU_INSN ++#define NIOS2_FPU_INSN(opt, insn, args) \ ++ {NIOS2_CONCAT (CODE_FOR_, insn), \ ++ "__builtin_custom_" NIOS2_STRINGIFY (opt), \ ++ NIOS2_CONCAT (NIOS2_BUILTIN_FPU_, opt), \ ++ &NIOS2_CONCAT (custom_, args), \ ++ NIOS2_CONCAT (nios2_expand_custom_, args)}, ++NIOS2_FOR_ALL_FPU_INSNS ++ ++ {0, 0, 0, 0, 0}, ++}; ++ ++static void ++nios2_init_builtins (void) ++{ ++ const struct builtin_description *d; ++ ++ ++ endlink = void_list_node; ++ ++ /* int fn (volatile const void *) ++ */ ++ int_ftype_volatile_const_void_p = build_function_type ( ++ integer_type_node, ++ tree_cons (NULL_TREE, ++ build_qualified_type (ptr_type_node, ++ TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE), ++ endlink)); ++ ++ /* void fn (volatile void *, int) ++ */ ++ void_ftype_volatile_void_p_int = build_function_type ( ++ void_type_node, ++ tree_cons (NULL_TREE, ++ build_qualified_type (ptr_type_node, TYPE_QUAL_VOLATILE), ++ tree_cons (NULL_TREE, integer_type_node, endlink))); ++ ++ /* void fn (void) ++ */ ++ void_ftype_void ++ = build_function_type (void_type_node, ++ endlink); ++ ++ /* int fn (int) ++ */ ++ int_ftype_int ++ = build_function_type (integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ endlink)); ++ ++ /* void fn (int, int) ++ */ ++ void_ftype_int_int ++ = build_function_type (void_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ endlink))); ++ ++ custom_n ++ = build_function_type (void_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ endlink)); ++ custom_ni ++ = build_function_type (void_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ endlink))); ++ custom_nf ++ = build_function_type (void_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ endlink))); ++ custom_np ++ = build_function_type (void_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, ptr_type_node, ++ endlink))); ++ custom_nii ++ = build_function_type (void_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ endlink)))); ++ custom_nif ++ = build_function_type (void_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ endlink)))); ++ custom_nip ++ = build_function_type (void_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, ptr_type_node, ++ endlink)))); ++ custom_nfi ++ = build_function_type (void_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ endlink)))); ++ custom_nff ++ = build_function_type (void_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ endlink)))); ++ custom_nfp ++ = build_function_type (void_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ tree_cons (NULL_TREE, ptr_type_node, ++ endlink)))); ++ custom_npi ++ = build_function_type (void_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, ptr_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ endlink)))); ++ custom_npf ++ = build_function_type (void_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, ptr_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ endlink)))); ++ custom_npp ++ = build_function_type (void_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, ptr_type_node, ++ tree_cons (NULL_TREE, ptr_type_node, ++ endlink)))); ++ ++ custom_in ++ = build_function_type (integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ endlink)); ++ custom_ini ++ = build_function_type (integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ endlink))); ++ custom_inf ++ = build_function_type (integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ endlink))); ++ custom_inp ++ = build_function_type (integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, ptr_type_node, ++ endlink))); ++ custom_inii ++ = build_function_type (integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ endlink)))); ++ custom_inif ++ = build_function_type (integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ endlink)))); ++ custom_inip ++ = build_function_type (integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, ptr_type_node, ++ endlink)))); ++ custom_infi ++ = build_function_type (integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ endlink)))); ++ custom_inff ++ = build_function_type (integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ endlink)))); ++ custom_infp ++ = build_function_type (integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ tree_cons (NULL_TREE, ptr_type_node, ++ endlink)))); ++ custom_inpi ++ = build_function_type (integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, ptr_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ endlink)))); ++ custom_inpf ++ = build_function_type (integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, ptr_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ endlink)))); ++ custom_inpp ++ = build_function_type (integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, ptr_type_node, ++ tree_cons (NULL_TREE, ptr_type_node, ++ endlink)))); ++ ++ custom_fn ++ = build_function_type (float_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ endlink)); ++ custom_fni ++ = build_function_type (float_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ endlink))); ++ custom_fnf ++ = build_function_type (float_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ endlink))); ++ custom_fnp ++ = build_function_type (float_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, ptr_type_node, ++ endlink))); ++ custom_fnii ++ = build_function_type (float_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ endlink)))); ++ custom_fnif ++ = build_function_type (float_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ endlink)))); ++ custom_fnip ++ = build_function_type (float_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, ptr_type_node, ++ endlink)))); ++ custom_fnfi ++ = build_function_type (float_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ endlink)))); ++ custom_fnff ++ = build_function_type (float_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ endlink)))); ++ custom_fnfp ++ = build_function_type (float_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ tree_cons (NULL_TREE, ptr_type_node, ++ endlink)))); ++ custom_fnpi ++ = build_function_type (float_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, ptr_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ endlink)))); ++ custom_fnpf ++ = build_function_type (float_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, ptr_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ endlink)))); ++ custom_fnpp ++ = build_function_type (float_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, ptr_type_node, ++ tree_cons (NULL_TREE, ptr_type_node, ++ endlink)))); ++ ++ ++ custom_pn ++ = build_function_type (ptr_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ endlink)); ++ custom_pni ++ = build_function_type (ptr_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ endlink))); ++ custom_pnf ++ = build_function_type (ptr_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ endlink))); ++ custom_pnp ++ = build_function_type (ptr_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, ptr_type_node, ++ endlink))); ++ custom_pnii ++ = build_function_type (ptr_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ endlink)))); ++ custom_pnif ++ = build_function_type (ptr_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ endlink)))); ++ custom_pnip ++ = build_function_type (ptr_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, ptr_type_node, ++ endlink)))); ++ custom_pnfi ++ = build_function_type (ptr_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ endlink)))); ++ custom_pnff ++ = build_function_type (ptr_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ endlink)))); ++ custom_pnfp ++ = build_function_type (ptr_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ tree_cons (NULL_TREE, ptr_type_node, ++ endlink)))); ++ custom_pnpi ++ = build_function_type (ptr_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, ptr_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ endlink)))); ++ custom_pnpf ++ = build_function_type (ptr_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, ptr_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ endlink)))); ++ custom_pnpp ++ = build_function_type (ptr_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ tree_cons (NULL_TREE, ptr_type_node, ++ tree_cons (NULL_TREE, ptr_type_node, ++ endlink)))); ++ ++ custom_zdz ++ = build_function_type (void_type_node, ++ tree_cons (NULL_TREE, double_type_node, ++ endlink)); ++ ++ custom_zsz ++ = build_function_type (void_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ endlink)); ++ ++ custom_szz ++ = build_function_type (float_type_node, ++ tree_cons (NULL_TREE, void_type_node, ++ endlink)); ++ ++ custom_sss ++ = build_function_type (float_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ endlink))); ++ ++ custom_ssz ++ = build_function_type (float_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ endlink)); ++ ++ custom_iss ++ = build_function_type (integer_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ endlink))); ++ ++ custom_ddd ++ = build_function_type (double_type_node, ++ tree_cons (NULL_TREE, double_type_node, ++ tree_cons (NULL_TREE, double_type_node, ++ endlink))); ++ ++ custom_ddz ++ = build_function_type (double_type_node, ++ tree_cons (NULL_TREE, double_type_node, ++ endlink)); ++ ++ custom_idd ++ = build_function_type (integer_type_node, ++ tree_cons (NULL_TREE, double_type_node, ++ tree_cons (NULL_TREE, double_type_node, ++ endlink))); ++ ++ custom_siz ++ = build_function_type (float_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ endlink)); ++ ++ custom_suz ++ = build_function_type (float_type_node, ++ tree_cons (NULL_TREE, unsigned_type_node, ++ endlink)); ++ ++ custom_diz ++ = build_function_type (double_type_node, ++ tree_cons (NULL_TREE, integer_type_node, ++ endlink)); ++ ++ custom_duz ++ = build_function_type (double_type_node, ++ tree_cons (NULL_TREE, unsigned_type_node, ++ endlink)); ++ ++ custom_isz ++ = build_function_type (integer_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ endlink)); ++ ++ custom_usz ++ = build_function_type (unsigned_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ endlink)); ++ ++ custom_idz ++ = build_function_type (integer_type_node, ++ tree_cons (NULL_TREE, double_type_node, ++ endlink)); ++ ++ custom_udz ++ = build_function_type (unsigned_type_node, ++ tree_cons (NULL_TREE, double_type_node, ++ endlink)); ++ ++ custom_dsz ++ = build_function_type (double_type_node, ++ tree_cons (NULL_TREE, float_type_node, ++ endlink)); ++ ++ custom_sdz ++ = build_function_type (float_type_node, ++ tree_cons (NULL_TREE, double_type_node, ++ endlink)); ++ ++ ++ for (d = bdesc; d->name; d++) ++ builtin_function (d->name, *d->type, d->code, ++ BUILT_IN_MD, NULL, NULL); ++} ++/* 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. */ ++ ++static rtx ++nios2_expand_builtin (tree exp, rtx target, rtx subtarget, ++ enum machine_mode mode, int ignore) ++{ ++ const struct builtin_description *d; ++ tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); ++ unsigned int fcode = DECL_FUNCTION_CODE (fndecl); ++ ++ for (d = bdesc; d->name; d++) ++ if (d->code == fcode) ++ { ++ if (d->code > NIOS2_FIRST_FPU_INSN && d->code < NIOS2_LAST_FPU_INSN) ++ { ++ nios2_fpu_info *inf = &nios2_fpu_insns[d->code - ++ (NIOS2_FIRST_FPU_INSN + 1)]; ++ const struct insn_data *idata = &insn_data[d->icode]; ++ if (inf->N < 0) ++ fatal_error ("Cannot call `%s' without specifying switch" ++ " `-mcustom-%s'", ++ d->name, ++ inf->option); ++ if (inf->args[0] != 'z' ++ && (!target ++ || !(idata->operand[0].predicate) (target, ++ idata->operand[0].mode))) ++ target = gen_reg_rtx (idata->operand[0].mode); ++ } ++ return (d->expander) (d, exp, target, subtarget, mode, ignore); ++ } ++ ++ /* We should have seen one of the functins we registered. */ ++ gcc_unreachable (); ++} ++ ++static rtx nios2_create_target (const struct builtin_description *, rtx); ++ ++ ++static rtx ++nios2_create_target (const struct builtin_description *d, rtx target) ++{ ++ if (!target ++ || !(*insn_data[d->icode].operand[0].predicate) ( ++ target, insn_data[d->icode].operand[0].mode)) ++ { ++ target = gen_reg_rtx (insn_data[d->icode].operand[0].mode); ++ } ++ ++ return target; ++} ++ ++ ++static rtx nios2_extract_opcode (const struct builtin_description *, int, tree); ++static rtx nios2_extract_operand (const struct builtin_description *, int, int, ++ tree); ++ ++static rtx ++nios2_extract_opcode (const struct builtin_description *d, int op, tree arglist) ++{ ++ enum machine_mode mode = insn_data[d->icode].operand[op].mode; ++ tree arg = TREE_VALUE (arglist); ++ rtx opcode = expand_expr (arg, NULL_RTX, mode, 0); ++ ++ if (!(*insn_data[d->icode].operand[op].predicate) (opcode, mode)) ++ error ("Custom instruction opcode must be compile time constant in the " ++ "range 0-255 for %s", d->name); ++ ++ builtin_custom_seen[INTVAL (opcode)] = d->name; ++ nios2_custom_check_insns (0); ++ return opcode; ++} ++ ++static rtx ++nios2_extract_operand (const struct builtin_description *d, int op, int argnum, ++ tree arglist) ++{ ++ enum machine_mode mode = insn_data[d->icode].operand[op].mode; ++ tree arg = TREE_VALUE (arglist); ++ rtx operand = expand_expr (arg, NULL_RTX, mode, 0); ++ ++ if (!(*insn_data[d->icode].operand[op].predicate) (operand, mode)) ++ operand = copy_to_mode_reg (mode, operand); ++ ++ /* ??? Better errors would be nice. */ ++ if (!(*insn_data[d->icode].operand[op].predicate) (operand, mode)) ++ error ("Invalid argument %d to %s", argnum, d->name); ++ ++ return operand; ++} ++ ++ ++static rtx ++nios2_expand_custom_n (const struct builtin_description *d, tree exp, ++ rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ ++ /* custom_n should have exactly one operand. */ ++ gcc_assert (insn_data[d->icode].n_operands == 1); ++ ++ opcode = nios2_extract_opcode (d, 0, arglist); ++ ++ pat = GEN_FCN (d->icode) (opcode); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return 0; ++} ++ ++static rtx ++nios2_expand_custom_Xn (const struct builtin_description *d, tree exp, ++ rtx target, rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ ++ /* custom_Xn should have exactly two operands. */ ++ gcc_assert (insn_data[d->icode].n_operands == 2); ++ ++ target = nios2_create_target (d, target); ++ opcode = nios2_extract_opcode (d, 1, arglist); ++ ++ pat = GEN_FCN (d->icode) (target, opcode); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_custom_nX (const struct builtin_description *d, tree exp, ++ rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ rtx operands[1]; ++ int i; ++ ++ ++ /* custom_nX should have exactly two operands. */ ++ gcc_assert (insn_data[d->icode].n_operands == 2); ++ ++ opcode = nios2_extract_opcode (d, 0, arglist); ++ for (i = 0; i < 1; i++) ++ { ++ arglist = TREE_CHAIN (arglist); ++ operands[i] = nios2_extract_operand (d, i + 1, i + 1, arglist); ++ } ++ ++ pat = GEN_FCN (d->icode) (opcode, operands[0]); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return 0; ++} ++ ++static rtx ++nios2_expand_custom_XnX (const struct builtin_description *d, tree exp, ++ rtx target, rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ rtx operands[1]; ++ int i; ++ ++ /* custom_Xn should have exactly three operands. */ ++ gcc_assert (insn_data[d->icode].n_operands == 3); ++ ++ target = nios2_create_target (d, target); ++ opcode = nios2_extract_opcode (d, 1, arglist); ++ ++ for (i = 0; i < 1; i++) ++ { ++ arglist = TREE_CHAIN (arglist); ++ operands[i] = nios2_extract_operand (d, i + 2, i + 1, arglist); ++ } ++ ++ pat = GEN_FCN (d->icode) (target, opcode, operands[0]); ++ ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_custom_nXX (const struct builtin_description *d, tree exp, ++ rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ rtx operands[2]; ++ int i; ++ ++ ++ /* custom_nX should have exactly three operands. */ ++ gcc_assert (insn_data[d->icode].n_operands == 3); ++ ++ opcode = nios2_extract_opcode (d, 0, arglist); ++ for (i = 0; i < 2; i++) ++ { ++ arglist = TREE_CHAIN (arglist); ++ operands[i] = nios2_extract_operand (d, i + 1, i + 1, arglist); ++ } ++ ++ pat = GEN_FCN (d->icode) (opcode, operands[0], operands[1]); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return 0; ++} ++ ++static rtx ++nios2_expand_custom_XnXX (const struct builtin_description *d, tree exp, ++ rtx target, rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ rtx operands[2]; ++ int i; ++ ++ ++ /* custom_XnX should have exactly four operands. */ ++ gcc_assert (insn_data[d->icode].n_operands == 4); ++ ++ target = nios2_create_target (d, target); ++ opcode = nios2_extract_opcode (d, 1, arglist); ++ for (i = 0; i < 2; i++) ++ { ++ arglist = TREE_CHAIN (arglist); ++ operands[i] = nios2_extract_operand (d, i + 2, i + 1, arglist); ++ } ++ ++ pat = GEN_FCN (d->icode) (target, opcode, operands[0], operands[1]); ++ ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return target; ++} ++ ++ ++ ++static rtx ++nios2_expand_STXIO (const struct builtin_description *d, tree exp, ++ rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx store_dest, store_val; ++ enum insn_code icode = d->icode; ++ ++ /* Stores should have exactly two operands. */ ++ gcc_assert (insn_data[icode].n_operands == 2); ++ ++ /* Process the destination of the store. */ ++ { ++ enum machine_mode mode = insn_data[icode].operand[0].mode; ++ tree arg = TREE_VALUE (arglist); ++ store_dest = expand_expr (arg, NULL_RTX, VOIDmode, 0); ++ ++ store_dest = gen_rtx_MEM (mode, copy_to_mode_reg (Pmode, store_dest)); ++ ++ /* ??? Better errors would be nice. */ ++ if (!(*insn_data[icode].operand[0].predicate) (store_dest, mode)) ++ error ("Invalid argument 1 to %s", d->name); ++ } ++ ++ ++ /* Process the value to store. */ ++ { ++ enum machine_mode mode = insn_data[icode].operand[1].mode; ++ tree arg = TREE_VALUE (TREE_CHAIN (arglist)); ++ store_val = expand_expr (arg, NULL_RTX, mode, 0); ++ ++ if (!(*insn_data[icode].operand[1].predicate) (store_val, mode)) ++ store_val = copy_to_mode_reg (mode, store_val); ++ ++ /* ??? Better errors would be nice. */ ++ if (!(*insn_data[icode].operand[1].predicate) (store_val, mode)) ++ error ("Invalid argument 2 to %s", d->name); ++ } ++ ++ pat = GEN_FCN (d->icode) (store_dest, store_val); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return 0; ++} ++ ++ ++static rtx ++nios2_expand_LDXIO (const struct builtin_description * d, tree exp, rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx ld_src; ++ enum insn_code icode = d->icode; ++ ++ /* Loads should have exactly two operands. */ ++ gcc_assert (insn_data[icode].n_operands == 2); ++ ++ target = nios2_create_target (d, target); ++ ++ { ++ enum machine_mode mode = insn_data[icode].operand[1].mode; ++ tree arg = TREE_VALUE (arglist); ++ ld_src = expand_expr (arg, NULL_RTX, VOIDmode, 0); ++ ++ ld_src = gen_rtx_MEM (mode, copy_to_mode_reg (Pmode, ld_src)); ++ ++ /* ??? Better errors would be nice. */ ++ if (!(*insn_data[icode].operand[1].predicate) (ld_src, mode)) ++ error ("Invalid argument 1 to %s", d->name); ++ } ++ ++ pat = GEN_FCN (d->icode) (target, ld_src); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return target; ++} ++ ++ ++static rtx ++nios2_expand_sync (const struct builtin_description * d ATTRIBUTE_UNUSED, ++ tree exp ATTRIBUTE_UNUSED, rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ emit_insn (gen_sync ()); ++ return 0; ++} ++ ++static rtx ++nios2_expand_rdctl (const struct builtin_description * d ATTRIBUTE_UNUSED, ++ tree exp ATTRIBUTE_UNUSED, rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx rdctl_reg; ++ enum insn_code icode = d->icode; ++ ++ /* rdctl should have exactly two operands. */ ++ gcc_assert (insn_data[icode].n_operands == 2); ++ ++ target = nios2_create_target (d, target); ++ ++ { ++ enum machine_mode mode = insn_data[icode].operand[1].mode; ++ tree arg = TREE_VALUE (arglist); ++ rdctl_reg = expand_expr (arg, NULL_RTX, VOIDmode, 0); ++ ++ if (!(*insn_data[icode].operand[1].predicate) (rdctl_reg, mode)) ++ error ("Control register number must be in range 0-31 for %s", d->name); ++ } ++ ++ pat = GEN_FCN (d->icode) (target, rdctl_reg); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_wrctl (const struct builtin_description * d ATTRIBUTE_UNUSED, ++ tree exp ATTRIBUTE_UNUSED, rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx wrctl_reg, store_val; ++ enum insn_code icode = d->icode; ++ ++ /* Stores should have exactly two operands. */ ++ gcc_assert (insn_data[icode].n_operands == 2); ++ ++ /* Process the destination of the store. */ ++ { ++ enum machine_mode mode = insn_data[icode].operand[0].mode; ++ tree arg = TREE_VALUE (arglist); ++ wrctl_reg = expand_expr (arg, NULL_RTX, VOIDmode, 0); ++ ++ if (!(*insn_data[icode].operand[0].predicate) (wrctl_reg, mode)) ++ error ("Control register number must be in range 0-31 for %s", d->name); ++ } ++ ++ ++ /* Process the value to store. */ ++ { ++ enum machine_mode mode = insn_data[icode].operand[1].mode; ++ tree arg = TREE_VALUE (TREE_CHAIN (arglist)); ++ store_val = expand_expr (arg, NULL_RTX, mode, 0); ++ ++ if (!(*insn_data[icode].operand[1].predicate) (store_val, mode)) ++ store_val = copy_to_mode_reg (mode, store_val); ++ ++ /* ??? Better errors would be nice. */ ++ if (!(*insn_data[icode].operand[1].predicate) (store_val, mode)) ++ error ("Invalid argument 2 to %s", d->name); ++ } ++ ++ pat = GEN_FCN (d->icode) (wrctl_reg, store_val); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return 0; ++} ++ ++static rtx ++nios2_extract_double (const struct insn_data *idata, tree arglist, int index) ++{ ++ rtx arg; ++ ++ while (index--) ++ arglist = TREE_CHAIN (arglist); ++ arg = expand_expr (TREE_VALUE (arglist), NULL_RTX, DFmode, 0); ++ if (!(*(idata->operand[index+1].predicate)) (arg, DFmode)) ++ arg = copy_to_mode_reg (DFmode, arg); ++ return arg; ++} ++ ++static rtx ++nios2_extract_float (const struct insn_data *idata, tree arglist, int index) ++{ ++ rtx arg; ++ ++ while (index--) ++ arglist = TREE_CHAIN (arglist); ++ arg = expand_expr (TREE_VALUE (arglist), NULL_RTX, SFmode, 0); ++ if (!(*(idata->operand[index+1].predicate)) (arg, SFmode)) ++ arg = copy_to_mode_reg (SFmode, arg); ++ return arg; ++} ++ ++static rtx ++nios2_extract_integer (const struct insn_data *idata, tree arglist, int index) ++{ ++ rtx arg; ++ ++ while (index--) ++ arglist = TREE_CHAIN (arglist); ++ arg = expand_expr (TREE_VALUE (arglist), NULL_RTX, SImode, 0); ++ if (!(*(idata->operand[index+1].predicate)) (arg, SImode)) ++ arg = copy_to_mode_reg (SImode, arg); ++ return arg; ++} ++ ++static rtx ++nios2_expand_custom_zdz (const struct builtin_description *d, ++ tree exp, ++ rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat = GEN_FCN (d->icode) (nios2_extract_double (&insn_data[d->icode], ++ arglist, 0)); ++ if (pat) ++ emit_insn (pat); ++ return 0; ++} ++ ++static rtx ++nios2_expand_custom_zsz (const struct builtin_description *d, ++ tree exp, ++ rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat = GEN_FCN (d->icode) (nios2_extract_float (&insn_data[d->icode], ++ arglist, 0)); ++ if (pat) ++ emit_insn (pat); ++ return 0; ++} ++ ++static rtx ++nios2_expand_custom_szz (const struct builtin_description *d, ++ tree exp ATTRIBUTE_UNUSED, ++ rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ rtx pat = GEN_FCN (d->icode) (target); ++ if (pat) ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_custom_sss (const struct builtin_description *d, ++ tree exp, ++ rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat = GEN_FCN (d->icode) (target, ++ nios2_extract_float (&insn_data[d->icode], ++ arglist, 0), ++ nios2_extract_float (&insn_data[d->icode], ++ arglist, 1)); ++ if (pat) ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_custom_ssz (const struct builtin_description *d, ++ tree exp, ++ rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat = GEN_FCN (d->icode) (target, ++ nios2_extract_float (&insn_data[d->icode], ++ arglist, 0)); ++ if (pat) ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_custom_iss (const struct builtin_description *d, ++ tree exp, ++ rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat = GEN_FCN (d->icode) (target, ++ nios2_extract_float (&insn_data[d->icode], ++ arglist, 0), ++ nios2_extract_float (&insn_data[d->icode], ++ arglist, 1)); ++ if (pat) ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_custom_ddd (const struct builtin_description *d, ++ tree exp, ++ rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat = GEN_FCN (d->icode) (target, ++ nios2_extract_double (&insn_data[d->icode], ++ arglist, 0), ++ nios2_extract_double (&insn_data[d->icode], ++ arglist, 1)); ++ if (pat) ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_custom_ddz (const struct builtin_description *d, ++ tree exp, ++ rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat = GEN_FCN (d->icode) (target, ++ nios2_extract_double (&insn_data[d->icode], ++ arglist, 0)); ++ if (pat) ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_custom_idd (const struct builtin_description *d, ++ tree exp, ++ rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat = GEN_FCN (d->icode) (target, ++ nios2_extract_double (&insn_data[d->icode], ++ arglist, 0), ++ nios2_extract_double (&insn_data[d->icode], ++ arglist, 1)); ++ if (pat) ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_custom_siz (const struct builtin_description *d, ++ tree exp, ++ rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat = GEN_FCN (d->icode) (target, ++ nios2_extract_integer (&insn_data[d->icode], ++ arglist, 0)); ++ if (pat) ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_custom_suz (const struct builtin_description *d, ++ tree exp, ++ rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat = GEN_FCN (d->icode) (target, ++ nios2_extract_integer (&insn_data[d->icode], ++ arglist, 0)); ++ if (pat) ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_custom_diz (const struct builtin_description *d, ++ tree exp, ++ rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat = GEN_FCN (d->icode) (target, ++ nios2_extract_integer (&insn_data[d->icode], ++ arglist, 0)); ++ if (pat) ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_custom_duz (const struct builtin_description *d, ++ tree exp, ++ rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat = GEN_FCN (d->icode) (target, ++ nios2_extract_integer (&insn_data[d->icode], ++ arglist, 0)); ++ if (pat) ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_custom_isz (const struct builtin_description *d, ++ tree exp, ++ rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat = GEN_FCN (d->icode) (target, ++ nios2_extract_float (&insn_data[d->icode], ++ arglist, 0)); ++ if (pat) ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_custom_usz (const struct builtin_description *d, ++ tree exp, ++ rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat = GEN_FCN (d->icode) (target, ++ nios2_extract_float (&insn_data[d->icode], ++ arglist, 0)); ++ if (pat) ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_custom_idz (const struct builtin_description *d, ++ tree exp, ++ rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat = GEN_FCN (d->icode) (target, ++ nios2_extract_double (&insn_data[d->icode], ++ arglist, 0)); ++ if (pat) ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_custom_udz (const struct builtin_description *d, ++ tree exp, ++ rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat = GEN_FCN (d->icode) (target, ++ nios2_extract_double (&insn_data[d->icode], ++ arglist, 0)); ++ if (pat) ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_custom_dsz (const struct builtin_description *d, ++ tree exp, ++ rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat = GEN_FCN (d->icode) (target, ++ nios2_extract_float (&insn_data[d->icode], ++ arglist, 0)); ++ if (pat) ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_custom_sdz (const struct builtin_description *d, ++ tree exp, ++ rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat = GEN_FCN (d->icode) (target, ++ nios2_extract_double (&insn_data[d->icode], ++ arglist, 0)); ++ if (pat) ++ emit_insn (pat); ++ return target; ++} ++ ++#include "gt-nios2.h" ++ +Index: gcc-4.1.2/gcc/config/nios2/nios2.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gcc-4.1.2/gcc/config/nios2/nios2.h 2010-06-30 08:50:26.000000000 +0200 +@@ -0,0 +1,1064 @@ ++/* NOT ASSIGNED TO FSF. COPYRIGHT ALTERA. */ ++/* Definitions of target machine for Altera NIOS 2G NIOS2 version. ++ Copyright (C) 2007 Altera ++ Contributed by Jonah Graham (jgraham@altera.com), ++ Will Reece (wreece@altera.com), and Jeff DaSilva (jdasilva@altera.com). ++ ++This file is part of GNU CC. ++ ++GNU CC 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, or (at your option) ++any later version. ++ ++GNU CC 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 GNU CC; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++ ++ ++#define TARGET_CPU_CPP_BUILTINS() \ ++ do \ ++ { \ ++ builtin_define_std ("NIOS2"); \ ++ builtin_define_std ("nios2"); \ ++ if (TARGET_BIG_ENDIAN) \ ++ builtin_define_std ("nios2_big_endian"); \ ++ else \ ++ builtin_define_std ("nios2_little_endian"); \ ++ } \ ++ while (0) ++#define TARGET_VERSION fprintf (stderr, " (Altera Nios II)") ++ ++ ++ ++ ++ ++/********************************* ++ * Run-time Target Specification ++ *********************************/ ++ ++extern int target_flags; ++ ++/* ++ * There's a lot of error-prone tedium with all the different ++ * custom floating point instructions. Try to automate it a bit ++ * to make it easier to deal with. ++ */ ++#define NIOS2_STRINGIFY_INNER(x) #x ++#define NIOS2_STRINGIFY(x) NIOS2_STRINGIFY_INNER(x) ++#define NIOS2_CONCAT_INNER(x, y) x ## y ++#define NIOS2_CONCAT(x, y) NIOS2_CONCAT_INNER (x, y) ++ ++#define NIOS2_FOR_ALL_FPU_INSNS \ ++ NIOS2_FPU_INSN (fwrx, nios2_fwrx, zdz) \ ++ NIOS2_FPU_INSN (fwry, nios2_fwry, zsz) \ ++ NIOS2_FPU_INSN (frdxlo, nios2_frdxlo, szz) \ ++ NIOS2_FPU_INSN (frdxhi, nios2_frdxhi, szz) \ ++ NIOS2_FPU_INSN (frdy, nios2_frdy, szz) \ ++\ ++ NIOS2_FPU_INSN (fadds, addsf3, sss) \ ++ NIOS2_FPU_INSN (fsubs, subsf3, sss) \ ++ NIOS2_FPU_INSN (fmuls, mulsf3, sss) \ ++ NIOS2_FPU_INSN (fdivs, divsf3, sss) \ ++ NIOS2_FPU_INSN (fmins, minsf3, sss) \ ++ NIOS2_FPU_INSN (fmaxs, maxsf3, sss) \ ++ NIOS2_FPU_INSN (fnegs, negsf2, ssz) \ ++ NIOS2_FPU_INSN (fabss, abssf2, ssz) \ ++ NIOS2_FPU_INSN (fsqrts, sqrtsf2, ssz) \ ++ NIOS2_FPU_INSN (fcoss, cossf2, ssz) \ ++ NIOS2_FPU_INSN (fsins, sinsf2, ssz) \ ++ NIOS2_FPU_INSN (ftans, tansf2, ssz) \ ++ NIOS2_FPU_INSN (fatans, atansf2, ssz) \ ++ NIOS2_FPU_INSN (fexps, expsf2, ssz) \ ++ NIOS2_FPU_INSN (flogs, logsf2, ssz) \ ++ NIOS2_FPU_INSN (fcmplts, nios2_sltsf, iss) \ ++ NIOS2_FPU_INSN (fcmples, nios2_slesf, iss) \ ++ NIOS2_FPU_INSN (fcmpgts, nios2_sgtsf, iss) \ ++ NIOS2_FPU_INSN (fcmpges, nios2_sgesf, iss) \ ++ NIOS2_FPU_INSN (fcmpeqs, nios2_seqsf, iss) \ ++ NIOS2_FPU_INSN (fcmpnes, nios2_snesf, iss) \ ++\ ++ NIOS2_FPU_INSN (faddd, adddf3, ddd) \ ++ NIOS2_FPU_INSN (fsubd, subdf3, ddd) \ ++ NIOS2_FPU_INSN (fmuld, muldf3, ddd) \ ++ NIOS2_FPU_INSN (fdivd, divdf3, ddd) \ ++ NIOS2_FPU_INSN (fmind, mindf3, ddd) \ ++ NIOS2_FPU_INSN (fmaxd, maxdf3, ddd) \ ++ NIOS2_FPU_INSN (fnegd, negdf2, ddz) \ ++ NIOS2_FPU_INSN (fabsd, absdf2, ddz) \ ++ NIOS2_FPU_INSN (fsqrtd, sqrtdf2, ddz) \ ++ NIOS2_FPU_INSN (fcosd, cosdf2, ddz) \ ++ NIOS2_FPU_INSN (fsind, sindf2, ddz) \ ++ NIOS2_FPU_INSN (ftand, tandf2, ddz) \ ++ NIOS2_FPU_INSN (fatand, atandf2, ddz) \ ++ NIOS2_FPU_INSN (fexpd, expdf2, ddz) \ ++ NIOS2_FPU_INSN (flogd, logdf2, ddz) \ ++ NIOS2_FPU_INSN (fcmpltd, nios2_sltdf, idd) \ ++ NIOS2_FPU_INSN (fcmpled, nios2_sledf, idd) \ ++ NIOS2_FPU_INSN (fcmpgtd, nios2_sgtdf, idd) \ ++ NIOS2_FPU_INSN (fcmpged, nios2_sgedf, idd) \ ++ NIOS2_FPU_INSN (fcmpeqd, nios2_seqdf, idd) \ ++ NIOS2_FPU_INSN (fcmpned, nios2_snedf, idd) \ ++\ ++ NIOS2_FPU_INSN (floatis, floatsisf2, siz) \ ++ NIOS2_FPU_INSN (floatus, floatunssisf2, suz) \ ++ NIOS2_FPU_INSN (floatid, floatsidf2, diz) \ ++ NIOS2_FPU_INSN (floatud, floatunssidf2, duz) \ ++ NIOS2_FPU_INSN (fixsi, fixsfsi2, isz) \ ++ NIOS2_FPU_INSN (fixsu, fixunssfsi2, usz) \ ++ NIOS2_FPU_INSN (fixdi, fixdfsi2, idz) \ ++ NIOS2_FPU_INSN (fixdu, fixunsdfsi2, udz) \ ++ NIOS2_FPU_INSN (fextsd, extendsfdf2, dsz) \ ++ NIOS2_FPU_INSN (ftruncds, truncdfsf2, sdz) ++ ++enum ++{ ++#define NIOS2_FPU_INSN(opt, insn, args) \ ++ NIOS2_CONCAT (nios2_fpu_, insn), ++NIOS2_FOR_ALL_FPU_INSNS ++ nios2_fpu_max_insn ++}; ++ ++struct cpp_reader; ++typedef const char * (*nios2_outputfn) (rtx); ++typedef void (*nios2_pragmafn) (struct cpp_reader *); ++ ++typedef struct ++{ ++ const char *option; /* name of switch, e.g. fadds */ ++ const char *insnnm; /* name of gcc insn, e.g. addsf3 */ ++ const char *args; /* args to gcc insn, e.g. sss */ ++ int N; /* value of switch as an integer, -1 = not used */ ++ nios2_outputfn output; /* output function for use in .md file */ ++ const char *pname; /* name of corresponding #pragma custom- */ ++ nios2_pragmafn pragma; /* pragma function for register_target_pragmas */ ++ const char *nopname; /* name of corresponding #pragma no-custom- */ ++ nios2_pragmafn nopragma; /* pragma function for register_target_pragmas */ ++ int is_double; /* does this insn have any double operands */ ++ int needed_by_double; /* is this insn needed if doubles are used? */ ++ int needs_unsafe; /* does this insn require ++ -funsafe-math-optimizations to work? */ ++ int needs_finite; /* does this insn require ++ -ffinite-math-only to work? */ ++ int pragma_seen; /* have we seen the corresponding #pragma? */ ++ int* pN; /* pointer to the value as set by the option ++ parser. */ ++} nios2_fpu_info; ++ ++extern nios2_fpu_info nios2_fpu_insns[nios2_fpu_max_insn]; ++extern const char *nios2_custom_fpu_cfg_string; ++ ++#undef NIOS2_FPU_INSN ++#define NIOS2_FPU_INSN(opt, insn, args) \ ++ extern int NIOS2_CONCAT (nios2_custom_, opt); ++NIOS2_FOR_ALL_FPU_INSNS ++ ++/* We're little endian, unless otherwise specified by defining BIG_ENDIAN_FLAG ++*/ ++#ifndef TARGET_ENDIAN_DEFAULT ++# define TARGET_ENDIAN_DEFAULT 0 ++#endif ++ ++/* Default target_flags if no switches specified. */ ++#ifndef TARGET_DEFAULT ++# define TARGET_DEFAULT (MASK_HAS_MUL | \ ++ TARGET_ENDIAN_DEFAULT) ++#endif ++ ++/* Switch Recognition by gcc.c. Add -G xx support */ ++#undef SWITCH_TAKES_ARG ++#define SWITCH_TAKES_ARG(CHAR) \ ++ (DEFAULT_SWITCH_TAKES_ARG (CHAR) || (CHAR) == 'G') ++ ++#define OVERRIDE_OPTIONS override_options () ++#define OPTIMIZATION_OPTIONS(LEVEL, SIZE) optimization_options (LEVEL, SIZE) ++#define CAN_DEBUG_WITHOUT_FP ++ ++#define CC1_SPEC "\ ++%{G*} %{EB:-meb} %{EL:-mel} %{EB:%{EL:%emay not use both -EB and -EL}}" ++ ++#if TARGET_ENDIAN_DEFAULT == 0 ++# define ASM_SPEC "\ ++%{!EB:%{!meb:-EL}} %{EB|meb:-EB}" ++# define LINK_SPEC_ENDIAN "\ ++%{!EB:%{!meb:-EL}} %{EB|meb:-EB}" ++# define MULTILIB_DEFAULTS { "EL" } ++#else ++# define ASM_SPEC "\ ++%{!EL:%{!mel:-EB}} %{EL|mel:-EL}" ++# define LINK_SPEC_ENDIAN "\ ++%{!EL:%{!mel:-EB}} %{EL|mel:-EL}" ++# define MULTILIB_DEFAULTS { "EB" } ++#endif ++ ++#define LINK_SPEC LINK_SPEC_ENDIAN \ ++ " %{shared:-shared} \ ++ %{static:-Bstatic}" ++ ++#undef LIB_SPEC ++#define LIB_SPEC \ ++"--start-group -lc -lgcc \ ++ -lnosys -lstack \ ++ --end-group \ ++" ++ ++ ++#undef STARTFILE_SPEC ++#define STARTFILE_SPEC \ ++"crt0%O%s" ++ ++#undef ENDFILE_SPEC ++#define ENDFILE_SPEC \ ++ "" ++ ++ ++/*********************** ++ * Storage Layout ++ ***********************/ ++ ++#define DEFAULT_SIGNED_CHAR 1 ++#define BITS_BIG_ENDIAN 0 ++#define BYTES_BIG_ENDIAN (TARGET_BIG_ENDIAN != 0) ++#define WORDS_BIG_ENDIAN (TARGET_BIG_ENDIAN != 0) ++#if defined(__nios2_big_endian__) ++#define LIBGCC2_WORDS_BIG_ENDIAN 1 ++#else ++#define LIBGCC2_WORDS_BIG_ENDIAN 0 ++#endif ++#define BITS_PER_UNIT 8 ++#define BITS_PER_WORD 32 ++#define UNITS_PER_WORD 4 ++#define POINTER_SIZE 32 ++#define BIGGEST_ALIGNMENT 32 ++#define STRICT_ALIGNMENT 1 ++#define FUNCTION_BOUNDARY 32 ++#define PARM_BOUNDARY 32 ++#define STACK_BOUNDARY 32 ++#define PREFERRED_STACK_BOUNDARY 32 ++#define MAX_FIXED_MODE_SIZE 64 ++ ++#define CONSTANT_ALIGNMENT(EXP, ALIGN) \ ++ ((TREE_CODE (EXP) == STRING_CST) \ ++ && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN)) ++ ++ ++/********************** ++ * Layout of Source Language Data Types ++ **********************/ ++ ++#define INT_TYPE_SIZE 32 ++#define SHORT_TYPE_SIZE 16 ++#define LONG_TYPE_SIZE 32 ++#define LONG_LONG_TYPE_SIZE 64 ++#define FLOAT_TYPE_SIZE 32 ++#define DOUBLE_TYPE_SIZE 64 ++#define LONG_DOUBLE_TYPE_SIZE DOUBLE_TYPE_SIZE ++ ++ ++/************************* ++ * Condition Code Status ++ ************************/ ++ ++/* comparison type */ ++/* ??? Currently CMP_DI is unused. CMP_SF and CMP_DF are only used if ++ the corresponding -mcustom-<opcode> switches are present. */ ++enum cmp_type { ++ CMP_SI, /* compare four byte integers */ ++ CMP_DI, /* compare eight byte integers */ ++ CMP_SF, /* compare single precision floats */ ++ CMP_DF, /* compare double precision floats */ ++ CMP_MAX /* max comparison type */ ++}; ++ ++extern GTY(()) rtx branch_cmp[2]; /* operands for compare */ ++extern enum cmp_type branch_type; /* what type of branch to use */ ++ ++/********************** ++ * Register Usage ++ **********************/ ++ ++/* ---------------------------------- * ++ * Basic Characteristics of Registers ++ * ---------------------------------- */ ++ ++/* ++Register Number ++ Register Name ++ Alternate Name ++ Purpose ++0 r0 zero always zero ++1 r1 at Assembler Temporary ++2-3 r2-r3 Return Location ++4-7 r4-r7 Register Arguments ++8-15 r8-r15 Caller Saved Registers ++16-22 r16-r22 Callee Saved Registers ++21 r21 sc Static Chain (Callee Saved) ++ ??? Does $sc want to be caller or callee ++ saved. If caller, 15, else 21. ++22 r22 Global Offset Table pointer ++23 r23 Thread pointer ++24 r24 et Exception Temporary ++25 r25 bt Breakpoint Temporary ++26 r26 gp Global Pointer ++27 r27 sp Stack Pointer ++28 r28 fp Frame Pointer ++29 r29 ea Exception Return Address ++30 r30 ba Breakpoint Return Address ++31 r31 ra Return Address ++ ++32 ctl0 status ++33 ctl1 estatus STATUS saved by exception ? ++34 ctl2 bstatus STATUS saved by break ? ++35 ctl3 ipri Interrupt Priority Mask ? ++36 ctl4 ecause Exception Cause ? ++ ++37 pc Not an actual register ++ ++38 fake_fp Fake Frame Pointer which will always be eliminated. ++39 fake_ap Fake Argument Pointer which will always be eliminated. ++ ++40 First Pseudo Register ++ ++ ++The definitions for all the hard register numbers ++are located in nios2.md. ++*/ ++ ++#define ET_REGNO (24) ++#define GP_REGNO (26) ++#define SP_REGNO (27) ++#define FP_REGNO (28) ++#define EA_REGNO (29) ++#define RA_REGNO (31) ++#define FIRST_RETVAL_REGNO (2) ++#define LAST_RETVAL_REGNO (3) ++#define FIRST_ARG_REGNO (4) ++#define LAST_ARG_REGNO (7) ++#define SC_REGNO (21) ++#define PC_REGNO (37) ++#define FAKE_FP_REGNO (38) ++#define FAKE_AP_REGNO (39) ++ ++#define FIRST_PSEUDO_REGISTER 40 ++#define NUM_ARG_REGS (LAST_ARG_REGNO - FIRST_ARG_REGNO + 1) ++ ++ ++ ++#define FIXED_REGISTERS \ ++ { \ ++/* +0 1 2 3 4 5 6 7 8 9 */ \ ++/* 0 */ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, \ ++/* 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ ++/* 20 */ 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, \ ++/* 30 */ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, \ ++ } ++ ++/* call used is the same as caller saved ++ + fixed regs + args + ret vals */ ++#define CALL_USED_REGISTERS \ ++ { \ ++/* +0 1 2 3 4 5 6 7 8 9 */ \ ++/* 0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ ++/* 10 */ 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, \ ++/* 20 */ 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, \ ++/* 30 */ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, \ ++ } ++ ++#define THREAD_POINTER_REGNUM 23 ++ ++#define HARD_REGNO_NREGS(REGNO, MODE) \ ++ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \ ++ / UNITS_PER_WORD) ++ ++/* --------------------------- * ++ * How Values Fit in Registers ++ * --------------------------- */ ++ ++#define HARD_REGNO_MODE_OK(REGNO, MODE) 1 ++ ++#define MODES_TIEABLE_P(MODE1, MODE2) 1 ++ ++ ++/************************* ++ * Register Classes ++ *************************/ ++ ++enum reg_class ++{ ++ NO_REGS, ++ D00_REG, ++ D01_REG, ++ D02_REG, ++ D03_REG, ++ D04_REG, ++ D05_REG, ++ D06_REG, ++ D07_REG, ++ D08_REG, ++ D09_REG, ++ D10_REG, ++ D11_REG, ++ D12_REG, ++ D13_REG, ++ D14_REG, ++ D15_REG, ++ D16_REG, ++ D17_REG, ++ D18_REG, ++ D19_REG, ++ D20_REG, ++ D21_REG, ++ D22_REG, ++ D23_REG, ++ D24_REG, ++ D25_REG, ++ D26_REG, ++ D27_REG, ++ D28_REG, ++ D29_REG, ++ D30_REG, ++ D31_REG, ++ SIB_REGS, ++ GP_REGS, ++ ALL_REGS, ++ LIM_REG_CLASSES ++}; ++ ++#define N_REG_CLASSES (int) LIM_REG_CLASSES ++ ++#define REG_CLASS_NAMES \ ++ {"NO_REGS", \ ++ "D00_REG", \ ++ "D01_REG", \ ++ "D02_REG", \ ++ "D03_REG", \ ++ "D04_REG", \ ++ "D05_REG", \ ++ "D06_REG", \ ++ "D07_REG", \ ++ "D08_REG", \ ++ "D09_REG", \ ++ "D10_REG", \ ++ "D11_REG", \ ++ "D12_REG", \ ++ "D13_REG", \ ++ "D14_REG", \ ++ "D15_REG", \ ++ "D16_REG", \ ++ "D17_REG", \ ++ "D18_REG", \ ++ "D19_REG", \ ++ "D20_REG", \ ++ "D21_REG", \ ++ "D22_REG", \ ++ "D23_REG", \ ++ "D24_REG", \ ++ "D25_REG", \ ++ "D26_REG", \ ++ "D27_REG", \ ++ "D28_REG", \ ++ "D29_REG", \ ++ "D30_REG", \ ++ "D31_REG", \ ++ "SIB_REGS", \ ++ "GP_REGS", \ ++ "ALL_REGS"} ++ ++#define GENERAL_REGS ALL_REGS ++ ++#define REG_CLASS_CONTENTS \ ++/* NO_REGS */ {{ 0, 0}, \ ++/* D00_REG */ { 1 << 0, 0}, \ ++/* D01_REG */ { 1 << 1, 0}, \ ++/* D02_REG */ { 1 << 2, 0}, \ ++/* D03_REG */ { 1 << 3, 0}, \ ++/* D04_REG */ { 1 << 4, 0}, \ ++/* D05_REG */ { 1 << 5, 0}, \ ++/* D06_REG */ { 1 << 6, 0}, \ ++/* D07_REG */ { 1 << 7, 0}, \ ++/* D08_REG */ { 1 << 8, 0}, \ ++/* D09_REG */ { 1 << 9, 0}, \ ++/* D10_REG */ { 1 << 10, 0}, \ ++/* D11_REG */ { 1 << 11, 0}, \ ++/* D12_REG */ { 1 << 12, 0}, \ ++/* D13_REG */ { 1 << 13, 0}, \ ++/* D14_REG */ { 1 << 14, 0}, \ ++/* D15_REG */ { 1 << 15, 0}, \ ++/* D16_REG */ { 1 << 16, 0}, \ ++/* D17_REG */ { 1 << 17, 0}, \ ++/* D18_REG */ { 1 << 18, 0}, \ ++/* D19_REG */ { 1 << 19, 0}, \ ++/* D20_REG */ { 1 << 20, 0}, \ ++/* D21_REG */ { 1 << 21, 0}, \ ++/* D22_REG */ { 1 << 22, 0}, \ ++/* D23_REG */ { 1 << 23, 0}, \ ++/* D24_REG */ { 1 << 24, 0}, \ ++/* D25_REG */ { 1 << 25, 0}, \ ++/* D26_REG */ { 1 << 26, 0}, \ ++/* D27_REG */ { 1 << 27, 0}, \ ++/* D28_REG */ { 1 << 28, 0}, \ ++/* D29_REG */ { 1 << 29, 0}, \ ++/* D30_REG */ { 1 << 30, 0}, \ ++/* D31_REG */ { 1 << 31, 0}, \ ++/* SIB_REGS */ { 0xfe0c, 0}, \ ++/* GP_REGS */ {~0, 0}, \ ++/* ALL_REGS */ {~0,~0}} \ ++ ++#define GP_REGNO_P(REGNO) ((REGNO) < 32) ++#define REGNO_REG_CLASS(REGNO) (GP_REGNO_P (REGNO) ? GP_REGS : ALL_REGS) ++ ++#define BASE_REG_CLASS ALL_REGS ++#define INDEX_REG_CLASS ALL_REGS ++ ++/* 'r', is handled automatically */ ++#define REG_CLASS_FROM_LETTER(C) ((C) == 'j' ? SIB_REGS : NO_REGS) ++ ++#define REG_CLASS_FROM_CONSTRAINT(CHAR, STR) \ ++ ((CHAR) == 'j' ? SIB_REGS : \ ++ reg_class_from_constraint ((CHAR), (STR))) ++ ++ ++#define REGNO_OK_FOR_BASE_P2(REGNO, STRICT) \ ++ ((STRICT) \ ++ ? (REGNO) < FIRST_PSEUDO_REGISTER \ ++ : (REGNO) < FIRST_PSEUDO_REGISTER || \ ++ (reg_renumber && reg_renumber[REGNO] < FIRST_PSEUDO_REGISTER)) ++ ++#define REGNO_OK_FOR_INDEX_P2(REGNO, STRICT) \ ++ (REGNO_OK_FOR_BASE_P2 (REGNO, STRICT)) ++ ++#define REGNO_OK_FOR_BASE_P(REGNO) \ ++ (REGNO_OK_FOR_BASE_P2 (REGNO, 1)) ++ ++#define REGNO_OK_FOR_INDEX_P(REGNO) \ ++ (REGNO_OK_FOR_INDEX_P2 (REGNO, 1)) ++ ++#define REG_OK_FOR_BASE_P2(X, STRICT) \ ++ (STRICT \ ++ ? REGNO_OK_FOR_BASE_P2 (REGNO (X), 1) \ ++ : REGNO_OK_FOR_BASE_P2 (REGNO (X), 1) || \ ++ REGNO(X) >= FIRST_PSEUDO_REGISTER) ++ ++#define REG_OK_FOR_INDEX_P2(X, STRICT) \ ++ (STRICT \ ++ ? REGNO_OK_FOR_INDEX_P2 (REGNO (X), 1) \ ++ : REGNO_OK_FOR_INDEX_P2 (REGNO (X), 1) || \ ++ REGNO(X) >= FIRST_PSEUDO_REGISTER) ++ ++#define CLASS_MAX_NREGS(CLASS, MODE) \ ++ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \ ++ / UNITS_PER_WORD) ++ ++ ++#define SMALL_INT(X) ((unsigned HOST_WIDE_INT) ((X) + 0x8000) < 0x10000) ++#define SMALL_INT_UNSIGNED(X) ((unsigned HOST_WIDE_INT) (X) < 0x10000) ++#define UPPER16_INT(X) (((X) & 0xffff) == 0) ++#define SHIFT_INT(X) ((X) >= 0 && (X) <= 31) ++#define RDWRCTL_INT(X) ((X) >= 0 && (X) <= 31) ++#define CUSTOM_INSN_OPCODE(X) ((X) >= 0 && (X) <= 255) ++ ++#define CONST_OK_FOR_LETTER_P(VALUE, C) \ ++ ( \ ++ (C) == 'I' ? SMALL_INT (VALUE) : \ ++ (C) == 'J' ? SMALL_INT_UNSIGNED (VALUE) : \ ++ (C) == 'K' ? UPPER16_INT (VALUE) : \ ++ (C) == 'L' ? SHIFT_INT (VALUE) : \ ++ (C) == 'M' ? (VALUE) == 0 : \ ++ (C) == 'N' ? CUSTOM_INSN_OPCODE (VALUE) : \ ++ (C) == 'O' ? RDWRCTL_INT (VALUE) : \ ++ 0) ++ ++#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) 0 ++ ++#define PREFERRED_RELOAD_CLASS(X, CLASS) \ ++ ((CLASS) == NO_REGS ? GENERAL_REGS : (CLASS)) ++ ++#define CONSTRAINT_LEN(C, STR) \ ++ ((C) == 'D' ? 3 : DEFAULT_CONSTRAINT_LEN ((C), (STR))) ++ ++/* 'S' matches immediates which are in small data ++ and therefore can be added to gp to create a ++ 32-bit value. */ ++#define EXTRA_CONSTRAINT(VALUE, C) \ ++ ((C) == 'S' \ ++ && (GET_CODE (VALUE) == SYMBOL_REF) \ ++ && SYMBOL_REF_IN_NIOS2_SMALL_DATA_P (VALUE)) ++ ++ ++ ++ ++/* Say that the epilogue uses the return address register. Note that ++ in the case of sibcalls, the values "used by the epilogue" are ++ considered live at the start of the called function. */ ++#define EPILOGUE_USES(REGNO) ((REGNO) == RA_REGNO) ++ ++ ++/********************************** ++ * Trampolines for Nested Functions ++ ***********************************/ ++ ++#define TRAMPOLINE_TEMPLATE(FILE) \ ++ error ("trampolines not yet implemented") ++#define TRAMPOLINE_SIZE 20 ++#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \ ++ error ("trampolines not yet implemented") ++ ++/*************************** ++ * Stack Layout and Calling Conventions ++ ***************************/ ++ ++/* ------------------ * ++ * Basic Stack Layout ++ * ------------------ */ ++ ++/* The downward variants are used by the compiler, ++ the upward ones serve as documentation */ ++#define STACK_GROWS_DOWNWARD ++#define FRAME_GROWS_UPWARD ++#define ARGS_GROW_UPWARD ++ ++#define STARTING_FRAME_OFFSET 0 ++#define FIRST_PARM_OFFSET(FUNDECL) 0 ++ ++/* Before the prologue, RA lives in r31. */ ++#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (VOIDmode, RA_REGNO) ++#define RETURN_ADDR_RTX(C,F) nios2_get_return_address (C) ++ ++/* -------------------------------------- * ++ * Registers That Address the Stack Frame ++ * -------------------------------------- */ ++ ++#define STACK_POINTER_REGNUM SP_REGNO ++#define STATIC_CHAIN_REGNUM SC_REGNO ++#define PC_REGNUM PC_REGNO ++#define DWARF_FRAME_RETURN_COLUMN RA_REGNO ++ ++/* The DWARF 2 CFA column which tracks the return address from a ++ signal handler context. */ ++#define SIGNAL_UNWIND_RETURN_COLUMN EA_REGNO ++ ++/* Base register for access to local variables of the function. We ++ pretend that the frame pointer is a non-existent hard register, and ++ then eliminate it to HARD_FRAME_POINTER_REGNUM. */ ++#define FRAME_POINTER_REGNUM FAKE_FP_REGNO ++ ++#define HARD_FRAME_POINTER_REGNUM FP_REGNO ++/* the argumnet pointer needs to always be eliminated ++ so it is set to a fake hard register. */ ++#define ARG_POINTER_REGNUM FAKE_AP_REGNO ++ ++/* The CFA includes the pretend args */ ++#define ARG_POINTER_CFA_OFFSET(FNDECL) \ ++ (gcc_assert ((FNDECL) == current_function_decl), \ ++ FIRST_PARM_OFFSET (FNDECL) + current_function_pretend_args_size) ++ ++/* ----------------------------------------- * ++ * Eliminating Frame Pointer and Arg Pointer ++ * ----------------------------------------- */ ++ ++#define FRAME_POINTER_REQUIRED 0 ++ ++#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}} ++ ++#define CAN_ELIMINATE(FROM, TO) \ ++ ((TO) == STACK_POINTER_REGNUM ? ! frame_pointer_needed : 1) ++ ++#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ ++ (OFFSET) = nios2_initial_elimination_offset ((FROM), (TO)) ++ ++/* Treat LOC as a byte offset from the stack pointer and round it up ++ to the next fully-aligned offset. */ ++#define STACK_ALIGN(LOC) \ ++ (((LOC) + ((PREFERRED_STACK_BOUNDARY / 8) - 1)) & \ ++ ~((PREFERRED_STACK_BOUNDARY / 8) - 1)) ++ ++ ++/* ------------------------------ * ++ * Passing Arguments in Registers ++ * ------------------------------ */ ++ ++/* see nios2.c */ ++#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ ++ (function_arg (&CUM, MODE, TYPE, NAMED)) ++ ++#define FUNCTION_ARG_CALLEE_COPIES(CUM, MODE, TYPE, NAMED) 0 ++ ++typedef struct nios2_args ++{ ++ int regs_used; ++} CUMULATIVE_ARGS; ++ ++/* This is to initialize the above unused CUM data type */ ++#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS) \ ++ (init_cumulative_args (&CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS)) ++ ++#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ ++ (function_arg_advance (&CUM, MODE, TYPE, NAMED)) ++ ++#define FUNCTION_ARG_PADDING(MODE, TYPE) \ ++ (nios2_function_arg_padding_upward ((MODE), (TYPE)) ? upward : downward) ++ ++#define PAD_VARARGS_DOWN \ ++ (FUNCTION_ARG_PADDING (TYPE_MODE (type), type) == downward) ++ ++#define BLOCK_REG_PADDING(MODE, TYPE, FIRST) \ ++ (nios2_block_reg_padding_upward ((MODE), (TYPE), (FIRST)) ? upward : \ ++ downward) ++ ++#define FUNCTION_ARG_REGNO_P(REGNO) \ ++ ((REGNO) >= FIRST_ARG_REGNO && (REGNO) <= LAST_ARG_REGNO) ++ ++/* ----------------------------- * ++ * Generating Code for Profiling ++ * ----------------------------- */ ++ ++ ++#define PROFILE_BEFORE_PROLOGUE ++#define NO_PROFILE_COUNTERS 1 ++#define FUNCTION_PROFILER(FILE, LABELNO) \ ++ function_profiler ((FILE), (LABELNO)) ++ ++/* --------------------------------------- * ++ * Passing Function Arguments on the Stack ++ * --------------------------------------- */ ++ ++#define PUSH_ARGS 0 ++#define ACCUMULATE_OUTGOING_ARGS 1 ++ ++#define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, STACKSIZE) 0 ++ ++/* --------------------------------------- * ++ * How Scalar Function Values Are Returned ++ * --------------------------------------- */ ++ ++#define FUNCTION_VALUE(VALTYPE, FUNC) \ ++ gen_rtx_REG(TYPE_MODE(VALTYPE), FIRST_RETVAL_REGNO) ++ ++#define LIBCALL_VALUE(MODE) \ ++ gen_rtx_REG(MODE, FIRST_RETVAL_REGNO) ++ ++#define FUNCTION_VALUE_REGNO_P(REGNO) ((REGNO) == FIRST_RETVAL_REGNO) ++ ++/* ----------------------------- * ++ * How Large Values Are Returned ++ * ----------------------------- */ ++ ++ ++#define RETURN_IN_MEMORY(TYPE) \ ++ nios2_return_in_memory (TYPE) ++ ++ ++#define STRUCT_VALUE 0 ++ ++#define DEFAULT_PCC_STRUCT_RETURN 0 ++ ++/******************* ++ * Addressing Modes ++ *******************/ ++ ++ ++#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \ ++ do \ ++ { \ ++ X = nios2_legitimize_address (X, OLDX, MODE); \ ++ if (memory_address_p (MODE, X)) \ ++ goto WIN; \ ++ } \ ++ while (0) ++ ++#define CONSTANT_ADDRESS_P(X) \ ++ (CONSTANT_P (X) && nios2_legitimate_address (X, Pmode, 0)) ++ ++#define MAX_REGS_PER_ADDRESS 1 ++ ++/* Go to ADDR if X is a valid address. */ ++#ifndef REG_OK_STRICT ++#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ ++ { \ ++ if (nios2_legitimate_address ((X), (MODE), 0)) \ ++ goto ADDR; \ ++ } ++#else ++#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ ++ { \ ++ if (nios2_legitimate_address ((X), (MODE), 1)) \ ++ goto ADDR; \ ++ } ++#endif ++ ++#ifndef REG_OK_STRICT ++#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P2 (REGNO (X), 0) ++#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P2 (REGNO (X), 0) ++#else ++#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P2 (REGNO (X), 1) ++#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P2 (REGNO (X), 1) ++#endif ++ ++#define LEGITIMATE_CONSTANT_P(X) nios2_legitimate_constant (X) ++ ++/* Nios II has no mode dependent addresses. */ ++#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) ++ ++/* Set if this has a weak declaration */ ++#define SYMBOL_FLAG_WEAK_DECL (1 << SYMBOL_FLAG_MACH_DEP_SHIFT) ++#define SYMBOL_REF_WEAK_DECL_P(RTX) \ ++ ((SYMBOL_REF_FLAGS (RTX) & SYMBOL_FLAG_WEAK_DECL) != 0) ++ ++ ++/* true if a symbol is both small and not weak. In this case, gp ++ relative access can be used. gp relative access cannot be used in ++ position independent code. gp relative access cannot be used for externally ++ defined symbols, because the compilation unit which defines the symbol may ++ place it in a section that cannot be reached from gp. */ ++#define SYMBOL_REF_IN_NIOS2_SMALL_DATA_P(RTX) \ ++ (!flag_pic && SYMBOL_REF_SMALL_P(RTX) && !SYMBOL_REF_WEAK_DECL_P(RTX) && \ ++ !SYMBOL_REF_EXTERNAL_P(RTX) && SYMBOL_REF_TLS_MODEL(RTX)==0) ++ ++/***************** ++ * Describing Relative Costs of Operations ++ *****************/ ++ ++#define SLOW_BYTE_ACCESS 1 ++ ++/* It is as good to call a constant function address as to call an address ++ kept in a register. ++ ??? Not true anymore really. Now that call cannot address full range ++ of memory callr may need to be used */ ++ ++#define NO_FUNCTION_CSE ++ ++/*************************** ++ * Position Independent Code ++ ***************************/ ++ ++#define PIC_OFFSET_TABLE_REGNUM 22 ++ ++#define LEGITIMATE_PIC_OPERAND_P(X) nios2_legitimate_pic_operand_p (X) ++ ++/***************************************** ++ * Defining the Output Assembler Language ++ *****************************************/ ++ ++/* ------------------------------------------ * ++ * The Overall Framework of an Assembler File ++ * ------------------------------------------ */ ++ ++#define ASM_APP_ON "#APP\n" ++#define ASM_APP_OFF "#NO_APP\n" ++ ++#define ASM_COMMENT_START "# " ++ ++/* ------------------------------- * ++ * Output and Generation of Labels ++ * ------------------------------- */ ++ ++#define GLOBAL_ASM_OP "\t.global\t" ++ ++ ++/* -------------- * ++ * Output of Data ++ * -------------- */ ++ ++/* -------------------------------- * ++ * Assembler Commands for Alignment ++ * -------------------------------- */ ++ ++#define ASM_OUTPUT_ALIGN(FILE, LOG) \ ++ do { \ ++ fprintf ((FILE), "%s%d\n", ALIGN_ASM_OP, (LOG)); \ ++ } while (0) ++ ++ ++/* -------------------------------- * ++ * Output of Assembler Instructions ++ * -------------------------------- */ ++ ++#define REGISTER_NAMES \ ++{ \ ++ "zero", \ ++ "at", \ ++ "r2", \ ++ "r3", \ ++ "r4", \ ++ "r5", \ ++ "r6", \ ++ "r7", \ ++ "r8", \ ++ "r9", \ ++ "r10", \ ++ "r11", \ ++ "r12", \ ++ "r13", \ ++ "r14", \ ++ "r15", \ ++ "r16", \ ++ "r17", \ ++ "r18", \ ++ "r19", \ ++ "r20", \ ++ "r21", \ ++ "r22", \ ++ "r23", \ ++ "et", \ ++ "bt", \ ++ "gp", \ ++ "sp", \ ++ "fp", \ ++ "ta", \ ++ "ba", \ ++ "ra", \ ++ "status", \ ++ "estatus", \ ++ "bstatus", \ ++ "ipri", \ ++ "ecause", \ ++ "pc", \ ++ "fake_fp", \ ++ "fake_ap", \ ++} ++ ++#define ADDITIONAL_REGISTER_NAMES \ ++{ \ ++ {"r0", 0}, \ ++ {"r1", 1}, \ ++ {"r24", 24}, \ ++ {"r25", 25}, \ ++ {"r26", 26}, \ ++ {"r27", 27}, \ ++ {"r28", 28}, \ ++ {"r29", 29}, \ ++ {"r30", 30}, \ ++ {"r31", 31} \ ++} ++ ++ ++#define ASM_OUTPUT_OPCODE(STREAM, PTR)\ ++ (PTR) = asm_output_opcode (STREAM, PTR) ++ ++#define PRINT_OPERAND(STREAM, X, CODE) \ ++ nios2_print_operand (STREAM, X, CODE) ++ ++#define PRINT_OPERAND_ADDRESS(STREAM, X) \ ++ nios2_print_operand_address (STREAM, X) ++ ++#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ ++do { fputs (integer_asm_op (POINTER_SIZE / BITS_PER_UNIT, TRUE), FILE); \ ++ fprintf (FILE, ".L%u\n", (unsigned) (VALUE)); \ ++ } while (0) ++ ++#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM, BODY, VALUE, REL)\ ++do { fputs (integer_asm_op (POINTER_SIZE / BITS_PER_UNIT, TRUE), STREAM); \ ++ fprintf (STREAM, ".L%u-.L%u\n", (unsigned) (VALUE), (unsigned) (REL)); \ ++ } while (0) ++ ++ ++/* ------------ * ++ * Label Output ++ * ------------ */ ++ ++ ++/* ---------------------------------------------------- * ++ * Dividing the Output into Sections (Texts, Data, ...) ++ * ---------------------------------------------------- */ ++ ++/* Output before read-only data. */ ++#define TEXT_SECTION_ASM_OP "\t.section\t.text" ++ ++/* Output before writable data. */ ++#define DATA_SECTION_ASM_OP "\t.section\t.data" ++ ++ ++/* Default the definition of "small data" to 8 bytes. */ ++/* ??? How come I can't use HOST_WIDE_INT here? */ ++extern unsigned long nios2_section_threshold; ++#define NIOS2_DEFAULT_GVALUE 8 ++ ++ ++ ++/* This says how to output assembler code to declare an ++ uninitialized external linkage data object. Under SVR4, ++ the linker seems to want the alignment of data objects ++ to depend on their types. We do exactly that here. */ ++ ++#undef COMMON_ASM_OP ++#define COMMON_ASM_OP "\t.comm\t" ++ ++#undef ASM_OUTPUT_ALIGNED_COMMON ++#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \ ++do \ ++{ \ ++ fprintf ((FILE), "%s", COMMON_ASM_OP); \ ++ assemble_name ((FILE), (NAME)); \ ++ fprintf ((FILE), ","HOST_WIDE_INT_PRINT_UNSIGNED",%u\n", (SIZE), \ ++ (ALIGN) / BITS_PER_UNIT); \ ++} \ ++while (0) ++ ++ ++/* This says how to output assembler code to declare an ++ uninitialized internal linkage data object. Under SVR4, ++ the linker seems to want the alignment of data objects ++ to depend on their types. We do exactly that here. */ ++ ++#undef ASM_OUTPUT_ALIGNED_LOCAL ++#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \ ++do { \ ++ if ((SIZE) <= nios2_section_threshold) \ ++ named_section (0, ".sbss", 0); \ ++ else \ ++ named_section (0, ".bss", 0); \ ++ ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object"); \ ++ if (!flag_inhibit_size_directive) \ ++ ASM_OUTPUT_SIZE_DIRECTIVE (FILE, NAME, SIZE); \ ++ ASM_OUTPUT_ALIGN ((FILE), exact_log2((ALIGN) / BITS_PER_UNIT)); \ ++ ASM_OUTPUT_LABEL(FILE, NAME); \ ++ ASM_OUTPUT_SKIP((FILE), (SIZE) ? (SIZE) : 1); \ ++} while (0) ++ ++/* Put the jump tables in .text because when using position independent code, ++ Nios II elf has no relocation that can represent arbitrary differences ++ between symbols in different sections. */ ++#define JUMP_TABLES_IN_TEXT_SECTION 1 ++ ++/* Exception Handling */ ++ ++/* Describe __builtin_eh_return */ ++#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, LAST_RETVAL_REGNO) ++#define EH_RETURN_DATA_REGNO(N) ((N) <= (LAST_ARG_REGNO - FIRST_ARG_REGNO) \ ++ ? (N) + FIRST_ARG_REGNO : INVALID_REGNUM) ++#define ASM_PREFERRED_EH_DATA_FORMAT(CODE, GLOBAL) \ ++ (!flag_pic ? DW_EH_PE_sdata4 \ ++ /* FIXME: These get expanded to dynamic relocs, which is wrong */ \ ++ /* : !(GLOBAL) ? DW_EH_PE_pcrel | DW_EH_PE_sdata4 */ \ ++ : DW_EH_PE_aligned) ++ ++/*************************** ++ * Miscellaneous Parameters ++ ***************************/ ++ ++#define MOVE_MAX 4 ++ ++#define STORE_FLAG_VALUE 1 ++#define Pmode SImode ++#define FUNCTION_MODE QImode ++ ++#define REGISTER_TARGET_PRAGMAS() nios2_register_target_pragmas () ++ ++#define CASE_VECTOR_MODE Pmode ++ ++#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 ++ ++#define LOAD_EXTEND_OP(MODE) (ZERO_EXTEND) ++ ++#define WORD_REGISTER_OPERATIONS +Index: gcc-4.1.2/gcc/config/nios2/nios2.md +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gcc-4.1.2/gcc/config/nios2/nios2.md 2010-06-30 08:50:26.000000000 +0200 +@@ -0,0 +1,3012 @@ ++;; NOT ASSIGNED TO FSF. COPYRIGHT ALTERA. ++;; ++;; Machine Description for Altera NIOS 2G NIOS2 version. ++;; Copyright (C) 2005 Altera ++;; Contributed by Jonah Graham (jgraham@altera.com) and ++;; Will Reece (wreece@altera.com). ++;; ++;; This file is part of GNU CC. ++;; ++;; GNU CC 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, or (at your option) ++;; any later version. ++;; ++;; GNU CC 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 GNU CC; see the file COPYING. If not, write to ++;; the Free Software Foundation, 59 Temple Place - Suite 330, ++;; Boston, MA 02111-1307, USA. */ ++ ++ ++ ++ ++;***************************************************************************** ++;* ++;* constraint strings ++;* ++;***************************************************************************** ++; ++; We use the following constraint letters for constants ++; ++; I: -32768 to -32767 ++; J: 0 to 65535 ++; K: $nnnn0000 for some nnnn ++; L: 0 to 31 (for shift counts) ++; M: 0 ++; N: 0 to 255 (for custom instruction numbers) ++; O: 0 to 31 (for control register numbers) ++; ++; We use the following built-in register classes: ++; ++; r: general purpose register (r0..r31) ++; m: memory operand ++; ++; Plus, we define the following constraint strings: ++; ++; S: symbol that is in the "small data" area ++; Dnn: Dnn_REG (just rnn) ++; ++ ++ ++ ++;***************************************************************************** ++;* ++;* constants ++;* ++;***************************************************************************** ++(define_constants [ ++ (UNSPEC_BLOCKAGE 0) ++ (UNSPEC_LDBIO 1) ++ (UNSPEC_LDBUIO 2) ++ (UNSPEC_LDHIO 3) ++ (UNSPEC_LDHUIO 4) ++ (UNSPEC_LDWIO 5) ++ (UNSPEC_STBIO 6) ++ (UNSPEC_STHIO 7) ++ (UNSPEC_STWIO 8) ++ (UNSPEC_SYNC 9) ++ (UNSPEC_WRCTL 10) ++ (UNSPEC_RDCTL 11) ++ (UNSPEC_TRAP 12) ++ (UNSPEC_STACK_OVERFLOW_DETECT_AND_TRAP 13) ++ (UNSPEC_FCOSS 14) ++ (UNSPEC_FCOSD 15) ++ (UNSPEC_FSINS 16) ++ (UNSPEC_FSIND 17) ++ (UNSPEC_FTANS 18) ++ (UNSPEC_FTAND 19) ++ (UNSPEC_FATANS 20) ++ (UNSPEC_FATAND 21) ++ (UNSPEC_FEXPS 22) ++ (UNSPEC_FEXPD 23) ++ (UNSPEC_FLOGS 24) ++ (UNSPEC_FLOGD 25) ++ (UNSPEC_FWRX 26) ++ (UNSPEC_FWRY 27) ++ (UNSPEC_FRDXLO 28) ++ (UNSPEC_FRDXHI 29) ++ (UNSPEC_FRDY 30) ++ (UNSPEC_LOAD_GOT_REGISTER 31) ++ (UNSPEC_PIC_SYM 32) ++ (UNSPEC_PIC_CALL_SYM 33) ++ (UNSPEC_TLS 34) ++ (UNSPEC_TLS_LDM 35) ++ (UNSPEC_LOAD_TLS_IE 36) ++ (UNSPEC_ADD_TLS_LE 37) ++ (UNSPEC_ADD_TLS_GD 38) ++ (UNSPEC_ADD_TLS_LDM 39) ++ (UNSPEC_ADD_TLS_LDO 40) ++ ++ (UNSPEC_EH_RETURN 41) ++ ++ ;; Note that values 100..151 are used by custom instructions, see below. ++]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* instruction scheduler ++;* ++;***************************************************************************** ++ ++; No schedule info is currently available, using an assumption that no ++; instruction can use the results of the previous instruction without ++; incuring a stall. ++ ++; length of an instruction (in bytes) ++(define_attr "length" "" (const_int 4)) ++(define_attr "type" ++ "unknown,complex,control,alu,cond_alu,st,ld,shift,mul,div,custom" ++ (const_string "complex")) ++ ++(define_asm_attributes ++ [(set_attr "length" "4") ++ (set_attr "type" "complex")]) ++ ++(define_automaton "nios2") ++(automata_option "v") ++;(automata_option "no-minimization") ++(automata_option "ndfa") ++ ++; The nios2 pipeline is fairly straightforward for the fast model. ++; Every alu operation is pipelined so that an instruction can ++; be issued every cycle. However, there are still potential ++; stalls which this description tries to deal with. ++ ++(define_cpu_unit "cpu" "nios2") ++ ++(define_insn_reservation "complex" 1 ++ (eq_attr "type" "complex") ++ "cpu") ++ ++(define_insn_reservation "control" 1 ++ (eq_attr "type" "control") ++ "cpu") ++ ++(define_insn_reservation "alu" 1 ++ (eq_attr "type" "alu") ++ "cpu") ++ ++(define_insn_reservation "cond_alu" 1 ++ (eq_attr "type" "cond_alu") ++ "cpu") ++ ++(define_insn_reservation "st" 1 ++ (eq_attr "type" "st") ++ "cpu") ++ ++(define_insn_reservation "custom" 1 ++ (eq_attr "type" "custom") ++ "cpu") ++ ++; shifts, muls and lds have three cycle latency ++(define_insn_reservation "ld" 3 ++ (eq_attr "type" "ld") ++ "cpu") ++ ++(define_insn_reservation "shift" 3 ++ (eq_attr "type" "shift") ++ "cpu") ++ ++(define_insn_reservation "mul" 3 ++ (eq_attr "type" "mul") ++ "cpu") ++ ++(define_insn_reservation "div" 1 ++ (eq_attr "type" "div") ++ "cpu") ++ ++ ++;***************************************************************************** ++;* ++;* MOV Instructions ++;* ++;***************************************************************************** ++ ++(define_expand "movqi" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "") ++ (match_operand:QI 1 "general_operand" ""))] ++ "" ++{ ++ if (nios2_emit_move_sequence (operands, QImode)) ++ DONE; ++}) ++ ++(define_insn "movqi_internal" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "=m, r,r, r") ++ (match_operand:QI 1 "general_operand" "rM,m,rM,I"))] ++ "(register_operand (operands[0], QImode) ++ || reg_or_0_operand (operands[1], QImode))" ++ "@ ++ stb%o0\\t%z1, %0 ++ ldbu%o1\\t%0, %1 ++ mov\\t%0, %z1 ++ movi\\t%0, %1" ++ [(set_attr "type" "st,ld,alu,alu")]) ++ ++(define_insn "ldbio" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDBIO)) ++ (use (match_operand:SI 1 "memory_operand" "m"))] ++ "" ++ "ldbio\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_insn "ldbuio" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDBUIO)) ++ (use (match_operand:SI 1 "memory_operand" "m"))] ++ "" ++ "ldbuio\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_insn "stbio" ++ [(set (match_operand:SI 0 "memory_operand" "=m") ++ (match_operand:SI 1 "reg_or_0_operand" "rM")) ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_STBIO)] ++ "" ++ "stbio\\t%z1, %0" ++ [(set_attr "type" "st")]) ++ ++ ++(define_expand "movhi" ++ [(set (match_operand:HI 0 "nonimmediate_operand" "") ++ (match_operand:HI 1 "general_operand" ""))] ++ "" ++{ ++ if (nios2_emit_move_sequence (operands, HImode)) ++ DONE; ++}) ++ ++(define_insn "movhi_internal" ++ [(set (match_operand:HI 0 "nonimmediate_operand" "=m, r,r, r,r") ++ (match_operand:HI 1 "general_operand" "rM,m,rM,I,J"))] ++ "(register_operand (operands[0], HImode) ++ || reg_or_0_operand (operands[1], HImode))" ++ "@ ++ sth%o0\\t%z1, %0 ++ ldhu%o1\\t%0, %1 ++ mov\\t%0, %z1 ++ movi\\t%0, %1 ++ movui\\t%0, %1" ++ [(set_attr "type" "st,ld,alu,alu,alu")]) ++ ++(define_insn "ldhio" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDHIO)) ++ (use (match_operand:SI 1 "memory_operand" "m"))] ++ "" ++ "ldhio\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_insn "ldhuio" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDHUIO)) ++ (use (match_operand:SI 1 "memory_operand" "m"))] ++ "" ++ "ldhuio\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_insn "sthio" ++ [(set (match_operand:SI 0 "memory_operand" "=m") ++ (match_operand:SI 1 "reg_or_0_operand" "rM")) ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_STHIO)] ++ "" ++ "sthio\\t%z1, %0" ++ [(set_attr "type" "st")]) ++ ++(define_expand "movsi" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "") ++ (match_operand:SI 1 "general_operand" ""))] ++ "" ++{ ++ if (nios2_emit_move_sequence (operands, SImode)) ++ DONE; ++}) ++ ++(define_insn "movsi_internal" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "=m, r,r, r,r,r,r") ++ (match_operand:SI 1 "general_operand" "rM,m,rM,I,J,S,i"))] ++ "(register_operand (operands[0], SImode) ++ || reg_or_0_operand (operands[1], SImode))" ++ "@ ++ stw%o0\\t%z1, %0 ++ ldw%o1\\t%0, %1 ++ mov\\t%0, %z1 ++ movi\\t%0, %1 ++ movui\\t%0, %1 ++ addi\\t%0, gp, %%gprel(%1) ++ movhi\\t%0, %H1\;addi\\t%0, %0, %L1" ++ [(set_attr "type" "st,ld,alu,alu,alu,alu,alu")]) ++ ++(define_insn "ldwio" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDWIO)) ++ (use (match_operand:SI 1 "memory_operand" "m"))] ++ "" ++ "ldwio\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_insn "stwio" ++ [(set (match_operand:SI 0 "memory_operand" "=m") ++ (match_operand:SI 1 "reg_or_0_operand" "rM")) ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_STWIO)] ++ "" ++ "stwio\\t%z1, %0" ++ [(set_attr "type" "st")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* zero extension ++;* ++;***************************************************************************** ++ ++ ++(define_insn "zero_extendhisi2" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))] ++ "" ++ "@ ++ andi\\t%0, %1, 0xffff ++ ldhu%o1\\t%0, %1" ++ [(set_attr "type" "alu,ld")]) ++ ++(define_insn "zero_extendqihi2" ++ [(set (match_operand:HI 0 "register_operand" "=r,r") ++ (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "r,m")))] ++ "" ++ "@ ++ andi\\t%0, %1, 0xff ++ ldbu%o1\\t%0, %1" ++ [(set_attr "type" "alu,ld")]) ++ ++(define_insn "zero_extendqisi2" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,m")))] ++ "" ++ "@ ++ andi\\t%0, %1, 0xff ++ ldbu%o1\\t%0, %1" ++ [(set_attr "type" "alu,ld")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* sign extension ++;* ++;***************************************************************************** ++(define_expand "extendhisi2" ++ [(set (match_operand:SI 0 "register_operand" "") ++ (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] ++ "" ++{ ++}) ++ ++(define_insn "*extendhisi2" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (sign_extend:SI (match_operand:HI 1 "register_operand" "r")))] ++ "" ++ "#") ++ ++(define_split ++ [(set (match_operand:SI 0 "register_operand" "") ++ (sign_extend:SI (match_operand:HI 1 "register_operand" "")))] ++ "reload_completed" ++ [(set (match_dup 0) ++ (and:SI (match_dup 1) (const_int 65535))) ++ (set (match_dup 0) ++ (xor:SI (match_dup 0) (const_int 32768))) ++ (set (match_dup 0) ++ (plus:SI (match_dup 0) (const_int -32768)))] ++ "operands[1] = gen_lowpart (SImode, operands[1]);") ++ ++(define_insn "extendhisi2_internal" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))] ++ "" ++ "ldh%o1\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++ ++(define_expand "extendqihi2" ++ [(set (match_operand:HI 0 "register_operand" "") ++ (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))] ++ "" ++{ ++}) ++ ++(define_insn "*extendqihi2" ++ [(set (match_operand:HI 0 "register_operand" "=r") ++ (sign_extend:HI (match_operand:QI 1 "register_operand" "r")))] ++ "" ++ "#") ++ ++(define_split ++ [(set (match_operand:HI 0 "register_operand" "") ++ (sign_extend:HI (match_operand:QI 1 "register_operand" "")))] ++ "reload_completed" ++ [(set (match_dup 0) ++ (and:SI (match_dup 1) (const_int 255))) ++ (set (match_dup 0) ++ (xor:SI (match_dup 0) (const_int 128))) ++ (set (match_dup 0) ++ (plus:SI (match_dup 0) (const_int -128)))] ++ "operands[0] = gen_lowpart (SImode, operands[0]); ++ operands[1] = gen_lowpart (SImode, operands[1]);") ++ ++ ++ ++(define_insn "extendqihi2_internal" ++ [(set (match_operand:HI 0 "register_operand" "=r") ++ (sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))] ++ "" ++ "ldb%o1\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++ ++(define_expand "extendqisi2" ++ [(set (match_operand:SI 0 "register_operand" "") ++ (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] ++ "" ++{ ++}) ++ ++(define_insn "*extendqisi2" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (sign_extend:SI (match_operand:QI 1 "register_operand" "r")))] ++ "" ++ "#") ++ ++(define_split ++ [(set (match_operand:SI 0 "register_operand" "") ++ (sign_extend:SI (match_operand:QI 1 "register_operand" "")))] ++ "reload_completed" ++ [(set (match_dup 0) ++ (and:SI (match_dup 1) (const_int 255))) ++ (set (match_dup 0) ++ (xor:SI (match_dup 0) (const_int 128))) ++ (set (match_dup 0) ++ (plus:SI (match_dup 0) (const_int -128)))] ++ "operands[1] = gen_lowpart (SImode, operands[1]);") ++ ++(define_insn "extendqisi2_insn" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))] ++ "" ++ "ldb%o1\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++ ++ ++ ++;***************************************************************************** ++;* ++;* Arithmetic Operations ++;* ++;***************************************************************************** ++ ++(define_insn "addsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (plus:SI (match_operand:SI 1 "register_operand" "%r,r") ++ (match_operand:SI 2 "arith_operand" "r,I")))] ++ "" ++ "add%i2\\t%0, %1, %z2" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "addsf3" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (plus:SF (match_operand:SF 1 "register_operand" "%r") ++ (match_operand:SF 2 "register_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_addsf3].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_addsf3].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "adddf3" ++ [(set (match_operand:DF 0 "register_operand" "=r") ++ (plus:DF (match_operand:DF 1 "register_operand" "%r") ++ (match_operand:DF 2 "register_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_adddf3].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_adddf3].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "subsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "register_operand" "r")))] ++ "" ++ "sub\\t%0, %z1, %2" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "subsf3" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (minus:SF (match_operand:SF 1 "register_operand" "r") ++ (match_operand:SF 2 "register_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_subsf3].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_subsf3].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "subdf3" ++ [(set (match_operand:DF 0 "register_operand" "=r") ++ (minus:DF (match_operand:DF 1 "register_operand" "r") ++ (match_operand:DF 2 "register_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_subdf3].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_subdf3].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "mulsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (mult:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "arith_operand" "r,I")))] ++ "TARGET_HAS_MUL" ++ "mul%i2\\t%0, %1, %z2" ++ [(set_attr "type" "mul")]) ++ ++(define_insn "mulsf3" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (mult:SF (match_operand:SF 1 "register_operand" "%r") ++ (match_operand:SF 2 "register_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_mulsf3].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_mulsf3].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "muldf3" ++ [(set (match_operand:DF 0 "register_operand" "=r") ++ (mult:DF (match_operand:DF 1 "register_operand" "%r") ++ (match_operand:DF 2 "register_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_muldf3].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_muldf3].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_expand "divsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (div:SI (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")))] ++ "" ++{ ++ if (!TARGET_HAS_DIV) ++ { ++ if (!TARGET_FAST_SW_DIV) ++ FAIL; ++ else ++ { ++ if (nios2_emit_expensive_div (operands, SImode)) ++ DONE; ++ } ++ } ++}) ++ ++(define_insn "divsi3_insn" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (div:SI (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")))] ++ "TARGET_HAS_DIV" ++ "div\\t%0, %1, %2" ++ [(set_attr "type" "div")]) ++ ++(define_insn "divsf3" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (div:SF (match_operand:SF 1 "register_operand" "r") ++ (match_operand:SF 2 "register_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_divsf3].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_divsf3].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "divdf3" ++ [(set (match_operand:DF 0 "register_operand" "=r") ++ (div:DF (match_operand:DF 1 "register_operand" "r") ++ (match_operand:DF 2 "register_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_divdf3].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_divdf3].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "udivsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (udiv:SI (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")))] ++ "TARGET_HAS_DIV" ++ "divu\\t%0, %1, %2" ++ [(set_attr "type" "div")]) ++ ++(define_insn "smulsi3_highpart" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (truncate:SI ++ (lshiftrt:DI ++ (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r")) ++ (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))) ++ (const_int 32))))] ++ "TARGET_HAS_MULX" ++ "mulxss\\t%0, %1, %2" ++ [(set_attr "type" "mul")]) ++ ++(define_insn "umulsi3_highpart" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (truncate:SI ++ (lshiftrt:DI ++ (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r")) ++ (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))) ++ (const_int 32))))] ++ "TARGET_HAS_MULX" ++ "mulxuu\\t%0, %1, %2" ++ [(set_attr "type" "mul")]) ++ ++ ++(define_expand "mulsidi3_little_endian" ++ [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 0) ++ (mult:SI (match_operand:SI 1 "register_operand" "") ++ (match_operand:SI 2 "register_operand" ""))) ++ (set (subreg:SI (match_dup 0) 4) ++ (truncate:SI (lshiftrt:DI (mult:DI (sign_extend:DI (match_dup 1)) ++ (sign_extend:DI (match_dup 2))) ++ (const_int 32))))] ++ "TARGET_HAS_MULX && !WORDS_BIG_ENDIAN" ++ "") ++ ++(define_expand "mulsidi3_big_endian" ++ [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 4) ++ (mult:SI (match_operand:SI 1 "register_operand" "") ++ (match_operand:SI 2 "register_operand" ""))) ++ (set (subreg:SI (match_dup 0) 0) ++ (truncate:SI (lshiftrt:DI (mult:DI (sign_extend:DI (match_dup 1)) ++ (sign_extend:DI (match_dup 2))) ++ (const_int 32))))] ++ "TARGET_HAS_MULX && WORDS_BIG_ENDIAN" ++ "") ++ ++(define_expand "mulsidi3" ++ [(match_operand:DI 0 "register_operand" "") ++ (match_operand:SI 1 "register_operand" "") ++ (match_operand:SI 2 "register_operand" "")] ++ "TARGET_HAS_MULX" ++ { ++ if (WORDS_BIG_ENDIAN) ++ { ++ emit_insn (gen_mulsidi3_big_endian (operands[0], ++ operands[1], ++ operands[2])); ++ } ++ else ++ { ++ emit_insn (gen_mulsidi3_little_endian (operands[0], ++ operands[1], ++ operands[2])); ++ } ++ DONE; ++ }) ++ ++(define_expand "umulsidi3_little_endian" ++ [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 0) ++ (mult:SI (match_operand:SI 1 "register_operand" "") ++ (match_operand:SI 2 "register_operand" ""))) ++ (set (subreg:SI (match_dup 0) 4) ++ (truncate:SI (lshiftrt:DI (mult:DI (zero_extend:DI (match_dup 1)) ++ (zero_extend:DI (match_dup 2))) ++ (const_int 32))))] ++ "TARGET_HAS_MULX && !WORDS_BIG_ENDIAN" ++ "") ++ ++(define_expand "umulsidi3_big_endian" ++ [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 4) ++ (mult:SI (match_operand:SI 1 "register_operand" "") ++ (match_operand:SI 2 "register_operand" ""))) ++ (set (subreg:SI (match_dup 0) 0) ++ (truncate:SI (lshiftrt:DI (mult:DI (zero_extend:DI (match_dup 1)) ++ (zero_extend:DI (match_dup 2))) ++ (const_int 32))))] ++ "TARGET_HAS_MULX && WORDS_BIG_ENDIAN" ++ "") ++ ++(define_expand "umulsidi3" ++ [(match_operand:DI 0 "register_operand" "") ++ (match_operand:SI 1 "register_operand" "") ++ (match_operand:SI 2 "register_operand" "")] ++ "TARGET_HAS_MULX" ++ { ++ if (WORDS_BIG_ENDIAN) ++ { ++ emit_insn (gen_umulsidi3_big_endian (operands[0], ++ operands[1], ++ operands[2])); ++ } ++ else ++ { ++ emit_insn (gen_umulsidi3_little_endian (operands[0], ++ operands[1], ++ operands[2])); ++ } ++ DONE; ++ }) ++ ++ ++;***************************************************************************** ++;* ++;* Negate and ones complement ++;* ++;***************************************************************************** ++ ++(define_insn "negsi2" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (neg:SI (match_operand:SI 1 "register_operand" "r")))] ++ "" ++{ ++ operands[2] = const0_rtx; ++ return "sub\\t%0, %z2, %1"; ++} ++ [(set_attr "type" "alu")]) ++ ++(define_insn "negsf2" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (neg:SF (match_operand:SF 1 "register_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_negsf2].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_negsf2].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "negdf2" ++ [(set (match_operand:DF 0 "register_operand" "=r") ++ (neg:DF (match_operand:DF 1 "register_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_negdf2].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_negdf2].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "one_cmplsi2" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (not:SI (match_operand:SI 1 "register_operand" "r")))] ++ "" ++{ ++ operands[2] = const0_rtx; ++ return "nor\\t%0, %z2, %1"; ++} ++ [(set_attr "type" "alu")]) ++ ++ ++;***************************************************************************** ++;* ++;* Miscellaneous floating point ++;* ++;***************************************************************************** ++(define_insn "nios2_fwrx" ++ [(unspec_volatile [(match_operand:DF 0 "register_operand" "r")] UNSPEC_FWRX)] ++ "nios2_fpu_insns[nios2_fpu_nios2_fwrx].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_nios2_fwrx].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "nios2_fwry" ++ [(unspec_volatile [(match_operand:SF 0 "register_operand" "r")] UNSPEC_FWRY)] ++ "nios2_fpu_insns[nios2_fpu_nios2_fwry].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_nios2_fwry].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "nios2_frdxlo" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(const_int 0)] UNSPEC_FRDXLO))] ++ "nios2_fpu_insns[nios2_fpu_nios2_frdxlo].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_nios2_frdxlo].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "nios2_frdxhi" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(const_int 0)] UNSPEC_FRDXHI))] ++ "nios2_fpu_insns[nios2_fpu_nios2_frdxhi].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_nios2_frdxhi].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "nios2_frdy" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(const_int 0)] UNSPEC_FRDY))] ++ "nios2_fpu_insns[nios2_fpu_nios2_frdy].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_nios2_frdy].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "minsf3" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (if_then_else:SF (lt:SF (match_operand:SF 1 "register_operand" "%r") ++ (match_operand:SF 2 "register_operand" "r")) ++ (match_dup 1) ++ (match_dup 2)))] ++ "nios2_fpu_insns[nios2_fpu_minsf3].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_minsf3].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "mindf3" ++ [(set (match_operand:DF 0 "register_operand" "=r") ++ (if_then_else:DF (lt:DF (match_operand:DF 1 "register_operand" "%r") ++ (match_operand:DF 2 "register_operand" "r")) ++ (match_dup 1) ++ (match_dup 2)))] ++ "nios2_fpu_insns[nios2_fpu_mindf3].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_mindf3].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "maxsf3" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (if_then_else:SF (lt:SF (match_operand:SF 1 "register_operand" "%r") ++ (match_operand:SF 2 "register_operand" "r")) ++ (match_dup 2) ++ (match_dup 1)))] ++ "nios2_fpu_insns[nios2_fpu_maxsf3].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_maxsf3].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "maxdf3" ++ [(set (match_operand:DF 0 "register_operand" "=r") ++ (if_then_else:DF (lt:DF (match_operand:DF 1 "register_operand" "%r") ++ (match_operand:DF 2 "register_operand" "r")) ++ (match_dup 2) ++ (match_dup 1)))] ++ "nios2_fpu_insns[nios2_fpu_maxdf3].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_maxdf3].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "abssf2" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (abs:SF (match_operand:SF 1 "register_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_abssf2].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_abssf2].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "absdf2" ++ [(set (match_operand:DF 0 "register_operand" "=r") ++ (abs:DF (match_operand:DF 1 "register_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_absdf2].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_absdf2].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "sqrtsf2" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (sqrt:SF (match_operand:SF 1 "register_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_sqrtsf2].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_sqrtsf2].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "sqrtdf2" ++ [(set (match_operand:DF 0 "register_operand" "=r") ++ (sqrt:DF (match_operand:DF 1 "register_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_sqrtdf2].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_sqrtdf2].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "cossf2" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec:SF [(match_operand:SF 1 "register_operand" "r")] UNSPEC_FCOSS))] ++ "nios2_fpu_insns[nios2_fpu_cossf2].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_cossf2].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "cosdf2" ++ [(set (match_operand:DF 0 "register_operand" "=r") ++ (unspec:DF [(match_operand:DF 1 "register_operand" "r")] UNSPEC_FCOSD))] ++ "nios2_fpu_insns[nios2_fpu_cosdf2].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_cosdf2].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "sinsf2" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec:SF [(match_operand:SF 1 "register_operand" "r")] UNSPEC_FSINS))] ++ "nios2_fpu_insns[nios2_fpu_sinsf2].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_sinsf2].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "sindf2" ++ [(set (match_operand:DF 0 "register_operand" "=r") ++ (unspec:DF [(match_operand:DF 1 "register_operand" "r")] UNSPEC_FSIND))] ++ "nios2_fpu_insns[nios2_fpu_sindf2].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_sindf2].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "tansf2" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec:SF [(match_operand:SF 1 "register_operand" "r")] UNSPEC_FTANS))] ++ "nios2_fpu_insns[nios2_fpu_tansf2].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_tansf2].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "tandf2" ++ [(set (match_operand:DF 0 "register_operand" "=r") ++ (unspec:DF [(match_operand:DF 1 "register_operand" "r")] UNSPEC_FTAND))] ++ "nios2_fpu_insns[nios2_fpu_tandf2].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_tandf2].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "atansf2" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec:SF [(match_operand:SF 1 "register_operand" "r")] UNSPEC_FATANS))] ++ "nios2_fpu_insns[nios2_fpu_atansf2].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_atansf2].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "atandf2" ++ [(set (match_operand:DF 0 "register_operand" "=r") ++ (unspec:DF [(match_operand:DF 1 "register_operand" "r")] UNSPEC_FATAND))] ++ "nios2_fpu_insns[nios2_fpu_atandf2].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_atandf2].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "expsf2" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec:SF [(match_operand:SF 1 "register_operand" "r")] UNSPEC_FEXPS))] ++ "nios2_fpu_insns[nios2_fpu_expsf2].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_expsf2].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "expdf2" ++ [(set (match_operand:DF 0 "register_operand" "=r") ++ (unspec:DF [(match_operand:DF 1 "register_operand" "r")] UNSPEC_FEXPD))] ++ "nios2_fpu_insns[nios2_fpu_expdf2].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_expdf2].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "logsf2" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec:SF [(match_operand:SF 1 "register_operand" "r")] UNSPEC_FLOGS))] ++ "nios2_fpu_insns[nios2_fpu_logsf2].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_logsf2].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "logdf2" ++ [(set (match_operand:DF 0 "register_operand" "=r") ++ (unspec:DF [(match_operand:DF 1 "register_operand" "r")] UNSPEC_FLOGD))] ++ "nios2_fpu_insns[nios2_fpu_logdf2].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_logdf2].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++ ++;***************************************************************************** ++;* ++;* Logical Operantions ++;* ++;***************************************************************************** ++ ++(define_insn "andsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r, r,r") ++ (and:SI (match_operand:SI 1 "register_operand" "%r, r,r") ++ (match_operand:SI 2 "logical_operand" "rM,J,K")))] ++ "" ++ "@ ++ and\\t%0, %1, %z2 ++ and%i2\\t%0, %1, %2 ++ andh%i2\\t%0, %1, %U2" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "iorsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r, r,r") ++ (ior:SI (match_operand:SI 1 "register_operand" "%r, r,r") ++ (match_operand:SI 2 "logical_operand" "rM,J,K")))] ++ "" ++ "@ ++ or\\t%0, %1, %z2 ++ or%i2\\t%0, %1, %2 ++ orh%i2\\t%0, %1, %U2" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "*norsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (and:SI (not:SI (match_operand:SI 1 "register_operand" "%r")) ++ (not:SI (match_operand:SI 2 "reg_or_0_operand" "rM"))))] ++ "" ++ "nor\\t%0, %1, %z2" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "xorsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r, r,r") ++ (xor:SI (match_operand:SI 1 "register_operand" "%r, r,r") ++ (match_operand:SI 2 "logical_operand" "rM,J,K")))] ++ "" ++ "@ ++ xor\\t%0, %1, %z2 ++ xor%i2\\t%0, %1, %2 ++ xorh%i2\\t%0, %1, %U2" ++ [(set_attr "type" "alu")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Shifts ++;* ++;***************************************************************************** ++ ++(define_insn "ashlsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (ashift:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "shift_operand" "r,L")))] ++ "" ++ ++{ ++ if( GET_CODE ( operands[2] ) == CONST_INT && INTVAL( operands[2] ) == 1 ) ++ return "add\t%0,%1,%1"; ++ return "sll%i2\t%0,%1,%z2"; ++} ++ [(set_attr "type" "shift")]) ++ ++(define_insn "ashrsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (ashiftrt:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "shift_operand" "r,L")))] ++ "" ++ "sra%i2\\t%0, %1, %z2" ++ [(set_attr "type" "shift")]) ++ ++(define_insn "lshrsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (lshiftrt:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "shift_operand" "r,L")))] ++ "" ++ "srl%i2\\t%0, %1, %z2" ++ [(set_attr "type" "shift")]) ++ ++(define_insn "rotlsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (rotate:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "shift_operand" "r,L")))] ++ "" ++ "rol%i2\\t%0, %1, %z2" ++ [(set_attr "type" "shift")]) ++ ++(define_insn "rotrsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (rotatert:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "register_operand" "r,r")))] ++ "" ++ "ror\\t%0, %1, %2" ++ [(set_attr "type" "shift")]) ++ ++(define_insn "*shift_mul_constants" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ashift:SI (mult:SI (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "const_int_operand" "I")) ++ (match_operand:SI 3 "const_int_operand" "I")))] ++ "TARGET_HAS_MUL && SMALL_INT (INTVAL (operands[2]) << INTVAL (operands[3]))" ++{ ++ HOST_WIDE_INT mul = INTVAL (operands[2]) << INTVAL (operands[3]); ++ rtx ops[3]; ++ ++ ops[0] = operands[0]; ++ ops[1] = operands[1]; ++ ops[2] = GEN_INT (mul); ++ ++ output_asm_insn ("muli\t%0, %1, %2", ops); ++ return ""; ++} ++ [(set_attr "type" "mul")]) ++ ++ ++ ++ ++;***************************************************************************** ++;* ++;* Converting between floating point and fixed point ++;* ++;***************************************************************************** ++(define_insn "floatsisf2" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (float:SF (match_operand:SI 1 "register_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_floatsisf2].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_floatsisf2].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "floatsidf2" ++ [(set (match_operand:DF 0 "register_operand" "=r") ++ (float:DF (match_operand:SI 1 "register_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_floatsidf2].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_floatsidf2].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "floatunssisf2" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unsigned_float:SF (match_operand:SI 1 "register_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_floatunssisf2].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_floatunssisf2].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "floatunssidf2" ++ [(set (match_operand:DF 0 "register_operand" "=r") ++ (unsigned_float:DF (match_operand:SI 1 "register_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_floatunssidf2].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_floatunssidf2].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "fixsfsi2" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (fix:SI (match_operand:SF 1 "general_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_fixsfsi2].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_fixsfsi2].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "fixdfsi2" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (fix:SI (match_operand:DF 1 "general_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_fixdfsi2].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_fixdfsi2].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "fixunssfsi2" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unsigned_fix:SI (match_operand:SF 1 "general_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_fixunssfsi2].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_fixunssfsi2].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "fixunsdfsi2" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unsigned_fix:SI (match_operand:DF 1 "general_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_fixunsdfsi2].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_fixunsdfsi2].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "extendsfdf2" ++ [(set (match_operand:DF 0 "register_operand" "=r") ++ (float_extend:DF (match_operand:SF 1 "general_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_extendsfdf2].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_extendsfdf2].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++(define_insn "truncdfsf2" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (float_truncate:SF (match_operand:DF 1 "general_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_truncdfsf2].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_truncdfsf2].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++ ++ ++ ++ ++ ++ ++ ++;***************************************************************************** ++;* ++;* Prologue, Epilogue and Return ++;* ++;***************************************************************************** ++ ++(define_expand "prologue" ++ [(const_int 1)] ++ "" ++{ ++ expand_prologue (); ++ DONE; ++}) ++ ++(define_expand "epilogue" ++ [(return)] ++ "" ++{ ++ expand_epilogue (false); ++ DONE; ++}) ++ ++(define_expand "sibcall_epilogue" ++ [(return)] ++ "" ++{ ++ expand_epilogue (true); ++ DONE; ++}) ++ ++(define_insn "return" ++ [(return)] ++ "reload_completed && nios2_can_use_return_insn ()" ++ "ret\\t" ++) ++ ++(define_insn "return_from_epilogue" ++ [(use (match_operand 0 "pmode_register_operand" "")) ++ (return)] ++ "reload_completed" ++ "ret\\t" ++) ++ ++;; Block any insns from being moved before this point, since the ++;; profiling call to mcount can use various registers that aren't ++;; saved or used to pass arguments. ++ ++(define_insn "blockage" ++ [(unspec_volatile [(const_int 0)] UNSPEC_BLOCKAGE)] ++ "" ++ "" ++ [(set_attr "type" "unknown") ++ (set_attr "length" "0")]) ++ ++;; This is used in compiling the unwind routines. ++(define_expand "eh_return" ++ [(use (match_operand 0 "general_operand"))] ++ "" ++{ ++ if (GET_MODE (operands[0]) != Pmode) ++ operands[0] = convert_to_mode (Pmode, operands[0], 0); ++ emit_insn (gen_eh_set_ra (operands[0])); ++ ++ DONE; ++}) ++ ++;; Clobber the return address on the stack. We can't expand this ++;; until we know where it will be put in the stack frame. ++ ++(define_insn "eh_set_ra" ++ [(unspec [(match_operand:SI 0 "register_operand" "r")] UNSPEC_EH_RETURN) ++ (clobber (match_scratch:SI 1 "=&r"))] ++ "" ++ "#") ++ ++(define_split ++ [(unspec [(match_operand 0 "register_operand")] UNSPEC_EH_RETURN) ++ (clobber (match_scratch 1))] ++ "reload_completed" ++ [(const_int 0)] ++{ ++ nios2_set_return_address (operands[0], operands[1]); ++ DONE; ++}) ++ ++ ++;***************************************************************************** ++;* ++;* Jumps and Calls ++;* ++;***************************************************************************** ++ ++(define_insn "indirect_jump" ++ [(set (pc) (match_operand:SI 0 "register_operand" "r"))] ++ "" ++ "jmp\\t%0" ++ [(set_attr "type" "control")]) ++ ++(define_insn "jump" ++ [(set (pc) ++ (label_ref (match_operand 0 "" "")))] ++ "" ++ "br\\t%0" ++ [(set_attr "type" "control")]) ++ ++ ++(define_expand "call" ++ [(parallel [(call (match_operand 0 "" "") ++ (match_operand 1 "" "")) ++ (clobber (reg:SI 31))])] ++ "" ++ { ++ nios2_adjust_call_address (&XEXP (operands[0], 0)); ++ } ++) ++ ++(define_expand "call_value" ++ [(parallel [(set (match_operand 0 "" "") ++ (call (match_operand 1 "" "") ++ (match_operand 2 "" ""))) ++ (clobber (reg:SI 31))])] ++ "" ++ { ++ nios2_adjust_call_address (&XEXP (operands[1], 0)); ++ } ++) ++ ++(define_insn "*call" ++ [(call (mem:QI (match_operand:SI 0 "call_operand" "i,r")) ++ (match_operand 1 "" "")) ++ (clobber (reg:SI 31))] ++ "" ++ "@ ++ call\\t%0 ++ callr\\t%0" ++ [(set_attr "type" "control,control")]) ++ ++(define_insn "*call_value" ++ [(set (match_operand 0 "" "") ++ (call (mem:QI (match_operand:SI 1 "call_operand" "i,r")) ++ (match_operand 2 "" ""))) ++ (clobber (reg:SI 31))] ++ "" ++ "@ ++ call\\t%1 ++ callr\\t%1" ++ [(set_attr "type" "control,control")]) ++ ++(define_expand "sibcall" ++ [(parallel [(call (match_operand 0 "" "") ++ (match_operand 1 "" "")) ++ (return)])] ++ "" ++ { ++ nios2_adjust_call_address (&XEXP (operands[0], 0)); ++ } ++) ++ ++(define_expand "sibcall_value" ++ [(parallel [(set (match_operand 0 "" "") ++ (call (match_operand 1 "" "") ++ (match_operand 2 "" ""))) ++ (return)])] ++ "" ++ { ++ nios2_adjust_call_address (&XEXP (operands[1], 0)); ++ } ++) ++ ++(define_insn "*sibcall" ++ [(call (mem:QI (match_operand:SI 0 "call_operand" "i,j")) ++ (match_operand 1 "" "")) ++ (return)] ++ "" ++ "@ ++ jmpi\\t%0 ++ jmp\\t%0" ++) ++ ++(define_insn "*sibcall_value" ++ [(set (match_operand 0 "register_operand" "") ++ (call (mem:QI (match_operand:SI 1 "call_operand" "i,j")) ++ (match_operand 2 "" ""))) ++ (return)] ++ "" ++ "@ ++ jmpi\\t%1 ++ jmp\\t%1" ++) ++ ++ ++ ++ ++(define_expand "tablejump" ++ [(parallel [(set (pc) (match_operand 0 "register_operand" "r")) ++ (use (label_ref (match_operand 1 "" "")))])] ++ "" ++ { ++ if (flag_pic) ++ { ++ /* Hopefully, CSE will eliminate this copy. */ ++ rtx reg1 = copy_addr_to_reg (gen_rtx_LABEL_REF (Pmode, operands[1])); ++ rtx reg2 = gen_reg_rtx (SImode); ++ ++ emit_insn (gen_addsi3 (reg2, operands[0], reg1)); ++ operands[0] = reg2; ++ } ++ } ++) ++ ++(define_insn "*tablejump" ++ [(set (pc) ++ (match_operand:SI 0 "register_operand" "r")) ++ (use (label_ref (match_operand 1 "" "")))] ++ "" ++ "jmp\\t%0" ++ [(set_attr "type" "control")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Comparisons ++;* ++;***************************************************************************** ++;; Flow here is rather complex (based on MIPS): ++;; ++;; 1) The cmp{si,di,sf,df} routine is called. It deposits the ++;; arguments into the branch_cmp array, and the type into ++;; branch_type. No RTL is generated. ++;; ++;; 2) The appropriate branch define_expand is called, which then ++;; creates the appropriate RTL for the comparison and branch. ++;; Different CC modes are used, based on what type of branch is ++;; done, so that we can constrain things appropriately. There ++;; are assumptions in the rest of GCC that break if we fold the ++;; operands into the branchs for integer operations, and use cc0 ++;; for floating point, so we use the fp status register instead. ++;; If needed, an appropriate temporary is created to hold the ++;; of the integer compare. ++ ++(define_expand "cmpsi" ++ [(set (cc0) ++ (compare:CC (match_operand:SI 0 "register_operand" "") ++ (match_operand:SI 1 "arith_operand" "")))] ++ "" ++{ ++ branch_cmp[0] = operands[0]; ++ branch_cmp[1] = operands[1]; ++ branch_type = CMP_SI; ++ DONE; ++}) ++ ++(define_expand "tstsi" ++ [(set (cc0) ++ (match_operand:SI 0 "register_operand" ""))] ++ "" ++{ ++ branch_cmp[0] = operands[0]; ++ branch_cmp[1] = const0_rtx; ++ branch_type = CMP_SI; ++ DONE; ++}) ++ ++(define_expand "cmpsf" ++ [(set (cc0) ++ (compare:CC (match_operand:SF 0 "register_operand" "") ++ (match_operand:SF 1 "register_operand" "")))] ++ "(nios2_fpu_insns[nios2_fpu_nios2_sltsf].N >= 0 ++ || nios2_fpu_insns[nios2_fpu_nios2_sgtsf].N >= 0) ++ && (nios2_fpu_insns[nios2_fpu_nios2_sgesf].N >= 0 ++ || nios2_fpu_insns[nios2_fpu_nios2_slesf].N >= 0) ++ && nios2_fpu_insns[nios2_fpu_nios2_seqsf].N >= 0 ++ && nios2_fpu_insns[nios2_fpu_nios2_snesf].N >= 0" ++{ ++ branch_cmp[0] = operands[0]; ++ branch_cmp[1] = operands[1]; ++ branch_type = CMP_SF; ++ DONE; ++}) ++ ++(define_expand "cmpdf" ++ [(set (cc0) ++ (compare:CC (match_operand:DF 0 "register_operand" "") ++ (match_operand:DF 1 "register_operand" "")))] ++ "(nios2_fpu_insns[nios2_fpu_nios2_sltdf].N >= 0 ++ || nios2_fpu_insns[nios2_fpu_nios2_sgtdf].N >= 0) ++ && (nios2_fpu_insns[nios2_fpu_nios2_sgedf].N >= 0 ++ || nios2_fpu_insns[nios2_fpu_nios2_sledf].N >= 0) ++ && nios2_fpu_insns[nios2_fpu_nios2_seqdf].N >= 0 ++ && nios2_fpu_insns[nios2_fpu_nios2_snedf].N >= 0" ++{ ++ branch_cmp[0] = operands[0]; ++ branch_cmp[1] = operands[1]; ++ branch_type = CMP_DF; ++ DONE; ++}) ++ ++ ++;***************************************************************************** ++;* ++;* setting a register from a comparison ++;* ++;***************************************************************************** ++ ++(define_expand "seq" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (eq:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI && branch_type != CMP_SF && branch_type != CMP_DF) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (EQ, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*seq" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (eq:SI (match_operand:SI 1 "reg_or_0_operand" "%rM") ++ (match_operand:SI 2 "arith_operand" "rI")))] ++ "" ++ "cmpeq%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_insn "nios2_seqsf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (eq:SI (match_operand:SF 1 "register_operand" "%r") ++ (match_operand:SF 2 "register_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_nios2_seqsf].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_nios2_seqsf].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++ ++(define_insn "nios2_seqdf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (eq:SI (match_operand:DF 1 "register_operand" "%r") ++ (match_operand:DF 2 "register_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_nios2_seqdf].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_nios2_seqdf].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++ ++(define_expand "sne" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ne:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI && branch_type != CMP_SF && branch_type != CMP_DF) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (NE, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sne" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ne:SI (match_operand:SI 1 "reg_or_0_operand" "%rM") ++ (match_operand:SI 2 "arith_operand" "rI")))] ++ "" ++ "cmpne%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_insn "nios2_snesf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ne:SI (match_operand:SF 1 "register_operand" "%r") ++ (match_operand:SF 2 "register_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_nios2_snesf].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_nios2_snesf].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++ ++(define_insn "nios2_snedf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ne:SI (match_operand:DF 1 "register_operand" "%r") ++ (match_operand:DF 2 "register_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_nios2_snedf].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_nios2_snedf].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++ ++(define_expand "sgt" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (gt:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI && branch_type != CMP_SF && branch_type != CMP_DF) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (GT, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sgt" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (gt:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "reg_or_0_operand" "rM")))] ++ "" ++ "cmplt\\t%0, %z2, %z1" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_insn "nios2_sgtsf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (gt:SI (match_operand:SF 1 "register_operand" "r") ++ (match_operand:SF 2 "register_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_nios2_sgtsf].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_nios2_sgtsf].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++ ++(define_insn "nios2_sgtdf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (gt:SI (match_operand:DF 1 "register_operand" "r") ++ (match_operand:DF 2 "register_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_nios2_sgtdf].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_nios2_sgtdf].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++ ++(define_expand "sge" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ge:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI && branch_type != CMP_SF && branch_type != CMP_DF) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (GE, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sge" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ge:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "arith_operand" "rI")))] ++ "" ++ "cmpge%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_insn "nios2_sgesf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ge:SI (match_operand:SF 1 "register_operand" "r") ++ (match_operand:SF 2 "register_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_nios2_sgesf].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_nios2_sgesf].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++ ++(define_insn "nios2_sgedf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ge:SI (match_operand:DF 1 "register_operand" "r") ++ (match_operand:DF 2 "register_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_nios2_sgedf].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_nios2_sgedf].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++ ++(define_expand "sle" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (le:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI && branch_type != CMP_SF && branch_type != CMP_DF) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (LE, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sle" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (le:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "reg_or_0_operand" "rM")))] ++ "" ++ "cmpge\\t%0, %z2, %z1" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_insn "nios2_slesf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (le:SI (match_operand:SF 1 "register_operand" "r") ++ (match_operand:SF 2 "register_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_nios2_slesf].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_nios2_slesf].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++ ++(define_insn "nios2_sledf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (le:SI (match_operand:DF 1 "register_operand" "r") ++ (match_operand:DF 2 "register_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_nios2_sledf].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_nios2_sledf].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++ ++(define_expand "slt" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (lt:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI && branch_type != CMP_SF && branch_type != CMP_DF) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (LT, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*slt" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (lt:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "arith_operand" "rI")))] ++ "" ++ "cmplt%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_insn "nios2_sltsf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (lt:SI (match_operand:SF 1 "register_operand" "r") ++ (match_operand:SF 2 "register_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_nios2_sltsf].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_nios2_sltsf].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++ ++(define_insn "nios2_sltdf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (lt:SI (match_operand:DF 1 "register_operand" "r") ++ (match_operand:DF 2 "register_operand" "r")))] ++ "nios2_fpu_insns[nios2_fpu_nios2_sltdf].N >= 0" ++ { ++ return (*nios2_fpu_insns[nios2_fpu_nios2_sltdf].output) (insn); ++ } ++ [(set_attr "type" "custom")]) ++ ++ ++(define_expand "sgtu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (gtu:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (GTU, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sgtu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (gtu:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "reg_or_0_operand" "rM")))] ++ "" ++ "cmpltu\\t%0, %z2, %z1" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "sgeu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (geu:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (GEU, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sgeu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (geu:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "uns_arith_operand" "rJ")))] ++ "" ++ "cmpgeu%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++(define_expand "sleu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (leu:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (LEU, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sleu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (leu:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "reg_or_0_operand" "rM")))] ++ "" ++ "cmpgeu\\t%0, %z2, %z1" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "sltu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ltu:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (LTU, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sltu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ltu:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "uns_arith_operand" "rJ")))] ++ "" ++ "cmpltu%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++ ++ ++ ++;***************************************************************************** ++;* ++;* branches ++;* ++;***************************************************************************** ++ ++(define_insn "*cbranch" ++ [(set (pc) ++ (if_then_else ++ (match_operator:SI 0 "comparison_operator" ++ [(match_operand:SI 2 "reg_or_0_operand" "rM") ++ (match_operand:SI 3 "reg_or_0_operand" "rM")]) ++ (label_ref (match_operand 1 "" "")) ++ (pc)))] ++ "" ++ "b%0\\t%z2, %z3, %l1" ++ [(set_attr "type" "control")]) ++ ++ ++(define_insn "nios2_cbranch_sf" ++ [(set (pc) ++ (if_then_else ++ (match_operator:SI 0 "comparison_operator" ++ [(match_operand:SF 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")]) ++ (label_ref (match_operand 1 "" "")) ++ (pc)))] ++ "" ++ { ++ return nios2_output_fpu_insn_cmps (insn, GET_CODE (operands[0])); ++ } ++ [(set_attr "type" "custom")]) ++ ++ ++(define_insn "nios2_cbranch_df" ++ [(set (pc) ++ (if_then_else ++ (match_operator:SI 0 "comparison_operator" ++ [(match_operand:DF 2 "register_operand" "r") ++ (match_operand:DF 3 "register_operand" "r")]) ++ (label_ref (match_operand 1 "" "")) ++ (pc)))] ++ "" ++ { ++ return nios2_output_fpu_insn_cmpd (insn, GET_CODE (operands[0])); ++ } ++ [(set_attr "type" "custom")]) ++ ++ ++(define_expand "beq" ++ [(set (pc) ++ (if_then_else (eq:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (EQ, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++ ++(define_expand "bne" ++ [(set (pc) ++ (if_then_else (ne:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (NE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++ ++(define_expand "bgt" ++ [(set (pc) ++ (if_then_else (gt:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (GT, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "bge" ++ [(set (pc) ++ (if_then_else (ge:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (GE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "ble" ++ [(set (pc) ++ (if_then_else (le:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (LE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "blt" ++ [(set (pc) ++ (if_then_else (lt:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (LT, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++ ++(define_expand "bgtu" ++ [(set (pc) ++ (if_then_else (gtu:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (GTU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "bgeu" ++ [(set (pc) ++ (if_then_else (geu:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (GEU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "bleu" ++ [(set (pc) ++ (if_then_else (leu:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (LEU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "bltu" ++ [(set (pc) ++ (if_then_else (ltu:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (LTU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++ ++;***************************************************************************** ++;* ++;* String and Block Operations ++;* ++;***************************************************************************** ++ ++; ??? This is all really a hack to get Dhrystone to work as fast as possible ++; things to be fixed: ++; * let the compiler core handle all of this, for that to work the extra ++; aliasing needs to be addressed. ++; * we use three temporary registers for loading and storing to ensure no ++; ld use stalls, this is excessive, because after the first ld/st only ++; two are needed. Only two would be needed all the way through if ++; we could schedule with other code. Consider: ++; 1 ld $1, 0($src) ++; 2 ld $2, 4($src) ++; 3 ld $3, 8($src) ++; 4 st $1, 0($dest) ++; 5 ld $1, 12($src) ++; 6 st $2, 4($src) ++; 7 etc. ++; The first store has to wait until 4. If it does not there will be one ++; cycle of stalling. However, if any other instruction could be placed ++; between 1 and 4, $3 would not be needed. ++; * In small we probably don't want to ever do this ourself because there ++; is no ld use stall. ++ ++(define_expand "movstrsi" ++ [(parallel [(set (match_operand:BLK 0 "general_operand" "") ++ (match_operand:BLK 1 "general_operand" "")) ++ (use (match_operand:SI 2 "const_int_operand" "")) ++ (use (match_operand:SI 3 "const_int_operand" "")) ++ (clobber (match_scratch:SI 4 "=&r")) ++ (clobber (match_scratch:SI 5 "=&r")) ++ (clobber (match_scratch:SI 6 "=&r"))])] ++ "TARGET_INLINE_MEMCPY" ++{ ++ rtx ld_addr_reg, st_addr_reg; ++ ++ /* If the predicate for op2 fails in expr.c:emit_block_move_via_movstr ++ it trys to copy to a register, but does not re-try the predicate. ++ ??? Intead of fixing expr.c, I fix it here. */ ++ if (!const_int_operand (operands[2], SImode)) ++ FAIL; ++ ++ /* ??? there are some magic numbers which need to be sorted out here. ++ the basis for them is not increasing code size hugely or going ++ out of range of offset addressing */ ++ if (INTVAL (operands[3]) < 4) ++ FAIL; ++ if (!optimize ++ || (optimize_size && INTVAL (operands[2]) > 12) ++ || (optimize < 3 && INTVAL (operands[2]) > 100) ++ || INTVAL (operands[2]) > 200) ++ FAIL; ++ ++ st_addr_reg ++ = replace_equiv_address (operands[0], ++ copy_to_mode_reg (Pmode, XEXP (operands[0], 0))); ++ ld_addr_reg ++ = replace_equiv_address (operands[1], ++ copy_to_mode_reg (Pmode, XEXP (operands[1], 0))); ++ emit_insn (gen_movstrsi_internal (st_addr_reg, ld_addr_reg, ++ operands[2], operands[3])); ++ ++ DONE; ++}) ++ ++ ++(define_insn "movstrsi_internal" ++ [(set (match_operand:BLK 0 "memory_operand" "=o") ++ (match_operand:BLK 1 "memory_operand" "o")) ++ (use (match_operand:SI 2 "const_int_operand" "i")) ++ (use (match_operand:SI 3 "const_int_operand" "i")) ++ (clobber (match_scratch:SI 4 "=&r")) ++ (clobber (match_scratch:SI 5 "=&r")) ++ (clobber (match_scratch:SI 6 "=&r"))] ++ "TARGET_INLINE_MEMCPY" ++{ ++ int ld_offset = INTVAL (operands[2]); ++ int ld_len = INTVAL (operands[2]); ++ int ld_reg = 0; ++ rtx ld_addr_reg = XEXP (operands[1], 0); ++ int st_offset = INTVAL (operands[2]); ++ int st_len = INTVAL (operands[2]); ++ int st_reg = 0; ++ rtx st_addr_reg = XEXP (operands[0], 0); ++ int delay_count = 0; ++ ++ /* ops[0] is the address used by the insn ++ ops[1] is the register being loaded or stored */ ++ rtx ops[2]; ++ ++ gcc_assert (INTVAL (operands[3]) >= 4); ++ ++ while (ld_offset >= 4) ++ { ++ /* if the load use delay has been met, I can start ++ storing */ ++ if (delay_count >= 3) ++ { ++ ops[0] = gen_rtx_MEM (SImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("stw\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 4; ++ } ++ ++ ops[0] = gen_rtx_MEM (SImode, ++ plus_constant (ld_addr_reg, ld_len - ld_offset)); ++ ops[1] = operands[ld_reg + 4]; ++ output_asm_insn ("ldw\t%1, %0", ops); ++ ++ ld_reg = (ld_reg + 1) % 3; ++ ld_offset -= 4; ++ delay_count++; ++ } ++ ++ if (ld_offset >= 2) ++ { ++ /* if the load use delay has been met, I can start ++ storing */ ++ if (delay_count >= 3) ++ { ++ ops[0] = gen_rtx_MEM (SImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("stw\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 4; ++ } ++ ++ ops[0] = gen_rtx_MEM (HImode, ++ plus_constant (ld_addr_reg, ld_len - ld_offset)); ++ ops[1] = operands[ld_reg + 4]; ++ output_asm_insn ("ldh\t%1, %0", ops); ++ ++ ld_reg = (ld_reg + 1) % 3; ++ ld_offset -= 2; ++ delay_count++; ++ } ++ ++ if (ld_offset >= 1) ++ { ++ /* if the load use delay has been met, I can start ++ storing */ ++ if (delay_count >= 3) ++ { ++ ops[0] = gen_rtx_MEM (SImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("stw\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 4; ++ } ++ ++ ops[0] = gen_rtx_MEM (QImode, ++ plus_constant (ld_addr_reg, ld_len - ld_offset)); ++ ops[1] = operands[ld_reg + 4]; ++ output_asm_insn ("ldb\t%1, %0", ops); ++ ++ ld_reg = (ld_reg + 1) % 3; ++ ld_offset -= 1; ++ delay_count++; ++ } ++ ++ while (st_offset >= 4) ++ { ++ ops[0] = gen_rtx_MEM (SImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("stw\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 4; ++ } ++ ++ while (st_offset >= 2) ++ { ++ ops[0] = gen_rtx_MEM (HImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("sth\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 2; ++ } ++ ++ while (st_offset >= 1) ++ { ++ ops[0] = gen_rtx_MEM (QImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("stb\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 1; ++ } ++ ++ return ""; ++} ++; ??? lengths are not being used yet, but I will probably forget ++; to update this once I am using lengths, so set it to something ++; definetely big enough to cover it. 400 allows for 200 bytes ++; of motion. ++ [(set_attr "length" "400")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Custom instructions ++;* ++;***************************************************************************** ++ ++(define_constants [ ++ (CUSTOM_N 100) ++ (CUSTOM_NI 101) ++ (CUSTOM_NF 102) ++ (CUSTOM_NP 103) ++ (CUSTOM_NII 104) ++ (CUSTOM_NIF 105) ++ (CUSTOM_NIP 106) ++ (CUSTOM_NFI 107) ++ (CUSTOM_NFF 108) ++ (CUSTOM_NFP 109) ++ (CUSTOM_NPI 110) ++ (CUSTOM_NPF 111) ++ (CUSTOM_NPP 112) ++ (CUSTOM_IN 113) ++ (CUSTOM_INI 114) ++ (CUSTOM_INF 115) ++ (CUSTOM_INP 116) ++ (CUSTOM_INII 117) ++ (CUSTOM_INIF 118) ++ (CUSTOM_INIP 119) ++ (CUSTOM_INFI 120) ++ (CUSTOM_INFF 121) ++ (CUSTOM_INFP 122) ++ (CUSTOM_INPI 123) ++ (CUSTOM_INPF 124) ++ (CUSTOM_INPP 125) ++ (CUSTOM_FN 126) ++ (CUSTOM_FNI 127) ++ (CUSTOM_FNF 128) ++ (CUSTOM_FNP 129) ++ (CUSTOM_FNII 130) ++ (CUSTOM_FNIF 131) ++ (CUSTOM_FNIP 132) ++ (CUSTOM_FNFI 133) ++ (CUSTOM_FNFF 134) ++ (CUSTOM_FNFP 135) ++ (CUSTOM_FNPI 136) ++ (CUSTOM_FNPF 137) ++ (CUSTOM_FNPP 138) ++ (CUSTOM_PN 139) ++ (CUSTOM_PNI 140) ++ (CUSTOM_PNF 141) ++ (CUSTOM_PNP 142) ++ (CUSTOM_PNII 143) ++ (CUSTOM_PNIF 144) ++ (CUSTOM_PNIP 145) ++ (CUSTOM_PNFI 146) ++ (CUSTOM_PNFF 147) ++ (CUSTOM_PNFP 148) ++ (CUSTOM_PNPI 149) ++ (CUSTOM_PNPF 150) ++ (CUSTOM_PNPP 151) ++]) ++ ++ ++(define_insn "custom_n" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")] CUSTOM_N)] ++ "" ++ "custom\\t%0, zero, zero, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_ni" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r")] CUSTOM_NI)] ++ "" ++ "custom\\t%0, zero, %1, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nf" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SF 1 "register_operand" "r")] CUSTOM_NF)] ++ "" ++ "custom\\t%0, zero, %1, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_np" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r")] CUSTOM_NP)] ++ "" ++ "custom\\t%0, zero, %1, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nii" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NII)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nif" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_NIF)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nip" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NIP)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nfi" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SF 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NFI)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nff" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SF 1 "register_operand" "r") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_NFF)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nfp" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SF 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NFP)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_npi" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NPI)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_npf" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_NPF)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_npp" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NPP)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++ ++ ++(define_insn "custom_in" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")] ++ CUSTOM_IN))] ++ "" ++ "custom\\t%1, %0, zero, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_ini" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] ++ CUSTOM_INI))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r")] ++ CUSTOM_INF))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] ++ CUSTOM_INP))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inii" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] ++ CUSTOM_INII))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inif" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] ++ CUSTOM_INIF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inip" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] ++ CUSTOM_INIP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_infi" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] ++ CUSTOM_INFI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inff" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] ++ CUSTOM_INFF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_infp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] ++ CUSTOM_INFP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inpi" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] ++ CUSTOM_INPI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inpf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] ++ CUSTOM_INPF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inpp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] ++ CUSTOM_INPP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++ ++ ++ ++ ++(define_insn "custom_fn" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")] ++ CUSTOM_FN))] ++ "" ++ "custom\\t%1, %0, zero, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fni" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] ++ CUSTOM_FNI))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnf" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r")] ++ CUSTOM_FNF))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnp" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] ++ CUSTOM_FNP))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnii" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] ++ CUSTOM_FNII))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnif" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] ++ CUSTOM_FNIF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnip" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] ++ CUSTOM_FNIP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnfi" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] ++ CUSTOM_FNFI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnff" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] ++ CUSTOM_FNFF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnfp" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] ++ CUSTOM_FNFP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnpi" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] ++ CUSTOM_FNPI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnpf" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] ++ CUSTOM_FNPF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnpp" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] ++ CUSTOM_FNPP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++ ++ ++(define_insn "custom_pn" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")] ++ CUSTOM_PN))] ++ "" ++ "custom\\t%1, %0, zero, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pni" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] ++ CUSTOM_PNI))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r")] ++ CUSTOM_PNF))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] ++ CUSTOM_PNP))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnii" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] ++ CUSTOM_PNII))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnif" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] ++ CUSTOM_PNIF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnip" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] ++ CUSTOM_PNIP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnfi" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] ++ CUSTOM_PNFI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnff" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] ++ CUSTOM_PNFF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnfp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] ++ CUSTOM_PNFP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnpi" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] ++ CUSTOM_PNPI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnpf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] ++ CUSTOM_PNPF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnpp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] ++ CUSTOM_PNPP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++ ++ ++ ++ ++ ++;***************************************************************************** ++;* ++;* Misc ++;* ++;***************************************************************************** ++ ++(define_insn "nop" ++ [(const_int 0)] ++ "" ++ "nop\\t" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "sync" ++ [(unspec_volatile [(const_int 0)] UNSPEC_SYNC)] ++ "" ++ "sync\\t" ++ [(set_attr "type" "control")]) ++ ++ ++(define_insn "rdctl" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "rdwrctl_operand" "O")] ++ UNSPEC_RDCTL))] ++ "" ++ "rdctl\\t%0, ctl%1" ++ [(set_attr "type" "control")]) ++ ++(define_insn "wrctl" ++ [(unspec_volatile:SI [(match_operand:SI 0 "rdwrctl_operand" "O") ++ (match_operand:SI 1 "reg_or_0_operand" "rM")] ++ UNSPEC_WRCTL)] ++ "" ++ "wrctl\\tctl%0, %z1" ++ [(set_attr "type" "control")]) ++ ++;Used to signal a stack overflow ++(define_insn "trap" ++ [(unspec_volatile [(const_int 0)] UNSPEC_TRAP)] ++ "" ++ "break\\t3" ++ [(set_attr "type" "control")]) ++ ++(define_insn "stack_overflow_detect_and_trap" ++ [(unspec_volatile [(const_int 0)] UNSPEC_STACK_OVERFLOW_DETECT_AND_TRAP)] ++ "" ++ "bgeu\\tsp, et, 1f\;break\\t3\;1:" ++ [(set_attr "type" "control")]) ++ ++;Load the GOT register. ++(define_insn "load_got_register" ++ [(set (match_operand:SI 0 "register_operand" "=&r") ++ (unspec:SI [(const_int 0)] UNSPEC_LOAD_GOT_REGISTER)) ++ (set (match_operand:SI 1 "register_operand" "=r") ++ (unspec:SI [(const_int 0)] UNSPEC_LOAD_GOT_REGISTER))] ++ "" ++ "nextpc\\t%0 ++\\t1: ++\\tmovhi\\t%1, %%hiadj(_GLOBAL_OFFSET_TABLE_ - 1b) ++\\taddi\\t%1, %1, %%lo(_GLOBAL_OFFSET_TABLE_ - 1b)" ++ [(set_attr "length" "12")]) ++ ++;; When generating pic, we need to load the symbol offset into a register. ++;; So that the optimizer does not confuse this with a normal symbol load ++;; we use an unspec. The offset will be loaded from a constant pool entry, ++;; since that is the only type of relocation we can use. ++ ++;; The rather odd constraints on the following are to force reload to leave ++;; the insn alone, and to force the minipool generation pass to then move ++;; the GOT symbol to memory. ++ ++;; FIXME:these uses look unnecessary. ++(define_insn "pic_load_addr" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec:SI [(match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "" "mX")] UNSPEC_PIC_SYM)) ++ (use (match_dup 1))] ++ "flag_pic" ++ "ldw\\t%0, %%got(%2)(%1)") ++ ++(define_insn "pic_load_call_addr" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec:SI [(match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "" "mX")] UNSPEC_PIC_CALL_SYM)) ++ (use (match_dup 1))] ++ "flag_pic" ++ "ldw\\t%0, %%call(%2)(%1)") ++ ++;; TLS support ++ ++(define_insn "add_tls_gd" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec:SI [(match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "" "mX")] UNSPEC_ADD_TLS_GD))] ++ "" ++ "addi\t%0, %1, %%tls_gd(%2)") ++ ++(define_insn "load_tls_ie" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec:SI [(match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "" "mX")] UNSPEC_LOAD_TLS_IE))] ++ "" ++ "ldw\t%0, %%tls_ie(%2)(%1)") ++ ++(define_insn "add_tls_ldm" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec:SI [(match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "" "mX")] UNSPEC_ADD_TLS_LDM))] ++ "" ++ "addi\t%0, %1, %%tls_ldm(%2)") ++ ++(define_insn "add_tls_ldo" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec:SI [(match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "" "mX")] UNSPEC_ADD_TLS_LDO))] ++ "" ++ "addi\t%0, %1, %%tls_ldo(%2)") ++ ++(define_insn "add_tls_le" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec:SI [(match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "" "mX")] UNSPEC_ADD_TLS_LE))] ++ "" ++ "addi\t%0, %1, %%tls_le(%2)") ++ ++ ++;***************************************************************************** ++;* ++;* Peepholes ++;* ++;***************************************************************************** ++ ++ ++;; Local Variables: ++;; mode: lisp ++;; End: +Index: gcc-4.1.2/gcc/config/nios2/nios2.opt +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gcc-4.1.2/gcc/config/nios2/nios2.opt 2010-06-30 08:50:26.000000000 +0200 +@@ -0,0 +1,519 @@ ++; NOT ASSIGNED TO FSF. COPYRIGHT ALTERA. ++; Options for the Nios II port of the compiler. ++ ++; 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 2, 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 COPYING. If not, write to the Free ++; Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA ++; 02110-1301, USA. ++ ++mhw-div ++Target Report Mask(HAS_DIV) ++Enable DIV, DIVU ++ ++mhw-mul ++Target Report Mask(HAS_MUL) ++Enable MUL instructions ++ ++mhw-mulx ++Target Report Mask(HAS_MULX) ++Enable MULX instructions, assume fast shifter ++ ++mfast-sw-div ++Target Report Mask(FAST_SW_DIV) ++Use table based fast divide (default at -O3) ++ ++minline-memory ++Target Report Mask(INLINE_MEMCPY) ++Inline small memcpy (default when optimizing) ++ ++mbypass-cache ++Target Report Mask(BYPASS_CACHE) ++All ld/st instructions use io variants ++ ++mstack-check ++Target Report Mask(STACK_CHECK) ++Enable stack limit checking ++ ++mreverse-bitfields ++Target Report Mask(REVERSE_BITFIELDS) ++Reverse the order of bitfields in a struct ++ ++meb ++Target Report RejectNegative Mask(BIG_ENDIAN) ++Use big-endian byte order ++ ++mel ++Target Report RejectNegative InverseMask(BIG_ENDIAN) ++Use little-endian byte order ++ ++mcustom-fpu-cfg= ++Target RejectNegative Joined Var(nios2_custom_fpu_cfg_string) VarExists ++Floating point custom instruction configuration name ++ ++mno-custom-ftruncds ++Target Report RejectNegative Var(nios2_custom_ftruncds, -1) VarExists ++Do not use the ftruncds custom instruction ++ ++mcustom-ftruncds= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_ftruncds) VarExists ++Integer id (N) of ftruncds custom instruction ++ ++mno-custom-fextsd ++Target Report RejectNegative Var(nios2_custom_fextsd, -1) VarExists ++Do not use the fextsd custom instruction ++ ++mcustom-fextsd= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fextsd) VarExists ++Integer id (N) of fextsd custom instruction ++ ++mno-custom-fixdu ++Target Report RejectNegative Var(nios2_custom_fixdu, -1) VarExists ++Do not use the fixdu custom instruction ++ ++mcustom-fixdu= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fixdu) VarExists ++Integer id (N) of fixdu custom instruction ++ ++mno-custom-fixdi ++Target Report RejectNegative Var(nios2_custom_fixdi, -1) VarExists ++Do not use the fixdi custom instruction ++ ++mcustom-fixdi= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fixdi) VarExists ++Integer id (N) of fixdi custom instruction ++ ++mno-custom-fixsu ++Target Report RejectNegative Var(nios2_custom_fixsu, -1) VarExists ++Do not use the fixsu custom instruction ++ ++mcustom-fixsu= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fixsu) VarExists ++Integer id (N) of fixsu custom instruction ++ ++mno-custom-fixsi ++Target Report RejectNegative Var(nios2_custom_fixsi, -1) VarExists ++Do not use the fixsi custom instruction ++ ++mcustom-fixsi= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fixsi) VarExists ++Integer id (N) of fixsi custom instruction ++ ++mno-custom-floatud ++Target Report RejectNegative Var(nios2_custom_floatud, -1) VarExists ++Do not use the floatud custom instruction ++ ++mcustom-floatud= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_floatud) VarExists ++Integer id (N) of floatud custom instruction ++ ++mno-custom-floatid ++Target Report RejectNegative Var(nios2_custom_floatid, -1) VarExists ++Do not use the floatid custom instruction ++ ++mcustom-floatid= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_floatid) VarExists ++Integer id (N) of floatid custom instruction ++ ++mno-custom-floatus ++Target Report RejectNegative Var(nios2_custom_floatus, -1) VarExists ++Do not use the floatus custom instruction ++ ++mcustom-floatus= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_floatus) VarExists ++Integer id (N) of floatus custom instruction ++ ++mno-custom-floatis ++Target Report RejectNegative Var(nios2_custom_floatis, -1) VarExists ++Do not use the floatis custom instruction ++ ++mcustom-floatis= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_floatis) VarExists ++Integer id (N) of floatis custom instruction ++ ++mno-custom-fcmpned ++Target Report RejectNegative Var(nios2_custom_fcmpned, -1) VarExists ++Do not use the fcmpned custom instruction ++ ++mcustom-fcmpned= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmpned) VarExists ++Integer id (N) of fcmpned custom instruction ++ ++mno-custom-fcmpeqd ++Target Report RejectNegative Var(nios2_custom_fcmpeqd, -1) VarExists ++Do not use the fcmpeqd custom instruction ++ ++mcustom-fcmpeqd= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmpeqd) VarExists ++Integer id (N) of fcmpeqd custom instruction ++ ++mno-custom-fcmpged ++Target Report RejectNegative Var(nios2_custom_fcmpged, -1) VarExists ++Do not use the fcmpged custom instruction ++ ++mcustom-fcmpged= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmpged) VarExists ++Integer id (N) of fcmpged custom instruction ++ ++mno-custom-fcmpgtd ++Target Report RejectNegative Var(nios2_custom_fcmpgtd, -1) VarExists ++Do not use the fcmpgtd custom instruction ++ ++mcustom-fcmpgtd= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmpgtd) VarExists ++Integer id (N) of fcmpgtd custom instruction ++ ++mno-custom-fcmpled ++Target Report RejectNegative Var(nios2_custom_fcmpled, -1) VarExists ++Do not use the fcmpled custom instruction ++ ++mcustom-fcmpled= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmpled) VarExists ++Integer id (N) of fcmpled custom instruction ++ ++mno-custom-fcmpltd ++Target Report RejectNegative Var(nios2_custom_fcmpltd, -1) VarExists ++Do not use the fcmpltd custom instruction ++ ++mcustom-fcmpltd= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmpltd) VarExists ++Integer id (N) of fcmpltd custom instruction ++ ++mno-custom-flogd ++Target Report RejectNegative Var(nios2_custom_flogd, -1) VarExists ++Do not use the flogd custom instruction ++ ++mcustom-flogd= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_flogd) VarExists ++Integer id (N) of flogd custom instruction ++ ++mno-custom-fexpd ++Target Report RejectNegative Var(nios2_custom_fexpd, -1) VarExists ++Do not use the fexpd custom instruction ++ ++mcustom-fexpd= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fexpd) VarExists ++Integer id (N) of fexpd custom instruction ++ ++mno-custom-fatand ++Target Report RejectNegative Var(nios2_custom_fatand, -1) VarExists ++Do not use the fatand custom instruction ++ ++mcustom-fatand= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fatand) VarExists ++Integer id (N) of fatand custom instruction ++ ++mno-custom-ftand ++Target Report RejectNegative Var(nios2_custom_ftand, -1) VarExists ++Do not use the ftand custom instruction ++ ++mcustom-ftand= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_ftand) VarExists ++Integer id (N) of ftand custom instruction ++ ++mno-custom-fsind ++Target Report RejectNegative Var(nios2_custom_fsind, -1) VarExists ++Do not use the fsind custom instruction ++ ++mcustom-fsind= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fsind) VarExists ++Integer id (N) of fsind custom instruction ++ ++mno-custom-fcosd ++Target Report RejectNegative Var(nios2_custom_fcosd, -1) VarExists ++Do not use the fcosd custom instruction ++ ++mcustom-fcosd= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fcosd) VarExists ++Integer id (N) of fcosd custom instruction ++ ++mno-custom-fsqrtd ++Target Report RejectNegative Var(nios2_custom_fsqrtd, -1) VarExists ++Do not use the fsqrtd custom instruction ++ ++mcustom-fsqrtd= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fsqrtd) VarExists ++Integer id (N) of fsqrtd custom instruction ++ ++mno-custom-fabsd ++Target Report RejectNegative Var(nios2_custom_fabsd, -1) VarExists ++Do not use the fabsd custom instruction ++ ++mcustom-fabsd= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fabsd) VarExists ++Integer id (N) of fabsd custom instruction ++ ++mno-custom-fnegd ++Target Report RejectNegative Var(nios2_custom_fnegd, -1) VarExists ++Do not use the fnegd custom instruction ++ ++mcustom-fnegd= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fnegd) VarExists ++Integer id (N) of fnegd custom instruction ++ ++mno-custom-fmaxd ++Target Report RejectNegative Var(nios2_custom_fmaxd, -1) VarExists ++Do not use the fmaxd custom instruction ++ ++mcustom-fmaxd= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fmaxd) VarExists ++Integer id (N) of fmaxd custom instruction ++ ++mno-custom-fmind ++Target Report RejectNegative Var(nios2_custom_fmind, -1) VarExists ++Do not use the fmind custom instruction ++ ++mcustom-fmind= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fmind) VarExists ++Integer id (N) of fmind custom instruction ++ ++mno-custom-fdivd ++Target Report RejectNegative Var(nios2_custom_fdivd, -1) VarExists ++Do not use the fdivd custom instruction ++ ++mcustom-fdivd= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fdivd) VarExists ++Integer id (N) of fdivd custom instruction ++ ++mno-custom-fmuld ++Target Report RejectNegative Var(nios2_custom_fmuld, -1) VarExists ++Do not use the fmuld custom instruction ++ ++mcustom-fmuld= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fmuld) VarExists ++Integer id (N) of fmuld custom instruction ++ ++mno-custom-fsubd ++Target Report RejectNegative Var(nios2_custom_fsubd, -1) VarExists ++Do not use the fsubd custom instruction ++ ++mcustom-fsubd= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fsubd) VarExists ++Integer id (N) of fsubd custom instruction ++ ++mno-custom-faddd ++Target Report RejectNegative Var(nios2_custom_faddd, -1) VarExists ++Do not use the faddd custom instruction ++ ++mcustom-faddd= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_faddd) VarExists ++Integer id (N) of faddd custom instruction ++ ++mno-custom-fcmpnes ++Target Report RejectNegative Var(nios2_custom_fcmpnes, -1) VarExists ++Do not use the fcmpnes custom instruction ++ ++mcustom-fcmpnes= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmpnes) VarExists ++Integer id (N) of fcmpnes custom instruction ++ ++mno-custom-fcmpeqs ++Target Report RejectNegative Var(nios2_custom_fcmpeqs, -1) VarExists ++Do not use the fcmpeqs custom instruction ++ ++mcustom-fcmpeqs= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmpeqs) VarExists ++Integer id (N) of fcmpeqs custom instruction ++ ++mno-custom-fcmpges ++Target Report RejectNegative Var(nios2_custom_fcmpges, -1) VarExists ++Do not use the fcmpges custom instruction ++ ++mcustom-fcmpges= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmpges) VarExists ++Integer id (N) of fcmpges custom instruction ++ ++mno-custom-fcmpgts ++Target Report RejectNegative Var(nios2_custom_fcmpgts, -1) VarExists ++Do not use the fcmpgts custom instruction ++ ++mcustom-fcmpgts= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmpgts) VarExists ++Integer id (N) of fcmpgts custom instruction ++ ++mno-custom-fcmples ++Target Report RejectNegative Var(nios2_custom_fcmples, -1) VarExists ++Do not use the fcmples custom instruction ++ ++mcustom-fcmples= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmples) VarExists ++Integer id (N) of fcmples custom instruction ++ ++mno-custom-fcmplts ++Target Report RejectNegative Var(nios2_custom_fcmplts, -1) VarExists ++Do not use the fcmplts custom instruction ++ ++mcustom-fcmplts= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmplts) VarExists ++Integer id (N) of fcmplts custom instruction ++ ++mno-custom-flogs ++Target Report RejectNegative Var(nios2_custom_flogs, -1) VarExists ++Do not use the flogs custom instruction ++ ++mcustom-flogs= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_flogs) VarExists ++Integer id (N) of flogs custom instruction ++ ++mno-custom-fexps ++Target Report RejectNegative Var(nios2_custom_fexps, -1) VarExists ++Do not use the fexps custom instruction ++ ++mcustom-fexps= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fexps) VarExists ++Integer id (N) of fexps custom instruction ++ ++mno-custom-fatans ++Target Report RejectNegative Var(nios2_custom_fatans, -1) VarExists ++Do not use the fatans custom instruction ++ ++mcustom-fatans= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fatans) VarExists ++Integer id (N) of fatans custom instruction ++ ++mno-custom-ftans ++Target Report RejectNegative Var(nios2_custom_ftans, -1) VarExists ++Do not use the ftans custom instruction ++ ++mcustom-ftans= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_ftans) VarExists ++Integer id (N) of ftans custom instruction ++ ++mno-custom-fsins ++Target Report RejectNegative Var(nios2_custom_fsins, -1) VarExists ++Do not use the fsins custom instruction ++ ++mcustom-fsins= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fsins) VarExists ++Integer id (N) of fsins custom instruction ++ ++mno-custom-fcoss ++Target Report RejectNegative Var(nios2_custom_fcoss, -1) VarExists ++Do not use the fcoss custom instruction ++ ++mcustom-fcoss= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fcoss) VarExists ++Integer id (N) of fcoss custom instruction ++ ++mno-custom-fsqrts ++Target Report RejectNegative Var(nios2_custom_fsqrts, -1) VarExists ++Do not use the fsqrts custom instruction ++ ++mcustom-fsqrts= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fsqrts) VarExists ++Integer id (N) of fsqrts custom instruction ++ ++mno-custom-fabss ++Target Report RejectNegative Var(nios2_custom_fabss, -1) VarExists ++Do not use the fabss custom instr ++ ++mcustom-fabss= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fabss) VarExists ++Integer id (N) of fabss custom instruction ++ ++mno-custom-fnegs ++Target Report RejectNegative Var(nios2_custom_fnegs, -1) VarExists ++Do not use the fnegs custom instruction ++ ++mcustom-fnegs= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fnegs) VarExists ++Integer id (N) of fnegs custom instruction ++ ++mno-custom-fmaxs ++Target Report RejectNegative Var(nios2_custom_fmaxs, -1) VarExists ++Do not use the fmaxs custom instruction ++ ++mcustom-fmaxs= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fmaxs) VarExists ++Integer id (N) of fmaxs custom instruction ++ ++mno-custom-fmins ++Target Report RejectNegative Var(nios2_custom_fmins, -1) VarExists ++Do not use the fmins custom instruction ++ ++mcustom-fmins= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fmins) VarExists ++Integer id (N) of fmins custom instruction ++ ++mno-custom-fdivs ++Target Report RejectNegative Var(nios2_custom_fdivs, -1) VarExists ++Do not use the fdivs custom instruction ++ ++mcustom-fdivs= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fdivs) VarExists ++Integer id (N) of fdivs custom instruction ++ ++mno-custom-fmuls ++Target Report RejectNegative Var(nios2_custom_fmuls, -1) VarExists ++Do not use the fmuls custom instruction ++ ++mcustom-fmuls= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fmuls) VarExists ++Integer id (N) of fmuls custom instruction ++ ++mno-custom-fsubs ++Target Report RejectNegative Var(nios2_custom_fsubs, -1) VarExists ++Do not use the fsubs custom instruction ++ ++mcustom-fsubs= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fsubs) VarExists ++Integer id (N) of fsubs custom instruction ++ ++mno-custom-fadds ++Target Report RejectNegative Var(nios2_custom_fadds, -1) VarExists ++Do not use the fadds custom instruction ++ ++mcustom-fadds= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fadds) VarExists ++Integer id (N) of fadds custom instruction ++ ++mno-custom-frdy ++Target Report RejectNegative Var(nios2_custom_frdy, -1) VarExists ++Do not use the frdy custom instruction ++ ++mcustom-frdy= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_frdy) VarExists ++Integer id (N) of frdy custom instruction ++ ++mno-custom-frdxhi ++Target Report RejectNegative Var(nios2_custom_frdxhi, -1) VarExists ++Do not use the frdxhi custom instruction ++ ++mcustom-frdxhi= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_frdxhi) VarExists ++Integer id (N) of frdxhi custom instruction ++ ++mno-custom-frdxlo ++Target Report RejectNegative Var(nios2_custom_frdxlo, -1) VarExists ++Do not use the frdxlo custom instruction ++ ++mcustom-frdxlo= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_frdxlo) VarExists ++Integer id (N) of frdxlo custom instruction ++ ++mno-custom-fwry ++Target Report RejectNegative Var(nios2_custom_fwry, -1) VarExists ++Do not use the fwry custom instruction ++ ++mcustom-fwry= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fwry) VarExists ++Integer id (N) of fwry custom instruction ++ ++mno-custom-fwrx ++Target Report RejectNegative Var(nios2_custom_fwrx, -1) VarExists ++Do not use the fwrx custom instruction ++ ++mcustom-fwrx= ++Target Report RejectNegative Joined UInteger Var(nios2_custom_fwrx) VarExists ++Integer id (N) of fwrx custom instruction +Index: gcc-4.1.2/gcc/config/nios2/t-linux +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gcc-4.1.2/gcc/config/nios2/t-linux 2010-06-30 08:50:26.000000000 +0200 +@@ -0,0 +1,9 @@ ++# Soft-float functions go in glibc only, to facilitate the possible ++# future addition of exception and rounding mode support integrated ++# with <fenv.h>. ++ ++FPBIT= ++DPBIT= ++LIB2FUNCS_EXCLUDE = _floatdidf _floatdisf _fixunsdfsi _fixunssfsi \ ++ _fixunsdfdi _fixdfdi _fixunssfdi _fixsfdi _floatundidf _floatundisf ++LIB2FUNCS_EXTRA += $(srcdir)/config/nios2/linux-atomic.c +Index: gcc-4.1.2/gcc/config/nios2/t-nios2 +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ gcc-4.1.2/gcc/config/nios2/t-nios2 2010-06-30 08:50:26.000000000 +0200 +@@ -0,0 +1,176 @@ ++## ++## Compiler flags to use when compiling libgcc2.c. ++## ++## LIB2FUNCS_EXTRA ++## A list of source file names to be compiled or assembled and inserted into ++## libgcc.a. ++ ++LIB2FUNCS_EXTRA=$(srcdir)/config/nios2/lib2-divmod.c \ ++ $(srcdir)/config/nios2/lib2-divmod-hi.c \ ++ $(srcdir)/config/nios2/lib2-divtable.c \ ++ $(srcdir)/config/nios2/lib2-mul.c ++ ++## ++## Floating Point Emulation ++## To have GCC include software floating point libraries in libgcc.a define FPBIT ++## and DPBIT along with a few rules as follows: ++## ++## # 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 ++ ++TARGET_LIBGCC2_CFLAGS = -O2 -fpic ++ ++# FLOAT_ONLY - no doubles ++# SMALL_MACHINE - QI/HI is faster than SI ++# Actually SMALL_MACHINE uses chars and shorts instead of ints ++# since ints (16-bit ones as they are today) are at least as fast ++# as chars and shorts, don't define SMALL_MACHINE ++# CMPtype - type returned by FP compare, i.e. INT (hard coded in fp-bit - see code ) ++ ++$(FPBIT): $(srcdir)/config/fp-bit.c Makefile ++ echo '#define FLOAT' > ${FPBIT} ++ echo '#ifndef __nios2_big_endian__' >> ${FPBIT} ++ echo '#define FLOAT_BIT_ORDER_MISMATCH' >> ${FPBIT} ++ echo '#endif' >> ${FPBIT} ++ cat $(srcdir)/config/fp-bit.c >> ${FPBIT} ++ ++$(DPBIT): $(srcdir)/config/fp-bit.c Makefile ++ echo '' > ${DPBIT} ++ echo '#ifndef __nios2_big_endian__' >> ${DPBIT} ++ echo '#define FLOAT_BIT_ORDER_MISMATCH' >> ${DPBIT} ++ echo '#endif' >> ${DPBIT} ++ cat $(srcdir)/config/fp-bit.c >> ${DPBIT} ++ ++EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o crti.o crtn.o crtbeginS.o \ ++ crtbeginT.o crtendS.o ++ ++# Assemble startup files. ++$(T)crti.o: $(srcdir)/config/nios2/crti.asm $(GCC_PASSES) ++ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \ ++ -c -o $(T)crti.o -x assembler-with-cpp $(srcdir)/config/nios2/crti.asm ++ ++$(T)crtn.o: $(srcdir)/config/nios2/crtn.asm $(GCC_PASSES) ++ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \ ++ -c -o $(T)crtn.o -x assembler-with-cpp $(srcdir)/config/nios2/crtn.asm ++ ++ ++## You may need to provide additional #defines at the beginning of ++## fp-bit.c and dp-bit.c to control target endianness and other options ++## ++## CRTSTUFF_T_CFLAGS ++## Special flags used when compiling crtstuff.c. See Initialization. ++## ++## CRTSTUFF_T_CFLAGS_S ++## Special flags used when compiling crtstuff.c for shared linking. Used ++## if you use crtbeginS.o and crtendS.o in EXTRA-PARTS. See Initialization. ++## ++## MULTILIB_OPTIONS ++## For some targets, invoking GCC in different ways produces objects that ++## can not be linked together. For example, for some targets GCC produces ++## both big and little endian code. For these targets, you must arrange ++## for multiple versions of libgcc.a to be compiled, one for each set of ++## incompatible options. When GCC invokes the linker, it arranges to link ++## in the right version of libgcc.a, based on the command line options ++## used. ++## The MULTILIB_OPTIONS macro lists the set of options for which special ++## versions of libgcc.a must be built. Write options that are mutually ++## incompatible side by side, separated by a slash. Write options that may ++## be used together separated by a space. The build procedure will build ++## all combinations of compatible options. ++## ++## For example, if you set MULTILIB_OPTIONS to m68000/m68020 msoft-float, ++## Makefile will build special versions of libgcc.a using the following ++## sets of options: -m68000, -m68020, -msoft-float, -m68000 -msoft-float, ++## and -m68020 -msoft-float. ++ ++ ++## The BUILD_BE_MULTILIB and BUILD_PG_MULTILIB variables allow the ++## makefile user to enable/disable the generation of the precompiled ++## big endian and profiling libraries. By default, the big endian ++## libraries are not created on a windows build and the profiling ++## libraries are not created on a Solaris build. All other library ++## combinations are created by default. ++ ++# Uncomment to temporarily avoid building big endian and profiling libraries during a Windows build. ++#ifeq ($(DEV_HOST_OS), win32) ++#BUILD_BE_MULTILIB ?= 0 ++#BUILD_PG_MULTILIB ?= 0 ++#endif ++ ++#By default, avoid building the profiling libraries during a Solaris build. ++ifeq ($(DEV_HOST_OS), solaris) ++BUILD_PG_MULTILIB ?= 0 ++endif ++ ++BUILD_BE_MULTILIB ?= 0 ++BUILD_PG_MULTILIB ?= 1 ++BUILD_MULTILIB ?= 0 ++ ++ifeq ($(BUILD_MULTILIB), 1) ++ ++MULTILIB_OPTIONS = mno-hw-mul mhw-mulx mstack-check mcustom-fpu-cfg=60-1 mcustom-fpu-cfg=60-2 ++ ++#Add the profiling flag to the multilib variable if required ++ifeq ($(BUILD_PG_MULTILIB), 1) ++MULTILIB_OPTIONS += pg ++endif ++ ++#Add the big endian flag to the multilib variable if required ++ifeq ($(BUILD_BE_MULTILIB), 1) ++MULTILIB_OPTIONS += EB/EL ++endif ++ ++endif ++ ++## MULTILIB_DIRNAMES ++## If MULTILIB_OPTIONS is used, this variable specifies the directory names ++## that should be used to hold the various libraries. Write one element in ++## MULTILIB_DIRNAMES for each element in MULTILIB_OPTIONS. If ++## MULTILIB_DIRNAMES is not used, the default value will be ++## MULTILIB_OPTIONS, with all slashes treated as spaces. ++## For example, if MULTILIB_OPTIONS is set to m68000/m68020 msoft-float, ++## then the default value of MULTILIB_DIRNAMES is m68000 m68020 ++## msoft-float. You may specify a different value if you desire a ++## different set of directory names. ++ ++# MULTILIB_DIRNAMES = ++ ++## MULTILIB_MATCHES ++## Sometimes the same option may be written in two different ways. If an ++## option is listed in MULTILIB_OPTIONS, GCC needs to know about any ++## synonyms. In that case, set MULTILIB_MATCHES to a list of items of the ++## form option=option to describe all relevant synonyms. For example, ++## m68000=mc68000 m68020=mc68020. ++ ++ifeq ($(BUILD_MULTILIB), 1) ++ifeq ($(BUILD_BE_MULTILIB), 1) ++MULTILIB_MATCHES = EL=mel EB=meb ++endif ++endif ++ ++## ++## MULTILIB_EXCEPTIONS ++## Sometimes when there are multiple sets of MULTILIB_OPTIONS being ++## specified, there are combinations that should not be built. In that ++## case, set MULTILIB_EXCEPTIONS to be all of the switch exceptions in ++## shell case syntax that should not be built. ++## For example, in the PowerPC embedded ABI support, it is not desirable to ++## build libraries compiled with the -mcall-aix option and either of the ++## -fleading-underscore or -mlittle options at the same time. Therefore ++## MULTILIB_EXCEPTIONS is set to ++## ++## *mcall-aix/*fleading-underscore* *mlittle/*mcall-aix* ++## ++ ++ifeq ($(BUILD_MULTILIB), 1) ++MULTILIB_EXCEPTIONS = *mno-hw-mul/*mhw-mulx* *mcustom-fpu-cfg=60-1/*mcustom-fpu-cfg=60-2* ++endif ++ ++## ++## MULTILIB_EXTRA_OPTS Sometimes it is desirable that when building ++## multiple versions of libgcc.a certain options should always be passed on ++## to the compiler. In that case, set MULTILIB_EXTRA_OPTS to be the list ++## of options to be used for all builds. ++## diff --git a/recipes/gcc/gcc-4.1.2/nios2-lib-flags.patch b/recipes/gcc/gcc-4.1.2/nios2-lib-flags.patch new file mode 100644 index 0000000000..e125ba0f6c --- /dev/null +++ b/recipes/gcc/gcc-4.1.2/nios2-lib-flags.patch @@ -0,0 +1,10 @@ +Index: gcc-4.1.2/config/mt-ospace +=================================================================== +--- gcc-4.1.2.orig/config/mt-ospace 2010-06-02 10:23:01.000000000 +0200 ++++ gcc-4.1.2/config/mt-ospace 2010-06-02 10:23:28.000000000 +0200 +@@ -1,3 +1,2 @@ +-# Build libraries optimizing for space, not speed. +- CFLAGS_FOR_TARGET = -g -Os +- CXXFLAGS_FOR_TARGET = -g -Os ++ CFLAGS_FOR_TARGET = -g -O2 ++ CXXFLAGS_FOR_TARGET = -g -O2 |