summaryrefslogtreecommitdiff
path: root/toolchain
diff options
context:
space:
mode:
Diffstat (limited to 'toolchain')
-rw-r--r--toolchain/gcc/3.4.4/900-nios2.patch10210
-rw-r--r--toolchain/gcc/3.4.5/900-nios2.patch10210
-rw-r--r--toolchain/gcc/Config.in2
3 files changed, 20420 insertions, 2 deletions
diff --git a/toolchain/gcc/3.4.4/900-nios2.patch b/toolchain/gcc/3.4.4/900-nios2.patch
new file mode 100644
index 000000000..39ac283ea
--- /dev/null
+++ b/toolchain/gcc/3.4.4/900-nios2.patch
@@ -0,0 +1,10210 @@
+--- gcc-3.4.3/gcc/Makefile.in
++++ gcc-3.4.3-nios2/gcc/Makefile.in
+@@ -3085,7 +3085,7 @@ install-mkheaders: stmp-int-hdrs $(STMP_
+ $(INSTALL_DATA) $(srcdir)/README-fixinc \
+ $(DESTDIR)$(itoolsdatadir)/include/README ; \
+ $(INSTALL_SCRIPT) fixinc.sh $(DESTDIR)$(itoolsdir)/fixinc.sh ; \
+- $(INSTALL_PROGRAM) fixinc/fixincl $(DESTDIR)$(itoolsdir)/fixincl ; \
++ $(INSTALL_PROGRAM) fixinc/fixincl$(build_exeext) $(DESTDIR)$(itoolsdir)/fixincl$(build_exeext) ; \
+ $(INSTALL_DATA) $(srcdir)/gsyslimits.h \
+ $(DESTDIR)$(itoolsdatadir)/gsyslimits.h ; \
+ else :; fi
+--- gcc-3.4.3/gcc/combine.c
++++ gcc-3.4.3-nios2/gcc/combine.c
+@@ -4380,6 +4380,14 @@ combine_simplify_rtx (rtx x, enum machin
+ mode);
+ }
+
++#ifndef __nios2__
++/* This screws up Nios II in this test case:
++
++if (x & 1)
++ return 2;
++else
++ return 3;
++*/
+ else if (STORE_FLAG_VALUE == 1
+ && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
+ && op1 == const0_rtx
+@@ -4391,6 +4399,7 @@ combine_simplify_rtx (rtx x, enum machin
+ gen_lowpart_for_combine (mode, op0),
+ const1_rtx);
+ }
++#endif
+
+ else if (STORE_FLAG_VALUE == 1
+ && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
+--- gcc-3.4.3/gcc/config/nios2/crti.asm
++++ gcc-3.4.3-nios2/gcc/config/nios2/crti.asm
+@@ -0,0 +1,88 @@
++/*
++ 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)
++ mov fp, sp
++
++
++ .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)
++ mov fp, sp
++
++
+--- gcc-3.4.3/gcc/config/nios2/crtn.asm
++++ gcc-3.4.3-nios2/gcc/config/nios2/crtn.asm
+@@ -0,0 +1,70 @@
++/*
++ 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
++
+--- gcc-3.4.3/gcc/config/nios2/lib2-divmod-hi.c
++++ gcc-3.4.3-nios2/gcc/config/nios2/lib2-divmod-hi.c
+@@ -0,0 +1,123 @@
++
++/* 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"
++
++
++#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"
++
++extern HItype __modhi3 (HItype, HItype);
++extern HItype __divhi3 (HItype, HItype);
++extern HItype __umodhi3 (HItype, HItype);
++extern HItype __udivhi3 (HItype, HItype);
++
++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;
++}
++
++
++HItype
++__udivhi3 (HItype a, HItype b)
++{
++ return udivmodhi4 (a, b, 0);
++}
++
++
++HItype
++__umodhi3 (HItype a, HItype b)
++{
++ return udivmodhi4 (a, b, 1);
++}
++
+--- gcc-3.4.3/gcc/config/nios2/lib2-divmod.c
++++ gcc-3.4.3-nios2/gcc/config/nios2/lib2-divmod.c
+@@ -0,0 +1,126 @@
++
++/* 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"
++
++
++#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"
++
++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);
++}
++
+--- gcc-3.4.3/gcc/config/nios2/lib2-divtable.c
++++ gcc-3.4.3-nios2/gcc/config/nios2/lib2-divtable.c
+@@ -0,0 +1,46 @@
++
++/* 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"
++
++
++#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,
++};
++
+--- gcc-3.4.3/gcc/config/nios2/lib2-mul.c
++++ gcc-3.4.3-nios2/gcc/config/nios2/lib2-mul.c
+@@ -0,0 +1,103 @@
++/* 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"
++
++
++#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"
++
++#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
+--- gcc-3.4.3/gcc/config/nios2/nios2-dp-bit.c
++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2-dp-bit.c
+@@ -0,0 +1,1652 @@
++
++/* This is a software floating point library which can be used
++ for targets without hardware floating point.
++ Copyright (C) 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004
++ Free Software Foundation, Inc.
++
++This file is free software; you can redistribute it and/or modify it
++under the terms of the GNU General Public License as published by 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 other files,
++ some of which are compiled with GCC, to produce an executable,
++ this library does not by itself cause the resulting executable
++ to be covered by the GNU General Public License.
++ This exception does not however invalidate any other reasons why
++ the executable file might be covered by the GNU General Public License. */
++
++/* This implements IEEE 754 format arithmetic, but does not provide a
++ mechanism for setting the rounding mode, or for generating or handling
++ exceptions.
++
++ The original code by Steve Chamberlain, hacked by Mark Eichin and Jim
++ Wilson, all of Cygnus Support. */
++
++/* The intended way to use this file is to make two copies, add `#define FLOAT'
++ to one copy, then compile both copies and add them to libgcc.a. */
++
++#include "tconfig.h"
++#include "coretypes.h"
++#include "tm.h"
++#include "config/fp-bit.h"
++
++/* The following macros can be defined to change the behavior of this file:
++ FLOAT: Implement a `float', aka SFmode, fp library. If this is not
++ defined, then this file implements a `double', aka DFmode, fp library.
++ FLOAT_ONLY: Used with FLOAT, to implement a `float' only library, i.e.
++ don't include float->double conversion which requires the double library.
++ This is useful only for machines which can't support doubles, e.g. some
++ 8-bit processors.
++ CMPtype: Specify the type that floating point compares should return.
++ This defaults to SItype, aka int.
++ US_SOFTWARE_GOFAST: This makes all entry points use the same names as the
++ US Software goFast library.
++ _DEBUG_BITFLOAT: This makes debugging the code a little easier, by adding
++ two integers to the FLO_union_type.
++ NO_DENORMALS: Disable handling of denormals.
++ NO_NANS: Disable nan and infinity handling
++ SMALL_MACHINE: Useful when operations on QIs and HIs are faster
++ than on an SI */
++
++/* We don't currently support extended floats (long doubles) on machines
++ without hardware to deal with them.
++
++ These stubs are just to keep the linker from complaining about unresolved
++ references which can be pulled in from libio & libstdc++, even if the
++ user isn't using long doubles. However, they may generate an unresolved
++ external to abort if abort is not used by the function, and the stubs
++ are referenced from within libc, since libgcc goes before and after the
++ system library. */
++
++#ifdef DECLARE_LIBRARY_RENAMES
++ DECLARE_LIBRARY_RENAMES
++#endif
++
++#ifdef EXTENDED_FLOAT_STUBS
++extern void abort (void);
++void __extendsfxf2 (void) { abort(); }
++void __extenddfxf2 (void) { abort(); }
++void __truncxfdf2 (void) { abort(); }
++void __truncxfsf2 (void) { abort(); }
++void __fixxfsi (void) { abort(); }
++void __floatsixf (void) { abort(); }
++void __addxf3 (void) { abort(); }
++void __subxf3 (void) { abort(); }
++void __mulxf3 (void) { abort(); }
++void __divxf3 (void) { abort(); }
++void __negxf2 (void) { abort(); }
++void __eqxf2 (void) { abort(); }
++void __nexf2 (void) { abort(); }
++void __gtxf2 (void) { abort(); }
++void __gexf2 (void) { abort(); }
++void __lexf2 (void) { abort(); }
++void __ltxf2 (void) { abort(); }
++
++void __extendsftf2 (void) { abort(); }
++void __extenddftf2 (void) { abort(); }
++void __trunctfdf2 (void) { abort(); }
++void __trunctfsf2 (void) { abort(); }
++void __fixtfsi (void) { abort(); }
++void __floatsitf (void) { abort(); }
++void __addtf3 (void) { abort(); }
++void __subtf3 (void) { abort(); }
++void __multf3 (void) { abort(); }
++void __divtf3 (void) { abort(); }
++void __negtf2 (void) { abort(); }
++void __eqtf2 (void) { abort(); }
++void __netf2 (void) { abort(); }
++void __gttf2 (void) { abort(); }
++void __getf2 (void) { abort(); }
++void __letf2 (void) { abort(); }
++void __lttf2 (void) { abort(); }
++#else /* !EXTENDED_FLOAT_STUBS, rest of file */
++
++/* IEEE "special" number predicates */
++
++#ifdef NO_NANS
++
++#define nan() 0
++#define isnan(x) 0
++#define isinf(x) 0
++#else
++
++#if defined L_thenan_sf
++const fp_number_type __thenan_sf = { CLASS_SNAN, 0, 0, {(fractype) 0} };
++#elif defined L_thenan_df
++const fp_number_type __thenan_df = { CLASS_SNAN, 0, 0, {(fractype) 0} };
++#elif defined L_thenan_tf
++const fp_number_type __thenan_tf = { CLASS_SNAN, 0, 0, {(fractype) 0} };
++#elif defined TFLOAT
++extern const fp_number_type __thenan_tf;
++#elif defined FLOAT
++extern const fp_number_type __thenan_sf;
++#else
++extern const fp_number_type __thenan_df;
++#endif
++
++INLINE
++static fp_number_type *
++nan (void)
++{
++ /* Discard the const qualifier... */
++#ifdef TFLOAT
++ return (fp_number_type *) (& __thenan_tf);
++#elif defined FLOAT
++ return (fp_number_type *) (& __thenan_sf);
++#else
++ return (fp_number_type *) (& __thenan_df);
++#endif
++}
++
++INLINE
++static int
++isnan ( fp_number_type * x)
++{
++ return x->class == CLASS_SNAN || x->class == CLASS_QNAN;
++}
++
++INLINE
++static int
++isinf ( fp_number_type * x)
++{
++ return x->class == CLASS_INFINITY;
++}
++
++#endif /* NO_NANS */
++
++INLINE
++static int
++iszero ( fp_number_type * x)
++{
++ return x->class == CLASS_ZERO;
++}
++
++INLINE
++static void
++flip_sign ( fp_number_type * x)
++{
++ x->sign = !x->sign;
++}
++
++extern FLO_type pack_d ( fp_number_type * );
++
++#if defined(L_pack_df) || defined(L_pack_sf) || defined(L_pack_tf)
++FLO_type
++pack_d ( fp_number_type * src)
++{
++ FLO_union_type dst;
++ fractype fraction = src->fraction.ll; /* wasn't unsigned before? */
++ int sign = src->sign;
++ int exp = 0;
++
++ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && (isnan (src) || isinf (src)))
++ {
++ /* We can't represent these values accurately. By using the
++ largest possible magnitude, we guarantee that the conversion
++ of infinity is at least as big as any finite number. */
++ exp = EXPMAX;
++ fraction = ((fractype) 1 << FRACBITS) - 1;
++ }
++ else if (isnan (src))
++ {
++ exp = EXPMAX;
++ if (src->class == CLASS_QNAN || 1)
++ {
++#ifdef QUIET_NAN_NEGATED
++ fraction |= QUIET_NAN - 1;
++#else
++ fraction |= QUIET_NAN;
++#endif
++ }
++ }
++ else if (isinf (src))
++ {
++ exp = EXPMAX;
++ fraction = 0;
++ }
++ else if (iszero (src))
++ {
++ exp = 0;
++ fraction = 0;
++ }
++ else if (fraction == 0)
++ {
++ exp = 0;
++ }
++ else
++ {
++ if (src->normal_exp < NORMAL_EXPMIN)
++ {
++#ifdef NO_DENORMALS
++ /* Go straight to a zero representation if denormals are not
++ supported. The denormal handling would be harmless but
++ isn't unnecessary. */
++ exp = 0;
++ fraction = 0;
++#else /* NO_DENORMALS */
++ /* This number's exponent is too low to fit into the bits
++ available in the number, so we'll store 0 in the exponent and
++ shift the fraction to the right to make up for it. */
++
++ int shift = NORMAL_EXPMIN - src->normal_exp;
++
++ exp = 0;
++
++ if (shift > FRAC_NBITS - NGARDS)
++ {
++ /* No point shifting, since it's more that 64 out. */
++ fraction = 0;
++ }
++ else
++ {
++ int lowbit = (fraction & (((fractype)1 << shift) - 1)) ? 1 : 0;
++ fraction = (fraction >> shift) | lowbit;
++ }
++ if ((fraction & GARDMASK) == GARDMSB)
++ {
++ if ((fraction & (1 << NGARDS)))
++ fraction += GARDROUND + 1;
++ }
++ else
++ {
++ /* Add to the guards to round up. */
++ fraction += GARDROUND;
++ }
++ /* Perhaps the rounding means we now need to change the
++ exponent, because the fraction is no longer denormal. */
++ if (fraction >= IMPLICIT_1)
++ {
++ exp += 1;
++ }
++ fraction >>= NGARDS;
++#endif /* NO_DENORMALS */
++ }
++ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS)
++ && src->normal_exp > EXPBIAS)
++ {
++ exp = EXPMAX;
++ fraction = 0;
++ }
++ else
++ {
++ exp = src->normal_exp + EXPBIAS;
++ if (!ROUND_TOWARDS_ZERO)
++ {
++ /* IF the gard bits are the all zero, but the first, then we're
++ half way between two numbers, choose the one which makes the
++ lsb of the answer 0. */
++ if ((fraction & GARDMASK) == GARDMSB)
++ {
++ if (fraction & (1 << NGARDS))
++ fraction += GARDROUND + 1;
++ }
++ else
++ {
++ /* Add a one to the guards to round up */
++ fraction += GARDROUND;
++ }
++ if (fraction >= IMPLICIT_2)
++ {
++ fraction >>= 1;
++ exp += 1;
++ }
++ }
++ fraction >>= NGARDS;
++
++ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp > EXPMAX)
++ {
++ /* Saturate on overflow. */
++ exp = EXPMAX;
++ fraction = ((fractype) 1 << FRACBITS) - 1;
++ }
++ }
++ }
++
++ /* We previously used bitfields to store the number, but this doesn't
++ handle little/big endian systems conveniently, so use shifts and
++ masks */
++#ifdef FLOAT_BIT_ORDER_MISMATCH
++ dst.bits.fraction = fraction;
++ dst.bits.exp = exp;
++ dst.bits.sign = sign;
++#else
++# if defined TFLOAT && defined HALFFRACBITS
++ {
++ halffractype high, low, unity;
++ int lowsign, lowexp;
++
++ unity = (halffractype) 1 << HALFFRACBITS;
++
++ /* Set HIGH to the high double's significand, masking out the implicit 1.
++ Set LOW to the low double's full significand. */
++ high = (fraction >> (FRACBITS - HALFFRACBITS)) & (unity - 1);
++ low = fraction & (unity * 2 - 1);
++
++ /* Get the initial sign and exponent of the low double. */
++ lowexp = exp - HALFFRACBITS - 1;
++ lowsign = sign;
++
++ /* HIGH should be rounded like a normal double, making |LOW| <=
++ 0.5 ULP of HIGH. Assume round-to-nearest. */
++ if (exp < EXPMAX)
++ if (low > unity || (low == unity && (high & 1) == 1))
++ {
++ /* Round HIGH up and adjust LOW to match. */
++ high++;
++ if (high == unity)
++ {
++ /* May make it infinite, but that's OK. */
++ high = 0;
++ exp++;
++ }
++ low = unity * 2 - low;
++ lowsign ^= 1;
++ }
++
++ high |= (halffractype) exp << HALFFRACBITS;
++ high |= (halffractype) sign << (HALFFRACBITS + EXPBITS);
++
++ if (exp == EXPMAX || exp == 0 || low == 0)
++ low = 0;
++ else
++ {
++ while (lowexp > 0 && low < unity)
++ {
++ low <<= 1;
++ lowexp--;
++ }
++
++ if (lowexp <= 0)
++ {
++ halffractype roundmsb, round;
++ int shift;
++
++ shift = 1 - lowexp;
++ roundmsb = (1 << (shift - 1));
++ round = low & ((roundmsb << 1) - 1);
++
++ low >>= shift;
++ lowexp = 0;
++
++ if (round > roundmsb || (round == roundmsb && (low & 1) == 1))
++ {
++ low++;
++ if (low == unity)
++ /* LOW rounds up to the smallest normal number. */
++ lowexp++;
++ }
++ }
++
++ low &= unity - 1;
++ low |= (halffractype) lowexp << HALFFRACBITS;
++ low |= (halffractype) lowsign << (HALFFRACBITS + EXPBITS);
++ }
++ dst.value_raw = ((fractype) high << HALFSHIFT) | low;
++ }
++# else
++ dst.value_raw = fraction & ((((fractype)1) << FRACBITS) - (fractype)1);
++ dst.value_raw |= ((fractype) (exp & ((1 << EXPBITS) - 1))) << FRACBITS;
++ dst.value_raw |= ((fractype) (sign & 1)) << (FRACBITS | EXPBITS);
++# endif
++#endif
++
++#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT)
++#ifdef TFLOAT
++ {
++ qrtrfractype tmp1 = dst.words[0];
++ qrtrfractype tmp2 = dst.words[1];
++ dst.words[0] = dst.words[3];
++ dst.words[1] = dst.words[2];
++ dst.words[2] = tmp2;
++ dst.words[3] = tmp1;
++ }
++#else
++ {
++ halffractype tmp = dst.words[0];
++ dst.words[0] = dst.words[1];
++ dst.words[1] = tmp;
++ }
++#endif
++#endif
++
++ return dst.value;
++}
++#endif
++
++#if defined(L_unpack_df) || defined(L_unpack_sf) || defined(L_unpack_tf)
++void
++unpack_d (FLO_union_type * src, fp_number_type * dst)
++{
++ /* We previously used bitfields to store the number, but this doesn't
++ handle little/big endian systems conveniently, so use shifts and
++ masks */
++ fractype fraction;
++ int exp;
++ int sign;
++
++#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT)
++ FLO_union_type swapped;
++
++#ifdef TFLOAT
++ swapped.words[0] = src->words[3];
++ swapped.words[1] = src->words[2];
++ swapped.words[2] = src->words[1];
++ swapped.words[3] = src->words[0];
++#else
++ swapped.words[0] = src->words[1];
++ swapped.words[1] = src->words[0];
++#endif
++ src = &swapped;
++#endif
++
++#ifdef FLOAT_BIT_ORDER_MISMATCH
++ fraction = src->bits.fraction;
++ exp = src->bits.exp;
++ sign = src->bits.sign;
++#else
++# if defined TFLOAT && defined HALFFRACBITS
++ {
++ halffractype high, low;
++
++ high = src->value_raw >> HALFSHIFT;
++ low = src->value_raw & (((fractype)1 << HALFSHIFT) - 1);
++
++ fraction = high & ((((fractype)1) << HALFFRACBITS) - 1);
++ fraction <<= FRACBITS - HALFFRACBITS;
++ exp = ((int)(high >> HALFFRACBITS)) & ((1 << EXPBITS) - 1);
++ sign = ((int)(high >> (((HALFFRACBITS + EXPBITS))))) & 1;
++
++ if (exp != EXPMAX && exp != 0 && low != 0)
++ {
++ int lowexp = ((int)(low >> HALFFRACBITS)) & ((1 << EXPBITS) - 1);
++ int lowsign = ((int)(low >> (((HALFFRACBITS + EXPBITS))))) & 1;
++ int shift;
++ fractype xlow;
++
++ xlow = low & ((((fractype)1) << HALFFRACBITS) - 1);
++ if (lowexp)
++ xlow |= (((halffractype)1) << HALFFRACBITS);
++ else
++ lowexp = 1;
++ shift = (FRACBITS - HALFFRACBITS) - (exp - lowexp);
++ if (shift > 0)
++ xlow <<= shift;
++ else if (shift < 0)
++ xlow >>= -shift;
++ if (sign == lowsign)
++ fraction += xlow;
++ else if (fraction >= xlow)
++ fraction -= xlow;
++ else
++ {
++ /* The high part is a power of two but the full number is lower.
++ This code will leave the implicit 1 in FRACTION, but we'd
++ have added that below anyway. */
++ fraction = (((fractype) 1 << FRACBITS) - xlow) << 1;
++ exp--;
++ }
++ }
++ }
++# else
++ fraction = src->value_raw & ((((fractype)1) << FRACBITS) - 1);
++ exp = ((int)(src->value_raw >> FRACBITS)) & ((1 << EXPBITS) - 1);
++ sign = ((int)(src->value_raw >> (FRACBITS + EXPBITS))) & 1;
++# endif
++#endif
++
++ dst->sign = sign;
++ if (exp == 0)
++ {
++ /* Hmm. Looks like 0 */
++ if (fraction == 0
++#ifdef NO_DENORMALS
++ || 1
++#endif
++ )
++ {
++ /* tastes like zero */
++ dst->class = CLASS_ZERO;
++ }
++ else
++ {
++ /* Zero exponent with nonzero fraction - it's denormalized,
++ so there isn't a leading implicit one - we'll shift it so
++ it gets one. */
++ dst->normal_exp = exp - EXPBIAS + 1;
++ fraction <<= NGARDS;
++
++ dst->class = CLASS_NUMBER;
++#if 1
++ while (fraction < IMPLICIT_1)
++ {
++ fraction <<= 1;
++ dst->normal_exp--;
++ }
++#endif
++ dst->fraction.ll = fraction;
++ }
++ }
++ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp == EXPMAX)
++ {
++ /* Huge exponent*/
++ if (fraction == 0)
++ {
++ /* Attached to a zero fraction - means infinity */
++ dst->class = CLASS_INFINITY;
++ }
++ else
++ {
++ /* Nonzero fraction, means nan */
++#ifdef QUIET_NAN_NEGATED
++ if ((fraction & QUIET_NAN) == 0)
++#else
++ if (fraction & QUIET_NAN)
++#endif
++ {
++ dst->class = CLASS_QNAN;
++ }
++ else
++ {
++ dst->class = CLASS_SNAN;
++ }
++ /* Keep the fraction part as the nan number */
++ dst->fraction.ll = fraction;
++ }
++ }
++ else
++ {
++ /* Nothing strange about this number */
++ dst->normal_exp = exp - EXPBIAS;
++ dst->class = CLASS_NUMBER;
++ dst->fraction.ll = (fraction << NGARDS) | IMPLICIT_1;
++ }
++}
++#endif /* L_unpack_df || L_unpack_sf */
++
++#if defined(L_addsub_sf) || defined(L_addsub_df) || defined(L_addsub_tf)
++static fp_number_type *
++_fpadd_parts (fp_number_type * a,
++ fp_number_type * b,
++ fp_number_type * tmp)
++{
++ intfrac tfraction;
++
++ /* Put commonly used fields in local variables. */
++ int a_normal_exp;
++ int b_normal_exp;
++ fractype a_fraction;
++ fractype b_fraction;
++
++ if (isnan (a))
++ {
++ return a;
++ }
++ if (isnan (b))
++ {
++ return b;
++ }
++ if (isinf (a))
++ {
++ /* Adding infinities with opposite signs yields a NaN. */
++ if (isinf (b) && a->sign != b->sign)
++ return nan ();
++ return a;
++ }
++ if (isinf (b))
++ {
++ return b;
++ }
++ if (iszero (b))
++ {
++ if (iszero (a))
++ {
++ *tmp = *a;
++ tmp->sign = a->sign & b->sign;
++ return tmp;
++ }
++ return a;
++ }
++ if (iszero (a))
++ {
++ return b;
++ }
++
++ /* Got two numbers. shift the smaller and increment the exponent till
++ they're the same */
++ {
++ int diff;
++
++ a_normal_exp = a->normal_exp;
++ b_normal_exp = b->normal_exp;
++ a_fraction = a->fraction.ll;
++ b_fraction = b->fraction.ll;
++
++ diff = a_normal_exp - b_normal_exp;
++
++ if (diff < 0)
++ diff = -diff;
++ if (diff < FRAC_NBITS)
++ {
++ /* ??? This does shifts one bit at a time. Optimize. */
++ while (a_normal_exp > b_normal_exp)
++ {
++ b_normal_exp++;
++ LSHIFT (b_fraction);
++ }
++ while (b_normal_exp > a_normal_exp)
++ {
++ a_normal_exp++;
++ LSHIFT (a_fraction);
++ }
++ }
++ else
++ {
++ /* Somethings's up.. choose the biggest */
++ if (a_normal_exp > b_normal_exp)
++ {
++ b_normal_exp = a_normal_exp;
++ b_fraction = 0;
++ }
++ else
++ {
++ a_normal_exp = b_normal_exp;
++ a_fraction = 0;
++ }
++ }
++ }
++
++ if (a->sign != b->sign)
++ {
++ if (a->sign)
++ {
++ tfraction = -a_fraction + b_fraction;
++ }
++ else
++ {
++ tfraction = a_fraction - b_fraction;
++ }
++ if (tfraction >= 0)
++ {
++ tmp->sign = 0;
++ tmp->normal_exp = a_normal_exp;
++ tmp->fraction.ll = tfraction;
++ }
++ else
++ {
++ tmp->sign = 1;
++ tmp->normal_exp = a_normal_exp;
++ tmp->fraction.ll = -tfraction;
++ }
++ /* and renormalize it */
++
++ while (tmp->fraction.ll < IMPLICIT_1 && tmp->fraction.ll)
++ {
++ tmp->fraction.ll <<= 1;
++ tmp->normal_exp--;
++ }
++ }
++ else
++ {
++ tmp->sign = a->sign;
++ tmp->normal_exp = a_normal_exp;
++ tmp->fraction.ll = a_fraction + b_fraction;
++ }
++ tmp->class = CLASS_NUMBER;
++ /* Now the fraction is added, we have to shift down to renormalize the
++ number */
++
++ if (tmp->fraction.ll >= IMPLICIT_2)
++ {
++ LSHIFT (tmp->fraction.ll);
++ tmp->normal_exp++;
++ }
++ return tmp;
++
++}
++
++FLO_type
++add (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ fp_number_type tmp;
++ fp_number_type *res;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ res = _fpadd_parts (&a, &b, &tmp);
++
++ return pack_d (res);
++}
++
++FLO_type
++sub (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ fp_number_type tmp;
++ fp_number_type *res;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ b.sign ^= 1;
++
++ res = _fpadd_parts (&a, &b, &tmp);
++
++ return pack_d (res);
++}
++#endif /* L_addsub_sf || L_addsub_df */
++
++#if defined(L_mul_sf) || defined(L_mul_df) || defined(L_mul_tf)
++static inline __attribute__ ((__always_inline__)) fp_number_type *
++_fpmul_parts ( fp_number_type * a,
++ fp_number_type * b,
++ fp_number_type * tmp)
++{
++ fractype low = 0;
++ fractype high = 0;
++
++ if (isnan (a))
++ {
++ a->sign = a->sign != b->sign;
++ return a;
++ }
++ if (isnan (b))
++ {
++ b->sign = a->sign != b->sign;
++ return b;
++ }
++ if (isinf (a))
++ {
++ if (iszero (b))
++ return nan ();
++ a->sign = a->sign != b->sign;
++ return a;
++ }
++ if (isinf (b))
++ {
++ if (iszero (a))
++ {
++ return nan ();
++ }
++ b->sign = a->sign != b->sign;
++ return b;
++ }
++ if (iszero (a))
++ {
++ a->sign = a->sign != b->sign;
++ return a;
++ }
++ if (iszero (b))
++ {
++ b->sign = a->sign != b->sign;
++ return b;
++ }
++
++ /* Calculate the mantissa by multiplying both numbers to get a
++ twice-as-wide number. */
++ {
++#if defined(NO_DI_MODE) || defined(TFLOAT)
++ {
++ fractype x = a->fraction.ll;
++ fractype ylow = b->fraction.ll;
++ fractype yhigh = 0;
++ int bit;
++
++ /* ??? This does multiplies one bit at a time. Optimize. */
++ for (bit = 0; bit < FRAC_NBITS; bit++)
++ {
++ int carry;
++
++ if (x & 1)
++ {
++ carry = (low += ylow) < ylow;
++ high += yhigh + carry;
++ }
++ yhigh <<= 1;
++ if (ylow & FRACHIGH)
++ {
++ yhigh |= 1;
++ }
++ ylow <<= 1;
++ x >>= 1;
++ }
++ }
++#elif defined(FLOAT)
++ /* Multiplying two USIs to get a UDI, we're safe. */
++ {
++ UDItype answer = (UDItype)a->fraction.ll * (UDItype)b->fraction.ll;
++
++ high = answer >> BITS_PER_SI;
++ low = answer;
++ }
++#else
++ /* fractype is DImode, but we need the result to be twice as wide.
++ Assuming a widening multiply from DImode to TImode is not
++ available, build one by hand. */
++ {
++ USItype nl = a->fraction.ll;
++ USItype nh = a->fraction.ll >> BITS_PER_SI;
++ USItype ml = b->fraction.ll;
++ USItype mh = b->fraction.ll >> BITS_PER_SI;
++ UDItype pp_ll = (UDItype) ml * nl;
++ UDItype pp_hl = (UDItype) mh * nl;
++ UDItype pp_lh = (UDItype) ml * nh;
++ UDItype pp_hh = (UDItype) mh * nh;
++ UDItype res2 = 0;
++ UDItype res0 = 0;
++ UDItype ps_hh__ = pp_hl + pp_lh;
++ if (ps_hh__ < pp_hl)
++ res2 += (UDItype)1 << BITS_PER_SI;
++ pp_hl = (UDItype)(USItype)ps_hh__ << BITS_PER_SI;
++ res0 = pp_ll + pp_hl;
++ if (res0 < pp_ll)
++ res2++;
++ res2 += (ps_hh__ >> BITS_PER_SI) + pp_hh;
++ high = res2;
++ low = res0;
++ }
++#endif
++ }
++
++ tmp->normal_exp = a->normal_exp + b->normal_exp
++ + FRAC_NBITS - (FRACBITS + NGARDS);
++ tmp->sign = a->sign != b->sign;
++ while (high >= IMPLICIT_2)
++ {
++ tmp->normal_exp++;
++ if (high & 1)
++ {
++ low >>= 1;
++ low |= FRACHIGH;
++ }
++ high >>= 1;
++ }
++ while (high < IMPLICIT_1)
++ {
++ tmp->normal_exp--;
++
++ high <<= 1;
++ if (low & FRACHIGH)
++ high |= 1;
++ low <<= 1;
++ }
++ /* rounding is tricky. if we only round if it won't make us round later. */
++#if 0
++ if (low & FRACHIGH2)
++ {
++ if (((high & GARDMASK) != GARDMSB)
++ && (((high + 1) & GARDMASK) == GARDMSB))
++ {
++ /* don't round, it gets done again later. */
++ }
++ else
++ {
++ high++;
++ }
++ }
++#endif
++ if (!ROUND_TOWARDS_ZERO && (high & GARDMASK) == GARDMSB)
++ {
++ if (high & (1 << NGARDS))
++ {
++ /* half way, so round to even */
++ high += GARDROUND + 1;
++ }
++ else if (low)
++ {
++ /* but we really weren't half way */
++ high += GARDROUND + 1;
++ }
++ }
++ tmp->fraction.ll = high;
++ tmp->class = CLASS_NUMBER;
++ return tmp;
++}
++
++FLO_type
++multiply (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ fp_number_type tmp;
++ fp_number_type *res;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ res = _fpmul_parts (&a, &b, &tmp);
++
++ return pack_d (res);
++}
++#endif /* L_mul_sf || L_mul_df */
++
++#if defined(L_div_sf) || defined(L_div_df) || defined(L_div_tf)
++static inline __attribute__ ((__always_inline__)) fp_number_type *
++_fpdiv_parts (fp_number_type * a,
++ fp_number_type * b)
++{
++ fractype bit;
++ fractype numerator;
++ fractype denominator;
++ fractype quotient;
++
++ if (isnan (a))
++ {
++ return a;
++ }
++ if (isnan (b))
++ {
++ return b;
++ }
++
++ a->sign = a->sign ^ b->sign;
++
++ if (isinf (a) || iszero (a))
++ {
++ if (a->class == b->class)
++ return nan ();
++ return a;
++ }
++
++ if (isinf (b))
++ {
++ a->fraction.ll = 0;
++ a->normal_exp = 0;
++ return a;
++ }
++ if (iszero (b))
++ {
++ a->class = CLASS_INFINITY;
++ return a;
++ }
++
++ /* Calculate the mantissa by multiplying both 64bit numbers to get a
++ 128 bit number */
++ {
++ /* quotient =
++ ( numerator / denominator) * 2^(numerator exponent - denominator exponent)
++ */
++
++ a->normal_exp = a->normal_exp - b->normal_exp;
++ numerator = a->fraction.ll;
++ denominator = b->fraction.ll;
++
++ if (numerator < denominator)
++ {
++ /* Fraction will be less than 1.0 */
++ numerator *= 2;
++ a->normal_exp--;
++ }
++ bit = IMPLICIT_1;
++ quotient = 0;
++ /* ??? Does divide one bit at a time. Optimize. */
++ while (bit)
++ {
++ if (numerator >= denominator)
++ {
++ quotient |= bit;
++ numerator -= denominator;
++ }
++ bit >>= 1;
++ numerator *= 2;
++ }
++
++ if (!ROUND_TOWARDS_ZERO && (quotient & GARDMASK) == GARDMSB)
++ {
++ if (quotient & (1 << NGARDS))
++ {
++ /* half way, so round to even */
++ quotient += GARDROUND + 1;
++ }
++ else if (numerator)
++ {
++ /* but we really weren't half way, more bits exist */
++ quotient += GARDROUND + 1;
++ }
++ }
++
++ a->fraction.ll = quotient;
++ return (a);
++ }
++}
++
++FLO_type
++divide (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ fp_number_type *res;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ res = _fpdiv_parts (&a, &b);
++
++ return pack_d (res);
++}
++#endif /* L_div_sf || L_div_df */
++
++#if defined(L_fpcmp_parts_sf) || defined(L_fpcmp_parts_df) \
++ || defined(L_fpcmp_parts_tf)
++/* according to the demo, fpcmp returns a comparison with 0... thus
++ a<b -> -1
++ a==b -> 0
++ a>b -> +1
++ */
++
++int
++__fpcmp_parts (fp_number_type * a, fp_number_type * b)
++{
++#if 0
++ /* either nan -> unordered. Must be checked outside of this routine. */
++ if (isnan (a) && isnan (b))
++ {
++ return 1; /* still unordered! */
++ }
++#endif
++
++ if (isnan (a) || isnan (b))
++ {
++ return 1; /* how to indicate unordered compare? */
++ }
++ if (isinf (a) && isinf (b))
++ {
++ /* +inf > -inf, but +inf != +inf */
++ /* b \a| +inf(0)| -inf(1)
++ ______\+--------+--------
++ +inf(0)| a==b(0)| a<b(-1)
++ -------+--------+--------
++ -inf(1)| a>b(1) | a==b(0)
++ -------+--------+--------
++ So since unordered must be nonzero, just line up the columns...
++ */
++ return b->sign - a->sign;
++ }
++ /* but not both... */
++ if (isinf (a))
++ {
++ return a->sign ? -1 : 1;
++ }
++ if (isinf (b))
++ {
++ return b->sign ? 1 : -1;
++ }
++ if (iszero (a) && iszero (b))
++ {
++ return 0;
++ }
++ if (iszero (a))
++ {
++ return b->sign ? 1 : -1;
++ }
++ if (iszero (b))
++ {
++ return a->sign ? -1 : 1;
++ }
++ /* now both are "normal". */
++ if (a->sign != b->sign)
++ {
++ /* opposite signs */
++ return a->sign ? -1 : 1;
++ }
++ /* same sign; exponents? */
++ if (a->normal_exp > b->normal_exp)
++ {
++ return a->sign ? -1 : 1;
++ }
++ if (a->normal_exp < b->normal_exp)
++ {
++ return a->sign ? 1 : -1;
++ }
++ /* same exponents; check size. */
++ if (a->fraction.ll > b->fraction.ll)
++ {
++ return a->sign ? -1 : 1;
++ }
++ if (a->fraction.ll < b->fraction.ll)
++ {
++ return a->sign ? 1 : -1;
++ }
++ /* after all that, they're equal. */
++ return 0;
++}
++#endif
++
++#if defined(L_compare_sf) || defined(L_compare_df) || defined(L_compoare_tf)
++CMPtype
++compare (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ return __fpcmp_parts (&a, &b);
++}
++#endif /* L_compare_sf || L_compare_df */
++
++#ifndef US_SOFTWARE_GOFAST
++
++/* These should be optimized for their specific tasks someday. */
++
++#if defined(L_eq_sf) || defined(L_eq_df) || defined(L_eq_tf)
++CMPtype
++_eq_f2 (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ if (isnan (&a) || isnan (&b))
++ return 1; /* false, truth == 0 */
++
++ return __fpcmp_parts (&a, &b) ;
++}
++#endif /* L_eq_sf || L_eq_df */
++
++#if defined(L_ne_sf) || defined(L_ne_df) || defined(L_ne_tf)
++CMPtype
++_ne_f2 (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ if (isnan (&a) || isnan (&b))
++ return 1; /* true, truth != 0 */
++
++ return __fpcmp_parts (&a, &b) ;
++}
++#endif /* L_ne_sf || L_ne_df */
++
++#if defined(L_gt_sf) || defined(L_gt_df) || defined(L_gt_tf)
++CMPtype
++_gt_f2 (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ if (isnan (&a) || isnan (&b))
++ return -1; /* false, truth > 0 */
++
++ return __fpcmp_parts (&a, &b);
++}
++#endif /* L_gt_sf || L_gt_df */
++
++#if defined(L_ge_sf) || defined(L_ge_df) || defined(L_ge_tf)
++CMPtype
++_ge_f2 (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ if (isnan (&a) || isnan (&b))
++ return -1; /* false, truth >= 0 */
++ return __fpcmp_parts (&a, &b) ;
++}
++#endif /* L_ge_sf || L_ge_df */
++
++#if defined(L_lt_sf) || defined(L_lt_df) || defined(L_lt_tf)
++CMPtype
++_lt_f2 (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ if (isnan (&a) || isnan (&b))
++ return 1; /* false, truth < 0 */
++
++ return __fpcmp_parts (&a, &b);
++}
++#endif /* L_lt_sf || L_lt_df */
++
++#if defined(L_le_sf) || defined(L_le_df) || defined(L_le_tf)
++CMPtype
++_le_f2 (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ if (isnan (&a) || isnan (&b))
++ return 1; /* false, truth <= 0 */
++
++ return __fpcmp_parts (&a, &b) ;
++}
++#endif /* L_le_sf || L_le_df */
++
++#endif /* ! US_SOFTWARE_GOFAST */
++
++#if defined(L_unord_sf) || defined(L_unord_df) || defined(L_unord_tf)
++CMPtype
++_unord_f2 (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ return (isnan (&a) || isnan (&b));
++}
++#endif /* L_unord_sf || L_unord_df */
++
++#if defined(L_si_to_sf) || defined(L_si_to_df) || defined(L_si_to_tf)
++FLO_type
++si_to_float (SItype arg_a)
++{
++ fp_number_type in;
++
++ in.class = CLASS_NUMBER;
++ in.sign = arg_a < 0;
++ if (!arg_a)
++ {
++ in.class = CLASS_ZERO;
++ }
++ else
++ {
++ in.normal_exp = FRACBITS + NGARDS;
++ if (in.sign)
++ {
++ /* Special case for minint, since there is no +ve integer
++ representation for it */
++ if (arg_a == (- MAX_SI_INT - 1))
++ {
++ return (FLO_type)(- MAX_SI_INT - 1);
++ }
++ in.fraction.ll = (-arg_a);
++ }
++ else
++ in.fraction.ll = arg_a;
++
++ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS)))
++ {
++ in.fraction.ll <<= 1;
++ in.normal_exp -= 1;
++ }
++ }
++ return pack_d (&in);
++}
++#endif /* L_si_to_sf || L_si_to_df */
++
++#if defined(L_usi_to_sf) || defined(L_usi_to_df) || defined(L_usi_to_tf)
++FLO_type
++usi_to_float (USItype arg_a)
++{
++ fp_number_type in;
++
++ in.sign = 0;
++ if (!arg_a)
++ {
++ in.class = CLASS_ZERO;
++ }
++ else
++ {
++ in.class = CLASS_NUMBER;
++ in.normal_exp = FRACBITS + NGARDS;
++ in.fraction.ll = arg_a;
++
++ while (in.fraction.ll > ((fractype)1 << (FRACBITS + NGARDS)))
++ {
++ in.fraction.ll >>= 1;
++ in.normal_exp += 1;
++ }
++ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS)))
++ {
++ in.fraction.ll <<= 1;
++ in.normal_exp -= 1;
++ }
++ }
++ return pack_d (&in);
++}
++#endif
++
++#if defined(L_sf_to_si) || defined(L_df_to_si) || defined(L_tf_to_si)
++SItype
++float_to_si (FLO_type arg_a)
++{
++ fp_number_type a;
++ SItype tmp;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &a);
++
++ if (iszero (&a))
++ return 0;
++ if (isnan (&a))
++ return 0;
++ /* get reasonable MAX_SI_INT... */
++ if (isinf (&a))
++ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT;
++ /* it is a number, but a small one */
++ if (a.normal_exp < 0)
++ return 0;
++ if (a.normal_exp > BITS_PER_SI - 2)
++ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT;
++ tmp = a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp);
++ return a.sign ? (-tmp) : (tmp);
++}
++#endif /* L_sf_to_si || L_df_to_si */
++
++#if defined(L_sf_to_usi) || defined(L_df_to_usi) || defined(L_tf_to_usi)
++#if defined US_SOFTWARE_GOFAST || defined(L_tf_to_usi)
++/* While libgcc2.c defines its own __fixunssfsi and __fixunsdfsi routines,
++ we also define them for GOFAST because the ones in libgcc2.c have the
++ wrong names and I'd rather define these here and keep GOFAST CYG-LOC's
++ out of libgcc2.c. We can't define these here if not GOFAST because then
++ there'd be duplicate copies. */
++
++USItype
++float_to_usi (FLO_type arg_a)
++{
++ fp_number_type a;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &a);
++
++ if (iszero (&a))
++ return 0;
++ if (isnan (&a))
++ return 0;
++ /* it is a negative number */
++ if (a.sign)
++ return 0;
++ /* get reasonable MAX_USI_INT... */
++ if (isinf (&a))
++ return MAX_USI_INT;
++ /* it is a number, but a small one */
++ if (a.normal_exp < 0)
++ return 0;
++ if (a.normal_exp > BITS_PER_SI - 1)
++ return MAX_USI_INT;
++ else if (a.normal_exp > (FRACBITS + NGARDS))
++ return a.fraction.ll << (a.normal_exp - (FRACBITS + NGARDS));
++ else
++ return a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp);
++}
++#endif /* US_SOFTWARE_GOFAST */
++#endif /* L_sf_to_usi || L_df_to_usi */
++
++#if defined(L_negate_sf) || defined(L_negate_df) || defined(L_negate_tf)
++FLO_type
++negate (FLO_type arg_a)
++{
++ fp_number_type a;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &a);
++
++ flip_sign (&a);
++ return pack_d (&a);
++}
++#endif /* L_negate_sf || L_negate_df */
++
++#ifdef FLOAT
++
++#if defined(L_make_sf)
++SFtype
++__make_fp(fp_class_type class,
++ unsigned int sign,
++ int exp,
++ USItype frac)
++{
++ fp_number_type in;
++
++ in.class = class;
++ in.sign = sign;
++ in.normal_exp = exp;
++ in.fraction.ll = frac;
++ return pack_d (&in);
++}
++#endif /* L_make_sf */
++
++#ifndef FLOAT_ONLY
++
++/* This enables one to build an fp library that supports float but not double.
++ Otherwise, we would get an undefined reference to __make_dp.
++ This is needed for some 8-bit ports that can't handle well values that
++ are 8-bytes in size, so we just don't support double for them at all. */
++
++#if defined(L_sf_to_df)
++DFtype
++sf_to_df (SFtype arg_a)
++{
++ fp_number_type in;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &in);
++
++ return __make_dp (in.class, in.sign, in.normal_exp,
++ ((UDItype) in.fraction.ll) << F_D_BITOFF);
++}
++#endif /* L_sf_to_df */
++
++#if defined(L_sf_to_tf) && defined(TMODES)
++TFtype
++sf_to_tf (SFtype arg_a)
++{
++ fp_number_type in;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &in);
++
++ return __make_tp (in.class, in.sign, in.normal_exp,
++ ((UTItype) in.fraction.ll) << F_T_BITOFF);
++}
++#endif /* L_sf_to_df */
++
++#endif /* ! FLOAT_ONLY */
++#endif /* FLOAT */
++
++#ifndef FLOAT
++
++extern SFtype __make_fp (fp_class_type, unsigned int, int, USItype);
++
++#if defined(L_make_df)
++DFtype
++__make_dp (fp_class_type class, unsigned int sign, int exp, UDItype frac)
++{
++ fp_number_type in;
++
++ in.class = class;
++ in.sign = sign;
++ in.normal_exp = exp;
++ in.fraction.ll = frac;
++ return pack_d (&in);
++}
++#endif /* L_make_df */
++
++#if defined(L_df_to_sf)
++SFtype
++df_to_sf (DFtype arg_a)
++{
++ fp_number_type in;
++ USItype sffrac;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &in);
++
++ sffrac = in.fraction.ll >> F_D_BITOFF;
++
++ /* We set the lowest guard bit in SFFRAC if we discarded any non
++ zero bits. */
++ if ((in.fraction.ll & (((USItype) 1 << F_D_BITOFF) - 1)) != 0)
++ sffrac |= 1;
++
++ return __make_fp (in.class, in.sign, in.normal_exp, sffrac);
++}
++#endif /* L_df_to_sf */
++
++#if defined(L_df_to_tf) && defined(TMODES) \
++ && !defined(FLOAT) && !defined(TFLOAT)
++TFtype
++df_to_tf (DFtype arg_a)
++{
++ fp_number_type in;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &in);
++
++ return __make_tp (in.class, in.sign, in.normal_exp,
++ ((UTItype) in.fraction.ll) << D_T_BITOFF);
++}
++#endif /* L_sf_to_df */
++
++#ifdef TFLOAT
++#if defined(L_make_tf)
++TFtype
++__make_tp(fp_class_type class,
++ unsigned int sign,
++ int exp,
++ UTItype frac)
++{
++ fp_number_type in;
++
++ in.class = class;
++ in.sign = sign;
++ in.normal_exp = exp;
++ in.fraction.ll = frac;
++ return pack_d (&in);
++}
++#endif /* L_make_tf */
++
++#if defined(L_tf_to_df)
++DFtype
++tf_to_df (TFtype arg_a)
++{
++ fp_number_type in;
++ UDItype sffrac;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &in);
++
++ sffrac = in.fraction.ll >> D_T_BITOFF;
++
++ /* We set the lowest guard bit in SFFRAC if we discarded any non
++ zero bits. */
++ if ((in.fraction.ll & (((UTItype) 1 << D_T_BITOFF) - 1)) != 0)
++ sffrac |= 1;
++
++ return __make_dp (in.class, in.sign, in.normal_exp, sffrac);
++}
++#endif /* L_tf_to_df */
++
++#if defined(L_tf_to_sf)
++SFtype
++tf_to_sf (TFtype arg_a)
++{
++ fp_number_type in;
++ USItype sffrac;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &in);
++
++ sffrac = in.fraction.ll >> F_T_BITOFF;
++
++ /* We set the lowest guard bit in SFFRAC if we discarded any non
++ zero bits. */
++ if ((in.fraction.ll & (((UTItype) 1 << F_T_BITOFF) - 1)) != 0)
++ sffrac |= 1;
++
++ return __make_fp (in.class, in.sign, in.normal_exp, sffrac);
++}
++#endif /* L_tf_to_sf */
++#endif /* TFLOAT */
++
++#endif /* ! FLOAT */
++#endif /* !EXTENDED_FLOAT_STUBS */
+--- gcc-3.4.3/gcc/config/nios2/nios2-fp-bit.c
++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2-fp-bit.c
+@@ -0,0 +1,1652 @@
++#define FLOAT
++/* This is a software floating point library which can be used
++ for targets without hardware floating point.
++ Copyright (C) 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004
++ Free Software Foundation, Inc.
++
++This file is free software; you can redistribute it and/or modify it
++under the terms of the GNU General Public License as published by 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 other files,
++ some of which are compiled with GCC, to produce an executable,
++ this library does not by itself cause the resulting executable
++ to be covered by the GNU General Public License.
++ This exception does not however invalidate any other reasons why
++ the executable file might be covered by the GNU General Public License. */
++
++/* This implements IEEE 754 format arithmetic, but does not provide a
++ mechanism for setting the rounding mode, or for generating or handling
++ exceptions.
++
++ The original code by Steve Chamberlain, hacked by Mark Eichin and Jim
++ Wilson, all of Cygnus Support. */
++
++/* The intended way to use this file is to make two copies, add `#define FLOAT'
++ to one copy, then compile both copies and add them to libgcc.a. */
++
++#include "tconfig.h"
++#include "coretypes.h"
++#include "tm.h"
++#include "config/fp-bit.h"
++
++/* The following macros can be defined to change the behavior of this file:
++ FLOAT: Implement a `float', aka SFmode, fp library. If this is not
++ defined, then this file implements a `double', aka DFmode, fp library.
++ FLOAT_ONLY: Used with FLOAT, to implement a `float' only library, i.e.
++ don't include float->double conversion which requires the double library.
++ This is useful only for machines which can't support doubles, e.g. some
++ 8-bit processors.
++ CMPtype: Specify the type that floating point compares should return.
++ This defaults to SItype, aka int.
++ US_SOFTWARE_GOFAST: This makes all entry points use the same names as the
++ US Software goFast library.
++ _DEBUG_BITFLOAT: This makes debugging the code a little easier, by adding
++ two integers to the FLO_union_type.
++ NO_DENORMALS: Disable handling of denormals.
++ NO_NANS: Disable nan and infinity handling
++ SMALL_MACHINE: Useful when operations on QIs and HIs are faster
++ than on an SI */
++
++/* We don't currently support extended floats (long doubles) on machines
++ without hardware to deal with them.
++
++ These stubs are just to keep the linker from complaining about unresolved
++ references which can be pulled in from libio & libstdc++, even if the
++ user isn't using long doubles. However, they may generate an unresolved
++ external to abort if abort is not used by the function, and the stubs
++ are referenced from within libc, since libgcc goes before and after the
++ system library. */
++
++#ifdef DECLARE_LIBRARY_RENAMES
++ DECLARE_LIBRARY_RENAMES
++#endif
++
++#ifdef EXTENDED_FLOAT_STUBS
++extern void abort (void);
++void __extendsfxf2 (void) { abort(); }
++void __extenddfxf2 (void) { abort(); }
++void __truncxfdf2 (void) { abort(); }
++void __truncxfsf2 (void) { abort(); }
++void __fixxfsi (void) { abort(); }
++void __floatsixf (void) { abort(); }
++void __addxf3 (void) { abort(); }
++void __subxf3 (void) { abort(); }
++void __mulxf3 (void) { abort(); }
++void __divxf3 (void) { abort(); }
++void __negxf2 (void) { abort(); }
++void __eqxf2 (void) { abort(); }
++void __nexf2 (void) { abort(); }
++void __gtxf2 (void) { abort(); }
++void __gexf2 (void) { abort(); }
++void __lexf2 (void) { abort(); }
++void __ltxf2 (void) { abort(); }
++
++void __extendsftf2 (void) { abort(); }
++void __extenddftf2 (void) { abort(); }
++void __trunctfdf2 (void) { abort(); }
++void __trunctfsf2 (void) { abort(); }
++void __fixtfsi (void) { abort(); }
++void __floatsitf (void) { abort(); }
++void __addtf3 (void) { abort(); }
++void __subtf3 (void) { abort(); }
++void __multf3 (void) { abort(); }
++void __divtf3 (void) { abort(); }
++void __negtf2 (void) { abort(); }
++void __eqtf2 (void) { abort(); }
++void __netf2 (void) { abort(); }
++void __gttf2 (void) { abort(); }
++void __getf2 (void) { abort(); }
++void __letf2 (void) { abort(); }
++void __lttf2 (void) { abort(); }
++#else /* !EXTENDED_FLOAT_STUBS, rest of file */
++
++/* IEEE "special" number predicates */
++
++#ifdef NO_NANS
++
++#define nan() 0
++#define isnan(x) 0
++#define isinf(x) 0
++#else
++
++#if defined L_thenan_sf
++const fp_number_type __thenan_sf = { CLASS_SNAN, 0, 0, {(fractype) 0} };
++#elif defined L_thenan_df
++const fp_number_type __thenan_df = { CLASS_SNAN, 0, 0, {(fractype) 0} };
++#elif defined L_thenan_tf
++const fp_number_type __thenan_tf = { CLASS_SNAN, 0, 0, {(fractype) 0} };
++#elif defined TFLOAT
++extern const fp_number_type __thenan_tf;
++#elif defined FLOAT
++extern const fp_number_type __thenan_sf;
++#else
++extern const fp_number_type __thenan_df;
++#endif
++
++INLINE
++static fp_number_type *
++nan (void)
++{
++ /* Discard the const qualifier... */
++#ifdef TFLOAT
++ return (fp_number_type *) (& __thenan_tf);
++#elif defined FLOAT
++ return (fp_number_type *) (& __thenan_sf);
++#else
++ return (fp_number_type *) (& __thenan_df);
++#endif
++}
++
++INLINE
++static int
++isnan ( fp_number_type * x)
++{
++ return x->class == CLASS_SNAN || x->class == CLASS_QNAN;
++}
++
++INLINE
++static int
++isinf ( fp_number_type * x)
++{
++ return x->class == CLASS_INFINITY;
++}
++
++#endif /* NO_NANS */
++
++INLINE
++static int
++iszero ( fp_number_type * x)
++{
++ return x->class == CLASS_ZERO;
++}
++
++INLINE
++static void
++flip_sign ( fp_number_type * x)
++{
++ x->sign = !x->sign;
++}
++
++extern FLO_type pack_d ( fp_number_type * );
++
++#if defined(L_pack_df) || defined(L_pack_sf) || defined(L_pack_tf)
++FLO_type
++pack_d ( fp_number_type * src)
++{
++ FLO_union_type dst;
++ fractype fraction = src->fraction.ll; /* wasn't unsigned before? */
++ int sign = src->sign;
++ int exp = 0;
++
++ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && (isnan (src) || isinf (src)))
++ {
++ /* We can't represent these values accurately. By using the
++ largest possible magnitude, we guarantee that the conversion
++ of infinity is at least as big as any finite number. */
++ exp = EXPMAX;
++ fraction = ((fractype) 1 << FRACBITS) - 1;
++ }
++ else if (isnan (src))
++ {
++ exp = EXPMAX;
++ if (src->class == CLASS_QNAN || 1)
++ {
++#ifdef QUIET_NAN_NEGATED
++ fraction |= QUIET_NAN - 1;
++#else
++ fraction |= QUIET_NAN;
++#endif
++ }
++ }
++ else if (isinf (src))
++ {
++ exp = EXPMAX;
++ fraction = 0;
++ }
++ else if (iszero (src))
++ {
++ exp = 0;
++ fraction = 0;
++ }
++ else if (fraction == 0)
++ {
++ exp = 0;
++ }
++ else
++ {
++ if (src->normal_exp < NORMAL_EXPMIN)
++ {
++#ifdef NO_DENORMALS
++ /* Go straight to a zero representation if denormals are not
++ supported. The denormal handling would be harmless but
++ isn't unnecessary. */
++ exp = 0;
++ fraction = 0;
++#else /* NO_DENORMALS */
++ /* This number's exponent is too low to fit into the bits
++ available in the number, so we'll store 0 in the exponent and
++ shift the fraction to the right to make up for it. */
++
++ int shift = NORMAL_EXPMIN - src->normal_exp;
++
++ exp = 0;
++
++ if (shift > FRAC_NBITS - NGARDS)
++ {
++ /* No point shifting, since it's more that 64 out. */
++ fraction = 0;
++ }
++ else
++ {
++ int lowbit = (fraction & (((fractype)1 << shift) - 1)) ? 1 : 0;
++ fraction = (fraction >> shift) | lowbit;
++ }
++ if ((fraction & GARDMASK) == GARDMSB)
++ {
++ if ((fraction & (1 << NGARDS)))
++ fraction += GARDROUND + 1;
++ }
++ else
++ {
++ /* Add to the guards to round up. */
++ fraction += GARDROUND;
++ }
++ /* Perhaps the rounding means we now need to change the
++ exponent, because the fraction is no longer denormal. */
++ if (fraction >= IMPLICIT_1)
++ {
++ exp += 1;
++ }
++ fraction >>= NGARDS;
++#endif /* NO_DENORMALS */
++ }
++ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS)
++ && src->normal_exp > EXPBIAS)
++ {
++ exp = EXPMAX;
++ fraction = 0;
++ }
++ else
++ {
++ exp = src->normal_exp + EXPBIAS;
++ if (!ROUND_TOWARDS_ZERO)
++ {
++ /* IF the gard bits are the all zero, but the first, then we're
++ half way between two numbers, choose the one which makes the
++ lsb of the answer 0. */
++ if ((fraction & GARDMASK) == GARDMSB)
++ {
++ if (fraction & (1 << NGARDS))
++ fraction += GARDROUND + 1;
++ }
++ else
++ {
++ /* Add a one to the guards to round up */
++ fraction += GARDROUND;
++ }
++ if (fraction >= IMPLICIT_2)
++ {
++ fraction >>= 1;
++ exp += 1;
++ }
++ }
++ fraction >>= NGARDS;
++
++ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp > EXPMAX)
++ {
++ /* Saturate on overflow. */
++ exp = EXPMAX;
++ fraction = ((fractype) 1 << FRACBITS) - 1;
++ }
++ }
++ }
++
++ /* We previously used bitfields to store the number, but this doesn't
++ handle little/big endian systems conveniently, so use shifts and
++ masks */
++#ifdef FLOAT_BIT_ORDER_MISMATCH
++ dst.bits.fraction = fraction;
++ dst.bits.exp = exp;
++ dst.bits.sign = sign;
++#else
++# if defined TFLOAT && defined HALFFRACBITS
++ {
++ halffractype high, low, unity;
++ int lowsign, lowexp;
++
++ unity = (halffractype) 1 << HALFFRACBITS;
++
++ /* Set HIGH to the high double's significand, masking out the implicit 1.
++ Set LOW to the low double's full significand. */
++ high = (fraction >> (FRACBITS - HALFFRACBITS)) & (unity - 1);
++ low = fraction & (unity * 2 - 1);
++
++ /* Get the initial sign and exponent of the low double. */
++ lowexp = exp - HALFFRACBITS - 1;
++ lowsign = sign;
++
++ /* HIGH should be rounded like a normal double, making |LOW| <=
++ 0.5 ULP of HIGH. Assume round-to-nearest. */
++ if (exp < EXPMAX)
++ if (low > unity || (low == unity && (high & 1) == 1))
++ {
++ /* Round HIGH up and adjust LOW to match. */
++ high++;
++ if (high == unity)
++ {
++ /* May make it infinite, but that's OK. */
++ high = 0;
++ exp++;
++ }
++ low = unity * 2 - low;
++ lowsign ^= 1;
++ }
++
++ high |= (halffractype) exp << HALFFRACBITS;
++ high |= (halffractype) sign << (HALFFRACBITS + EXPBITS);
++
++ if (exp == EXPMAX || exp == 0 || low == 0)
++ low = 0;
++ else
++ {
++ while (lowexp > 0 && low < unity)
++ {
++ low <<= 1;
++ lowexp--;
++ }
++
++ if (lowexp <= 0)
++ {
++ halffractype roundmsb, round;
++ int shift;
++
++ shift = 1 - lowexp;
++ roundmsb = (1 << (shift - 1));
++ round = low & ((roundmsb << 1) - 1);
++
++ low >>= shift;
++ lowexp = 0;
++
++ if (round > roundmsb || (round == roundmsb && (low & 1) == 1))
++ {
++ low++;
++ if (low == unity)
++ /* LOW rounds up to the smallest normal number. */
++ lowexp++;
++ }
++ }
++
++ low &= unity - 1;
++ low |= (halffractype) lowexp << HALFFRACBITS;
++ low |= (halffractype) lowsign << (HALFFRACBITS + EXPBITS);
++ }
++ dst.value_raw = ((fractype) high << HALFSHIFT) | low;
++ }
++# else
++ dst.value_raw = fraction & ((((fractype)1) << FRACBITS) - (fractype)1);
++ dst.value_raw |= ((fractype) (exp & ((1 << EXPBITS) - 1))) << FRACBITS;
++ dst.value_raw |= ((fractype) (sign & 1)) << (FRACBITS | EXPBITS);
++# endif
++#endif
++
++#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT)
++#ifdef TFLOAT
++ {
++ qrtrfractype tmp1 = dst.words[0];
++ qrtrfractype tmp2 = dst.words[1];
++ dst.words[0] = dst.words[3];
++ dst.words[1] = dst.words[2];
++ dst.words[2] = tmp2;
++ dst.words[3] = tmp1;
++ }
++#else
++ {
++ halffractype tmp = dst.words[0];
++ dst.words[0] = dst.words[1];
++ dst.words[1] = tmp;
++ }
++#endif
++#endif
++
++ return dst.value;
++}
++#endif
++
++#if defined(L_unpack_df) || defined(L_unpack_sf) || defined(L_unpack_tf)
++void
++unpack_d (FLO_union_type * src, fp_number_type * dst)
++{
++ /* We previously used bitfields to store the number, but this doesn't
++ handle little/big endian systems conveniently, so use shifts and
++ masks */
++ fractype fraction;
++ int exp;
++ int sign;
++
++#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT)
++ FLO_union_type swapped;
++
++#ifdef TFLOAT
++ swapped.words[0] = src->words[3];
++ swapped.words[1] = src->words[2];
++ swapped.words[2] = src->words[1];
++ swapped.words[3] = src->words[0];
++#else
++ swapped.words[0] = src->words[1];
++ swapped.words[1] = src->words[0];
++#endif
++ src = &swapped;
++#endif
++
++#ifdef FLOAT_BIT_ORDER_MISMATCH
++ fraction = src->bits.fraction;
++ exp = src->bits.exp;
++ sign = src->bits.sign;
++#else
++# if defined TFLOAT && defined HALFFRACBITS
++ {
++ halffractype high, low;
++
++ high = src->value_raw >> HALFSHIFT;
++ low = src->value_raw & (((fractype)1 << HALFSHIFT) - 1);
++
++ fraction = high & ((((fractype)1) << HALFFRACBITS) - 1);
++ fraction <<= FRACBITS - HALFFRACBITS;
++ exp = ((int)(high >> HALFFRACBITS)) & ((1 << EXPBITS) - 1);
++ sign = ((int)(high >> (((HALFFRACBITS + EXPBITS))))) & 1;
++
++ if (exp != EXPMAX && exp != 0 && low != 0)
++ {
++ int lowexp = ((int)(low >> HALFFRACBITS)) & ((1 << EXPBITS) - 1);
++ int lowsign = ((int)(low >> (((HALFFRACBITS + EXPBITS))))) & 1;
++ int shift;
++ fractype xlow;
++
++ xlow = low & ((((fractype)1) << HALFFRACBITS) - 1);
++ if (lowexp)
++ xlow |= (((halffractype)1) << HALFFRACBITS);
++ else
++ lowexp = 1;
++ shift = (FRACBITS - HALFFRACBITS) - (exp - lowexp);
++ if (shift > 0)
++ xlow <<= shift;
++ else if (shift < 0)
++ xlow >>= -shift;
++ if (sign == lowsign)
++ fraction += xlow;
++ else if (fraction >= xlow)
++ fraction -= xlow;
++ else
++ {
++ /* The high part is a power of two but the full number is lower.
++ This code will leave the implicit 1 in FRACTION, but we'd
++ have added that below anyway. */
++ fraction = (((fractype) 1 << FRACBITS) - xlow) << 1;
++ exp--;
++ }
++ }
++ }
++# else
++ fraction = src->value_raw & ((((fractype)1) << FRACBITS) - 1);
++ exp = ((int)(src->value_raw >> FRACBITS)) & ((1 << EXPBITS) - 1);
++ sign = ((int)(src->value_raw >> (FRACBITS + EXPBITS))) & 1;
++# endif
++#endif
++
++ dst->sign = sign;
++ if (exp == 0)
++ {
++ /* Hmm. Looks like 0 */
++ if (fraction == 0
++#ifdef NO_DENORMALS
++ || 1
++#endif
++ )
++ {
++ /* tastes like zero */
++ dst->class = CLASS_ZERO;
++ }
++ else
++ {
++ /* Zero exponent with nonzero fraction - it's denormalized,
++ so there isn't a leading implicit one - we'll shift it so
++ it gets one. */
++ dst->normal_exp = exp - EXPBIAS + 1;
++ fraction <<= NGARDS;
++
++ dst->class = CLASS_NUMBER;
++#if 1
++ while (fraction < IMPLICIT_1)
++ {
++ fraction <<= 1;
++ dst->normal_exp--;
++ }
++#endif
++ dst->fraction.ll = fraction;
++ }
++ }
++ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp == EXPMAX)
++ {
++ /* Huge exponent*/
++ if (fraction == 0)
++ {
++ /* Attached to a zero fraction - means infinity */
++ dst->class = CLASS_INFINITY;
++ }
++ else
++ {
++ /* Nonzero fraction, means nan */
++#ifdef QUIET_NAN_NEGATED
++ if ((fraction & QUIET_NAN) == 0)
++#else
++ if (fraction & QUIET_NAN)
++#endif
++ {
++ dst->class = CLASS_QNAN;
++ }
++ else
++ {
++ dst->class = CLASS_SNAN;
++ }
++ /* Keep the fraction part as the nan number */
++ dst->fraction.ll = fraction;
++ }
++ }
++ else
++ {
++ /* Nothing strange about this number */
++ dst->normal_exp = exp - EXPBIAS;
++ dst->class = CLASS_NUMBER;
++ dst->fraction.ll = (fraction << NGARDS) | IMPLICIT_1;
++ }
++}
++#endif /* L_unpack_df || L_unpack_sf */
++
++#if defined(L_addsub_sf) || defined(L_addsub_df) || defined(L_addsub_tf)
++static fp_number_type *
++_fpadd_parts (fp_number_type * a,
++ fp_number_type * b,
++ fp_number_type * tmp)
++{
++ intfrac tfraction;
++
++ /* Put commonly used fields in local variables. */
++ int a_normal_exp;
++ int b_normal_exp;
++ fractype a_fraction;
++ fractype b_fraction;
++
++ if (isnan (a))
++ {
++ return a;
++ }
++ if (isnan (b))
++ {
++ return b;
++ }
++ if (isinf (a))
++ {
++ /* Adding infinities with opposite signs yields a NaN. */
++ if (isinf (b) && a->sign != b->sign)
++ return nan ();
++ return a;
++ }
++ if (isinf (b))
++ {
++ return b;
++ }
++ if (iszero (b))
++ {
++ if (iszero (a))
++ {
++ *tmp = *a;
++ tmp->sign = a->sign & b->sign;
++ return tmp;
++ }
++ return a;
++ }
++ if (iszero (a))
++ {
++ return b;
++ }
++
++ /* Got two numbers. shift the smaller and increment the exponent till
++ they're the same */
++ {
++ int diff;
++
++ a_normal_exp = a->normal_exp;
++ b_normal_exp = b->normal_exp;
++ a_fraction = a->fraction.ll;
++ b_fraction = b->fraction.ll;
++
++ diff = a_normal_exp - b_normal_exp;
++
++ if (diff < 0)
++ diff = -diff;
++ if (diff < FRAC_NBITS)
++ {
++ /* ??? This does shifts one bit at a time. Optimize. */
++ while (a_normal_exp > b_normal_exp)
++ {
++ b_normal_exp++;
++ LSHIFT (b_fraction);
++ }
++ while (b_normal_exp > a_normal_exp)
++ {
++ a_normal_exp++;
++ LSHIFT (a_fraction);
++ }
++ }
++ else
++ {
++ /* Somethings's up.. choose the biggest */
++ if (a_normal_exp > b_normal_exp)
++ {
++ b_normal_exp = a_normal_exp;
++ b_fraction = 0;
++ }
++ else
++ {
++ a_normal_exp = b_normal_exp;
++ a_fraction = 0;
++ }
++ }
++ }
++
++ if (a->sign != b->sign)
++ {
++ if (a->sign)
++ {
++ tfraction = -a_fraction + b_fraction;
++ }
++ else
++ {
++ tfraction = a_fraction - b_fraction;
++ }
++ if (tfraction >= 0)
++ {
++ tmp->sign = 0;
++ tmp->normal_exp = a_normal_exp;
++ tmp->fraction.ll = tfraction;
++ }
++ else
++ {
++ tmp->sign = 1;
++ tmp->normal_exp = a_normal_exp;
++ tmp->fraction.ll = -tfraction;
++ }
++ /* and renormalize it */
++
++ while (tmp->fraction.ll < IMPLICIT_1 && tmp->fraction.ll)
++ {
++ tmp->fraction.ll <<= 1;
++ tmp->normal_exp--;
++ }
++ }
++ else
++ {
++ tmp->sign = a->sign;
++ tmp->normal_exp = a_normal_exp;
++ tmp->fraction.ll = a_fraction + b_fraction;
++ }
++ tmp->class = CLASS_NUMBER;
++ /* Now the fraction is added, we have to shift down to renormalize the
++ number */
++
++ if (tmp->fraction.ll >= IMPLICIT_2)
++ {
++ LSHIFT (tmp->fraction.ll);
++ tmp->normal_exp++;
++ }
++ return tmp;
++
++}
++
++FLO_type
++add (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ fp_number_type tmp;
++ fp_number_type *res;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ res = _fpadd_parts (&a, &b, &tmp);
++
++ return pack_d (res);
++}
++
++FLO_type
++sub (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ fp_number_type tmp;
++ fp_number_type *res;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ b.sign ^= 1;
++
++ res = _fpadd_parts (&a, &b, &tmp);
++
++ return pack_d (res);
++}
++#endif /* L_addsub_sf || L_addsub_df */
++
++#if defined(L_mul_sf) || defined(L_mul_df) || defined(L_mul_tf)
++static inline __attribute__ ((__always_inline__)) fp_number_type *
++_fpmul_parts ( fp_number_type * a,
++ fp_number_type * b,
++ fp_number_type * tmp)
++{
++ fractype low = 0;
++ fractype high = 0;
++
++ if (isnan (a))
++ {
++ a->sign = a->sign != b->sign;
++ return a;
++ }
++ if (isnan (b))
++ {
++ b->sign = a->sign != b->sign;
++ return b;
++ }
++ if (isinf (a))
++ {
++ if (iszero (b))
++ return nan ();
++ a->sign = a->sign != b->sign;
++ return a;
++ }
++ if (isinf (b))
++ {
++ if (iszero (a))
++ {
++ return nan ();
++ }
++ b->sign = a->sign != b->sign;
++ return b;
++ }
++ if (iszero (a))
++ {
++ a->sign = a->sign != b->sign;
++ return a;
++ }
++ if (iszero (b))
++ {
++ b->sign = a->sign != b->sign;
++ return b;
++ }
++
++ /* Calculate the mantissa by multiplying both numbers to get a
++ twice-as-wide number. */
++ {
++#if defined(NO_DI_MODE) || defined(TFLOAT)
++ {
++ fractype x = a->fraction.ll;
++ fractype ylow = b->fraction.ll;
++ fractype yhigh = 0;
++ int bit;
++
++ /* ??? This does multiplies one bit at a time. Optimize. */
++ for (bit = 0; bit < FRAC_NBITS; bit++)
++ {
++ int carry;
++
++ if (x & 1)
++ {
++ carry = (low += ylow) < ylow;
++ high += yhigh + carry;
++ }
++ yhigh <<= 1;
++ if (ylow & FRACHIGH)
++ {
++ yhigh |= 1;
++ }
++ ylow <<= 1;
++ x >>= 1;
++ }
++ }
++#elif defined(FLOAT)
++ /* Multiplying two USIs to get a UDI, we're safe. */
++ {
++ UDItype answer = (UDItype)a->fraction.ll * (UDItype)b->fraction.ll;
++
++ high = answer >> BITS_PER_SI;
++ low = answer;
++ }
++#else
++ /* fractype is DImode, but we need the result to be twice as wide.
++ Assuming a widening multiply from DImode to TImode is not
++ available, build one by hand. */
++ {
++ USItype nl = a->fraction.ll;
++ USItype nh = a->fraction.ll >> BITS_PER_SI;
++ USItype ml = b->fraction.ll;
++ USItype mh = b->fraction.ll >> BITS_PER_SI;
++ UDItype pp_ll = (UDItype) ml * nl;
++ UDItype pp_hl = (UDItype) mh * nl;
++ UDItype pp_lh = (UDItype) ml * nh;
++ UDItype pp_hh = (UDItype) mh * nh;
++ UDItype res2 = 0;
++ UDItype res0 = 0;
++ UDItype ps_hh__ = pp_hl + pp_lh;
++ if (ps_hh__ < pp_hl)
++ res2 += (UDItype)1 << BITS_PER_SI;
++ pp_hl = (UDItype)(USItype)ps_hh__ << BITS_PER_SI;
++ res0 = pp_ll + pp_hl;
++ if (res0 < pp_ll)
++ res2++;
++ res2 += (ps_hh__ >> BITS_PER_SI) + pp_hh;
++ high = res2;
++ low = res0;
++ }
++#endif
++ }
++
++ tmp->normal_exp = a->normal_exp + b->normal_exp
++ + FRAC_NBITS - (FRACBITS + NGARDS);
++ tmp->sign = a->sign != b->sign;
++ while (high >= IMPLICIT_2)
++ {
++ tmp->normal_exp++;
++ if (high & 1)
++ {
++ low >>= 1;
++ low |= FRACHIGH;
++ }
++ high >>= 1;
++ }
++ while (high < IMPLICIT_1)
++ {
++ tmp->normal_exp--;
++
++ high <<= 1;
++ if (low & FRACHIGH)
++ high |= 1;
++ low <<= 1;
++ }
++ /* rounding is tricky. if we only round if it won't make us round later. */
++#if 0
++ if (low & FRACHIGH2)
++ {
++ if (((high & GARDMASK) != GARDMSB)
++ && (((high + 1) & GARDMASK) == GARDMSB))
++ {
++ /* don't round, it gets done again later. */
++ }
++ else
++ {
++ high++;
++ }
++ }
++#endif
++ if (!ROUND_TOWARDS_ZERO && (high & GARDMASK) == GARDMSB)
++ {
++ if (high & (1 << NGARDS))
++ {
++ /* half way, so round to even */
++ high += GARDROUND + 1;
++ }
++ else if (low)
++ {
++ /* but we really weren't half way */
++ high += GARDROUND + 1;
++ }
++ }
++ tmp->fraction.ll = high;
++ tmp->class = CLASS_NUMBER;
++ return tmp;
++}
++
++FLO_type
++multiply (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ fp_number_type tmp;
++ fp_number_type *res;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ res = _fpmul_parts (&a, &b, &tmp);
++
++ return pack_d (res);
++}
++#endif /* L_mul_sf || L_mul_df */
++
++#if defined(L_div_sf) || defined(L_div_df) || defined(L_div_tf)
++static inline __attribute__ ((__always_inline__)) fp_number_type *
++_fpdiv_parts (fp_number_type * a,
++ fp_number_type * b)
++{
++ fractype bit;
++ fractype numerator;
++ fractype denominator;
++ fractype quotient;
++
++ if (isnan (a))
++ {
++ return a;
++ }
++ if (isnan (b))
++ {
++ return b;
++ }
++
++ a->sign = a->sign ^ b->sign;
++
++ if (isinf (a) || iszero (a))
++ {
++ if (a->class == b->class)
++ return nan ();
++ return a;
++ }
++
++ if (isinf (b))
++ {
++ a->fraction.ll = 0;
++ a->normal_exp = 0;
++ return a;
++ }
++ if (iszero (b))
++ {
++ a->class = CLASS_INFINITY;
++ return a;
++ }
++
++ /* Calculate the mantissa by multiplying both 64bit numbers to get a
++ 128 bit number */
++ {
++ /* quotient =
++ ( numerator / denominator) * 2^(numerator exponent - denominator exponent)
++ */
++
++ a->normal_exp = a->normal_exp - b->normal_exp;
++ numerator = a->fraction.ll;
++ denominator = b->fraction.ll;
++
++ if (numerator < denominator)
++ {
++ /* Fraction will be less than 1.0 */
++ numerator *= 2;
++ a->normal_exp--;
++ }
++ bit = IMPLICIT_1;
++ quotient = 0;
++ /* ??? Does divide one bit at a time. Optimize. */
++ while (bit)
++ {
++ if (numerator >= denominator)
++ {
++ quotient |= bit;
++ numerator -= denominator;
++ }
++ bit >>= 1;
++ numerator *= 2;
++ }
++
++ if (!ROUND_TOWARDS_ZERO && (quotient & GARDMASK) == GARDMSB)
++ {
++ if (quotient & (1 << NGARDS))
++ {
++ /* half way, so round to even */
++ quotient += GARDROUND + 1;
++ }
++ else if (numerator)
++ {
++ /* but we really weren't half way, more bits exist */
++ quotient += GARDROUND + 1;
++ }
++ }
++
++ a->fraction.ll = quotient;
++ return (a);
++ }
++}
++
++FLO_type
++divide (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ fp_number_type *res;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ res = _fpdiv_parts (&a, &b);
++
++ return pack_d (res);
++}
++#endif /* L_div_sf || L_div_df */
++
++#if defined(L_fpcmp_parts_sf) || defined(L_fpcmp_parts_df) \
++ || defined(L_fpcmp_parts_tf)
++/* according to the demo, fpcmp returns a comparison with 0... thus
++ a<b -> -1
++ a==b -> 0
++ a>b -> +1
++ */
++
++int
++__fpcmp_parts (fp_number_type * a, fp_number_type * b)
++{
++#if 0
++ /* either nan -> unordered. Must be checked outside of this routine. */
++ if (isnan (a) && isnan (b))
++ {
++ return 1; /* still unordered! */
++ }
++#endif
++
++ if (isnan (a) || isnan (b))
++ {
++ return 1; /* how to indicate unordered compare? */
++ }
++ if (isinf (a) && isinf (b))
++ {
++ /* +inf > -inf, but +inf != +inf */
++ /* b \a| +inf(0)| -inf(1)
++ ______\+--------+--------
++ +inf(0)| a==b(0)| a<b(-1)
++ -------+--------+--------
++ -inf(1)| a>b(1) | a==b(0)
++ -------+--------+--------
++ So since unordered must be nonzero, just line up the columns...
++ */
++ return b->sign - a->sign;
++ }
++ /* but not both... */
++ if (isinf (a))
++ {
++ return a->sign ? -1 : 1;
++ }
++ if (isinf (b))
++ {
++ return b->sign ? 1 : -1;
++ }
++ if (iszero (a) && iszero (b))
++ {
++ return 0;
++ }
++ if (iszero (a))
++ {
++ return b->sign ? 1 : -1;
++ }
++ if (iszero (b))
++ {
++ return a->sign ? -1 : 1;
++ }
++ /* now both are "normal". */
++ if (a->sign != b->sign)
++ {
++ /* opposite signs */
++ return a->sign ? -1 : 1;
++ }
++ /* same sign; exponents? */
++ if (a->normal_exp > b->normal_exp)
++ {
++ return a->sign ? -1 : 1;
++ }
++ if (a->normal_exp < b->normal_exp)
++ {
++ return a->sign ? 1 : -1;
++ }
++ /* same exponents; check size. */
++ if (a->fraction.ll > b->fraction.ll)
++ {
++ return a->sign ? -1 : 1;
++ }
++ if (a->fraction.ll < b->fraction.ll)
++ {
++ return a->sign ? 1 : -1;
++ }
++ /* after all that, they're equal. */
++ return 0;
++}
++#endif
++
++#if defined(L_compare_sf) || defined(L_compare_df) || defined(L_compoare_tf)
++CMPtype
++compare (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ return __fpcmp_parts (&a, &b);
++}
++#endif /* L_compare_sf || L_compare_df */
++
++#ifndef US_SOFTWARE_GOFAST
++
++/* These should be optimized for their specific tasks someday. */
++
++#if defined(L_eq_sf) || defined(L_eq_df) || defined(L_eq_tf)
++CMPtype
++_eq_f2 (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ if (isnan (&a) || isnan (&b))
++ return 1; /* false, truth == 0 */
++
++ return __fpcmp_parts (&a, &b) ;
++}
++#endif /* L_eq_sf || L_eq_df */
++
++#if defined(L_ne_sf) || defined(L_ne_df) || defined(L_ne_tf)
++CMPtype
++_ne_f2 (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ if (isnan (&a) || isnan (&b))
++ return 1; /* true, truth != 0 */
++
++ return __fpcmp_parts (&a, &b) ;
++}
++#endif /* L_ne_sf || L_ne_df */
++
++#if defined(L_gt_sf) || defined(L_gt_df) || defined(L_gt_tf)
++CMPtype
++_gt_f2 (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ if (isnan (&a) || isnan (&b))
++ return -1; /* false, truth > 0 */
++
++ return __fpcmp_parts (&a, &b);
++}
++#endif /* L_gt_sf || L_gt_df */
++
++#if defined(L_ge_sf) || defined(L_ge_df) || defined(L_ge_tf)
++CMPtype
++_ge_f2 (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ if (isnan (&a) || isnan (&b))
++ return -1; /* false, truth >= 0 */
++ return __fpcmp_parts (&a, &b) ;
++}
++#endif /* L_ge_sf || L_ge_df */
++
++#if defined(L_lt_sf) || defined(L_lt_df) || defined(L_lt_tf)
++CMPtype
++_lt_f2 (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ if (isnan (&a) || isnan (&b))
++ return 1; /* false, truth < 0 */
++
++ return __fpcmp_parts (&a, &b);
++}
++#endif /* L_lt_sf || L_lt_df */
++
++#if defined(L_le_sf) || defined(L_le_df) || defined(L_le_tf)
++CMPtype
++_le_f2 (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ if (isnan (&a) || isnan (&b))
++ return 1; /* false, truth <= 0 */
++
++ return __fpcmp_parts (&a, &b) ;
++}
++#endif /* L_le_sf || L_le_df */
++
++#endif /* ! US_SOFTWARE_GOFAST */
++
++#if defined(L_unord_sf) || defined(L_unord_df) || defined(L_unord_tf)
++CMPtype
++_unord_f2 (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ return (isnan (&a) || isnan (&b));
++}
++#endif /* L_unord_sf || L_unord_df */
++
++#if defined(L_si_to_sf) || defined(L_si_to_df) || defined(L_si_to_tf)
++FLO_type
++si_to_float (SItype arg_a)
++{
++ fp_number_type in;
++
++ in.class = CLASS_NUMBER;
++ in.sign = arg_a < 0;
++ if (!arg_a)
++ {
++ in.class = CLASS_ZERO;
++ }
++ else
++ {
++ in.normal_exp = FRACBITS + NGARDS;
++ if (in.sign)
++ {
++ /* Special case for minint, since there is no +ve integer
++ representation for it */
++ if (arg_a == (- MAX_SI_INT - 1))
++ {
++ return (FLO_type)(- MAX_SI_INT - 1);
++ }
++ in.fraction.ll = (-arg_a);
++ }
++ else
++ in.fraction.ll = arg_a;
++
++ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS)))
++ {
++ in.fraction.ll <<= 1;
++ in.normal_exp -= 1;
++ }
++ }
++ return pack_d (&in);
++}
++#endif /* L_si_to_sf || L_si_to_df */
++
++#if defined(L_usi_to_sf) || defined(L_usi_to_df) || defined(L_usi_to_tf)
++FLO_type
++usi_to_float (USItype arg_a)
++{
++ fp_number_type in;
++
++ in.sign = 0;
++ if (!arg_a)
++ {
++ in.class = CLASS_ZERO;
++ }
++ else
++ {
++ in.class = CLASS_NUMBER;
++ in.normal_exp = FRACBITS + NGARDS;
++ in.fraction.ll = arg_a;
++
++ while (in.fraction.ll > ((fractype)1 << (FRACBITS + NGARDS)))
++ {
++ in.fraction.ll >>= 1;
++ in.normal_exp += 1;
++ }
++ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS)))
++ {
++ in.fraction.ll <<= 1;
++ in.normal_exp -= 1;
++ }
++ }
++ return pack_d (&in);
++}
++#endif
++
++#if defined(L_sf_to_si) || defined(L_df_to_si) || defined(L_tf_to_si)
++SItype
++float_to_si (FLO_type arg_a)
++{
++ fp_number_type a;
++ SItype tmp;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &a);
++
++ if (iszero (&a))
++ return 0;
++ if (isnan (&a))
++ return 0;
++ /* get reasonable MAX_SI_INT... */
++ if (isinf (&a))
++ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT;
++ /* it is a number, but a small one */
++ if (a.normal_exp < 0)
++ return 0;
++ if (a.normal_exp > BITS_PER_SI - 2)
++ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT;
++ tmp = a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp);
++ return a.sign ? (-tmp) : (tmp);
++}
++#endif /* L_sf_to_si || L_df_to_si */
++
++#if defined(L_sf_to_usi) || defined(L_df_to_usi) || defined(L_tf_to_usi)
++#if defined US_SOFTWARE_GOFAST || defined(L_tf_to_usi)
++/* While libgcc2.c defines its own __fixunssfsi and __fixunsdfsi routines,
++ we also define them for GOFAST because the ones in libgcc2.c have the
++ wrong names and I'd rather define these here and keep GOFAST CYG-LOC's
++ out of libgcc2.c. We can't define these here if not GOFAST because then
++ there'd be duplicate copies. */
++
++USItype
++float_to_usi (FLO_type arg_a)
++{
++ fp_number_type a;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &a);
++
++ if (iszero (&a))
++ return 0;
++ if (isnan (&a))
++ return 0;
++ /* it is a negative number */
++ if (a.sign)
++ return 0;
++ /* get reasonable MAX_USI_INT... */
++ if (isinf (&a))
++ return MAX_USI_INT;
++ /* it is a number, but a small one */
++ if (a.normal_exp < 0)
++ return 0;
++ if (a.normal_exp > BITS_PER_SI - 1)
++ return MAX_USI_INT;
++ else if (a.normal_exp > (FRACBITS + NGARDS))
++ return a.fraction.ll << (a.normal_exp - (FRACBITS + NGARDS));
++ else
++ return a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp);
++}
++#endif /* US_SOFTWARE_GOFAST */
++#endif /* L_sf_to_usi || L_df_to_usi */
++
++#if defined(L_negate_sf) || defined(L_negate_df) || defined(L_negate_tf)
++FLO_type
++negate (FLO_type arg_a)
++{
++ fp_number_type a;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &a);
++
++ flip_sign (&a);
++ return pack_d (&a);
++}
++#endif /* L_negate_sf || L_negate_df */
++
++#ifdef FLOAT
++
++#if defined(L_make_sf)
++SFtype
++__make_fp(fp_class_type class,
++ unsigned int sign,
++ int exp,
++ USItype frac)
++{
++ fp_number_type in;
++
++ in.class = class;
++ in.sign = sign;
++ in.normal_exp = exp;
++ in.fraction.ll = frac;
++ return pack_d (&in);
++}
++#endif /* L_make_sf */
++
++#ifndef FLOAT_ONLY
++
++/* This enables one to build an fp library that supports float but not double.
++ Otherwise, we would get an undefined reference to __make_dp.
++ This is needed for some 8-bit ports that can't handle well values that
++ are 8-bytes in size, so we just don't support double for them at all. */
++
++#if defined(L_sf_to_df)
++DFtype
++sf_to_df (SFtype arg_a)
++{
++ fp_number_type in;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &in);
++
++ return __make_dp (in.class, in.sign, in.normal_exp,
++ ((UDItype) in.fraction.ll) << F_D_BITOFF);
++}
++#endif /* L_sf_to_df */
++
++#if defined(L_sf_to_tf) && defined(TMODES)
++TFtype
++sf_to_tf (SFtype arg_a)
++{
++ fp_number_type in;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &in);
++
++ return __make_tp (in.class, in.sign, in.normal_exp,
++ ((UTItype) in.fraction.ll) << F_T_BITOFF);
++}
++#endif /* L_sf_to_df */
++
++#endif /* ! FLOAT_ONLY */
++#endif /* FLOAT */
++
++#ifndef FLOAT
++
++extern SFtype __make_fp (fp_class_type, unsigned int, int, USItype);
++
++#if defined(L_make_df)
++DFtype
++__make_dp (fp_class_type class, unsigned int sign, int exp, UDItype frac)
++{
++ fp_number_type in;
++
++ in.class = class;
++ in.sign = sign;
++ in.normal_exp = exp;
++ in.fraction.ll = frac;
++ return pack_d (&in);
++}
++#endif /* L_make_df */
++
++#if defined(L_df_to_sf)
++SFtype
++df_to_sf (DFtype arg_a)
++{
++ fp_number_type in;
++ USItype sffrac;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &in);
++
++ sffrac = in.fraction.ll >> F_D_BITOFF;
++
++ /* We set the lowest guard bit in SFFRAC if we discarded any non
++ zero bits. */
++ if ((in.fraction.ll & (((USItype) 1 << F_D_BITOFF) - 1)) != 0)
++ sffrac |= 1;
++
++ return __make_fp (in.class, in.sign, in.normal_exp, sffrac);
++}
++#endif /* L_df_to_sf */
++
++#if defined(L_df_to_tf) && defined(TMODES) \
++ && !defined(FLOAT) && !defined(TFLOAT)
++TFtype
++df_to_tf (DFtype arg_a)
++{
++ fp_number_type in;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &in);
++
++ return __make_tp (in.class, in.sign, in.normal_exp,
++ ((UTItype) in.fraction.ll) << D_T_BITOFF);
++}
++#endif /* L_sf_to_df */
++
++#ifdef TFLOAT
++#if defined(L_make_tf)
++TFtype
++__make_tp(fp_class_type class,
++ unsigned int sign,
++ int exp,
++ UTItype frac)
++{
++ fp_number_type in;
++
++ in.class = class;
++ in.sign = sign;
++ in.normal_exp = exp;
++ in.fraction.ll = frac;
++ return pack_d (&in);
++}
++#endif /* L_make_tf */
++
++#if defined(L_tf_to_df)
++DFtype
++tf_to_df (TFtype arg_a)
++{
++ fp_number_type in;
++ UDItype sffrac;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &in);
++
++ sffrac = in.fraction.ll >> D_T_BITOFF;
++
++ /* We set the lowest guard bit in SFFRAC if we discarded any non
++ zero bits. */
++ if ((in.fraction.ll & (((UTItype) 1 << D_T_BITOFF) - 1)) != 0)
++ sffrac |= 1;
++
++ return __make_dp (in.class, in.sign, in.normal_exp, sffrac);
++}
++#endif /* L_tf_to_df */
++
++#if defined(L_tf_to_sf)
++SFtype
++tf_to_sf (TFtype arg_a)
++{
++ fp_number_type in;
++ USItype sffrac;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &in);
++
++ sffrac = in.fraction.ll >> F_T_BITOFF;
++
++ /* We set the lowest guard bit in SFFRAC if we discarded any non
++ zero bits. */
++ if ((in.fraction.ll & (((UTItype) 1 << F_T_BITOFF) - 1)) != 0)
++ sffrac |= 1;
++
++ return __make_fp (in.class, in.sign, in.normal_exp, sffrac);
++}
++#endif /* L_tf_to_sf */
++#endif /* TFLOAT */
++
++#endif /* ! FLOAT */
++#endif /* !EXTENDED_FLOAT_STUBS */
+--- gcc-3.4.3/gcc/config/nios2/nios2-protos.h
++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2-protos.h
+@@ -0,0 +1,70 @@
++/* 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);
++
++
++#ifdef RTX_CODE
++extern int nios2_legitimate_address (rtx, enum machine_mode, int);
++extern void nios2_print_operand (FILE *, rtx, int);
++extern void nios2_print_operand_address (FILE *, rtx);
++
++extern int nios2_emit_move_sequence (rtx *, enum machine_mode);
++extern int nios2_emit_expensive_div (rtx *, enum machine_mode);
++
++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 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);
++
++# ifdef HAVE_MACHINE_MODES
++# if defined TREE_CODE
++extern void function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode, tree, int);
++extern rtx function_arg (const CUMULATIVE_ARGS *, enum machine_mode, tree, int);
++extern int function_arg_partial_nregs (const CUMULATIVE_ARGS *, enum machine_mode, tree, int);
++extern void init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree, int);
++extern int nios2_setup_incoming_varargs (const CUMULATIVE_ARGS *, enum machine_mode, tree, int);
++
++# endif /* TREE_CODE */
++# endif /* HAVE_MACHINE_MODES */
++#endif
++
++#ifdef TREE_CODE
++extern int nios2_return_in_memory (tree);
++
++#endif /* TREE_CODE */
+--- gcc-3.4.3/gcc/config/nios2/nios2.c
++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2.c
+@@ -0,0 +1,2853 @@
++/* 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. */
++
++
++#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 "ggc.h"
++#include "reload.h"
++#include "debug.h"
++#include "optabs.h"
++#include "target.h"
++#include "target-def.h"
++
++/* local prototypes */
++static bool nios2_rtx_costs (rtx, int, int, int *);
++
++static void nios2_asm_function_prologue (FILE *, HOST_WIDE_INT);
++static int nios2_use_dfa_pipeline_interface (void);
++static int nios2_issue_rate (void);
++static struct machine_function *nios2_init_machine_status (void);
++static bool nios2_in_small_data_p (tree);
++static rtx save_reg (int, HOST_WIDE_INT, rtx);
++static rtx restore_reg (int, HOST_WIDE_INT);
++static unsigned int nios2_section_type_flags (tree, const char *, int);
++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 void nios2_encode_section_info (tree, rtx, int);
++
++/* Initialize the GCC target structure. */
++#undef TARGET_ASM_FUNCTION_PROLOGUE
++#define TARGET_ASM_FUNCTION_PROLOGUE nios2_asm_function_prologue
++
++#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE
++#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE \
++ nios2_use_dfa_pipeline_interface
++#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_RTX_COSTS
++#define TARGET_RTX_COSTS nios2_rtx_costs
++
++
++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 (())
++{
++ 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 */
++ int save_reg_rounded; /* # 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 */
++ int num_regs; /* number of gp registers saved */
++};
++
++struct machine_function
++GTY (())
++{
++
++ /* Current frame information, calculated by compute_frame_size. */
++ struct nios2_frame_info frame;
++};
++
++
++/***************************************
++ * Section encodings
++ ***************************************/
++
++
++
++
++
++/***************************************
++ * 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 rtx
++save_reg (int regno, HOST_WIDE_INT offset, rtx cfa_store_reg)
++{
++ rtx insn, stack_slot;
++
++ stack_slot = gen_rtx_PLUS (SImode,
++ cfa_store_reg,
++ GEN_INT (offset));
++
++ insn = emit_insn (gen_rtx_SET (SImode,
++ gen_rtx_MEM (SImode, stack_slot),
++ gen_rtx_REG (SImode, regno)));
++
++ RTX_FRAME_RELATED_P (insn) = 1;
++
++ return insn;
++}
++
++static rtx
++restore_reg (int regno, HOST_WIDE_INT offset)
++{
++ rtx insn, stack_slot;
++
++ if (TOO_BIG_OFFSET (offset))
++ {
++ stack_slot = gen_rtx_REG (SImode, TEMP_REG_NUM);
++ insn = emit_insn (gen_rtx_SET (SImode,
++ stack_slot,
++ GEN_INT (offset)));
++
++ insn = emit_insn (gen_rtx_SET (SImode,
++ stack_slot,
++ gen_rtx_PLUS (SImode,
++ stack_slot,
++ stack_pointer_rtx)));
++ }
++ else
++ {
++ stack_slot = gen_rtx_PLUS (SImode,
++ stack_pointer_rtx,
++ GEN_INT (offset));
++ }
++
++ stack_slot = gen_rtx_MEM (SImode, stack_slot);
++
++ insn = emit_move_insn (gen_rtx_REG (SImode, regno), stack_slot);
++
++ return insn;
++}
++
++
++/* There are two possible paths for prologue expansion,
++- the first is if the total frame size is < 2^15-1. In that
++case all the immediates will fit into the 16-bit immediate
++fields.
++- the second is when the frame size is too big, in that
++case an additional temporary register is used, first
++as a cfa_temp to offset the sp, second as the cfa_store
++register.
++
++See the comment above dwarf2out_frame_debug_expr in
++dwarf2out.c for more explanation of the "rules."
++
++
++Case 1:
++Rule # Example Insn Effect
++2 addi sp, sp, -total_frame_size cfa.reg=sp, cfa.offset=total_frame_size
++ cfa_store.reg=sp, cfa_store.offset=total_frame_size
++12 stw ra, offset(sp)
++12 stw r16, offset(sp)
++1 mov fp, sp
++
++Case 2:
++Rule # Example Insn Effect
++6 movi r8, total_frame_size cfa_temp.reg=r8, cfa_temp.offset=total_frame_size
++2 sub sp, sp, r8 cfa.reg=sp, cfa.offset=total_frame_size
++ cfa_store.reg=sp, cfa_store.offset=total_frame_size
++5 add r8, r8, sp cfa_store.reg=r8, cfa_store.offset=0
++12 stw ra, offset(r8)
++12 stw r16, offset(r8)
++1 mov fp, sp
++
++*/
++
++void
++expand_prologue ()
++{
++ int i;
++ HOST_WIDE_INT total_frame_size;
++ int cfa_store_offset;
++ rtx insn;
++ rtx cfa_store_reg = 0;
++
++ total_frame_size = compute_frame_size ();
++
++ if (total_frame_size)
++ {
++
++ if (TOO_BIG_OFFSET (total_frame_size))
++ {
++ /* cfa_temp and cfa_store_reg are the same register,
++ cfa_store_reg overwrites cfa_temp */
++ cfa_store_reg = gen_rtx_REG (SImode, TEMP_REG_NUM);
++ insn = emit_insn (gen_rtx_SET (SImode,
++ cfa_store_reg,
++ GEN_INT (total_frame_size)));
++
++ RTX_FRAME_RELATED_P (insn) = 1;
++
++
++ insn = gen_rtx_SET (SImode,
++ stack_pointer_rtx,
++ gen_rtx_MINUS (SImode,
++ stack_pointer_rtx,
++ cfa_store_reg));
++
++ insn = emit_insn (insn);
++ RTX_FRAME_RELATED_P (insn) = 1;
++
++
++ /* if there are no registers to save, I don't need to
++ create a cfa_store */
++ if (cfun->machine->frame.save_reg_size)
++ {
++ insn = gen_rtx_SET (SImode,
++ cfa_store_reg,
++ gen_rtx_PLUS (SImode,
++ cfa_store_reg,
++ stack_pointer_rtx));
++
++ insn = emit_insn (insn);
++ RTX_FRAME_RELATED_P (insn) = 1;
++ }
++
++ cfa_store_offset
++ = total_frame_size
++ - (cfun->machine->frame.save_regs_offset
++ + cfun->machine->frame.save_reg_rounded);
++ }
++ else
++ {
++ insn = gen_rtx_SET (SImode,
++ stack_pointer_rtx,
++ gen_rtx_PLUS (SImode,
++ stack_pointer_rtx,
++ GEN_INT (-total_frame_size)));
++ insn = emit_insn (insn);
++ RTX_FRAME_RELATED_P (insn) = 1;
++
++ cfa_store_reg = stack_pointer_rtx;
++ cfa_store_offset
++ = cfun->machine->frame.save_regs_offset
++ + cfun->machine->frame.save_reg_rounded;
++ }
++ }
++
++ if (MUST_SAVE_REGISTER (RA_REGNO))
++ {
++ cfa_store_offset -= 4;
++ save_reg (RA_REGNO, cfa_store_offset, cfa_store_reg);
++ }
++ if (MUST_SAVE_REGISTER (FP_REGNO))
++ {
++ cfa_store_offset -= 4;
++ save_reg (FP_REGNO, cfa_store_offset, cfa_store_reg);
++ }
++
++ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
++ {
++ if (MUST_SAVE_REGISTER (i) && i != FP_REGNO && i != RA_REGNO)
++ {
++ cfa_store_offset -= 4;
++ save_reg (i, cfa_store_offset, cfa_store_reg);
++ }
++ }
++
++ if (frame_pointer_needed)
++ {
++ insn = emit_insn (gen_rtx_SET (SImode,
++ gen_rtx_REG (SImode, FP_REGNO),
++ gen_rtx_REG (SImode, SP_REGNO)));
++
++ RTX_FRAME_RELATED_P (insn) = 1;
++ }
++
++ /* 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 i;
++ HOST_WIDE_INT total_frame_size;
++ int register_store_offset;
++
++ total_frame_size = compute_frame_size ();
++
++ if (!sibcall_p && nios2_can_use_return_insn ())
++ {
++ insn = emit_jump_insn (gen_return ());
++ return;
++ }
++
++ emit_insn (gen_blockage ());
++
++ register_store_offset =
++ cfun->machine->frame.save_regs_offset +
++ cfun->machine->frame.save_reg_rounded;
++
++ if (MUST_SAVE_REGISTER (RA_REGNO))
++ {
++ register_store_offset -= 4;
++ restore_reg (RA_REGNO, register_store_offset);
++ }
++
++ if (MUST_SAVE_REGISTER (FP_REGNO))
++ {
++ register_store_offset -= 4;
++ restore_reg (FP_REGNO, register_store_offset);
++ }
++
++ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
++ {
++ if (MUST_SAVE_REGISTER (i) && i != FP_REGNO && i != RA_REGNO)
++ {
++ register_store_offset -= 4;
++ restore_reg (i, register_store_offset);
++ }
++ }
++
++ if (total_frame_size)
++ {
++ rtx sp_adjust;
++
++ if (TOO_BIG_OFFSET (total_frame_size))
++ {
++ sp_adjust = gen_rtx_REG (SImode, TEMP_REG_NUM);
++ insn = emit_insn (gen_rtx_SET (SImode,
++ sp_adjust,
++ GEN_INT (total_frame_size)));
++
++ }
++ else
++ {
++ sp_adjust = GEN_INT (total_frame_size);
++ }
++
++ insn = gen_rtx_SET (SImode,
++ stack_pointer_rtx,
++ gen_rtx_PLUS (SImode,
++ stack_pointer_rtx,
++ sp_adjust));
++ insn = emit_insn (insn);
++ }
++
++
++ if (!sibcall_p)
++ {
++ insn = emit_jump_insn (gen_return_from_epilogue (gen_rtx (REG, Pmode,
++ RA_REGNO)));
++ }
++}
++
++
++bool
++nios2_function_ok_for_sibcall (tree a ATTRIBUTE_UNUSED, tree b ATTRIBUTE_UNUSED)
++{
++ return true;
++}
++
++
++
++
++
++/* ----------------------- *
++ * Profiling
++ * ----------------------- */
++
++void
++function_profiler (FILE *file, int labelno)
++{
++ fprintf (file, "\t%s mcount begin, label: .LP%d\n",
++ ASM_COMMENT_START, labelno);
++ fprintf (file, "\tnextpc\tr8\n");
++ fprintf (file, "\tmov\tr9, ra\n");
++ fprintf (file, "\tmovhi\tr10, %%hiadj(.LP%d)\n", labelno);
++ fprintf (file, "\taddi\tr10, r10, %%lo(.LP%d)\n", labelno);
++ fprintf (file, "\tcall\tmcount\n");
++ fprintf (file, "\tmov\tra, r9\n");
++ fprintf (file, "\t%s mcount end\n", ASM_COMMENT_START);
++}
++
++
++/***************************************
++ * 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 save_reg_rounded = %d\n", ASM_COMMENT_START,
++ cfun->machine->frame.save_reg_rounded);
++ fprintf (file, "\t%s initialized = %d\n", ASM_COMMENT_START,
++ cfun->machine->frame.initialized);
++ fprintf (file, "\t%s num_regs = %d\n", ASM_COMMENT_START,
++ cfun->machine->frame.num_regs);
++ 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 the bytes needed to compute the frame pointer from the current
++ stack pointer.
++*/
++
++HOST_WIDE_INT
++compute_frame_size ()
++{
++ 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 save_reg_rounded;
++ /* # bytes needed to store callee save regs (rounded) */
++ HOST_WIDE_INT out_args_size; /* # bytes needed for outgoing args */
++
++ 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; regno <= FIRST_PSEUDO_REGISTER; regno++)
++ {
++ if (MUST_SAVE_REGISTER (regno))
++ {
++ save_reg_size += 4;
++ }
++ }
++
++ save_reg_rounded = STACK_ALIGN (save_reg_size);
++ total_size += save_reg_rounded;
++
++ total_size += STACK_ALIGN (current_function_pretend_args_size);
++
++ /* Save other computed information. */
++ cfun->machine->frame.total_size = total_size;
++ cfun->machine->frame.var_size = var_size;
++ cfun->machine->frame.args_size = current_function_outgoing_args_size;
++ cfun->machine->frame.save_reg_size = save_reg_size;
++ cfun->machine->frame.save_reg_rounded = save_reg_rounded;
++ cfun->machine->frame.initialized = reload_completed;
++ cfun->machine->frame.num_regs = save_reg_size / UNITS_PER_WORD;
++
++ cfun->machine->frame.save_regs_offset
++ = save_reg_rounded ? current_function_outgoing_args_size + var_size : 0;
++
++ return total_size;
++}
++
++
++int
++nios2_initial_elimination_offset (int from, int to ATTRIBUTE_UNUSED)
++{
++ int offset;
++
++ /* Set OFFSET to the offset from the stack pointer. */
++ switch (from)
++ {
++ case FRAME_POINTER_REGNUM:
++ offset = 0;
++ break;
++
++ case ARG_POINTER_REGNUM:
++ compute_frame_size ();
++ offset = cfun->machine->frame.total_size;
++ offset -= current_function_pretend_args_size;
++ break;
++
++ case RETURN_ADDRESS_POINTER_REGNUM:
++ compute_frame_size ();
++ /* since the return address is always the first of the
++ saved registers, return the offset to the beginning
++ of the saved registers block */
++ offset = cfun->machine->frame.save_regs_offset;
++ break;
++
++ default:
++ abort ();
++ }
++
++ 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 ()
++{
++ 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;
++}
++
++
++
++
++
++/***************************************
++ *
++ ***************************************/
++
++const char *nios2_sys_nosys_string; /* for -msys=nosys */
++const char *nios2_sys_lib_string; /* for -msys-lib= */
++const char *nios2_sys_crt0_string; /* for -msys-crt0= */
++
++void
++override_options ()
++{
++ /* 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 (nios2_sys_nosys_string && *nios2_sys_nosys_string)
++ {
++ error ("invalid option '-msys=nosys%s'", nios2_sys_nosys_string);
++ }
++
++ /* If we don't have mul, we don't have mulx either! */
++ if (!TARGET_HAS_MUL && TARGET_HAS_MULX)
++ {
++ target_flags &= ~HAS_MULX_FLAG;
++ }
++
++}
++
++void
++optimization_options (int level, int size)
++{
++ if (level || size)
++ {
++ target_flags |= INLINE_MEMCPY_FLAG;
++ }
++
++ if (level >= 3 && !size)
++ {
++ target_flags |= FAST_SW_DIV_FLAG;
++ }
++}
++
++/* Allocate a chunk of memory for per-function machine-dependent data. */
++static struct machine_function *
++nios2_init_machine_status ()
++{
++ 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.
++ ***************************************/
++
++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);
++ }
++
++ 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 */
++ if (mode != SImode)
++ abort ();
++
++ 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;
++}
++
++/* 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;
++}
++
++/* 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);
++ if (test == ITEST_MAX)
++ abort ();
++
++ p_info = &info[(int) test];
++
++ mode = GET_MODE (cmp0);
++ if (mode == VOIDmode)
++ mode = GET_MODE (cmp1);
++
++ branch_p = (destination != 0);
++
++ /* 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. */
++ if ((p_info->unsignedp
++ ? (unsigned HOST_WIDE_INT) new >
++ (unsigned HOST_WIDE_INT) INTVAL (cmp1)
++ : new > INTVAL (cmp1)) != (p_info->const_add > 0))
++ {
++ /* ??? This case can never happen with the current numbers,
++ but I am paranoid and would rather an abort than
++ a bug I will never find */
++ abort ();
++ }
++ else
++ 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 (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 (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 (p_info->test_code_reg, mode, cmp0, cmp1));
++ }
++ else
++ {
++ emit_move_insn (result,
++ gen_rtx (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 (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_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_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) && CONSTANT_P (op1))
++ ret_val = REG_OK_FOR_BASE_P2 (op0, strict)
++ && SMALL_INT (INTVAL (op1));
++ else if (REG_P (op1) && CONSTANT_P (op0))
++ 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 && 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);
++
++ /* ??? these string names need moving into an array in some header file */
++ if (strcmp (name, ".sbss") == 0
++ || strncmp (name, ".sbss.", 6) == 0
++ || strcmp (name, ".sdata") == 0
++ || strncmp (name, ".sdata.", 7) == 0)
++ flags |= SECTION_SMALL;
++
++ return flags;
++}
++
++
++
++
++/*****************************************
++ * 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
++ */
++
++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
++ && ((MEM_VOLATILE_P (op) && !TARGET_CACHE_VOLATILE)
++ || 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;
++ }
++
++ 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;
++ }
++
++
++ case SUBREG:
++ case MEM:
++ if (letter == 0)
++ {
++ output_address (op);
++ return;
++ }
++
++ case CODE_LABEL:
++ if (letter == 0)
++ {
++ output_addr_const (file, op);
++ return;
++ }
++
++ default:
++ break;
++ }
++
++ fprintf (stderr, "Missing way to print (%c) ", letter);
++ debug_rtx (op);
++ abort ();
++}
++
++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);
++ abort ();
++}
++
++
++
++
++
++/****************************
++ * Predicates
++ ****************************/
++
++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));
++}
++
++
++
++
++
++
++
++/*****************************************************************************
++**
++** instruction scheduler
++**
++*****************************************************************************/
++static int
++nios2_use_dfa_pipeline_interface ()
++{
++ return 1;
++}
++
++
++static int
++nios2_issue_rate ()
++{
++#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;
++}
++
++
++/* 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;
++}
++
++/* 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;
++}
++
++int
++function_arg_partial_nregs (const CUMULATIVE_ARGS *cum,
++ enum machine_mode mode, tree type,
++ 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 < NUM_ARG_REGS
++ && cum->regs_used + param_size > NUM_ARG_REGS)
++ {
++ return NUM_ARG_REGS - cum->regs_used;
++ }
++ else
++ {
++ return 0;
++ }
++}
++
++
++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. */
++int
++nios2_setup_incoming_varargs (const CUMULATIVE_ARGS *cum,
++ enum machine_mode mode, tree type,
++ int no_rtl)
++{
++ CUMULATIVE_ARGS local_cum;
++ int regs_to_push;
++
++ local_cum = *cum;
++ FUNCTION_ARG_ADVANCE (local_cum, mode, type, 1);
++
++ regs_to_push = NUM_ARG_REGS - local_cum.regs_used;
++
++ if (!no_rtl)
++ {
++ 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 ());
++ }
++ }
++
++ return regs_to_push * UNITS_PER_WORD;
++
++}
++
++
++
++/*****************************************************************************
++**
++** 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,
++
++ NIOS2_BUILTIN_CUSTOM_N,
++ NIOS2_BUILTIN_CUSTOM_NI,
++ NIOS2_BUILTIN_CUSTOM_NF,
++ NIOS2_BUILTIN_CUSTOM_NP,
++ NIOS2_BUILTIN_CUSTOM_NII,
++ NIOS2_BUILTIN_CUSTOM_NIF,
++ NIOS2_BUILTIN_CUSTOM_NIP,
++ NIOS2_BUILTIN_CUSTOM_NFI,
++ NIOS2_BUILTIN_CUSTOM_NFF,
++ NIOS2_BUILTIN_CUSTOM_NFP,
++ NIOS2_BUILTIN_CUSTOM_NPI,
++ NIOS2_BUILTIN_CUSTOM_NPF,
++ NIOS2_BUILTIN_CUSTOM_NPP,
++ NIOS2_BUILTIN_CUSTOM_IN,
++ NIOS2_BUILTIN_CUSTOM_INI,
++ NIOS2_BUILTIN_CUSTOM_INF,
++ NIOS2_BUILTIN_CUSTOM_INP,
++ NIOS2_BUILTIN_CUSTOM_INII,
++ NIOS2_BUILTIN_CUSTOM_INIF,
++ NIOS2_BUILTIN_CUSTOM_INIP,
++ NIOS2_BUILTIN_CUSTOM_INFI,
++ NIOS2_BUILTIN_CUSTOM_INFF,
++ NIOS2_BUILTIN_CUSTOM_INFP,
++ NIOS2_BUILTIN_CUSTOM_INPI,
++ NIOS2_BUILTIN_CUSTOM_INPF,
++ NIOS2_BUILTIN_CUSTOM_INPP,
++ NIOS2_BUILTIN_CUSTOM_FN,
++ NIOS2_BUILTIN_CUSTOM_FNI,
++ NIOS2_BUILTIN_CUSTOM_FNF,
++ NIOS2_BUILTIN_CUSTOM_FNP,
++ NIOS2_BUILTIN_CUSTOM_FNII,
++ NIOS2_BUILTIN_CUSTOM_FNIF,
++ NIOS2_BUILTIN_CUSTOM_FNIP,
++ NIOS2_BUILTIN_CUSTOM_FNFI,
++ NIOS2_BUILTIN_CUSTOM_FNFF,
++ NIOS2_BUILTIN_CUSTOM_FNFP,
++ NIOS2_BUILTIN_CUSTOM_FNPI,
++ NIOS2_BUILTIN_CUSTOM_FNPF,
++ NIOS2_BUILTIN_CUSTOM_FNPP,
++ NIOS2_BUILTIN_CUSTOM_PN,
++ NIOS2_BUILTIN_CUSTOM_PNI,
++ NIOS2_BUILTIN_CUSTOM_PNF,
++ NIOS2_BUILTIN_CUSTOM_PNP,
++ NIOS2_BUILTIN_CUSTOM_PNII,
++ NIOS2_BUILTIN_CUSTOM_PNIF,
++ NIOS2_BUILTIN_CUSTOM_PNIP,
++ NIOS2_BUILTIN_CUSTOM_PNFI,
++ NIOS2_BUILTIN_CUSTOM_PNFF,
++ NIOS2_BUILTIN_CUSTOM_PNFP,
++ NIOS2_BUILTIN_CUSTOM_PNPI,
++ NIOS2_BUILTIN_CUSTOM_PNPF,
++ NIOS2_BUILTIN_CUSTOM_PNPP,
++
++
++ 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) PARAMS ((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 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;
++
++static tree custom_n;
++static tree custom_ni;
++static tree custom_nf;
++static tree custom_np;
++static tree custom_nii;
++static tree custom_nif;
++static tree custom_nip;
++static tree custom_nfi;
++static tree custom_nff;
++static tree custom_nfp;
++static tree custom_npi;
++static tree custom_npf;
++static tree custom_npp;
++static tree custom_in;
++static tree custom_ini;
++static tree custom_inf;
++static tree custom_inp;
++static tree custom_inii;
++static tree custom_inif;
++static tree custom_inip;
++static tree custom_infi;
++static tree custom_inff;
++static tree custom_infp;
++static tree custom_inpi;
++static tree custom_inpf;
++static tree custom_inpp;
++static tree custom_fn;
++static tree custom_fni;
++static tree custom_fnf;
++static tree custom_fnp;
++static tree custom_fnii;
++static tree custom_fnif;
++static tree custom_fnip;
++static tree custom_fnfi;
++static tree custom_fnff;
++static tree custom_fnfp;
++static tree custom_fnpi;
++static tree custom_fnpf;
++static tree custom_fnpp;
++static tree custom_pn;
++static tree custom_pni;
++static tree custom_pnf;
++static tree custom_pnp;
++static tree custom_pnii;
++static tree custom_pnif;
++static tree custom_pnip;
++static tree custom_pnfi;
++static tree custom_pnff;
++static tree custom_pnfp;
++static tree custom_pnpi;
++static tree custom_pnpf;
++static tree custom_pnpp;
++
++
++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},
++
++ {CODE_FOR_custom_n, "__builtin_custom_n", NIOS2_BUILTIN_CUSTOM_N, &custom_n, nios2_expand_custom_n},
++ {CODE_FOR_custom_ni, "__builtin_custom_ni", NIOS2_BUILTIN_CUSTOM_NI, &custom_ni, nios2_expand_custom_nX},
++ {CODE_FOR_custom_nf, "__builtin_custom_nf", NIOS2_BUILTIN_CUSTOM_NF, &custom_nf, nios2_expand_custom_nX},
++ {CODE_FOR_custom_np, "__builtin_custom_np", NIOS2_BUILTIN_CUSTOM_NP, &custom_np, nios2_expand_custom_nX},
++ {CODE_FOR_custom_nii, "__builtin_custom_nii", NIOS2_BUILTIN_CUSTOM_NII, &custom_nii, nios2_expand_custom_nXX},
++ {CODE_FOR_custom_nif, "__builtin_custom_nif", NIOS2_BUILTIN_CUSTOM_NIF, &custom_nif, nios2_expand_custom_nXX},
++ {CODE_FOR_custom_nip, "__builtin_custom_nip", NIOS2_BUILTIN_CUSTOM_NIP, &custom_nip, nios2_expand_custom_nXX},
++ {CODE_FOR_custom_nfi, "__builtin_custom_nfi", NIOS2_BUILTIN_CUSTOM_NFI, &custom_nfi, nios2_expand_custom_nXX},
++ {CODE_FOR_custom_nff, "__builtin_custom_nff", NIOS2_BUILTIN_CUSTOM_NFF, &custom_nff, nios2_expand_custom_nXX},
++ {CODE_FOR_custom_nfp, "__builtin_custom_nfp", NIOS2_BUILTIN_CUSTOM_NFP, &custom_nfp, nios2_expand_custom_nXX},
++ {CODE_FOR_custom_npi, "__builtin_custom_npi", NIOS2_BUILTIN_CUSTOM_NPI, &custom_npi, nios2_expand_custom_nXX},
++ {CODE_FOR_custom_npf, "__builtin_custom_npf", NIOS2_BUILTIN_CUSTOM_NPF, &custom_npf, nios2_expand_custom_nXX},
++ {CODE_FOR_custom_npp, "__builtin_custom_npp", NIOS2_BUILTIN_CUSTOM_NPP, &custom_npp, nios2_expand_custom_nXX},
++ {CODE_FOR_custom_in, "__builtin_custom_in", NIOS2_BUILTIN_CUSTOM_IN, &custom_in, nios2_expand_custom_Xn},
++ {CODE_FOR_custom_ini, "__builtin_custom_ini", NIOS2_BUILTIN_CUSTOM_INI, &custom_ini, nios2_expand_custom_XnX},
++ {CODE_FOR_custom_inf, "__builtin_custom_inf", NIOS2_BUILTIN_CUSTOM_INF, &custom_inf, nios2_expand_custom_XnX},
++ {CODE_FOR_custom_inp, "__builtin_custom_inp", NIOS2_BUILTIN_CUSTOM_INP, &custom_inp, nios2_expand_custom_XnX},
++ {CODE_FOR_custom_inii, "__builtin_custom_inii", NIOS2_BUILTIN_CUSTOM_INII, &custom_inii, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_inif, "__builtin_custom_inif", NIOS2_BUILTIN_CUSTOM_INIF, &custom_inif, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_inip, "__builtin_custom_inip", NIOS2_BUILTIN_CUSTOM_INIP, &custom_inip, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_infi, "__builtin_custom_infi", NIOS2_BUILTIN_CUSTOM_INFI, &custom_infi, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_inff, "__builtin_custom_inff", NIOS2_BUILTIN_CUSTOM_INFF, &custom_inff, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_infp, "__builtin_custom_infp", NIOS2_BUILTIN_CUSTOM_INFP, &custom_infp, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_inpi, "__builtin_custom_inpi", NIOS2_BUILTIN_CUSTOM_INPI, &custom_inpi, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_inpf, "__builtin_custom_inpf", NIOS2_BUILTIN_CUSTOM_INPF, &custom_inpf, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_inpp, "__builtin_custom_inpp", NIOS2_BUILTIN_CUSTOM_INPP, &custom_inpp, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_fn, "__builtin_custom_fn", NIOS2_BUILTIN_CUSTOM_FN, &custom_fn, nios2_expand_custom_Xn},
++ {CODE_FOR_custom_fni, "__builtin_custom_fni", NIOS2_BUILTIN_CUSTOM_FNI, &custom_fni, nios2_expand_custom_XnX},
++ {CODE_FOR_custom_fnf, "__builtin_custom_fnf", NIOS2_BUILTIN_CUSTOM_FNF, &custom_fnf, nios2_expand_custom_XnX},
++ {CODE_FOR_custom_fnp, "__builtin_custom_fnp", NIOS2_BUILTIN_CUSTOM_FNP, &custom_fnp, nios2_expand_custom_XnX},
++ {CODE_FOR_custom_fnii, "__builtin_custom_fnii", NIOS2_BUILTIN_CUSTOM_FNII, &custom_fnii, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_fnif, "__builtin_custom_fnif", NIOS2_BUILTIN_CUSTOM_FNIF, &custom_fnif, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_fnip, "__builtin_custom_fnip", NIOS2_BUILTIN_CUSTOM_FNIP, &custom_fnip, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_fnfi, "__builtin_custom_fnfi", NIOS2_BUILTIN_CUSTOM_FNFI, &custom_fnfi, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_fnff, "__builtin_custom_fnff", NIOS2_BUILTIN_CUSTOM_FNFF, &custom_fnff, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_fnfp, "__builtin_custom_fnfp", NIOS2_BUILTIN_CUSTOM_FNFP, &custom_fnfp, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_fnpi, "__builtin_custom_fnpi", NIOS2_BUILTIN_CUSTOM_FNPI, &custom_fnpi, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_fnpf, "__builtin_custom_fnpf", NIOS2_BUILTIN_CUSTOM_FNPF, &custom_fnpf, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_fnpp, "__builtin_custom_fnpp", NIOS2_BUILTIN_CUSTOM_FNPP, &custom_fnpp, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_pn, "__builtin_custom_pn", NIOS2_BUILTIN_CUSTOM_PN, &custom_pn, nios2_expand_custom_Xn},
++ {CODE_FOR_custom_pni, "__builtin_custom_pni", NIOS2_BUILTIN_CUSTOM_PNI, &custom_pni, nios2_expand_custom_XnX},
++ {CODE_FOR_custom_pnf, "__builtin_custom_pnf", NIOS2_BUILTIN_CUSTOM_PNF, &custom_pnf, nios2_expand_custom_XnX},
++ {CODE_FOR_custom_pnp, "__builtin_custom_pnp", NIOS2_BUILTIN_CUSTOM_PNP, &custom_pnp, nios2_expand_custom_XnX},
++ {CODE_FOR_custom_pnii, "__builtin_custom_pnii", NIOS2_BUILTIN_CUSTOM_PNII, &custom_pnii, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_pnif, "__builtin_custom_pnif", NIOS2_BUILTIN_CUSTOM_PNIF, &custom_pnif, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_pnip, "__builtin_custom_pnip", NIOS2_BUILTIN_CUSTOM_PNIP, &custom_pnip, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_pnfi, "__builtin_custom_pnfi", NIOS2_BUILTIN_CUSTOM_PNFI, &custom_pnfi, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_pnff, "__builtin_custom_pnff", NIOS2_BUILTIN_CUSTOM_PNFF, &custom_pnff, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_pnfp, "__builtin_custom_pnfp", NIOS2_BUILTIN_CUSTOM_PNFP, &custom_pnfp, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_pnpi, "__builtin_custom_pnpi", NIOS2_BUILTIN_CUSTOM_PNPI, &custom_pnpi, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_pnpf, "__builtin_custom_pnpf", NIOS2_BUILTIN_CUSTOM_PNPF, &custom_pnpf, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_pnpp, "__builtin_custom_pnpp", NIOS2_BUILTIN_CUSTOM_PNPP, &custom_pnpp, nios2_expand_custom_XnXX},
++
++
++ {0, 0, 0, 0, 0},
++};
++
++/* This does not have a closing bracket on purpose (see use) */
++#define def_param(TYPE) \
++ tree_cons (NULL_TREE, TYPE,
++
++static void
++nios2_init_builtins ()
++{
++ const struct builtin_description *d;
++
++
++ endlink = void_list_node;
++
++ /* Special indenting here because one of the brackets is in def_param */
++ /* *INDENT-OFF* */
++
++ /* int fn (volatile const void *)
++ */
++ int_ftype_volatile_const_void_p
++ = build_function_type (integer_type_node,
++ def_param (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,
++ def_param (build_qualified_type (ptr_type_node,
++ TYPE_QUAL_VOLATILE))
++ def_param (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,
++ def_param (integer_type_node)
++ endlink));
++
++ /* void fn (int, int)
++ */
++ void_ftype_int_int
++ = build_function_type (void_type_node,
++ def_param (integer_type_node)
++ def_param (integer_type_node)
++ endlink)));
++
++
++#define CUSTOM_NUM def_param (integer_type_node)
++
++ custom_n
++ = build_function_type (void_type_node,
++ CUSTOM_NUM
++ endlink));
++ custom_ni
++ = build_function_type (void_type_node,
++ CUSTOM_NUM
++ def_param (integer_type_node)
++ endlink)));
++ custom_nf
++ = build_function_type (void_type_node,
++ CUSTOM_NUM
++ def_param (float_type_node)
++ endlink)));
++ custom_np
++ = build_function_type (void_type_node,
++ CUSTOM_NUM
++ def_param (ptr_type_node)
++ endlink)));
++ custom_nii
++ = build_function_type (void_type_node,
++ CUSTOM_NUM
++ def_param (integer_type_node)
++ def_param (integer_type_node)
++ endlink))));
++ custom_nif
++ = build_function_type (void_type_node,
++ CUSTOM_NUM
++ def_param (integer_type_node)
++ def_param (float_type_node)
++ endlink))));
++ custom_nip
++ = build_function_type (void_type_node,
++ CUSTOM_NUM
++ def_param (integer_type_node)
++ def_param (ptr_type_node)
++ endlink))));
++ custom_nfi
++ = build_function_type (void_type_node,
++ CUSTOM_NUM
++ def_param (float_type_node)
++ def_param (integer_type_node)
++ endlink))));
++ custom_nff
++ = build_function_type (void_type_node,
++ CUSTOM_NUM
++ def_param (float_type_node)
++ def_param (float_type_node)
++ endlink))));
++ custom_nfp
++ = build_function_type (void_type_node,
++ CUSTOM_NUM
++ def_param (float_type_node)
++ def_param (ptr_type_node)
++ endlink))));
++ custom_npi
++ = build_function_type (void_type_node,
++ CUSTOM_NUM
++ def_param (ptr_type_node)
++ def_param (integer_type_node)
++ endlink))));
++ custom_npf
++ = build_function_type (void_type_node,
++ CUSTOM_NUM
++ def_param (ptr_type_node)
++ def_param (float_type_node)
++ endlink))));
++ custom_npp
++ = build_function_type (void_type_node,
++ CUSTOM_NUM
++ def_param (ptr_type_node)
++ def_param (ptr_type_node)
++ endlink))));
++
++ custom_in
++ = build_function_type (integer_type_node,
++ CUSTOM_NUM
++ endlink));
++ custom_ini
++ = build_function_type (integer_type_node,
++ CUSTOM_NUM
++ def_param (integer_type_node)
++ endlink)));
++ custom_inf
++ = build_function_type (integer_type_node,
++ CUSTOM_NUM
++ def_param (float_type_node)
++ endlink)));
++ custom_inp
++ = build_function_type (integer_type_node,
++ CUSTOM_NUM
++ def_param (ptr_type_node)
++ endlink)));
++ custom_inii
++ = build_function_type (integer_type_node,
++ CUSTOM_NUM
++ def_param (integer_type_node)
++ def_param (integer_type_node)
++ endlink))));
++ custom_inif
++ = build_function_type (integer_type_node,
++ CUSTOM_NUM
++ def_param (integer_type_node)
++ def_param (float_type_node)
++ endlink))));
++ custom_inip
++ = build_function_type (integer_type_node,
++ CUSTOM_NUM
++ def_param (integer_type_node)
++ def_param (ptr_type_node)
++ endlink))));
++ custom_infi
++ = build_function_type (integer_type_node,
++ CUSTOM_NUM
++ def_param (float_type_node)
++ def_param (integer_type_node)
++ endlink))));
++ custom_inff
++ = build_function_type (integer_type_node,
++ CUSTOM_NUM
++ def_param (float_type_node)
++ def_param (float_type_node)
++ endlink))));
++ custom_infp
++ = build_function_type (integer_type_node,
++ CUSTOM_NUM
++ def_param (float_type_node)
++ def_param (ptr_type_node)
++ endlink))));
++ custom_inpi
++ = build_function_type (integer_type_node,
++ CUSTOM_NUM
++ def_param (ptr_type_node)
++ def_param (integer_type_node)
++ endlink))));
++ custom_inpf
++ = build_function_type (integer_type_node,
++ CUSTOM_NUM
++ def_param (ptr_type_node)
++ def_param (float_type_node)
++ endlink))));
++ custom_inpp
++ = build_function_type (integer_type_node,
++ CUSTOM_NUM
++ def_param (ptr_type_node)
++ def_param (ptr_type_node)
++ endlink))));
++
++ custom_fn
++ = build_function_type (float_type_node,
++ CUSTOM_NUM
++ endlink));
++ custom_fni
++ = build_function_type (float_type_node,
++ CUSTOM_NUM
++ def_param (integer_type_node)
++ endlink)));
++ custom_fnf
++ = build_function_type (float_type_node,
++ CUSTOM_NUM
++ def_param (float_type_node)
++ endlink)));
++ custom_fnp
++ = build_function_type (float_type_node,
++ CUSTOM_NUM
++ def_param (ptr_type_node)
++ endlink)));
++ custom_fnii
++ = build_function_type (float_type_node,
++ CUSTOM_NUM
++ def_param (integer_type_node)
++ def_param (integer_type_node)
++ endlink))));
++ custom_fnif
++ = build_function_type (float_type_node,
++ CUSTOM_NUM
++ def_param (integer_type_node)
++ def_param (float_type_node)
++ endlink))));
++ custom_fnip
++ = build_function_type (float_type_node,
++ CUSTOM_NUM
++ def_param (integer_type_node)
++ def_param (ptr_type_node)
++ endlink))));
++ custom_fnfi
++ = build_function_type (float_type_node,
++ CUSTOM_NUM
++ def_param (float_type_node)
++ def_param (integer_type_node)
++ endlink))));
++ custom_fnff
++ = build_function_type (float_type_node,
++ CUSTOM_NUM
++ def_param (float_type_node)
++ def_param (float_type_node)
++ endlink))));
++ custom_fnfp
++ = build_function_type (float_type_node,
++ CUSTOM_NUM
++ def_param (float_type_node)
++ def_param (ptr_type_node)
++ endlink))));
++ custom_fnpi
++ = build_function_type (float_type_node,
++ CUSTOM_NUM
++ def_param (ptr_type_node)
++ def_param (integer_type_node)
++ endlink))));
++ custom_fnpf
++ = build_function_type (float_type_node,
++ CUSTOM_NUM
++ def_param (ptr_type_node)
++ def_param (float_type_node)
++ endlink))));
++ custom_fnpp
++ = build_function_type (float_type_node,
++ CUSTOM_NUM
++ def_param (ptr_type_node)
++ def_param (ptr_type_node)
++ endlink))));
++
++
++ custom_pn
++ = build_function_type (ptr_type_node,
++ CUSTOM_NUM
++ endlink));
++ custom_pni
++ = build_function_type (ptr_type_node,
++ CUSTOM_NUM
++ def_param (integer_type_node)
++ endlink)));
++ custom_pnf
++ = build_function_type (ptr_type_node,
++ CUSTOM_NUM
++ def_param (float_type_node)
++ endlink)));
++ custom_pnp
++ = build_function_type (ptr_type_node,
++ CUSTOM_NUM
++ def_param (ptr_type_node)
++ endlink)));
++ custom_pnii
++ = build_function_type (ptr_type_node,
++ CUSTOM_NUM
++ def_param (integer_type_node)
++ def_param (integer_type_node)
++ endlink))));
++ custom_pnif
++ = build_function_type (ptr_type_node,
++ CUSTOM_NUM
++ def_param (integer_type_node)
++ def_param (float_type_node)
++ endlink))));
++ custom_pnip
++ = build_function_type (ptr_type_node,
++ CUSTOM_NUM
++ def_param (integer_type_node)
++ def_param (ptr_type_node)
++ endlink))));
++ custom_pnfi
++ = build_function_type (ptr_type_node,
++ CUSTOM_NUM
++ def_param (float_type_node)
++ def_param (integer_type_node)
++ endlink))));
++ custom_pnff
++ = build_function_type (ptr_type_node,
++ CUSTOM_NUM
++ def_param (float_type_node)
++ def_param (float_type_node)
++ endlink))));
++ custom_pnfp
++ = build_function_type (ptr_type_node,
++ CUSTOM_NUM
++ def_param (float_type_node)
++ def_param (ptr_type_node)
++ endlink))));
++ custom_pnpi
++ = build_function_type (ptr_type_node,
++ CUSTOM_NUM
++ def_param (ptr_type_node)
++ def_param (integer_type_node)
++ endlink))));
++ custom_pnpf
++ = build_function_type (ptr_type_node,
++ CUSTOM_NUM
++ def_param (ptr_type_node)
++ def_param (float_type_node)
++ endlink))));
++ custom_pnpp
++ = build_function_type (ptr_type_node,
++ CUSTOM_NUM
++ def_param (ptr_type_node)
++ def_param (ptr_type_node)
++ endlink))));
++
++
++
++ /* *INDENT-ON* */
++
++
++ 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)
++ return (d->expander) (d, exp, target, subtarget, mode, ignore);
++
++ /* we should have seen one of the functins we registered */
++ abort ();
++}
++
++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);
++ opcode = protect_from_queue (opcode, 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);
++
++ 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);
++ operand = protect_from_queue (operand, 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 */
++ if (insn_data[d->icode].n_operands != 1)
++ abort ();
++
++ 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 */
++ if (insn_data[d->icode].n_operands != 2)
++ abort ();
++
++ 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 */
++ if (insn_data[d->icode].n_operands != 2)
++ abort ();
++
++ 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 */
++ if (insn_data[d->icode].n_operands != 3)
++ abort ();
++
++ 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 */
++ if (insn_data[d->icode].n_operands != 3)
++ abort ();
++
++ 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 */
++ if (insn_data[d->icode].n_operands != 4)
++ abort ();
++
++ 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 */
++ if (insn_data[icode].n_operands != 2)
++ abort ();
++
++ /* 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 = protect_from_queue (store_dest, 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);
++ store_val = protect_from_queue (store_val, 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 */
++ if (insn_data[icode].n_operands != 2)
++ abort ();
++
++ 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 = protect_from_queue (ld_src, 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 */
++ if (insn_data[icode].n_operands != 2)
++ abort ();
++
++ 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);
++ rdctl_reg = protect_from_queue (rdctl_reg, 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 */
++ if (insn_data[icode].n_operands != 2)
++ abort ();
++
++ /* 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);
++ wrctl_reg = protect_from_queue (wrctl_reg, 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);
++ store_val = protect_from_queue (store_val, 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;
++}
++
++
++#include "gt-nios2.h"
++
+--- gcc-3.4.3/gcc/config/nios2/nios2.h
++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2.h
+@@ -0,0 +1,823 @@
++/* Definitions of target machine 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. */
++
++
++
++#define TARGET_CPU_CPP_BUILTINS() \
++ do \
++ { \
++ builtin_define_std ("NIOS2"); \
++ builtin_define_std ("nios2"); \
++ } \
++ while (0)
++#define TARGET_VERSION fprintf (stderr, " (Altera Nios II)")
++
++
++
++
++
++/*********************************
++ * Run-time Target Specification
++ *********************************/
++
++#define HAS_DIV_FLAG 0x0001
++#define HAS_MUL_FLAG 0x0002
++#define HAS_MULX_FLAG 0x0004
++#define FAST_SW_DIV_FLAG 0x0008
++#define INLINE_MEMCPY_FLAG 0x00010
++#define CACHE_VOLATILE_FLAG 0x0020
++#define BYPASS_CACHE_FLAG 0x0040
++
++extern int target_flags;
++#define TARGET_HAS_DIV (target_flags & HAS_DIV_FLAG)
++#define TARGET_HAS_MUL (target_flags & HAS_MUL_FLAG)
++#define TARGET_HAS_MULX (target_flags & HAS_MULX_FLAG)
++#define TARGET_FAST_SW_DIV (target_flags & FAST_SW_DIV_FLAG)
++#define TARGET_INLINE_MEMCPY (target_flags & INLINE_MEMCPY_FLAG)
++#define TARGET_CACHE_VOLATILE (target_flags & CACHE_VOLATILE_FLAG)
++#define TARGET_BYPASS_CACHE (target_flags & BYPASS_CACHE_FLAG)
++
++#define TARGET_SWITCHES \
++{ \
++ { "hw-div", HAS_DIV_FLAG, \
++ N_("Enable DIV, DIVU") }, \
++ { "no-hw-div", -HAS_DIV_FLAG, \
++ N_("Disable DIV, DIVU (default)") }, \
++ { "hw-mul", HAS_MUL_FLAG, \
++ N_("Enable MUL instructions (default)") }, \
++ { "hw-mulx", HAS_MULX_FLAG, \
++ N_("Enable MULX instructions, assume fast shifter") }, \
++ { "no-hw-mul", -HAS_MUL_FLAG, \
++ N_("Disable MUL instructions") }, \
++ { "no-hw-mulx", -HAS_MULX_FLAG, \
++ N_("Disable MULX instructions, assume slow shifter (default and implied by -mno-hw-mul)") }, \
++ { "fast-sw-div", FAST_SW_DIV_FLAG, \
++ N_("Use table based fast divide (default at -O3)") }, \
++ { "no-fast-sw-div", -FAST_SW_DIV_FLAG, \
++ N_("Don't use table based fast divide ever") }, \
++ { "inline-memcpy", INLINE_MEMCPY_FLAG, \
++ N_("Inline small memcpy (default when optimizing)") }, \
++ { "no-inline-memcpy", -INLINE_MEMCPY_FLAG, \
++ N_("Don't Inline small memcpy") }, \
++ { "cache-volatile", CACHE_VOLATILE_FLAG, \
++ N_("Volatile accesses use non-io variants of instructions (default)") }, \
++ { "no-cache-volatile", -CACHE_VOLATILE_FLAG, \
++ N_("Volatile accesses use io variants of instructions") }, \
++ { "bypass-cache", BYPASS_CACHE_FLAG, \
++ N_("All ld/st instructins use io variants") }, \
++ { "no-bypass-cache", -BYPASS_CACHE_FLAG, \
++ N_("All ld/st instructins do not use io variants (default)") }, \
++ { "smallc", 0, \
++ N_("Link with a limited version of the C library") }, \
++ { "ctors-in-init", 0, \
++ "" /* undocumented: N_("Link with static constructors and destructors in init") */ }, \
++ { "", TARGET_DEFAULT, 0 } \
++}
++
++
++extern const char *nios2_sys_nosys_string; /* for -msys=nosys */
++extern const char *nios2_sys_lib_string; /* for -msys-lib= */
++extern const char *nios2_sys_crt0_string; /* for -msys-crt0= */
++
++#define TARGET_OPTIONS \
++{ \
++ { "sys=nosys", &nios2_sys_nosys_string, \
++ N_("Use stub versions of OS library calls (default)"), 0}, \
++ { "sys-lib=", &nios2_sys_lib_string, \
++ N_("Name of System Library to link against. (Converted to a -l option)"), 0}, \
++ { "sys-crt0=", &nios2_sys_crt0_string, \
++ N_("Name of the startfile. (default is a crt0 for the ISS only)"), 0}, \
++}
++
++
++/* Default target_flags if no switches specified. */
++#ifndef TARGET_DEFAULT
++# define TARGET_DEFAULT (HAS_MUL_FLAG | CACHE_VOLATILE_FLAG)
++#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*}"
++
++#undef LIB_SPEC
++#define LIB_SPEC \
++"--start-group %{msmallc: -lsmallc} %{!msmallc: -lc} -lgcc \
++ %{msys-lib=*: -l%*} \
++ %{!msys-lib=*: -lc } \
++ --end-group \
++ %{msys-lib=: %eYou need a library name for -msys-lib=} \
++"
++
++
++#undef STARTFILE_SPEC
++#define STARTFILE_SPEC \
++"%{msys-crt0=*: %*} %{!msys-crt0=*: crt1%O%s} \
++ %{msys-crt0=: %eYou need a C startup file for -msys-crt0=} \
++ %{mctors-in-init: crti%O%s crtbegin%O%s} \
++"
++
++#undef ENDFILE_SPEC
++#define ENDFILE_SPEC \
++ "%{mctors-in-init: crtend%O%s crtn%O%s}"
++
++
++/***********************
++ * Storage Layout
++ ***********************/
++
++#define DEFAULT_SIGNED_CHAR 1
++#define BITS_BIG_ENDIAN 0
++#define BYTES_BIG_ENDIAN 0
++#define WORDS_BIG_ENDIAN 0
++#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 only CMP_SI is used */
++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
++23 r23 sc Static Chain (Callee Saved)
++ ??? Does $sc want to be caller or callee
++ saved. If caller, 15, else 23.
++24 r24 Exception Temporary
++25 r25 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 rap Return address pointer, this does not
++ actually exist and will be eliminated
++
++39 fake_fp Fake Frame Pointer which will always be eliminated.
++40 fake_ap Fake Argument Pointer which will always be eliminated.
++
++41 First Pseudo Register
++
++
++The definitions for all the hard register numbers
++are located in nios2.md.
++*/
++
++#define FIRST_PSEUDO_REGISTER 41
++#define NUM_ARG_REGS (LAST_ARG_REGNO - FIRST_ARG_REGNO + 1)
++
++
++
++/* also see CONDITIONAL_REGISTER_USAGE */
++#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, 0, 0, 1, 1, 1, 1, 0, 1, \
++/* 30 */ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, \
++/* 40 */ 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, 0, 0, 1, 1, 1, 1, 0, 1, \
++/* 30 */ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, \
++/* 40 */ 1, \
++ }
++
++#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,
++ ALL_REGS,
++ LIM_REG_CLASSES
++};
++
++#define N_REG_CLASSES (int) LIM_REG_CLASSES
++
++#define REG_CLASS_NAMES \
++ {"NO_REGS", \
++ "ALL_REGS"}
++
++#define GENERAL_REGS ALL_REGS
++
++#define REG_CLASS_CONTENTS \
++/* NO_REGS */ {{ 0, 0}, \
++/* ALL_REGS */ {~0,~0}} \
++
++#define REGNO_REG_CLASS(REGNO) ALL_REGS
++
++#define BASE_REG_CLASS ALL_REGS
++#define INDEX_REG_CLASS ALL_REGS
++
++/* only one reg class, 'r', is handled automatically */
++#define REG_CLASS_FROM_LETTER(CHAR) NO_REGS
++
++#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))
++
++/* '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)
++
++
++#define DEFAULT_MAIN_RETURN c_expand_return (integer_zero_node)
++
++/**********************************
++ * 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 current_function_outgoing_args_size
++#define FIRST_PARM_OFFSET(FUNDECL) 0
++
++/* Before the prologue, RA lives in r31. */
++#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (VOIDmode, RA_REGNO)
++
++/* -------------------------------------- *
++ * 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
++
++/* 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
++#define RETURN_ADDRESS_POINTER_REGNUM RAP_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
++
++/* ----------------------------------------- *
++ * 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}, \
++ { RETURN_ADDRESS_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
++ { RETURN_ADDRESS_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \
++ { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
++ { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}}
++
++#define CAN_ELIMINATE(FROM, TO) 1
++
++#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
++ (OFFSET) = nios2_initial_elimination_offset ((FROM), (TO))
++
++#define MUST_SAVE_REGISTER(regno) \
++ ((regs_ever_live[regno] && !call_used_regs[regno]) \
++ || (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed) \
++ || (regno == RA_REGNO && regs_ever_live[RA_REGNO]))
++
++/* 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_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \
++ (function_arg_partial_nregs (&CUM, MODE, TYPE, NAMED))
++
++#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) 0
++
++#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_REGNO_P(REGNO) \
++ ((REGNO) >= FIRST_ARG_REGNO && (REGNO) <= LAST_ARG_REGNO)
++
++#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \
++ { \
++ int pret_size = nios2_setup_incoming_varargs (&(CUM), (MODE), \
++ (TYPE), (NO_RTL)); \
++ if (pret_size) \
++ (PRETEND_SIZE) = pret_size; \
++ }
++
++/* ----------------------------- *
++ * Generating Code for Profiling
++ * ----------------------------- */
++
++#define PROFILE_BEFORE_PROLOGUE
++
++#define FUNCTION_PROFILER(FILE, LABELNO) \
++ function_profiler ((FILE), (LABELNO))
++
++/* --------------------------------------- *
++ * Passing Function Arguments on the Stack
++ * --------------------------------------- */
++
++#define PROMOTE_PROTOTYPES 1
++
++#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)
++
++#define CONSTANT_ADDRESS_P(X) (CONSTANT_P (X))
++
++#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) 1
++
++/* 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 */
++#define SYMBOL_REF_IN_NIOS2_SMALL_DATA_P(RTX) \
++ (SYMBOL_REF_SMALL_P(RTX) && !SYMBOL_REF_WEAK_DECL_P(RTX))
++
++/*****************
++ * 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
++#define NO_RECURSIVE_FUNCTION_CSE
++
++
++
++/*****************************************
++ * 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
++ * -------------- */
++
++#define DWARF2_UNWIND_INFO 0
++
++
++/* -------------------------------- *
++ * 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", \
++ "r24", \
++ "r25", \
++ "gp", \
++ "sp", \
++ "fp", \
++ "ta", \
++ "ba", \
++ "ra", \
++ "status", \
++ "estatus", \
++ "bstatus", \
++ "ipri", \
++ "ecause", \
++ "pc", \
++ "rap", \
++ "fake_fp", \
++ "fake_ap", \
++}
++
++#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)
++
++
++/* ------------ *
++ * 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 \
++{ \
++ if ((SIZE) <= nios2_section_threshold) \
++ { \
++ named_section (0, ".sbss", 0); \
++ (*targetm.asm_out.globalize_label) (FILE, NAME); \
++ 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); \
++ } \
++ else \
++ { \
++ 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)
++
++
++
++/***************************
++ * Miscellaneous Parameters
++ ***************************/
++
++#define MOVE_MAX 4
++
++#define Pmode SImode
++#define FUNCTION_MODE QImode
++
++#define CASE_VECTOR_MODE Pmode
++
++#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
++
++#define LOAD_EXTEND_OP(MODE) (ZERO_EXTEND)
++
++#define WORD_REGISTER_OPERATIONS
+--- gcc-3.4.3/gcc/config/nios2/nios2.md
++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2.md
+@@ -0,0 +1,2078 @@
++;; Machine Description 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. */
++
++
++
++;*****************************************************************************
++;*
++;* constants
++;*
++;*****************************************************************************
++(define_constants [
++ (GP_REGNO 26)
++ (SP_REGNO 27)
++ (FP_REGNO 28)
++ (RA_REGNO 31)
++ (RAP_REGNO 38)
++ (FIRST_RETVAL_REGNO 2)
++ (LAST_RETVAL_REGNO 3)
++ (FIRST_ARG_REGNO 4)
++ (LAST_ARG_REGNO 7)
++ (SC_REGNO 23)
++ (PC_REGNO 37)
++ (FAKE_FP_REGNO 39)
++ (FAKE_AP_REGNO 40)
++
++
++ (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)
++
++])
++
++
++
++;*****************************************************************************
++;*
++;* 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)
++ || register_operand (operands[1], QImode)
++ || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
++ "@
++ 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 "register_operand" "r"))
++ (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)
++ || register_operand (operands[1], HImode)
++ || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
++ "@
++ 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 "register_operand" "r"))
++ (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)
++ || register_operand (operands[1], SImode)
++ || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
++ "@
++ 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 "register_operand" "r"))
++ (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" "")))]
++ ""
++{
++ if (optimize && GET_CODE (operands[1]) == MEM)
++ operands[1] = force_not_mem (operands[1]);
++
++ if (GET_CODE (operands[1]) != MEM)
++ {
++ rtx op1 = gen_lowpart (SImode, operands[1]);
++ rtx temp = gen_reg_rtx (SImode);
++ rtx shift = GEN_INT (16);
++
++ emit_insn (gen_ashlsi3 (temp, op1, shift));
++ emit_insn (gen_ashrsi3 (operands[0], temp, shift));
++ DONE;
++ }
++})
++
++(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" "")))]
++ ""
++{
++ if (optimize && GET_CODE (operands[1]) == MEM)
++ operands[1] = force_not_mem (operands[1]);
++
++ if (GET_CODE (operands[1]) != MEM)
++ {
++ rtx op0 = gen_lowpart (SImode, operands[0]);
++ rtx op1 = gen_lowpart (SImode, operands[1]);
++ rtx temp = gen_reg_rtx (SImode);
++ rtx shift = GEN_INT (24);
++
++ emit_insn (gen_ashlsi3 (temp, op1, shift));
++ emit_insn (gen_ashrsi3 (op0, temp, shift));
++ DONE;
++ }
++})
++
++(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" "")))]
++ ""
++{
++ if (optimize && GET_CODE (operands[1]) == MEM)
++ operands[1] = force_not_mem (operands[1]);
++
++ if (GET_CODE (operands[1]) != MEM)
++ {
++ rtx op1 = gen_lowpart (SImode, operands[1]);
++ rtx temp = gen_reg_rtx (SImode);
++ rtx shift = GEN_INT (24);
++
++ emit_insn (gen_ashlsi3 (temp, op1, shift));
++ emit_insn (gen_ashrsi3 (operands[0], temp, shift));
++ DONE;
++ }
++})
++
++(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 "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 "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_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 "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"
++ [(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"
++ "")
++
++(define_expand "umulsidi3"
++ [(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"
++ "")
++
++
++
++;*****************************************************************************
++;*
++;* 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 "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")])
++
++
++
++; 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")))]
++ ""
++ "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")])
++
++
++
++
++;*****************************************************************************
++;*
++;* 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")])
++
++
++
++;*****************************************************************************
++;*
++;* 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_insn "indirect_call"
++ [(call (mem:QI (match_operand:SI 0 "register_operand" "r"))
++ (match_operand 1 "" ""))
++ (clobber (reg:SI RA_REGNO))]
++ ""
++ "callr\\t%0"
++ [(set_attr "type" "control")])
++
++(define_insn "indirect_call_value"
++ [(set (match_operand 0 "" "")
++ (call (mem:QI (match_operand:SI 1 "register_operand" "r"))
++ (match_operand 2 "" "")))
++ (clobber (reg:SI RA_REGNO))]
++ ""
++ "callr\\t%1"
++)
++
++(define_expand "call"
++ [(parallel [(call (match_operand 0 "" "")
++ (match_operand 1 "" ""))
++ (clobber (reg:SI RA_REGNO))])]
++ ""
++ "")
++
++(define_expand "call_value"
++ [(parallel [(set (match_operand 0 "" "")
++ (call (match_operand 1 "" "")
++ (match_operand 2 "" "")))
++ (clobber (reg:SI RA_REGNO))])]
++ ""
++ "")
++
++(define_insn "*call"
++ [(call (mem:QI (match_operand:SI 0 "immediate_operand" "i"))
++ (match_operand 1 "" ""))
++ (clobber (match_operand:SI 2 "register_operand" "=r"))]
++ ""
++ "call\\t%0"
++ [(set_attr "type" "control")])
++
++(define_insn "*call_value"
++ [(set (match_operand 0 "" "")
++ (call (mem:QI (match_operand:SI 1 "immediate_operand" "i"))
++ (match_operand 2 "" "")))
++ (clobber (match_operand:SI 3 "register_operand" "=r"))]
++ ""
++ "call\\t%1"
++ [(set_attr "type" "control")])
++
++(define_expand "sibcall"
++ [(parallel [(call (match_operand 0 "" "")
++ (match_operand 1 "" ""))
++ (return)
++ (use (match_operand 2 "" ""))])]
++ ""
++ {
++ XEXP (operands[0], 0) = copy_to_mode_reg (SImode, XEXP (operands[0], 0));
++
++ if (operands[2] == NULL_RTX)
++ operands[2] = const0_rtx;
++ }
++)
++
++(define_expand "sibcall_value"
++ [(parallel [(set (match_operand 0 "" "")
++ (call (match_operand 1 "" "")
++ (match_operand 2 "" "")))
++ (return)
++ (use (match_operand 3 "" ""))])]
++ ""
++ {
++ XEXP (operands[1], 0) = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
++
++ if (operands[3] == NULL_RTX)
++ operands[3] = const0_rtx;
++ }
++)
++
++(define_insn "sibcall_insn"
++ [(call (mem:QI (match_operand:SI 0 "register_operand" "r"))
++ (match_operand 1 "" ""))
++ (return)
++ (use (match_operand 2 "" ""))]
++ ""
++ "jmp\\t%0"
++)
++
++(define_insn "sibcall_value_insn"
++ [(set (match_operand 0 "register_operand" "")
++ (call (mem:QI (match_operand:SI 1 "register_operand" "r"))
++ (match_operand 2 "" "")))
++ (return)
++ (use (match_operand 3 "" ""))]
++ ""
++ "jmp\\t%1"
++)
++
++
++
++
++(define_expand "tablejump"
++ [(parallel [(set (pc) (match_operand 0 "register_operand" "r"))
++ (use (label_ref (match_operand 1 "" "")))])]
++ ""
++ ""
++)
++
++(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;
++})
++
++
++;*****************************************************************************
++;*
++;* 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)
++ 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_expand "sne"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ne: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 (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_expand "sgt"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (gt: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 (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_expand "sge"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ge: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 (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_expand "sle"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (le: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 (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_expand "slt"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (lt: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 (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_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_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];
++
++ if (INTVAL (operands[3]) < 4)
++ abort ();
++
++ 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 "register_operand" "r")] UNSPEC_WRCTL)]
++ ""
++ "wrctl\\tctl%0, %1"
++ [(set_attr "type" "control")])
++
++
++
++;*****************************************************************************
++;*
++;* Peepholes
++;*
++;*****************************************************************************
++
++
+--- gcc-3.4.3/gcc/config/nios2/t-nios2
++++ gcc-3.4.3-nios2/gcc/config/nios2/t-nios2
+@@ -0,0 +1,123 @@
++##
++## 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=$(srcdir)/config/nios2/nios2-fp-bit.c
++DPBIT=$(srcdir)/config/nios2/nios2-dp-bit.c
++
++TARGET_LIBGCC2_CFLAGS = -O2
++
++# 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}
++ cat $(srcdir)/config/fp-bit.c >> ${FPBIT}
++
++$(DPBIT): $(srcdir)/config/fp-bit.c Makefile
++ echo '' > ${DPBIT}
++ cat $(srcdir)/config/fp-bit.c >> ${DPBIT}
++
++EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o crti.o crtn.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.
++
++MULTILIB_OPTIONS = mno-hw-mul mhw-mulx
++
++## 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.
++##
++## 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*
++##
++
++MULTILIB_EXCEPTIONS = *mno-hw-mul/*mhw-mulx*
++
++##
++## 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.
++##
++
+--- gcc-3.4.3/gcc/config.gcc
++++ gcc-3.4.3-nios2/gcc/config.gcc
+@@ -1321,6 +1321,10 @@ m32rle-*-linux*)
+ thread_file='posix'
+ fi
+ ;;
++# JBG
++nios2-*-* | nios2-*-*)
++ tm_file="elfos.h ${tm_file}"
++ ;;
+ # m68hc11 and m68hc12 share the same machine description.
+ m68hc11-*-*|m6811-*-*)
+ tm_file="dbxelf.h elfos.h m68hc11/m68hc11.h"
+--- gcc-3.4.3/gcc/cse.c
++++ gcc-3.4.3-nios2/gcc/cse.c
+@@ -3134,6 +3134,10 @@ find_comparison_args (enum rtx_code code
+ #ifdef FLOAT_STORE_FLAG_VALUE
+ REAL_VALUE_TYPE fsfv;
+ #endif
++#ifdef __nios2__
++ if (p->is_const)
++ break;
++#endif
+
+ /* If the entry isn't valid, skip it. */
+ if (! exp_equiv_p (p->exp, p->exp, 1, 0))
+--- gcc-3.4.3/gcc/doc/extend.texi
++++ gcc-3.4.3-nios2/gcc/doc/extend.texi
+@@ -5636,12 +5636,118 @@ to those machines. Generally these gene
+ instructions, but allow the compiler to schedule those calls.
+
+ @menu
++* Altera Nios II Built-in Functions::
+ * Alpha Built-in Functions::
+ * ARM Built-in Functions::
+ * X86 Built-in Functions::
+ * PowerPC AltiVec Built-in Functions::
+ @end menu
+
++@node Altera Nios II Built-in Functions
++@subsection Altera Nios II Built-in Functions
++
++These built-in functions are available for the Altera Nios II
++family of processors.
++
++The following built-in functions are always available. They
++all generate the machine instruction that is part of the name.
++
++@example
++int __builtin_ldbio (volatile const void *)
++int __builtin_ldbuio (volatile const void *)
++int __builtin_ldhio (volatile const void *)
++int __builtin_ldhuio (volatile const void *)
++int __builtin_ldwio (volatile const void *)
++void __builtin_stbio (volatile void *, int)
++void __builtin_sthio (volatile void *, int)
++void __builtin_stwio (volatile void *, int)
++void __builtin_sync (void)
++int __builtin_rdctl (int)
++void __builtin_wrctl (int, int)
++@end example
++
++The following built-in functions are always available. They
++all generate a Nios II Custom Instruction. The name of the
++function represents the types that the function takes and
++returns. The letter before the @code{n} is the return type
++or void if absent. The @code{n} represnts the first parameter
++to all the custom instructions, the custom instruction number.
++The two letters after the @code{n} represent the up to two
++parameters to the function.
++
++The letters reprsent the following data types:
++@table @code
++@item <no letter>
++@code{void} for return type and no parameter for parameter types.
++
++@item i
++@code{int} for return type and parameter type
++
++@item f
++@code{float} for return type and parameter type
++
++@item p
++@code{void *} for return type and parameter type
++
++@end table
++
++And the function names are:
++@example
++void __builtin_custom_n (void)
++void __builtin_custom_ni (int)
++void __builtin_custom_nf (float)
++void __builtin_custom_np (void *)
++void __builtin_custom_nii (int, int)
++void __builtin_custom_nif (int, float)
++void __builtin_custom_nip (int, void *)
++void __builtin_custom_nfi (float, int)
++void __builtin_custom_nff (float, float)
++void __builtin_custom_nfp (float, void *)
++void __builtin_custom_npi (void *, int)
++void __builtin_custom_npf (void *, float)
++void __builtin_custom_npp (void *, void *)
++int __builtin_custom_in (void)
++int __builtin_custom_ini (int)
++int __builtin_custom_inf (float)
++int __builtin_custom_inp (void *)
++int __builtin_custom_inii (int, int)
++int __builtin_custom_inif (int, float)
++int __builtin_custom_inip (int, void *)
++int __builtin_custom_infi (float, int)
++int __builtin_custom_inff (float, float)
++int __builtin_custom_infp (float, void *)
++int __builtin_custom_inpi (void *, int)
++int __builtin_custom_inpf (void *, float)
++int __builtin_custom_inpp (void *, void *)
++float __builtin_custom_fn (void)
++float __builtin_custom_fni (int)
++float __builtin_custom_fnf (float)
++float __builtin_custom_fnp (void *)
++float __builtin_custom_fnii (int, int)
++float __builtin_custom_fnif (int, float)
++float __builtin_custom_fnip (int, void *)
++float __builtin_custom_fnfi (float, int)
++float __builtin_custom_fnff (float, float)
++float __builtin_custom_fnfp (float, void *)
++float __builtin_custom_fnpi (void *, int)
++float __builtin_custom_fnpf (void *, float)
++float __builtin_custom_fnpp (void *, void *)
++void * __builtin_custom_pn (void)
++void * __builtin_custom_pni (int)
++void * __builtin_custom_pnf (float)
++void * __builtin_custom_pnp (void *)
++void * __builtin_custom_pnii (int, int)
++void * __builtin_custom_pnif (int, float)
++void * __builtin_custom_pnip (int, void *)
++void * __builtin_custom_pnfi (float, int)
++void * __builtin_custom_pnff (float, float)
++void * __builtin_custom_pnfp (float, void *)
++void * __builtin_custom_pnpi (void *, int)
++void * __builtin_custom_pnpf (void *, float)
++void * __builtin_custom_pnpp (void *, void *)
++@end example
++
++
+ @node Alpha Built-in Functions
+ @subsection Alpha Built-in Functions
+
+--- gcc-3.4.3/gcc/doc/invoke.texi
++++ gcc-3.4.3-nios2/gcc/doc/invoke.texi
+@@ -337,6 +337,14 @@ in the following sections.
+ @item Machine Dependent Options
+ @xref{Submodel Options,,Hardware Models and Configurations}.
+
++@emph{Altera Nios II Options}
++@gccoptlist{-msmallc -mno-bypass-cache -mbypass-cache @gol
++-mno-cache-volatile -mcache-volatile -mno-inline-memcpy @gol
++-minline-memcpy -mno-fast-sw-div -mfast-sw-div @gol
++-mhw-mul -mno-hw-mul -mhw-mulx -mno-hw-mulx @gol
++-mno-hw-div -mhw-div @gol
++-msys-crt0= -msys-lib= -msys=nosys }
++
+ @emph{M680x0 Options}
+ @gccoptlist{-m68000 -m68020 -m68020-40 -m68020-60 -m68030 -m68040 @gol
+ -m68060 -mcpu32 -m5200 -m68881 -mbitfield -mc68000 -mc68020 @gol
+@@ -5836,6 +5844,7 @@ machine description. The default for th
+ that macro, which enables you to change the defaults.
+
+ @menu
++* Altera Nios II Options::
+ * M680x0 Options::
+ * M68hc1x Options::
+ * VAX Options::
+@@ -5871,6 +5880,103 @@ that macro, which enables you to change
+ * FRV Options::
+ @end menu
+
++
++@node Altera Nios II Options
++@subsection Altera Nios II Options
++@cindex Altera Nios II options
++
++These are the @samp{-m} options defined for the Altera Nios II
++processor.
++
++@table @gcctabopt
++
++@item -msmallc
++@opindex msmallc
++
++Link with a limited version of the C library, -lsmallc. For more
++information see the C Library Documentation.
++
++
++@item -mbypass-cache
++@itemx -mno-bypass-cache
++@opindex mno-bypass-cache
++@opindex mbypass-cache
++
++Force all load and store instructions to always bypass cache by
++using io variants of the instructions. The default is to not
++bypass the cache.
++
++@item -mno-cache-volatile
++@itemx -mcache-volatile
++@opindex mcache-volatile
++@opindex mno-cache-volatile
++
++Volatile memory access bypass the cache using the io variants of
++the ld and st instructions. The default is to cache volatile
++accesses.
++
++-mno-cache-volatile is deprecated and will be deleted in a
++future GCC release.
++
++
++@item -mno-inline-memcpy
++@itemx -minline-memcpy
++@opindex mno-inline-memcpy
++@opindex minline-memcpy
++
++Do not inline memcpy. The default is to inline when -O is on.
++
++
++@item -mno-fast-sw-div
++@itemx -mfast-sw-div
++@opindex mno-fast-sw-div
++@opindex mfast-sw-div
++
++Do no use table based fast divide for small numbers. The default
++is to use the fast divide at -O3 and above.
++
++
++@item -mno-hw-mul
++@itemx -mhw-mul
++@itemx -mno-hw-mulx
++@itemx -mhw-mulx
++@itemx -mno-hw-div
++@itemx -mhw-div
++@opindex mno-hw-mul
++@opindex mhw-mul
++@opindex mno-hw-mulx
++@opindex mhw-mulx
++@opindex mno-hw-div
++@opindex mhw-div
++
++Enable or disable emitting @code{mul}, @code{mulx} and @code{div} family of
++instructions by the compiler. The default is to emit @code{mul}
++and not emit @code{div} and @code{mulx}.
++
++The different combinations of @code{mul} and @code{mulx} instructions
++generate a different multilib options.
++
++
++@item -msys-crt0=@var{startfile}
++@opindex msys-crt0
++
++@var{startfile} is the file name of the startfile (crt0) to use
++when linking. The default is crt0.o that comes with libgloss
++and is only suitable for use with the instruction set
++simulator.
++
++@item -msys-lib=@var{systemlib}
++@itemx -msys-lib=nosys
++@opindex msys-lib
++
++@var{systemlib} is the library name of the library which provides
++the system calls required by the C library, e.g. @code{read}, @code{write}
++etc. The default is to use nosys, this library provides
++stub implementations of the calls and is part of libgloss.
++
++@end table
++
++
+ @node M680x0 Options
+ @subsection M680x0 Options
+ @cindex M680x0 options
+--- gcc-3.4.3/gcc/doc/md.texi
++++ gcc-3.4.3-nios2/gcc/doc/md.texi
+@@ -1335,6 +1335,49 @@ However, here is a summary of the machin
+ available on some particular machines.
+
+ @table @emph
++
++@item Altera Nios II family---@file{nios2.h}
++@table @code
++
++@item I
++Integer that is valid as an immediate operand in an
++instruction taking a signed 16-bit number. Range
++@minus{}32768 to 32767.
++
++@item J
++Integer that is valid as an immediate operand in an
++instruction taking an unsigned 16-bit number. Range
++0 to 65535.
++
++@item K
++Integer that is valid as an immediate operand in an
++instruction taking only the upper 16-bits of a
++32-bit number. Range 32-bit numbers with the lower
++16-bits being 0.
++
++@item L
++Integer that is valid as an immediate operand for a
++shift instruction. Range 0 to 31.
++
++
++@item M
++Integer that is valid as an immediate operand for
++only the value 0. Can be used in conjunction with
++the format modifier @code{z} to use @code{r0}
++instead of @code{0} in the assembly output.
++
++@item N
++Integer that is valid as an immediate operand for
++a custom instruction opcode. Range 0 to 255.
++
++@item S
++Matches immediates which are addresses in the small
++data section and therefore can be added to @code{gp}
++as a 16-bit immediate to re-create their 32-bit value.
++
++@end table
++
++
+ @item ARM family---@file{arm.h}
+ @table @code
+ @item f
diff --git a/toolchain/gcc/3.4.5/900-nios2.patch b/toolchain/gcc/3.4.5/900-nios2.patch
new file mode 100644
index 000000000..39ac283ea
--- /dev/null
+++ b/toolchain/gcc/3.4.5/900-nios2.patch
@@ -0,0 +1,10210 @@
+--- gcc-3.4.3/gcc/Makefile.in
++++ gcc-3.4.3-nios2/gcc/Makefile.in
+@@ -3085,7 +3085,7 @@ install-mkheaders: stmp-int-hdrs $(STMP_
+ $(INSTALL_DATA) $(srcdir)/README-fixinc \
+ $(DESTDIR)$(itoolsdatadir)/include/README ; \
+ $(INSTALL_SCRIPT) fixinc.sh $(DESTDIR)$(itoolsdir)/fixinc.sh ; \
+- $(INSTALL_PROGRAM) fixinc/fixincl $(DESTDIR)$(itoolsdir)/fixincl ; \
++ $(INSTALL_PROGRAM) fixinc/fixincl$(build_exeext) $(DESTDIR)$(itoolsdir)/fixincl$(build_exeext) ; \
+ $(INSTALL_DATA) $(srcdir)/gsyslimits.h \
+ $(DESTDIR)$(itoolsdatadir)/gsyslimits.h ; \
+ else :; fi
+--- gcc-3.4.3/gcc/combine.c
++++ gcc-3.4.3-nios2/gcc/combine.c
+@@ -4380,6 +4380,14 @@ combine_simplify_rtx (rtx x, enum machin
+ mode);
+ }
+
++#ifndef __nios2__
++/* This screws up Nios II in this test case:
++
++if (x & 1)
++ return 2;
++else
++ return 3;
++*/
+ else if (STORE_FLAG_VALUE == 1
+ && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
+ && op1 == const0_rtx
+@@ -4391,6 +4399,7 @@ combine_simplify_rtx (rtx x, enum machin
+ gen_lowpart_for_combine (mode, op0),
+ const1_rtx);
+ }
++#endif
+
+ else if (STORE_FLAG_VALUE == 1
+ && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
+--- gcc-3.4.3/gcc/config/nios2/crti.asm
++++ gcc-3.4.3-nios2/gcc/config/nios2/crti.asm
+@@ -0,0 +1,88 @@
++/*
++ 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)
++ mov fp, sp
++
++
++ .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)
++ mov fp, sp
++
++
+--- gcc-3.4.3/gcc/config/nios2/crtn.asm
++++ gcc-3.4.3-nios2/gcc/config/nios2/crtn.asm
+@@ -0,0 +1,70 @@
++/*
++ 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
++
+--- gcc-3.4.3/gcc/config/nios2/lib2-divmod-hi.c
++++ gcc-3.4.3-nios2/gcc/config/nios2/lib2-divmod-hi.c
+@@ -0,0 +1,123 @@
++
++/* 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"
++
++
++#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"
++
++extern HItype __modhi3 (HItype, HItype);
++extern HItype __divhi3 (HItype, HItype);
++extern HItype __umodhi3 (HItype, HItype);
++extern HItype __udivhi3 (HItype, HItype);
++
++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;
++}
++
++
++HItype
++__udivhi3 (HItype a, HItype b)
++{
++ return udivmodhi4 (a, b, 0);
++}
++
++
++HItype
++__umodhi3 (HItype a, HItype b)
++{
++ return udivmodhi4 (a, b, 1);
++}
++
+--- gcc-3.4.3/gcc/config/nios2/lib2-divmod.c
++++ gcc-3.4.3-nios2/gcc/config/nios2/lib2-divmod.c
+@@ -0,0 +1,126 @@
++
++/* 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"
++
++
++#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"
++
++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);
++}
++
+--- gcc-3.4.3/gcc/config/nios2/lib2-divtable.c
++++ gcc-3.4.3-nios2/gcc/config/nios2/lib2-divtable.c
+@@ -0,0 +1,46 @@
++
++/* 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"
++
++
++#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,
++};
++
+--- gcc-3.4.3/gcc/config/nios2/lib2-mul.c
++++ gcc-3.4.3-nios2/gcc/config/nios2/lib2-mul.c
+@@ -0,0 +1,103 @@
++/* 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"
++
++
++#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"
++
++#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
+--- gcc-3.4.3/gcc/config/nios2/nios2-dp-bit.c
++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2-dp-bit.c
+@@ -0,0 +1,1652 @@
++
++/* This is a software floating point library which can be used
++ for targets without hardware floating point.
++ Copyright (C) 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004
++ Free Software Foundation, Inc.
++
++This file is free software; you can redistribute it and/or modify it
++under the terms of the GNU General Public License as published by 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 other files,
++ some of which are compiled with GCC, to produce an executable,
++ this library does not by itself cause the resulting executable
++ to be covered by the GNU General Public License.
++ This exception does not however invalidate any other reasons why
++ the executable file might be covered by the GNU General Public License. */
++
++/* This implements IEEE 754 format arithmetic, but does not provide a
++ mechanism for setting the rounding mode, or for generating or handling
++ exceptions.
++
++ The original code by Steve Chamberlain, hacked by Mark Eichin and Jim
++ Wilson, all of Cygnus Support. */
++
++/* The intended way to use this file is to make two copies, add `#define FLOAT'
++ to one copy, then compile both copies and add them to libgcc.a. */
++
++#include "tconfig.h"
++#include "coretypes.h"
++#include "tm.h"
++#include "config/fp-bit.h"
++
++/* The following macros can be defined to change the behavior of this file:
++ FLOAT: Implement a `float', aka SFmode, fp library. If this is not
++ defined, then this file implements a `double', aka DFmode, fp library.
++ FLOAT_ONLY: Used with FLOAT, to implement a `float' only library, i.e.
++ don't include float->double conversion which requires the double library.
++ This is useful only for machines which can't support doubles, e.g. some
++ 8-bit processors.
++ CMPtype: Specify the type that floating point compares should return.
++ This defaults to SItype, aka int.
++ US_SOFTWARE_GOFAST: This makes all entry points use the same names as the
++ US Software goFast library.
++ _DEBUG_BITFLOAT: This makes debugging the code a little easier, by adding
++ two integers to the FLO_union_type.
++ NO_DENORMALS: Disable handling of denormals.
++ NO_NANS: Disable nan and infinity handling
++ SMALL_MACHINE: Useful when operations on QIs and HIs are faster
++ than on an SI */
++
++/* We don't currently support extended floats (long doubles) on machines
++ without hardware to deal with them.
++
++ These stubs are just to keep the linker from complaining about unresolved
++ references which can be pulled in from libio & libstdc++, even if the
++ user isn't using long doubles. However, they may generate an unresolved
++ external to abort if abort is not used by the function, and the stubs
++ are referenced from within libc, since libgcc goes before and after the
++ system library. */
++
++#ifdef DECLARE_LIBRARY_RENAMES
++ DECLARE_LIBRARY_RENAMES
++#endif
++
++#ifdef EXTENDED_FLOAT_STUBS
++extern void abort (void);
++void __extendsfxf2 (void) { abort(); }
++void __extenddfxf2 (void) { abort(); }
++void __truncxfdf2 (void) { abort(); }
++void __truncxfsf2 (void) { abort(); }
++void __fixxfsi (void) { abort(); }
++void __floatsixf (void) { abort(); }
++void __addxf3 (void) { abort(); }
++void __subxf3 (void) { abort(); }
++void __mulxf3 (void) { abort(); }
++void __divxf3 (void) { abort(); }
++void __negxf2 (void) { abort(); }
++void __eqxf2 (void) { abort(); }
++void __nexf2 (void) { abort(); }
++void __gtxf2 (void) { abort(); }
++void __gexf2 (void) { abort(); }
++void __lexf2 (void) { abort(); }
++void __ltxf2 (void) { abort(); }
++
++void __extendsftf2 (void) { abort(); }
++void __extenddftf2 (void) { abort(); }
++void __trunctfdf2 (void) { abort(); }
++void __trunctfsf2 (void) { abort(); }
++void __fixtfsi (void) { abort(); }
++void __floatsitf (void) { abort(); }
++void __addtf3 (void) { abort(); }
++void __subtf3 (void) { abort(); }
++void __multf3 (void) { abort(); }
++void __divtf3 (void) { abort(); }
++void __negtf2 (void) { abort(); }
++void __eqtf2 (void) { abort(); }
++void __netf2 (void) { abort(); }
++void __gttf2 (void) { abort(); }
++void __getf2 (void) { abort(); }
++void __letf2 (void) { abort(); }
++void __lttf2 (void) { abort(); }
++#else /* !EXTENDED_FLOAT_STUBS, rest of file */
++
++/* IEEE "special" number predicates */
++
++#ifdef NO_NANS
++
++#define nan() 0
++#define isnan(x) 0
++#define isinf(x) 0
++#else
++
++#if defined L_thenan_sf
++const fp_number_type __thenan_sf = { CLASS_SNAN, 0, 0, {(fractype) 0} };
++#elif defined L_thenan_df
++const fp_number_type __thenan_df = { CLASS_SNAN, 0, 0, {(fractype) 0} };
++#elif defined L_thenan_tf
++const fp_number_type __thenan_tf = { CLASS_SNAN, 0, 0, {(fractype) 0} };
++#elif defined TFLOAT
++extern const fp_number_type __thenan_tf;
++#elif defined FLOAT
++extern const fp_number_type __thenan_sf;
++#else
++extern const fp_number_type __thenan_df;
++#endif
++
++INLINE
++static fp_number_type *
++nan (void)
++{
++ /* Discard the const qualifier... */
++#ifdef TFLOAT
++ return (fp_number_type *) (& __thenan_tf);
++#elif defined FLOAT
++ return (fp_number_type *) (& __thenan_sf);
++#else
++ return (fp_number_type *) (& __thenan_df);
++#endif
++}
++
++INLINE
++static int
++isnan ( fp_number_type * x)
++{
++ return x->class == CLASS_SNAN || x->class == CLASS_QNAN;
++}
++
++INLINE
++static int
++isinf ( fp_number_type * x)
++{
++ return x->class == CLASS_INFINITY;
++}
++
++#endif /* NO_NANS */
++
++INLINE
++static int
++iszero ( fp_number_type * x)
++{
++ return x->class == CLASS_ZERO;
++}
++
++INLINE
++static void
++flip_sign ( fp_number_type * x)
++{
++ x->sign = !x->sign;
++}
++
++extern FLO_type pack_d ( fp_number_type * );
++
++#if defined(L_pack_df) || defined(L_pack_sf) || defined(L_pack_tf)
++FLO_type
++pack_d ( fp_number_type * src)
++{
++ FLO_union_type dst;
++ fractype fraction = src->fraction.ll; /* wasn't unsigned before? */
++ int sign = src->sign;
++ int exp = 0;
++
++ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && (isnan (src) || isinf (src)))
++ {
++ /* We can't represent these values accurately. By using the
++ largest possible magnitude, we guarantee that the conversion
++ of infinity is at least as big as any finite number. */
++ exp = EXPMAX;
++ fraction = ((fractype) 1 << FRACBITS) - 1;
++ }
++ else if (isnan (src))
++ {
++ exp = EXPMAX;
++ if (src->class == CLASS_QNAN || 1)
++ {
++#ifdef QUIET_NAN_NEGATED
++ fraction |= QUIET_NAN - 1;
++#else
++ fraction |= QUIET_NAN;
++#endif
++ }
++ }
++ else if (isinf (src))
++ {
++ exp = EXPMAX;
++ fraction = 0;
++ }
++ else if (iszero (src))
++ {
++ exp = 0;
++ fraction = 0;
++ }
++ else if (fraction == 0)
++ {
++ exp = 0;
++ }
++ else
++ {
++ if (src->normal_exp < NORMAL_EXPMIN)
++ {
++#ifdef NO_DENORMALS
++ /* Go straight to a zero representation if denormals are not
++ supported. The denormal handling would be harmless but
++ isn't unnecessary. */
++ exp = 0;
++ fraction = 0;
++#else /* NO_DENORMALS */
++ /* This number's exponent is too low to fit into the bits
++ available in the number, so we'll store 0 in the exponent and
++ shift the fraction to the right to make up for it. */
++
++ int shift = NORMAL_EXPMIN - src->normal_exp;
++
++ exp = 0;
++
++ if (shift > FRAC_NBITS - NGARDS)
++ {
++ /* No point shifting, since it's more that 64 out. */
++ fraction = 0;
++ }
++ else
++ {
++ int lowbit = (fraction & (((fractype)1 << shift) - 1)) ? 1 : 0;
++ fraction = (fraction >> shift) | lowbit;
++ }
++ if ((fraction & GARDMASK) == GARDMSB)
++ {
++ if ((fraction & (1 << NGARDS)))
++ fraction += GARDROUND + 1;
++ }
++ else
++ {
++ /* Add to the guards to round up. */
++ fraction += GARDROUND;
++ }
++ /* Perhaps the rounding means we now need to change the
++ exponent, because the fraction is no longer denormal. */
++ if (fraction >= IMPLICIT_1)
++ {
++ exp += 1;
++ }
++ fraction >>= NGARDS;
++#endif /* NO_DENORMALS */
++ }
++ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS)
++ && src->normal_exp > EXPBIAS)
++ {
++ exp = EXPMAX;
++ fraction = 0;
++ }
++ else
++ {
++ exp = src->normal_exp + EXPBIAS;
++ if (!ROUND_TOWARDS_ZERO)
++ {
++ /* IF the gard bits are the all zero, but the first, then we're
++ half way between two numbers, choose the one which makes the
++ lsb of the answer 0. */
++ if ((fraction & GARDMASK) == GARDMSB)
++ {
++ if (fraction & (1 << NGARDS))
++ fraction += GARDROUND + 1;
++ }
++ else
++ {
++ /* Add a one to the guards to round up */
++ fraction += GARDROUND;
++ }
++ if (fraction >= IMPLICIT_2)
++ {
++ fraction >>= 1;
++ exp += 1;
++ }
++ }
++ fraction >>= NGARDS;
++
++ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp > EXPMAX)
++ {
++ /* Saturate on overflow. */
++ exp = EXPMAX;
++ fraction = ((fractype) 1 << FRACBITS) - 1;
++ }
++ }
++ }
++
++ /* We previously used bitfields to store the number, but this doesn't
++ handle little/big endian systems conveniently, so use shifts and
++ masks */
++#ifdef FLOAT_BIT_ORDER_MISMATCH
++ dst.bits.fraction = fraction;
++ dst.bits.exp = exp;
++ dst.bits.sign = sign;
++#else
++# if defined TFLOAT && defined HALFFRACBITS
++ {
++ halffractype high, low, unity;
++ int lowsign, lowexp;
++
++ unity = (halffractype) 1 << HALFFRACBITS;
++
++ /* Set HIGH to the high double's significand, masking out the implicit 1.
++ Set LOW to the low double's full significand. */
++ high = (fraction >> (FRACBITS - HALFFRACBITS)) & (unity - 1);
++ low = fraction & (unity * 2 - 1);
++
++ /* Get the initial sign and exponent of the low double. */
++ lowexp = exp - HALFFRACBITS - 1;
++ lowsign = sign;
++
++ /* HIGH should be rounded like a normal double, making |LOW| <=
++ 0.5 ULP of HIGH. Assume round-to-nearest. */
++ if (exp < EXPMAX)
++ if (low > unity || (low == unity && (high & 1) == 1))
++ {
++ /* Round HIGH up and adjust LOW to match. */
++ high++;
++ if (high == unity)
++ {
++ /* May make it infinite, but that's OK. */
++ high = 0;
++ exp++;
++ }
++ low = unity * 2 - low;
++ lowsign ^= 1;
++ }
++
++ high |= (halffractype) exp << HALFFRACBITS;
++ high |= (halffractype) sign << (HALFFRACBITS + EXPBITS);
++
++ if (exp == EXPMAX || exp == 0 || low == 0)
++ low = 0;
++ else
++ {
++ while (lowexp > 0 && low < unity)
++ {
++ low <<= 1;
++ lowexp--;
++ }
++
++ if (lowexp <= 0)
++ {
++ halffractype roundmsb, round;
++ int shift;
++
++ shift = 1 - lowexp;
++ roundmsb = (1 << (shift - 1));
++ round = low & ((roundmsb << 1) - 1);
++
++ low >>= shift;
++ lowexp = 0;
++
++ if (round > roundmsb || (round == roundmsb && (low & 1) == 1))
++ {
++ low++;
++ if (low == unity)
++ /* LOW rounds up to the smallest normal number. */
++ lowexp++;
++ }
++ }
++
++ low &= unity - 1;
++ low |= (halffractype) lowexp << HALFFRACBITS;
++ low |= (halffractype) lowsign << (HALFFRACBITS + EXPBITS);
++ }
++ dst.value_raw = ((fractype) high << HALFSHIFT) | low;
++ }
++# else
++ dst.value_raw = fraction & ((((fractype)1) << FRACBITS) - (fractype)1);
++ dst.value_raw |= ((fractype) (exp & ((1 << EXPBITS) - 1))) << FRACBITS;
++ dst.value_raw |= ((fractype) (sign & 1)) << (FRACBITS | EXPBITS);
++# endif
++#endif
++
++#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT)
++#ifdef TFLOAT
++ {
++ qrtrfractype tmp1 = dst.words[0];
++ qrtrfractype tmp2 = dst.words[1];
++ dst.words[0] = dst.words[3];
++ dst.words[1] = dst.words[2];
++ dst.words[2] = tmp2;
++ dst.words[3] = tmp1;
++ }
++#else
++ {
++ halffractype tmp = dst.words[0];
++ dst.words[0] = dst.words[1];
++ dst.words[1] = tmp;
++ }
++#endif
++#endif
++
++ return dst.value;
++}
++#endif
++
++#if defined(L_unpack_df) || defined(L_unpack_sf) || defined(L_unpack_tf)
++void
++unpack_d (FLO_union_type * src, fp_number_type * dst)
++{
++ /* We previously used bitfields to store the number, but this doesn't
++ handle little/big endian systems conveniently, so use shifts and
++ masks */
++ fractype fraction;
++ int exp;
++ int sign;
++
++#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT)
++ FLO_union_type swapped;
++
++#ifdef TFLOAT
++ swapped.words[0] = src->words[3];
++ swapped.words[1] = src->words[2];
++ swapped.words[2] = src->words[1];
++ swapped.words[3] = src->words[0];
++#else
++ swapped.words[0] = src->words[1];
++ swapped.words[1] = src->words[0];
++#endif
++ src = &swapped;
++#endif
++
++#ifdef FLOAT_BIT_ORDER_MISMATCH
++ fraction = src->bits.fraction;
++ exp = src->bits.exp;
++ sign = src->bits.sign;
++#else
++# if defined TFLOAT && defined HALFFRACBITS
++ {
++ halffractype high, low;
++
++ high = src->value_raw >> HALFSHIFT;
++ low = src->value_raw & (((fractype)1 << HALFSHIFT) - 1);
++
++ fraction = high & ((((fractype)1) << HALFFRACBITS) - 1);
++ fraction <<= FRACBITS - HALFFRACBITS;
++ exp = ((int)(high >> HALFFRACBITS)) & ((1 << EXPBITS) - 1);
++ sign = ((int)(high >> (((HALFFRACBITS + EXPBITS))))) & 1;
++
++ if (exp != EXPMAX && exp != 0 && low != 0)
++ {
++ int lowexp = ((int)(low >> HALFFRACBITS)) & ((1 << EXPBITS) - 1);
++ int lowsign = ((int)(low >> (((HALFFRACBITS + EXPBITS))))) & 1;
++ int shift;
++ fractype xlow;
++
++ xlow = low & ((((fractype)1) << HALFFRACBITS) - 1);
++ if (lowexp)
++ xlow |= (((halffractype)1) << HALFFRACBITS);
++ else
++ lowexp = 1;
++ shift = (FRACBITS - HALFFRACBITS) - (exp - lowexp);
++ if (shift > 0)
++ xlow <<= shift;
++ else if (shift < 0)
++ xlow >>= -shift;
++ if (sign == lowsign)
++ fraction += xlow;
++ else if (fraction >= xlow)
++ fraction -= xlow;
++ else
++ {
++ /* The high part is a power of two but the full number is lower.
++ This code will leave the implicit 1 in FRACTION, but we'd
++ have added that below anyway. */
++ fraction = (((fractype) 1 << FRACBITS) - xlow) << 1;
++ exp--;
++ }
++ }
++ }
++# else
++ fraction = src->value_raw & ((((fractype)1) << FRACBITS) - 1);
++ exp = ((int)(src->value_raw >> FRACBITS)) & ((1 << EXPBITS) - 1);
++ sign = ((int)(src->value_raw >> (FRACBITS + EXPBITS))) & 1;
++# endif
++#endif
++
++ dst->sign = sign;
++ if (exp == 0)
++ {
++ /* Hmm. Looks like 0 */
++ if (fraction == 0
++#ifdef NO_DENORMALS
++ || 1
++#endif
++ )
++ {
++ /* tastes like zero */
++ dst->class = CLASS_ZERO;
++ }
++ else
++ {
++ /* Zero exponent with nonzero fraction - it's denormalized,
++ so there isn't a leading implicit one - we'll shift it so
++ it gets one. */
++ dst->normal_exp = exp - EXPBIAS + 1;
++ fraction <<= NGARDS;
++
++ dst->class = CLASS_NUMBER;
++#if 1
++ while (fraction < IMPLICIT_1)
++ {
++ fraction <<= 1;
++ dst->normal_exp--;
++ }
++#endif
++ dst->fraction.ll = fraction;
++ }
++ }
++ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp == EXPMAX)
++ {
++ /* Huge exponent*/
++ if (fraction == 0)
++ {
++ /* Attached to a zero fraction - means infinity */
++ dst->class = CLASS_INFINITY;
++ }
++ else
++ {
++ /* Nonzero fraction, means nan */
++#ifdef QUIET_NAN_NEGATED
++ if ((fraction & QUIET_NAN) == 0)
++#else
++ if (fraction & QUIET_NAN)
++#endif
++ {
++ dst->class = CLASS_QNAN;
++ }
++ else
++ {
++ dst->class = CLASS_SNAN;
++ }
++ /* Keep the fraction part as the nan number */
++ dst->fraction.ll = fraction;
++ }
++ }
++ else
++ {
++ /* Nothing strange about this number */
++ dst->normal_exp = exp - EXPBIAS;
++ dst->class = CLASS_NUMBER;
++ dst->fraction.ll = (fraction << NGARDS) | IMPLICIT_1;
++ }
++}
++#endif /* L_unpack_df || L_unpack_sf */
++
++#if defined(L_addsub_sf) || defined(L_addsub_df) || defined(L_addsub_tf)
++static fp_number_type *
++_fpadd_parts (fp_number_type * a,
++ fp_number_type * b,
++ fp_number_type * tmp)
++{
++ intfrac tfraction;
++
++ /* Put commonly used fields in local variables. */
++ int a_normal_exp;
++ int b_normal_exp;
++ fractype a_fraction;
++ fractype b_fraction;
++
++ if (isnan (a))
++ {
++ return a;
++ }
++ if (isnan (b))
++ {
++ return b;
++ }
++ if (isinf (a))
++ {
++ /* Adding infinities with opposite signs yields a NaN. */
++ if (isinf (b) && a->sign != b->sign)
++ return nan ();
++ return a;
++ }
++ if (isinf (b))
++ {
++ return b;
++ }
++ if (iszero (b))
++ {
++ if (iszero (a))
++ {
++ *tmp = *a;
++ tmp->sign = a->sign & b->sign;
++ return tmp;
++ }
++ return a;
++ }
++ if (iszero (a))
++ {
++ return b;
++ }
++
++ /* Got two numbers. shift the smaller and increment the exponent till
++ they're the same */
++ {
++ int diff;
++
++ a_normal_exp = a->normal_exp;
++ b_normal_exp = b->normal_exp;
++ a_fraction = a->fraction.ll;
++ b_fraction = b->fraction.ll;
++
++ diff = a_normal_exp - b_normal_exp;
++
++ if (diff < 0)
++ diff = -diff;
++ if (diff < FRAC_NBITS)
++ {
++ /* ??? This does shifts one bit at a time. Optimize. */
++ while (a_normal_exp > b_normal_exp)
++ {
++ b_normal_exp++;
++ LSHIFT (b_fraction);
++ }
++ while (b_normal_exp > a_normal_exp)
++ {
++ a_normal_exp++;
++ LSHIFT (a_fraction);
++ }
++ }
++ else
++ {
++ /* Somethings's up.. choose the biggest */
++ if (a_normal_exp > b_normal_exp)
++ {
++ b_normal_exp = a_normal_exp;
++ b_fraction = 0;
++ }
++ else
++ {
++ a_normal_exp = b_normal_exp;
++ a_fraction = 0;
++ }
++ }
++ }
++
++ if (a->sign != b->sign)
++ {
++ if (a->sign)
++ {
++ tfraction = -a_fraction + b_fraction;
++ }
++ else
++ {
++ tfraction = a_fraction - b_fraction;
++ }
++ if (tfraction >= 0)
++ {
++ tmp->sign = 0;
++ tmp->normal_exp = a_normal_exp;
++ tmp->fraction.ll = tfraction;
++ }
++ else
++ {
++ tmp->sign = 1;
++ tmp->normal_exp = a_normal_exp;
++ tmp->fraction.ll = -tfraction;
++ }
++ /* and renormalize it */
++
++ while (tmp->fraction.ll < IMPLICIT_1 && tmp->fraction.ll)
++ {
++ tmp->fraction.ll <<= 1;
++ tmp->normal_exp--;
++ }
++ }
++ else
++ {
++ tmp->sign = a->sign;
++ tmp->normal_exp = a_normal_exp;
++ tmp->fraction.ll = a_fraction + b_fraction;
++ }
++ tmp->class = CLASS_NUMBER;
++ /* Now the fraction is added, we have to shift down to renormalize the
++ number */
++
++ if (tmp->fraction.ll >= IMPLICIT_2)
++ {
++ LSHIFT (tmp->fraction.ll);
++ tmp->normal_exp++;
++ }
++ return tmp;
++
++}
++
++FLO_type
++add (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ fp_number_type tmp;
++ fp_number_type *res;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ res = _fpadd_parts (&a, &b, &tmp);
++
++ return pack_d (res);
++}
++
++FLO_type
++sub (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ fp_number_type tmp;
++ fp_number_type *res;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ b.sign ^= 1;
++
++ res = _fpadd_parts (&a, &b, &tmp);
++
++ return pack_d (res);
++}
++#endif /* L_addsub_sf || L_addsub_df */
++
++#if defined(L_mul_sf) || defined(L_mul_df) || defined(L_mul_tf)
++static inline __attribute__ ((__always_inline__)) fp_number_type *
++_fpmul_parts ( fp_number_type * a,
++ fp_number_type * b,
++ fp_number_type * tmp)
++{
++ fractype low = 0;
++ fractype high = 0;
++
++ if (isnan (a))
++ {
++ a->sign = a->sign != b->sign;
++ return a;
++ }
++ if (isnan (b))
++ {
++ b->sign = a->sign != b->sign;
++ return b;
++ }
++ if (isinf (a))
++ {
++ if (iszero (b))
++ return nan ();
++ a->sign = a->sign != b->sign;
++ return a;
++ }
++ if (isinf (b))
++ {
++ if (iszero (a))
++ {
++ return nan ();
++ }
++ b->sign = a->sign != b->sign;
++ return b;
++ }
++ if (iszero (a))
++ {
++ a->sign = a->sign != b->sign;
++ return a;
++ }
++ if (iszero (b))
++ {
++ b->sign = a->sign != b->sign;
++ return b;
++ }
++
++ /* Calculate the mantissa by multiplying both numbers to get a
++ twice-as-wide number. */
++ {
++#if defined(NO_DI_MODE) || defined(TFLOAT)
++ {
++ fractype x = a->fraction.ll;
++ fractype ylow = b->fraction.ll;
++ fractype yhigh = 0;
++ int bit;
++
++ /* ??? This does multiplies one bit at a time. Optimize. */
++ for (bit = 0; bit < FRAC_NBITS; bit++)
++ {
++ int carry;
++
++ if (x & 1)
++ {
++ carry = (low += ylow) < ylow;
++ high += yhigh + carry;
++ }
++ yhigh <<= 1;
++ if (ylow & FRACHIGH)
++ {
++ yhigh |= 1;
++ }
++ ylow <<= 1;
++ x >>= 1;
++ }
++ }
++#elif defined(FLOAT)
++ /* Multiplying two USIs to get a UDI, we're safe. */
++ {
++ UDItype answer = (UDItype)a->fraction.ll * (UDItype)b->fraction.ll;
++
++ high = answer >> BITS_PER_SI;
++ low = answer;
++ }
++#else
++ /* fractype is DImode, but we need the result to be twice as wide.
++ Assuming a widening multiply from DImode to TImode is not
++ available, build one by hand. */
++ {
++ USItype nl = a->fraction.ll;
++ USItype nh = a->fraction.ll >> BITS_PER_SI;
++ USItype ml = b->fraction.ll;
++ USItype mh = b->fraction.ll >> BITS_PER_SI;
++ UDItype pp_ll = (UDItype) ml * nl;
++ UDItype pp_hl = (UDItype) mh * nl;
++ UDItype pp_lh = (UDItype) ml * nh;
++ UDItype pp_hh = (UDItype) mh * nh;
++ UDItype res2 = 0;
++ UDItype res0 = 0;
++ UDItype ps_hh__ = pp_hl + pp_lh;
++ if (ps_hh__ < pp_hl)
++ res2 += (UDItype)1 << BITS_PER_SI;
++ pp_hl = (UDItype)(USItype)ps_hh__ << BITS_PER_SI;
++ res0 = pp_ll + pp_hl;
++ if (res0 < pp_ll)
++ res2++;
++ res2 += (ps_hh__ >> BITS_PER_SI) + pp_hh;
++ high = res2;
++ low = res0;
++ }
++#endif
++ }
++
++ tmp->normal_exp = a->normal_exp + b->normal_exp
++ + FRAC_NBITS - (FRACBITS + NGARDS);
++ tmp->sign = a->sign != b->sign;
++ while (high >= IMPLICIT_2)
++ {
++ tmp->normal_exp++;
++ if (high & 1)
++ {
++ low >>= 1;
++ low |= FRACHIGH;
++ }
++ high >>= 1;
++ }
++ while (high < IMPLICIT_1)
++ {
++ tmp->normal_exp--;
++
++ high <<= 1;
++ if (low & FRACHIGH)
++ high |= 1;
++ low <<= 1;
++ }
++ /* rounding is tricky. if we only round if it won't make us round later. */
++#if 0
++ if (low & FRACHIGH2)
++ {
++ if (((high & GARDMASK) != GARDMSB)
++ && (((high + 1) & GARDMASK) == GARDMSB))
++ {
++ /* don't round, it gets done again later. */
++ }
++ else
++ {
++ high++;
++ }
++ }
++#endif
++ if (!ROUND_TOWARDS_ZERO && (high & GARDMASK) == GARDMSB)
++ {
++ if (high & (1 << NGARDS))
++ {
++ /* half way, so round to even */
++ high += GARDROUND + 1;
++ }
++ else if (low)
++ {
++ /* but we really weren't half way */
++ high += GARDROUND + 1;
++ }
++ }
++ tmp->fraction.ll = high;
++ tmp->class = CLASS_NUMBER;
++ return tmp;
++}
++
++FLO_type
++multiply (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ fp_number_type tmp;
++ fp_number_type *res;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ res = _fpmul_parts (&a, &b, &tmp);
++
++ return pack_d (res);
++}
++#endif /* L_mul_sf || L_mul_df */
++
++#if defined(L_div_sf) || defined(L_div_df) || defined(L_div_tf)
++static inline __attribute__ ((__always_inline__)) fp_number_type *
++_fpdiv_parts (fp_number_type * a,
++ fp_number_type * b)
++{
++ fractype bit;
++ fractype numerator;
++ fractype denominator;
++ fractype quotient;
++
++ if (isnan (a))
++ {
++ return a;
++ }
++ if (isnan (b))
++ {
++ return b;
++ }
++
++ a->sign = a->sign ^ b->sign;
++
++ if (isinf (a) || iszero (a))
++ {
++ if (a->class == b->class)
++ return nan ();
++ return a;
++ }
++
++ if (isinf (b))
++ {
++ a->fraction.ll = 0;
++ a->normal_exp = 0;
++ return a;
++ }
++ if (iszero (b))
++ {
++ a->class = CLASS_INFINITY;
++ return a;
++ }
++
++ /* Calculate the mantissa by multiplying both 64bit numbers to get a
++ 128 bit number */
++ {
++ /* quotient =
++ ( numerator / denominator) * 2^(numerator exponent - denominator exponent)
++ */
++
++ a->normal_exp = a->normal_exp - b->normal_exp;
++ numerator = a->fraction.ll;
++ denominator = b->fraction.ll;
++
++ if (numerator < denominator)
++ {
++ /* Fraction will be less than 1.0 */
++ numerator *= 2;
++ a->normal_exp--;
++ }
++ bit = IMPLICIT_1;
++ quotient = 0;
++ /* ??? Does divide one bit at a time. Optimize. */
++ while (bit)
++ {
++ if (numerator >= denominator)
++ {
++ quotient |= bit;
++ numerator -= denominator;
++ }
++ bit >>= 1;
++ numerator *= 2;
++ }
++
++ if (!ROUND_TOWARDS_ZERO && (quotient & GARDMASK) == GARDMSB)
++ {
++ if (quotient & (1 << NGARDS))
++ {
++ /* half way, so round to even */
++ quotient += GARDROUND + 1;
++ }
++ else if (numerator)
++ {
++ /* but we really weren't half way, more bits exist */
++ quotient += GARDROUND + 1;
++ }
++ }
++
++ a->fraction.ll = quotient;
++ return (a);
++ }
++}
++
++FLO_type
++divide (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ fp_number_type *res;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ res = _fpdiv_parts (&a, &b);
++
++ return pack_d (res);
++}
++#endif /* L_div_sf || L_div_df */
++
++#if defined(L_fpcmp_parts_sf) || defined(L_fpcmp_parts_df) \
++ || defined(L_fpcmp_parts_tf)
++/* according to the demo, fpcmp returns a comparison with 0... thus
++ a<b -> -1
++ a==b -> 0
++ a>b -> +1
++ */
++
++int
++__fpcmp_parts (fp_number_type * a, fp_number_type * b)
++{
++#if 0
++ /* either nan -> unordered. Must be checked outside of this routine. */
++ if (isnan (a) && isnan (b))
++ {
++ return 1; /* still unordered! */
++ }
++#endif
++
++ if (isnan (a) || isnan (b))
++ {
++ return 1; /* how to indicate unordered compare? */
++ }
++ if (isinf (a) && isinf (b))
++ {
++ /* +inf > -inf, but +inf != +inf */
++ /* b \a| +inf(0)| -inf(1)
++ ______\+--------+--------
++ +inf(0)| a==b(0)| a<b(-1)
++ -------+--------+--------
++ -inf(1)| a>b(1) | a==b(0)
++ -------+--------+--------
++ So since unordered must be nonzero, just line up the columns...
++ */
++ return b->sign - a->sign;
++ }
++ /* but not both... */
++ if (isinf (a))
++ {
++ return a->sign ? -1 : 1;
++ }
++ if (isinf (b))
++ {
++ return b->sign ? 1 : -1;
++ }
++ if (iszero (a) && iszero (b))
++ {
++ return 0;
++ }
++ if (iszero (a))
++ {
++ return b->sign ? 1 : -1;
++ }
++ if (iszero (b))
++ {
++ return a->sign ? -1 : 1;
++ }
++ /* now both are "normal". */
++ if (a->sign != b->sign)
++ {
++ /* opposite signs */
++ return a->sign ? -1 : 1;
++ }
++ /* same sign; exponents? */
++ if (a->normal_exp > b->normal_exp)
++ {
++ return a->sign ? -1 : 1;
++ }
++ if (a->normal_exp < b->normal_exp)
++ {
++ return a->sign ? 1 : -1;
++ }
++ /* same exponents; check size. */
++ if (a->fraction.ll > b->fraction.ll)
++ {
++ return a->sign ? -1 : 1;
++ }
++ if (a->fraction.ll < b->fraction.ll)
++ {
++ return a->sign ? 1 : -1;
++ }
++ /* after all that, they're equal. */
++ return 0;
++}
++#endif
++
++#if defined(L_compare_sf) || defined(L_compare_df) || defined(L_compoare_tf)
++CMPtype
++compare (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ return __fpcmp_parts (&a, &b);
++}
++#endif /* L_compare_sf || L_compare_df */
++
++#ifndef US_SOFTWARE_GOFAST
++
++/* These should be optimized for their specific tasks someday. */
++
++#if defined(L_eq_sf) || defined(L_eq_df) || defined(L_eq_tf)
++CMPtype
++_eq_f2 (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ if (isnan (&a) || isnan (&b))
++ return 1; /* false, truth == 0 */
++
++ return __fpcmp_parts (&a, &b) ;
++}
++#endif /* L_eq_sf || L_eq_df */
++
++#if defined(L_ne_sf) || defined(L_ne_df) || defined(L_ne_tf)
++CMPtype
++_ne_f2 (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ if (isnan (&a) || isnan (&b))
++ return 1; /* true, truth != 0 */
++
++ return __fpcmp_parts (&a, &b) ;
++}
++#endif /* L_ne_sf || L_ne_df */
++
++#if defined(L_gt_sf) || defined(L_gt_df) || defined(L_gt_tf)
++CMPtype
++_gt_f2 (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ if (isnan (&a) || isnan (&b))
++ return -1; /* false, truth > 0 */
++
++ return __fpcmp_parts (&a, &b);
++}
++#endif /* L_gt_sf || L_gt_df */
++
++#if defined(L_ge_sf) || defined(L_ge_df) || defined(L_ge_tf)
++CMPtype
++_ge_f2 (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ if (isnan (&a) || isnan (&b))
++ return -1; /* false, truth >= 0 */
++ return __fpcmp_parts (&a, &b) ;
++}
++#endif /* L_ge_sf || L_ge_df */
++
++#if defined(L_lt_sf) || defined(L_lt_df) || defined(L_lt_tf)
++CMPtype
++_lt_f2 (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ if (isnan (&a) || isnan (&b))
++ return 1; /* false, truth < 0 */
++
++ return __fpcmp_parts (&a, &b);
++}
++#endif /* L_lt_sf || L_lt_df */
++
++#if defined(L_le_sf) || defined(L_le_df) || defined(L_le_tf)
++CMPtype
++_le_f2 (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ if (isnan (&a) || isnan (&b))
++ return 1; /* false, truth <= 0 */
++
++ return __fpcmp_parts (&a, &b) ;
++}
++#endif /* L_le_sf || L_le_df */
++
++#endif /* ! US_SOFTWARE_GOFAST */
++
++#if defined(L_unord_sf) || defined(L_unord_df) || defined(L_unord_tf)
++CMPtype
++_unord_f2 (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ return (isnan (&a) || isnan (&b));
++}
++#endif /* L_unord_sf || L_unord_df */
++
++#if defined(L_si_to_sf) || defined(L_si_to_df) || defined(L_si_to_tf)
++FLO_type
++si_to_float (SItype arg_a)
++{
++ fp_number_type in;
++
++ in.class = CLASS_NUMBER;
++ in.sign = arg_a < 0;
++ if (!arg_a)
++ {
++ in.class = CLASS_ZERO;
++ }
++ else
++ {
++ in.normal_exp = FRACBITS + NGARDS;
++ if (in.sign)
++ {
++ /* Special case for minint, since there is no +ve integer
++ representation for it */
++ if (arg_a == (- MAX_SI_INT - 1))
++ {
++ return (FLO_type)(- MAX_SI_INT - 1);
++ }
++ in.fraction.ll = (-arg_a);
++ }
++ else
++ in.fraction.ll = arg_a;
++
++ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS)))
++ {
++ in.fraction.ll <<= 1;
++ in.normal_exp -= 1;
++ }
++ }
++ return pack_d (&in);
++}
++#endif /* L_si_to_sf || L_si_to_df */
++
++#if defined(L_usi_to_sf) || defined(L_usi_to_df) || defined(L_usi_to_tf)
++FLO_type
++usi_to_float (USItype arg_a)
++{
++ fp_number_type in;
++
++ in.sign = 0;
++ if (!arg_a)
++ {
++ in.class = CLASS_ZERO;
++ }
++ else
++ {
++ in.class = CLASS_NUMBER;
++ in.normal_exp = FRACBITS + NGARDS;
++ in.fraction.ll = arg_a;
++
++ while (in.fraction.ll > ((fractype)1 << (FRACBITS + NGARDS)))
++ {
++ in.fraction.ll >>= 1;
++ in.normal_exp += 1;
++ }
++ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS)))
++ {
++ in.fraction.ll <<= 1;
++ in.normal_exp -= 1;
++ }
++ }
++ return pack_d (&in);
++}
++#endif
++
++#if defined(L_sf_to_si) || defined(L_df_to_si) || defined(L_tf_to_si)
++SItype
++float_to_si (FLO_type arg_a)
++{
++ fp_number_type a;
++ SItype tmp;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &a);
++
++ if (iszero (&a))
++ return 0;
++ if (isnan (&a))
++ return 0;
++ /* get reasonable MAX_SI_INT... */
++ if (isinf (&a))
++ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT;
++ /* it is a number, but a small one */
++ if (a.normal_exp < 0)
++ return 0;
++ if (a.normal_exp > BITS_PER_SI - 2)
++ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT;
++ tmp = a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp);
++ return a.sign ? (-tmp) : (tmp);
++}
++#endif /* L_sf_to_si || L_df_to_si */
++
++#if defined(L_sf_to_usi) || defined(L_df_to_usi) || defined(L_tf_to_usi)
++#if defined US_SOFTWARE_GOFAST || defined(L_tf_to_usi)
++/* While libgcc2.c defines its own __fixunssfsi and __fixunsdfsi routines,
++ we also define them for GOFAST because the ones in libgcc2.c have the
++ wrong names and I'd rather define these here and keep GOFAST CYG-LOC's
++ out of libgcc2.c. We can't define these here if not GOFAST because then
++ there'd be duplicate copies. */
++
++USItype
++float_to_usi (FLO_type arg_a)
++{
++ fp_number_type a;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &a);
++
++ if (iszero (&a))
++ return 0;
++ if (isnan (&a))
++ return 0;
++ /* it is a negative number */
++ if (a.sign)
++ return 0;
++ /* get reasonable MAX_USI_INT... */
++ if (isinf (&a))
++ return MAX_USI_INT;
++ /* it is a number, but a small one */
++ if (a.normal_exp < 0)
++ return 0;
++ if (a.normal_exp > BITS_PER_SI - 1)
++ return MAX_USI_INT;
++ else if (a.normal_exp > (FRACBITS + NGARDS))
++ return a.fraction.ll << (a.normal_exp - (FRACBITS + NGARDS));
++ else
++ return a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp);
++}
++#endif /* US_SOFTWARE_GOFAST */
++#endif /* L_sf_to_usi || L_df_to_usi */
++
++#if defined(L_negate_sf) || defined(L_negate_df) || defined(L_negate_tf)
++FLO_type
++negate (FLO_type arg_a)
++{
++ fp_number_type a;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &a);
++
++ flip_sign (&a);
++ return pack_d (&a);
++}
++#endif /* L_negate_sf || L_negate_df */
++
++#ifdef FLOAT
++
++#if defined(L_make_sf)
++SFtype
++__make_fp(fp_class_type class,
++ unsigned int sign,
++ int exp,
++ USItype frac)
++{
++ fp_number_type in;
++
++ in.class = class;
++ in.sign = sign;
++ in.normal_exp = exp;
++ in.fraction.ll = frac;
++ return pack_d (&in);
++}
++#endif /* L_make_sf */
++
++#ifndef FLOAT_ONLY
++
++/* This enables one to build an fp library that supports float but not double.
++ Otherwise, we would get an undefined reference to __make_dp.
++ This is needed for some 8-bit ports that can't handle well values that
++ are 8-bytes in size, so we just don't support double for them at all. */
++
++#if defined(L_sf_to_df)
++DFtype
++sf_to_df (SFtype arg_a)
++{
++ fp_number_type in;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &in);
++
++ return __make_dp (in.class, in.sign, in.normal_exp,
++ ((UDItype) in.fraction.ll) << F_D_BITOFF);
++}
++#endif /* L_sf_to_df */
++
++#if defined(L_sf_to_tf) && defined(TMODES)
++TFtype
++sf_to_tf (SFtype arg_a)
++{
++ fp_number_type in;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &in);
++
++ return __make_tp (in.class, in.sign, in.normal_exp,
++ ((UTItype) in.fraction.ll) << F_T_BITOFF);
++}
++#endif /* L_sf_to_df */
++
++#endif /* ! FLOAT_ONLY */
++#endif /* FLOAT */
++
++#ifndef FLOAT
++
++extern SFtype __make_fp (fp_class_type, unsigned int, int, USItype);
++
++#if defined(L_make_df)
++DFtype
++__make_dp (fp_class_type class, unsigned int sign, int exp, UDItype frac)
++{
++ fp_number_type in;
++
++ in.class = class;
++ in.sign = sign;
++ in.normal_exp = exp;
++ in.fraction.ll = frac;
++ return pack_d (&in);
++}
++#endif /* L_make_df */
++
++#if defined(L_df_to_sf)
++SFtype
++df_to_sf (DFtype arg_a)
++{
++ fp_number_type in;
++ USItype sffrac;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &in);
++
++ sffrac = in.fraction.ll >> F_D_BITOFF;
++
++ /* We set the lowest guard bit in SFFRAC if we discarded any non
++ zero bits. */
++ if ((in.fraction.ll & (((USItype) 1 << F_D_BITOFF) - 1)) != 0)
++ sffrac |= 1;
++
++ return __make_fp (in.class, in.sign, in.normal_exp, sffrac);
++}
++#endif /* L_df_to_sf */
++
++#if defined(L_df_to_tf) && defined(TMODES) \
++ && !defined(FLOAT) && !defined(TFLOAT)
++TFtype
++df_to_tf (DFtype arg_a)
++{
++ fp_number_type in;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &in);
++
++ return __make_tp (in.class, in.sign, in.normal_exp,
++ ((UTItype) in.fraction.ll) << D_T_BITOFF);
++}
++#endif /* L_sf_to_df */
++
++#ifdef TFLOAT
++#if defined(L_make_tf)
++TFtype
++__make_tp(fp_class_type class,
++ unsigned int sign,
++ int exp,
++ UTItype frac)
++{
++ fp_number_type in;
++
++ in.class = class;
++ in.sign = sign;
++ in.normal_exp = exp;
++ in.fraction.ll = frac;
++ return pack_d (&in);
++}
++#endif /* L_make_tf */
++
++#if defined(L_tf_to_df)
++DFtype
++tf_to_df (TFtype arg_a)
++{
++ fp_number_type in;
++ UDItype sffrac;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &in);
++
++ sffrac = in.fraction.ll >> D_T_BITOFF;
++
++ /* We set the lowest guard bit in SFFRAC if we discarded any non
++ zero bits. */
++ if ((in.fraction.ll & (((UTItype) 1 << D_T_BITOFF) - 1)) != 0)
++ sffrac |= 1;
++
++ return __make_dp (in.class, in.sign, in.normal_exp, sffrac);
++}
++#endif /* L_tf_to_df */
++
++#if defined(L_tf_to_sf)
++SFtype
++tf_to_sf (TFtype arg_a)
++{
++ fp_number_type in;
++ USItype sffrac;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &in);
++
++ sffrac = in.fraction.ll >> F_T_BITOFF;
++
++ /* We set the lowest guard bit in SFFRAC if we discarded any non
++ zero bits. */
++ if ((in.fraction.ll & (((UTItype) 1 << F_T_BITOFF) - 1)) != 0)
++ sffrac |= 1;
++
++ return __make_fp (in.class, in.sign, in.normal_exp, sffrac);
++}
++#endif /* L_tf_to_sf */
++#endif /* TFLOAT */
++
++#endif /* ! FLOAT */
++#endif /* !EXTENDED_FLOAT_STUBS */
+--- gcc-3.4.3/gcc/config/nios2/nios2-fp-bit.c
++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2-fp-bit.c
+@@ -0,0 +1,1652 @@
++#define FLOAT
++/* This is a software floating point library which can be used
++ for targets without hardware floating point.
++ Copyright (C) 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004
++ Free Software Foundation, Inc.
++
++This file is free software; you can redistribute it and/or modify it
++under the terms of the GNU General Public License as published by 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 other files,
++ some of which are compiled with GCC, to produce an executable,
++ this library does not by itself cause the resulting executable
++ to be covered by the GNU General Public License.
++ This exception does not however invalidate any other reasons why
++ the executable file might be covered by the GNU General Public License. */
++
++/* This implements IEEE 754 format arithmetic, but does not provide a
++ mechanism for setting the rounding mode, or for generating or handling
++ exceptions.
++
++ The original code by Steve Chamberlain, hacked by Mark Eichin and Jim
++ Wilson, all of Cygnus Support. */
++
++/* The intended way to use this file is to make two copies, add `#define FLOAT'
++ to one copy, then compile both copies and add them to libgcc.a. */
++
++#include "tconfig.h"
++#include "coretypes.h"
++#include "tm.h"
++#include "config/fp-bit.h"
++
++/* The following macros can be defined to change the behavior of this file:
++ FLOAT: Implement a `float', aka SFmode, fp library. If this is not
++ defined, then this file implements a `double', aka DFmode, fp library.
++ FLOAT_ONLY: Used with FLOAT, to implement a `float' only library, i.e.
++ don't include float->double conversion which requires the double library.
++ This is useful only for machines which can't support doubles, e.g. some
++ 8-bit processors.
++ CMPtype: Specify the type that floating point compares should return.
++ This defaults to SItype, aka int.
++ US_SOFTWARE_GOFAST: This makes all entry points use the same names as the
++ US Software goFast library.
++ _DEBUG_BITFLOAT: This makes debugging the code a little easier, by adding
++ two integers to the FLO_union_type.
++ NO_DENORMALS: Disable handling of denormals.
++ NO_NANS: Disable nan and infinity handling
++ SMALL_MACHINE: Useful when operations on QIs and HIs are faster
++ than on an SI */
++
++/* We don't currently support extended floats (long doubles) on machines
++ without hardware to deal with them.
++
++ These stubs are just to keep the linker from complaining about unresolved
++ references which can be pulled in from libio & libstdc++, even if the
++ user isn't using long doubles. However, they may generate an unresolved
++ external to abort if abort is not used by the function, and the stubs
++ are referenced from within libc, since libgcc goes before and after the
++ system library. */
++
++#ifdef DECLARE_LIBRARY_RENAMES
++ DECLARE_LIBRARY_RENAMES
++#endif
++
++#ifdef EXTENDED_FLOAT_STUBS
++extern void abort (void);
++void __extendsfxf2 (void) { abort(); }
++void __extenddfxf2 (void) { abort(); }
++void __truncxfdf2 (void) { abort(); }
++void __truncxfsf2 (void) { abort(); }
++void __fixxfsi (void) { abort(); }
++void __floatsixf (void) { abort(); }
++void __addxf3 (void) { abort(); }
++void __subxf3 (void) { abort(); }
++void __mulxf3 (void) { abort(); }
++void __divxf3 (void) { abort(); }
++void __negxf2 (void) { abort(); }
++void __eqxf2 (void) { abort(); }
++void __nexf2 (void) { abort(); }
++void __gtxf2 (void) { abort(); }
++void __gexf2 (void) { abort(); }
++void __lexf2 (void) { abort(); }
++void __ltxf2 (void) { abort(); }
++
++void __extendsftf2 (void) { abort(); }
++void __extenddftf2 (void) { abort(); }
++void __trunctfdf2 (void) { abort(); }
++void __trunctfsf2 (void) { abort(); }
++void __fixtfsi (void) { abort(); }
++void __floatsitf (void) { abort(); }
++void __addtf3 (void) { abort(); }
++void __subtf3 (void) { abort(); }
++void __multf3 (void) { abort(); }
++void __divtf3 (void) { abort(); }
++void __negtf2 (void) { abort(); }
++void __eqtf2 (void) { abort(); }
++void __netf2 (void) { abort(); }
++void __gttf2 (void) { abort(); }
++void __getf2 (void) { abort(); }
++void __letf2 (void) { abort(); }
++void __lttf2 (void) { abort(); }
++#else /* !EXTENDED_FLOAT_STUBS, rest of file */
++
++/* IEEE "special" number predicates */
++
++#ifdef NO_NANS
++
++#define nan() 0
++#define isnan(x) 0
++#define isinf(x) 0
++#else
++
++#if defined L_thenan_sf
++const fp_number_type __thenan_sf = { CLASS_SNAN, 0, 0, {(fractype) 0} };
++#elif defined L_thenan_df
++const fp_number_type __thenan_df = { CLASS_SNAN, 0, 0, {(fractype) 0} };
++#elif defined L_thenan_tf
++const fp_number_type __thenan_tf = { CLASS_SNAN, 0, 0, {(fractype) 0} };
++#elif defined TFLOAT
++extern const fp_number_type __thenan_tf;
++#elif defined FLOAT
++extern const fp_number_type __thenan_sf;
++#else
++extern const fp_number_type __thenan_df;
++#endif
++
++INLINE
++static fp_number_type *
++nan (void)
++{
++ /* Discard the const qualifier... */
++#ifdef TFLOAT
++ return (fp_number_type *) (& __thenan_tf);
++#elif defined FLOAT
++ return (fp_number_type *) (& __thenan_sf);
++#else
++ return (fp_number_type *) (& __thenan_df);
++#endif
++}
++
++INLINE
++static int
++isnan ( fp_number_type * x)
++{
++ return x->class == CLASS_SNAN || x->class == CLASS_QNAN;
++}
++
++INLINE
++static int
++isinf ( fp_number_type * x)
++{
++ return x->class == CLASS_INFINITY;
++}
++
++#endif /* NO_NANS */
++
++INLINE
++static int
++iszero ( fp_number_type * x)
++{
++ return x->class == CLASS_ZERO;
++}
++
++INLINE
++static void
++flip_sign ( fp_number_type * x)
++{
++ x->sign = !x->sign;
++}
++
++extern FLO_type pack_d ( fp_number_type * );
++
++#if defined(L_pack_df) || defined(L_pack_sf) || defined(L_pack_tf)
++FLO_type
++pack_d ( fp_number_type * src)
++{
++ FLO_union_type dst;
++ fractype fraction = src->fraction.ll; /* wasn't unsigned before? */
++ int sign = src->sign;
++ int exp = 0;
++
++ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && (isnan (src) || isinf (src)))
++ {
++ /* We can't represent these values accurately. By using the
++ largest possible magnitude, we guarantee that the conversion
++ of infinity is at least as big as any finite number. */
++ exp = EXPMAX;
++ fraction = ((fractype) 1 << FRACBITS) - 1;
++ }
++ else if (isnan (src))
++ {
++ exp = EXPMAX;
++ if (src->class == CLASS_QNAN || 1)
++ {
++#ifdef QUIET_NAN_NEGATED
++ fraction |= QUIET_NAN - 1;
++#else
++ fraction |= QUIET_NAN;
++#endif
++ }
++ }
++ else if (isinf (src))
++ {
++ exp = EXPMAX;
++ fraction = 0;
++ }
++ else if (iszero (src))
++ {
++ exp = 0;
++ fraction = 0;
++ }
++ else if (fraction == 0)
++ {
++ exp = 0;
++ }
++ else
++ {
++ if (src->normal_exp < NORMAL_EXPMIN)
++ {
++#ifdef NO_DENORMALS
++ /* Go straight to a zero representation if denormals are not
++ supported. The denormal handling would be harmless but
++ isn't unnecessary. */
++ exp = 0;
++ fraction = 0;
++#else /* NO_DENORMALS */
++ /* This number's exponent is too low to fit into the bits
++ available in the number, so we'll store 0 in the exponent and
++ shift the fraction to the right to make up for it. */
++
++ int shift = NORMAL_EXPMIN - src->normal_exp;
++
++ exp = 0;
++
++ if (shift > FRAC_NBITS - NGARDS)
++ {
++ /* No point shifting, since it's more that 64 out. */
++ fraction = 0;
++ }
++ else
++ {
++ int lowbit = (fraction & (((fractype)1 << shift) - 1)) ? 1 : 0;
++ fraction = (fraction >> shift) | lowbit;
++ }
++ if ((fraction & GARDMASK) == GARDMSB)
++ {
++ if ((fraction & (1 << NGARDS)))
++ fraction += GARDROUND + 1;
++ }
++ else
++ {
++ /* Add to the guards to round up. */
++ fraction += GARDROUND;
++ }
++ /* Perhaps the rounding means we now need to change the
++ exponent, because the fraction is no longer denormal. */
++ if (fraction >= IMPLICIT_1)
++ {
++ exp += 1;
++ }
++ fraction >>= NGARDS;
++#endif /* NO_DENORMALS */
++ }
++ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS)
++ && src->normal_exp > EXPBIAS)
++ {
++ exp = EXPMAX;
++ fraction = 0;
++ }
++ else
++ {
++ exp = src->normal_exp + EXPBIAS;
++ if (!ROUND_TOWARDS_ZERO)
++ {
++ /* IF the gard bits are the all zero, but the first, then we're
++ half way between two numbers, choose the one which makes the
++ lsb of the answer 0. */
++ if ((fraction & GARDMASK) == GARDMSB)
++ {
++ if (fraction & (1 << NGARDS))
++ fraction += GARDROUND + 1;
++ }
++ else
++ {
++ /* Add a one to the guards to round up */
++ fraction += GARDROUND;
++ }
++ if (fraction >= IMPLICIT_2)
++ {
++ fraction >>= 1;
++ exp += 1;
++ }
++ }
++ fraction >>= NGARDS;
++
++ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp > EXPMAX)
++ {
++ /* Saturate on overflow. */
++ exp = EXPMAX;
++ fraction = ((fractype) 1 << FRACBITS) - 1;
++ }
++ }
++ }
++
++ /* We previously used bitfields to store the number, but this doesn't
++ handle little/big endian systems conveniently, so use shifts and
++ masks */
++#ifdef FLOAT_BIT_ORDER_MISMATCH
++ dst.bits.fraction = fraction;
++ dst.bits.exp = exp;
++ dst.bits.sign = sign;
++#else
++# if defined TFLOAT && defined HALFFRACBITS
++ {
++ halffractype high, low, unity;
++ int lowsign, lowexp;
++
++ unity = (halffractype) 1 << HALFFRACBITS;
++
++ /* Set HIGH to the high double's significand, masking out the implicit 1.
++ Set LOW to the low double's full significand. */
++ high = (fraction >> (FRACBITS - HALFFRACBITS)) & (unity - 1);
++ low = fraction & (unity * 2 - 1);
++
++ /* Get the initial sign and exponent of the low double. */
++ lowexp = exp - HALFFRACBITS - 1;
++ lowsign = sign;
++
++ /* HIGH should be rounded like a normal double, making |LOW| <=
++ 0.5 ULP of HIGH. Assume round-to-nearest. */
++ if (exp < EXPMAX)
++ if (low > unity || (low == unity && (high & 1) == 1))
++ {
++ /* Round HIGH up and adjust LOW to match. */
++ high++;
++ if (high == unity)
++ {
++ /* May make it infinite, but that's OK. */
++ high = 0;
++ exp++;
++ }
++ low = unity * 2 - low;
++ lowsign ^= 1;
++ }
++
++ high |= (halffractype) exp << HALFFRACBITS;
++ high |= (halffractype) sign << (HALFFRACBITS + EXPBITS);
++
++ if (exp == EXPMAX || exp == 0 || low == 0)
++ low = 0;
++ else
++ {
++ while (lowexp > 0 && low < unity)
++ {
++ low <<= 1;
++ lowexp--;
++ }
++
++ if (lowexp <= 0)
++ {
++ halffractype roundmsb, round;
++ int shift;
++
++ shift = 1 - lowexp;
++ roundmsb = (1 << (shift - 1));
++ round = low & ((roundmsb << 1) - 1);
++
++ low >>= shift;
++ lowexp = 0;
++
++ if (round > roundmsb || (round == roundmsb && (low & 1) == 1))
++ {
++ low++;
++ if (low == unity)
++ /* LOW rounds up to the smallest normal number. */
++ lowexp++;
++ }
++ }
++
++ low &= unity - 1;
++ low |= (halffractype) lowexp << HALFFRACBITS;
++ low |= (halffractype) lowsign << (HALFFRACBITS + EXPBITS);
++ }
++ dst.value_raw = ((fractype) high << HALFSHIFT) | low;
++ }
++# else
++ dst.value_raw = fraction & ((((fractype)1) << FRACBITS) - (fractype)1);
++ dst.value_raw |= ((fractype) (exp & ((1 << EXPBITS) - 1))) << FRACBITS;
++ dst.value_raw |= ((fractype) (sign & 1)) << (FRACBITS | EXPBITS);
++# endif
++#endif
++
++#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT)
++#ifdef TFLOAT
++ {
++ qrtrfractype tmp1 = dst.words[0];
++ qrtrfractype tmp2 = dst.words[1];
++ dst.words[0] = dst.words[3];
++ dst.words[1] = dst.words[2];
++ dst.words[2] = tmp2;
++ dst.words[3] = tmp1;
++ }
++#else
++ {
++ halffractype tmp = dst.words[0];
++ dst.words[0] = dst.words[1];
++ dst.words[1] = tmp;
++ }
++#endif
++#endif
++
++ return dst.value;
++}
++#endif
++
++#if defined(L_unpack_df) || defined(L_unpack_sf) || defined(L_unpack_tf)
++void
++unpack_d (FLO_union_type * src, fp_number_type * dst)
++{
++ /* We previously used bitfields to store the number, but this doesn't
++ handle little/big endian systems conveniently, so use shifts and
++ masks */
++ fractype fraction;
++ int exp;
++ int sign;
++
++#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT)
++ FLO_union_type swapped;
++
++#ifdef TFLOAT
++ swapped.words[0] = src->words[3];
++ swapped.words[1] = src->words[2];
++ swapped.words[2] = src->words[1];
++ swapped.words[3] = src->words[0];
++#else
++ swapped.words[0] = src->words[1];
++ swapped.words[1] = src->words[0];
++#endif
++ src = &swapped;
++#endif
++
++#ifdef FLOAT_BIT_ORDER_MISMATCH
++ fraction = src->bits.fraction;
++ exp = src->bits.exp;
++ sign = src->bits.sign;
++#else
++# if defined TFLOAT && defined HALFFRACBITS
++ {
++ halffractype high, low;
++
++ high = src->value_raw >> HALFSHIFT;
++ low = src->value_raw & (((fractype)1 << HALFSHIFT) - 1);
++
++ fraction = high & ((((fractype)1) << HALFFRACBITS) - 1);
++ fraction <<= FRACBITS - HALFFRACBITS;
++ exp = ((int)(high >> HALFFRACBITS)) & ((1 << EXPBITS) - 1);
++ sign = ((int)(high >> (((HALFFRACBITS + EXPBITS))))) & 1;
++
++ if (exp != EXPMAX && exp != 0 && low != 0)
++ {
++ int lowexp = ((int)(low >> HALFFRACBITS)) & ((1 << EXPBITS) - 1);
++ int lowsign = ((int)(low >> (((HALFFRACBITS + EXPBITS))))) & 1;
++ int shift;
++ fractype xlow;
++
++ xlow = low & ((((fractype)1) << HALFFRACBITS) - 1);
++ if (lowexp)
++ xlow |= (((halffractype)1) << HALFFRACBITS);
++ else
++ lowexp = 1;
++ shift = (FRACBITS - HALFFRACBITS) - (exp - lowexp);
++ if (shift > 0)
++ xlow <<= shift;
++ else if (shift < 0)
++ xlow >>= -shift;
++ if (sign == lowsign)
++ fraction += xlow;
++ else if (fraction >= xlow)
++ fraction -= xlow;
++ else
++ {
++ /* The high part is a power of two but the full number is lower.
++ This code will leave the implicit 1 in FRACTION, but we'd
++ have added that below anyway. */
++ fraction = (((fractype) 1 << FRACBITS) - xlow) << 1;
++ exp--;
++ }
++ }
++ }
++# else
++ fraction = src->value_raw & ((((fractype)1) << FRACBITS) - 1);
++ exp = ((int)(src->value_raw >> FRACBITS)) & ((1 << EXPBITS) - 1);
++ sign = ((int)(src->value_raw >> (FRACBITS + EXPBITS))) & 1;
++# endif
++#endif
++
++ dst->sign = sign;
++ if (exp == 0)
++ {
++ /* Hmm. Looks like 0 */
++ if (fraction == 0
++#ifdef NO_DENORMALS
++ || 1
++#endif
++ )
++ {
++ /* tastes like zero */
++ dst->class = CLASS_ZERO;
++ }
++ else
++ {
++ /* Zero exponent with nonzero fraction - it's denormalized,
++ so there isn't a leading implicit one - we'll shift it so
++ it gets one. */
++ dst->normal_exp = exp - EXPBIAS + 1;
++ fraction <<= NGARDS;
++
++ dst->class = CLASS_NUMBER;
++#if 1
++ while (fraction < IMPLICIT_1)
++ {
++ fraction <<= 1;
++ dst->normal_exp--;
++ }
++#endif
++ dst->fraction.ll = fraction;
++ }
++ }
++ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp == EXPMAX)
++ {
++ /* Huge exponent*/
++ if (fraction == 0)
++ {
++ /* Attached to a zero fraction - means infinity */
++ dst->class = CLASS_INFINITY;
++ }
++ else
++ {
++ /* Nonzero fraction, means nan */
++#ifdef QUIET_NAN_NEGATED
++ if ((fraction & QUIET_NAN) == 0)
++#else
++ if (fraction & QUIET_NAN)
++#endif
++ {
++ dst->class = CLASS_QNAN;
++ }
++ else
++ {
++ dst->class = CLASS_SNAN;
++ }
++ /* Keep the fraction part as the nan number */
++ dst->fraction.ll = fraction;
++ }
++ }
++ else
++ {
++ /* Nothing strange about this number */
++ dst->normal_exp = exp - EXPBIAS;
++ dst->class = CLASS_NUMBER;
++ dst->fraction.ll = (fraction << NGARDS) | IMPLICIT_1;
++ }
++}
++#endif /* L_unpack_df || L_unpack_sf */
++
++#if defined(L_addsub_sf) || defined(L_addsub_df) || defined(L_addsub_tf)
++static fp_number_type *
++_fpadd_parts (fp_number_type * a,
++ fp_number_type * b,
++ fp_number_type * tmp)
++{
++ intfrac tfraction;
++
++ /* Put commonly used fields in local variables. */
++ int a_normal_exp;
++ int b_normal_exp;
++ fractype a_fraction;
++ fractype b_fraction;
++
++ if (isnan (a))
++ {
++ return a;
++ }
++ if (isnan (b))
++ {
++ return b;
++ }
++ if (isinf (a))
++ {
++ /* Adding infinities with opposite signs yields a NaN. */
++ if (isinf (b) && a->sign != b->sign)
++ return nan ();
++ return a;
++ }
++ if (isinf (b))
++ {
++ return b;
++ }
++ if (iszero (b))
++ {
++ if (iszero (a))
++ {
++ *tmp = *a;
++ tmp->sign = a->sign & b->sign;
++ return tmp;
++ }
++ return a;
++ }
++ if (iszero (a))
++ {
++ return b;
++ }
++
++ /* Got two numbers. shift the smaller and increment the exponent till
++ they're the same */
++ {
++ int diff;
++
++ a_normal_exp = a->normal_exp;
++ b_normal_exp = b->normal_exp;
++ a_fraction = a->fraction.ll;
++ b_fraction = b->fraction.ll;
++
++ diff = a_normal_exp - b_normal_exp;
++
++ if (diff < 0)
++ diff = -diff;
++ if (diff < FRAC_NBITS)
++ {
++ /* ??? This does shifts one bit at a time. Optimize. */
++ while (a_normal_exp > b_normal_exp)
++ {
++ b_normal_exp++;
++ LSHIFT (b_fraction);
++ }
++ while (b_normal_exp > a_normal_exp)
++ {
++ a_normal_exp++;
++ LSHIFT (a_fraction);
++ }
++ }
++ else
++ {
++ /* Somethings's up.. choose the biggest */
++ if (a_normal_exp > b_normal_exp)
++ {
++ b_normal_exp = a_normal_exp;
++ b_fraction = 0;
++ }
++ else
++ {
++ a_normal_exp = b_normal_exp;
++ a_fraction = 0;
++ }
++ }
++ }
++
++ if (a->sign != b->sign)
++ {
++ if (a->sign)
++ {
++ tfraction = -a_fraction + b_fraction;
++ }
++ else
++ {
++ tfraction = a_fraction - b_fraction;
++ }
++ if (tfraction >= 0)
++ {
++ tmp->sign = 0;
++ tmp->normal_exp = a_normal_exp;
++ tmp->fraction.ll = tfraction;
++ }
++ else
++ {
++ tmp->sign = 1;
++ tmp->normal_exp = a_normal_exp;
++ tmp->fraction.ll = -tfraction;
++ }
++ /* and renormalize it */
++
++ while (tmp->fraction.ll < IMPLICIT_1 && tmp->fraction.ll)
++ {
++ tmp->fraction.ll <<= 1;
++ tmp->normal_exp--;
++ }
++ }
++ else
++ {
++ tmp->sign = a->sign;
++ tmp->normal_exp = a_normal_exp;
++ tmp->fraction.ll = a_fraction + b_fraction;
++ }
++ tmp->class = CLASS_NUMBER;
++ /* Now the fraction is added, we have to shift down to renormalize the
++ number */
++
++ if (tmp->fraction.ll >= IMPLICIT_2)
++ {
++ LSHIFT (tmp->fraction.ll);
++ tmp->normal_exp++;
++ }
++ return tmp;
++
++}
++
++FLO_type
++add (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ fp_number_type tmp;
++ fp_number_type *res;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ res = _fpadd_parts (&a, &b, &tmp);
++
++ return pack_d (res);
++}
++
++FLO_type
++sub (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ fp_number_type tmp;
++ fp_number_type *res;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ b.sign ^= 1;
++
++ res = _fpadd_parts (&a, &b, &tmp);
++
++ return pack_d (res);
++}
++#endif /* L_addsub_sf || L_addsub_df */
++
++#if defined(L_mul_sf) || defined(L_mul_df) || defined(L_mul_tf)
++static inline __attribute__ ((__always_inline__)) fp_number_type *
++_fpmul_parts ( fp_number_type * a,
++ fp_number_type * b,
++ fp_number_type * tmp)
++{
++ fractype low = 0;
++ fractype high = 0;
++
++ if (isnan (a))
++ {
++ a->sign = a->sign != b->sign;
++ return a;
++ }
++ if (isnan (b))
++ {
++ b->sign = a->sign != b->sign;
++ return b;
++ }
++ if (isinf (a))
++ {
++ if (iszero (b))
++ return nan ();
++ a->sign = a->sign != b->sign;
++ return a;
++ }
++ if (isinf (b))
++ {
++ if (iszero (a))
++ {
++ return nan ();
++ }
++ b->sign = a->sign != b->sign;
++ return b;
++ }
++ if (iszero (a))
++ {
++ a->sign = a->sign != b->sign;
++ return a;
++ }
++ if (iszero (b))
++ {
++ b->sign = a->sign != b->sign;
++ return b;
++ }
++
++ /* Calculate the mantissa by multiplying both numbers to get a
++ twice-as-wide number. */
++ {
++#if defined(NO_DI_MODE) || defined(TFLOAT)
++ {
++ fractype x = a->fraction.ll;
++ fractype ylow = b->fraction.ll;
++ fractype yhigh = 0;
++ int bit;
++
++ /* ??? This does multiplies one bit at a time. Optimize. */
++ for (bit = 0; bit < FRAC_NBITS; bit++)
++ {
++ int carry;
++
++ if (x & 1)
++ {
++ carry = (low += ylow) < ylow;
++ high += yhigh + carry;
++ }
++ yhigh <<= 1;
++ if (ylow & FRACHIGH)
++ {
++ yhigh |= 1;
++ }
++ ylow <<= 1;
++ x >>= 1;
++ }
++ }
++#elif defined(FLOAT)
++ /* Multiplying two USIs to get a UDI, we're safe. */
++ {
++ UDItype answer = (UDItype)a->fraction.ll * (UDItype)b->fraction.ll;
++
++ high = answer >> BITS_PER_SI;
++ low = answer;
++ }
++#else
++ /* fractype is DImode, but we need the result to be twice as wide.
++ Assuming a widening multiply from DImode to TImode is not
++ available, build one by hand. */
++ {
++ USItype nl = a->fraction.ll;
++ USItype nh = a->fraction.ll >> BITS_PER_SI;
++ USItype ml = b->fraction.ll;
++ USItype mh = b->fraction.ll >> BITS_PER_SI;
++ UDItype pp_ll = (UDItype) ml * nl;
++ UDItype pp_hl = (UDItype) mh * nl;
++ UDItype pp_lh = (UDItype) ml * nh;
++ UDItype pp_hh = (UDItype) mh * nh;
++ UDItype res2 = 0;
++ UDItype res0 = 0;
++ UDItype ps_hh__ = pp_hl + pp_lh;
++ if (ps_hh__ < pp_hl)
++ res2 += (UDItype)1 << BITS_PER_SI;
++ pp_hl = (UDItype)(USItype)ps_hh__ << BITS_PER_SI;
++ res0 = pp_ll + pp_hl;
++ if (res0 < pp_ll)
++ res2++;
++ res2 += (ps_hh__ >> BITS_PER_SI) + pp_hh;
++ high = res2;
++ low = res0;
++ }
++#endif
++ }
++
++ tmp->normal_exp = a->normal_exp + b->normal_exp
++ + FRAC_NBITS - (FRACBITS + NGARDS);
++ tmp->sign = a->sign != b->sign;
++ while (high >= IMPLICIT_2)
++ {
++ tmp->normal_exp++;
++ if (high & 1)
++ {
++ low >>= 1;
++ low |= FRACHIGH;
++ }
++ high >>= 1;
++ }
++ while (high < IMPLICIT_1)
++ {
++ tmp->normal_exp--;
++
++ high <<= 1;
++ if (low & FRACHIGH)
++ high |= 1;
++ low <<= 1;
++ }
++ /* rounding is tricky. if we only round if it won't make us round later. */
++#if 0
++ if (low & FRACHIGH2)
++ {
++ if (((high & GARDMASK) != GARDMSB)
++ && (((high + 1) & GARDMASK) == GARDMSB))
++ {
++ /* don't round, it gets done again later. */
++ }
++ else
++ {
++ high++;
++ }
++ }
++#endif
++ if (!ROUND_TOWARDS_ZERO && (high & GARDMASK) == GARDMSB)
++ {
++ if (high & (1 << NGARDS))
++ {
++ /* half way, so round to even */
++ high += GARDROUND + 1;
++ }
++ else if (low)
++ {
++ /* but we really weren't half way */
++ high += GARDROUND + 1;
++ }
++ }
++ tmp->fraction.ll = high;
++ tmp->class = CLASS_NUMBER;
++ return tmp;
++}
++
++FLO_type
++multiply (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ fp_number_type tmp;
++ fp_number_type *res;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ res = _fpmul_parts (&a, &b, &tmp);
++
++ return pack_d (res);
++}
++#endif /* L_mul_sf || L_mul_df */
++
++#if defined(L_div_sf) || defined(L_div_df) || defined(L_div_tf)
++static inline __attribute__ ((__always_inline__)) fp_number_type *
++_fpdiv_parts (fp_number_type * a,
++ fp_number_type * b)
++{
++ fractype bit;
++ fractype numerator;
++ fractype denominator;
++ fractype quotient;
++
++ if (isnan (a))
++ {
++ return a;
++ }
++ if (isnan (b))
++ {
++ return b;
++ }
++
++ a->sign = a->sign ^ b->sign;
++
++ if (isinf (a) || iszero (a))
++ {
++ if (a->class == b->class)
++ return nan ();
++ return a;
++ }
++
++ if (isinf (b))
++ {
++ a->fraction.ll = 0;
++ a->normal_exp = 0;
++ return a;
++ }
++ if (iszero (b))
++ {
++ a->class = CLASS_INFINITY;
++ return a;
++ }
++
++ /* Calculate the mantissa by multiplying both 64bit numbers to get a
++ 128 bit number */
++ {
++ /* quotient =
++ ( numerator / denominator) * 2^(numerator exponent - denominator exponent)
++ */
++
++ a->normal_exp = a->normal_exp - b->normal_exp;
++ numerator = a->fraction.ll;
++ denominator = b->fraction.ll;
++
++ if (numerator < denominator)
++ {
++ /* Fraction will be less than 1.0 */
++ numerator *= 2;
++ a->normal_exp--;
++ }
++ bit = IMPLICIT_1;
++ quotient = 0;
++ /* ??? Does divide one bit at a time. Optimize. */
++ while (bit)
++ {
++ if (numerator >= denominator)
++ {
++ quotient |= bit;
++ numerator -= denominator;
++ }
++ bit >>= 1;
++ numerator *= 2;
++ }
++
++ if (!ROUND_TOWARDS_ZERO && (quotient & GARDMASK) == GARDMSB)
++ {
++ if (quotient & (1 << NGARDS))
++ {
++ /* half way, so round to even */
++ quotient += GARDROUND + 1;
++ }
++ else if (numerator)
++ {
++ /* but we really weren't half way, more bits exist */
++ quotient += GARDROUND + 1;
++ }
++ }
++
++ a->fraction.ll = quotient;
++ return (a);
++ }
++}
++
++FLO_type
++divide (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ fp_number_type *res;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ res = _fpdiv_parts (&a, &b);
++
++ return pack_d (res);
++}
++#endif /* L_div_sf || L_div_df */
++
++#if defined(L_fpcmp_parts_sf) || defined(L_fpcmp_parts_df) \
++ || defined(L_fpcmp_parts_tf)
++/* according to the demo, fpcmp returns a comparison with 0... thus
++ a<b -> -1
++ a==b -> 0
++ a>b -> +1
++ */
++
++int
++__fpcmp_parts (fp_number_type * a, fp_number_type * b)
++{
++#if 0
++ /* either nan -> unordered. Must be checked outside of this routine. */
++ if (isnan (a) && isnan (b))
++ {
++ return 1; /* still unordered! */
++ }
++#endif
++
++ if (isnan (a) || isnan (b))
++ {
++ return 1; /* how to indicate unordered compare? */
++ }
++ if (isinf (a) && isinf (b))
++ {
++ /* +inf > -inf, but +inf != +inf */
++ /* b \a| +inf(0)| -inf(1)
++ ______\+--------+--------
++ +inf(0)| a==b(0)| a<b(-1)
++ -------+--------+--------
++ -inf(1)| a>b(1) | a==b(0)
++ -------+--------+--------
++ So since unordered must be nonzero, just line up the columns...
++ */
++ return b->sign - a->sign;
++ }
++ /* but not both... */
++ if (isinf (a))
++ {
++ return a->sign ? -1 : 1;
++ }
++ if (isinf (b))
++ {
++ return b->sign ? 1 : -1;
++ }
++ if (iszero (a) && iszero (b))
++ {
++ return 0;
++ }
++ if (iszero (a))
++ {
++ return b->sign ? 1 : -1;
++ }
++ if (iszero (b))
++ {
++ return a->sign ? -1 : 1;
++ }
++ /* now both are "normal". */
++ if (a->sign != b->sign)
++ {
++ /* opposite signs */
++ return a->sign ? -1 : 1;
++ }
++ /* same sign; exponents? */
++ if (a->normal_exp > b->normal_exp)
++ {
++ return a->sign ? -1 : 1;
++ }
++ if (a->normal_exp < b->normal_exp)
++ {
++ return a->sign ? 1 : -1;
++ }
++ /* same exponents; check size. */
++ if (a->fraction.ll > b->fraction.ll)
++ {
++ return a->sign ? -1 : 1;
++ }
++ if (a->fraction.ll < b->fraction.ll)
++ {
++ return a->sign ? 1 : -1;
++ }
++ /* after all that, they're equal. */
++ return 0;
++}
++#endif
++
++#if defined(L_compare_sf) || defined(L_compare_df) || defined(L_compoare_tf)
++CMPtype
++compare (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ return __fpcmp_parts (&a, &b);
++}
++#endif /* L_compare_sf || L_compare_df */
++
++#ifndef US_SOFTWARE_GOFAST
++
++/* These should be optimized for their specific tasks someday. */
++
++#if defined(L_eq_sf) || defined(L_eq_df) || defined(L_eq_tf)
++CMPtype
++_eq_f2 (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ if (isnan (&a) || isnan (&b))
++ return 1; /* false, truth == 0 */
++
++ return __fpcmp_parts (&a, &b) ;
++}
++#endif /* L_eq_sf || L_eq_df */
++
++#if defined(L_ne_sf) || defined(L_ne_df) || defined(L_ne_tf)
++CMPtype
++_ne_f2 (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ if (isnan (&a) || isnan (&b))
++ return 1; /* true, truth != 0 */
++
++ return __fpcmp_parts (&a, &b) ;
++}
++#endif /* L_ne_sf || L_ne_df */
++
++#if defined(L_gt_sf) || defined(L_gt_df) || defined(L_gt_tf)
++CMPtype
++_gt_f2 (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ if (isnan (&a) || isnan (&b))
++ return -1; /* false, truth > 0 */
++
++ return __fpcmp_parts (&a, &b);
++}
++#endif /* L_gt_sf || L_gt_df */
++
++#if defined(L_ge_sf) || defined(L_ge_df) || defined(L_ge_tf)
++CMPtype
++_ge_f2 (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ if (isnan (&a) || isnan (&b))
++ return -1; /* false, truth >= 0 */
++ return __fpcmp_parts (&a, &b) ;
++}
++#endif /* L_ge_sf || L_ge_df */
++
++#if defined(L_lt_sf) || defined(L_lt_df) || defined(L_lt_tf)
++CMPtype
++_lt_f2 (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ if (isnan (&a) || isnan (&b))
++ return 1; /* false, truth < 0 */
++
++ return __fpcmp_parts (&a, &b);
++}
++#endif /* L_lt_sf || L_lt_df */
++
++#if defined(L_le_sf) || defined(L_le_df) || defined(L_le_tf)
++CMPtype
++_le_f2 (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ if (isnan (&a) || isnan (&b))
++ return 1; /* false, truth <= 0 */
++
++ return __fpcmp_parts (&a, &b) ;
++}
++#endif /* L_le_sf || L_le_df */
++
++#endif /* ! US_SOFTWARE_GOFAST */
++
++#if defined(L_unord_sf) || defined(L_unord_df) || defined(L_unord_tf)
++CMPtype
++_unord_f2 (FLO_type arg_a, FLO_type arg_b)
++{
++ fp_number_type a;
++ fp_number_type b;
++ FLO_union_type au, bu;
++
++ au.value = arg_a;
++ bu.value = arg_b;
++
++ unpack_d (&au, &a);
++ unpack_d (&bu, &b);
++
++ return (isnan (&a) || isnan (&b));
++}
++#endif /* L_unord_sf || L_unord_df */
++
++#if defined(L_si_to_sf) || defined(L_si_to_df) || defined(L_si_to_tf)
++FLO_type
++si_to_float (SItype arg_a)
++{
++ fp_number_type in;
++
++ in.class = CLASS_NUMBER;
++ in.sign = arg_a < 0;
++ if (!arg_a)
++ {
++ in.class = CLASS_ZERO;
++ }
++ else
++ {
++ in.normal_exp = FRACBITS + NGARDS;
++ if (in.sign)
++ {
++ /* Special case for minint, since there is no +ve integer
++ representation for it */
++ if (arg_a == (- MAX_SI_INT - 1))
++ {
++ return (FLO_type)(- MAX_SI_INT - 1);
++ }
++ in.fraction.ll = (-arg_a);
++ }
++ else
++ in.fraction.ll = arg_a;
++
++ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS)))
++ {
++ in.fraction.ll <<= 1;
++ in.normal_exp -= 1;
++ }
++ }
++ return pack_d (&in);
++}
++#endif /* L_si_to_sf || L_si_to_df */
++
++#if defined(L_usi_to_sf) || defined(L_usi_to_df) || defined(L_usi_to_tf)
++FLO_type
++usi_to_float (USItype arg_a)
++{
++ fp_number_type in;
++
++ in.sign = 0;
++ if (!arg_a)
++ {
++ in.class = CLASS_ZERO;
++ }
++ else
++ {
++ in.class = CLASS_NUMBER;
++ in.normal_exp = FRACBITS + NGARDS;
++ in.fraction.ll = arg_a;
++
++ while (in.fraction.ll > ((fractype)1 << (FRACBITS + NGARDS)))
++ {
++ in.fraction.ll >>= 1;
++ in.normal_exp += 1;
++ }
++ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS)))
++ {
++ in.fraction.ll <<= 1;
++ in.normal_exp -= 1;
++ }
++ }
++ return pack_d (&in);
++}
++#endif
++
++#if defined(L_sf_to_si) || defined(L_df_to_si) || defined(L_tf_to_si)
++SItype
++float_to_si (FLO_type arg_a)
++{
++ fp_number_type a;
++ SItype tmp;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &a);
++
++ if (iszero (&a))
++ return 0;
++ if (isnan (&a))
++ return 0;
++ /* get reasonable MAX_SI_INT... */
++ if (isinf (&a))
++ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT;
++ /* it is a number, but a small one */
++ if (a.normal_exp < 0)
++ return 0;
++ if (a.normal_exp > BITS_PER_SI - 2)
++ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT;
++ tmp = a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp);
++ return a.sign ? (-tmp) : (tmp);
++}
++#endif /* L_sf_to_si || L_df_to_si */
++
++#if defined(L_sf_to_usi) || defined(L_df_to_usi) || defined(L_tf_to_usi)
++#if defined US_SOFTWARE_GOFAST || defined(L_tf_to_usi)
++/* While libgcc2.c defines its own __fixunssfsi and __fixunsdfsi routines,
++ we also define them for GOFAST because the ones in libgcc2.c have the
++ wrong names and I'd rather define these here and keep GOFAST CYG-LOC's
++ out of libgcc2.c. We can't define these here if not GOFAST because then
++ there'd be duplicate copies. */
++
++USItype
++float_to_usi (FLO_type arg_a)
++{
++ fp_number_type a;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &a);
++
++ if (iszero (&a))
++ return 0;
++ if (isnan (&a))
++ return 0;
++ /* it is a negative number */
++ if (a.sign)
++ return 0;
++ /* get reasonable MAX_USI_INT... */
++ if (isinf (&a))
++ return MAX_USI_INT;
++ /* it is a number, but a small one */
++ if (a.normal_exp < 0)
++ return 0;
++ if (a.normal_exp > BITS_PER_SI - 1)
++ return MAX_USI_INT;
++ else if (a.normal_exp > (FRACBITS + NGARDS))
++ return a.fraction.ll << (a.normal_exp - (FRACBITS + NGARDS));
++ else
++ return a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp);
++}
++#endif /* US_SOFTWARE_GOFAST */
++#endif /* L_sf_to_usi || L_df_to_usi */
++
++#if defined(L_negate_sf) || defined(L_negate_df) || defined(L_negate_tf)
++FLO_type
++negate (FLO_type arg_a)
++{
++ fp_number_type a;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &a);
++
++ flip_sign (&a);
++ return pack_d (&a);
++}
++#endif /* L_negate_sf || L_negate_df */
++
++#ifdef FLOAT
++
++#if defined(L_make_sf)
++SFtype
++__make_fp(fp_class_type class,
++ unsigned int sign,
++ int exp,
++ USItype frac)
++{
++ fp_number_type in;
++
++ in.class = class;
++ in.sign = sign;
++ in.normal_exp = exp;
++ in.fraction.ll = frac;
++ return pack_d (&in);
++}
++#endif /* L_make_sf */
++
++#ifndef FLOAT_ONLY
++
++/* This enables one to build an fp library that supports float but not double.
++ Otherwise, we would get an undefined reference to __make_dp.
++ This is needed for some 8-bit ports that can't handle well values that
++ are 8-bytes in size, so we just don't support double for them at all. */
++
++#if defined(L_sf_to_df)
++DFtype
++sf_to_df (SFtype arg_a)
++{
++ fp_number_type in;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &in);
++
++ return __make_dp (in.class, in.sign, in.normal_exp,
++ ((UDItype) in.fraction.ll) << F_D_BITOFF);
++}
++#endif /* L_sf_to_df */
++
++#if defined(L_sf_to_tf) && defined(TMODES)
++TFtype
++sf_to_tf (SFtype arg_a)
++{
++ fp_number_type in;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &in);
++
++ return __make_tp (in.class, in.sign, in.normal_exp,
++ ((UTItype) in.fraction.ll) << F_T_BITOFF);
++}
++#endif /* L_sf_to_df */
++
++#endif /* ! FLOAT_ONLY */
++#endif /* FLOAT */
++
++#ifndef FLOAT
++
++extern SFtype __make_fp (fp_class_type, unsigned int, int, USItype);
++
++#if defined(L_make_df)
++DFtype
++__make_dp (fp_class_type class, unsigned int sign, int exp, UDItype frac)
++{
++ fp_number_type in;
++
++ in.class = class;
++ in.sign = sign;
++ in.normal_exp = exp;
++ in.fraction.ll = frac;
++ return pack_d (&in);
++}
++#endif /* L_make_df */
++
++#if defined(L_df_to_sf)
++SFtype
++df_to_sf (DFtype arg_a)
++{
++ fp_number_type in;
++ USItype sffrac;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &in);
++
++ sffrac = in.fraction.ll >> F_D_BITOFF;
++
++ /* We set the lowest guard bit in SFFRAC if we discarded any non
++ zero bits. */
++ if ((in.fraction.ll & (((USItype) 1 << F_D_BITOFF) - 1)) != 0)
++ sffrac |= 1;
++
++ return __make_fp (in.class, in.sign, in.normal_exp, sffrac);
++}
++#endif /* L_df_to_sf */
++
++#if defined(L_df_to_tf) && defined(TMODES) \
++ && !defined(FLOAT) && !defined(TFLOAT)
++TFtype
++df_to_tf (DFtype arg_a)
++{
++ fp_number_type in;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &in);
++
++ return __make_tp (in.class, in.sign, in.normal_exp,
++ ((UTItype) in.fraction.ll) << D_T_BITOFF);
++}
++#endif /* L_sf_to_df */
++
++#ifdef TFLOAT
++#if defined(L_make_tf)
++TFtype
++__make_tp(fp_class_type class,
++ unsigned int sign,
++ int exp,
++ UTItype frac)
++{
++ fp_number_type in;
++
++ in.class = class;
++ in.sign = sign;
++ in.normal_exp = exp;
++ in.fraction.ll = frac;
++ return pack_d (&in);
++}
++#endif /* L_make_tf */
++
++#if defined(L_tf_to_df)
++DFtype
++tf_to_df (TFtype arg_a)
++{
++ fp_number_type in;
++ UDItype sffrac;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &in);
++
++ sffrac = in.fraction.ll >> D_T_BITOFF;
++
++ /* We set the lowest guard bit in SFFRAC if we discarded any non
++ zero bits. */
++ if ((in.fraction.ll & (((UTItype) 1 << D_T_BITOFF) - 1)) != 0)
++ sffrac |= 1;
++
++ return __make_dp (in.class, in.sign, in.normal_exp, sffrac);
++}
++#endif /* L_tf_to_df */
++
++#if defined(L_tf_to_sf)
++SFtype
++tf_to_sf (TFtype arg_a)
++{
++ fp_number_type in;
++ USItype sffrac;
++ FLO_union_type au;
++
++ au.value = arg_a;
++ unpack_d (&au, &in);
++
++ sffrac = in.fraction.ll >> F_T_BITOFF;
++
++ /* We set the lowest guard bit in SFFRAC if we discarded any non
++ zero bits. */
++ if ((in.fraction.ll & (((UTItype) 1 << F_T_BITOFF) - 1)) != 0)
++ sffrac |= 1;
++
++ return __make_fp (in.class, in.sign, in.normal_exp, sffrac);
++}
++#endif /* L_tf_to_sf */
++#endif /* TFLOAT */
++
++#endif /* ! FLOAT */
++#endif /* !EXTENDED_FLOAT_STUBS */
+--- gcc-3.4.3/gcc/config/nios2/nios2-protos.h
++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2-protos.h
+@@ -0,0 +1,70 @@
++/* 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);
++
++
++#ifdef RTX_CODE
++extern int nios2_legitimate_address (rtx, enum machine_mode, int);
++extern void nios2_print_operand (FILE *, rtx, int);
++extern void nios2_print_operand_address (FILE *, rtx);
++
++extern int nios2_emit_move_sequence (rtx *, enum machine_mode);
++extern int nios2_emit_expensive_div (rtx *, enum machine_mode);
++
++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 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);
++
++# ifdef HAVE_MACHINE_MODES
++# if defined TREE_CODE
++extern void function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode, tree, int);
++extern rtx function_arg (const CUMULATIVE_ARGS *, enum machine_mode, tree, int);
++extern int function_arg_partial_nregs (const CUMULATIVE_ARGS *, enum machine_mode, tree, int);
++extern void init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree, int);
++extern int nios2_setup_incoming_varargs (const CUMULATIVE_ARGS *, enum machine_mode, tree, int);
++
++# endif /* TREE_CODE */
++# endif /* HAVE_MACHINE_MODES */
++#endif
++
++#ifdef TREE_CODE
++extern int nios2_return_in_memory (tree);
++
++#endif /* TREE_CODE */
+--- gcc-3.4.3/gcc/config/nios2/nios2.c
++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2.c
+@@ -0,0 +1,2853 @@
++/* 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. */
++
++
++#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 "ggc.h"
++#include "reload.h"
++#include "debug.h"
++#include "optabs.h"
++#include "target.h"
++#include "target-def.h"
++
++/* local prototypes */
++static bool nios2_rtx_costs (rtx, int, int, int *);
++
++static void nios2_asm_function_prologue (FILE *, HOST_WIDE_INT);
++static int nios2_use_dfa_pipeline_interface (void);
++static int nios2_issue_rate (void);
++static struct machine_function *nios2_init_machine_status (void);
++static bool nios2_in_small_data_p (tree);
++static rtx save_reg (int, HOST_WIDE_INT, rtx);
++static rtx restore_reg (int, HOST_WIDE_INT);
++static unsigned int nios2_section_type_flags (tree, const char *, int);
++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 void nios2_encode_section_info (tree, rtx, int);
++
++/* Initialize the GCC target structure. */
++#undef TARGET_ASM_FUNCTION_PROLOGUE
++#define TARGET_ASM_FUNCTION_PROLOGUE nios2_asm_function_prologue
++
++#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE
++#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE \
++ nios2_use_dfa_pipeline_interface
++#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_RTX_COSTS
++#define TARGET_RTX_COSTS nios2_rtx_costs
++
++
++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 (())
++{
++ 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 */
++ int save_reg_rounded; /* # 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 */
++ int num_regs; /* number of gp registers saved */
++};
++
++struct machine_function
++GTY (())
++{
++
++ /* Current frame information, calculated by compute_frame_size. */
++ struct nios2_frame_info frame;
++};
++
++
++/***************************************
++ * Section encodings
++ ***************************************/
++
++
++
++
++
++/***************************************
++ * 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 rtx
++save_reg (int regno, HOST_WIDE_INT offset, rtx cfa_store_reg)
++{
++ rtx insn, stack_slot;
++
++ stack_slot = gen_rtx_PLUS (SImode,
++ cfa_store_reg,
++ GEN_INT (offset));
++
++ insn = emit_insn (gen_rtx_SET (SImode,
++ gen_rtx_MEM (SImode, stack_slot),
++ gen_rtx_REG (SImode, regno)));
++
++ RTX_FRAME_RELATED_P (insn) = 1;
++
++ return insn;
++}
++
++static rtx
++restore_reg (int regno, HOST_WIDE_INT offset)
++{
++ rtx insn, stack_slot;
++
++ if (TOO_BIG_OFFSET (offset))
++ {
++ stack_slot = gen_rtx_REG (SImode, TEMP_REG_NUM);
++ insn = emit_insn (gen_rtx_SET (SImode,
++ stack_slot,
++ GEN_INT (offset)));
++
++ insn = emit_insn (gen_rtx_SET (SImode,
++ stack_slot,
++ gen_rtx_PLUS (SImode,
++ stack_slot,
++ stack_pointer_rtx)));
++ }
++ else
++ {
++ stack_slot = gen_rtx_PLUS (SImode,
++ stack_pointer_rtx,
++ GEN_INT (offset));
++ }
++
++ stack_slot = gen_rtx_MEM (SImode, stack_slot);
++
++ insn = emit_move_insn (gen_rtx_REG (SImode, regno), stack_slot);
++
++ return insn;
++}
++
++
++/* There are two possible paths for prologue expansion,
++- the first is if the total frame size is < 2^15-1. In that
++case all the immediates will fit into the 16-bit immediate
++fields.
++- the second is when the frame size is too big, in that
++case an additional temporary register is used, first
++as a cfa_temp to offset the sp, second as the cfa_store
++register.
++
++See the comment above dwarf2out_frame_debug_expr in
++dwarf2out.c for more explanation of the "rules."
++
++
++Case 1:
++Rule # Example Insn Effect
++2 addi sp, sp, -total_frame_size cfa.reg=sp, cfa.offset=total_frame_size
++ cfa_store.reg=sp, cfa_store.offset=total_frame_size
++12 stw ra, offset(sp)
++12 stw r16, offset(sp)
++1 mov fp, sp
++
++Case 2:
++Rule # Example Insn Effect
++6 movi r8, total_frame_size cfa_temp.reg=r8, cfa_temp.offset=total_frame_size
++2 sub sp, sp, r8 cfa.reg=sp, cfa.offset=total_frame_size
++ cfa_store.reg=sp, cfa_store.offset=total_frame_size
++5 add r8, r8, sp cfa_store.reg=r8, cfa_store.offset=0
++12 stw ra, offset(r8)
++12 stw r16, offset(r8)
++1 mov fp, sp
++
++*/
++
++void
++expand_prologue ()
++{
++ int i;
++ HOST_WIDE_INT total_frame_size;
++ int cfa_store_offset;
++ rtx insn;
++ rtx cfa_store_reg = 0;
++
++ total_frame_size = compute_frame_size ();
++
++ if (total_frame_size)
++ {
++
++ if (TOO_BIG_OFFSET (total_frame_size))
++ {
++ /* cfa_temp and cfa_store_reg are the same register,
++ cfa_store_reg overwrites cfa_temp */
++ cfa_store_reg = gen_rtx_REG (SImode, TEMP_REG_NUM);
++ insn = emit_insn (gen_rtx_SET (SImode,
++ cfa_store_reg,
++ GEN_INT (total_frame_size)));
++
++ RTX_FRAME_RELATED_P (insn) = 1;
++
++
++ insn = gen_rtx_SET (SImode,
++ stack_pointer_rtx,
++ gen_rtx_MINUS (SImode,
++ stack_pointer_rtx,
++ cfa_store_reg));
++
++ insn = emit_insn (insn);
++ RTX_FRAME_RELATED_P (insn) = 1;
++
++
++ /* if there are no registers to save, I don't need to
++ create a cfa_store */
++ if (cfun->machine->frame.save_reg_size)
++ {
++ insn = gen_rtx_SET (SImode,
++ cfa_store_reg,
++ gen_rtx_PLUS (SImode,
++ cfa_store_reg,
++ stack_pointer_rtx));
++
++ insn = emit_insn (insn);
++ RTX_FRAME_RELATED_P (insn) = 1;
++ }
++
++ cfa_store_offset
++ = total_frame_size
++ - (cfun->machine->frame.save_regs_offset
++ + cfun->machine->frame.save_reg_rounded);
++ }
++ else
++ {
++ insn = gen_rtx_SET (SImode,
++ stack_pointer_rtx,
++ gen_rtx_PLUS (SImode,
++ stack_pointer_rtx,
++ GEN_INT (-total_frame_size)));
++ insn = emit_insn (insn);
++ RTX_FRAME_RELATED_P (insn) = 1;
++
++ cfa_store_reg = stack_pointer_rtx;
++ cfa_store_offset
++ = cfun->machine->frame.save_regs_offset
++ + cfun->machine->frame.save_reg_rounded;
++ }
++ }
++
++ if (MUST_SAVE_REGISTER (RA_REGNO))
++ {
++ cfa_store_offset -= 4;
++ save_reg (RA_REGNO, cfa_store_offset, cfa_store_reg);
++ }
++ if (MUST_SAVE_REGISTER (FP_REGNO))
++ {
++ cfa_store_offset -= 4;
++ save_reg (FP_REGNO, cfa_store_offset, cfa_store_reg);
++ }
++
++ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
++ {
++ if (MUST_SAVE_REGISTER (i) && i != FP_REGNO && i != RA_REGNO)
++ {
++ cfa_store_offset -= 4;
++ save_reg (i, cfa_store_offset, cfa_store_reg);
++ }
++ }
++
++ if (frame_pointer_needed)
++ {
++ insn = emit_insn (gen_rtx_SET (SImode,
++ gen_rtx_REG (SImode, FP_REGNO),
++ gen_rtx_REG (SImode, SP_REGNO)));
++
++ RTX_FRAME_RELATED_P (insn) = 1;
++ }
++
++ /* 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 i;
++ HOST_WIDE_INT total_frame_size;
++ int register_store_offset;
++
++ total_frame_size = compute_frame_size ();
++
++ if (!sibcall_p && nios2_can_use_return_insn ())
++ {
++ insn = emit_jump_insn (gen_return ());
++ return;
++ }
++
++ emit_insn (gen_blockage ());
++
++ register_store_offset =
++ cfun->machine->frame.save_regs_offset +
++ cfun->machine->frame.save_reg_rounded;
++
++ if (MUST_SAVE_REGISTER (RA_REGNO))
++ {
++ register_store_offset -= 4;
++ restore_reg (RA_REGNO, register_store_offset);
++ }
++
++ if (MUST_SAVE_REGISTER (FP_REGNO))
++ {
++ register_store_offset -= 4;
++ restore_reg (FP_REGNO, register_store_offset);
++ }
++
++ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
++ {
++ if (MUST_SAVE_REGISTER (i) && i != FP_REGNO && i != RA_REGNO)
++ {
++ register_store_offset -= 4;
++ restore_reg (i, register_store_offset);
++ }
++ }
++
++ if (total_frame_size)
++ {
++ rtx sp_adjust;
++
++ if (TOO_BIG_OFFSET (total_frame_size))
++ {
++ sp_adjust = gen_rtx_REG (SImode, TEMP_REG_NUM);
++ insn = emit_insn (gen_rtx_SET (SImode,
++ sp_adjust,
++ GEN_INT (total_frame_size)));
++
++ }
++ else
++ {
++ sp_adjust = GEN_INT (total_frame_size);
++ }
++
++ insn = gen_rtx_SET (SImode,
++ stack_pointer_rtx,
++ gen_rtx_PLUS (SImode,
++ stack_pointer_rtx,
++ sp_adjust));
++ insn = emit_insn (insn);
++ }
++
++
++ if (!sibcall_p)
++ {
++ insn = emit_jump_insn (gen_return_from_epilogue (gen_rtx (REG, Pmode,
++ RA_REGNO)));
++ }
++}
++
++
++bool
++nios2_function_ok_for_sibcall (tree a ATTRIBUTE_UNUSED, tree b ATTRIBUTE_UNUSED)
++{
++ return true;
++}
++
++
++
++
++
++/* ----------------------- *
++ * Profiling
++ * ----------------------- */
++
++void
++function_profiler (FILE *file, int labelno)
++{
++ fprintf (file, "\t%s mcount begin, label: .LP%d\n",
++ ASM_COMMENT_START, labelno);
++ fprintf (file, "\tnextpc\tr8\n");
++ fprintf (file, "\tmov\tr9, ra\n");
++ fprintf (file, "\tmovhi\tr10, %%hiadj(.LP%d)\n", labelno);
++ fprintf (file, "\taddi\tr10, r10, %%lo(.LP%d)\n", labelno);
++ fprintf (file, "\tcall\tmcount\n");
++ fprintf (file, "\tmov\tra, r9\n");
++ fprintf (file, "\t%s mcount end\n", ASM_COMMENT_START);
++}
++
++
++/***************************************
++ * 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 save_reg_rounded = %d\n", ASM_COMMENT_START,
++ cfun->machine->frame.save_reg_rounded);
++ fprintf (file, "\t%s initialized = %d\n", ASM_COMMENT_START,
++ cfun->machine->frame.initialized);
++ fprintf (file, "\t%s num_regs = %d\n", ASM_COMMENT_START,
++ cfun->machine->frame.num_regs);
++ 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 the bytes needed to compute the frame pointer from the current
++ stack pointer.
++*/
++
++HOST_WIDE_INT
++compute_frame_size ()
++{
++ 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 save_reg_rounded;
++ /* # bytes needed to store callee save regs (rounded) */
++ HOST_WIDE_INT out_args_size; /* # bytes needed for outgoing args */
++
++ 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; regno <= FIRST_PSEUDO_REGISTER; regno++)
++ {
++ if (MUST_SAVE_REGISTER (regno))
++ {
++ save_reg_size += 4;
++ }
++ }
++
++ save_reg_rounded = STACK_ALIGN (save_reg_size);
++ total_size += save_reg_rounded;
++
++ total_size += STACK_ALIGN (current_function_pretend_args_size);
++
++ /* Save other computed information. */
++ cfun->machine->frame.total_size = total_size;
++ cfun->machine->frame.var_size = var_size;
++ cfun->machine->frame.args_size = current_function_outgoing_args_size;
++ cfun->machine->frame.save_reg_size = save_reg_size;
++ cfun->machine->frame.save_reg_rounded = save_reg_rounded;
++ cfun->machine->frame.initialized = reload_completed;
++ cfun->machine->frame.num_regs = save_reg_size / UNITS_PER_WORD;
++
++ cfun->machine->frame.save_regs_offset
++ = save_reg_rounded ? current_function_outgoing_args_size + var_size : 0;
++
++ return total_size;
++}
++
++
++int
++nios2_initial_elimination_offset (int from, int to ATTRIBUTE_UNUSED)
++{
++ int offset;
++
++ /* Set OFFSET to the offset from the stack pointer. */
++ switch (from)
++ {
++ case FRAME_POINTER_REGNUM:
++ offset = 0;
++ break;
++
++ case ARG_POINTER_REGNUM:
++ compute_frame_size ();
++ offset = cfun->machine->frame.total_size;
++ offset -= current_function_pretend_args_size;
++ break;
++
++ case RETURN_ADDRESS_POINTER_REGNUM:
++ compute_frame_size ();
++ /* since the return address is always the first of the
++ saved registers, return the offset to the beginning
++ of the saved registers block */
++ offset = cfun->machine->frame.save_regs_offset;
++ break;
++
++ default:
++ abort ();
++ }
++
++ 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 ()
++{
++ 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;
++}
++
++
++
++
++
++/***************************************
++ *
++ ***************************************/
++
++const char *nios2_sys_nosys_string; /* for -msys=nosys */
++const char *nios2_sys_lib_string; /* for -msys-lib= */
++const char *nios2_sys_crt0_string; /* for -msys-crt0= */
++
++void
++override_options ()
++{
++ /* 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 (nios2_sys_nosys_string && *nios2_sys_nosys_string)
++ {
++ error ("invalid option '-msys=nosys%s'", nios2_sys_nosys_string);
++ }
++
++ /* If we don't have mul, we don't have mulx either! */
++ if (!TARGET_HAS_MUL && TARGET_HAS_MULX)
++ {
++ target_flags &= ~HAS_MULX_FLAG;
++ }
++
++}
++
++void
++optimization_options (int level, int size)
++{
++ if (level || size)
++ {
++ target_flags |= INLINE_MEMCPY_FLAG;
++ }
++
++ if (level >= 3 && !size)
++ {
++ target_flags |= FAST_SW_DIV_FLAG;
++ }
++}
++
++/* Allocate a chunk of memory for per-function machine-dependent data. */
++static struct machine_function *
++nios2_init_machine_status ()
++{
++ 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.
++ ***************************************/
++
++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);
++ }
++
++ 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 */
++ if (mode != SImode)
++ abort ();
++
++ 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;
++}
++
++/* 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;
++}
++
++/* 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);
++ if (test == ITEST_MAX)
++ abort ();
++
++ p_info = &info[(int) test];
++
++ mode = GET_MODE (cmp0);
++ if (mode == VOIDmode)
++ mode = GET_MODE (cmp1);
++
++ branch_p = (destination != 0);
++
++ /* 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. */
++ if ((p_info->unsignedp
++ ? (unsigned HOST_WIDE_INT) new >
++ (unsigned HOST_WIDE_INT) INTVAL (cmp1)
++ : new > INTVAL (cmp1)) != (p_info->const_add > 0))
++ {
++ /* ??? This case can never happen with the current numbers,
++ but I am paranoid and would rather an abort than
++ a bug I will never find */
++ abort ();
++ }
++ else
++ 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 (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 (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 (p_info->test_code_reg, mode, cmp0, cmp1));
++ }
++ else
++ {
++ emit_move_insn (result,
++ gen_rtx (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 (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_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_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) && CONSTANT_P (op1))
++ ret_val = REG_OK_FOR_BASE_P2 (op0, strict)
++ && SMALL_INT (INTVAL (op1));
++ else if (REG_P (op1) && CONSTANT_P (op0))
++ 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 && 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);
++
++ /* ??? these string names need moving into an array in some header file */
++ if (strcmp (name, ".sbss") == 0
++ || strncmp (name, ".sbss.", 6) == 0
++ || strcmp (name, ".sdata") == 0
++ || strncmp (name, ".sdata.", 7) == 0)
++ flags |= SECTION_SMALL;
++
++ return flags;
++}
++
++
++
++
++/*****************************************
++ * 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
++ */
++
++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
++ && ((MEM_VOLATILE_P (op) && !TARGET_CACHE_VOLATILE)
++ || 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;
++ }
++
++ 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;
++ }
++
++
++ case SUBREG:
++ case MEM:
++ if (letter == 0)
++ {
++ output_address (op);
++ return;
++ }
++
++ case CODE_LABEL:
++ if (letter == 0)
++ {
++ output_addr_const (file, op);
++ return;
++ }
++
++ default:
++ break;
++ }
++
++ fprintf (stderr, "Missing way to print (%c) ", letter);
++ debug_rtx (op);
++ abort ();
++}
++
++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);
++ abort ();
++}
++
++
++
++
++
++/****************************
++ * Predicates
++ ****************************/
++
++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));
++}
++
++
++
++
++
++
++
++/*****************************************************************************
++**
++** instruction scheduler
++**
++*****************************************************************************/
++static int
++nios2_use_dfa_pipeline_interface ()
++{
++ return 1;
++}
++
++
++static int
++nios2_issue_rate ()
++{
++#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;
++}
++
++
++/* 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;
++}
++
++/* 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;
++}
++
++int
++function_arg_partial_nregs (const CUMULATIVE_ARGS *cum,
++ enum machine_mode mode, tree type,
++ 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 < NUM_ARG_REGS
++ && cum->regs_used + param_size > NUM_ARG_REGS)
++ {
++ return NUM_ARG_REGS - cum->regs_used;
++ }
++ else
++ {
++ return 0;
++ }
++}
++
++
++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. */
++int
++nios2_setup_incoming_varargs (const CUMULATIVE_ARGS *cum,
++ enum machine_mode mode, tree type,
++ int no_rtl)
++{
++ CUMULATIVE_ARGS local_cum;
++ int regs_to_push;
++
++ local_cum = *cum;
++ FUNCTION_ARG_ADVANCE (local_cum, mode, type, 1);
++
++ regs_to_push = NUM_ARG_REGS - local_cum.regs_used;
++
++ if (!no_rtl)
++ {
++ 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 ());
++ }
++ }
++
++ return regs_to_push * UNITS_PER_WORD;
++
++}
++
++
++
++/*****************************************************************************
++**
++** 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,
++
++ NIOS2_BUILTIN_CUSTOM_N,
++ NIOS2_BUILTIN_CUSTOM_NI,
++ NIOS2_BUILTIN_CUSTOM_NF,
++ NIOS2_BUILTIN_CUSTOM_NP,
++ NIOS2_BUILTIN_CUSTOM_NII,
++ NIOS2_BUILTIN_CUSTOM_NIF,
++ NIOS2_BUILTIN_CUSTOM_NIP,
++ NIOS2_BUILTIN_CUSTOM_NFI,
++ NIOS2_BUILTIN_CUSTOM_NFF,
++ NIOS2_BUILTIN_CUSTOM_NFP,
++ NIOS2_BUILTIN_CUSTOM_NPI,
++ NIOS2_BUILTIN_CUSTOM_NPF,
++ NIOS2_BUILTIN_CUSTOM_NPP,
++ NIOS2_BUILTIN_CUSTOM_IN,
++ NIOS2_BUILTIN_CUSTOM_INI,
++ NIOS2_BUILTIN_CUSTOM_INF,
++ NIOS2_BUILTIN_CUSTOM_INP,
++ NIOS2_BUILTIN_CUSTOM_INII,
++ NIOS2_BUILTIN_CUSTOM_INIF,
++ NIOS2_BUILTIN_CUSTOM_INIP,
++ NIOS2_BUILTIN_CUSTOM_INFI,
++ NIOS2_BUILTIN_CUSTOM_INFF,
++ NIOS2_BUILTIN_CUSTOM_INFP,
++ NIOS2_BUILTIN_CUSTOM_INPI,
++ NIOS2_BUILTIN_CUSTOM_INPF,
++ NIOS2_BUILTIN_CUSTOM_INPP,
++ NIOS2_BUILTIN_CUSTOM_FN,
++ NIOS2_BUILTIN_CUSTOM_FNI,
++ NIOS2_BUILTIN_CUSTOM_FNF,
++ NIOS2_BUILTIN_CUSTOM_FNP,
++ NIOS2_BUILTIN_CUSTOM_FNII,
++ NIOS2_BUILTIN_CUSTOM_FNIF,
++ NIOS2_BUILTIN_CUSTOM_FNIP,
++ NIOS2_BUILTIN_CUSTOM_FNFI,
++ NIOS2_BUILTIN_CUSTOM_FNFF,
++ NIOS2_BUILTIN_CUSTOM_FNFP,
++ NIOS2_BUILTIN_CUSTOM_FNPI,
++ NIOS2_BUILTIN_CUSTOM_FNPF,
++ NIOS2_BUILTIN_CUSTOM_FNPP,
++ NIOS2_BUILTIN_CUSTOM_PN,
++ NIOS2_BUILTIN_CUSTOM_PNI,
++ NIOS2_BUILTIN_CUSTOM_PNF,
++ NIOS2_BUILTIN_CUSTOM_PNP,
++ NIOS2_BUILTIN_CUSTOM_PNII,
++ NIOS2_BUILTIN_CUSTOM_PNIF,
++ NIOS2_BUILTIN_CUSTOM_PNIP,
++ NIOS2_BUILTIN_CUSTOM_PNFI,
++ NIOS2_BUILTIN_CUSTOM_PNFF,
++ NIOS2_BUILTIN_CUSTOM_PNFP,
++ NIOS2_BUILTIN_CUSTOM_PNPI,
++ NIOS2_BUILTIN_CUSTOM_PNPF,
++ NIOS2_BUILTIN_CUSTOM_PNPP,
++
++
++ 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) PARAMS ((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 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;
++
++static tree custom_n;
++static tree custom_ni;
++static tree custom_nf;
++static tree custom_np;
++static tree custom_nii;
++static tree custom_nif;
++static tree custom_nip;
++static tree custom_nfi;
++static tree custom_nff;
++static tree custom_nfp;
++static tree custom_npi;
++static tree custom_npf;
++static tree custom_npp;
++static tree custom_in;
++static tree custom_ini;
++static tree custom_inf;
++static tree custom_inp;
++static tree custom_inii;
++static tree custom_inif;
++static tree custom_inip;
++static tree custom_infi;
++static tree custom_inff;
++static tree custom_infp;
++static tree custom_inpi;
++static tree custom_inpf;
++static tree custom_inpp;
++static tree custom_fn;
++static tree custom_fni;
++static tree custom_fnf;
++static tree custom_fnp;
++static tree custom_fnii;
++static tree custom_fnif;
++static tree custom_fnip;
++static tree custom_fnfi;
++static tree custom_fnff;
++static tree custom_fnfp;
++static tree custom_fnpi;
++static tree custom_fnpf;
++static tree custom_fnpp;
++static tree custom_pn;
++static tree custom_pni;
++static tree custom_pnf;
++static tree custom_pnp;
++static tree custom_pnii;
++static tree custom_pnif;
++static tree custom_pnip;
++static tree custom_pnfi;
++static tree custom_pnff;
++static tree custom_pnfp;
++static tree custom_pnpi;
++static tree custom_pnpf;
++static tree custom_pnpp;
++
++
++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},
++
++ {CODE_FOR_custom_n, "__builtin_custom_n", NIOS2_BUILTIN_CUSTOM_N, &custom_n, nios2_expand_custom_n},
++ {CODE_FOR_custom_ni, "__builtin_custom_ni", NIOS2_BUILTIN_CUSTOM_NI, &custom_ni, nios2_expand_custom_nX},
++ {CODE_FOR_custom_nf, "__builtin_custom_nf", NIOS2_BUILTIN_CUSTOM_NF, &custom_nf, nios2_expand_custom_nX},
++ {CODE_FOR_custom_np, "__builtin_custom_np", NIOS2_BUILTIN_CUSTOM_NP, &custom_np, nios2_expand_custom_nX},
++ {CODE_FOR_custom_nii, "__builtin_custom_nii", NIOS2_BUILTIN_CUSTOM_NII, &custom_nii, nios2_expand_custom_nXX},
++ {CODE_FOR_custom_nif, "__builtin_custom_nif", NIOS2_BUILTIN_CUSTOM_NIF, &custom_nif, nios2_expand_custom_nXX},
++ {CODE_FOR_custom_nip, "__builtin_custom_nip", NIOS2_BUILTIN_CUSTOM_NIP, &custom_nip, nios2_expand_custom_nXX},
++ {CODE_FOR_custom_nfi, "__builtin_custom_nfi", NIOS2_BUILTIN_CUSTOM_NFI, &custom_nfi, nios2_expand_custom_nXX},
++ {CODE_FOR_custom_nff, "__builtin_custom_nff", NIOS2_BUILTIN_CUSTOM_NFF, &custom_nff, nios2_expand_custom_nXX},
++ {CODE_FOR_custom_nfp, "__builtin_custom_nfp", NIOS2_BUILTIN_CUSTOM_NFP, &custom_nfp, nios2_expand_custom_nXX},
++ {CODE_FOR_custom_npi, "__builtin_custom_npi", NIOS2_BUILTIN_CUSTOM_NPI, &custom_npi, nios2_expand_custom_nXX},
++ {CODE_FOR_custom_npf, "__builtin_custom_npf", NIOS2_BUILTIN_CUSTOM_NPF, &custom_npf, nios2_expand_custom_nXX},
++ {CODE_FOR_custom_npp, "__builtin_custom_npp", NIOS2_BUILTIN_CUSTOM_NPP, &custom_npp, nios2_expand_custom_nXX},
++ {CODE_FOR_custom_in, "__builtin_custom_in", NIOS2_BUILTIN_CUSTOM_IN, &custom_in, nios2_expand_custom_Xn},
++ {CODE_FOR_custom_ini, "__builtin_custom_ini", NIOS2_BUILTIN_CUSTOM_INI, &custom_ini, nios2_expand_custom_XnX},
++ {CODE_FOR_custom_inf, "__builtin_custom_inf", NIOS2_BUILTIN_CUSTOM_INF, &custom_inf, nios2_expand_custom_XnX},
++ {CODE_FOR_custom_inp, "__builtin_custom_inp", NIOS2_BUILTIN_CUSTOM_INP, &custom_inp, nios2_expand_custom_XnX},
++ {CODE_FOR_custom_inii, "__builtin_custom_inii", NIOS2_BUILTIN_CUSTOM_INII, &custom_inii, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_inif, "__builtin_custom_inif", NIOS2_BUILTIN_CUSTOM_INIF, &custom_inif, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_inip, "__builtin_custom_inip", NIOS2_BUILTIN_CUSTOM_INIP, &custom_inip, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_infi, "__builtin_custom_infi", NIOS2_BUILTIN_CUSTOM_INFI, &custom_infi, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_inff, "__builtin_custom_inff", NIOS2_BUILTIN_CUSTOM_INFF, &custom_inff, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_infp, "__builtin_custom_infp", NIOS2_BUILTIN_CUSTOM_INFP, &custom_infp, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_inpi, "__builtin_custom_inpi", NIOS2_BUILTIN_CUSTOM_INPI, &custom_inpi, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_inpf, "__builtin_custom_inpf", NIOS2_BUILTIN_CUSTOM_INPF, &custom_inpf, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_inpp, "__builtin_custom_inpp", NIOS2_BUILTIN_CUSTOM_INPP, &custom_inpp, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_fn, "__builtin_custom_fn", NIOS2_BUILTIN_CUSTOM_FN, &custom_fn, nios2_expand_custom_Xn},
++ {CODE_FOR_custom_fni, "__builtin_custom_fni", NIOS2_BUILTIN_CUSTOM_FNI, &custom_fni, nios2_expand_custom_XnX},
++ {CODE_FOR_custom_fnf, "__builtin_custom_fnf", NIOS2_BUILTIN_CUSTOM_FNF, &custom_fnf, nios2_expand_custom_XnX},
++ {CODE_FOR_custom_fnp, "__builtin_custom_fnp", NIOS2_BUILTIN_CUSTOM_FNP, &custom_fnp, nios2_expand_custom_XnX},
++ {CODE_FOR_custom_fnii, "__builtin_custom_fnii", NIOS2_BUILTIN_CUSTOM_FNII, &custom_fnii, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_fnif, "__builtin_custom_fnif", NIOS2_BUILTIN_CUSTOM_FNIF, &custom_fnif, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_fnip, "__builtin_custom_fnip", NIOS2_BUILTIN_CUSTOM_FNIP, &custom_fnip, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_fnfi, "__builtin_custom_fnfi", NIOS2_BUILTIN_CUSTOM_FNFI, &custom_fnfi, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_fnff, "__builtin_custom_fnff", NIOS2_BUILTIN_CUSTOM_FNFF, &custom_fnff, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_fnfp, "__builtin_custom_fnfp", NIOS2_BUILTIN_CUSTOM_FNFP, &custom_fnfp, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_fnpi, "__builtin_custom_fnpi", NIOS2_BUILTIN_CUSTOM_FNPI, &custom_fnpi, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_fnpf, "__builtin_custom_fnpf", NIOS2_BUILTIN_CUSTOM_FNPF, &custom_fnpf, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_fnpp, "__builtin_custom_fnpp", NIOS2_BUILTIN_CUSTOM_FNPP, &custom_fnpp, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_pn, "__builtin_custom_pn", NIOS2_BUILTIN_CUSTOM_PN, &custom_pn, nios2_expand_custom_Xn},
++ {CODE_FOR_custom_pni, "__builtin_custom_pni", NIOS2_BUILTIN_CUSTOM_PNI, &custom_pni, nios2_expand_custom_XnX},
++ {CODE_FOR_custom_pnf, "__builtin_custom_pnf", NIOS2_BUILTIN_CUSTOM_PNF, &custom_pnf, nios2_expand_custom_XnX},
++ {CODE_FOR_custom_pnp, "__builtin_custom_pnp", NIOS2_BUILTIN_CUSTOM_PNP, &custom_pnp, nios2_expand_custom_XnX},
++ {CODE_FOR_custom_pnii, "__builtin_custom_pnii", NIOS2_BUILTIN_CUSTOM_PNII, &custom_pnii, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_pnif, "__builtin_custom_pnif", NIOS2_BUILTIN_CUSTOM_PNIF, &custom_pnif, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_pnip, "__builtin_custom_pnip", NIOS2_BUILTIN_CUSTOM_PNIP, &custom_pnip, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_pnfi, "__builtin_custom_pnfi", NIOS2_BUILTIN_CUSTOM_PNFI, &custom_pnfi, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_pnff, "__builtin_custom_pnff", NIOS2_BUILTIN_CUSTOM_PNFF, &custom_pnff, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_pnfp, "__builtin_custom_pnfp", NIOS2_BUILTIN_CUSTOM_PNFP, &custom_pnfp, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_pnpi, "__builtin_custom_pnpi", NIOS2_BUILTIN_CUSTOM_PNPI, &custom_pnpi, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_pnpf, "__builtin_custom_pnpf", NIOS2_BUILTIN_CUSTOM_PNPF, &custom_pnpf, nios2_expand_custom_XnXX},
++ {CODE_FOR_custom_pnpp, "__builtin_custom_pnpp", NIOS2_BUILTIN_CUSTOM_PNPP, &custom_pnpp, nios2_expand_custom_XnXX},
++
++
++ {0, 0, 0, 0, 0},
++};
++
++/* This does not have a closing bracket on purpose (see use) */
++#define def_param(TYPE) \
++ tree_cons (NULL_TREE, TYPE,
++
++static void
++nios2_init_builtins ()
++{
++ const struct builtin_description *d;
++
++
++ endlink = void_list_node;
++
++ /* Special indenting here because one of the brackets is in def_param */
++ /* *INDENT-OFF* */
++
++ /* int fn (volatile const void *)
++ */
++ int_ftype_volatile_const_void_p
++ = build_function_type (integer_type_node,
++ def_param (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,
++ def_param (build_qualified_type (ptr_type_node,
++ TYPE_QUAL_VOLATILE))
++ def_param (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,
++ def_param (integer_type_node)
++ endlink));
++
++ /* void fn (int, int)
++ */
++ void_ftype_int_int
++ = build_function_type (void_type_node,
++ def_param (integer_type_node)
++ def_param (integer_type_node)
++ endlink)));
++
++
++#define CUSTOM_NUM def_param (integer_type_node)
++
++ custom_n
++ = build_function_type (void_type_node,
++ CUSTOM_NUM
++ endlink));
++ custom_ni
++ = build_function_type (void_type_node,
++ CUSTOM_NUM
++ def_param (integer_type_node)
++ endlink)));
++ custom_nf
++ = build_function_type (void_type_node,
++ CUSTOM_NUM
++ def_param (float_type_node)
++ endlink)));
++ custom_np
++ = build_function_type (void_type_node,
++ CUSTOM_NUM
++ def_param (ptr_type_node)
++ endlink)));
++ custom_nii
++ = build_function_type (void_type_node,
++ CUSTOM_NUM
++ def_param (integer_type_node)
++ def_param (integer_type_node)
++ endlink))));
++ custom_nif
++ = build_function_type (void_type_node,
++ CUSTOM_NUM
++ def_param (integer_type_node)
++ def_param (float_type_node)
++ endlink))));
++ custom_nip
++ = build_function_type (void_type_node,
++ CUSTOM_NUM
++ def_param (integer_type_node)
++ def_param (ptr_type_node)
++ endlink))));
++ custom_nfi
++ = build_function_type (void_type_node,
++ CUSTOM_NUM
++ def_param (float_type_node)
++ def_param (integer_type_node)
++ endlink))));
++ custom_nff
++ = build_function_type (void_type_node,
++ CUSTOM_NUM
++ def_param (float_type_node)
++ def_param (float_type_node)
++ endlink))));
++ custom_nfp
++ = build_function_type (void_type_node,
++ CUSTOM_NUM
++ def_param (float_type_node)
++ def_param (ptr_type_node)
++ endlink))));
++ custom_npi
++ = build_function_type (void_type_node,
++ CUSTOM_NUM
++ def_param (ptr_type_node)
++ def_param (integer_type_node)
++ endlink))));
++ custom_npf
++ = build_function_type (void_type_node,
++ CUSTOM_NUM
++ def_param (ptr_type_node)
++ def_param (float_type_node)
++ endlink))));
++ custom_npp
++ = build_function_type (void_type_node,
++ CUSTOM_NUM
++ def_param (ptr_type_node)
++ def_param (ptr_type_node)
++ endlink))));
++
++ custom_in
++ = build_function_type (integer_type_node,
++ CUSTOM_NUM
++ endlink));
++ custom_ini
++ = build_function_type (integer_type_node,
++ CUSTOM_NUM
++ def_param (integer_type_node)
++ endlink)));
++ custom_inf
++ = build_function_type (integer_type_node,
++ CUSTOM_NUM
++ def_param (float_type_node)
++ endlink)));
++ custom_inp
++ = build_function_type (integer_type_node,
++ CUSTOM_NUM
++ def_param (ptr_type_node)
++ endlink)));
++ custom_inii
++ = build_function_type (integer_type_node,
++ CUSTOM_NUM
++ def_param (integer_type_node)
++ def_param (integer_type_node)
++ endlink))));
++ custom_inif
++ = build_function_type (integer_type_node,
++ CUSTOM_NUM
++ def_param (integer_type_node)
++ def_param (float_type_node)
++ endlink))));
++ custom_inip
++ = build_function_type (integer_type_node,
++ CUSTOM_NUM
++ def_param (integer_type_node)
++ def_param (ptr_type_node)
++ endlink))));
++ custom_infi
++ = build_function_type (integer_type_node,
++ CUSTOM_NUM
++ def_param (float_type_node)
++ def_param (integer_type_node)
++ endlink))));
++ custom_inff
++ = build_function_type (integer_type_node,
++ CUSTOM_NUM
++ def_param (float_type_node)
++ def_param (float_type_node)
++ endlink))));
++ custom_infp
++ = build_function_type (integer_type_node,
++ CUSTOM_NUM
++ def_param (float_type_node)
++ def_param (ptr_type_node)
++ endlink))));
++ custom_inpi
++ = build_function_type (integer_type_node,
++ CUSTOM_NUM
++ def_param (ptr_type_node)
++ def_param (integer_type_node)
++ endlink))));
++ custom_inpf
++ = build_function_type (integer_type_node,
++ CUSTOM_NUM
++ def_param (ptr_type_node)
++ def_param (float_type_node)
++ endlink))));
++ custom_inpp
++ = build_function_type (integer_type_node,
++ CUSTOM_NUM
++ def_param (ptr_type_node)
++ def_param (ptr_type_node)
++ endlink))));
++
++ custom_fn
++ = build_function_type (float_type_node,
++ CUSTOM_NUM
++ endlink));
++ custom_fni
++ = build_function_type (float_type_node,
++ CUSTOM_NUM
++ def_param (integer_type_node)
++ endlink)));
++ custom_fnf
++ = build_function_type (float_type_node,
++ CUSTOM_NUM
++ def_param (float_type_node)
++ endlink)));
++ custom_fnp
++ = build_function_type (float_type_node,
++ CUSTOM_NUM
++ def_param (ptr_type_node)
++ endlink)));
++ custom_fnii
++ = build_function_type (float_type_node,
++ CUSTOM_NUM
++ def_param (integer_type_node)
++ def_param (integer_type_node)
++ endlink))));
++ custom_fnif
++ = build_function_type (float_type_node,
++ CUSTOM_NUM
++ def_param (integer_type_node)
++ def_param (float_type_node)
++ endlink))));
++ custom_fnip
++ = build_function_type (float_type_node,
++ CUSTOM_NUM
++ def_param (integer_type_node)
++ def_param (ptr_type_node)
++ endlink))));
++ custom_fnfi
++ = build_function_type (float_type_node,
++ CUSTOM_NUM
++ def_param (float_type_node)
++ def_param (integer_type_node)
++ endlink))));
++ custom_fnff
++ = build_function_type (float_type_node,
++ CUSTOM_NUM
++ def_param (float_type_node)
++ def_param (float_type_node)
++ endlink))));
++ custom_fnfp
++ = build_function_type (float_type_node,
++ CUSTOM_NUM
++ def_param (float_type_node)
++ def_param (ptr_type_node)
++ endlink))));
++ custom_fnpi
++ = build_function_type (float_type_node,
++ CUSTOM_NUM
++ def_param (ptr_type_node)
++ def_param (integer_type_node)
++ endlink))));
++ custom_fnpf
++ = build_function_type (float_type_node,
++ CUSTOM_NUM
++ def_param (ptr_type_node)
++ def_param (float_type_node)
++ endlink))));
++ custom_fnpp
++ = build_function_type (float_type_node,
++ CUSTOM_NUM
++ def_param (ptr_type_node)
++ def_param (ptr_type_node)
++ endlink))));
++
++
++ custom_pn
++ = build_function_type (ptr_type_node,
++ CUSTOM_NUM
++ endlink));
++ custom_pni
++ = build_function_type (ptr_type_node,
++ CUSTOM_NUM
++ def_param (integer_type_node)
++ endlink)));
++ custom_pnf
++ = build_function_type (ptr_type_node,
++ CUSTOM_NUM
++ def_param (float_type_node)
++ endlink)));
++ custom_pnp
++ = build_function_type (ptr_type_node,
++ CUSTOM_NUM
++ def_param (ptr_type_node)
++ endlink)));
++ custom_pnii
++ = build_function_type (ptr_type_node,
++ CUSTOM_NUM
++ def_param (integer_type_node)
++ def_param (integer_type_node)
++ endlink))));
++ custom_pnif
++ = build_function_type (ptr_type_node,
++ CUSTOM_NUM
++ def_param (integer_type_node)
++ def_param (float_type_node)
++ endlink))));
++ custom_pnip
++ = build_function_type (ptr_type_node,
++ CUSTOM_NUM
++ def_param (integer_type_node)
++ def_param (ptr_type_node)
++ endlink))));
++ custom_pnfi
++ = build_function_type (ptr_type_node,
++ CUSTOM_NUM
++ def_param (float_type_node)
++ def_param (integer_type_node)
++ endlink))));
++ custom_pnff
++ = build_function_type (ptr_type_node,
++ CUSTOM_NUM
++ def_param (float_type_node)
++ def_param (float_type_node)
++ endlink))));
++ custom_pnfp
++ = build_function_type (ptr_type_node,
++ CUSTOM_NUM
++ def_param (float_type_node)
++ def_param (ptr_type_node)
++ endlink))));
++ custom_pnpi
++ = build_function_type (ptr_type_node,
++ CUSTOM_NUM
++ def_param (ptr_type_node)
++ def_param (integer_type_node)
++ endlink))));
++ custom_pnpf
++ = build_function_type (ptr_type_node,
++ CUSTOM_NUM
++ def_param (ptr_type_node)
++ def_param (float_type_node)
++ endlink))));
++ custom_pnpp
++ = build_function_type (ptr_type_node,
++ CUSTOM_NUM
++ def_param (ptr_type_node)
++ def_param (ptr_type_node)
++ endlink))));
++
++
++
++ /* *INDENT-ON* */
++
++
++ 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)
++ return (d->expander) (d, exp, target, subtarget, mode, ignore);
++
++ /* we should have seen one of the functins we registered */
++ abort ();
++}
++
++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);
++ opcode = protect_from_queue (opcode, 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);
++
++ 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);
++ operand = protect_from_queue (operand, 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 */
++ if (insn_data[d->icode].n_operands != 1)
++ abort ();
++
++ 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 */
++ if (insn_data[d->icode].n_operands != 2)
++ abort ();
++
++ 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 */
++ if (insn_data[d->icode].n_operands != 2)
++ abort ();
++
++ 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 */
++ if (insn_data[d->icode].n_operands != 3)
++ abort ();
++
++ 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 */
++ if (insn_data[d->icode].n_operands != 3)
++ abort ();
++
++ 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 */
++ if (insn_data[d->icode].n_operands != 4)
++ abort ();
++
++ 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 */
++ if (insn_data[icode].n_operands != 2)
++ abort ();
++
++ /* 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 = protect_from_queue (store_dest, 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);
++ store_val = protect_from_queue (store_val, 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 */
++ if (insn_data[icode].n_operands != 2)
++ abort ();
++
++ 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 = protect_from_queue (ld_src, 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 */
++ if (insn_data[icode].n_operands != 2)
++ abort ();
++
++ 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);
++ rdctl_reg = protect_from_queue (rdctl_reg, 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 */
++ if (insn_data[icode].n_operands != 2)
++ abort ();
++
++ /* 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);
++ wrctl_reg = protect_from_queue (wrctl_reg, 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);
++ store_val = protect_from_queue (store_val, 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;
++}
++
++
++#include "gt-nios2.h"
++
+--- gcc-3.4.3/gcc/config/nios2/nios2.h
++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2.h
+@@ -0,0 +1,823 @@
++/* Definitions of target machine 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. */
++
++
++
++#define TARGET_CPU_CPP_BUILTINS() \
++ do \
++ { \
++ builtin_define_std ("NIOS2"); \
++ builtin_define_std ("nios2"); \
++ } \
++ while (0)
++#define TARGET_VERSION fprintf (stderr, " (Altera Nios II)")
++
++
++
++
++
++/*********************************
++ * Run-time Target Specification
++ *********************************/
++
++#define HAS_DIV_FLAG 0x0001
++#define HAS_MUL_FLAG 0x0002
++#define HAS_MULX_FLAG 0x0004
++#define FAST_SW_DIV_FLAG 0x0008
++#define INLINE_MEMCPY_FLAG 0x00010
++#define CACHE_VOLATILE_FLAG 0x0020
++#define BYPASS_CACHE_FLAG 0x0040
++
++extern int target_flags;
++#define TARGET_HAS_DIV (target_flags & HAS_DIV_FLAG)
++#define TARGET_HAS_MUL (target_flags & HAS_MUL_FLAG)
++#define TARGET_HAS_MULX (target_flags & HAS_MULX_FLAG)
++#define TARGET_FAST_SW_DIV (target_flags & FAST_SW_DIV_FLAG)
++#define TARGET_INLINE_MEMCPY (target_flags & INLINE_MEMCPY_FLAG)
++#define TARGET_CACHE_VOLATILE (target_flags & CACHE_VOLATILE_FLAG)
++#define TARGET_BYPASS_CACHE (target_flags & BYPASS_CACHE_FLAG)
++
++#define TARGET_SWITCHES \
++{ \
++ { "hw-div", HAS_DIV_FLAG, \
++ N_("Enable DIV, DIVU") }, \
++ { "no-hw-div", -HAS_DIV_FLAG, \
++ N_("Disable DIV, DIVU (default)") }, \
++ { "hw-mul", HAS_MUL_FLAG, \
++ N_("Enable MUL instructions (default)") }, \
++ { "hw-mulx", HAS_MULX_FLAG, \
++ N_("Enable MULX instructions, assume fast shifter") }, \
++ { "no-hw-mul", -HAS_MUL_FLAG, \
++ N_("Disable MUL instructions") }, \
++ { "no-hw-mulx", -HAS_MULX_FLAG, \
++ N_("Disable MULX instructions, assume slow shifter (default and implied by -mno-hw-mul)") }, \
++ { "fast-sw-div", FAST_SW_DIV_FLAG, \
++ N_("Use table based fast divide (default at -O3)") }, \
++ { "no-fast-sw-div", -FAST_SW_DIV_FLAG, \
++ N_("Don't use table based fast divide ever") }, \
++ { "inline-memcpy", INLINE_MEMCPY_FLAG, \
++ N_("Inline small memcpy (default when optimizing)") }, \
++ { "no-inline-memcpy", -INLINE_MEMCPY_FLAG, \
++ N_("Don't Inline small memcpy") }, \
++ { "cache-volatile", CACHE_VOLATILE_FLAG, \
++ N_("Volatile accesses use non-io variants of instructions (default)") }, \
++ { "no-cache-volatile", -CACHE_VOLATILE_FLAG, \
++ N_("Volatile accesses use io variants of instructions") }, \
++ { "bypass-cache", BYPASS_CACHE_FLAG, \
++ N_("All ld/st instructins use io variants") }, \
++ { "no-bypass-cache", -BYPASS_CACHE_FLAG, \
++ N_("All ld/st instructins do not use io variants (default)") }, \
++ { "smallc", 0, \
++ N_("Link with a limited version of the C library") }, \
++ { "ctors-in-init", 0, \
++ "" /* undocumented: N_("Link with static constructors and destructors in init") */ }, \
++ { "", TARGET_DEFAULT, 0 } \
++}
++
++
++extern const char *nios2_sys_nosys_string; /* for -msys=nosys */
++extern const char *nios2_sys_lib_string; /* for -msys-lib= */
++extern const char *nios2_sys_crt0_string; /* for -msys-crt0= */
++
++#define TARGET_OPTIONS \
++{ \
++ { "sys=nosys", &nios2_sys_nosys_string, \
++ N_("Use stub versions of OS library calls (default)"), 0}, \
++ { "sys-lib=", &nios2_sys_lib_string, \
++ N_("Name of System Library to link against. (Converted to a -l option)"), 0}, \
++ { "sys-crt0=", &nios2_sys_crt0_string, \
++ N_("Name of the startfile. (default is a crt0 for the ISS only)"), 0}, \
++}
++
++
++/* Default target_flags if no switches specified. */
++#ifndef TARGET_DEFAULT
++# define TARGET_DEFAULT (HAS_MUL_FLAG | CACHE_VOLATILE_FLAG)
++#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*}"
++
++#undef LIB_SPEC
++#define LIB_SPEC \
++"--start-group %{msmallc: -lsmallc} %{!msmallc: -lc} -lgcc \
++ %{msys-lib=*: -l%*} \
++ %{!msys-lib=*: -lc } \
++ --end-group \
++ %{msys-lib=: %eYou need a library name for -msys-lib=} \
++"
++
++
++#undef STARTFILE_SPEC
++#define STARTFILE_SPEC \
++"%{msys-crt0=*: %*} %{!msys-crt0=*: crt1%O%s} \
++ %{msys-crt0=: %eYou need a C startup file for -msys-crt0=} \
++ %{mctors-in-init: crti%O%s crtbegin%O%s} \
++"
++
++#undef ENDFILE_SPEC
++#define ENDFILE_SPEC \
++ "%{mctors-in-init: crtend%O%s crtn%O%s}"
++
++
++/***********************
++ * Storage Layout
++ ***********************/
++
++#define DEFAULT_SIGNED_CHAR 1
++#define BITS_BIG_ENDIAN 0
++#define BYTES_BIG_ENDIAN 0
++#define WORDS_BIG_ENDIAN 0
++#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 only CMP_SI is used */
++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
++23 r23 sc Static Chain (Callee Saved)
++ ??? Does $sc want to be caller or callee
++ saved. If caller, 15, else 23.
++24 r24 Exception Temporary
++25 r25 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 rap Return address pointer, this does not
++ actually exist and will be eliminated
++
++39 fake_fp Fake Frame Pointer which will always be eliminated.
++40 fake_ap Fake Argument Pointer which will always be eliminated.
++
++41 First Pseudo Register
++
++
++The definitions for all the hard register numbers
++are located in nios2.md.
++*/
++
++#define FIRST_PSEUDO_REGISTER 41
++#define NUM_ARG_REGS (LAST_ARG_REGNO - FIRST_ARG_REGNO + 1)
++
++
++
++/* also see CONDITIONAL_REGISTER_USAGE */
++#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, 0, 0, 1, 1, 1, 1, 0, 1, \
++/* 30 */ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, \
++/* 40 */ 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, 0, 0, 1, 1, 1, 1, 0, 1, \
++/* 30 */ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, \
++/* 40 */ 1, \
++ }
++
++#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,
++ ALL_REGS,
++ LIM_REG_CLASSES
++};
++
++#define N_REG_CLASSES (int) LIM_REG_CLASSES
++
++#define REG_CLASS_NAMES \
++ {"NO_REGS", \
++ "ALL_REGS"}
++
++#define GENERAL_REGS ALL_REGS
++
++#define REG_CLASS_CONTENTS \
++/* NO_REGS */ {{ 0, 0}, \
++/* ALL_REGS */ {~0,~0}} \
++
++#define REGNO_REG_CLASS(REGNO) ALL_REGS
++
++#define BASE_REG_CLASS ALL_REGS
++#define INDEX_REG_CLASS ALL_REGS
++
++/* only one reg class, 'r', is handled automatically */
++#define REG_CLASS_FROM_LETTER(CHAR) NO_REGS
++
++#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))
++
++/* '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)
++
++
++#define DEFAULT_MAIN_RETURN c_expand_return (integer_zero_node)
++
++/**********************************
++ * 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 current_function_outgoing_args_size
++#define FIRST_PARM_OFFSET(FUNDECL) 0
++
++/* Before the prologue, RA lives in r31. */
++#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (VOIDmode, RA_REGNO)
++
++/* -------------------------------------- *
++ * 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
++
++/* 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
++#define RETURN_ADDRESS_POINTER_REGNUM RAP_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
++
++/* ----------------------------------------- *
++ * 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}, \
++ { RETURN_ADDRESS_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
++ { RETURN_ADDRESS_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \
++ { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
++ { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}}
++
++#define CAN_ELIMINATE(FROM, TO) 1
++
++#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
++ (OFFSET) = nios2_initial_elimination_offset ((FROM), (TO))
++
++#define MUST_SAVE_REGISTER(regno) \
++ ((regs_ever_live[regno] && !call_used_regs[regno]) \
++ || (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed) \
++ || (regno == RA_REGNO && regs_ever_live[RA_REGNO]))
++
++/* 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_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \
++ (function_arg_partial_nregs (&CUM, MODE, TYPE, NAMED))
++
++#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) 0
++
++#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_REGNO_P(REGNO) \
++ ((REGNO) >= FIRST_ARG_REGNO && (REGNO) <= LAST_ARG_REGNO)
++
++#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \
++ { \
++ int pret_size = nios2_setup_incoming_varargs (&(CUM), (MODE), \
++ (TYPE), (NO_RTL)); \
++ if (pret_size) \
++ (PRETEND_SIZE) = pret_size; \
++ }
++
++/* ----------------------------- *
++ * Generating Code for Profiling
++ * ----------------------------- */
++
++#define PROFILE_BEFORE_PROLOGUE
++
++#define FUNCTION_PROFILER(FILE, LABELNO) \
++ function_profiler ((FILE), (LABELNO))
++
++/* --------------------------------------- *
++ * Passing Function Arguments on the Stack
++ * --------------------------------------- */
++
++#define PROMOTE_PROTOTYPES 1
++
++#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)
++
++#define CONSTANT_ADDRESS_P(X) (CONSTANT_P (X))
++
++#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) 1
++
++/* 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 */
++#define SYMBOL_REF_IN_NIOS2_SMALL_DATA_P(RTX) \
++ (SYMBOL_REF_SMALL_P(RTX) && !SYMBOL_REF_WEAK_DECL_P(RTX))
++
++/*****************
++ * 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
++#define NO_RECURSIVE_FUNCTION_CSE
++
++
++
++/*****************************************
++ * 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
++ * -------------- */
++
++#define DWARF2_UNWIND_INFO 0
++
++
++/* -------------------------------- *
++ * 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", \
++ "r24", \
++ "r25", \
++ "gp", \
++ "sp", \
++ "fp", \
++ "ta", \
++ "ba", \
++ "ra", \
++ "status", \
++ "estatus", \
++ "bstatus", \
++ "ipri", \
++ "ecause", \
++ "pc", \
++ "rap", \
++ "fake_fp", \
++ "fake_ap", \
++}
++
++#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)
++
++
++/* ------------ *
++ * 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 \
++{ \
++ if ((SIZE) <= nios2_section_threshold) \
++ { \
++ named_section (0, ".sbss", 0); \
++ (*targetm.asm_out.globalize_label) (FILE, NAME); \
++ 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); \
++ } \
++ else \
++ { \
++ 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)
++
++
++
++/***************************
++ * Miscellaneous Parameters
++ ***************************/
++
++#define MOVE_MAX 4
++
++#define Pmode SImode
++#define FUNCTION_MODE QImode
++
++#define CASE_VECTOR_MODE Pmode
++
++#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
++
++#define LOAD_EXTEND_OP(MODE) (ZERO_EXTEND)
++
++#define WORD_REGISTER_OPERATIONS
+--- gcc-3.4.3/gcc/config/nios2/nios2.md
++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2.md
+@@ -0,0 +1,2078 @@
++;; Machine Description 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. */
++
++
++
++;*****************************************************************************
++;*
++;* constants
++;*
++;*****************************************************************************
++(define_constants [
++ (GP_REGNO 26)
++ (SP_REGNO 27)
++ (FP_REGNO 28)
++ (RA_REGNO 31)
++ (RAP_REGNO 38)
++ (FIRST_RETVAL_REGNO 2)
++ (LAST_RETVAL_REGNO 3)
++ (FIRST_ARG_REGNO 4)
++ (LAST_ARG_REGNO 7)
++ (SC_REGNO 23)
++ (PC_REGNO 37)
++ (FAKE_FP_REGNO 39)
++ (FAKE_AP_REGNO 40)
++
++
++ (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)
++
++])
++
++
++
++;*****************************************************************************
++;*
++;* 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)
++ || register_operand (operands[1], QImode)
++ || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
++ "@
++ 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 "register_operand" "r"))
++ (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)
++ || register_operand (operands[1], HImode)
++ || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
++ "@
++ 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 "register_operand" "r"))
++ (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)
++ || register_operand (operands[1], SImode)
++ || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
++ "@
++ 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 "register_operand" "r"))
++ (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" "")))]
++ ""
++{
++ if (optimize && GET_CODE (operands[1]) == MEM)
++ operands[1] = force_not_mem (operands[1]);
++
++ if (GET_CODE (operands[1]) != MEM)
++ {
++ rtx op1 = gen_lowpart (SImode, operands[1]);
++ rtx temp = gen_reg_rtx (SImode);
++ rtx shift = GEN_INT (16);
++
++ emit_insn (gen_ashlsi3 (temp, op1, shift));
++ emit_insn (gen_ashrsi3 (operands[0], temp, shift));
++ DONE;
++ }
++})
++
++(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" "")))]
++ ""
++{
++ if (optimize && GET_CODE (operands[1]) == MEM)
++ operands[1] = force_not_mem (operands[1]);
++
++ if (GET_CODE (operands[1]) != MEM)
++ {
++ rtx op0 = gen_lowpart (SImode, operands[0]);
++ rtx op1 = gen_lowpart (SImode, operands[1]);
++ rtx temp = gen_reg_rtx (SImode);
++ rtx shift = GEN_INT (24);
++
++ emit_insn (gen_ashlsi3 (temp, op1, shift));
++ emit_insn (gen_ashrsi3 (op0, temp, shift));
++ DONE;
++ }
++})
++
++(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" "")))]
++ ""
++{
++ if (optimize && GET_CODE (operands[1]) == MEM)
++ operands[1] = force_not_mem (operands[1]);
++
++ if (GET_CODE (operands[1]) != MEM)
++ {
++ rtx op1 = gen_lowpart (SImode, operands[1]);
++ rtx temp = gen_reg_rtx (SImode);
++ rtx shift = GEN_INT (24);
++
++ emit_insn (gen_ashlsi3 (temp, op1, shift));
++ emit_insn (gen_ashrsi3 (operands[0], temp, shift));
++ DONE;
++ }
++})
++
++(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 "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 "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_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 "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"
++ [(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"
++ "")
++
++(define_expand "umulsidi3"
++ [(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"
++ "")
++
++
++
++;*****************************************************************************
++;*
++;* 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 "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")])
++
++
++
++; 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")))]
++ ""
++ "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")])
++
++
++
++
++;*****************************************************************************
++;*
++;* 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")])
++
++
++
++;*****************************************************************************
++;*
++;* 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_insn "indirect_call"
++ [(call (mem:QI (match_operand:SI 0 "register_operand" "r"))
++ (match_operand 1 "" ""))
++ (clobber (reg:SI RA_REGNO))]
++ ""
++ "callr\\t%0"
++ [(set_attr "type" "control")])
++
++(define_insn "indirect_call_value"
++ [(set (match_operand 0 "" "")
++ (call (mem:QI (match_operand:SI 1 "register_operand" "r"))
++ (match_operand 2 "" "")))
++ (clobber (reg:SI RA_REGNO))]
++ ""
++ "callr\\t%1"
++)
++
++(define_expand "call"
++ [(parallel [(call (match_operand 0 "" "")
++ (match_operand 1 "" ""))
++ (clobber (reg:SI RA_REGNO))])]
++ ""
++ "")
++
++(define_expand "call_value"
++ [(parallel [(set (match_operand 0 "" "")
++ (call (match_operand 1 "" "")
++ (match_operand 2 "" "")))
++ (clobber (reg:SI RA_REGNO))])]
++ ""
++ "")
++
++(define_insn "*call"
++ [(call (mem:QI (match_operand:SI 0 "immediate_operand" "i"))
++ (match_operand 1 "" ""))
++ (clobber (match_operand:SI 2 "register_operand" "=r"))]
++ ""
++ "call\\t%0"
++ [(set_attr "type" "control")])
++
++(define_insn "*call_value"
++ [(set (match_operand 0 "" "")
++ (call (mem:QI (match_operand:SI 1 "immediate_operand" "i"))
++ (match_operand 2 "" "")))
++ (clobber (match_operand:SI 3 "register_operand" "=r"))]
++ ""
++ "call\\t%1"
++ [(set_attr "type" "control")])
++
++(define_expand "sibcall"
++ [(parallel [(call (match_operand 0 "" "")
++ (match_operand 1 "" ""))
++ (return)
++ (use (match_operand 2 "" ""))])]
++ ""
++ {
++ XEXP (operands[0], 0) = copy_to_mode_reg (SImode, XEXP (operands[0], 0));
++
++ if (operands[2] == NULL_RTX)
++ operands[2] = const0_rtx;
++ }
++)
++
++(define_expand "sibcall_value"
++ [(parallel [(set (match_operand 0 "" "")
++ (call (match_operand 1 "" "")
++ (match_operand 2 "" "")))
++ (return)
++ (use (match_operand 3 "" ""))])]
++ ""
++ {
++ XEXP (operands[1], 0) = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
++
++ if (operands[3] == NULL_RTX)
++ operands[3] = const0_rtx;
++ }
++)
++
++(define_insn "sibcall_insn"
++ [(call (mem:QI (match_operand:SI 0 "register_operand" "r"))
++ (match_operand 1 "" ""))
++ (return)
++ (use (match_operand 2 "" ""))]
++ ""
++ "jmp\\t%0"
++)
++
++(define_insn "sibcall_value_insn"
++ [(set (match_operand 0 "register_operand" "")
++ (call (mem:QI (match_operand:SI 1 "register_operand" "r"))
++ (match_operand 2 "" "")))
++ (return)
++ (use (match_operand 3 "" ""))]
++ ""
++ "jmp\\t%1"
++)
++
++
++
++
++(define_expand "tablejump"
++ [(parallel [(set (pc) (match_operand 0 "register_operand" "r"))
++ (use (label_ref (match_operand 1 "" "")))])]
++ ""
++ ""
++)
++
++(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;
++})
++
++
++;*****************************************************************************
++;*
++;* 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)
++ 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_expand "sne"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ne: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 (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_expand "sgt"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (gt: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 (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_expand "sge"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (ge: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 (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_expand "sle"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (le: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 (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_expand "slt"
++ [(set (match_operand:SI 0 "register_operand" "=r")
++ (lt: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 (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_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_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];
++
++ if (INTVAL (operands[3]) < 4)
++ abort ();
++
++ 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 "register_operand" "r")] UNSPEC_WRCTL)]
++ ""
++ "wrctl\\tctl%0, %1"
++ [(set_attr "type" "control")])
++
++
++
++;*****************************************************************************
++;*
++;* Peepholes
++;*
++;*****************************************************************************
++
++
+--- gcc-3.4.3/gcc/config/nios2/t-nios2
++++ gcc-3.4.3-nios2/gcc/config/nios2/t-nios2
+@@ -0,0 +1,123 @@
++##
++## 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=$(srcdir)/config/nios2/nios2-fp-bit.c
++DPBIT=$(srcdir)/config/nios2/nios2-dp-bit.c
++
++TARGET_LIBGCC2_CFLAGS = -O2
++
++# 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}
++ cat $(srcdir)/config/fp-bit.c >> ${FPBIT}
++
++$(DPBIT): $(srcdir)/config/fp-bit.c Makefile
++ echo '' > ${DPBIT}
++ cat $(srcdir)/config/fp-bit.c >> ${DPBIT}
++
++EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o crti.o crtn.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.
++
++MULTILIB_OPTIONS = mno-hw-mul mhw-mulx
++
++## 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.
++##
++## 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*
++##
++
++MULTILIB_EXCEPTIONS = *mno-hw-mul/*mhw-mulx*
++
++##
++## 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.
++##
++
+--- gcc-3.4.3/gcc/config.gcc
++++ gcc-3.4.3-nios2/gcc/config.gcc
+@@ -1321,6 +1321,10 @@ m32rle-*-linux*)
+ thread_file='posix'
+ fi
+ ;;
++# JBG
++nios2-*-* | nios2-*-*)
++ tm_file="elfos.h ${tm_file}"
++ ;;
+ # m68hc11 and m68hc12 share the same machine description.
+ m68hc11-*-*|m6811-*-*)
+ tm_file="dbxelf.h elfos.h m68hc11/m68hc11.h"
+--- gcc-3.4.3/gcc/cse.c
++++ gcc-3.4.3-nios2/gcc/cse.c
+@@ -3134,6 +3134,10 @@ find_comparison_args (enum rtx_code code
+ #ifdef FLOAT_STORE_FLAG_VALUE
+ REAL_VALUE_TYPE fsfv;
+ #endif
++#ifdef __nios2__
++ if (p->is_const)
++ break;
++#endif
+
+ /* If the entry isn't valid, skip it. */
+ if (! exp_equiv_p (p->exp, p->exp, 1, 0))
+--- gcc-3.4.3/gcc/doc/extend.texi
++++ gcc-3.4.3-nios2/gcc/doc/extend.texi
+@@ -5636,12 +5636,118 @@ to those machines. Generally these gene
+ instructions, but allow the compiler to schedule those calls.
+
+ @menu
++* Altera Nios II Built-in Functions::
+ * Alpha Built-in Functions::
+ * ARM Built-in Functions::
+ * X86 Built-in Functions::
+ * PowerPC AltiVec Built-in Functions::
+ @end menu
+
++@node Altera Nios II Built-in Functions
++@subsection Altera Nios II Built-in Functions
++
++These built-in functions are available for the Altera Nios II
++family of processors.
++
++The following built-in functions are always available. They
++all generate the machine instruction that is part of the name.
++
++@example
++int __builtin_ldbio (volatile const void *)
++int __builtin_ldbuio (volatile const void *)
++int __builtin_ldhio (volatile const void *)
++int __builtin_ldhuio (volatile const void *)
++int __builtin_ldwio (volatile const void *)
++void __builtin_stbio (volatile void *, int)
++void __builtin_sthio (volatile void *, int)
++void __builtin_stwio (volatile void *, int)
++void __builtin_sync (void)
++int __builtin_rdctl (int)
++void __builtin_wrctl (int, int)
++@end example
++
++The following built-in functions are always available. They
++all generate a Nios II Custom Instruction. The name of the
++function represents the types that the function takes and
++returns. The letter before the @code{n} is the return type
++or void if absent. The @code{n} represnts the first parameter
++to all the custom instructions, the custom instruction number.
++The two letters after the @code{n} represent the up to two
++parameters to the function.
++
++The letters reprsent the following data types:
++@table @code
++@item <no letter>
++@code{void} for return type and no parameter for parameter types.
++
++@item i
++@code{int} for return type and parameter type
++
++@item f
++@code{float} for return type and parameter type
++
++@item p
++@code{void *} for return type and parameter type
++
++@end table
++
++And the function names are:
++@example
++void __builtin_custom_n (void)
++void __builtin_custom_ni (int)
++void __builtin_custom_nf (float)
++void __builtin_custom_np (void *)
++void __builtin_custom_nii (int, int)
++void __builtin_custom_nif (int, float)
++void __builtin_custom_nip (int, void *)
++void __builtin_custom_nfi (float, int)
++void __builtin_custom_nff (float, float)
++void __builtin_custom_nfp (float, void *)
++void __builtin_custom_npi (void *, int)
++void __builtin_custom_npf (void *, float)
++void __builtin_custom_npp (void *, void *)
++int __builtin_custom_in (void)
++int __builtin_custom_ini (int)
++int __builtin_custom_inf (float)
++int __builtin_custom_inp (void *)
++int __builtin_custom_inii (int, int)
++int __builtin_custom_inif (int, float)
++int __builtin_custom_inip (int, void *)
++int __builtin_custom_infi (float, int)
++int __builtin_custom_inff (float, float)
++int __builtin_custom_infp (float, void *)
++int __builtin_custom_inpi (void *, int)
++int __builtin_custom_inpf (void *, float)
++int __builtin_custom_inpp (void *, void *)
++float __builtin_custom_fn (void)
++float __builtin_custom_fni (int)
++float __builtin_custom_fnf (float)
++float __builtin_custom_fnp (void *)
++float __builtin_custom_fnii (int, int)
++float __builtin_custom_fnif (int, float)
++float __builtin_custom_fnip (int, void *)
++float __builtin_custom_fnfi (float, int)
++float __builtin_custom_fnff (float, float)
++float __builtin_custom_fnfp (float, void *)
++float __builtin_custom_fnpi (void *, int)
++float __builtin_custom_fnpf (void *, float)
++float __builtin_custom_fnpp (void *, void *)
++void * __builtin_custom_pn (void)
++void * __builtin_custom_pni (int)
++void * __builtin_custom_pnf (float)
++void * __builtin_custom_pnp (void *)
++void * __builtin_custom_pnii (int, int)
++void * __builtin_custom_pnif (int, float)
++void * __builtin_custom_pnip (int, void *)
++void * __builtin_custom_pnfi (float, int)
++void * __builtin_custom_pnff (float, float)
++void * __builtin_custom_pnfp (float, void *)
++void * __builtin_custom_pnpi (void *, int)
++void * __builtin_custom_pnpf (void *, float)
++void * __builtin_custom_pnpp (void *, void *)
++@end example
++
++
+ @node Alpha Built-in Functions
+ @subsection Alpha Built-in Functions
+
+--- gcc-3.4.3/gcc/doc/invoke.texi
++++ gcc-3.4.3-nios2/gcc/doc/invoke.texi
+@@ -337,6 +337,14 @@ in the following sections.
+ @item Machine Dependent Options
+ @xref{Submodel Options,,Hardware Models and Configurations}.
+
++@emph{Altera Nios II Options}
++@gccoptlist{-msmallc -mno-bypass-cache -mbypass-cache @gol
++-mno-cache-volatile -mcache-volatile -mno-inline-memcpy @gol
++-minline-memcpy -mno-fast-sw-div -mfast-sw-div @gol
++-mhw-mul -mno-hw-mul -mhw-mulx -mno-hw-mulx @gol
++-mno-hw-div -mhw-div @gol
++-msys-crt0= -msys-lib= -msys=nosys }
++
+ @emph{M680x0 Options}
+ @gccoptlist{-m68000 -m68020 -m68020-40 -m68020-60 -m68030 -m68040 @gol
+ -m68060 -mcpu32 -m5200 -m68881 -mbitfield -mc68000 -mc68020 @gol
+@@ -5836,6 +5844,7 @@ machine description. The default for th
+ that macro, which enables you to change the defaults.
+
+ @menu
++* Altera Nios II Options::
+ * M680x0 Options::
+ * M68hc1x Options::
+ * VAX Options::
+@@ -5871,6 +5880,103 @@ that macro, which enables you to change
+ * FRV Options::
+ @end menu
+
++
++@node Altera Nios II Options
++@subsection Altera Nios II Options
++@cindex Altera Nios II options
++
++These are the @samp{-m} options defined for the Altera Nios II
++processor.
++
++@table @gcctabopt
++
++@item -msmallc
++@opindex msmallc
++
++Link with a limited version of the C library, -lsmallc. For more
++information see the C Library Documentation.
++
++
++@item -mbypass-cache
++@itemx -mno-bypass-cache
++@opindex mno-bypass-cache
++@opindex mbypass-cache
++
++Force all load and store instructions to always bypass cache by
++using io variants of the instructions. The default is to not
++bypass the cache.
++
++@item -mno-cache-volatile
++@itemx -mcache-volatile
++@opindex mcache-volatile
++@opindex mno-cache-volatile
++
++Volatile memory access bypass the cache using the io variants of
++the ld and st instructions. The default is to cache volatile
++accesses.
++
++-mno-cache-volatile is deprecated and will be deleted in a
++future GCC release.
++
++
++@item -mno-inline-memcpy
++@itemx -minline-memcpy
++@opindex mno-inline-memcpy
++@opindex minline-memcpy
++
++Do not inline memcpy. The default is to inline when -O is on.
++
++
++@item -mno-fast-sw-div
++@itemx -mfast-sw-div
++@opindex mno-fast-sw-div
++@opindex mfast-sw-div
++
++Do no use table based fast divide for small numbers. The default
++is to use the fast divide at -O3 and above.
++
++
++@item -mno-hw-mul
++@itemx -mhw-mul
++@itemx -mno-hw-mulx
++@itemx -mhw-mulx
++@itemx -mno-hw-div
++@itemx -mhw-div
++@opindex mno-hw-mul
++@opindex mhw-mul
++@opindex mno-hw-mulx
++@opindex mhw-mulx
++@opindex mno-hw-div
++@opindex mhw-div
++
++Enable or disable emitting @code{mul}, @code{mulx} and @code{div} family of
++instructions by the compiler. The default is to emit @code{mul}
++and not emit @code{div} and @code{mulx}.
++
++The different combinations of @code{mul} and @code{mulx} instructions
++generate a different multilib options.
++
++
++@item -msys-crt0=@var{startfile}
++@opindex msys-crt0
++
++@var{startfile} is the file name of the startfile (crt0) to use
++when linking. The default is crt0.o that comes with libgloss
++and is only suitable for use with the instruction set
++simulator.
++
++@item -msys-lib=@var{systemlib}
++@itemx -msys-lib=nosys
++@opindex msys-lib
++
++@var{systemlib} is the library name of the library which provides
++the system calls required by the C library, e.g. @code{read}, @code{write}
++etc. The default is to use nosys, this library provides
++stub implementations of the calls and is part of libgloss.
++
++@end table
++
++
+ @node M680x0 Options
+ @subsection M680x0 Options
+ @cindex M680x0 options
+--- gcc-3.4.3/gcc/doc/md.texi
++++ gcc-3.4.3-nios2/gcc/doc/md.texi
+@@ -1335,6 +1335,49 @@ However, here is a summary of the machin
+ available on some particular machines.
+
+ @table @emph
++
++@item Altera Nios II family---@file{nios2.h}
++@table @code
++
++@item I
++Integer that is valid as an immediate operand in an
++instruction taking a signed 16-bit number. Range
++@minus{}32768 to 32767.
++
++@item J
++Integer that is valid as an immediate operand in an
++instruction taking an unsigned 16-bit number. Range
++0 to 65535.
++
++@item K
++Integer that is valid as an immediate operand in an
++instruction taking only the upper 16-bits of a
++32-bit number. Range 32-bit numbers with the lower
++16-bits being 0.
++
++@item L
++Integer that is valid as an immediate operand for a
++shift instruction. Range 0 to 31.
++
++
++@item M
++Integer that is valid as an immediate operand for
++only the value 0. Can be used in conjunction with
++the format modifier @code{z} to use @code{r0}
++instead of @code{0} in the assembly output.
++
++@item N
++Integer that is valid as an immediate operand for
++a custom instruction opcode. Range 0 to 255.
++
++@item S
++Matches immediates which are addresses in the small
++data section and therefore can be added to @code{gp}
++as a 16-bit immediate to re-create their 32-bit value.
++
++@end table
++
++
+ @item ARM family---@file{arm.h}
+ @table @code
+ @item f
diff --git a/toolchain/gcc/Config.in b/toolchain/gcc/Config.in
index ed7356e53..a821e3cca 100644
--- a/toolchain/gcc/Config.in
+++ b/toolchain/gcc/Config.in
@@ -23,11 +23,9 @@ choice
bool "gcc 3.4.3"
config BR2_GCC_VERSION_3_4_4
- depends !BR2_nios2
bool "gcc 3.4.4"
config BR2_GCC_VERSION_3_4_5
- depends !BR2_nios2
bool "gcc 3.4.5"
config BR2_GCC_VERSION_4_0_0