summaryrefslogtreecommitdiffstats
path: root/recipes/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'recipes/gcc')
-rw-r--r--recipes/gcc/gcc-4.1.2.inc6
-rw-r--r--recipes/gcc/gcc-4.1.2/gcc-config-nios2.patch41
-rw-r--r--recipes/gcc/gcc-4.1.2/gcc-nios2.patch11017
-rw-r--r--recipes/gcc/gcc-4.1.2/nios2-lib-flags.patch10
4 files changed, 11074 insertions, 0 deletions
diff --git a/recipes/gcc/gcc-4.1.2.inc b/recipes/gcc/gcc-4.1.2.inc
index e89a8de241..3b6cf30913 100644
--- a/recipes/gcc/gcc-4.1.2.inc
+++ b/recipes/gcc/gcc-4.1.2.inc
@@ -33,6 +33,12 @@ SRC_URI = "${GNU_MIRROR}/gcc/gcc-${PV}/gcc-${PV}.tar.bz2;name=archive \
SRC_URI_append_sh3 = " file://sh3-installfix-fixheaders.patch "
+SRC_URI_append_nios2 = " \
+ file://gcc-nios2.patch \
+ file://gcc-config-nios2.patch \
+ file://nios2-lib-flags.patch \
+ "
+
SRC_URI_avr32 = "http://www.angstrom-distribution.org/unstable/sources/gcc-4.1.2-atmel.1.1.0.tar.gz;name=atmel \
# file://100-uclibc-conf.patch \
# file://200-uclibc-locale.patch \
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)&regs->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