diff options
Diffstat (limited to 'toolchain/gcc/3.4.2')
-rw-r--r-- | toolchain/gcc/3.4.2/900-nios2.patch | 10210 |
1 files changed, 10210 insertions, 0 deletions
diff --git a/toolchain/gcc/3.4.2/900-nios2.patch b/toolchain/gcc/3.4.2/900-nios2.patch new file mode 100644 index 000000000..91bf7fea1 --- /dev/null +++ b/toolchain/gcc/3.4.2/900-nios2.patch @@ -0,0 +1,10210 @@ +--- gcc-3.4.2/gcc/Makefile.in ++++ gcc-3.4.2.nios2/gcc/Makefile.in +@@ -3067,7 +3067,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.2/gcc/combine.c ++++ gcc-3.4.2.nios2/gcc/combine.c +@@ -4379,6 +4379,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 +@@ -4390,6 +4398,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.2/gcc/config/nios2/crti.asm ++++ gcc-3.4.2.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.2/gcc/config/nios2/crtn.asm ++++ gcc-3.4.2.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.2/gcc/config/nios2/lib2-divmod-hi.c ++++ gcc-3.4.2.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.2/gcc/config/nios2/lib2-divmod.c ++++ gcc-3.4.2.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.2/gcc/config/nios2/lib2-divtable.c ++++ gcc-3.4.2.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.2/gcc/config/nios2/lib2-mul.c ++++ gcc-3.4.2.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.2/gcc/config/nios2/nios2-dp-bit.c ++++ gcc-3.4.2.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.2/gcc/config/nios2/nios2-fp-bit.c ++++ gcc-3.4.2.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.2/gcc/config/nios2/nios2-protos.h ++++ gcc-3.4.2.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.2/gcc/config/nios2/nios2.c ++++ gcc-3.4.2.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.2/gcc/config/nios2/nios2.h ++++ gcc-3.4.2.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=*: crt0%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.2/gcc/config/nios2/nios2.md ++++ gcc-3.4.2.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.2/gcc/config/nios2/t-nios2 ++++ gcc-3.4.2.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.2/gcc/config.gcc ++++ gcc-3.4.2.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.2/gcc/cse.c ++++ gcc-3.4.2.nios2/gcc/cse.c +@@ -3133,6 +3133,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.2/gcc/doc/extend.texi ++++ gcc-3.4.2.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.2/gcc/doc/invoke.texi ++++ gcc-3.4.2.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.2/gcc/doc/md.texi ++++ gcc-3.4.2.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 |