buildrootschalter/toolchain/gcc/3.4.6/900-nios2.patch

14378 lines
407 KiB
Diff
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

diff --git a/config.sub b/config.sub
index d2e3557..2297c30 100755
--- a/config.sub
+++ b/config.sub
@@ -276,6 +276,15 @@ case $basic_machine in
basic_machine=$basic_machine-unknown
os=-none
;;
+ # JBG
+ nios2 | nios2-* | nios2el | nios2el-*)
+ basic_machine=nios2-altera
+ os=-none_el
+ ;;
+ nios2eb | nios2eb-*)
+ basic_machine=nios2-altera
+ os=-none_eb
+ ;;
m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
;;
diff --git a/gcc/combine.c b/gcc/combine.c
index 8f43c23..02648b1 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -4381,6 +4381,14 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
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
@@ -4392,6 +4400,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
gen_lowpart_for_combine (mode, op0),
const1_rtx);
}
+#endif
else if (STORE_FLAG_VALUE == 1
&& new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
diff --git a/gcc/config.gcc b/gcc/config.gcc
index d22f34b..4ecb6e9 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -1337,6 +1337,17 @@ m32rle-*-linux*)
thread_file='posix'
fi
;;
+# JBG
+nios2-*-elf*_eb)
+ tm_file="elfos.h nios2/big.h ${tm_file}"
+ ;;
+nios2-*-elf*)
+ tm_file="elfos.h ${tm_file}"
+ ;;
+nios2-*-uclibc*) # Altera Nios2 running uClinux with uClibc
+ tm_file="elfos.h ${tm_file} nios2/nios2-uclibc.h"
+ tmake_file=nios2/t-nios2-uclibc
+ ;;
# m68hc11 and m68hc12 share the same machine description.
m68hc11-*-*|m6811-*-*)
tm_file="dbxelf.h elfos.h m68hc11/m68hc11.h"
diff --git a/gcc/config/nios2/big.h b/gcc/config/nios2/big.h
new file mode 100644
index 0000000..b7b1731
--- /dev/null
+++ b/gcc/config/nios2/big.h
@@ -0,0 +1,23 @@
+/*
+ big.h - Additional definitions for nios2 targets that default to big-endian
+
+ Copyright (C) 2006 Altera
+
+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_ENDIAN_DEFAULT BIG_ENDIAN_FLAG
diff --git a/gcc/config/nios2/crti.asm b/gcc/config/nios2/crti.asm
new file mode 100644
index 0000000..1fcfeb2
--- /dev/null
+++ b/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
+
+
diff --git a/gcc/config/nios2/crtn.asm b/gcc/config/nios2/crtn.asm
new file mode 100644
index 0000000..e337480
--- /dev/null
+++ b/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
+
diff --git a/gcc/config/nios2/lib2-divmod-hi.c b/gcc/config/nios2/lib2-divmod-hi.c
new file mode 100644
index 0000000..10bd6e4
--- /dev/null
+++ b/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);
+}
+
diff --git a/gcc/config/nios2/lib2-divmod.c b/gcc/config/nios2/lib2-divmod.c
new file mode 100644
index 0000000..00e730d
--- /dev/null
+++ b/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);
+}
+
diff --git a/gcc/config/nios2/lib2-divtable.c b/gcc/config/nios2/lib2-divtable.c
new file mode 100644
index 0000000..48a7bd7
--- /dev/null
+++ b/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,
+};
+
diff --git a/gcc/config/nios2/lib2-mul.c b/gcc/config/nios2/lib2-mul.c
new file mode 100644
index 0000000..8511b33
--- /dev/null
+++ b/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
diff --git a/gcc/config/nios2/nios2-dp-bit.c b/gcc/config/nios2/nios2-dp-bit.c
new file mode 100644
index 0000000..4d63748
--- /dev/null
+++ b/gcc/config/nios2/nios2-dp-bit.c
@@ -0,0 +1,1655 @@
+
+#ifndef __nios2_big_endian__
+#define FLOAT_BIT_ORDER_MISMATCH
+#endif
+/* 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 */
diff --git a/gcc/config/nios2/nios2-fp-bit.c b/gcc/config/nios2/nios2-fp-bit.c
new file mode 100644
index 0000000..839ffcc
--- /dev/null
+++ b/gcc/config/nios2/nios2-fp-bit.c
@@ -0,0 +1,1655 @@
+#define FLOAT
+#ifndef __nios2_big_endian__
+#define FLOAT_BIT_ORDER_MISMATCH
+#endif
+/* 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 */
diff --git a/gcc/config/nios2/nios2-protos.h b/gcc/config/nios2/nios2-protos.h
new file mode 100644
index 0000000..dc75c4f
--- /dev/null
+++ b/gcc/config/nios2/nios2-protos.h
@@ -0,0 +1,78 @@
+/* Subroutines for assembler code output for Altera NIOS 2G NIOS2 version.
+ Copyright (C) 2003 Altera
+ Contributed by Jonah Graham (jgraham@altera.com).
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+extern void dump_frame_size (FILE *);
+extern HOST_WIDE_INT compute_frame_size (void);
+extern int nios2_initial_elimination_offset (int, int);
+extern void override_options (void);
+extern void optimization_options (int, int);
+extern int nios2_can_use_return_insn (void);
+extern void expand_prologue (void);
+extern void expand_epilogue (bool);
+extern void function_profiler (FILE *, int);
+extern enum reg_class reg_class_from_constraint (char, const char *);
+extern void nios2_register_target_pragmas (void);
+
+#ifdef RTX_CODE
+extern int nios2_legitimate_address (rtx, enum machine_mode, int);
+extern 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);
+
+/* custom fpu instruction output */
+extern const char *nios2_output_fpu_insn_cmps (rtx, enum rtx_code);
+extern const char *nios2_output_fpu_insn_cmpd (rtx, enum rtx_code);
+
+# ifdef HAVE_MACHINE_MODES
+# if defined TREE_CODE
+extern rtx function_arg (const CUMULATIVE_ARGS *, enum machine_mode, tree, int);
+extern int nios2_must_pass_in_stack (enum machine_mode, tree);
+extern int function_arg_partial_nregs (const CUMULATIVE_ARGS *, enum machine_mode, tree, int);
+extern void function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode, tree, int);
+extern int nios2_function_arg_padding (enum machine_mode, tree);
+extern int nios2_block_reg_padding (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 */
diff --git a/gcc/config/nios2/nios2-uclibc.h b/gcc/config/nios2/nios2-uclibc.h
new file mode 100644
index 0000000..af98cdd
--- /dev/null
+++ b/gcc/config/nios2/nios2-uclibc.h
@@ -0,0 +1,75 @@
+#ifdef USE_UCLIBC
+
+#undef TARGET_SWITCHES
+#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") }, \
+ { "stack-check", STACK_CHECK_FLAG, \
+ N_("Enable stack limit checking.") }, \
+ { "no-stack-check", -STACK_CHECK_FLAG, \
+ N_("Disable stack limit checking (default).") }, \
+ { "reverse-bitfields", REVERSE_BITFIELDS_FLAG, \
+ N_("Reverse the order of bitfields in a struct.") }, \
+ { "no-reverse-bitfields", -REVERSE_BITFIELDS_FLAG, \
+ N_("Use the normal order of bitfields in a struct (default).") }, \
+ { "eb", BIG_ENDIAN_FLAG, \
+ N_("Use big-endian byte order") }, \
+ { "el", -BIG_ENDIAN_FLAG, \
+ N_("Use little-endian byte order") }, \
+ { "", TARGET_DEFAULT, 0 } \
+}
+
+/* The GNU C++ standard library requires that these macros be defined. */
+#undef CPLUSPLUS_CPP_SPEC
+#define CPLUSPLUS_CPP_SPEC "-D_GNU_SOURCE %(cpp)"
+
+#undef LIB_SPEC
+#define LIB_SPEC \
+"--start-group %{msmallc: -lsmallc} %{!msmallc: -lc} -lgcc \
+ %{msys-lib=*: -l%*} \
+ %{!msys-lib=*: -lc} \
+ --end-group \
+ %{msys-lib=: %eYou need a library name for -msys-lib=} \
+"
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC \
+"%{msys-crt0=*: %*} %{!msys-crt0=*: crt1%O%s} \
+ %{msys-crt0=: %eYou need a C startup file for -msys-crt0=} \
+ crti%O%s crtbegin%O%s \
+"
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC \
+ " crtend%O%s crtn%O%s"
+
+#endif /* USE_UCLIBC */
diff --git a/gcc/config/nios2/nios2.c b/gcc/config/nios2/nios2.c
new file mode 100644
index 0000000..8723a86
--- /dev/null
+++ b/gcc/config/nios2/nios2.c
@@ -0,0 +1,4694 @@
+/* Subroutines for assembler code output for Altera NIOS 2G NIOS2 version.
+ Copyright (C) 2005 Altera
+ Contributed by Jonah Graham (jgraham@altera.com) and Will Reece (wreece@altera.com).
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+#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"
+#include "c-pragma.h" /* for c_register_pragma */
+#include "cpplib.h" /* for CPP_NUMBER */
+
+/* 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);
+
+/* 0 --> no #pragma seen
+ 1 --> in scope of #pragma reverse_bitfields
+ -1 --> in scope of #pragma no_reverse_bitfields */
+static int nios2_pragma_reverse_bitfields_flag = 0;
+static void nios2_pragma_reverse_bitfields (struct cpp_reader *);
+static void nios2_pragma_no_reverse_bitfields (struct cpp_reader *);
+static tree nios2_handle_struct_attribute (tree *, tree, tree, int, bool *);
+static void nios2_insert_attributes (tree, tree *);
+static bool nios2_reverse_bitfield_layout_p (tree record_type);
+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_REVERSE_BITFIELD_LAYOUT_P
+#define TARGET_REVERSE_BITFIELD_LAYOUT_P nios2_reverse_bitfield_layout_p
+
+#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
+
+const struct attribute_spec nios2_attribute_table[] =
+{
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ { "reverse_bitfields", 0, 0, false, false, false, nios2_handle_struct_attribute },
+ { "no_reverse_bitfields", 0, 0, false, false, false, nios2_handle_struct_attribute },
+ { "pragma_reverse_bitfields", 0, 0, false, false, false, NULL },
+ { "pragma_no_reverse_bitfields", 0, 0, false, false, false, NULL },
+ { NULL, 0, 0, false, false, false, NULL }
+};
+
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE nios2_attribute_table
+
+#undef TARGET_INSERT_ATTRIBUTES
+#define TARGET_INSERT_ATTRIBUTES nios2_insert_attributes
+
+/* ??? Might want to redefine TARGET_RETURN_IN_MSB here to handle
+ big-endian case; depends on what ABI we choose. */
+
+struct gcc_target targetm = TARGET_INITIALIZER;
+
+
+
+/* Threshold for data being put into the small data/bss area, instead
+ of the normal data area (references to the small data/bss area take
+ 1 instruction, and use the global pointer, references to the normal
+ data area takes 2 instructions). */
+unsigned HOST_WIDE_INT nios2_section_threshold = NIOS2_DEFAULT_GVALUE;
+
+
+/* Structure to be filled in by compute_frame_size with register
+ save masks, and offsets for the current function. */
+
+struct nios2_frame_info
+GTY (())
+{
+ 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;
+};
+
+
+/***************************************
+ * Register Classes
+ ***************************************/
+
+enum reg_class
+reg_class_from_constraint (char chr, const char *str)
+{
+ if (chr == 'D' && ISDIGIT (str[1]) && ISDIGIT (str[2]))
+ {
+ int regno;
+ int ones = str[2] - '0';
+ int tens = str[1] - '0';
+
+ regno = ones + (10 * tens);
+ if (regno < 0 || regno > 31)
+ return NO_REGS;
+
+ return D00_REG + regno;
+ }
+
+ return NO_REGS;
+}
+
+
+/***************************************
+ * Stack Layout and Calling Conventions
+ ***************************************/
+
+
+#define TOO_BIG_OFFSET(X) ((X) > ((1 << 15) - 1))
+#define TEMP_REG_NUM 8
+
+static void
+nios2_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
+{
+ if (flag_verbose_asm || flag_debug_asm)
+ {
+ compute_frame_size ();
+ dump_frame_size (file);
+ }
+}
+
+static 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 = 0;
+ 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 (current_function_limit_stack)
+ {
+ emit_insn (gen_stack_overflow_detect_and_trap ());
+ }
+ }
+
+ 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 ATTRIBUTE_UNUSED)
+{
+ fprintf (file, "\tmov\tr8, ra\n");
+ fprintf (file, "\tcall\tmcount\n");
+ fprintf (file, "\tmov\tra, r8\n");
+}
+
+
+/***************************************
+ * Stack Layout
+ ***************************************/
+
+
+void
+dump_frame_size (FILE *file)
+{
+ fprintf (file, "\t%s Current Frame Info\n", ASM_COMMENT_START);
+
+ fprintf (file, "\t%s total_size = %ld\n", ASM_COMMENT_START,
+ cfun->machine->frame.total_size);
+ fprintf (file, "\t%s var_size = %ld\n", ASM_COMMENT_START,
+ cfun->machine->frame.var_size);
+ fprintf (file, "\t%s args_size = %ld\n", ASM_COMMENT_START,
+ cfun->machine->frame.args_size);
+ fprintf (file, "\t%s save_reg_size = %d\n", ASM_COMMENT_START,
+ cfun->machine->frame.save_reg_size);
+ fprintf (file, "\t%s 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;
+}
+
+
+
+
+
+/***************************************
+ *
+ ***************************************/
+
+/*
+ * Try to take a bit of tedium out of the __builtin_custom_<blah>
+ * builtin functions, too.
+ */
+
+#define NIOS2_FOR_ALL_CUSTOM_BUILTINS \
+ NIOS2_DO_BUILTIN (N, n, n ) \
+ NIOS2_DO_BUILTIN (NI, ni, nX ) \
+ NIOS2_DO_BUILTIN (NF, nf, nX ) \
+ NIOS2_DO_BUILTIN (NP, np, nX ) \
+ NIOS2_DO_BUILTIN (NII, nii, nXX ) \
+ NIOS2_DO_BUILTIN (NIF, nif, nXX ) \
+ NIOS2_DO_BUILTIN (NIP, nip, nXX ) \
+ NIOS2_DO_BUILTIN (NFI, nfi, nXX ) \
+ NIOS2_DO_BUILTIN (NFF, nff, nXX ) \
+ NIOS2_DO_BUILTIN (NFP, nfp, nXX ) \
+ NIOS2_DO_BUILTIN (NPI, npi, nXX ) \
+ NIOS2_DO_BUILTIN (NPF, npf, nXX ) \
+ NIOS2_DO_BUILTIN (NPP, npp, nXX ) \
+ NIOS2_DO_BUILTIN (IN, in, Xn ) \
+ NIOS2_DO_BUILTIN (INI, ini, XnX ) \
+ NIOS2_DO_BUILTIN (INF, inf, XnX ) \
+ NIOS2_DO_BUILTIN (INP, inp, XnX ) \
+ NIOS2_DO_BUILTIN (INII, inii, XnXX ) \
+ NIOS2_DO_BUILTIN (INIF, inif, XnXX ) \
+ NIOS2_DO_BUILTIN (INIP, inip, XnXX ) \
+ NIOS2_DO_BUILTIN (INFI, infi, XnXX ) \
+ NIOS2_DO_BUILTIN (INFF, inff, XnXX ) \
+ NIOS2_DO_BUILTIN (INFP, infp, XnXX ) \
+ NIOS2_DO_BUILTIN (INPI, inpi, XnXX ) \
+ NIOS2_DO_BUILTIN (INPF, inpf, XnXX ) \
+ NIOS2_DO_BUILTIN (INPP, inpp, XnXX ) \
+ NIOS2_DO_BUILTIN (FN, fn, Xn ) \
+ NIOS2_DO_BUILTIN (FNI, fni, XnX ) \
+ NIOS2_DO_BUILTIN (FNF, fnf, XnX ) \
+ NIOS2_DO_BUILTIN (FNP, fnp, XnX ) \
+ NIOS2_DO_BUILTIN (FNII, fnii, XnXX ) \
+ NIOS2_DO_BUILTIN (FNIF, fnif, XnXX ) \
+ NIOS2_DO_BUILTIN (FNIP, fnip, XnXX ) \
+ NIOS2_DO_BUILTIN (FNFI, fnfi, XnXX ) \
+ NIOS2_DO_BUILTIN (FNFF, fnff, XnXX ) \
+ NIOS2_DO_BUILTIN (FNFP, fnfp, XnXX ) \
+ NIOS2_DO_BUILTIN (FNPI, fnpi, XnXX ) \
+ NIOS2_DO_BUILTIN (FNPF, fnpf, XnXX ) \
+ NIOS2_DO_BUILTIN (FNPP, fnpp, XnXX ) \
+ NIOS2_DO_BUILTIN (PN, pn, Xn ) \
+ NIOS2_DO_BUILTIN (PNI, pni, XnX ) \
+ NIOS2_DO_BUILTIN (PNF, pnf, XnX ) \
+ NIOS2_DO_BUILTIN (PNP, pnp, XnX ) \
+ NIOS2_DO_BUILTIN (PNII, pnii, XnXX ) \
+ NIOS2_DO_BUILTIN (PNIF, pnif, XnXX ) \
+ NIOS2_DO_BUILTIN (PNIP, pnip, XnXX ) \
+ NIOS2_DO_BUILTIN (PNFI, pnfi, XnXX ) \
+ NIOS2_DO_BUILTIN (PNFF, pnff, XnXX ) \
+ NIOS2_DO_BUILTIN (PNFP, pnfp, XnXX ) \
+ NIOS2_DO_BUILTIN (PNPI, pnpi, XnXX ) \
+ NIOS2_DO_BUILTIN (PNPF, pnpf, XnXX ) \
+ NIOS2_DO_BUILTIN (PNPP, pnpp, XnXX )
+
+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= */
+
+#undef NIOS2_FPU_INSN
+#define NIOS2_FPU_INSN(opt, insn, args) \
+static const char *NIOS2_CONCAT (nios2_output_fpu_insn_, insn) (rtx); \
+static void NIOS2_CONCAT (nios2_pragma_, insn) (struct cpp_reader *); \
+static void NIOS2_CONCAT (nios2_pragma_no_, insn) (struct cpp_reader *);
+NIOS2_FOR_ALL_FPU_INSNS
+
+nios2_fpu_info nios2_fpu_insns[nios2_fpu_max_insn] = {
+#undef NIOS2_FPU_INSN
+#define NIOS2_FPU_INSN(opt, insn, args) \
+ { NIOS2_STRINGIFY (opt), \
+ NIOS2_STRINGIFY (insn), \
+ NIOS2_STRINGIFY (args), \
+ 0, \
+ -1, \
+ NIOS2_CONCAT (nios2_output_fpu_insn_, insn), \
+ "custom_" NIOS2_STRINGIFY (opt), \
+ NIOS2_CONCAT (nios2_pragma_, insn), \
+ "no_custom_" NIOS2_STRINGIFY (opt), \
+ NIOS2_CONCAT (nios2_pragma_no_, insn), \
+ 0, \
+ 0, \
+ 0, \
+ 0, \
+ 0 },
+ NIOS2_FOR_ALL_FPU_INSNS
+};
+
+const char *nios2_custom_fpu_cfg_string;
+
+static const char *builtin_custom_seen[256];
+
+static void
+nios2_custom_switch (const char *parameter, int *value, const char *opt)
+{
+ /*
+ * We only document values from 0-255, but we secretly allow -1 so
+ * that the -mno-custom-<opt> switches work.
+ */
+ if (parameter && *parameter)
+ {
+ char *endptr;
+ long v = strtol (parameter, &endptr, 0);
+ if (*endptr)
+ {
+ error ("switch `-mcustom-%s' value `%s' must be a number between 0 and 255",
+ opt, parameter);
+ }
+ if (v < -1 || v > 255)
+ {
+ error ("switch `-mcustom-%s' value %ld must be between 0 and 255",
+ opt, v);
+ }
+ *value = (int)v;
+ }
+}
+
+static void
+nios2_custom_check_insns (int is_pragma)
+{
+ int i;
+ int has_double = 0;
+ int errors = 0;
+ const char *ns[256];
+ int ps[256];
+
+ for (i = 0; i < nios2_fpu_max_insn; i++)
+ {
+ if (nios2_fpu_insns[i].is_double && nios2_fpu_insns[i].N >= 0)
+ {
+ has_double = 1;
+ }
+ }
+
+ if (has_double)
+ {
+ for (i = 0; i < nios2_fpu_max_insn; i++)
+ {
+ if (nios2_fpu_insns[i].needed_by_double
+ && nios2_fpu_insns[i].N < 0)
+ {
+ if (is_pragma)
+ {
+ error ("either switch `-mcustom-%s' or `#pragma custom_%s' is required for double precision floating point",
+ nios2_fpu_insns[i].option,
+ nios2_fpu_insns[i].option);
+ }
+ else
+ {
+ error ("switch `-mcustom-%s' is required for double precision floating point",
+ nios2_fpu_insns[i].option);
+ }
+ errors = 1;
+ }
+ }
+ }
+
+ /*
+ * Warn if the user has certain exotic operations that won't get used
+ * without -funsafe-math-optimizations, See expand_builtin () in
+ * bulitins.c.
+ */
+ if (!flag_unsafe_math_optimizations)
+ {
+ for (i = 0; i < nios2_fpu_max_insn; i++)
+ {
+ if (nios2_fpu_insns[i].needs_unsafe && nios2_fpu_insns[i].N >= 0)
+ {
+ warning ("%s%s' has no effect unless -funsafe-math-optimizations is specified",
+ is_pragma ? "`#pragma custom_" : "switch `-mcustom-",
+ nios2_fpu_insns[i].option);
+ /* Just one warning per function per compilation unit, please. */
+ nios2_fpu_insns[i].needs_unsafe = 0;
+ }
+ }
+ }
+
+ /*
+ * Warn if the user is trying to use -mcustom-fmins et. al, that won't
+ * get used without -ffinite-math-only. See fold in fold () in
+ * fold-const.c
+ */
+ if (!flag_finite_math_only)
+ {
+ for (i = 0; i < nios2_fpu_max_insn; i++)
+ {
+ if (nios2_fpu_insns[i].needs_finite && nios2_fpu_insns[i].N >= 0)
+ {
+ warning ("%s%s' has no effect unless -ffinite-math-only is specified",
+ is_pragma ? "`#pragma custom_" : "switch `-mcustom-",
+ nios2_fpu_insns[i].option);
+ /* Just one warning per function per compilation unit, please. */
+ nios2_fpu_insns[i].needs_finite = 0;
+ }
+ }
+ }
+
+ /*
+ * Warn the user about double precision divide braindamage until we
+ * can fix it properly. See the RDIV_EXPR case of expand_expr_real in
+ * expr.c.
+ */
+ {
+ static int warned = 0;
+ if (flag_unsafe_math_optimizations
+ && !optimize_size
+ && nios2_fpu_insns[nios2_fpu_divdf3].N >= 0
+ && !warned)
+ {
+ warning ("%s%s' behaves poorly without -Os",
+ is_pragma ? "`#pragma custom_" : "switch `-mcustom-",
+ nios2_fpu_insns[nios2_fpu_divdf3].option);
+ warned = 1;
+ }
+ }
+
+ /*
+ * The following bit of voodoo is lifted from the generated file
+ * insn-opinit.c: to allow #pragmas to work properly, we have to tweak
+ * the optab_table manually -- it only gets initialized once after the
+ * switches are handled and before any #pragmas are seen.
+ */
+ if (is_pragma)
+ {
+ /* Only do this if the optabs have already been defined, not
+ when we're handling command line switches. */
+ addv_optab->handlers[SFmode].insn_code =
+ add_optab->handlers[SFmode].insn_code = CODE_FOR_nothing;
+ addv_optab->handlers[DFmode].insn_code =
+ add_optab->handlers[DFmode].insn_code = CODE_FOR_nothing;
+ subv_optab->handlers[SFmode].insn_code =
+ sub_optab->handlers[SFmode].insn_code = CODE_FOR_nothing;
+ subv_optab->handlers[DFmode].insn_code =
+ sub_optab->handlers[DFmode].insn_code = CODE_FOR_nothing;
+ smulv_optab->handlers[SFmode].insn_code =
+ smul_optab->handlers[SFmode].insn_code = CODE_FOR_nothing;
+ smulv_optab->handlers[DFmode].insn_code =
+ smul_optab->handlers[DFmode].insn_code = CODE_FOR_nothing;
+ sdiv_optab->handlers[SFmode].insn_code = CODE_FOR_nothing;
+ sdiv_optab->handlers[DFmode].insn_code = CODE_FOR_nothing;
+ negv_optab->handlers[SFmode].insn_code =
+ neg_optab->handlers[SFmode].insn_code = CODE_FOR_nothing;
+ negv_optab->handlers[DFmode].insn_code =
+ neg_optab->handlers[DFmode].insn_code = CODE_FOR_nothing;
+ smin_optab->handlers[SFmode].insn_code = CODE_FOR_nothing;
+ smin_optab->handlers[DFmode].insn_code = CODE_FOR_nothing;
+ smax_optab->handlers[SFmode].insn_code = CODE_FOR_nothing;
+ smax_optab->handlers[DFmode].insn_code = CODE_FOR_nothing;
+ absv_optab->handlers[SFmode].insn_code =
+ abs_optab->handlers[SFmode].insn_code = CODE_FOR_nothing;
+ absv_optab->handlers[DFmode].insn_code =
+ abs_optab->handlers[DFmode].insn_code = CODE_FOR_nothing;
+ sqrt_optab->handlers[SFmode].insn_code = CODE_FOR_nothing;
+ sqrt_optab->handlers[DFmode].insn_code = CODE_FOR_nothing;
+ cos_optab->handlers[SFmode].insn_code = CODE_FOR_nothing;
+ cos_optab->handlers[DFmode].insn_code = CODE_FOR_nothing;
+ sin_optab->handlers[SFmode].insn_code = CODE_FOR_nothing;
+ sin_optab->handlers[DFmode].insn_code = CODE_FOR_nothing;
+ tan_optab->handlers[SFmode].insn_code = CODE_FOR_nothing;
+ tan_optab->handlers[DFmode].insn_code = CODE_FOR_nothing;
+ atan_optab->handlers[SFmode].insn_code = CODE_FOR_nothing;
+ atan_optab->handlers[DFmode].insn_code = CODE_FOR_nothing;
+ exp_optab->handlers[SFmode].insn_code = CODE_FOR_nothing;
+ exp_optab->handlers[DFmode].insn_code = CODE_FOR_nothing;
+ log_optab->handlers[SFmode].insn_code = CODE_FOR_nothing;
+ log_optab->handlers[DFmode].insn_code = CODE_FOR_nothing;
+ sfloat_optab->handlers[SFmode][SImode].insn_code = CODE_FOR_nothing;
+ sfloat_optab->handlers[DFmode][SImode].insn_code = CODE_FOR_nothing;
+ ufloat_optab->handlers[SFmode][SImode].insn_code = CODE_FOR_nothing;
+ ufloat_optab->handlers[DFmode][SImode].insn_code = CODE_FOR_nothing;
+ sfix_optab->handlers[SImode][SFmode].insn_code = CODE_FOR_nothing;
+ sfix_optab->handlers[SImode][DFmode].insn_code = CODE_FOR_nothing;
+ ufix_optab->handlers[SImode][SFmode].insn_code = CODE_FOR_nothing;
+ ufix_optab->handlers[SImode][DFmode].insn_code = CODE_FOR_nothing;
+ sext_optab->handlers[DFmode][SFmode].insn_code = CODE_FOR_nothing;
+ trunc_optab->handlers[SFmode][DFmode].insn_code = CODE_FOR_nothing;
+ cmp_optab->handlers[SFmode].insn_code = CODE_FOR_nothing;
+ cmp_optab->handlers[DFmode].insn_code = CODE_FOR_nothing;
+
+ if (HAVE_addsf3)
+ addv_optab->handlers[SFmode].insn_code =
+ add_optab->handlers[SFmode].insn_code = CODE_FOR_addsf3;
+ if (HAVE_adddf3)
+ addv_optab->handlers[DFmode].insn_code =
+ add_optab->handlers[DFmode].insn_code = CODE_FOR_adddf3;
+ if (HAVE_subsf3)
+ subv_optab->handlers[SFmode].insn_code =
+ sub_optab->handlers[SFmode].insn_code = CODE_FOR_subsf3;
+ if (HAVE_subdf3)
+ subv_optab->handlers[DFmode].insn_code =
+ sub_optab->handlers[DFmode].insn_code = CODE_FOR_subdf3;
+ if (HAVE_mulsf3)
+ smulv_optab->handlers[SFmode].insn_code =
+ smul_optab->handlers[SFmode].insn_code = CODE_FOR_mulsf3;
+ if (HAVE_muldf3)
+ smulv_optab->handlers[DFmode].insn_code =
+ smul_optab->handlers[DFmode].insn_code = CODE_FOR_muldf3;
+ if (HAVE_divsf3)
+ sdiv_optab->handlers[SFmode].insn_code = CODE_FOR_divsf3;
+ if (HAVE_divdf3)
+ sdiv_optab->handlers[DFmode].insn_code = CODE_FOR_divdf3;
+ if (HAVE_negsf2)
+ negv_optab->handlers[SFmode].insn_code =
+ neg_optab->handlers[SFmode].insn_code = CODE_FOR_negsf2;
+ if (HAVE_negdf2)
+ negv_optab->handlers[DFmode].insn_code =
+ neg_optab->handlers[DFmode].insn_code = CODE_FOR_negdf2;
+ if (HAVE_minsf3)
+ smin_optab->handlers[SFmode].insn_code = CODE_FOR_minsf3;
+ if (HAVE_mindf3)
+ smin_optab->handlers[DFmode].insn_code = CODE_FOR_mindf3;
+ if (HAVE_maxsf3)
+ smax_optab->handlers[SFmode].insn_code = CODE_FOR_maxsf3;
+ if (HAVE_maxdf3)
+ smax_optab->handlers[DFmode].insn_code = CODE_FOR_maxdf3;
+ if (HAVE_abssf2)
+ absv_optab->handlers[SFmode].insn_code =
+ abs_optab->handlers[SFmode].insn_code = CODE_FOR_abssf2;
+ if (HAVE_absdf2)
+ absv_optab->handlers[DFmode].insn_code =
+ abs_optab->handlers[DFmode].insn_code = CODE_FOR_absdf2;
+ if (HAVE_sqrtsf2)
+ sqrt_optab->handlers[SFmode].insn_code = CODE_FOR_sqrtsf2;
+ if (HAVE_sqrtdf2)
+ sqrt_optab->handlers[DFmode].insn_code = CODE_FOR_sqrtdf2;
+ if (HAVE_cossf2)
+ cos_optab->handlers[SFmode].insn_code = CODE_FOR_cossf2;
+ if (HAVE_cosdf2)
+ cos_optab->handlers[DFmode].insn_code = CODE_FOR_cosdf2;
+ if (HAVE_sinsf2)
+ sin_optab->handlers[SFmode].insn_code = CODE_FOR_sinsf2;
+ if (HAVE_sindf2)
+ sin_optab->handlers[DFmode].insn_code = CODE_FOR_sindf2;
+ if (HAVE_tansf2)
+ tan_optab->handlers[SFmode].insn_code = CODE_FOR_tansf2;
+ if (HAVE_tandf2)
+ tan_optab->handlers[DFmode].insn_code = CODE_FOR_tandf2;
+ if (HAVE_atansf2)
+ atan_optab->handlers[SFmode].insn_code = CODE_FOR_atansf2;
+ if (HAVE_atandf2)
+ atan_optab->handlers[DFmode].insn_code = CODE_FOR_atandf2;
+ if (HAVE_expsf2)
+ exp_optab->handlers[SFmode].insn_code = CODE_FOR_expsf2;
+ if (HAVE_expdf2)
+ exp_optab->handlers[DFmode].insn_code = CODE_FOR_expdf2;
+ if (HAVE_logsf2)
+ log_optab->handlers[SFmode].insn_code = CODE_FOR_logsf2;
+ if (HAVE_logdf2)
+ log_optab->handlers[DFmode].insn_code = CODE_FOR_logdf2;
+ if (HAVE_floatsisf2)
+ sfloat_optab->handlers[SFmode][SImode].insn_code = CODE_FOR_floatsisf2;
+ if (HAVE_floatsidf2)
+ sfloat_optab->handlers[DFmode][SImode].insn_code = CODE_FOR_floatsidf2;
+ if (HAVE_floatunssisf2)
+ ufloat_optab->handlers[SFmode][SImode].insn_code = CODE_FOR_floatunssisf2;
+ if (HAVE_floatunssidf2)
+ ufloat_optab->handlers[DFmode][SImode].insn_code = CODE_FOR_floatunssidf2;
+ if (HAVE_fixsfsi2)
+ sfix_optab->handlers[SImode][SFmode].insn_code = CODE_FOR_fixsfsi2;
+ if (HAVE_fixdfsi2)
+ sfix_optab->handlers[SImode][DFmode].insn_code = CODE_FOR_fixdfsi2;
+ if (HAVE_fixunssfsi2)
+ ufix_optab->handlers[SImode][SFmode].insn_code = CODE_FOR_fixunssfsi2;
+ if (HAVE_fixunsdfsi2)
+ ufix_optab->handlers[SImode][DFmode].insn_code = CODE_FOR_fixunsdfsi2;
+ if (HAVE_extendsfdf2)
+ sext_optab->handlers[DFmode][SFmode].insn_code = CODE_FOR_extendsfdf2;
+ if (HAVE_truncdfsf2)
+ trunc_optab->handlers[SFmode][DFmode].insn_code = CODE_FOR_truncdfsf2;
+ if (HAVE_cmpsf)
+ cmp_optab->handlers[SFmode].insn_code = CODE_FOR_cmpsf;
+ if (HAVE_cmpdf)
+ cmp_optab->handlers[DFmode].insn_code = CODE_FOR_cmpdf;
+ }
+
+ /* Check for duplicate values of N */
+ for (i = 0; i < 256; i++)
+ {
+ ns[i] = 0;
+ ps[i] = 0;
+ }
+
+ for (i = 0; i < nios2_fpu_max_insn; i++)
+ {
+ int N = nios2_fpu_insns[i].N;
+ if (N >= 0)
+ {
+ if (ns[N])
+ {
+ error ("%s%s' conflicts with %s%s'",
+ is_pragma ? "`#pragma custom_" : "switch `-mcustom-",
+ nios2_fpu_insns[i].option,
+ ps[N] ? "`#pragma custom_" : "switch `-mcustom-",
+ ns[N]);
+ errors = 1;
+ }
+ else if (builtin_custom_seen[N])
+ {
+ error ("call to `%s' conflicts with %s%s'",
+ builtin_custom_seen[N],
+ (nios2_fpu_insns[i].pragma_seen
+ ? "`#pragma custom_" : "switch `-mcustom-"),
+ nios2_fpu_insns[i].option);
+ errors = 1;
+ }
+ else
+ {
+ ns[N] = nios2_fpu_insns[i].option;
+ ps[N] = nios2_fpu_insns[i].pragma_seen;
+ }
+ }
+ }
+
+ if (errors)
+ {
+ fatal_error ("conflicting use of -mcustom switches, #pragmas, and/or __builtin_custom_ functions");
+ }
+}
+
+static void
+nios2_handle_custom_fpu_cfg (const char *cfg, int is_pragma)
+{
+#undef NIOS2_FPU_INSN
+#define NIOS2_FPU_INSN(opt, insn, args) \
+ int opt = nios2_fpu_insns[NIOS2_CONCAT (nios2_fpu_, insn)].N;
+NIOS2_FOR_ALL_FPU_INSNS
+
+ /*
+ * ??? These are just some sample possibilities. We'll change these
+ * at the last minute to match the capabilities of the actual fpu.
+ */
+ if (!strcasecmp (cfg, "60-1"))
+ {
+ fmuls = 252;
+ fadds = 253;
+ fsubs = 254;
+ flag_single_precision_constant = 1;
+ }
+ else if (!strcasecmp (cfg, "60-2"))
+ {
+ fmuls = 252;
+ fadds = 253;
+ fsubs = 254;
+ fdivs = 255;
+ flag_single_precision_constant = 1;
+ }
+ else if (!strcasecmp (cfg, "72-3"))
+ {
+ floatus = 243;
+ fixsi = 244;
+ floatis = 245;
+ fcmpgts = 246;
+ fcmples = 249;
+ fcmpeqs = 250;
+ fcmpnes = 251;
+ fmuls = 252;
+ fadds = 253;
+ fsubs = 254;
+ fdivs = 255;
+ flag_single_precision_constant = 1;
+ }
+ else
+ {
+ warning ("ignoring unrecognized %sfpu-cfg' value `%s'",
+ is_pragma ? "`#pragma custom_" : "switch -mcustom-", cfg);
+ }
+
+#undef NIOS2_FPU_INSN
+#define NIOS2_FPU_INSN(opt, insn, args) \
+ nios2_fpu_insns[NIOS2_CONCAT (nios2_fpu_, insn)].N = opt;
+NIOS2_FOR_ALL_FPU_INSNS
+
+ /* Guard against errors in the standard configurations. */
+ nios2_custom_check_insns (is_pragma);
+}
+
+void
+override_options ()
+{
+ int i;
+
+ /* Function to allocate machine-dependent function status. */
+ init_machine_status = &nios2_init_machine_status;
+
+ nios2_section_threshold
+ = g_switch_set ? g_switch_value : NIOS2_DEFAULT_GVALUE;
+
+ if (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;
+ }
+
+ /* Set up for stack limit checking */
+ if (TARGET_STACK_CHECK)
+ {
+ stack_limit_rtx = gen_rtx_REG(SImode, ET_REGNO);
+ }
+
+ for (i = 0; i < nios2_fpu_max_insn; i++)
+ {
+ nios2_fpu_insns[i].is_double = (nios2_fpu_insns[i].args[0] == 'd'
+ || nios2_fpu_insns[i].args[0] == 'd'
+ || nios2_fpu_insns[i].args[0] == 'd');
+ nios2_fpu_insns[i].needed_by_double = (i == nios2_fpu_nios2_fwrx
+ || i == nios2_fpu_nios2_fwry
+ || i == nios2_fpu_nios2_frdxlo
+ || i == nios2_fpu_nios2_frdxhi
+ || i == nios2_fpu_nios2_frdy);
+ nios2_fpu_insns[i].needs_unsafe = (i == nios2_fpu_cossf2
+ || i == nios2_fpu_cosdf2
+ || i == nios2_fpu_sinsf2
+ || i == nios2_fpu_sindf2
+ || i == nios2_fpu_tansf2
+ || i == nios2_fpu_tandf2
+ || i == nios2_fpu_atansf2
+ || i == nios2_fpu_atandf2
+ || i == nios2_fpu_expsf2
+ || i == nios2_fpu_expdf2
+ || i == nios2_fpu_logsf2
+ || i == nios2_fpu_logdf2);
+ nios2_fpu_insns[i].needs_finite = (i == nios2_fpu_minsf3
+ || i == nios2_fpu_maxsf3
+ || i == nios2_fpu_mindf3
+ || i == nios2_fpu_maxdf3);
+ }
+
+ /*
+ * We haven't seen any __builtin_custom functions yet.
+ */
+ for (i = 0; i < 256; i++)
+ {
+ builtin_custom_seen[i] = 0;
+ }
+
+ /*
+ * Set up default handling for floating point custom instructions.
+ *
+ * Putting things in this order means that the -mcustom-fpu-cfg=
+ * switch will always be overridden by individual -mcustom-fadds=
+ * switches, regardless of the order in which they were specified
+ * on the command line. ??? Remember to document this.
+ */
+ if (nios2_custom_fpu_cfg_string && *nios2_custom_fpu_cfg_string)
+ {
+ nios2_handle_custom_fpu_cfg (nios2_custom_fpu_cfg_string, 0);
+ }
+
+ for (i = 0; i < nios2_fpu_max_insn; i++)
+ {
+ nios2_custom_switch (nios2_fpu_insns[i].value,
+ &nios2_fpu_insns[i].N,
+ nios2_fpu_insns[i].option);
+ }
+
+ nios2_custom_check_insns (0);
+}
+
+void
+optimization_options (int level, int size)
+{
+ if (level || size)
+ {
+ target_flags |= 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;
+}
+
+bool have_nios2_fpu_cmp_insn( enum rtx_code cond_t, enum cmp_type cmp_t );
+enum rtx_code get_reverse_cond(enum rtx_code cond_t);
+
+bool
+have_nios2_fpu_cmp_insn( enum rtx_code cond_t, enum cmp_type cmp_t )
+{
+ if (cmp_t == CMP_SF)
+ {
+ switch (cond_t) {
+ case EQ:
+ return (nios2_fpu_insns[nios2_fpu_nios2_seqsf].N >= 0);
+ case NE:
+ return (nios2_fpu_insns[nios2_fpu_nios2_snesf].N >= 0);
+ case GT:
+ return (nios2_fpu_insns[nios2_fpu_nios2_sgtsf].N >= 0);
+ case GE:
+ return (nios2_fpu_insns[nios2_fpu_nios2_sgesf].N >= 0);
+ case LT:
+ return (nios2_fpu_insns[nios2_fpu_nios2_sltsf].N >= 0);
+ case LE:
+ return (nios2_fpu_insns[nios2_fpu_nios2_slesf].N >= 0);
+ default:
+ break;
+ }
+ }
+ else if (cmp_t == CMP_DF)
+ {
+ switch (cond_t) {
+ case EQ:
+ return (nios2_fpu_insns[nios2_fpu_nios2_seqdf].N >= 0);
+ case NE:
+ return (nios2_fpu_insns[nios2_fpu_nios2_snedf].N >= 0);
+ case GT:
+ return (nios2_fpu_insns[nios2_fpu_nios2_sgtdf].N >= 0);
+ case GE:
+ return (nios2_fpu_insns[nios2_fpu_nios2_sgedf].N >= 0);
+ case LT:
+ return (nios2_fpu_insns[nios2_fpu_nios2_sltdf].N >= 0);
+ case LE:
+ return (nios2_fpu_insns[nios2_fpu_nios2_sledf].N >= 0);
+ default:
+ break;
+ }
+ }
+
+ return false;
+}
+
+/* Note that get_reverse_cond() is not the same as get_inverse_cond()
+ get_reverse_cond() means that if the operand order is reversed,
+ what is the operand that is needed to generate the same condition?
+*/
+enum rtx_code
+get_reverse_cond(enum rtx_code cond_t)
+{
+ switch (cond_t)
+ {
+ case GT: return LT;
+ case GE: return LE;
+ case LT: return GT;
+ case LE: return GE;
+ case GTU: return LTU;
+ case GEU: return LEU;
+ case LTU: return GTU;
+ case LEU: return GEU;
+ default: break;
+ }
+
+ return cond_t;
+}
+
+
+/* Generate the code to compare (and possibly branch) two integer values
+ TEST_CODE is the comparison code we are trying to emulate
+ (or implement directly)
+ RESULT is where to store the result of the comparison,
+ or null to emit a branch
+ CMP0 CMP1 are the two comparison operands
+ DESTINATION is the destination of the branch, or null to only compare
+ */
+
+void
+gen_int_relational (enum rtx_code test_code, /* relational test (EQ, etc) */
+ rtx result, /* result to store comp. or 0 if branch */
+ rtx cmp0, /* first operand to compare */
+ rtx cmp1, /* second operand to compare */
+ rtx destination) /* destination of the branch, or 0 if compare */
+{
+ struct cmp_info
+ {
+ /* for register (or 0) compares */
+ enum rtx_code test_code_reg; /* code to use in instruction (LT vs. LTU) */
+ int reverse_regs; /* reverse registers in test */
+
+ /* for immediate compares */
+ enum rtx_code test_code_const;
+ /* code to use in instruction (LT vs. LTU) */
+ int const_low; /* low bound of constant we can accept */
+ int const_high; /* high bound of constant we can accept */
+ int const_add; /* constant to add */
+
+ /* generic info */
+ int unsignedp; /* != 0 for unsigned comparisons. */
+ };
+
+ static const struct cmp_info info[(int) ITEST_MAX] = {
+
+ {EQ, 0, EQ, -32768, 32767, 0, 0}, /* EQ */
+ {NE, 0, NE, -32768, 32767, 0, 0}, /* NE */
+
+ {LT, 1, GE, -32769, 32766, 1, 0}, /* GT */
+ {GE, 0, GE, -32768, 32767, 0, 0}, /* GE */
+ {LT, 0, LT, -32768, 32767, 0, 0}, /* LT */
+ {GE, 1, LT, -32769, 32766, 1, 0}, /* LE */
+
+ {LTU, 1, GEU, 0, 65534, 1, 0}, /* GTU */
+ {GEU, 0, GEU, 0, 65535, 0, 0}, /* GEU */
+ {LTU, 0, LTU, 0, 65535, 0, 0}, /* LTU */
+ {GEU, 1, LTU, 0, 65534, 1, 0}, /* LEU */
+ };
+
+ enum internal_test test;
+ enum machine_mode mode;
+ const struct cmp_info *p_info;
+ int branch_p;
+
+
+ test = map_test_to_internal_test (test_code);
+ 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);
+
+ /* Handle floating point comparison directly. */
+ if (branch_type == CMP_SF || branch_type == CMP_DF)
+ {
+
+ bool reverse_operands = false;
+
+ enum machine_mode float_mode = (branch_type == CMP_SF) ? SFmode : DFmode;
+
+ if (!register_operand (cmp0, float_mode)
+ || !register_operand (cmp1, float_mode))
+ {
+ abort ();
+ }
+
+ if (branch_p)
+ {
+ test_code = p_info->test_code_reg;
+ reverse_operands = (p_info->reverse_regs);
+ }
+
+ if ( !have_nios2_fpu_cmp_insn(test_code, branch_type) &&
+ have_nios2_fpu_cmp_insn(get_reverse_cond(test_code), branch_type) )
+ {
+ test_code = get_reverse_cond(test_code);
+ reverse_operands = !reverse_operands;
+ }
+
+ if (reverse_operands)
+ {
+ rtx temp = cmp0;
+ cmp0 = cmp1;
+ cmp1 = temp;
+ }
+
+ if (branch_p)
+ {
+ rtx cond = gen_rtx (test_code, SImode, cmp0, cmp1);
+ rtx label = gen_rtx_LABEL_REF (VOIDmode, destination);
+ rtx insn = gen_rtx_SET (VOIDmode, pc_rtx,
+ gen_rtx_IF_THEN_ELSE (VOIDmode,
+ cond, label, pc_rtx));
+ emit_jump_insn (insn);
+ }
+ else
+ {
+ emit_move_insn (result, gen_rtx (test_code, SImode, cmp0, cmp1));
+ }
+ return;
+ }
+
+ /* We can't, under any circumstances, have const_ints in cmp0
+ ??? Actually we could have const0 */
+ if (GET_CODE (cmp0) == CONST_INT)
+ cmp0 = force_reg (mode, cmp0);
+
+ /* if the comparison is against an int not in legal range
+ move it into a register */
+ if (GET_CODE (cmp1) == CONST_INT)
+ {
+ HOST_WIDE_INT value = INTVAL (cmp1);
+
+ if (value < p_info->const_low || value > p_info->const_high)
+ cmp1 = force_reg (mode, cmp1);
+ }
+
+ /* Comparison to constants, may involve adding 1 to change a GT into GE.
+ Comparison between two registers, may involve switching operands. */
+ if (GET_CODE (cmp1) == CONST_INT)
+ {
+ if (p_info->const_add != 0)
+ {
+ HOST_WIDE_INT new = INTVAL (cmp1) + p_info->const_add;
+
+ /* If modification of cmp1 caused overflow,
+ we would get the wrong answer if we follow the usual path;
+ thus, x > 0xffffffffU would turn into x > 0U. */
+ 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) && GET_CODE (op1) == CONST_INT)
+ ret_val = REG_OK_FOR_BASE_P2 (op0, strict)
+ && SMALL_INT (INTVAL (op1));
+ else if (REG_P (op1) && GET_CODE (op0) == CONST_INT)
+ ret_val = REG_OK_FOR_BASE_P2 (op1, strict)
+ && SMALL_INT (INTVAL (op0));
+ else
+ ret_val = 0;
+ }
+ break;
+
+ default:
+ ret_val = 0;
+ break;
+ }
+
+ return ret_val;
+}
+
+/* Return true if EXP should be placed in the small data section. */
+
+static bool
+nios2_in_small_data_p (tree exp)
+{
+ /* We want to merge strings, so we never consider them small data. */
+ if (TREE_CODE (exp) == STRING_CST)
+ return false;
+
+ if (TREE_CODE (exp) == VAR_DECL && DECL_SECTION_NAME (exp))
+ {
+ const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (exp));
+ /* ??? these string names need moving into
+ an array in some header file */
+ if (nios2_section_threshold > 0
+ && (strcmp (section, ".sbss") == 0
+ || strncmp (section, ".sbss.", 6) == 0
+ || strcmp (section, ".sdata") == 0
+ || strncmp (section, ".sdata.", 7) == 0))
+ return true;
+ }
+ else if (TREE_CODE (exp) == VAR_DECL)
+ {
+ HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp));
+
+ /* If this is an incomplete type with size 0, then we can't put it
+ in sdata because it might be too big when completed. */
+ if (size > 0 && (unsigned HOST_WIDE_INT)size <= nios2_section_threshold)
+ return true;
+ }
+
+ return false;
+}
+
+static void
+nios2_encode_section_info (tree decl, rtx rtl, int first)
+{
+
+ rtx symbol;
+ int flags;
+
+ default_encode_section_info (decl, rtl, first);
+
+ /* Careful not to prod global register variables. */
+ if (GET_CODE (rtl) != MEM)
+ return;
+ symbol = XEXP (rtl, 0);
+ if (GET_CODE (symbol) != SYMBOL_REF)
+ return;
+
+ flags = SYMBOL_REF_FLAGS (symbol);
+
+ /* We don't want weak variables to be addressed with gp in case they end up with
+ value 0 which is not within 2^15 of $gp */
+ if (DECL_P (decl) && DECL_WEAK (decl))
+ flags |= SYMBOL_FLAG_WEAK_DECL;
+
+ SYMBOL_REF_FLAGS (symbol) = flags;
+}
+
+
+static unsigned int
+nios2_section_type_flags (tree decl, const char *name, int reloc)
+{
+ unsigned int flags;
+
+ flags = default_section_type_flags (decl, name, reloc);
+
+ /* ??? 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;
+}
+
+/* Handle a #pragma reverse_bitfields */
+static void
+nios2_pragma_reverse_bitfields (struct cpp_reader *pfile ATTRIBUTE_UNUSED)
+{
+ nios2_pragma_reverse_bitfields_flag = 1; /* Reverse */
+}
+
+/* Handle a #pragma no_reverse_bitfields */
+static void
+nios2_pragma_no_reverse_bitfields (struct cpp_reader *pfile ATTRIBUTE_UNUSED)
+{
+ nios2_pragma_reverse_bitfields_flag = -1; /* Forward */
+}
+
+/* Handle the various #pragma custom_<switch>s */
+static void
+nios2_pragma_fpu (int *value, const char *opt, int *seen)
+{
+ tree t;
+ if (c_lex (&t) != CPP_NUMBER)
+ {
+ error ("`#pragma custom_%s' value must be a number between 0 and 255",
+ opt);
+ return;
+ }
+
+ if (TREE_INT_CST_HIGH (t) == 0
+ && TREE_INT_CST_LOW (t) <= 255)
+ {
+ *value = (int)TREE_INT_CST_LOW (t);
+ *seen = 1;
+ }
+ else
+ {
+ error ("`#pragma custom_%s' value must be between 0 and 255", opt);
+ }
+ nios2_custom_check_insns (1);
+}
+
+/* Handle the various #pragma no_custom_<switch>s */
+static void
+nios2_pragma_no_fpu (int *value, const char *opt ATTRIBUTE_UNUSED)
+{
+ *value = -1;
+ nios2_custom_check_insns (1);
+}
+
+#undef NIOS2_FPU_INSN
+#define NIOS2_FPU_INSN(opt, insn, args) \
+static void \
+NIOS2_CONCAT (nios2_pragma_, insn) \
+ (struct cpp_reader *pfile ATTRIBUTE_UNUSED) \
+{ \
+ nios2_fpu_info *inf = &(nios2_fpu_insns[NIOS2_CONCAT (nios2_fpu_, insn)]); \
+ nios2_pragma_fpu (&(inf->N), inf->option, &(inf->pragma_seen)); \
+} \
+static void \
+NIOS2_CONCAT (nios2_pragma_no_, insn) \
+ (struct cpp_reader *pfile ATTRIBUTE_UNUSED) \
+{ \
+ nios2_fpu_info *inf = &(nios2_fpu_insns[NIOS2_CONCAT (nios2_fpu_, insn)]); \
+ nios2_pragma_no_fpu (&(inf->N), inf->option); \
+}
+NIOS2_FOR_ALL_FPU_INSNS
+
+static void
+nios2_pragma_handle_custom_fpu_cfg (struct cpp_reader *pfile ATTRIBUTE_UNUSED)
+{
+ tree t;
+ if (c_lex (&t) != CPP_STRING)
+ {
+ error ("`#pragma custom_fpu_cfg' value must be a string");
+ return;
+ }
+
+ if (TREE_STRING_LENGTH (t) > 0)
+ {
+ nios2_handle_custom_fpu_cfg (TREE_STRING_POINTER (t), 1);
+ }
+}
+
+void
+nios2_register_target_pragmas ()
+{
+ int i;
+
+ c_register_pragma (0, "reverse_bitfields",
+ nios2_pragma_reverse_bitfields);
+ c_register_pragma (0, "no_reverse_bitfields",
+ nios2_pragma_no_reverse_bitfields);
+
+ for (i = 0; i < nios2_fpu_max_insn; i++)
+ {
+ nios2_fpu_info *inf = &(nios2_fpu_insns[i]);
+ c_register_pragma (0, inf->pname, inf->pragma);
+ c_register_pragma (0, inf->nopname, inf->nopragma);
+ }
+
+ c_register_pragma (0, "custom_fpu_cfg",
+ nios2_pragma_handle_custom_fpu_cfg);
+}
+
+/* Handle a "reverse_bitfields" or "no_reverse_bitfields" attribute.
+ ??? What do these attributes mean on a union? */
+static tree
+nios2_handle_struct_attribute (tree *node, tree name,
+ tree args ATTRIBUTE_UNUSED,
+ int flags ATTRIBUTE_UNUSED,
+ bool *no_add_attrs)
+{
+ tree *type = NULL;
+ if (DECL_P (*node))
+ {
+ if (TREE_CODE (*node) == TYPE_DECL)
+ {
+ type = &TREE_TYPE (*node);
+ }
+ }
+ else
+ {
+ type = node;
+ }
+
+ if (!(type && (TREE_CODE (*type) == RECORD_TYPE
+ || TREE_CODE (*type) == UNION_TYPE)))
+ {
+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ else if ((is_attribute_p ("reverse_bitfields", name)
+ && lookup_attribute ("no_reverse_bitfields",
+ TYPE_ATTRIBUTES (*type)))
+ || ((is_attribute_p ("no_reverse_bitfields", name)
+ && lookup_attribute ("reverse_bitfields",
+ TYPE_ATTRIBUTES (*type)))))
+ {
+ warning ("`%s' incompatible attribute ignored",
+ IDENTIFIER_POINTER (name));
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
+/*
+ Add __attribute__ ((pragma_reverse_bitfields)) when in the scope of a
+ #pragma reverse_bitfields, or __attribute__
+ ((pragma_no_reverse_bitfields)) when in the scope of a #pragma
+ no_reverse_bitfields. This gets called before
+ nios2_handle_struct_attribute above, so we can't just reuse the same
+ attributes.
+*/
+static void
+nios2_insert_attributes (tree node, tree *attr_ptr)
+{
+ tree type = NULL;
+ if (DECL_P (node))
+ {
+ if (TREE_CODE (node) == TYPE_DECL)
+ {
+ type = TREE_TYPE (node);
+ }
+ }
+ else
+ {
+ type = node;
+ }
+
+ if (!type
+ || (TREE_CODE (type) != RECORD_TYPE
+ && TREE_CODE (type) != UNION_TYPE))
+ {
+ /* We can ignore things other than structs & unions */
+ return;
+ }
+
+ if (lookup_attribute ("reverse_bitfields", TYPE_ATTRIBUTES (type))
+ || lookup_attribute ("no_reverse_bitfields", TYPE_ATTRIBUTES (type)))
+ {
+ /* If an attribute is already set, it silently overrides the
+ current #pragma, if any */
+ return;
+ }
+
+ if (nios2_pragma_reverse_bitfields_flag)
+ {
+ const char *id = (nios2_pragma_reverse_bitfields_flag == 1 ?
+ "pragma_reverse_bitfields" :
+ "pragma_no_reverse_bitfields");
+ /* No attribute set, and we are in the scope of a #pragma */
+ *attr_ptr = tree_cons (get_identifier (id), NULL, *attr_ptr);
+ }
+}
+
+
+/*
+ * The attributes take precedence over the pragmas, which in turn take
+ * precedence over the compile-time switches.
+ */
+static bool
+nios2_reverse_bitfield_layout_p (tree record_type)
+{
+ return ((TARGET_REVERSE_BITFIELDS
+ && !lookup_attribute ("pragma_no_reverse_bitfields",
+ TYPE_ATTRIBUTES (record_type))
+ && !lookup_attribute ("no_reverse_bitfields",
+ TYPE_ATTRIBUTES (record_type)))
+ || (lookup_attribute ("pragma_reverse_bitfields",
+ TYPE_ATTRIBUTES (record_type))
+ && !lookup_attribute ("no_reverse_bitfields",
+ TYPE_ATTRIBUTES (record_type)))
+ || lookup_attribute ("reverse_bitfields",
+ TYPE_ATTRIBUTES (record_type)));
+}
+
+
+/*****************************************
+ * Defining the Output Assembler Language
+ *****************************************/
+
+/* -------------- *
+ * Output of Data
+ * -------------- */
+
+
+/* -------------------------------- *
+ * Output of Assembler Instructions
+ * -------------------------------- */
+
+
+/* print the operand OP to file stream
+ FILE modified by LETTER. LETTER
+ can be one of:
+ i: print "i" if OP is an immediate, except 0
+ o: print "io" if OP is volatile
+
+ z: for const0_rtx print $0 instead of 0
+ H: for %hiadj
+ L: for %lo
+ U: for upper half of 32 bit value
+ D: for the upper 32-bits of a 64-bit double value
+ */
+
+void
+nios2_print_operand (FILE *file, rtx op, int letter)
+{
+
+ switch (letter)
+ {
+ case 'i':
+ if (CONSTANT_P (op) && (op != const0_rtx))
+ fprintf (file, "i");
+ return;
+
+ case 'o':
+ if (GET_CODE (op) == MEM
+ && ((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;
+ }
+ else if (letter == 'D')
+ {
+ fprintf (file, "%s", reg_names[REGNO (op)+1]);
+ return;
+ }
+ break;
+
+ case CONST_INT:
+ if (INTVAL (op) == 0 && letter == 'z')
+ {
+ fprintf (file, "zero");
+ return;
+ }
+ else if (letter == 'U')
+ {
+ HOST_WIDE_INT val = INTVAL (op);
+ rtx new_op;
+ val = (val / 65536) & 0xFFFF;
+ new_op = GEN_INT (val);
+ output_addr_const (file, new_op);
+ return;
+ }
+
+ /* else, fall through */
+ case CONST:
+ case LABEL_REF:
+ case SYMBOL_REF:
+ case CONST_DOUBLE:
+ if (letter == 0 || letter == 'z')
+ {
+ output_addr_const (file, op);
+ return;
+ }
+ else if (letter == 'H')
+ {
+ fprintf (file, "%%hiadj(");
+ output_addr_const (file, op);
+ fprintf (file, ")");
+ return;
+ }
+ else if (letter == 'L')
+ {
+ fprintf (file, "%%lo(");
+ output_addr_const (file, op);
+ fprintf (file, ")");
+ return;
+ }
+ break;
+
+
+ case SUBREG:
+ case MEM:
+ if (letter == 0)
+ {
+ output_address (op);
+ return;
+ }
+ break;
+
+ case CODE_LABEL:
+ if (letter == 0)
+ {
+ output_addr_const (file, op);
+ return;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ fprintf (stderr, "Missing way to print (%c) ", letter);
+ debug_rtx (op);
+ 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));
+}
+
+
+
+
+/*****************************************************************************
+**
+** custom fpu instruction output
+**
+*****************************************************************************/
+
+static const char *nios2_custom_fpu_insn_zdz (rtx, int, const char *);
+static const char *nios2_custom_fpu_insn_zsz (rtx, int, const char *);
+static const char *nios2_custom_fpu_insn_szz (rtx, int, const char *);
+static const char *nios2_custom_fpu_insn_sss (rtx, int, const char *);
+static const char *nios2_custom_fpu_insn_ssz (rtx, int, const char *);
+static const char *nios2_custom_fpu_insn_iss (rtx, int, const char *);
+static const char *nios2_custom_fpu_insn_ddd (rtx, int, const char *);
+static const char *nios2_custom_fpu_insn_ddz (rtx, int, const char *);
+static const char *nios2_custom_fpu_insn_idd (rtx, int, const char *);
+static const char *nios2_custom_fpu_insn_siz (rtx, int, const char *);
+static const char *nios2_custom_fpu_insn_suz (rtx, int, const char *);
+static const char *nios2_custom_fpu_insn_diz (rtx, int, const char *);
+static const char *nios2_custom_fpu_insn_duz (rtx, int, const char *);
+static const char *nios2_custom_fpu_insn_isz (rtx, int, const char *);
+static const char *nios2_custom_fpu_insn_usz (rtx, int, const char *);
+static const char *nios2_custom_fpu_insn_idz (rtx, int, const char *);
+static const char *nios2_custom_fpu_insn_udz (rtx, int, const char *);
+static const char *nios2_custom_fpu_insn_dsz (rtx, int, const char *);
+static const char *nios2_custom_fpu_insn_sdz (rtx, int, const char *);
+
+static const char *
+nios2_custom_fpu_insn_zdz (rtx insn, int N, const char *opt)
+{
+ static char buf[1024];
+
+ if (N < 0)
+ {
+ fatal_insn ("attempt to use disabled fpu instruction", insn);
+ }
+ if (snprintf (buf, sizeof (buf),
+ "custom\t%d, zero, %%0, %%D0 # %s %%0",
+ N, opt) >= (int)sizeof (buf))
+ {
+ fatal_insn ("buffer overflow", insn);
+ }
+ return buf;
+}
+
+static const char *
+nios2_custom_fpu_insn_zsz (rtx insn, int N, const char *opt)
+{
+ static char buf[1024];
+
+ if (N < 0)
+ {
+ fatal_insn ("attempt to use disabled fpu instruction", insn);
+ }
+ if (snprintf (buf, sizeof (buf),
+ "custom\t%d, zero, %%0, zero # %s %%0",
+ N, opt) >= (int)sizeof (buf))
+ {
+ fatal_insn ("buffer overflow", insn);
+ }
+ return buf;
+}
+
+static const char *
+nios2_custom_fpu_insn_szz (rtx insn, int N, const char *opt)
+{
+ static char buf[1024];
+
+ if (N < 0)
+ {
+ fatal_insn ("attempt to use disabled fpu instruction", insn);
+ }
+ if (snprintf (buf, sizeof (buf),
+ "custom\t%d, %%0, zero, zero # %s %%0",
+ N, opt) >= (int)sizeof (buf))
+ {
+ fatal_insn ("buffer overflow", insn);
+ }
+ return buf;
+}
+
+static const char *
+nios2_custom_fpu_insn_sss (rtx insn, int N, const char *opt)
+{
+ static char buf[1024];
+
+ if (N < 0)
+ {
+ fatal_insn ("attempt to use disabled fpu instruction", insn);
+ }
+ if (snprintf (buf, sizeof (buf),
+ "custom\t%d, %%0, %%1, %%2 # %s %%0, %%1, %%2",
+ N, opt) >= (int)sizeof (buf))
+ {
+ fatal_insn ("buffer overflow", insn);
+ }
+ return buf;
+}
+
+static const char *
+nios2_custom_fpu_insn_ssz (rtx insn, int N, const char *opt)
+{
+ static char buf[1024];
+
+ if (N < 0)
+ {
+ fatal_insn ("attempt to use disabled fpu instruction", insn);
+ }
+ if (snprintf (buf, sizeof (buf),
+ "custom\t%d, %%0, %%1, zero # %s %%0, %%1",
+ N, opt) >= (int)sizeof (buf))
+ {
+ fatal_insn ("buffer overflow", insn);
+ }
+ return buf;
+}
+
+static const char *
+nios2_custom_fpu_insn_iss (rtx insn, int N, const char *opt)
+{
+ return nios2_custom_fpu_insn_sss (insn, N, opt);
+}
+
+static const char *
+nios2_custom_fpu_insn_ddd (rtx insn, int N, const char *opt)
+{
+ static char buf[1024];
+
+ if (N < 0
+ || nios2_fpu_insns[nios2_fpu_nios2_frdy].N < 0
+ || nios2_fpu_insns[nios2_fpu_nios2_fwrx].N < 0)
+ {
+ fatal_insn ("attempt to use disabled fpu instruction", insn);
+ }
+ if (snprintf (buf, sizeof (buf),
+ "custom\t%d, zero, %%1, %%D1 # fwrx %%1\n\t"
+ "custom\t%d, %%D0, %%2, %%D2 # %s %%0, %%1, %%2\n\t"
+ "custom\t%d, %%0, zero, zero # frdy %%0",
+ nios2_fpu_insns[nios2_fpu_nios2_fwrx].N,
+ N, opt,
+ nios2_fpu_insns[nios2_fpu_nios2_frdy].N) >= (int)sizeof (buf))
+ {
+ fatal_insn ("buffer overflow", insn);
+ }
+ return buf;
+}
+
+static const char *
+nios2_custom_fpu_insn_ddz (rtx insn, int N, const char *opt)
+{
+ static char buf[1024];
+
+ if (N < 0 || nios2_fpu_insns[nios2_fpu_nios2_frdy].N < 0)
+ {
+ fatal_insn ("attempt to use disabled fpu instruction", insn);
+ }
+ if (snprintf (buf, sizeof (buf),
+ "custom\t%d, %%D0, %%1, %%D1 # %s %%0, %%1\n\t"
+ "custom\t%d, %%0, zero, zero # frdy %%0",
+ N, opt,
+ nios2_fpu_insns[nios2_fpu_nios2_frdy].N) >= (int)sizeof (buf))
+ {
+ fatal_insn ("buffer overflow", insn);
+ }
+ return buf;
+}
+
+static const char *
+nios2_custom_fpu_insn_idd (rtx insn, int N, const char *opt)
+{
+ static char buf[1024];
+
+ if (N < 0 || nios2_fpu_insns[nios2_fpu_nios2_fwrx].N < 0)
+ {
+ fatal_insn ("attempt to use disabled fpu instruction", insn);
+ }
+ if (snprintf (buf, sizeof (buf),
+ "custom\t%d, zero, %%1, %%D1 # fwrx %%1\n\t"
+ "custom\t%d, %%0, %%2, %%D2 # %s %%0, %%1, %%2",
+ nios2_fpu_insns[nios2_fpu_nios2_fwrx].N,
+ N, opt) >= (int)sizeof (buf))
+ {
+ fatal_insn ("buffer overflow", insn);
+ }
+ return buf;
+}
+
+static const char *
+nios2_custom_fpu_insn_siz (rtx insn, int N, const char *opt)
+{
+ return nios2_custom_fpu_insn_ssz (insn, N, opt);
+}
+
+static const char *
+nios2_custom_fpu_insn_suz (rtx insn, int N, const char *opt)
+{
+ return nios2_custom_fpu_insn_ssz (insn, N, opt);
+}
+
+static const char *
+nios2_custom_fpu_insn_diz (rtx insn, int N, const char *opt)
+{
+ return nios2_custom_fpu_insn_dsz (insn, N, opt);
+}
+
+static const char *
+nios2_custom_fpu_insn_duz (rtx insn, int N, const char *opt)
+{
+ return nios2_custom_fpu_insn_dsz (insn, N, opt);
+}
+
+static const char *
+nios2_custom_fpu_insn_isz (rtx insn, int N, const char *opt)
+{
+ return nios2_custom_fpu_insn_ssz (insn, N, opt);
+}
+
+static const char *
+nios2_custom_fpu_insn_usz (rtx insn, int N, const char *opt)
+{
+ return nios2_custom_fpu_insn_ssz (insn, N, opt);
+}
+
+static const char *
+nios2_custom_fpu_insn_idz (rtx insn, int N, const char *opt)
+{
+ return nios2_custom_fpu_insn_sdz (insn, N, opt);
+}
+
+static const char *
+nios2_custom_fpu_insn_udz (rtx insn, int N, const char *opt)
+{
+ return nios2_custom_fpu_insn_sdz (insn, N, opt);
+}
+
+static const char *
+nios2_custom_fpu_insn_dsz (rtx insn, int N, const char *opt)
+{
+ static char buf[1024];
+
+ if (N < 0 || nios2_fpu_insns[nios2_fpu_nios2_frdy].N < 0)
+ {
+ fatal_insn ("attempt to use disabled fpu instruction", insn);
+ }
+ if (snprintf (buf, sizeof (buf),
+ "custom\t%d, %%D0, %%1, zero # %s %%0, %%1\n\t"
+ "custom\t%d, %%0, zero, zero # frdy %%0",
+ N, opt,
+ nios2_fpu_insns[nios2_fpu_nios2_frdy].N) >= (int)sizeof (buf))
+ {
+ fatal_insn ("buffer overflow", insn);
+ }
+ return buf;
+}
+
+static const char *
+nios2_custom_fpu_insn_sdz (rtx insn, int N, const char *opt)
+{
+ static char buf[1024];
+
+ if (N < 0)
+ {
+ fatal_insn ("attempt to use disabled fpu instruction", insn);
+ }
+ if (snprintf (buf, sizeof (buf),
+ "custom\t%d, %%0, %%1, %%D1 # %s %%0, %%1",
+ N, opt) >= (int)sizeof (buf))
+ {
+ fatal_insn ("buffer overflow", insn);
+ }
+ return buf;
+}
+
+#undef NIOS2_FPU_INSN
+#define NIOS2_FPU_INSN(opt, insn, args) \
+static const char * \
+NIOS2_CONCAT (nios2_output_fpu_insn_, insn) (rtx i) \
+{ \
+ return NIOS2_CONCAT (nios2_custom_fpu_insn_, args) \
+ (i, \
+ nios2_fpu_insns[NIOS2_CONCAT (nios2_fpu_, insn)].N, \
+ nios2_fpu_insns[NIOS2_CONCAT (nios2_fpu_, insn)].option); \
+}
+NIOS2_FOR_ALL_FPU_INSNS
+
+
+
+const char *
+nios2_output_fpu_insn_cmps (rtx insn, enum rtx_code cond)
+{
+ static char buf[1024];
+ int N;
+ const char *opt;
+
+ int operandL = 2;
+ int operandR = 3;
+
+ if ( !have_nios2_fpu_cmp_insn(cond, CMP_SF) &&
+ have_nios2_fpu_cmp_insn(get_reverse_cond(cond), CMP_SF) ) {
+
+ int temp = operandL;
+ operandL = operandR;
+ operandR = temp;
+
+ cond = get_reverse_cond(cond);
+ }
+
+ switch (cond)
+ {
+ case EQ:
+ N = nios2_fpu_insns[nios2_fpu_nios2_seqsf].N;
+ opt = "fcmpeqs";
+ break;
+ case NE:
+ N = nios2_fpu_insns[nios2_fpu_nios2_snesf].N;
+ opt = "fcmpnes";
+ break;
+ case GT:
+ N = nios2_fpu_insns[nios2_fpu_nios2_sgtsf].N;
+ opt = "fcmpgts";
+ break;
+ case GE:
+ N = nios2_fpu_insns[nios2_fpu_nios2_sgesf].N;
+ opt = "fcmpges";
+ break;
+ case LT:
+ N = nios2_fpu_insns[nios2_fpu_nios2_sltsf].N;
+ opt = "fcmplts";
+ break;
+ case LE:
+ N = nios2_fpu_insns[nios2_fpu_nios2_slesf].N;
+ opt = "fcmples"; break;
+ default:
+ fatal_insn ("bad single compare", insn);
+ }
+
+ if (N < 0)
+ {
+ fatal_insn ("attempt to use disabled fpu instruction", insn);
+ }
+
+ /*
+ * ??? This raises the whole vexing issue of how to handle
+ * out-of-range branches. Punt for now, seeing as how nios2-elf-as
+ * doesn't even _try_ to handle out-of-range branches yet!
+ */
+ if (snprintf (buf, sizeof (buf),
+ ".set\tnoat\n\t"
+ "custom\t%d, at, %%%d, %%%d # %s at, %%%d, %%%d\n\t"
+ "bne\tat, zero, %%l1\n\t"
+ ".set\tat",
+ N, operandL, operandR, opt, operandL, operandR) >= (int)sizeof (buf))
+ {
+ fatal_insn ("buffer overflow", insn);
+ }
+ return buf;
+}
+
+const char *
+nios2_output_fpu_insn_cmpd (rtx insn, enum rtx_code cond)
+{
+ static char buf[1024];
+ int N;
+ const char *opt;
+
+ int operandL = 2;
+ int operandR = 3;
+
+ if ( !have_nios2_fpu_cmp_insn(cond, CMP_DF) &&
+ have_nios2_fpu_cmp_insn(get_reverse_cond(cond), CMP_DF) ) {
+
+ int temp = operandL;
+ operandL = operandR;
+ operandR = temp;
+
+ cond = get_reverse_cond(cond);
+ }
+
+ switch (cond)
+ {
+ case EQ:
+ N = nios2_fpu_insns[nios2_fpu_nios2_seqdf].N;
+ opt = "fcmpeqd";
+ break;
+ case NE:
+ N = nios2_fpu_insns[nios2_fpu_nios2_snedf].N;
+ opt = "fcmpned";
+ break;
+ case GT:
+ N = nios2_fpu_insns[nios2_fpu_nios2_sgtdf].N;
+ opt = "fcmpgtd";
+ break;
+ case GE:
+ N = nios2_fpu_insns[nios2_fpu_nios2_sgedf].N;
+ opt = "fcmpged";
+ break;
+ case LT:
+ N = nios2_fpu_insns[nios2_fpu_nios2_sltdf].N;
+ opt = "fcmpltd";
+ break;
+ case LE:
+ N = nios2_fpu_insns[nios2_fpu_nios2_sledf].N;
+ opt = "fcmpled";
+ break;
+ default:
+ fatal_insn ("bad double compare", insn);
+ }
+
+ if (N < 0 || nios2_fpu_insns[nios2_fpu_nios2_fwrx].N < 0)
+ {
+ fatal_insn ("attempt to use disabled fpu instruction", insn);
+ }
+ if (snprintf (buf, sizeof (buf),
+ ".set\tnoat\n\t"
+ "custom\t%d, zero, %%%d, %%D%d # fwrx %%%d\n\t"
+ "custom\t%d, at, %%%d, %%D%d # %s at, %%%d, %%%d\n\t"
+ "bne\tat, zero, %%l1\n\t"
+ ".set\tat",
+ nios2_fpu_insns[nios2_fpu_nios2_fwrx].N, operandL, operandL, operandL,
+ N, operandR, operandR, operandL, operandR, opt) >= (int)sizeof (buf))
+ {
+ fatal_insn ("buffer overflow", insn);
+ }
+ return buf;
+}
+
+
+
+
+/*****************************************************************************
+**
+** 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;
+}
+
+
+/* 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;
+}
+
+/*
+ * This is just default_must_pass_in_stack from calls.c sans the final
+ * test for padding which isn't needed: we define BLOCK_REG_PADDING
+ * instead.
+ */
+int
+nios2_must_pass_in_stack (enum machine_mode mode, tree type)
+{
+ if (!type)
+ return false;
+
+ /* If the type has variable size... */
+ if (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
+ return true;
+
+ /* If the type is marked as addressable (it is required
+ to be constructed into the stack)... */
+ if (TREE_ADDRESSABLE (type))
+ return true;
+
+ return false;
+}
+
+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;
+ }
+}
+
+
+/* Update the data in CUM to advance over an argument
+ of mode MODE and data type TYPE.
+ (TYPE is null for libcalls where that information may not be available.) */
+
+void
+function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+ tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED)
+{
+ HOST_WIDE_INT param_size;
+
+ if (mode == BLKmode)
+ {
+ param_size = int_size_in_bytes (type);
+ if (param_size < 0)
+ internal_error
+ ("Do not know how to handle large structs or variable length types");
+ }
+ else
+ {
+ param_size = GET_MODE_SIZE (mode);
+ }
+
+ /* convert to words (round up) */
+ param_size = (3 + param_size) / 4;
+
+ if (cum->regs_used + param_size > NUM_ARG_REGS)
+ {
+ cum->regs_used = NUM_ARG_REGS;
+ }
+ else
+ {
+ cum->regs_used += param_size;
+ }
+
+ return;
+}
+
+int
+nios2_function_arg_padding_upward (enum machine_mode mode, tree type)
+{
+ /* On little-endian targets, the first byte of every stack argument
+ is passed in the first byte of the stack slot. */
+ if (!BYTES_BIG_ENDIAN)
+ return 1;
+
+ /* Otherwise, integral types are padded downward: the last byte of a
+ stack argument is passed in the last byte of the stack slot. */
+ if (type != 0
+ ? INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type)
+ : GET_MODE_CLASS (mode) == MODE_INT)
+ return 0;
+
+ /* Arguments smaller than a stack slot are padded downward. */
+ if (mode != BLKmode)
+ return (GET_MODE_BITSIZE (mode) >= PARM_BOUNDARY) ? 1 : 0;
+ else
+ return ((int_size_in_bytes (type) >= (PARM_BOUNDARY / BITS_PER_UNIT))
+ ? 1 : 0);
+}
+
+int
+nios2_block_reg_padding_upward (enum machine_mode mode, tree type,
+ int first ATTRIBUTE_UNUSED)
+{
+ /* ??? Do we need to treat floating point specially, ala MIPS? */
+ return nios2_function_arg_padding_upward (mode, type);
+}
+
+int
+nios2_return_in_memory (tree type)
+{
+ int res = ((int_size_in_bytes (type) > (2 * UNITS_PER_WORD))
+ || (int_size_in_bytes (type) == -1));
+
+ return res;
+}
+
+/* ??? It may be possible to eliminate the copyback and implement
+ my own va_arg type, but that is more work for now. */
+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,
+
+#undef NIOS2_DO_BUILTIN
+#define NIOS2_DO_BUILTIN(upper, lower, handler) \
+ NIOS2_CONCAT (NIOS2_BUILTIN_CUSTOM_, upper),
+NIOS2_FOR_ALL_CUSTOM_BUILTINS
+
+ NIOS2_FIRST_FPU_INSN,
+
+#undef NIOS2_FPU_INSN
+#define NIOS2_FPU_INSN(opt, insn, args) \
+ NIOS2_CONCAT (NIOS2_BUILTIN_FPU_, opt),
+NIOS2_FOR_ALL_FPU_INSNS
+
+ NIOS2_LAST_FPU_INSN,
+
+ LIM_NIOS2_BUILTINS
+};
+
+struct builtin_description
+{
+ const enum insn_code icode;
+ const char *const name;
+ const enum nios2_builtins code;
+ const tree *type;
+ rtx (* expander) (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+};
+
+static rtx nios2_expand_STXIO (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_LDXIO (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_sync (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_rdctl (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_wrctl (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+
+static rtx nios2_expand_custom_n (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_custom_Xn (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_custom_nX (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_custom_XnX (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_custom_nXX (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_custom_XnXX (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+
+static rtx nios2_expand_custom_zdz (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_custom_zsz (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_custom_szz (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_custom_sss (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_custom_ssz (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_custom_iss (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_custom_ddd (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_custom_ddz (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_custom_idd (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_custom_siz (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_custom_suz (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_custom_diz (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_custom_duz (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_custom_isz (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_custom_usz (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_custom_idz (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_custom_udz (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_custom_dsz (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_custom_sdz (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+
+static tree endlink;
+
+/* int fn (volatile const void *)
+ */
+static tree int_ftype_volatile_const_void_p;
+
+/* int fn (int)
+ */
+static tree int_ftype_int;
+
+/* void fn (int, int)
+ */
+static tree void_ftype_int_int;
+
+/* void fn (volatile void *, int)
+ */
+static tree void_ftype_volatile_void_p_int;
+
+/* void fn (void)
+ */
+static tree void_ftype_void;
+
+#undef NIOS2_DO_BUILTIN
+#define NIOS2_DO_BUILTIN(upper, lower, handler) \
+ static tree NIOS2_CONCAT (custom_, lower);
+NIOS2_FOR_ALL_CUSTOM_BUILTINS
+
+static tree custom_zdz;
+static tree custom_zsz;
+static tree custom_szz;
+static tree custom_sss;
+static tree custom_ssz;
+static tree custom_iss;
+static tree custom_ddd;
+static tree custom_ddz;
+static tree custom_idd;
+static tree custom_siz;
+static tree custom_suz;
+static tree custom_diz;
+static tree custom_duz;
+static tree custom_isz;
+static tree custom_usz;
+static tree custom_idz;
+static tree custom_udz;
+static tree custom_dsz;
+static tree custom_sdz;
+
+static const struct builtin_description bdesc[] = {
+ {CODE_FOR_ldbio, "__builtin_ldbio", NIOS2_BUILTIN_LDBIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO},
+ {CODE_FOR_ldbuio, "__builtin_ldbuio", NIOS2_BUILTIN_LDBUIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO},
+ {CODE_FOR_ldhio, "__builtin_ldhio", NIOS2_BUILTIN_LDHIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO},
+ {CODE_FOR_ldhuio, "__builtin_ldhuio", NIOS2_BUILTIN_LDHUIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO},
+ {CODE_FOR_ldwio, "__builtin_ldwio", NIOS2_BUILTIN_LDWIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO},
+
+ {CODE_FOR_stbio, "__builtin_stbio", NIOS2_BUILTIN_STBIO, &void_ftype_volatile_void_p_int, nios2_expand_STXIO},
+ {CODE_FOR_sthio, "__builtin_sthio", NIOS2_BUILTIN_STHIO, &void_ftype_volatile_void_p_int, nios2_expand_STXIO},
+ {CODE_FOR_stwio, "__builtin_stwio", NIOS2_BUILTIN_STWIO, &void_ftype_volatile_void_p_int, nios2_expand_STXIO},
+
+ {CODE_FOR_sync, "__builtin_sync", NIOS2_BUILTIN_SYNC, &void_ftype_void, nios2_expand_sync},
+ {CODE_FOR_rdctl, "__builtin_rdctl", NIOS2_BUILTIN_RDCTL, &int_ftype_int, nios2_expand_rdctl},
+ {CODE_FOR_wrctl, "__builtin_wrctl", NIOS2_BUILTIN_WRCTL, &void_ftype_int_int, nios2_expand_wrctl},
+
+#undef NIOS2_DO_BUILTIN
+#define NIOS2_DO_BUILTIN(upper, lower, handler) \
+ {NIOS2_CONCAT (CODE_FOR_custom_, lower), \
+ "__builtin_custom_" NIOS2_STRINGIFY (lower), \
+ NIOS2_CONCAT (NIOS2_BUILTIN_CUSTOM_, upper), \
+ &NIOS2_CONCAT (custom_, lower), \
+ NIOS2_CONCAT (nios2_expand_custom_, handler)},
+NIOS2_FOR_ALL_CUSTOM_BUILTINS
+
+#undef NIOS2_FPU_INSN
+#define NIOS2_FPU_INSN(opt, insn, args) \
+ {NIOS2_CONCAT (CODE_FOR_, insn), \
+ "__builtin_custom_" NIOS2_STRINGIFY (opt), \
+ NIOS2_CONCAT (NIOS2_BUILTIN_FPU_, opt), \
+ &NIOS2_CONCAT (custom_, args), \
+ NIOS2_CONCAT (nios2_expand_custom_, args)},
+NIOS2_FOR_ALL_FPU_INSNS
+
+ {0, 0, 0, 0, 0},
+};
+
+/* 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))));
+
+ custom_zdz
+ = build_function_type (void_type_node,
+ def_param (double_type_node)
+ endlink));
+
+ custom_zsz
+ = build_function_type (void_type_node,
+ def_param (float_type_node)
+ endlink));
+
+ custom_szz
+ = build_function_type (float_type_node,
+ def_param (void_type_node)
+ endlink));
+
+ custom_sss
+ = build_function_type (float_type_node,
+ def_param (float_type_node)
+ def_param (float_type_node)
+ endlink)));
+
+ custom_ssz
+ = build_function_type (float_type_node,
+ def_param (float_type_node)
+ endlink));
+
+ custom_iss
+ = build_function_type (integer_type_node,
+ def_param (float_type_node)
+ def_param (float_type_node)
+ endlink)));
+
+ custom_ddd
+ = build_function_type (double_type_node,
+ def_param (double_type_node)
+ def_param (double_type_node)
+ endlink)));
+
+ custom_ddz
+ = build_function_type (double_type_node,
+ def_param (double_type_node)
+ endlink));
+
+ custom_idd
+ = build_function_type (integer_type_node,
+ def_param (double_type_node)
+ def_param (double_type_node)
+ endlink)));
+
+ custom_siz
+ = build_function_type (float_type_node,
+ def_param (integer_type_node)
+ endlink));
+
+ custom_suz
+ = build_function_type (float_type_node,
+ def_param (unsigned_type_node)
+ endlink));
+
+ custom_diz
+ = build_function_type (double_type_node,
+ def_param (integer_type_node)
+ endlink));
+
+ custom_duz
+ = build_function_type (double_type_node,
+ def_param (unsigned_type_node)
+ endlink));
+
+ custom_isz
+ = build_function_type (integer_type_node,
+ def_param (float_type_node)
+ endlink));
+
+ custom_usz
+ = build_function_type (unsigned_type_node,
+ def_param (float_type_node)
+ endlink));
+
+ custom_idz
+ = build_function_type (integer_type_node,
+ def_param (double_type_node)
+ endlink));
+
+ custom_udz
+ = build_function_type (unsigned_type_node,
+ def_param (double_type_node)
+ endlink));
+
+ custom_dsz
+ = build_function_type (double_type_node,
+ def_param (float_type_node)
+ endlink));
+
+ custom_sdz
+ = build_function_type (float_type_node,
+ def_param (double_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)
+ {
+ if (d->code > NIOS2_FIRST_FPU_INSN && d->code < NIOS2_LAST_FPU_INSN)
+ {
+ nios2_fpu_info *inf = &nios2_fpu_insns[d->code - (NIOS2_FIRST_FPU_INSN + 1)];
+ const struct insn_data *idata = &insn_data[d->icode];
+ if (inf->N < 0)
+ {
+ fatal_error ("Cannot call `%s' without specifying switch `-mcustom-%s'",
+ d->name,
+ inf->option);
+ }
+ if (inf->args[0] != 'z'
+ && (!target
+ || !(idata->operand[0].predicate) (target,
+ idata->operand[0].mode)))
+ target = gen_reg_rtx (idata->operand[0].mode);
+ }
+ return (d->expander) (d, exp, target, subtarget, mode, ignore);
+ }
+
+ /* we should have seen one of the functins we registered */
+ 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);
+
+ builtin_custom_seen[INTVAL (opcode)] = d->name;
+ nios2_custom_check_insns (0);
+ return opcode;
+}
+
+static rtx
+nios2_extract_operand (const struct builtin_description *d, int op, int argnum, tree arglist)
+{
+ enum machine_mode mode = insn_data[d->icode].operand[op].mode;
+ tree arg = TREE_VALUE (arglist);
+ rtx operand = expand_expr (arg, NULL_RTX, mode, 0);
+ 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;
+}
+
+static rtx
+nios2_extract_double (const struct insn_data *idata, tree arglist, int index)
+{
+ rtx arg;
+
+ while (index--)
+ {
+ arglist = TREE_CHAIN (arglist);
+ }
+ arg = expand_expr (TREE_VALUE (arglist), NULL_RTX, DFmode, 0);
+ arg = protect_from_queue (arg, 0);
+ if (!(*(idata->operand[index+1].predicate)) (arg, DFmode))
+ {
+ arg = copy_to_mode_reg (DFmode, arg);
+ }
+ return arg;
+}
+
+static rtx
+nios2_extract_float (const struct insn_data *idata, tree arglist, int index)
+{
+ rtx arg;
+
+ while (index--)
+ {
+ arglist = TREE_CHAIN (arglist);
+ }
+ arg = expand_expr (TREE_VALUE (arglist), NULL_RTX, SFmode, 0);
+ arg = protect_from_queue (arg, 0);
+ if (!(*(idata->operand[index+1].predicate)) (arg, SFmode))
+ {
+ arg = copy_to_mode_reg (SFmode, arg);
+ }
+ return arg;
+}
+
+static rtx
+nios2_extract_integer (const struct insn_data *idata, tree arglist, int index)
+{
+ rtx arg;
+
+ while (index--)
+ {
+ arglist = TREE_CHAIN (arglist);
+ }
+ arg = expand_expr (TREE_VALUE (arglist), NULL_RTX, SImode, 0);
+ arg = protect_from_queue (arg, 0);
+ if (!(*(idata->operand[index+1].predicate)) (arg, SImode))
+ {
+ arg = copy_to_mode_reg (SImode, arg);
+ }
+ return protect_from_queue (arg, 0);
+}
+
+static rtx
+nios2_expand_custom_zdz (const struct builtin_description *d,
+ tree exp,
+ rtx target ATTRIBUTE_UNUSED,
+ rtx subtarget ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ tree arglist = TREE_OPERAND (exp, 1);
+ rtx pat = GEN_FCN (d->icode) (nios2_extract_double (&insn_data[d->icode],
+ arglist, 0));
+ if (pat)
+ emit_insn (pat);
+ return 0;
+}
+
+static rtx
+nios2_expand_custom_zsz (const struct builtin_description *d,
+ tree exp,
+ rtx target ATTRIBUTE_UNUSED,
+ rtx subtarget ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ tree arglist = TREE_OPERAND (exp, 1);
+ rtx pat = GEN_FCN (d->icode) (nios2_extract_float (&insn_data[d->icode],
+ arglist, 0));
+ if (pat)
+ emit_insn (pat);
+ return 0;
+}
+
+static rtx
+nios2_expand_custom_szz (const struct builtin_description *d,
+ tree exp ATTRIBUTE_UNUSED,
+ rtx target,
+ rtx subtarget ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ rtx pat = GEN_FCN (d->icode) (target);
+ if (pat)
+ emit_insn (pat);
+ return target;
+}
+
+static rtx
+nios2_expand_custom_sss (const struct builtin_description *d,
+ tree exp,
+ rtx target,
+ rtx subtarget ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ tree arglist = TREE_OPERAND (exp, 1);
+ rtx pat = GEN_FCN (d->icode) (target,
+ nios2_extract_float (&insn_data[d->icode],
+ arglist, 0),
+ nios2_extract_float (&insn_data[d->icode],
+ arglist, 1));
+ if (pat)
+ emit_insn (pat);
+ return target;
+}
+
+static rtx
+nios2_expand_custom_ssz (const struct builtin_description *d,
+ tree exp,
+ rtx target,
+ rtx subtarget ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ tree arglist = TREE_OPERAND (exp, 1);
+ rtx pat = GEN_FCN (d->icode) (target,
+ nios2_extract_float (&insn_data[d->icode],
+ arglist, 0));
+ if (pat)
+ emit_insn (pat);
+ return target;
+}
+
+static rtx
+nios2_expand_custom_iss (const struct builtin_description *d,
+ tree exp,
+ rtx target,
+ rtx subtarget ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ tree arglist = TREE_OPERAND (exp, 1);
+ rtx pat = GEN_FCN (d->icode) (target,
+ nios2_extract_float (&insn_data[d->icode],
+ arglist, 0),
+ nios2_extract_float (&insn_data[d->icode],
+ arglist, 1));
+ if (pat)
+ emit_insn (pat);
+ return target;
+}
+
+static rtx
+nios2_expand_custom_ddd (const struct builtin_description *d,
+ tree exp,
+ rtx target,
+ rtx subtarget ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ tree arglist = TREE_OPERAND (exp, 1);
+ rtx pat = GEN_FCN (d->icode) (target,
+ nios2_extract_double (&insn_data[d->icode],
+ arglist, 0),
+ nios2_extract_double (&insn_data[d->icode],
+ arglist, 1));
+ if (pat)
+ emit_insn (pat);
+ return target;
+}
+
+static rtx
+nios2_expand_custom_ddz (const struct builtin_description *d,
+ tree exp,
+ rtx target,
+ rtx subtarget ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ tree arglist = TREE_OPERAND (exp, 1);
+ rtx pat = GEN_FCN (d->icode) (target,
+ nios2_extract_double (&insn_data[d->icode],
+ arglist, 0));
+ if (pat)
+ emit_insn (pat);
+ return target;
+}
+
+static rtx
+nios2_expand_custom_idd (const struct builtin_description *d,
+ tree exp,
+ rtx target,
+ rtx subtarget ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ tree arglist = TREE_OPERAND (exp, 1);
+ rtx pat = GEN_FCN (d->icode) (target,
+ nios2_extract_double (&insn_data[d->icode],
+ arglist, 0),
+ nios2_extract_double (&insn_data[d->icode],
+ arglist, 1));
+ if (pat)
+ emit_insn (pat);
+ return target;
+}
+
+static rtx
+nios2_expand_custom_siz (const struct builtin_description *d,
+ tree exp,
+ rtx target,
+ rtx subtarget ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ tree arglist = TREE_OPERAND (exp, 1);
+ rtx pat = GEN_FCN (d->icode) (target,
+ nios2_extract_integer (&insn_data[d->icode],
+ arglist, 0));
+ if (pat)
+ emit_insn (pat);
+ return target;
+}
+
+static rtx
+nios2_expand_custom_suz (const struct builtin_description *d,
+ tree exp,
+ rtx target,
+ rtx subtarget ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ tree arglist = TREE_OPERAND (exp, 1);
+ rtx pat = GEN_FCN (d->icode) (target,
+ nios2_extract_integer (&insn_data[d->icode],
+ arglist, 0));
+ if (pat)
+ emit_insn (pat);
+ return target;
+}
+
+static rtx
+nios2_expand_custom_diz (const struct builtin_description *d,
+ tree exp,
+ rtx target,
+ rtx subtarget ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ tree arglist = TREE_OPERAND (exp, 1);
+ rtx pat = GEN_FCN (d->icode) (target,
+ nios2_extract_integer (&insn_data[d->icode],
+ arglist, 0));
+ if (pat)
+ emit_insn (pat);
+ return target;
+}
+
+static rtx
+nios2_expand_custom_duz (const struct builtin_description *d,
+ tree exp,
+ rtx target,
+ rtx subtarget ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ tree arglist = TREE_OPERAND (exp, 1);
+ rtx pat = GEN_FCN (d->icode) (target,
+ nios2_extract_integer (&insn_data[d->icode],
+ arglist, 0));
+ if (pat)
+ emit_insn (pat);
+ return target;
+}
+
+static rtx
+nios2_expand_custom_isz (const struct builtin_description *d,
+ tree exp,
+ rtx target,
+ rtx subtarget ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ tree arglist = TREE_OPERAND (exp, 1);
+ rtx pat = GEN_FCN (d->icode) (target,
+ nios2_extract_float (&insn_data[d->icode],
+ arglist, 0));
+ if (pat)
+ emit_insn (pat);
+ return target;
+}
+
+static rtx
+nios2_expand_custom_usz (const struct builtin_description *d,
+ tree exp,
+ rtx target,
+ rtx subtarget ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ tree arglist = TREE_OPERAND (exp, 1);
+ rtx pat = GEN_FCN (d->icode) (target,
+ nios2_extract_float (&insn_data[d->icode],
+ arglist, 0));
+ if (pat)
+ emit_insn (pat);
+ return target;
+}
+
+static rtx
+nios2_expand_custom_idz (const struct builtin_description *d,
+ tree exp,
+ rtx target,
+ rtx subtarget ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ tree arglist = TREE_OPERAND (exp, 1);
+ rtx pat = GEN_FCN (d->icode) (target,
+ nios2_extract_double (&insn_data[d->icode],
+ arglist, 0));
+ if (pat)
+ emit_insn (pat);
+ return target;
+}
+
+static rtx
+nios2_expand_custom_udz (const struct builtin_description *d,
+ tree exp,
+ rtx target,
+ rtx subtarget ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ tree arglist = TREE_OPERAND (exp, 1);
+ rtx pat = GEN_FCN (d->icode) (target,
+ nios2_extract_double (&insn_data[d->icode],
+ arglist, 0));
+ if (pat)
+ emit_insn (pat);
+ return target;
+}
+
+static rtx
+nios2_expand_custom_dsz (const struct builtin_description *d,
+ tree exp,
+ rtx target,
+ rtx subtarget ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ tree arglist = TREE_OPERAND (exp, 1);
+ rtx pat = GEN_FCN (d->icode) (target,
+ nios2_extract_float (&insn_data[d->icode],
+ arglist, 0));
+ if (pat)
+ emit_insn (pat);
+ return target;
+}
+
+static rtx
+nios2_expand_custom_sdz (const struct builtin_description *d,
+ tree exp,
+ rtx target,
+ rtx subtarget ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ tree arglist = TREE_OPERAND (exp, 1);
+ rtx pat = GEN_FCN (d->icode) (target,
+ nios2_extract_double (&insn_data[d->icode],
+ arglist, 0));
+ if (pat)
+ emit_insn (pat);
+ return target;
+}
+
+#include "gt-nios2.h"
+
diff --git a/gcc/config/nios2/nios2.h b/gcc/config/nios2/nios2.h
new file mode 100644
index 0000000..500ccf0
--- /dev/null
+++ b/gcc/config/nios2/nios2.h
@@ -0,0 +1,1130 @@
+/* Definitions of target machine for Altera NIOS 2G NIOS2 version.
+ Copyright (C) 2005 Altera
+ Contributed by Jonah Graham (jgraham@altera.com) and Will Reece (wreece@altera.com).
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+
+#define TARGET_CPU_CPP_BUILTINS() \
+ do \
+ { \
+ builtin_define_std ("NIOS2"); \
+ builtin_define_std ("nios2"); \
+ if (TARGET_BIG_ENDIAN) \
+ builtin_define_std ("nios2_big_endian"); \
+ else \
+ builtin_define_std ("nios2_little_endian"); \
+ } \
+ while (0)
+#define TARGET_VERSION fprintf (stderr, " (Altera Nios II)")
+
+
+
+
+
+/*********************************
+ * Run-time Target Specification
+ *********************************/
+
+#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
+#define STACK_CHECK_FLAG 0x0080
+#define REVERSE_BITFIELDS_FLAG 0x0100
+/* Reserve 0x0200 for REVERSE_ENDIAN_FLAG */
+#define BIG_ENDIAN_FLAG 0x0400
+
+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_STACK_CHECK (target_flags & STACK_CHECK_FLAG)
+#define TARGET_REVERSE_BITFIELDS (target_flags & REVERSE_BITFIELDS_FLAG)
+#define TARGET_BIG_ENDIAN (target_flags & BIG_ENDIAN_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") */ }, \
+ { "stack-check", STACK_CHECK_FLAG, \
+ N_("Enable stack limit checking.") }, \
+ { "no-stack-check", -STACK_CHECK_FLAG, \
+ N_("Disable stack limit checking (default).") }, \
+ { "reverse-bitfields", REVERSE_BITFIELDS_FLAG, \
+ N_("Reverse the order of bitfields in a struct.") }, \
+ { "no-reverse-bitfields", -REVERSE_BITFIELDS_FLAG, \
+ N_("Use the normal order of bitfields in a struct (default).") }, \
+ { "eb", BIG_ENDIAN_FLAG, \
+ N_("Use big-endian byte order") }, \
+ { "el", -BIG_ENDIAN_FLAG, \
+ N_("Use little-endian byte order") }, \
+ { "", 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= */
+
+/*
+ * There's a lot of error-prone tedium with all the different
+ * custom floating point instructions. Try to automate it a bit
+ * to make it easier to deal with.
+ */
+#define NIOS2_STRINGIFY_INNER(x) #x
+#define NIOS2_STRINGIFY(x) NIOS2_STRINGIFY_INNER(x)
+#define NIOS2_CONCAT_INNER(x, y) x ## y
+#define NIOS2_CONCAT(x, y) NIOS2_CONCAT_INNER (x, y)
+
+#define NIOS2_FOR_ALL_FPU_INSNS \
+ NIOS2_FPU_INSN (fwrx, nios2_fwrx, zdz) \
+ NIOS2_FPU_INSN (fwry, nios2_fwry, zsz) \
+ NIOS2_FPU_INSN (frdxlo, nios2_frdxlo, szz) \
+ NIOS2_FPU_INSN (frdxhi, nios2_frdxhi, szz) \
+ NIOS2_FPU_INSN (frdy, nios2_frdy, szz) \
+\
+ NIOS2_FPU_INSN (fadds, addsf3, sss) \
+ NIOS2_FPU_INSN (fsubs, subsf3, sss) \
+ NIOS2_FPU_INSN (fmuls, mulsf3, sss) \
+ NIOS2_FPU_INSN (fdivs, divsf3, sss) \
+ NIOS2_FPU_INSN (fmins, minsf3, sss) \
+ NIOS2_FPU_INSN (fmaxs, maxsf3, sss) \
+ NIOS2_FPU_INSN (fnegs, negsf2, ssz) \
+ NIOS2_FPU_INSN (fabss, abssf2, ssz) \
+ NIOS2_FPU_INSN (fsqrts, sqrtsf2, ssz) \
+ NIOS2_FPU_INSN (fcoss, cossf2, ssz) \
+ NIOS2_FPU_INSN (fsins, sinsf2, ssz) \
+ NIOS2_FPU_INSN (ftans, tansf2, ssz) \
+ NIOS2_FPU_INSN (fatans, atansf2, ssz) \
+ NIOS2_FPU_INSN (fexps, expsf2, ssz) \
+ NIOS2_FPU_INSN (flogs, logsf2, ssz) \
+ NIOS2_FPU_INSN (fcmplts, nios2_sltsf, iss) \
+ NIOS2_FPU_INSN (fcmples, nios2_slesf, iss) \
+ NIOS2_FPU_INSN (fcmpgts, nios2_sgtsf, iss) \
+ NIOS2_FPU_INSN (fcmpges, nios2_sgesf, iss) \
+ NIOS2_FPU_INSN (fcmpeqs, nios2_seqsf, iss) \
+ NIOS2_FPU_INSN (fcmpnes, nios2_snesf, iss) \
+\
+ NIOS2_FPU_INSN (faddd, adddf3, ddd) \
+ NIOS2_FPU_INSN (fsubd, subdf3, ddd) \
+ NIOS2_FPU_INSN (fmuld, muldf3, ddd) \
+ NIOS2_FPU_INSN (fdivd, divdf3, ddd) \
+ NIOS2_FPU_INSN (fmind, mindf3, ddd) \
+ NIOS2_FPU_INSN (fmaxd, maxdf3, ddd) \
+ NIOS2_FPU_INSN (fnegd, negdf2, ddz) \
+ NIOS2_FPU_INSN (fabsd, absdf2, ddz) \
+ NIOS2_FPU_INSN (fsqrtd, sqrtdf2, ddz) \
+ NIOS2_FPU_INSN (fcosd, cosdf2, ddz) \
+ NIOS2_FPU_INSN (fsind, sindf2, ddz) \
+ NIOS2_FPU_INSN (ftand, tandf2, ddz) \
+ NIOS2_FPU_INSN (fatand, atandf2, ddz) \
+ NIOS2_FPU_INSN (fexpd, expdf2, ddz) \
+ NIOS2_FPU_INSN (flogd, logdf2, ddz) \
+ NIOS2_FPU_INSN (fcmpltd, nios2_sltdf, idd) \
+ NIOS2_FPU_INSN (fcmpled, nios2_sledf, idd) \
+ NIOS2_FPU_INSN (fcmpgtd, nios2_sgtdf, idd) \
+ NIOS2_FPU_INSN (fcmpged, nios2_sgedf, idd) \
+ NIOS2_FPU_INSN (fcmpeqd, nios2_seqdf, idd) \
+ NIOS2_FPU_INSN (fcmpned, nios2_snedf, idd) \
+\
+ NIOS2_FPU_INSN (floatis, floatsisf2, siz) \
+ NIOS2_FPU_INSN (floatus, floatunssisf2, suz) \
+ NIOS2_FPU_INSN (floatid, floatsidf2, diz) \
+ NIOS2_FPU_INSN (floatud, floatunssidf2, duz) \
+ NIOS2_FPU_INSN (fixsi, fixsfsi2, isz) \
+ NIOS2_FPU_INSN (fixsu, fixunssfsi2, usz) \
+ NIOS2_FPU_INSN (fixdi, fixdfsi2, idz) \
+ NIOS2_FPU_INSN (fixdu, fixunsdfsi2, udz) \
+ NIOS2_FPU_INSN (fextsd, extendsfdf2, dsz) \
+ NIOS2_FPU_INSN (ftruncds, truncdfsf2, sdz)
+
+enum
+{
+#define NIOS2_FPU_INSN(opt, insn, args) \
+ NIOS2_CONCAT (nios2_fpu_, insn),
+NIOS2_FOR_ALL_FPU_INSNS
+ nios2_fpu_max_insn
+};
+
+struct cpp_reader;
+typedef const char * (*nios2_outputfn) (rtx);
+typedef void (*nios2_pragmafn) (struct cpp_reader *);
+
+typedef struct
+{
+ const char *option; /* name of switch, e.g. fadds */
+ const char *insnnm; /* name of gcc insn, e.g. addsf3 */
+ const char *args; /* args to gcc insn, e.g. sss */
+ const char *value; /* value of switch as a string */
+ int N; /* value of switch as an integer, -1 = not used */
+ nios2_outputfn output; /* output function for use in .md file */
+ const char *pname; /* name of corresponding #pragma custom- */
+ nios2_pragmafn pragma; /* pragma function for register_target_pragmas */
+ const char *nopname; /* name of corresponding #pragma no-custom- */
+ nios2_pragmafn nopragma; /* pragma function for register_target_pragmas */
+ int is_double; /* does this insn have any double operands */
+ int needed_by_double; /* is this insn needed if doubles are used? */
+ int needs_unsafe; /* does this insn require
+ -funsafe-math-optimizations to work? */
+ int needs_finite; /* does this insn require
+ -ffinite-math-only to work? */
+ int pragma_seen; /* have we seen the corresponding #pragma? */
+} nios2_fpu_info;
+
+extern nios2_fpu_info nios2_fpu_insns[nios2_fpu_max_insn];
+extern const char *nios2_custom_fpu_cfg_string;
+
+#undef NIOS2_FPU_INSN
+#define NIOS2_FPU_INSN(opt, insn, args) \
+ { \
+ "custom-" NIOS2_STRINGIFY (opt) "=", \
+ &(nios2_fpu_insns[NIOS2_CONCAT (nios2_fpu_, insn)].value), \
+ N_("Integer id (N) of " NIOS2_STRINGIFY (opt) " custom instruction"), \
+ 0 \
+ }, \
+ { \
+ "no-custom-" NIOS2_STRINGIFY (opt), \
+ &(nios2_fpu_insns[NIOS2_CONCAT (nios2_fpu_, insn)].value), \
+ N_("Do not use the " NIOS2_STRINGIFY (opt) " custom instruction"), \
+ "-1" \
+ },
+
+#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}, \
+ NIOS2_FOR_ALL_FPU_INSNS \
+ { "custom-fpu-cfg=", &nios2_custom_fpu_cfg_string, \
+ N_("Floating point custom instruction configuration name"), 0 }, \
+}
+
+/* We're little endian, unless otherwise specified by including big.h */
+#ifndef TARGET_ENDIAN_DEFAULT
+# define TARGET_ENDIAN_DEFAULT 0
+#endif
+
+/* Default target_flags if no switches specified. */
+#ifndef TARGET_DEFAULT
+# define TARGET_DEFAULT (HAS_MUL_FLAG | CACHE_VOLATILE_FLAG | TARGET_ENDIAN_DEFAULT)
+#endif
+
+/* Switch Recognition by gcc.c. Add -G xx support */
+#undef SWITCH_TAKES_ARG
+#define SWITCH_TAKES_ARG(CHAR) \
+ (DEFAULT_SWITCH_TAKES_ARG (CHAR) || (CHAR) == 'G')
+
+#define OVERRIDE_OPTIONS override_options ()
+#define OPTIMIZATION_OPTIONS(LEVEL, SIZE) optimization_options (LEVEL, SIZE)
+#define CAN_DEBUG_WITHOUT_FP
+
+#define CC1_SPEC "\
+%{G*} %{EB:-meb} %{EL:-mel} %{EB:%{EL:%emay not use both -EB and -EL}}"
+
+#if TARGET_ENDIAN_DEFAULT == 0
+# define ASM_SPEC "\
+%{!EB:%{!meb:-EL}} %{EB|meb:-EB}"
+# define LINK_SPEC "\
+%{!EB:%{!meb:-EL}} %{EB|meb:-EB}"
+# define MULTILIB_DEFAULTS { "EL" }
+#else
+# define ASM_SPEC "\
+%{!EL:%{!mel:-EB}} %{EL|mel:-EL}"
+# define LINK_SPEC "\
+%{!EL:%{!mel:-EB}} %{EL|mel:-EL}"
+# define MULTILIB_DEFAULTS { "EB" }
+#endif
+
+#undef LIB_SPEC
+#define LIB_SPEC \
+"--start-group %{msmallc: -lsmallc} %{!msmallc: -lc} -lgcc \
+ %{msys-lib=*: -l%*} \
+ %{!msys-lib=*: -lnosys -lstack} \
+ --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 (TARGET_BIG_ENDIAN != 0)
+#define WORDS_BIG_ENDIAN (TARGET_BIG_ENDIAN != 0)
+#if defined(__nios2_big_endian__)
+#define LIBGCC2_WORDS_BIG_ENDIAN 1
+#else
+#define LIBGCC2_WORDS_BIG_ENDIAN 0
+#endif
+#define BITS_PER_UNIT 8
+#define BITS_PER_WORD 32
+#define UNITS_PER_WORD 4
+#define POINTER_SIZE 32
+#define BIGGEST_ALIGNMENT 32
+#define STRICT_ALIGNMENT 1
+#define FUNCTION_BOUNDARY 32
+#define PARM_BOUNDARY 32
+#define STACK_BOUNDARY 32
+#define PREFERRED_STACK_BOUNDARY 32
+#define MAX_FIXED_MODE_SIZE 64
+
+#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
+ ((TREE_CODE (EXP) == STRING_CST) \
+ && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
+
+
+/**********************
+ * Layout of Source Language Data Types
+ **********************/
+
+#define INT_TYPE_SIZE 32
+#define SHORT_TYPE_SIZE 16
+#define LONG_TYPE_SIZE 32
+#define LONG_LONG_TYPE_SIZE 64
+#define FLOAT_TYPE_SIZE 32
+#define DOUBLE_TYPE_SIZE 64
+#define LONG_DOUBLE_TYPE_SIZE DOUBLE_TYPE_SIZE
+
+
+/*************************
+ * Condition Code Status
+ ************************/
+
+/* comparison type */
+/* ??? Currently CMP_DI is unused. CMP_SF and CMP_DF are only used if
+ the corresponding -mcustom-<opcode> switches are present. */
+enum cmp_type {
+ CMP_SI, /* compare four byte integers */
+ CMP_DI, /* compare eight byte integers */
+ CMP_SF, /* compare single precision floats */
+ CMP_DF, /* compare double precision floats */
+ CMP_MAX /* max comparison type */
+};
+
+extern GTY(()) rtx branch_cmp[2]; /* operands for compare */
+extern enum cmp_type branch_type; /* what type of branch to use */
+
+/**********************
+ * Register Usage
+ **********************/
+
+/* ---------------------------------- *
+ * Basic Characteristics of Registers
+ * ---------------------------------- */
+
+/*
+Register Number
+ Register Name
+ Alternate Name
+ Purpose
+0 r0 zero always zero
+1 r1 at Assembler Temporary
+2-3 r2-r3 Return Location
+4-7 r4-r7 Register Arguments
+8-15 r8-r15 Caller Saved Registers
+16-22 r16-r22 Callee Saved Registers
+23 r23 sc Static Chain (Callee Saved)
+ ??? Does $sc want to be caller or callee
+ saved. If caller, 15, else 23.
+24 r24 et Exception Temporary
+25 r25 bt Breakpoint Temporary
+26 r26 gp Global Pointer
+27 r27 sp Stack Pointer
+28 r28 fp Frame Pointer
+29 r29 ea Exception Return Address
+30 r30 ba Breakpoint Return Address
+31 r31 ra Return Address
+
+32 ctl0 status
+33 ctl1 estatus STATUS saved by exception ?
+34 ctl2 bstatus STATUS saved by break ?
+35 ctl3 ipri Interrupt Priority Mask ?
+36 ctl4 ecause Exception Cause ?
+
+37 pc Not an actual register
+
+38 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,
+ D00_REG,
+ D01_REG,
+ D02_REG,
+ D03_REG,
+ D04_REG,
+ D05_REG,
+ D06_REG,
+ D07_REG,
+ D08_REG,
+ D09_REG,
+ D10_REG,
+ D11_REG,
+ D12_REG,
+ D13_REG,
+ D14_REG,
+ D15_REG,
+ D16_REG,
+ D17_REG,
+ D18_REG,
+ D19_REG,
+ D20_REG,
+ D21_REG,
+ D22_REG,
+ D23_REG,
+ D24_REG,
+ D25_REG,
+ D26_REG,
+ D27_REG,
+ D28_REG,
+ D29_REG,
+ D30_REG,
+ D31_REG,
+ GP_REGS,
+ ALL_REGS,
+ LIM_REG_CLASSES
+};
+
+#define N_REG_CLASSES (int) LIM_REG_CLASSES
+
+#define REG_CLASS_NAMES \
+ {"NO_REGS", \
+ "D00_REG", \
+ "D01_REG", \
+ "D02_REG", \
+ "D03_REG", \
+ "D04_REG", \
+ "D05_REG", \
+ "D06_REG", \
+ "D07_REG", \
+ "D08_REG", \
+ "D09_REG", \
+ "D10_REG", \
+ "D11_REG", \
+ "D12_REG", \
+ "D13_REG", \
+ "D14_REG", \
+ "D15_REG", \
+ "D16_REG", \
+ "D17_REG", \
+ "D18_REG", \
+ "D19_REG", \
+ "D20_REG", \
+ "D21_REG", \
+ "D22_REG", \
+ "D23_REG", \
+ "D24_REG", \
+ "D25_REG", \
+ "D26_REG", \
+ "D27_REG", \
+ "D28_REG", \
+ "D29_REG", \
+ "D30_REG", \
+ "D31_REG", \
+ "GP_REGS", \
+ "ALL_REGS"}
+
+#define GENERAL_REGS ALL_REGS
+
+#define REG_CLASS_CONTENTS \
+/* NO_REGS */ {{ 0, 0}, \
+/* D00_REG */ { 1 << 0, 0}, \
+/* D01_REG */ { 1 << 1, 0}, \
+/* D02_REG */ { 1 << 2, 0}, \
+/* D03_REG */ { 1 << 3, 0}, \
+/* D04_REG */ { 1 << 4, 0}, \
+/* D05_REG */ { 1 << 5, 0}, \
+/* D06_REG */ { 1 << 6, 0}, \
+/* D07_REG */ { 1 << 7, 0}, \
+/* D08_REG */ { 1 << 8, 0}, \
+/* D09_REG */ { 1 << 9, 0}, \
+/* D10_REG */ { 1 << 10, 0}, \
+/* D11_REG */ { 1 << 11, 0}, \
+/* D12_REG */ { 1 << 12, 0}, \
+/* D13_REG */ { 1 << 13, 0}, \
+/* D14_REG */ { 1 << 14, 0}, \
+/* D15_REG */ { 1 << 15, 0}, \
+/* D16_REG */ { 1 << 16, 0}, \
+/* D17_REG */ { 1 << 17, 0}, \
+/* D18_REG */ { 1 << 18, 0}, \
+/* D19_REG */ { 1 << 19, 0}, \
+/* D20_REG */ { 1 << 20, 0}, \
+/* D21_REG */ { 1 << 21, 0}, \
+/* D22_REG */ { 1 << 22, 0}, \
+/* D23_REG */ { 1 << 23, 0}, \
+/* D24_REG */ { 1 << 24, 0}, \
+/* D25_REG */ { 1 << 25, 0}, \
+/* D26_REG */ { 1 << 26, 0}, \
+/* D27_REG */ { 1 << 27, 0}, \
+/* D28_REG */ { 1 << 28, 0}, \
+/* D29_REG */ { 1 << 29, 0}, \
+/* D30_REG */ { 1 << 30, 0}, \
+/* D31_REG */ { 1 << 31, 0}, \
+/* GP_REGS */ {~0, 0}, \
+/* ALL_REGS */ {~0,~0}} \
+
+#define REGNO_REG_CLASS(REGNO) ((REGNO) <= 31 ? GP_REGS : ALL_REGS)
+
+#define BASE_REG_CLASS ALL_REGS
+#define INDEX_REG_CLASS ALL_REGS
+
+/* 'r', is handled automatically */
+#define REG_CLASS_FROM_CONSTRAINT(CHAR, STR) \
+ reg_class_from_constraint ((CHAR), (STR))
+
+
+#define REGNO_OK_FOR_BASE_P2(REGNO, STRICT) \
+ ((STRICT) \
+ ? (REGNO) < FIRST_PSEUDO_REGISTER \
+ : (REGNO) < FIRST_PSEUDO_REGISTER || (reg_renumber && reg_renumber[REGNO] < FIRST_PSEUDO_REGISTER))
+
+#define REGNO_OK_FOR_INDEX_P2(REGNO, STRICT) \
+ (REGNO_OK_FOR_BASE_P2 (REGNO, STRICT))
+
+#define REGNO_OK_FOR_BASE_P(REGNO) \
+ (REGNO_OK_FOR_BASE_P2 (REGNO, 1))
+
+#define REGNO_OK_FOR_INDEX_P(REGNO) \
+ (REGNO_OK_FOR_INDEX_P2 (REGNO, 1))
+
+#define REG_OK_FOR_BASE_P2(X, STRICT) \
+ (STRICT \
+ ? REGNO_OK_FOR_BASE_P2 (REGNO (X), 1) \
+ : REGNO_OK_FOR_BASE_P2 (REGNO (X), 1) || REGNO(X) >= FIRST_PSEUDO_REGISTER)
+
+#define REG_OK_FOR_INDEX_P2(X, STRICT) \
+ (STRICT \
+ ? REGNO_OK_FOR_INDEX_P2 (REGNO (X), 1) \
+ : REGNO_OK_FOR_INDEX_P2 (REGNO (X), 1) || REGNO(X) >= FIRST_PSEUDO_REGISTER)
+
+#define CLASS_MAX_NREGS(CLASS, MODE) \
+ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \
+ / UNITS_PER_WORD)
+
+
+#define SMALL_INT(X) ((unsigned HOST_WIDE_INT) ((X) + 0x8000) < 0x10000)
+#define SMALL_INT_UNSIGNED(X) ((unsigned HOST_WIDE_INT) (X) < 0x10000)
+#define UPPER16_INT(X) (((X) & 0xffff) == 0)
+#define SHIFT_INT(X) ((X) >= 0 && (X) <= 31)
+#define RDWRCTL_INT(X) ((X) >= 0 && (X) <= 31)
+#define CUSTOM_INSN_OPCODE(X) ((X) >= 0 && (X) <= 255)
+
+#define CONST_OK_FOR_LETTER_P(VALUE, C) \
+ ( \
+ (C) == 'I' ? SMALL_INT (VALUE) : \
+ (C) == 'J' ? SMALL_INT_UNSIGNED (VALUE) : \
+ (C) == 'K' ? UPPER16_INT (VALUE) : \
+ (C) == 'L' ? SHIFT_INT (VALUE) : \
+ (C) == 'M' ? (VALUE) == 0 : \
+ (C) == 'N' ? CUSTOM_INSN_OPCODE (VALUE) : \
+ (C) == 'O' ? RDWRCTL_INT (VALUE) : \
+ 0)
+
+#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) 0
+
+#define PREFERRED_RELOAD_CLASS(X, CLASS) \
+ ((CLASS) == NO_REGS ? GENERAL_REGS : (CLASS))
+
+#define CONSTRAINT_LEN(C, STR) \
+ ((C) == 'D' ? 3 : DEFAULT_CONSTRAINT_LEN ((C), (STR)))
+
+/* 'S' matches immediates which are in small data
+ and therefore can be added to gp to create a
+ 32-bit value. */
+#define EXTRA_CONSTRAINT(VALUE, C) \
+ ((C) == 'S' \
+ && (GET_CODE (VALUE) == SYMBOL_REF) \
+ && SYMBOL_REF_IN_NIOS2_SMALL_DATA_P (VALUE))
+
+
+
+
+/* Say that the epilogue uses the return address register. Note that
+ in the case of sibcalls, the values "used by the epilogue" are
+ considered live at the start of the called function. */
+#define EPILOGUE_USES(REGNO) ((REGNO) == RA_REGNO)
+
+
+#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 MUST_PASS_IN_STACK(MODE, TYPE) \
+ nios2_must_pass_in_stack ((MODE), (TYPE))
+
+#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_PADDING(MODE, TYPE) \
+ (nios2_function_arg_padding_upward ((MODE), (TYPE)) ? upward : downward)
+
+#define PAD_VARARGS_DOWN \
+ (FUNCTION_ARG_PADDING (TYPE_MODE (type), type) == downward)
+
+#define BLOCK_REG_PADDING(MODE, TYPE, FIRST) \
+ (nios2_block_reg_padding_upward ((MODE), (TYPE), (FIRST)) ? upward : downward)
+
+#define FUNCTION_ARG_REGNO_P(REGNO) \
+ ((REGNO) >= FIRST_ARG_REGNO && (REGNO) <= LAST_ARG_REGNO)
+
+#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 NO_PROFILE_COUNTERS 1
+#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", \
+ "et", \
+ "bt", \
+ "gp", \
+ "sp", \
+ "fp", \
+ "ta", \
+ "ba", \
+ "ra", \
+ "status", \
+ "estatus", \
+ "bstatus", \
+ "ipri", \
+ "ecause", \
+ "pc", \
+ "rap", \
+ "fake_fp", \
+ "fake_ap", \
+}
+
+#define ADDITIONAL_REGISTER_NAMES \
+{ \
+ {"r0", 0}, \
+ {"r1", 1}, \
+ {"r24", 24}, \
+ {"r25", 25}, \
+ {"r26", 26}, \
+ {"r27", 27}, \
+ {"r28", 28}, \
+ {"r29", 29}, \
+ {"r30", 30}, \
+ {"r31", 31} \
+}
+
+
+#define ASM_OUTPUT_OPCODE(STREAM, PTR)\
+ (PTR) = asm_output_opcode (STREAM, PTR)
+
+#define PRINT_OPERAND(STREAM, X, CODE) \
+ nios2_print_operand (STREAM, X, CODE)
+
+#define PRINT_OPERAND_ADDRESS(STREAM, X) \
+ nios2_print_operand_address (STREAM, X)
+
+#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
+do { fputs (integer_asm_op (POINTER_SIZE / BITS_PER_UNIT, TRUE), FILE); \
+ fprintf (FILE, ".L%u\n", (unsigned) (VALUE)); \
+ } while (0)
+
+
+/* ------------ *
+ * 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 STORE_FLAG_VALUE 1
+#define Pmode SImode
+#define FUNCTION_MODE QImode
+
+#define REGISTER_TARGET_PRAGMAS() nios2_register_target_pragmas ();
+
+#define CASE_VECTOR_MODE Pmode
+
+#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
+
+#define LOAD_EXTEND_OP(MODE) (ZERO_EXTEND)
+
+#define WORD_REGISTER_OPERATIONS
diff --git a/gcc/config/nios2/nios2.md b/gcc/config/nios2/nios2.md
new file mode 100644
index 0000000..6183247
--- /dev/null
+++ b/gcc/config/nios2/nios2.md
@@ -0,0 +1,2867 @@
+;; Machine Description for Altera NIOS 2G NIOS2 version.
+;; Copyright (C) 2005 Altera
+;; Contributed by Jonah Graham (jgraham@altera.com) and Will Reece (wreece@altera.com).
+;;
+;; This file is part of GNU CC.
+;;
+;; GNU CC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+;;
+;; GNU CC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GNU CC; see the file COPYING. If not, write to
+;; the Free Software Foundation, 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA. */
+
+
+
+
+;*****************************************************************************
+;*
+;* constraint strings
+;*
+;*****************************************************************************
+;
+; We use the following constraint letters for constants
+;
+; I: -32768 to -32767
+; J: 0 to 65535
+; K: $nnnn0000 for some nnnn
+; L: 0 to 31 (for shift counts)
+; M: 0
+; N: 0 to 255 (for custom instruction numbers)
+; O: 0 to 31 (for control register numbers)
+;
+; We use the following built-in register classes:
+;
+; r: general purpose register (r0..r31)
+; m: memory operand
+;
+; Plus, we define the following constraint strings:
+;
+; S: symbol that is in the "small data" area
+; Dnn: Dnn_REG (just rnn)
+;
+
+
+
+;*****************************************************************************
+;*
+;* constants
+;*
+;*****************************************************************************
+(define_constants [
+ (ET_REGNO 24)
+ (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)
+ (UNSPEC_TRAP 12)
+ (UNSPEC_STACK_OVERFLOW_DETECT_AND_TRAP 13)
+ (UNSPEC_FCOSS 14)
+ (UNSPEC_FCOSD 15)
+ (UNSPEC_FSINS 16)
+ (UNSPEC_FSIND 17)
+ (UNSPEC_FTANS 18)
+ (UNSPEC_FTAND 19)
+ (UNSPEC_FATANS 20)
+ (UNSPEC_FATAND 21)
+ (UNSPEC_FEXPS 22)
+ (UNSPEC_FEXPD 23)
+ (UNSPEC_FLOGS 24)
+ (UNSPEC_FLOGD 25)
+ (UNSPEC_FWRX 26)
+ (UNSPEC_FWRY 27)
+ (UNSPEC_FRDXLO 28)
+ (UNSPEC_FRDXHI 29)
+ (UNSPEC_FRDY 30)
+ ;; Note that values 100..151 are used by custom instructions, see below.
+])
+
+
+
+;*****************************************************************************
+;*
+;* instruction scheduler
+;*
+;*****************************************************************************
+
+; No schedule info is currently available, using an assumption that no
+; instruction can use the results of the previous instruction without
+; incuring a stall.
+
+; length of an instruction (in bytes)
+(define_attr "length" "" (const_int 4))
+(define_attr "type" "unknown,complex,control,alu,cond_alu,st,ld,shift,mul,div,custom" (const_string "complex"))
+
+(define_asm_attributes
+ [(set_attr "length" "4")
+ (set_attr "type" "complex")])
+
+(define_automaton "nios2")
+(automata_option "v")
+;(automata_option "no-minimization")
+(automata_option "ndfa")
+
+; The nios2 pipeline is fairly straightforward for the fast model.
+; Every alu operation is pipelined so that an instruction can
+; be issued every cycle. However, there are still potential
+; stalls which this description tries to deal with.
+
+(define_cpu_unit "cpu" "nios2")
+
+(define_insn_reservation "complex" 1
+ (eq_attr "type" "complex")
+ "cpu")
+
+(define_insn_reservation "control" 1
+ (eq_attr "type" "control")
+ "cpu")
+
+(define_insn_reservation "alu" 1
+ (eq_attr "type" "alu")
+ "cpu")
+
+(define_insn_reservation "cond_alu" 1
+ (eq_attr "type" "cond_alu")
+ "cpu")
+
+(define_insn_reservation "st" 1
+ (eq_attr "type" "st")
+ "cpu")
+
+(define_insn_reservation "custom" 1
+ (eq_attr "type" "custom")
+ "cpu")
+
+; shifts, muls and lds have three cycle latency
+(define_insn_reservation "ld" 3
+ (eq_attr "type" "ld")
+ "cpu")
+
+(define_insn_reservation "shift" 3
+ (eq_attr "type" "shift")
+ "cpu")
+
+(define_insn_reservation "mul" 3
+ (eq_attr "type" "mul")
+ "cpu")
+
+(define_insn_reservation "div" 1
+ (eq_attr "type" "div")
+ "cpu")
+
+
+;*****************************************************************************
+;*
+;* MOV Instructions
+;*
+;*****************************************************************************
+
+(define_expand "movqi"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "")
+ (match_operand:QI 1 "general_operand" ""))]
+ ""
+{
+ if (nios2_emit_move_sequence (operands, QImode))
+ DONE;
+})
+
+(define_insn "movqi_internal"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=m, r,r, r")
+ (match_operand:QI 1 "general_operand" "rM,m,rM,I"))]
+ "(register_operand (operands[0], QImode)
+ || reg_or_0_operand (operands[1], QImode))"
+ "@
+ stb%o0\\t%z1, %0
+ ldbu%o1\\t%0, %1
+ mov\\t%0, %z1
+ movi\\t%0, %1"
+ [(set_attr "type" "st,ld,alu,alu")])
+
+(define_insn "ldbio"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDBIO))
+ (use (match_operand:SI 1 "memory_operand" "m"))]
+ ""
+ "ldbio\\t%0, %1"
+ [(set_attr "type" "ld")])
+
+(define_insn "ldbuio"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDBUIO))
+ (use (match_operand:SI 1 "memory_operand" "m"))]
+ ""
+ "ldbuio\\t%0, %1"
+ [(set_attr "type" "ld")])
+
+(define_insn "stbio"
+ [(set (match_operand:SI 0 "memory_operand" "=m")
+ (match_operand:SI 1 "reg_or_0_operand" "rM"))
+ (unspec_volatile:SI [(const_int 0)] UNSPEC_STBIO)]
+ ""
+ "stbio\\t%z1, %0"
+ [(set_attr "type" "st")])
+
+
+(define_expand "movhi"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "")
+ (match_operand:HI 1 "general_operand" ""))]
+ ""
+{
+ if (nios2_emit_move_sequence (operands, HImode))
+ DONE;
+})
+
+(define_insn "movhi_internal"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=m, r,r, r,r")
+ (match_operand:HI 1 "general_operand" "rM,m,rM,I,J"))]
+ "(register_operand (operands[0], HImode)
+ || reg_or_0_operand (operands[1], HImode))"
+ "@
+ sth%o0\\t%z1, %0
+ ldhu%o1\\t%0, %1
+ mov\\t%0, %z1
+ movi\\t%0, %1
+ movui\\t%0, %1"
+ [(set_attr "type" "st,ld,alu,alu,alu")])
+
+(define_insn "ldhio"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDHIO))
+ (use (match_operand:SI 1 "memory_operand" "m"))]
+ ""
+ "ldhio\\t%0, %1"
+ [(set_attr "type" "ld")])
+
+(define_insn "ldhuio"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDHUIO))
+ (use (match_operand:SI 1 "memory_operand" "m"))]
+ ""
+ "ldhuio\\t%0, %1"
+ [(set_attr "type" "ld")])
+
+(define_insn "sthio"
+ [(set (match_operand:SI 0 "memory_operand" "=m")
+ (match_operand:SI 1 "reg_or_0_operand" "rM"))
+ (unspec_volatile:SI [(const_int 0)] UNSPEC_STHIO)]
+ ""
+ "sthio\\t%z1, %0"
+ [(set_attr "type" "st")])
+
+(define_expand "movsi"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "")
+ (match_operand:SI 1 "general_operand" ""))]
+ ""
+{
+ if (nios2_emit_move_sequence (operands, SImode))
+ DONE;
+})
+
+(define_insn "movsi_internal"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=m, r,r, r,r,r,r")
+ (match_operand:SI 1 "general_operand" "rM,m,rM,I,J,S,i"))]
+ "(register_operand (operands[0], SImode)
+ || reg_or_0_operand (operands[1], SImode))"
+ "@
+ stw%o0\\t%z1, %0
+ ldw%o1\\t%0, %1
+ mov\\t%0, %z1
+ movi\\t%0, %1
+ movui\\t%0, %1
+ addi\\t%0, gp, %%gprel(%1)
+ movhi\\t%0, %H1\;addi\\t%0, %0, %L1"
+ [(set_attr "type" "st,ld,alu,alu,alu,alu,alu")])
+
+(define_insn "ldwio"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDWIO))
+ (use (match_operand:SI 1 "memory_operand" "m"))]
+ ""
+ "ldwio\\t%0, %1"
+ [(set_attr "type" "ld")])
+
+(define_insn "stwio"
+ [(set (match_operand:SI 0 "memory_operand" "=m")
+ (match_operand:SI 1 "reg_or_0_operand" "rM"))
+ (unspec_volatile:SI [(const_int 0)] UNSPEC_STWIO)]
+ ""
+ "stwio\\t%z1, %0"
+ [(set_attr "type" "st")])
+
+
+
+;*****************************************************************************
+;*
+;* zero extension
+;*
+;*****************************************************************************
+
+
+(define_insn "zero_extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))]
+ ""
+ "@
+ andi\\t%0, %1, 0xffff
+ ldhu%o1\\t%0, %1"
+ [(set_attr "type" "alu,ld")])
+
+(define_insn "zero_extendqihi2"
+ [(set (match_operand:HI 0 "register_operand" "=r,r")
+ (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
+ ""
+ "@
+ andi\\t%0, %1, 0xff
+ ldbu%o1\\t%0, %1"
+ [(set_attr "type" "alu,ld")])
+
+(define_insn "zero_extendqisi2"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
+ ""
+ "@
+ andi\\t%0, %1, 0xff
+ ldbu%o1\\t%0, %1"
+ [(set_attr "type" "alu,ld")])
+
+
+
+;*****************************************************************************
+;*
+;* sign extension
+;*
+;*****************************************************************************
+(define_expand "extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))]
+ ""
+{
+})
+
+(define_insn "*extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extend:SI (match_operand:HI 1 "register_operand" "r")))]
+ ""
+ "#")
+
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (sign_extend:SI (match_operand:HI 1 "register_operand" "")))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (and:SI (match_dup 1) (const_int 65535)))
+ (set (match_dup 0)
+ (xor:SI (match_dup 0) (const_int 32768)))
+ (set (match_dup 0)
+ (plus:SI (match_dup 0) (const_int -32768)))]
+ "operands[1] = gen_lowpart (SImode, operands[1]);")
+
+(define_insn "extendhisi2_internal"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))]
+ ""
+ "ldh%o1\\t%0, %1"
+ [(set_attr "type" "ld")])
+
+
+(define_expand "extendqihi2"
+ [(set (match_operand:HI 0 "register_operand" "")
+ (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))]
+ ""
+{
+})
+
+(define_insn "*extendqihi2"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (sign_extend:HI (match_operand:QI 1 "register_operand" "r")))]
+ ""
+ "#")
+
+(define_split
+ [(set (match_operand:HI 0 "register_operand" "")
+ (sign_extend:HI (match_operand:QI 1 "register_operand" "")))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (and:SI (match_dup 1) (const_int 255)))
+ (set (match_dup 0)
+ (xor:SI (match_dup 0) (const_int 128)))
+ (set (match_dup 0)
+ (plus:SI (match_dup 0) (const_int -128)))]
+ "operands[0] = gen_lowpart (SImode, operands[0]);
+ operands[1] = gen_lowpart (SImode, operands[1]);")
+
+
+
+(define_insn "extendqihi2_internal"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))]
+ ""
+ "ldb%o1\\t%0, %1"
+ [(set_attr "type" "ld")])
+
+
+(define_expand "extendqisi2"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))]
+ ""
+{
+})
+
+(define_insn "*extendqisi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extend:SI (match_operand:QI 1 "register_operand" "r")))]
+ ""
+ "#")
+
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (sign_extend:SI (match_operand:QI 1 "register_operand" "")))]
+ "reload_completed"
+ [(set (match_dup 0)
+ (and:SI (match_dup 1) (const_int 255)))
+ (set (match_dup 0)
+ (xor:SI (match_dup 0) (const_int 128)))
+ (set (match_dup 0)
+ (plus:SI (match_dup 0) (const_int -128)))]
+ "operands[1] = gen_lowpart (SImode, operands[1]);")
+
+(define_insn "extendqisi2_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))]
+ ""
+ "ldb%o1\\t%0, %1"
+ [(set_attr "type" "ld")])
+
+
+
+
+;*****************************************************************************
+;*
+;* Arithmetic Operations
+;*
+;*****************************************************************************
+
+(define_insn "addsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (plus:SI (match_operand:SI 1 "register_operand" "%r,r")
+ (match_operand:SI 2 "arith_operand" "r,I")))]
+ ""
+ "add%i2\\t%0, %1, %z2"
+ [(set_attr "type" "alu")])
+
+(define_insn "addsf3"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (plus:SF (match_operand:SF 1 "register_operand" "%r")
+ (match_operand:SF 2 "register_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_addsf3].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_addsf3].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "adddf3"
+ [(set (match_operand:DF 0 "register_operand" "=r")
+ (plus:DF (match_operand:DF 1 "register_operand" "%r")
+ (match_operand:DF 2 "register_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_adddf3].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_adddf3].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "subsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
+ (match_operand:SI 2 "register_operand" "r")))]
+ ""
+ "sub\\t%0, %z1, %2"
+ [(set_attr "type" "alu")])
+
+(define_insn "subsf3"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (minus:SF (match_operand:SF 1 "register_operand" "r")
+ (match_operand:SF 2 "register_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_subsf3].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_subsf3].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "subdf3"
+ [(set (match_operand:DF 0 "register_operand" "=r")
+ (minus:DF (match_operand:DF 1 "register_operand" "r")
+ (match_operand:DF 2 "register_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_subdf3].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_subdf3].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "mulsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (mult:SI (match_operand:SI 1 "register_operand" "r,r")
+ (match_operand:SI 2 "arith_operand" "r,I")))]
+ "TARGET_HAS_MUL"
+ "mul%i2\\t%0, %1, %z2"
+ [(set_attr "type" "mul")])
+
+(define_insn "mulsf3"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (mult:SF (match_operand:SF 1 "register_operand" "%r")
+ (match_operand:SF 2 "register_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_mulsf3].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_mulsf3].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "muldf3"
+ [(set (match_operand:DF 0 "register_operand" "=r")
+ (mult:DF (match_operand:DF 1 "register_operand" "%r")
+ (match_operand:DF 2 "register_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_muldf3].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_muldf3].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_expand "divsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (div:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "register_operand" "r")))]
+ ""
+{
+ if (!TARGET_HAS_DIV)
+ {
+ if (!TARGET_FAST_SW_DIV)
+ FAIL;
+ else
+ {
+ if (nios2_emit_expensive_div (operands, SImode))
+ DONE;
+ }
+ }
+})
+
+(define_insn "divsi3_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (div:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "register_operand" "r")))]
+ "TARGET_HAS_DIV"
+ "div\\t%0, %1, %2"
+ [(set_attr "type" "div")])
+
+(define_insn "divsf3"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (div:SF (match_operand:SF 1 "register_operand" "r")
+ (match_operand:SF 2 "register_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_divsf3].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_divsf3].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "divdf3"
+ [(set (match_operand:DF 0 "register_operand" "=r")
+ (div:DF (match_operand:DF 1 "register_operand" "r")
+ (match_operand:DF 2 "register_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_divdf3].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_divdf3].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "udivsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (udiv:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "register_operand" "r")))]
+ "TARGET_HAS_DIV"
+ "divu\\t%0, %1, %2"
+ [(set_attr "type" "div")])
+
+(define_insn "smulsi3_highpart"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (truncate:SI
+ (lshiftrt:DI
+ (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r"))
+ (sign_extend:DI (match_operand:SI 2 "register_operand" "r")))
+ (const_int 32))))]
+ "TARGET_HAS_MULX"
+ "mulxss\\t%0, %1, %2"
+ [(set_attr "type" "mul")])
+
+(define_insn "umulsi3_highpart"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (truncate:SI
+ (lshiftrt:DI
+ (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
+ (zero_extend:DI (match_operand:SI 2 "register_operand" "r")))
+ (const_int 32))))]
+ "TARGET_HAS_MULX"
+ "mulxuu\\t%0, %1, %2"
+ [(set_attr "type" "mul")])
+
+
+(define_expand "mulsidi3_little_endian"
+ [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 0)
+ (mult:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "register_operand" "")))
+ (set (subreg:SI (match_dup 0) 4)
+ (truncate:SI (lshiftrt:DI (mult:DI (sign_extend:DI (match_dup 1))
+ (sign_extend:DI (match_dup 2)))
+ (const_int 32))))]
+ "TARGET_HAS_MULX && !WORDS_BIG_ENDIAN"
+ "")
+
+(define_expand "mulsidi3_big_endian"
+ [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 4)
+ (mult:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "register_operand" "")))
+ (set (subreg:SI (match_dup 0) 0)
+ (truncate:SI (lshiftrt:DI (mult:DI (sign_extend:DI (match_dup 1))
+ (sign_extend:DI (match_dup 2)))
+ (const_int 32))))]
+ "TARGET_HAS_MULX && WORDS_BIG_ENDIAN"
+ "")
+
+(define_expand "mulsidi3"
+ [(match_operand:DI 0 "register_operand" "")
+ (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "register_operand" "")]
+ "TARGET_HAS_MULX"
+ {
+ if (WORDS_BIG_ENDIAN)
+ {
+ emit_insn (gen_mulsidi3_big_endian (operands[0],
+ operands[1],
+ operands[2]));
+ }
+ else
+ {
+ emit_insn (gen_mulsidi3_little_endian (operands[0],
+ operands[1],
+ operands[2]));
+ }
+ DONE;
+ })
+
+(define_expand "umulsidi3_little_endian"
+ [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 0)
+ (mult:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "register_operand" "")))
+ (set (subreg:SI (match_dup 0) 4)
+ (truncate:SI (lshiftrt:DI (mult:DI (zero_extend:DI (match_dup 1))
+ (zero_extend:DI (match_dup 2)))
+ (const_int 32))))]
+ "TARGET_HAS_MULX && !WORDS_BIG_ENDIAN"
+ "")
+
+(define_expand "umulsidi3_big_endian"
+ [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 4)
+ (mult:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "register_operand" "")))
+ (set (subreg:SI (match_dup 0) 0)
+ (truncate:SI (lshiftrt:DI (mult:DI (zero_extend:DI (match_dup 1))
+ (zero_extend:DI (match_dup 2)))
+ (const_int 32))))]
+ "TARGET_HAS_MULX && WORDS_BIG_ENDIAN"
+ "")
+
+(define_expand "umulsidi3"
+ [(match_operand:DI 0 "register_operand" "")
+ (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "register_operand" "")]
+ "TARGET_HAS_MULX"
+ {
+ if (WORDS_BIG_ENDIAN)
+ {
+ emit_insn (gen_umulsidi3_big_endian (operands[0],
+ operands[1],
+ operands[2]));
+ }
+ else
+ {
+ emit_insn (gen_umulsidi3_little_endian (operands[0],
+ operands[1],
+ operands[2]));
+ }
+ DONE;
+ })
+
+
+;*****************************************************************************
+;*
+;* Negate and ones complement
+;*
+;*****************************************************************************
+
+(define_insn "negsi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (neg:SI (match_operand:SI 1 "register_operand" "r")))]
+ ""
+{
+ operands[2] = const0_rtx;
+ return "sub\\t%0, %z2, %1";
+}
+ [(set_attr "type" "alu")])
+
+(define_insn "negsf2"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (neg:SF (match_operand:SF 1 "register_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_negsf2].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_negsf2].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "negdf2"
+ [(set (match_operand:DF 0 "register_operand" "=r")
+ (neg:DF (match_operand:DF 1 "register_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_negdf2].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_negdf2].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "one_cmplsi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (not:SI (match_operand:SI 1 "register_operand" "r")))]
+ ""
+{
+ operands[2] = const0_rtx;
+ return "nor\\t%0, %z2, %1";
+}
+ [(set_attr "type" "alu")])
+
+
+;*****************************************************************************
+;*
+;* Miscellaneous floating point
+;*
+;*****************************************************************************
+(define_insn "nios2_fwrx"
+ [(unspec_volatile [(match_operand:DF 0 "register_operand" "r")] UNSPEC_FWRX)]
+ "nios2_fpu_insns[nios2_fpu_nios2_fwrx].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_nios2_fwrx].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "nios2_fwry"
+ [(unspec_volatile [(match_operand:SF 0 "register_operand" "r")] UNSPEC_FWRY)]
+ "nios2_fpu_insns[nios2_fpu_nios2_fwry].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_nios2_fwry].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "nios2_frdxlo"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (unspec_volatile:SF [(const_int 0)] UNSPEC_FRDXLO))]
+ "nios2_fpu_insns[nios2_fpu_nios2_frdxlo].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_nios2_frdxlo].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "nios2_frdxhi"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (unspec_volatile:SF [(const_int 0)] UNSPEC_FRDXHI))]
+ "nios2_fpu_insns[nios2_fpu_nios2_frdxhi].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_nios2_frdxhi].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "nios2_frdy"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (unspec_volatile:SF [(const_int 0)] UNSPEC_FRDY))]
+ "nios2_fpu_insns[nios2_fpu_nios2_frdy].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_nios2_frdy].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "minsf3"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (if_then_else:SF (lt:SF (match_operand:SF 1 "register_operand" "%r")
+ (match_operand:SF 2 "register_operand" "r"))
+ (match_dup 1)
+ (match_dup 2)))]
+ "nios2_fpu_insns[nios2_fpu_minsf3].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_minsf3].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "mindf3"
+ [(set (match_operand:DF 0 "register_operand" "=r")
+ (if_then_else:DF (lt:DF (match_operand:DF 1 "register_operand" "%r")
+ (match_operand:DF 2 "register_operand" "r"))
+ (match_dup 1)
+ (match_dup 2)))]
+ "nios2_fpu_insns[nios2_fpu_mindf3].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_mindf3].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "maxsf3"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (if_then_else:SF (lt:SF (match_operand:SF 1 "register_operand" "%r")
+ (match_operand:SF 2 "register_operand" "r"))
+ (match_dup 2)
+ (match_dup 1)))]
+ "nios2_fpu_insns[nios2_fpu_maxsf3].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_maxsf3].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "maxdf3"
+ [(set (match_operand:DF 0 "register_operand" "=r")
+ (if_then_else:DF (lt:DF (match_operand:DF 1 "register_operand" "%r")
+ (match_operand:DF 2 "register_operand" "r"))
+ (match_dup 2)
+ (match_dup 1)))]
+ "nios2_fpu_insns[nios2_fpu_maxdf3].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_maxdf3].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "abssf2"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (abs:SF (match_operand:SF 1 "register_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_abssf2].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_abssf2].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "absdf2"
+ [(set (match_operand:DF 0 "register_operand" "=r")
+ (abs:DF (match_operand:DF 1 "register_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_absdf2].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_absdf2].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "sqrtsf2"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (sqrt:SF (match_operand:SF 1 "register_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_sqrtsf2].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_sqrtsf2].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "sqrtdf2"
+ [(set (match_operand:DF 0 "register_operand" "=r")
+ (sqrt:DF (match_operand:DF 1 "register_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_sqrtdf2].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_sqrtdf2].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "cossf2"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (unspec:SF [(match_operand:SF 1 "register_operand" "r")] UNSPEC_FCOSS))]
+ "nios2_fpu_insns[nios2_fpu_cossf2].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_cossf2].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "cosdf2"
+ [(set (match_operand:DF 0 "register_operand" "=r")
+ (unspec:DF [(match_operand:DF 1 "register_operand" "r")] UNSPEC_FCOSD))]
+ "nios2_fpu_insns[nios2_fpu_cosdf2].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_cosdf2].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "sinsf2"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (unspec:SF [(match_operand:SF 1 "register_operand" "r")] UNSPEC_FSINS))]
+ "nios2_fpu_insns[nios2_fpu_sinsf2].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_sinsf2].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "sindf2"
+ [(set (match_operand:DF 0 "register_operand" "=r")
+ (unspec:DF [(match_operand:DF 1 "register_operand" "r")] UNSPEC_FSIND))]
+ "nios2_fpu_insns[nios2_fpu_sindf2].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_sindf2].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "tansf2"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (unspec:SF [(match_operand:SF 1 "register_operand" "r")] UNSPEC_FTANS))]
+ "nios2_fpu_insns[nios2_fpu_tansf2].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_tansf2].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "tandf2"
+ [(set (match_operand:DF 0 "register_operand" "=r")
+ (unspec:DF [(match_operand:DF 1 "register_operand" "r")] UNSPEC_FTAND))]
+ "nios2_fpu_insns[nios2_fpu_tandf2].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_tandf2].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "atansf2"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (unspec:SF [(match_operand:SF 1 "register_operand" "r")] UNSPEC_FATANS))]
+ "nios2_fpu_insns[nios2_fpu_atansf2].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_atansf2].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "atandf2"
+ [(set (match_operand:DF 0 "register_operand" "=r")
+ (unspec:DF [(match_operand:DF 1 "register_operand" "r")] UNSPEC_FATAND))]
+ "nios2_fpu_insns[nios2_fpu_atandf2].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_atandf2].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "expsf2"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (unspec:SF [(match_operand:SF 1 "register_operand" "r")] UNSPEC_FEXPS))]
+ "nios2_fpu_insns[nios2_fpu_expsf2].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_expsf2].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "expdf2"
+ [(set (match_operand:DF 0 "register_operand" "=r")
+ (unspec:DF [(match_operand:DF 1 "register_operand" "r")] UNSPEC_FEXPD))]
+ "nios2_fpu_insns[nios2_fpu_expdf2].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_expdf2].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "logsf2"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (unspec:SF [(match_operand:SF 1 "register_operand" "r")] UNSPEC_FLOGS))]
+ "nios2_fpu_insns[nios2_fpu_logsf2].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_logsf2].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "logdf2"
+ [(set (match_operand:DF 0 "register_operand" "=r")
+ (unspec:DF [(match_operand:DF 1 "register_operand" "r")] UNSPEC_FLOGD))]
+ "nios2_fpu_insns[nios2_fpu_logdf2].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_logdf2].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+
+;*****************************************************************************
+;*
+;* Logical Operantions
+;*
+;*****************************************************************************
+
+(define_insn "andsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r, r,r")
+ (and:SI (match_operand:SI 1 "register_operand" "%r, r,r")
+ (match_operand:SI 2 "logical_operand" "rM,J,K")))]
+ ""
+ "@
+ and\\t%0, %1, %z2
+ and%i2\\t%0, %1, %2
+ andh%i2\\t%0, %1, %U2"
+ [(set_attr "type" "alu")])
+
+(define_insn "iorsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r, r,r")
+ (ior:SI (match_operand:SI 1 "register_operand" "%r, r,r")
+ (match_operand:SI 2 "logical_operand" "rM,J,K")))]
+ ""
+ "@
+ or\\t%0, %1, %z2
+ or%i2\\t%0, %1, %2
+ orh%i2\\t%0, %1, %U2"
+ [(set_attr "type" "alu")])
+
+(define_insn "*norsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (and:SI (not:SI (match_operand:SI 1 "register_operand" "%r"))
+ (not:SI (match_operand:SI 2 "reg_or_0_operand" "rM"))))]
+ ""
+ "nor\\t%0, %1, %z2"
+ [(set_attr "type" "alu")])
+
+(define_insn "xorsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r, r,r")
+ (xor:SI (match_operand:SI 1 "register_operand" "%r, r,r")
+ (match_operand:SI 2 "logical_operand" "rM,J,K")))]
+ ""
+ "@
+ xor\\t%0, %1, %z2
+ xor%i2\\t%0, %1, %2
+ xorh%i2\\t%0, %1, %U2"
+ [(set_attr "type" "alu")])
+
+
+
+;*****************************************************************************
+;*
+;* Shifts
+;*
+;*****************************************************************************
+
+(define_insn "ashlsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (ashift:SI (match_operand:SI 1 "register_operand" "r,r")
+ (match_operand:SI 2 "shift_operand" "r,L")))]
+ ""
+
+{
+ if( GET_CODE ( operands[2] ) == CONST_INT && INTVAL( operands[2] ) == 1 )
+ return "add\t%0,%1,%1";
+ return "sll%i2\t%0,%1,%z2";
+}
+ [(set_attr "type" "shift")])
+
+(define_insn "ashrsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (ashiftrt:SI (match_operand:SI 1 "register_operand" "r,r")
+ (match_operand:SI 2 "shift_operand" "r,L")))]
+ ""
+ "sra%i2\\t%0, %1, %z2"
+ [(set_attr "type" "shift")])
+
+(define_insn "lshrsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (lshiftrt:SI (match_operand:SI 1 "register_operand" "r,r")
+ (match_operand:SI 2 "shift_operand" "r,L")))]
+ ""
+ "srl%i2\\t%0, %1, %z2"
+ [(set_attr "type" "shift")])
+
+(define_insn "rotlsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (rotate:SI (match_operand:SI 1 "register_operand" "r,r")
+ (match_operand:SI 2 "shift_operand" "r,L")))]
+ ""
+ "rol%i2\\t%0, %1, %z2"
+ [(set_attr "type" "shift")])
+
+(define_insn "rotrsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (rotatert:SI (match_operand:SI 1 "register_operand" "r,r")
+ (match_operand:SI 2 "register_operand" "r,r")))]
+ ""
+ "ror\\t%0, %1, %2"
+ [(set_attr "type" "shift")])
+
+(define_insn "*shift_mul_constants"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ashift:SI (mult:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "const_int_operand" "I"))
+ (match_operand:SI 3 "const_int_operand" "I")))]
+ "TARGET_HAS_MUL && SMALL_INT (INTVAL (operands[2]) << INTVAL (operands[3]))"
+{
+ HOST_WIDE_INT mul = INTVAL (operands[2]) << INTVAL (operands[3]);
+ rtx ops[3];
+
+ ops[0] = operands[0];
+ ops[1] = operands[1];
+ ops[2] = GEN_INT (mul);
+
+ output_asm_insn ("muli\t%0, %1, %2", ops);
+ return "";
+}
+ [(set_attr "type" "mul")])
+
+
+
+
+;*****************************************************************************
+;*
+;* Converting between floating point and fixed point
+;*
+;*****************************************************************************
+(define_insn "floatsisf2"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (float:SF (match_operand:SI 1 "register_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_floatsisf2].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_floatsisf2].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "floatsidf2"
+ [(set (match_operand:DF 0 "register_operand" "=r")
+ (float:DF (match_operand:SI 1 "register_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_floatsidf2].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_floatsidf2].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "floatunssisf2"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (unsigned_float:SF (match_operand:SI 1 "register_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_floatunssisf2].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_floatunssisf2].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "floatunssidf2"
+ [(set (match_operand:DF 0 "register_operand" "=r")
+ (unsigned_float:DF (match_operand:SI 1 "register_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_floatunssidf2].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_floatunssidf2].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "fixsfsi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (fix:SI (match_operand:SF 1 "general_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_fixsfsi2].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_fixsfsi2].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "fixdfsi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (fix:SI (match_operand:DF 1 "general_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_fixdfsi2].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_fixdfsi2].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "fixunssfsi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unsigned_fix:SI (match_operand:SF 1 "general_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_fixunssfsi2].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_fixunssfsi2].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "fixunsdfsi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unsigned_fix:SI (match_operand:DF 1 "general_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_fixunsdfsi2].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_fixunsdfsi2].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "extendsfdf2"
+ [(set (match_operand:DF 0 "register_operand" "=r")
+ (float_extend:DF (match_operand:SF 1 "general_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_extendsfdf2].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_extendsfdf2].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+(define_insn "truncdfsf2"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (float_truncate:SF (match_operand:DF 1 "general_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_truncdfsf2].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_truncdfsf2].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+
+
+
+
+
+
+
+;*****************************************************************************
+;*
+;* Prologue, Epilogue and Return
+;*
+;*****************************************************************************
+
+(define_expand "prologue"
+ [(const_int 1)]
+ ""
+{
+ expand_prologue ();
+ DONE;
+})
+
+(define_expand "epilogue"
+ [(return)]
+ ""
+{
+ expand_epilogue (false);
+ DONE;
+})
+
+(define_expand "sibcall_epilogue"
+ [(return)]
+ ""
+{
+ expand_epilogue (true);
+ DONE;
+})
+
+(define_insn "return"
+ [(return)]
+ "reload_completed && nios2_can_use_return_insn ()"
+ "ret\\t"
+)
+
+(define_insn "return_from_epilogue"
+ [(use (match_operand 0 "pmode_register_operand" ""))
+ (return)]
+ "reload_completed"
+ "ret\\t"
+)
+
+;; Block any insns from being moved before this point, since the
+;; profiling call to mcount can use various registers that aren't
+;; saved or used to pass arguments.
+
+(define_insn "blockage"
+ [(unspec_volatile [(const_int 0)] UNSPEC_BLOCKAGE)]
+ ""
+ ""
+ [(set_attr "type" "unknown")
+ (set_attr "length" "0")])
+
+
+
+;*****************************************************************************
+;*
+;* 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" "D08"))
+ (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" "D08"))
+ (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;
+})
+
+(define_expand "cmpsf"
+ [(set (cc0)
+ (compare:CC (match_operand:SF 0 "register_operand" "")
+ (match_operand:SF 1 "register_operand" "")))]
+ "(nios2_fpu_insns[nios2_fpu_nios2_sltsf].N >= 0
+ || nios2_fpu_insns[nios2_fpu_nios2_sgtsf].N >= 0)
+ && (nios2_fpu_insns[nios2_fpu_nios2_sgesf].N >= 0
+ || nios2_fpu_insns[nios2_fpu_nios2_slesf].N >= 0)
+ && nios2_fpu_insns[nios2_fpu_nios2_seqsf].N >= 0
+ && nios2_fpu_insns[nios2_fpu_nios2_snesf].N >= 0"
+{
+ branch_cmp[0] = operands[0];
+ branch_cmp[1] = operands[1];
+ branch_type = CMP_SF;
+ DONE;
+})
+
+(define_expand "cmpdf"
+ [(set (cc0)
+ (compare:CC (match_operand:DF 0 "register_operand" "")
+ (match_operand:DF 1 "register_operand" "")))]
+ "(nios2_fpu_insns[nios2_fpu_nios2_sltdf].N >= 0
+ || nios2_fpu_insns[nios2_fpu_nios2_sgtdf].N >= 0)
+ && (nios2_fpu_insns[nios2_fpu_nios2_sgedf].N >= 0
+ || nios2_fpu_insns[nios2_fpu_nios2_sledf].N >= 0)
+ && nios2_fpu_insns[nios2_fpu_nios2_seqdf].N >= 0
+ && nios2_fpu_insns[nios2_fpu_nios2_snedf].N >= 0"
+{
+ branch_cmp[0] = operands[0];
+ branch_cmp[1] = operands[1];
+ branch_type = CMP_DF;
+ DONE;
+})
+
+
+;*****************************************************************************
+;*
+;* setting a register from a comparison
+;*
+;*****************************************************************************
+
+(define_expand "seq"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (eq:SI (match_dup 1)
+ (match_dup 2)))]
+ ""
+{
+ if (branch_type != CMP_SI && branch_type != CMP_SF && branch_type != CMP_DF)
+ FAIL;
+
+ /* set up operands from compare. */
+ operands[1] = branch_cmp[0];
+ operands[2] = branch_cmp[1];
+
+ gen_int_relational (EQ, operands[0], operands[1], operands[2], NULL_RTX);
+ DONE;
+})
+
+
+(define_insn "*seq"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (eq:SI (match_operand:SI 1 "reg_or_0_operand" "%rM")
+ (match_operand:SI 2 "arith_operand" "rI")))]
+ ""
+ "cmpeq%i2\\t%0, %z1, %z2"
+ [(set_attr "type" "alu")])
+
+
+(define_insn "nios2_seqsf"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (eq:SI (match_operand:SF 1 "register_operand" "%r")
+ (match_operand:SF 2 "register_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_nios2_seqsf].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_nios2_seqsf].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+
+(define_insn "nios2_seqdf"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (eq:SI (match_operand:DF 1 "register_operand" "%r")
+ (match_operand:DF 2 "register_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_nios2_seqdf].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_nios2_seqdf].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+
+(define_expand "sne"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ne:SI (match_dup 1)
+ (match_dup 2)))]
+ ""
+{
+ if (branch_type != CMP_SI && branch_type != CMP_SF && branch_type != CMP_DF)
+ FAIL;
+
+ /* set up operands from compare. */
+ operands[1] = branch_cmp[0];
+ operands[2] = branch_cmp[1];
+
+ gen_int_relational (NE, operands[0], operands[1], operands[2], NULL_RTX);
+ DONE;
+})
+
+
+(define_insn "*sne"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ne:SI (match_operand:SI 1 "reg_or_0_operand" "%rM")
+ (match_operand:SI 2 "arith_operand" "rI")))]
+ ""
+ "cmpne%i2\\t%0, %z1, %z2"
+ [(set_attr "type" "alu")])
+
+
+(define_insn "nios2_snesf"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ne:SI (match_operand:SF 1 "register_operand" "%r")
+ (match_operand:SF 2 "register_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_nios2_snesf].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_nios2_snesf].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+
+(define_insn "nios2_snedf"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ne:SI (match_operand:DF 1 "register_operand" "%r")
+ (match_operand:DF 2 "register_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_nios2_snedf].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_nios2_snedf].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+
+(define_expand "sgt"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (gt:SI (match_dup 1)
+ (match_dup 2)))]
+ ""
+{
+ if (branch_type != CMP_SI && branch_type != CMP_SF && branch_type != CMP_DF)
+ FAIL;
+
+ /* set up operands from compare. */
+ operands[1] = branch_cmp[0];
+ operands[2] = branch_cmp[1];
+
+ gen_int_relational (GT, operands[0], operands[1], operands[2], NULL_RTX);
+ DONE;
+})
+
+
+(define_insn "*sgt"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (gt:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
+ (match_operand:SI 2 "reg_or_0_operand" "rM")))]
+ ""
+ "cmplt\\t%0, %z2, %z1"
+ [(set_attr "type" "alu")])
+
+
+(define_insn "nios2_sgtsf"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (gt:SI (match_operand:SF 1 "register_operand" "r")
+ (match_operand:SF 2 "register_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_nios2_sgtsf].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_nios2_sgtsf].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+
+(define_insn "nios2_sgtdf"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (gt:SI (match_operand:DF 1 "register_operand" "r")
+ (match_operand:DF 2 "register_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_nios2_sgtdf].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_nios2_sgtdf].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+
+(define_expand "sge"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ge:SI (match_dup 1)
+ (match_dup 2)))]
+ ""
+{
+ if (branch_type != CMP_SI && branch_type != CMP_SF && branch_type != CMP_DF)
+ FAIL;
+
+ /* set up operands from compare. */
+ operands[1] = branch_cmp[0];
+ operands[2] = branch_cmp[1];
+
+ gen_int_relational (GE, operands[0], operands[1], operands[2], NULL_RTX);
+ DONE;
+})
+
+
+(define_insn "*sge"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ge:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
+ (match_operand:SI 2 "arith_operand" "rI")))]
+ ""
+ "cmpge%i2\\t%0, %z1, %z2"
+ [(set_attr "type" "alu")])
+
+
+(define_insn "nios2_sgesf"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ge:SI (match_operand:SF 1 "register_operand" "r")
+ (match_operand:SF 2 "register_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_nios2_sgesf].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_nios2_sgesf].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+
+(define_insn "nios2_sgedf"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ge:SI (match_operand:DF 1 "register_operand" "r")
+ (match_operand:DF 2 "register_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_nios2_sgedf].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_nios2_sgedf].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+
+(define_expand "sle"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (le:SI (match_dup 1)
+ (match_dup 2)))]
+ ""
+{
+ if (branch_type != CMP_SI && branch_type != CMP_SF && branch_type != CMP_DF)
+ FAIL;
+
+ /* set up operands from compare. */
+ operands[1] = branch_cmp[0];
+ operands[2] = branch_cmp[1];
+
+ gen_int_relational (LE, operands[0], operands[1], operands[2], NULL_RTX);
+ DONE;
+})
+
+
+(define_insn "*sle"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (le:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
+ (match_operand:SI 2 "reg_or_0_operand" "rM")))]
+ ""
+ "cmpge\\t%0, %z2, %z1"
+ [(set_attr "type" "alu")])
+
+
+(define_insn "nios2_slesf"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (le:SI (match_operand:SF 1 "register_operand" "r")
+ (match_operand:SF 2 "register_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_nios2_slesf].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_nios2_slesf].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+
+(define_insn "nios2_sledf"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (le:SI (match_operand:DF 1 "register_operand" "r")
+ (match_operand:DF 2 "register_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_nios2_sledf].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_nios2_sledf].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+
+(define_expand "slt"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (lt:SI (match_dup 1)
+ (match_dup 2)))]
+ ""
+{
+ if (branch_type != CMP_SI && branch_type != CMP_SF && branch_type != CMP_DF)
+ FAIL;
+
+ /* set up operands from compare. */
+ operands[1] = branch_cmp[0];
+ operands[2] = branch_cmp[1];
+
+ gen_int_relational (LT, operands[0], operands[1], operands[2], NULL_RTX);
+ DONE;
+})
+
+
+(define_insn "*slt"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (lt:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
+ (match_operand:SI 2 "arith_operand" "rI")))]
+ ""
+ "cmplt%i2\\t%0, %z1, %z2"
+ [(set_attr "type" "alu")])
+
+
+(define_insn "nios2_sltsf"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (lt:SI (match_operand:SF 1 "register_operand" "r")
+ (match_operand:SF 2 "register_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_nios2_sltsf].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_nios2_sltsf].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+
+(define_insn "nios2_sltdf"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (lt:SI (match_operand:DF 1 "register_operand" "r")
+ (match_operand:DF 2 "register_operand" "r")))]
+ "nios2_fpu_insns[nios2_fpu_nios2_sltdf].N >= 0"
+ {
+ return (*nios2_fpu_insns[nios2_fpu_nios2_sltdf].output) (insn);
+ }
+ [(set_attr "type" "custom")])
+
+
+(define_expand "sgtu"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (gtu:SI (match_dup 1)
+ (match_dup 2)))]
+ ""
+{
+ if (branch_type != CMP_SI)
+ FAIL;
+
+ /* set up operands from compare. */
+ operands[1] = branch_cmp[0];
+ operands[2] = branch_cmp[1];
+
+ gen_int_relational (GTU, operands[0], operands[1], operands[2], NULL_RTX);
+ DONE;
+})
+
+
+(define_insn "*sgtu"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (gtu:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
+ (match_operand:SI 2 "reg_or_0_operand" "rM")))]
+ ""
+ "cmpltu\\t%0, %z2, %z1"
+ [(set_attr "type" "alu")])
+
+
+(define_expand "sgeu"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (geu:SI (match_dup 1)
+ (match_dup 2)))]
+ ""
+{
+ if (branch_type != CMP_SI)
+ FAIL;
+
+ /* set up operands from compare. */
+ operands[1] = branch_cmp[0];
+ operands[2] = branch_cmp[1];
+
+ gen_int_relational (GEU, operands[0], operands[1], operands[2], NULL_RTX);
+ DONE;
+})
+
+
+(define_insn "*sgeu"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (geu:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
+ (match_operand:SI 2 "uns_arith_operand" "rJ")))]
+ ""
+ "cmpgeu%i2\\t%0, %z1, %z2"
+ [(set_attr "type" "alu")])
+
+(define_expand "sleu"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (leu:SI (match_dup 1)
+ (match_dup 2)))]
+ ""
+{
+ if (branch_type != CMP_SI)
+ FAIL;
+
+ /* set up operands from compare. */
+ operands[1] = branch_cmp[0];
+ operands[2] = branch_cmp[1];
+
+ gen_int_relational (LEU, operands[0], operands[1], operands[2], NULL_RTX);
+ DONE;
+})
+
+
+(define_insn "*sleu"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (leu:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
+ (match_operand:SI 2 "reg_or_0_operand" "rM")))]
+ ""
+ "cmpgeu\\t%0, %z2, %z1"
+ [(set_attr "type" "alu")])
+
+
+(define_expand "sltu"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ltu:SI (match_dup 1)
+ (match_dup 2)))]
+ ""
+{
+ if (branch_type != CMP_SI)
+ FAIL;
+
+ /* set up operands from compare. */
+ operands[1] = branch_cmp[0];
+ operands[2] = branch_cmp[1];
+
+ gen_int_relational (LTU, operands[0], operands[1], operands[2], NULL_RTX);
+ DONE;
+})
+
+
+(define_insn "*sltu"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ltu:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
+ (match_operand:SI 2 "uns_arith_operand" "rJ")))]
+ ""
+ "cmpltu%i2\\t%0, %z1, %z2"
+ [(set_attr "type" "alu")])
+
+
+
+
+;*****************************************************************************
+;*
+;* branches
+;*
+;*****************************************************************************
+
+(define_insn "*cbranch"
+ [(set (pc)
+ (if_then_else
+ (match_operator:SI 0 "comparison_operator"
+ [(match_operand:SI 2 "reg_or_0_operand" "rM")
+ (match_operand:SI 3 "reg_or_0_operand" "rM")])
+ (label_ref (match_operand 1 "" ""))
+ (pc)))]
+ ""
+ "b%0\\t%z2, %z3, %l1"
+ [(set_attr "type" "control")])
+
+
+(define_insn "nios2_cbranch_sf"
+ [(set (pc)
+ (if_then_else
+ (match_operator:SI 0 "comparison_operator"
+ [(match_operand:SF 2 "register_operand" "r")
+ (match_operand:SF 3 "register_operand" "r")])
+ (label_ref (match_operand 1 "" ""))
+ (pc)))]
+ ""
+ {
+ return nios2_output_fpu_insn_cmps (insn, GET_CODE (operands[0]));
+ }
+ [(set_attr "type" "custom")])
+
+
+(define_insn "nios2_cbranch_df"
+ [(set (pc)
+ (if_then_else
+ (match_operator:SI 0 "comparison_operator"
+ [(match_operand:DF 2 "register_operand" "r")
+ (match_operand:DF 3 "register_operand" "r")])
+ (label_ref (match_operand 1 "" ""))
+ (pc)))]
+ ""
+ {
+ return nios2_output_fpu_insn_cmpd (insn, GET_CODE (operands[0]));
+ }
+ [(set_attr "type" "custom")])
+
+
+(define_expand "beq"
+ [(set (pc)
+ (if_then_else (eq:CC (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+{
+ gen_int_relational (EQ, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]);
+ DONE;
+})
+
+
+(define_expand "bne"
+ [(set (pc)
+ (if_then_else (ne:CC (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+{
+ gen_int_relational (NE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]);
+ DONE;
+})
+
+
+(define_expand "bgt"
+ [(set (pc)
+ (if_then_else (gt:CC (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+{
+ gen_int_relational (GT, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]);
+ DONE;
+})
+
+(define_expand "bge"
+ [(set (pc)
+ (if_then_else (ge:CC (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+{
+ gen_int_relational (GE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]);
+ DONE;
+})
+
+(define_expand "ble"
+ [(set (pc)
+ (if_then_else (le:CC (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+{
+ gen_int_relational (LE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]);
+ DONE;
+})
+
+(define_expand "blt"
+ [(set (pc)
+ (if_then_else (lt:CC (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+{
+ gen_int_relational (LT, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]);
+ DONE;
+})
+
+
+(define_expand "bgtu"
+ [(set (pc)
+ (if_then_else (gtu:CC (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+{
+ gen_int_relational (GTU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]);
+ DONE;
+})
+
+(define_expand "bgeu"
+ [(set (pc)
+ (if_then_else (geu:CC (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+{
+ gen_int_relational (GEU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]);
+ DONE;
+})
+
+(define_expand "bleu"
+ [(set (pc)
+ (if_then_else (leu:CC (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+{
+ gen_int_relational (LEU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]);
+ DONE;
+})
+
+(define_expand "bltu"
+ [(set (pc)
+ (if_then_else (ltu:CC (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+{
+ gen_int_relational (LTU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]);
+ DONE;
+})
+
+
+;*****************************************************************************
+;*
+;* String and Block Operations
+;*
+;*****************************************************************************
+
+; ??? This is all really a hack to get Dhrystone to work as fast as possible
+; things to be fixed:
+; * let the compiler core handle all of this, for that to work the extra
+; aliasing needs to be addressed.
+; * we use three temporary registers for loading and storing to ensure no
+; ld use stalls, this is excessive, because after the first ld/st only
+; two are needed. Only two would be needed all the way through if
+; we could schedule with other code. Consider:
+; 1 ld $1, 0($src)
+; 2 ld $2, 4($src)
+; 3 ld $3, 8($src)
+; 4 st $1, 0($dest)
+; 5 ld $1, 12($src)
+; 6 st $2, 4($src)
+; 7 etc.
+; The first store has to wait until 4. If it does not there will be one
+; cycle of stalling. However, if any other instruction could be placed
+; between 1 and 4, $3 would not be needed.
+; * In small we probably don't want to ever do this ourself because there
+; is no ld use stall.
+
+(define_expand "movstrsi"
+ [(parallel [(set (match_operand:BLK 0 "general_operand" "")
+ (match_operand:BLK 1 "general_operand" ""))
+ (use (match_operand:SI 2 "const_int_operand" ""))
+ (use (match_operand:SI 3 "const_int_operand" ""))
+ (clobber (match_scratch:SI 4 "=&r"))
+ (clobber (match_scratch:SI 5 "=&r"))
+ (clobber (match_scratch:SI 6 "=&r"))])]
+ "TARGET_INLINE_MEMCPY"
+{
+ rtx ld_addr_reg, st_addr_reg;
+
+ /* If the predicate for op2 fails in expr.c:emit_block_move_via_movstr
+ it trys to copy to a register, but does not re-try the predicate.
+ ??? Intead of fixing expr.c, I fix it here. */
+ if (!const_int_operand (operands[2], SImode))
+ FAIL;
+
+ /* ??? there are some magic numbers which need to be sorted out here.
+ the basis for them is not increasing code size hugely or going
+ out of range of offset addressing */
+ if (INTVAL (operands[3]) < 4)
+ FAIL;
+ if (!optimize
+ || (optimize_size && INTVAL (operands[2]) > 12)
+ || (optimize < 3 && INTVAL (operands[2]) > 100)
+ || INTVAL (operands[2]) > 200)
+ FAIL;
+
+ st_addr_reg
+ = replace_equiv_address (operands[0],
+ copy_to_mode_reg (Pmode, XEXP (operands[0], 0)));
+ ld_addr_reg
+ = replace_equiv_address (operands[1],
+ copy_to_mode_reg (Pmode, XEXP (operands[1], 0)));
+ emit_insn (gen_movstrsi_internal (st_addr_reg, ld_addr_reg,
+ operands[2], operands[3]));
+
+ DONE;
+})
+
+
+(define_insn "movstrsi_internal"
+ [(set (match_operand:BLK 0 "memory_operand" "=o")
+ (match_operand:BLK 1 "memory_operand" "o"))
+ (use (match_operand:SI 2 "const_int_operand" "i"))
+ (use (match_operand:SI 3 "const_int_operand" "i"))
+ (clobber (match_scratch:SI 4 "=&r"))
+ (clobber (match_scratch:SI 5 "=&r"))
+ (clobber (match_scratch:SI 6 "=&r"))]
+ "TARGET_INLINE_MEMCPY"
+{
+ int ld_offset = INTVAL (operands[2]);
+ int ld_len = INTVAL (operands[2]);
+ int ld_reg = 0;
+ rtx ld_addr_reg = XEXP (operands[1], 0);
+ int st_offset = INTVAL (operands[2]);
+ int st_len = INTVAL (operands[2]);
+ int st_reg = 0;
+ rtx st_addr_reg = XEXP (operands[0], 0);
+ int delay_count = 0;
+
+ /* ops[0] is the address used by the insn
+ ops[1] is the register being loaded or stored */
+ rtx ops[2];
+
+ 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 "reg_or_0_operand" "rM")] UNSPEC_WRCTL)]
+ ""
+ "wrctl\\tctl%0, %z1"
+ [(set_attr "type" "control")])
+
+;Used to signal a stack overflow
+(define_insn "trap"
+ [(unspec_volatile [(const_int 0)] UNSPEC_TRAP)]
+ ""
+ "break\\t3"
+ [(set_attr "type" "control")])
+
+(define_insn "stack_overflow_detect_and_trap"
+ [(unspec_volatile [(const_int 0)] UNSPEC_STACK_OVERFLOW_DETECT_AND_TRAP)]
+ ""
+ "bgeu\\tsp, et, 1f\;break\\t3\;1:"
+ [(set_attr "type" "control")])
+
+
+;*****************************************************************************
+;*
+;* Peepholes
+;*
+;*****************************************************************************
+
+
+;; Local Variables:
+;; mode: lisp
+;; End:
diff --git a/gcc/config/nios2/t-nios2 b/gcc/config/nios2/t-nios2
new file mode 100644
index 0000000..b92f80a
--- /dev/null
+++ b/gcc/config/nios2/t-nios2
@@ -0,0 +1,175 @@
+##
+## 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}
+ echo '#ifndef __nios2_big_endian__' >> ${FPBIT}
+ echo '#define FLOAT_BIT_ORDER_MISMATCH' >> ${FPBIT}
+ echo '#endif' >> ${FPBIT}
+ cat $(srcdir)/config/fp-bit.c >> ${FPBIT}
+
+$(DPBIT): $(srcdir)/config/fp-bit.c Makefile
+ echo '' > ${DPBIT}
+ echo '#ifndef __nios2_big_endian__' >> ${DPBIT}
+ echo '#define FLOAT_BIT_ORDER_MISMATCH' >> ${DPBIT}
+ echo '#endif' >> ${DPBIT}
+ cat $(srcdir)/config/fp-bit.c >> ${DPBIT}
+
+EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o crti.o crtn.o
+
+# Assemble startup files.
+$(T)crti.o: $(srcdir)/config/nios2/crti.asm $(GCC_PASSES)
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \
+ -c -o $(T)crti.o -x assembler-with-cpp $(srcdir)/config/nios2/crti.asm
+
+$(T)crtn.o: $(srcdir)/config/nios2/crtn.asm $(GCC_PASSES)
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \
+ -c -o $(T)crtn.o -x assembler-with-cpp $(srcdir)/config/nios2/crtn.asm
+
+
+## You may need to provide additional #defines at the beginning of
+## fp-bit.c and dp-bit.c to control target endianness and other options
+##
+## CRTSTUFF_T_CFLAGS
+## Special flags used when compiling crtstuff.c. See Initialization.
+##
+## CRTSTUFF_T_CFLAGS_S
+## Special flags used when compiling crtstuff.c for shared linking. Used
+## if you use crtbeginS.o and crtendS.o in EXTRA-PARTS. See Initialization.
+##
+## MULTILIB_OPTIONS
+## For some targets, invoking GCC in different ways produces objects that
+## can not be linked together. For example, for some targets GCC produces
+## both big and little endian code. For these targets, you must arrange
+## for multiple versions of libgcc.a to be compiled, one for each set of
+## incompatible options. When GCC invokes the linker, it arranges to link
+## in the right version of libgcc.a, based on the command line options
+## used.
+## The MULTILIB_OPTIONS macro lists the set of options for which special
+## versions of libgcc.a must be built. Write options that are mutually
+## incompatible side by side, separated by a slash. Write options that may
+## be used together separated by a space. The build procedure will build
+## all combinations of compatible options.
+##
+## For example, if you set MULTILIB_OPTIONS to m68000/m68020 msoft-float,
+## Makefile will build special versions of libgcc.a using the following
+## sets of options: -m68000, -m68020, -msoft-float, -m68000 -msoft-float,
+## and -m68020 -msoft-float.
+
+
+## The BUILD_BE_MULTILIB and BUILD_PG_MULTILIB variables allow the
+## makefile user to enable/disable the generation of the precompiled
+## big endian and profiling libraries. By default, the big endian
+## libraries are not created on a windows build and the profiling
+## libraries are not created on a Solaris build. All other library
+## combinations are created by default.
+
+# Uncomment to temporarily avoid building big endian and profiling libraries during a Windows build.
+#ifeq ($(DEV_HOST_OS), win32)
+#BUILD_BE_MULTILIB ?= 0
+#BUILD_PG_MULTILIB ?= 0
+#endif
+
+#By default, avoid building the profiling libraries during a Solaris build.
+ifeq ($(DEV_HOST_OS), solaris)
+BUILD_PG_MULTILIB ?= 0
+endif
+
+BUILD_BE_MULTILIB ?= 1
+BUILD_PG_MULTILIB ?= 1
+BUILD_MULTILIB ?= 1
+
+ifeq ($(BUILD_MULTILIB), 1)
+
+MULTILIB_OPTIONS = mno-hw-mul mhw-mulx mstack-check mcustom-fpu-cfg=60-1 mcustom-fpu-cfg=60-2
+
+#Add the profiling flag to the multilib variable if required
+ifeq ($(BUILD_PG_MULTILIB), 1)
+MULTILIB_OPTIONS += pg
+endif
+
+#Add the big endian flag to the multilib variable if required
+ifeq ($(BUILD_BE_MULTILIB), 1)
+MULTILIB_OPTIONS += EB/EL
+endif
+
+endif
+
+## MULTILIB_DIRNAMES
+## If MULTILIB_OPTIONS is used, this variable specifies the directory names
+## that should be used to hold the various libraries. Write one element in
+## MULTILIB_DIRNAMES for each element in MULTILIB_OPTIONS. If
+## MULTILIB_DIRNAMES is not used, the default value will be
+## MULTILIB_OPTIONS, with all slashes treated as spaces.
+## For example, if MULTILIB_OPTIONS is set to m68000/m68020 msoft-float,
+## then the default value of MULTILIB_DIRNAMES is m68000 m68020
+## msoft-float. You may specify a different value if you desire a
+## different set of directory names.
+
+# MULTILIB_DIRNAMES =
+
+## MULTILIB_MATCHES
+## Sometimes the same option may be written in two different ways. If an
+## option is listed in MULTILIB_OPTIONS, GCC needs to know about any
+## synonyms. In that case, set MULTILIB_MATCHES to a list of items of the
+## form option=option to describe all relevant synonyms. For example,
+## m68000=mc68000 m68020=mc68020.
+
+ifeq ($(BUILD_MULTILIB), 1)
+ifeq ($(BUILD_BE_MULTILIB), 1)
+MULTILIB_MATCHES = EL=mel EB=meb
+endif
+endif
+
+##
+## MULTILIB_EXCEPTIONS
+## Sometimes when there are multiple sets of MULTILIB_OPTIONS being
+## specified, there are combinations that should not be built. In that
+## case, set MULTILIB_EXCEPTIONS to be all of the switch exceptions in
+## shell case syntax that should not be built.
+## For example, in the PowerPC embedded ABI support, it is not desirable to
+## build libraries compiled with the -mcall-aix option and either of the
+## -fleading-underscore or -mlittle options at the same time. Therefore
+## MULTILIB_EXCEPTIONS is set to
+##
+## *mcall-aix/*fleading-underscore* *mlittle/*mcall-aix*
+##
+
+ifeq ($(BUILD_MULTILIB), 1)
+MULTILIB_EXCEPTIONS = *mno-hw-mul/*mhw-mulx* *mcustom-fpu-cfg=60-1/*mcustom-fpu-cfg=60-2*
+endif
+
+##
+## MULTILIB_EXTRA_OPTS Sometimes it is desirable that when building
+## multiple versions of libgcc.a certain options should always be passed on
+## to the compiler. In that case, set MULTILIB_EXTRA_OPTS to be the list
+## of options to be used for all builds.
+##
+
diff --git a/gcc/config/nios2/t-nios2-uclibc b/gcc/config/nios2/t-nios2-uclibc
new file mode 100644
index 0000000..9a303db
--- /dev/null
+++ b/gcc/config/nios2/t-nios2-uclibc
@@ -0,0 +1,152 @@
+##
+## 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}
+ echo '#ifndef __nios2_big_endian__' >> ${FPBIT}
+ echo '#define FLOAT_BIT_ORDER_MISMATCH' >> ${FPBIT}
+ echo '#endif' >> ${FPBIT}
+ cat $(srcdir)/config/fp-bit.c >> ${FPBIT}
+
+$(DPBIT): $(srcdir)/config/fp-bit.c Makefile
+ echo '' > ${DPBIT}
+ echo '#ifndef __nios2_big_endian__' >> ${DPBIT}
+ echo '#define FLOAT_BIT_ORDER_MISMATCH' >> ${DPBIT}
+ echo '#endif' >> ${DPBIT}
+ cat $(srcdir)/config/fp-bit.c >> ${DPBIT}
+
+EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o
+
+## You may need to provide additional #defines at the beginning of
+## fp-bit.c and dp-bit.c to control target endianness and other options
+##
+## CRTSTUFF_T_CFLAGS
+## Special flags used when compiling crtstuff.c. See Initialization.
+##
+## CRTSTUFF_T_CFLAGS_S
+## Special flags used when compiling crtstuff.c for shared linking. Used
+## if you use crtbeginS.o and crtendS.o in EXTRA-PARTS. See Initialization.
+##
+## MULTILIB_OPTIONS
+## For some targets, invoking GCC in different ways produces objects that
+## can not be linked together. For example, for some targets GCC produces
+## both big and little endian code. For these targets, you must arrange
+## for multiple versions of libgcc.a to be compiled, one for each set of
+## incompatible options. When GCC invokes the linker, it arranges to link
+## in the right version of libgcc.a, based on the command line options
+## used.
+## The MULTILIB_OPTIONS macro lists the set of options for which special
+## versions of libgcc.a must be built. Write options that are mutually
+## incompatible side by side, separated by a slash. Write options that may
+## be used together separated by a space. The build procedure will build
+## all combinations of compatible options.
+##
+## For example, if you set MULTILIB_OPTIONS to m68000/m68020 msoft-float,
+## Makefile will build special versions of libgcc.a using the following
+## sets of options: -m68000, -m68020, -msoft-float, -m68000 -msoft-float,
+## and -m68020 -msoft-float.
+
+
+## The BUILD_BE_MULTILIB and BUILD_PG_MULTILIB variables allow the
+## makefile user to enable/disable the generation of the precompiled
+## big endian and profiling libraries.
+
+# By default, avoid building big endian and profiling libraries
+BUILD_BE_MULTILIB ?= 0
+BUILD_PG_MULTILIB ?= 0
+BUILD_MULTILIB ?= 1
+
+ifeq ($(BUILD_MULTILIB), 1)
+
+MULTILIB_OPTIONS = mno-hw-mul mhw-mulx mstack-check mcustom-fpu-cfg=60-1 mcustom-fpu-cfg=60-2
+
+#Add the profiling flag to the multilib variable if required
+ifeq ($(BUILD_PG_MULTILIB), 1)
+MULTILIB_OPTIONS += pg
+endif
+
+#Add the big endian flag to the multilib variable if required
+ifeq ($(BUILD_BE_MULTILIB), 1)
+MULTILIB_OPTIONS += EB/EL
+endif
+
+endif
+
+## MULTILIB_DIRNAMES
+## If MULTILIB_OPTIONS is used, this variable specifies the directory names
+## that should be used to hold the various libraries. Write one element in
+## MULTILIB_DIRNAMES for each element in MULTILIB_OPTIONS. If
+## MULTILIB_DIRNAMES is not used, the default value will be
+## MULTILIB_OPTIONS, with all slashes treated as spaces.
+## For example, if MULTILIB_OPTIONS is set to m68000/m68020 msoft-float,
+## then the default value of MULTILIB_DIRNAMES is m68000 m68020
+## msoft-float. You may specify a different value if you desire a
+## different set of directory names.
+
+# MULTILIB_DIRNAMES =
+
+## MULTILIB_MATCHES
+## Sometimes the same option may be written in two different ways. If an
+## option is listed in MULTILIB_OPTIONS, GCC needs to know about any
+## synonyms. In that case, set MULTILIB_MATCHES to a list of items of the
+## form option=option to describe all relevant synonyms. For example,
+## m68000=mc68000 m68020=mc68020.
+
+ifeq ($(BUILD_MULTILIB), 1)
+ifeq ($(BUILD_BE_MULTILIB), 1)
+MULTILIB_MATCHES = EL=mel EB=meb
+endif
+endif
+
+##
+## MULTILIB_EXCEPTIONS
+## Sometimes when there are multiple sets of MULTILIB_OPTIONS being
+## specified, there are combinations that should not be built. In that
+## case, set MULTILIB_EXCEPTIONS to be all of the switch exceptions in
+## shell case syntax that should not be built.
+## For example, in the PowerPC embedded ABI support, it is not desirable to
+## build libraries compiled with the -mcall-aix option and either of the
+## -fleading-underscore or -mlittle options at the same time. Therefore
+## MULTILIB_EXCEPTIONS is set to
+##
+## *mcall-aix/*fleading-underscore* *mlittle/*mcall-aix*
+##
+
+ifeq ($(BUILD_MULTILIB), 1)
+MULTILIB_EXCEPTIONS = *mno-hw-mul/*mhw-mulx* *mcustom-fpu-cfg=60-1/*mcustom-fpu-cfg=60-2*
+endif
+
+##
+## MULTILIB_EXTRA_OPTS Sometimes it is desirable that when building
+## multiple versions of libgcc.a certain options should always be passed on
+## to the compiler. In that case, set MULTILIB_EXTRA_OPTS to be the list
+## of options to be used for all builds.
+##
+
diff --git a/gcc/cse.c b/gcc/cse.c
index 72af39a..b36310c 100644
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -3134,6 +3134,10 @@ find_comparison_args (enum rtx_code code, rtx *parg1, rtx *parg2,
#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))
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 4638645..cdb248d 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -2488,6 +2488,33 @@ contents of that register. The @code{short_call} attribute always places
the offset to the function from the call site into the @samp{BL}
instruction directly.
+@item reverse_bitfields/no_reverse_bitfields
+@cindex reverse_bitfields on Altera Nios II
+This attribute specifies the order of bitfield allocation within a
+particular struct on Altera's Nios II processor. This overrides both
+the @option{-mno-reverse-bitfields} and @option{-mreverse-bitfields}
+switches, as well as any @code{#pragma} that might be present. It is
+ignored except when present on a struct.
+
+@smallexample
+struct inner
+@{
+ unsigned int a:1;
+ unsigned int b:31;
+@} __attribute__ ((reverse_bitfields));
+
+union outer
+@{
+ struct inner inner;
+ unsigned int val;
+@};
+
+@end smallexample
+
+will cause a to be allocated overlapping the most significant bit of
+val, regardless of any @code{#pragma} or compiler switch. See the
+@option{-mreverse-bitfields} switch for more examples.
+
@item function_vector
@cindex calling functions through the function vector on the H8/300 processors
Use this attribute on the H8/300, H8/300H, and H8S to indicate that the specified
@@ -5638,12 +5665,118 @@ to those machines. Generally these generate calls to specific machine
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
@@ -8022,6 +8155,7 @@ we do not recommend the use of pragmas; @xref{Function Attributes},
for further explanation.
@menu
+* Altera Nios II Pragmas::
* ARM Pragmas::
* RS/6000 and PowerPC Pragmas::
* Darwin Pragmas::
@@ -8029,6 +8163,29 @@ for further explanation.
* Tru64 Pragmas::
@end menu
+@node Altera Nios II Pragmas
+@subsection Altera Nios II Pragmas
+
+The Altera Nios II target defines two pragmas to control the placement
+of bitfields within a struct.
+
+@table @code
+@item reverse_bitfields
+@cindex pragma, reverse_bitfields
+Cause all subsequent structs to behave as though the -mreverse-bitfields
+compiler switch had been given. Can be overridden by the
+@code{no_reverse_bitfields} attribute or a subsequent
+@code{#pragma no_reverse_bitfields}.
+
+@item no_reverse_bitfields
+@cindex pragma, no_reverse_bitfields
+Cause all subsequent structs to behave as though the -mno-reverse-bitfields
+compiler switch had been given. Can be overridden by the
+@code{reverse_bitfields} attribute or a subsequent
+@code{#pragma reverse_bitfields}.
+
+@end table
+
@node ARM Pragmas
@subsection ARM Pragmas
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index e683d0c..b34200f 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -337,6 +337,16 @@ 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
+-mno-stack-check -mstack-check @gol
+-msys-crt0= -msys-lib= -msys=nosys @gol
+-mreverse-bitfields -mno-reverse-bitfields}
+
@emph{M680x0 Options}
@gccoptlist{-m68000 -m68020 -m68020-40 -m68020-60 -m68030 -m68040 @gol
-m68060 -mcpu32 -m5200 -m68881 -mbitfield -mc68000 -mc68020 @gol
@@ -5839,6 +5849,7 @@ machine description. The default for the options is also defined by
that macro, which enables you to change the defaults.
@menu
+* Altera Nios II Options::
* M680x0 Options::
* M68hc1x Options::
* VAX Options::
@@ -5874,6 +5885,290 @@ that macro, which enables you to change the defaults.
* 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 -mno-stack-check
+@itemx -mstack-check
+@opindex no-stack-check
+@opindex stack-check
+Enables or disables the checking for sufficient memory when
+items are pushed onto the stack. A checked and non-checked
+version of each of the multilibs is provided.
+
+@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.
+
+@item -mno-reverse-bitfields
+@itemx -mreverse-bitfields
+@opindex mno-reverse-bitfields
+@opindex mreverse-bitfields
+When enabled, bitfields within a struct are allocated in reverse order.
+This is useful with legacy code that depends on the (inherently
+non-portable) ordering of bitfields via a union. Given:
+
+@smallexample
+struct inner
+@{
+ unsigned int a:1;
+ unsigned int b:31;
+@};
+
+union outer
+@{
+ struct inner inner;
+ unsigned int val;
+@};
+
+unsigned int f()
+@{
+ union outer o;
+ o.inner.a = 1;
+ o.inner.b = 0;
+ return o.val;
+@}
+@end smallexample
+
+a call to @code{f} will return 1 when compiled with
+@option{-mno-reverse-bitfields} (the default), or 2147483648 when
+compiled with @option{-mreverse-bitfields}.
+
+For structures that are a multiple of 32 bits wide, the reversal is
+done 32 bits at a time. For structures that are an odd multiple of 16
+bits wide, the reversal is done 16 bits at a time. For structures
+that are an odd multiple of 8 bits wide, the reversal is done 8 bits
+at a time. The size of a structure (as measured by the @code{sizeof}
+operator) never changes between @option{-mno-reverse-bitfields} and
+@option{-mreverse-bitfields}. Nonetheless, there can be some
+confusing corner cases with structs where the compiler has to add
+additional padding to meet alignment restrictions. Consider:
+
+@smallexample
+struct inner
+@{
+ unsigned int a:1;
+ unsigned int b:15;
+@};
+
+union outer
+@{
+ struct inner inner;
+ unsigned int val;
+@};
+
+unsigned int f()
+@{
+ union outer o;
+ o.val = 0;
+ o.inner.b = 1;
+ return o.val;
+@}
+@end smallexample
+
+a call to @code{f} will return 2 when compiled with
+@option{-mno-reverse-bitfields} (the default), or 65536 when compiled
+with @option{-mreverse-bitfields}. This is because @code{sizeof
+(inner)} is 4 in both cases. In the @option{-mno-reverse-bitfields}
+case, the compiler pads the struct at the end to be 4 bytes long,
+effectively doing:
+
+@smallexample
+struct inner
+@{
+ unsigned int a:1;
+ unsigned int b:15;
+ unsigned int padding:16;
+@};
+@end smallexample
+
+In the @option{-mreverse-bitfields} case, the hidden padding is
+reversed along with everything else, yielding the equivalent of:
+
+@smallexample
+struct inner
+@{
+ unsigned int padding:16;
+ unsigned int b:15;
+ unsigned int a:1;
+@};
+@end smallexample
+
+Of course, if we would rather that @code{sizeof (inner)} was 2, we could
+write the struct as:
+
+@smallexample
+struct inner
+@{
+ unsigned short a:1;
+ unsigned short b:15;
+@};
+@end smallexample
+
+and the padding would go away.
+
+In some cases, especially when using the @code{__packed__} attribute,
+there is no well-defined bit reversal that is possible: the compiler
+will issue an error message in this case. Consider:
+
+@smallexample
+struct invalid
+@{
+ unsigned int f1:1;
+ unsigned int f2:15;
+ unsigned int f3:4;
+ unsigned int f4:4;
+@} __attribute__ ((__packed__));
+@end smallexample
+
+Since @code{sizeof (invalid)} is 3, we are forced to try reversing
+individual bytes in the struct. But f2 is more than a byte wide, so
+we can't reverse it and still have it be contiguous. Similar cases
+occur when dealing with arrays or other large contiguous objects:
+
+@smallexample
+struct invalid2
+@{
+ unsigned char f1[5];
+ unsigned char f2[3];
+@};
+@end smallexample
+
+You'll have to rewrite the affected structs to say exactly what you
+mean in odd cases like that.
+
+Finally, note that individual fields are sized as a whole. The structs
+
+@smallexample
+struct array1
+@{
+ unsigned char f1[3];
+ unsigned char f2;
+@}
+@end smallexample
+
+and:
+
+@smallexample
+struct array2
+@{
+ unsigned char f1a;
+ unsigned char f1b;
+ unsigned char f1c;
+ unsigned char f2;
+@}
+@end smallexample
+
+are not equivalent. When compiled with @option{-mreverse-bitfields},
+they behave the same as:
+
+@smallexample
+struct array1r
+@{
+ unsigned char f2;
+ unsigned char f1[3];
+@}
+@end smallexample
+
+and:
+
+@smallexample
+struct array2r
+@{
+ unsigned char f2;
+ unsigned char f1c;
+ unsigned char f1b;
+ unsigned char f1a;
+@}
+@end smallexample
+
+would, respectively, when compiled with
+@option{-mno-reverse-bitfields}. In particular, f1 is treated as a
+single contiguous 24-bit object for purposes of reversal, while f1a,
+f1b, and f1c are treated as individual 8-bit objects that need not
+(and do not) remain contiguous. Use caution.
+
+@end table
+
+
@node M680x0 Options
@subsection M680x0 Options
@cindex M680x0 options
diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index b73f325..4a134b2 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -1337,6 +1337,58 @@ However, here is a summary of the machine-dependent constraints
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.
+
+@item D@var{nn}
+For a given two digit @var{nn} constrains the operand
+to the corresponding register. Example: D02 forces the
+operand into register r2. The side effect of using this
+operand constraint is that reload may not be able to
+meet the constraint. If reload fails, an error message
+about failing to find any register to spill in the
+D@var{nn}_REG register class will be emitted.
+
+@end table
+
+
@item ARM family---@file{arm.h}
@table @code
@item f
diff --git a/gcc/stor-layout.c b/gcc/stor-layout.c
index 4527fe4..e7cc581 100644
--- a/gcc/stor-layout.c
+++ b/gcc/stor-layout.c
@@ -1435,6 +1435,355 @@ finalize_type_size (tree type)
}
}
+static void
+reverse_bitfield_layout (record_layout_info rli)
+{
+ tree field;
+ tree rev_size;
+ unsigned int rev_size_int;
+
+ /*
+ * The size of the words we'll be reversing. Normally, we reverse
+ * entire SImode words. However, if the entire struct's size isn't an
+ * exact multiple of the size of SImode, we can reverse HImode or even
+ * QImode pieces. In the examples below, assume SImode/int is 32
+ * bits, HImode/short is 16 bits, and QImode/char is 8 bits.
+ * Consider:
+ *
+ * struct s1
+ * {
+ * int f1:1;
+ * int f2:31;
+ * };
+ *
+ * struct s2
+ * {
+ * int f1:1;
+ * int f2:15;
+ * } __attribute__ ((__packed__));
+ *
+ * struct s3
+ * {
+ * short f1:1;
+ * short f2:15;
+ * };
+ *
+ * struct s4
+ * {
+ * int f1:1;
+ * int f2:15;
+ * };
+ *
+ * struct s5
+ * {
+ * int f1:8;
+ * int f2:8;
+ * int f3:4;
+ * int f4:4;
+ * } __attribute__ ((__packed__));
+ *
+ * struct s6
+ * {
+ * int f1:1;
+ * int f2:15;
+ * int f3:4;
+ * int f4:4;
+ * int f5:8;
+ * };
+ *
+ * struct s7
+ * {
+ * int f1:1;
+ * int f2:15;
+ * int f3:4;
+ * int f4:4;
+ * } __attribute__ ((__packed__));
+ *
+ * struct s8
+ * {
+ * char f1;
+ * short f2;
+ * char f3;
+ * };
+ *
+ * struct s9
+ * {
+ * char f1;
+ * short f2;
+ * char f3;
+ * } __attribute__ ((__packed__));
+ *
+ * struct s10
+ * {
+ * char f1;
+ * short f2;
+ * char f3;
+ * short f4;
+ * };
+ *
+ * struct s11
+ * {
+ * char f1[5];
+ * int f2;
+ * };
+ *
+ * struct s12
+ * {
+ * char f1[5];
+ * char f2[3];
+ * int f3;
+ * };
+ *
+ * struct s13
+ * {
+ * char f1[3];
+ * int f2;
+ * };
+ *
+ * struct s14
+ * {
+ * char f1a;
+ * char f1b;
+ * char f1c;
+ * int f2;
+ * };
+ *
+ * Then we have:
+ *
+ * sizeof (struct s1) == 4
+ * sizeof (struct s2) == 2
+ * sizeof (struct s3) == 2
+ * sizeof (struct s4) == 4
+ * sizeof (struct s5) == 3
+ * sizeof (struct s6) == 4
+ * sizeof (struct s7) == 3
+ * sizeof (struct s8) == 6
+ * sizeof (struct s9) == 4
+ * sizeof (struct s10) == 8
+ * sizeof (struct s11) == 12
+ * sizeof (struct s12) == 12
+ *
+ * We want the equivalent reversed bitfield structs to be:
+ *
+ * struct s1r
+ * {
+ * int f2:31;
+ * int f1:1;
+ * };
+ *
+ * struct s2r
+ * {
+ * int f2:15;
+ * int f1:1;
+ * } __attribute__ ((__packed__));
+ *
+ * struct s3r
+ * {
+ * short f2:15;
+ * short f1:1;
+ * };
+ *
+ * struct s4r
+ * {
+ * int unnamed:16;
+ * int f2:15;
+ * int f1:1;
+ * };
+ *
+ * struct s5r
+ * {
+ * int f1:8;
+ * int f2:8;
+ * int f4:4;
+ * int f3:4;
+ * } __attribute__ ((__packed__));
+ *
+ * struct s6r
+ * {
+ * int f5:8;
+ * int f4:4;
+ * int f3:4;
+ * int f2:15;
+ * int f1:1;
+ * };
+ *
+ * struct s7r
+ * {
+ * #error cannot reverse bitfield
+ * } __attribute__ ((__packed__));
+ *
+ * struct s8r
+ * {
+ * char unnamed1;
+ * char f1;
+ * short f2;
+ * char unnamed2;
+ * char f3;
+ * };
+ *
+ * struct s9r
+ * {
+ * char f3;
+ * short f2;
+ * char f1;
+ * } __attribute__ ((__packed__));
+ *
+ * struct s10r
+ * {
+ * short f2;
+ * char unnamed1;
+ * char f1;
+ * short f4;
+ * char unnamed2;
+ * char f3;
+ * };
+ *
+ * struct s11r
+ * {
+ * char f1[5];
+ * int f2;
+ * };
+ *
+ * struct s12r
+ * {
+ * #error cannot reverse bitfield
+ * };
+ *
+ * struct s13r
+ * {
+ * char unnamed;
+ * char f1[3];
+ * int f2;
+ * };
+ *
+ * struct s14r
+ * {
+ * char unnamed;
+ * char f1c;
+ * char f1b;
+ * char f1a;
+ * int f2;
+ * };
+ *
+ * Note that the s4, s8, s10, s13, and s14 cases produce somewhat
+ * suprising results: the normally hidden padding bytes the compiler
+ * adds are also reversed. Further note that s13 and s14 are not
+ * equivalent: the f1 field in s13 is 24-bits wide, and is reversed
+ * accordingly, while the three fields f1a, f1b, and f1c in s14 are
+ * reversed as individual bytes.
+ *
+ * The s7 and s12 cases produce an error: we can't reverse a bitfield
+ * that is larger than word size we're reversing. The error is
+ * suppressed in the s11 case since the field in question and the
+ * field that follows are both word aligned.
+ */
+
+ /*
+ * First, figure out what size words to reverse. We look at the total
+ * number of bits currently in use by the struct, rounded up to the
+ * next multiple of rli->record_align, to decide.
+ */
+ {
+ int bits_in_use = TREE_INT_CST_LOW (round_up (rli_size_so_far (rli),
+ rli->record_align));
+ unsigned int size;
+ for (size = GET_MODE_BITSIZE (SImode);
+ size >= GET_MODE_BITSIZE (QImode);
+ size /= 2)
+ {
+ if (bits_in_use % size == 0)
+ {
+ break;
+ }
+ }
+ if (size < GET_MODE_BITSIZE (QImode))
+ {
+ /*
+ * rli->record_align should never be less than QImode, even
+ * for packed structs.
+ */
+ abort ();
+ }
+ rev_size = size_int_type (size, bitsizetype);
+ rev_size_int = size;
+ }
+
+ /*
+ * Then, iterate over the fields, reversing them as we go.
+ */
+ for (field = TYPE_FIELDS (rli->t); field; field = TREE_CHAIN (field))
+ {
+ tree type = TREE_TYPE (field);
+ if (TREE_CODE (field) != FIELD_DECL)
+ {
+ continue;
+ }
+ if (TREE_CODE (field) == ERROR_MARK || TREE_CODE (type) == ERROR_MARK)
+ {
+ return;
+ }
+ {
+ tree offset = DECL_FIELD_OFFSET (field);
+ tree offset_type = TREE_TYPE (offset);
+ tree bit_offset = DECL_FIELD_BIT_OFFSET (field);
+ tree bit_offset_type = TREE_TYPE (bit_offset);
+ tree bit = bit_from_pos (offset, bit_offset);
+ tree true_size = DECL_SIZE (field);
+ pos_from_bit (&offset, &bit_offset, rev_size_int, bit);
+ bit_offset = size_binop (MINUS_EXPR,
+ size_binop (MINUS_EXPR, rev_size, true_size),
+ bit_offset);
+ if (TREE_INT_CST_HIGH (bit_offset) != 0)
+ {
+ /*
+ * This happens when a field spans a rev_size boundary (see
+ * example s7 above): rather than try to come up with some
+ * well-defined, but non-intuitive definition for this case,
+ * just issue an error. It can also happen for large fields,
+ * e.g. arrays or other structs: if these large fields were
+ * already aligned, leave them be; otherwise issue the error
+ * in this case as well.
+ */
+ if ((TREE_INT_CST_HIGH (true_size) != 0
+ || TREE_INT_CST_LOW (true_size) > rev_size_int)
+ && TREE_INT_CST_HIGH (DECL_FIELD_BIT_OFFSET (field)) == 0
+ && TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field)) == 0)
+ {
+ tree next_field = TREE_CHAIN (field);
+ if (!next_field)
+ {
+ /* No following field, so we're ok. */
+ continue;
+ }
+ else
+ {
+ tree next_offset = DECL_FIELD_OFFSET (next_field);
+ tree next_bit_offset = DECL_FIELD_BIT_OFFSET (next_field);
+ tree next_bit = bit_from_pos (next_offset, next_bit_offset);
+ pos_from_bit (&next_offset, &next_bit_offset, rev_size_int,
+ next_bit);
+ if (TREE_INT_CST_HIGH (next_bit_offset) == 0
+ && TREE_INT_CST_LOW (next_bit_offset) == 0)
+ {
+ /* Following field is aligned wrt rev_size_int boundary,
+ so we're ok. */
+ continue;
+ }
+ }
+ }
+ error ("unable to reverse bitfields in structure");
+ return;
+ }
+ bit = bit_from_pos (offset, bit_offset);
+ pos_from_bit (&offset, &bit_offset, rli->offset_align, bit);
+ TREE_TYPE (offset) = offset_type;
+ DECL_FIELD_OFFSET (field) = offset;
+ TREE_TYPE (bit_offset) = bit_offset_type;
+ DECL_FIELD_BIT_OFFSET (field) = bit_offset;
+ }
+ }
+}
+
/* Do all of the work required to layout the type indicated by RLI,
once the fields have been laid out. This function will call `free'
for RLI, unless FREE_P is false. Passing a value other than false
@@ -1444,6 +1793,12 @@ finalize_type_size (tree type)
void
finish_record_layout (record_layout_info rli, int free_p)
{
+ /* Optionally reverse the placement of bitfields within the record */
+ if ((* targetm.reverse_bitfield_layout_p) (rli->t))
+ {
+ reverse_bitfield_layout (rli);
+ }
+
/* Compute the final size. */
finalize_record_size (rli);
diff --git a/gcc/target-def.h b/gcc/target-def.h
index 32d00ae..bdea4d4 100644
--- a/gcc/target-def.h
+++ b/gcc/target-def.h
@@ -300,6 +300,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define TARGET_INSERT_ATTRIBUTES hook_void_tree_treeptr
#define TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P hook_bool_tree_false
#define TARGET_MS_BITFIELD_LAYOUT_P hook_bool_tree_false
+#define TARGET_REVERSE_BITFIELD_LAYOUT_P hook_bool_tree_false
#define TARGET_RTX_COSTS hook_bool_rtx_int_int_intp_false
#define TARGET_MANGLE_FUNDAMENTAL_TYPE hook_constcharptr_tree_null
@@ -368,6 +369,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
TARGET_INSERT_ATTRIBUTES, \
TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P, \
TARGET_MS_BITFIELD_LAYOUT_P, \
+ TARGET_REVERSE_BITFIELD_LAYOUT_P, \
TARGET_INIT_BUILTINS, \
TARGET_EXPAND_BUILTIN, \
TARGET_MANGLE_FUNDAMENTAL_TYPE, \
diff --git a/gcc/target.h b/gcc/target.h
index 59788f9..97bde5f 100644
--- a/gcc/target.h
+++ b/gcc/target.h
@@ -295,6 +295,10 @@ struct gcc_target
Microsoft Visual C++ bitfield layout rules. */
bool (* ms_bitfield_layout_p) (tree record_type);
+ /* Return true if bitfields in RECORD_TYPE should be allocated
+ within their base type's bytes starting at the opposite end. */
+ bool (* reverse_bitfield_layout_p) (tree record_type);
+
/* Set up target-specific built-in functions. */
void (* init_builtins) (void);
diff --git a/gcc/varasm.c b/gcc/varasm.c
index 33307e5..d4ed0fc 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -3912,6 +3912,107 @@ array_size_for_constructor (tree val)
return tree_low_cst (i, 1);
}
+struct reorder_bitfields_key
+{
+ tree field;
+ tree value;
+};
+
+static int
+reorder_bitfields_compare (const void *x1, const void *x2)
+{
+ const struct reorder_bitfields_key *key1 = x1;
+ const struct reorder_bitfields_key *key2 = x2;
+ int pos1 = int_bit_position (key1->field);
+ int pos2 = int_bit_position (key2->field);
+
+ if (pos1 < pos2)
+ {
+ return -1;
+ }
+ else if (pos1 > pos2)
+ {
+ return 1;
+ }
+ else
+ {
+ /*
+ * No two fields should ever have the same bit_position, so
+ * something is horribly wrong.
+ */
+ abort ();
+ }
+}
+
+static void
+reorder_bitfields (tree *first_field, tree *first_value)
+{
+ struct reorder_bitfields_key *keys;
+ size_t field_count;
+ tree field;
+ tree value;
+ size_t i;
+
+ /*
+ * Find out how many fields are in this record, and allocate an array
+ * of keys to hold them all.
+ */
+ field_count = 0;
+ for (field = *first_field; field; field = TREE_CHAIN (field))
+ {
+ field_count++;
+ }
+ if (field_count < 2)
+ {
+ return;
+ }
+ keys = xmalloc (sizeof (struct reorder_bitfields_key) * field_count);
+
+ /*
+ * Make copies of the existing fields and values (using signed integer
+ * zeros for missing values) in the array of keys.
+ */
+ field = *first_field;
+ value = *first_value;
+ for (i = 0; i < field_count; i++)
+ {
+ keys[i].field = copy_node (field);
+ field = TREE_CHAIN (field);
+ if (value)
+ {
+ keys[i].value = copy_node (value);
+ TREE_PURPOSE (keys[i].value) = keys[i].field;
+ value = TREE_CHAIN (value);
+ }
+ else
+ {
+ keys[i].value = tree_cons (keys[i].field, ssize_int (0), 0);
+ }
+ }
+
+ /*
+ * Sort the array based on position of the fields in the record.
+ */
+ qsort (keys, field_count, sizeof (struct reorder_bitfields_key),
+ reorder_bitfields_compare);
+
+ /*
+ * Build new lists out of the sorted array.
+ */
+ for (i = 0; i < field_count - 1; i++)
+ {
+ TREE_CHAIN (keys[i].field) = keys[i+1].field;
+ TREE_CHAIN (keys[i].value) = keys[i+1].value;
+ }
+ *first_field = keys[0].field;
+ *first_value = keys[0].value;
+
+ /*
+ * Get rid of our array of keys and we're done.
+ */
+ free (keys);
+}
+
/* Subroutine of output_constant, used for CONSTRUCTORs (aggregate constants).
Generate at least SIZE bytes, padding if necessary. */
@@ -3928,12 +4029,29 @@ output_constructor (tree exp, unsigned HOST_WIDE_INT size,
/* Nonzero means BYTE contains part of a byte, to be output. */
int byte_buffer_in_use = 0;
int byte = 0;
+ tree first_link = CONSTRUCTOR_ELTS (exp);
if (HOST_BITS_PER_WIDE_INT < BITS_PER_UNIT)
abort ();
if (TREE_CODE (type) == RECORD_TYPE)
+ {
+ if ((*targetm.reverse_bitfield_layout_p) (type))
+ {
+ /*
+ * If we're reversing bitfields, we have to reverse the order in
+ * which constructors containing bitfields are output. The
+ * easiest way to do that is to reorder the constructor elements
+ * and fields to be in memory-order.
+ */
field = TYPE_FIELDS (type);
+ reorder_bitfields (&field, &first_link);
+ }
+ else
+ {
+ field = TYPE_FIELDS (type);
+ }
+ }
if (TREE_CODE (type) == ARRAY_TYPE
&& TYPE_DOMAIN (type) != 0)
@@ -3948,7 +4066,7 @@ output_constructor (tree exp, unsigned HOST_WIDE_INT size,
There is always a maximum of one element in the chain LINK for unions
(even if the initializer in a source program incorrectly contains
more one). */
- for (link = CONSTRUCTOR_ELTS (exp);
+ for (link = first_link;
link;
link = TREE_CHAIN (link),
field = field ? TREE_CHAIN (field) : 0)