crosstool-ng/patches/gcc/3.4.6/900-nios2.patch
2007-08-15 21:23:08 +00:00

10232 lines
277 KiB
Diff
Raw Permalink 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 -durN gcc-3.4.6.orig/gcc/combine.c gcc-3.4.6/gcc/combine.c
--- gcc-3.4.6.orig/gcc/combine.c 2005-08-08 20:41:04.000000000 +0200
+++ gcc-3.4.6/gcc/combine.c 2007-08-15 23:09:36.000000000 +0200
@@ -4381,6 +4381,14 @@
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 @@
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 -durN gcc-3.4.6.orig/gcc/config/nios2/crti.asm gcc-3.4.6/gcc/config/nios2/crti.asm
--- gcc-3.4.6.orig/gcc/config/nios2/crti.asm 1970-01-01 01:00:00.000000000 +0100
+++ gcc-3.4.6/gcc/config/nios2/crti.asm 2007-08-15 23:09:36.000000000 +0200
@@ -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 -durN gcc-3.4.6.orig/gcc/config/nios2/crtn.asm gcc-3.4.6/gcc/config/nios2/crtn.asm
--- gcc-3.4.6.orig/gcc/config/nios2/crtn.asm 1970-01-01 01:00:00.000000000 +0100
+++ gcc-3.4.6/gcc/config/nios2/crtn.asm 2007-08-15 23:09:36.000000000 +0200
@@ -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 -durN gcc-3.4.6.orig/gcc/config/nios2/lib2-divmod.c gcc-3.4.6/gcc/config/nios2/lib2-divmod.c
--- gcc-3.4.6.orig/gcc/config/nios2/lib2-divmod.c 1970-01-01 01:00:00.000000000 +0100
+++ gcc-3.4.6/gcc/config/nios2/lib2-divmod.c 2007-08-15 23:09:36.000000000 +0200
@@ -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 -durN gcc-3.4.6.orig/gcc/config/nios2/lib2-divmod-hi.c gcc-3.4.6/gcc/config/nios2/lib2-divmod-hi.c
--- gcc-3.4.6.orig/gcc/config/nios2/lib2-divmod-hi.c 1970-01-01 01:00:00.000000000 +0100
+++ gcc-3.4.6/gcc/config/nios2/lib2-divmod-hi.c 2007-08-15 23:09:36.000000000 +0200
@@ -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 -durN gcc-3.4.6.orig/gcc/config/nios2/lib2-divtable.c gcc-3.4.6/gcc/config/nios2/lib2-divtable.c
--- gcc-3.4.6.orig/gcc/config/nios2/lib2-divtable.c 1970-01-01 01:00:00.000000000 +0100
+++ gcc-3.4.6/gcc/config/nios2/lib2-divtable.c 2007-08-15 23:09:36.000000000 +0200
@@ -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 -durN gcc-3.4.6.orig/gcc/config/nios2/lib2-mul.c gcc-3.4.6/gcc/config/nios2/lib2-mul.c
--- gcc-3.4.6.orig/gcc/config/nios2/lib2-mul.c 1970-01-01 01:00:00.000000000 +0100
+++ gcc-3.4.6/gcc/config/nios2/lib2-mul.c 2007-08-15 23:09:36.000000000 +0200
@@ -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 -durN gcc-3.4.6.orig/gcc/config/nios2/nios2.c gcc-3.4.6/gcc/config/nios2/nios2.c
--- gcc-3.4.6.orig/gcc/config/nios2/nios2.c 1970-01-01 01:00:00.000000000 +0100
+++ gcc-3.4.6/gcc/config/nios2/nios2.c 2007-08-15 23:09:36.000000000 +0200
@@ -0,0 +1,2853 @@
+/* Subroutines for assembler code output for Altera NIOS 2G NIOS2 version.
+ Copyright (C) 2003 Altera
+ Contributed by Jonah Graham (jgraham@altera.com).
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+#include <stdio.h>
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "rtl.h"
+#include "tree.h"
+#include "tm_p.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "real.h"
+#include "insn-config.h"
+#include "conditions.h"
+#include "output.h"
+#include "insn-attr.h"
+#include "flags.h"
+#include "recog.h"
+#include "expr.h"
+#include "toplev.h"
+#include "basic-block.h"
+#include "function.h"
+#include "ggc.h"
+#include "reload.h"
+#include "debug.h"
+#include "optabs.h"
+#include "target.h"
+#include "target-def.h"
+
+/* local prototypes */
+static bool nios2_rtx_costs (rtx, int, int, int *);
+
+static void nios2_asm_function_prologue (FILE *, HOST_WIDE_INT);
+static int nios2_use_dfa_pipeline_interface (void);
+static int nios2_issue_rate (void);
+static struct machine_function *nios2_init_machine_status (void);
+static bool nios2_in_small_data_p (tree);
+static rtx save_reg (int, HOST_WIDE_INT, rtx);
+static rtx restore_reg (int, HOST_WIDE_INT);
+static unsigned int nios2_section_type_flags (tree, const char *, int);
+static void nios2_init_builtins (void);
+static rtx nios2_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
+static bool nios2_function_ok_for_sibcall (tree, tree);
+static void nios2_encode_section_info (tree, rtx, int);
+
+/* Initialize the GCC target structure. */
+#undef TARGET_ASM_FUNCTION_PROLOGUE
+#define TARGET_ASM_FUNCTION_PROLOGUE nios2_asm_function_prologue
+
+#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE
+#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE \
+ nios2_use_dfa_pipeline_interface
+#undef TARGET_SCHED_ISSUE_RATE
+#define TARGET_SCHED_ISSUE_RATE nios2_issue_rate
+#undef TARGET_IN_SMALL_DATA_P
+#define TARGET_IN_SMALL_DATA_P nios2_in_small_data_p
+#undef TARGET_ENCODE_SECTION_INFO
+#define TARGET_ENCODE_SECTION_INFO nios2_encode_section_info
+#undef TARGET_SECTION_TYPE_FLAGS
+#define TARGET_SECTION_TYPE_FLAGS nios2_section_type_flags
+
+#undef TARGET_INIT_BUILTINS
+#define TARGET_INIT_BUILTINS nios2_init_builtins
+#undef TARGET_EXPAND_BUILTIN
+#define TARGET_EXPAND_BUILTIN nios2_expand_builtin
+
+#undef TARGET_FUNCTION_OK_FOR_SIBCALL
+#define TARGET_FUNCTION_OK_FOR_SIBCALL nios2_function_ok_for_sibcall
+
+#undef TARGET_RTX_COSTS
+#define TARGET_RTX_COSTS nios2_rtx_costs
+
+
+struct gcc_target targetm = TARGET_INITIALIZER;
+
+
+
+/* Threshold for data being put into the small data/bss area, instead
+ of the normal data area (references to the small data/bss area take
+ 1 instruction, and use the global pointer, references to the normal
+ data area takes 2 instructions). */
+unsigned HOST_WIDE_INT nios2_section_threshold = NIOS2_DEFAULT_GVALUE;
+
+
+/* Structure to be filled in by compute_frame_size with register
+ save masks, and offsets for the current function. */
+
+struct nios2_frame_info
+GTY (())
+{
+ long total_size; /* # bytes that the entire frame takes up */
+ long var_size; /* # bytes that variables take up */
+ long args_size; /* # bytes that outgoing arguments take up */
+ int save_reg_size; /* # bytes needed to store gp regs */
+ int save_reg_rounded; /* # bytes needed to store gp regs */
+ long save_regs_offset; /* offset from new sp to store gp registers */
+ int initialized; /* != 0 if frame size already calculated */
+ int num_regs; /* number of gp registers saved */
+};
+
+struct machine_function
+GTY (())
+{
+
+ /* Current frame information, calculated by compute_frame_size. */
+ struct nios2_frame_info frame;
+};
+
+
+/***************************************
+ * Section encodings
+ ***************************************/
+
+
+
+
+
+/***************************************
+ * Stack Layout and Calling Conventions
+ ***************************************/
+
+
+#define TOO_BIG_OFFSET(X) ((X) > ((1 << 15) - 1))
+#define TEMP_REG_NUM 8
+
+static void
+nios2_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
+{
+ if (flag_verbose_asm || flag_debug_asm)
+ {
+ compute_frame_size ();
+ dump_frame_size (file);
+ }
+}
+
+static rtx
+save_reg (int regno, HOST_WIDE_INT offset, rtx cfa_store_reg)
+{
+ rtx insn, stack_slot;
+
+ stack_slot = gen_rtx_PLUS (SImode,
+ cfa_store_reg,
+ GEN_INT (offset));
+
+ insn = emit_insn (gen_rtx_SET (SImode,
+ gen_rtx_MEM (SImode, stack_slot),
+ gen_rtx_REG (SImode, regno)));
+
+ RTX_FRAME_RELATED_P (insn) = 1;
+
+ return insn;
+}
+
+static rtx
+restore_reg (int regno, HOST_WIDE_INT offset)
+{
+ rtx insn, stack_slot;
+
+ if (TOO_BIG_OFFSET (offset))
+ {
+ stack_slot = gen_rtx_REG (SImode, TEMP_REG_NUM);
+ insn = emit_insn (gen_rtx_SET (SImode,
+ stack_slot,
+ GEN_INT (offset)));
+
+ insn = emit_insn (gen_rtx_SET (SImode,
+ stack_slot,
+ gen_rtx_PLUS (SImode,
+ stack_slot,
+ stack_pointer_rtx)));
+ }
+ else
+ {
+ stack_slot = gen_rtx_PLUS (SImode,
+ stack_pointer_rtx,
+ GEN_INT (offset));
+ }
+
+ stack_slot = gen_rtx_MEM (SImode, stack_slot);
+
+ insn = emit_move_insn (gen_rtx_REG (SImode, regno), stack_slot);
+
+ return insn;
+}
+
+
+/* There are two possible paths for prologue expansion,
+- the first is if the total frame size is < 2^15-1. In that
+case all the immediates will fit into the 16-bit immediate
+fields.
+- the second is when the frame size is too big, in that
+case an additional temporary register is used, first
+as a cfa_temp to offset the sp, second as the cfa_store
+register.
+
+See the comment above dwarf2out_frame_debug_expr in
+dwarf2out.c for more explanation of the "rules."
+
+
+Case 1:
+Rule # Example Insn Effect
+2 addi sp, sp, -total_frame_size cfa.reg=sp, cfa.offset=total_frame_size
+ cfa_store.reg=sp, cfa_store.offset=total_frame_size
+12 stw ra, offset(sp)
+12 stw r16, offset(sp)
+1 mov fp, sp
+
+Case 2:
+Rule # Example Insn Effect
+6 movi r8, total_frame_size cfa_temp.reg=r8, cfa_temp.offset=total_frame_size
+2 sub sp, sp, r8 cfa.reg=sp, cfa.offset=total_frame_size
+ cfa_store.reg=sp, cfa_store.offset=total_frame_size
+5 add r8, r8, sp cfa_store.reg=r8, cfa_store.offset=0
+12 stw ra, offset(r8)
+12 stw r16, offset(r8)
+1 mov fp, sp
+
+*/
+
+void
+expand_prologue ()
+{
+ int i;
+ HOST_WIDE_INT total_frame_size;
+ int cfa_store_offset;
+ rtx insn;
+ rtx cfa_store_reg = 0;
+
+ total_frame_size = compute_frame_size ();
+
+ if (total_frame_size)
+ {
+
+ if (TOO_BIG_OFFSET (total_frame_size))
+ {
+ /* cfa_temp and cfa_store_reg are the same register,
+ cfa_store_reg overwrites cfa_temp */
+ cfa_store_reg = gen_rtx_REG (SImode, TEMP_REG_NUM);
+ insn = emit_insn (gen_rtx_SET (SImode,
+ cfa_store_reg,
+ GEN_INT (total_frame_size)));
+
+ RTX_FRAME_RELATED_P (insn) = 1;
+
+
+ insn = gen_rtx_SET (SImode,
+ stack_pointer_rtx,
+ gen_rtx_MINUS (SImode,
+ stack_pointer_rtx,
+ cfa_store_reg));
+
+ insn = emit_insn (insn);
+ RTX_FRAME_RELATED_P (insn) = 1;
+
+
+ /* if there are no registers to save, I don't need to
+ create a cfa_store */
+ if (cfun->machine->frame.save_reg_size)
+ {
+ insn = gen_rtx_SET (SImode,
+ cfa_store_reg,
+ gen_rtx_PLUS (SImode,
+ cfa_store_reg,
+ stack_pointer_rtx));
+
+ insn = emit_insn (insn);
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+
+ cfa_store_offset
+ = total_frame_size
+ - (cfun->machine->frame.save_regs_offset
+ + cfun->machine->frame.save_reg_rounded);
+ }
+ else
+ {
+ insn = gen_rtx_SET (SImode,
+ stack_pointer_rtx,
+ gen_rtx_PLUS (SImode,
+ stack_pointer_rtx,
+ GEN_INT (-total_frame_size)));
+ insn = emit_insn (insn);
+ RTX_FRAME_RELATED_P (insn) = 1;
+
+ cfa_store_reg = stack_pointer_rtx;
+ cfa_store_offset
+ = cfun->machine->frame.save_regs_offset
+ + cfun->machine->frame.save_reg_rounded;
+ }
+ }
+
+ if (MUST_SAVE_REGISTER (RA_REGNO))
+ {
+ cfa_store_offset -= 4;
+ save_reg (RA_REGNO, cfa_store_offset, cfa_store_reg);
+ }
+ if (MUST_SAVE_REGISTER (FP_REGNO))
+ {
+ cfa_store_offset -= 4;
+ save_reg (FP_REGNO, cfa_store_offset, cfa_store_reg);
+ }
+
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ {
+ if (MUST_SAVE_REGISTER (i) && i != FP_REGNO && i != RA_REGNO)
+ {
+ cfa_store_offset -= 4;
+ save_reg (i, cfa_store_offset, cfa_store_reg);
+ }
+ }
+
+ if (frame_pointer_needed)
+ {
+ insn = emit_insn (gen_rtx_SET (SImode,
+ gen_rtx_REG (SImode, FP_REGNO),
+ gen_rtx_REG (SImode, SP_REGNO)));
+
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+
+ /* If we are profiling, make sure no instructions are scheduled before
+ the call to mcount. */
+ if (current_function_profile)
+ emit_insn (gen_blockage ());
+}
+
+void
+expand_epilogue (bool sibcall_p)
+{
+ rtx insn;
+ int i;
+ HOST_WIDE_INT total_frame_size;
+ int register_store_offset;
+
+ total_frame_size = compute_frame_size ();
+
+ if (!sibcall_p && nios2_can_use_return_insn ())
+ {
+ insn = emit_jump_insn (gen_return ());
+ return;
+ }
+
+ emit_insn (gen_blockage ());
+
+ register_store_offset =
+ cfun->machine->frame.save_regs_offset +
+ cfun->machine->frame.save_reg_rounded;
+
+ if (MUST_SAVE_REGISTER (RA_REGNO))
+ {
+ register_store_offset -= 4;
+ restore_reg (RA_REGNO, register_store_offset);
+ }
+
+ if (MUST_SAVE_REGISTER (FP_REGNO))
+ {
+ register_store_offset -= 4;
+ restore_reg (FP_REGNO, register_store_offset);
+ }
+
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ {
+ if (MUST_SAVE_REGISTER (i) && i != FP_REGNO && i != RA_REGNO)
+ {
+ register_store_offset -= 4;
+ restore_reg (i, register_store_offset);
+ }
+ }
+
+ if (total_frame_size)
+ {
+ rtx sp_adjust;
+
+ if (TOO_BIG_OFFSET (total_frame_size))
+ {
+ sp_adjust = gen_rtx_REG (SImode, TEMP_REG_NUM);
+ insn = emit_insn (gen_rtx_SET (SImode,
+ sp_adjust,
+ GEN_INT (total_frame_size)));
+
+ }
+ else
+ {
+ sp_adjust = GEN_INT (total_frame_size);
+ }
+
+ insn = gen_rtx_SET (SImode,
+ stack_pointer_rtx,
+ gen_rtx_PLUS (SImode,
+ stack_pointer_rtx,
+ sp_adjust));
+ insn = emit_insn (insn);
+ }
+
+
+ if (!sibcall_p)
+ {
+ insn = emit_jump_insn (gen_return_from_epilogue (gen_rtx (REG, Pmode,
+ RA_REGNO)));
+ }
+}
+
+
+bool
+nios2_function_ok_for_sibcall (tree a ATTRIBUTE_UNUSED, tree b ATTRIBUTE_UNUSED)
+{
+ return true;
+}
+
+
+
+
+
+/* ----------------------- *
+ * Profiling
+ * ----------------------- */
+
+void
+function_profiler (FILE *file, int labelno)
+{
+ fprintf (file, "\t%s mcount begin, label: .LP%d\n",
+ ASM_COMMENT_START, labelno);
+ fprintf (file, "\tnextpc\tr8\n");
+ fprintf (file, "\tmov\tr9, ra\n");
+ fprintf (file, "\tmovhi\tr10, %%hiadj(.LP%d)\n", labelno);
+ fprintf (file, "\taddi\tr10, r10, %%lo(.LP%d)\n", labelno);
+ fprintf (file, "\tcall\tmcount\n");
+ fprintf (file, "\tmov\tra, r9\n");
+ fprintf (file, "\t%s mcount end\n", ASM_COMMENT_START);
+}
+
+
+/***************************************
+ * Stack Layout
+ ***************************************/
+
+
+void
+dump_frame_size (FILE *file)
+{
+ fprintf (file, "\t%s Current Frame Info\n", ASM_COMMENT_START);
+
+ fprintf (file, "\t%s total_size = %ld\n", ASM_COMMENT_START,
+ cfun->machine->frame.total_size);
+ fprintf (file, "\t%s var_size = %ld\n", ASM_COMMENT_START,
+ cfun->machine->frame.var_size);
+ fprintf (file, "\t%s args_size = %ld\n", ASM_COMMENT_START,
+ cfun->machine->frame.args_size);
+ fprintf (file, "\t%s save_reg_size = %d\n", ASM_COMMENT_START,
+ cfun->machine->frame.save_reg_size);
+ fprintf (file, "\t%s save_reg_rounded = %d\n", ASM_COMMENT_START,
+ cfun->machine->frame.save_reg_rounded);
+ fprintf (file, "\t%s initialized = %d\n", ASM_COMMENT_START,
+ cfun->machine->frame.initialized);
+ fprintf (file, "\t%s num_regs = %d\n", ASM_COMMENT_START,
+ cfun->machine->frame.num_regs);
+ fprintf (file, "\t%s save_regs_offset = %ld\n", ASM_COMMENT_START,
+ cfun->machine->frame.save_regs_offset);
+ fprintf (file, "\t%s current_function_is_leaf = %d\n", ASM_COMMENT_START,
+ current_function_is_leaf);
+ fprintf (file, "\t%s frame_pointer_needed = %d\n", ASM_COMMENT_START,
+ frame_pointer_needed);
+ fprintf (file, "\t%s pretend_args_size = %d\n", ASM_COMMENT_START,
+ current_function_pretend_args_size);
+
+}
+
+
+/* Return the bytes needed to compute the frame pointer from the current
+ stack pointer.
+*/
+
+HOST_WIDE_INT
+compute_frame_size ()
+{
+ unsigned int regno;
+ HOST_WIDE_INT var_size; /* # of var. bytes allocated */
+ HOST_WIDE_INT total_size; /* # bytes that the entire frame takes up */
+ HOST_WIDE_INT save_reg_size; /* # bytes needed to store callee save regs */
+ HOST_WIDE_INT save_reg_rounded;
+ /* # bytes needed to store callee save regs (rounded) */
+ HOST_WIDE_INT out_args_size; /* # bytes needed for outgoing args */
+
+ save_reg_size = 0;
+ var_size = STACK_ALIGN (get_frame_size ());
+ out_args_size = STACK_ALIGN (current_function_outgoing_args_size);
+
+ total_size = var_size + out_args_size;
+
+ /* Calculate space needed for gp registers. */
+ for (regno = 0; regno <= FIRST_PSEUDO_REGISTER; regno++)
+ {
+ if (MUST_SAVE_REGISTER (regno))
+ {
+ save_reg_size += 4;
+ }
+ }
+
+ save_reg_rounded = STACK_ALIGN (save_reg_size);
+ total_size += save_reg_rounded;
+
+ total_size += STACK_ALIGN (current_function_pretend_args_size);
+
+ /* Save other computed information. */
+ cfun->machine->frame.total_size = total_size;
+ cfun->machine->frame.var_size = var_size;
+ cfun->machine->frame.args_size = current_function_outgoing_args_size;
+ cfun->machine->frame.save_reg_size = save_reg_size;
+ cfun->machine->frame.save_reg_rounded = save_reg_rounded;
+ cfun->machine->frame.initialized = reload_completed;
+ cfun->machine->frame.num_regs = save_reg_size / UNITS_PER_WORD;
+
+ cfun->machine->frame.save_regs_offset
+ = save_reg_rounded ? current_function_outgoing_args_size + var_size : 0;
+
+ return total_size;
+}
+
+
+int
+nios2_initial_elimination_offset (int from, int to ATTRIBUTE_UNUSED)
+{
+ int offset;
+
+ /* Set OFFSET to the offset from the stack pointer. */
+ switch (from)
+ {
+ case FRAME_POINTER_REGNUM:
+ offset = 0;
+ break;
+
+ case ARG_POINTER_REGNUM:
+ compute_frame_size ();
+ offset = cfun->machine->frame.total_size;
+ offset -= current_function_pretend_args_size;
+ break;
+
+ case RETURN_ADDRESS_POINTER_REGNUM:
+ compute_frame_size ();
+ /* since the return address is always the first of the
+ saved registers, return the offset to the beginning
+ of the saved registers block */
+ offset = cfun->machine->frame.save_regs_offset;
+ break;
+
+ default:
+ abort ();
+ }
+
+ return offset;
+}
+
+/* Return nonzero if this function is known to have a null epilogue.
+ This allows the optimizer to omit jumps to jumps if no stack
+ was created. */
+int
+nios2_can_use_return_insn ()
+{
+ if (!reload_completed)
+ return 0;
+
+ if (regs_ever_live[RA_REGNO] || current_function_profile)
+ return 0;
+
+ if (cfun->machine->frame.initialized)
+ return cfun->machine->frame.total_size == 0;
+
+ return compute_frame_size () == 0;
+}
+
+
+
+
+
+/***************************************
+ *
+ ***************************************/
+
+const char *nios2_sys_nosys_string; /* for -msys=nosys */
+const char *nios2_sys_lib_string; /* for -msys-lib= */
+const char *nios2_sys_crt0_string; /* for -msys-crt0= */
+
+void
+override_options ()
+{
+ /* Function to allocate machine-dependent function status. */
+ init_machine_status = &nios2_init_machine_status;
+
+ nios2_section_threshold
+ = g_switch_set ? g_switch_value : NIOS2_DEFAULT_GVALUE;
+
+ if (nios2_sys_nosys_string && *nios2_sys_nosys_string)
+ {
+ error ("invalid option '-msys=nosys%s'", nios2_sys_nosys_string);
+ }
+
+ /* If we don't have mul, we don't have mulx either! */
+ if (!TARGET_HAS_MUL && TARGET_HAS_MULX)
+ {
+ target_flags &= ~HAS_MULX_FLAG;
+ }
+
+}
+
+void
+optimization_options (int level, int size)
+{
+ if (level || size)
+ {
+ target_flags |= INLINE_MEMCPY_FLAG;
+ }
+
+ if (level >= 3 && !size)
+ {
+ target_flags |= FAST_SW_DIV_FLAG;
+ }
+}
+
+/* Allocate a chunk of memory for per-function machine-dependent data. */
+static struct machine_function *
+nios2_init_machine_status ()
+{
+ return ((struct machine_function *)
+ ggc_alloc_cleared (sizeof (struct machine_function)));
+}
+
+
+
+/*****************
+ * Describing Relative Costs of Operations
+ *****************/
+
+/* Compute a (partial) cost for rtx X. Return true if the complete
+ cost has been computed, and false if subexpressions should be
+ scanned. In either case, *TOTAL contains the cost result. */
+
+
+
+static bool
+nios2_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total)
+{
+ switch (code)
+ {
+ case CONST_INT:
+ if (INTVAL (x) == 0)
+ {
+ *total = COSTS_N_INSNS (0);
+ return true;
+ }
+ else if (SMALL_INT (INTVAL (x))
+ || SMALL_INT_UNSIGNED (INTVAL (x))
+ || UPPER16_INT (INTVAL (x)))
+ {
+ *total = COSTS_N_INSNS (2);
+ return true;
+ }
+ else
+ {
+ *total = COSTS_N_INSNS (4);
+ return true;
+ }
+
+ case LABEL_REF:
+ case SYMBOL_REF:
+ /* ??? gp relative stuff will fit in here */
+ /* fall through */
+ case CONST:
+ case CONST_DOUBLE:
+ {
+ *total = COSTS_N_INSNS (4);
+ return true;
+ }
+
+ case MULT:
+ {
+ *total = COSTS_N_INSNS (1);
+ return false;
+ }
+ case SIGN_EXTEND:
+ {
+ *total = COSTS_N_INSNS (3);
+ return false;
+ }
+ case ZERO_EXTEND:
+ {
+ *total = COSTS_N_INSNS (1);
+ return false;
+ }
+
+ default:
+ return false;
+ }
+}
+
+
+/***************************************
+ * INSTRUCTION SUPPORT
+ *
+ * These functions are used within the Machine Description to
+ * handle common or complicated output and expansions from
+ * instructions.
+ ***************************************/
+
+int
+nios2_emit_move_sequence (rtx *operands, enum machine_mode mode)
+{
+ rtx to = operands[0];
+ rtx from = operands[1];
+
+ if (!register_operand (to, mode) && !reg_or_0_operand (from, mode))
+ {
+ if (no_new_pseudos)
+ internal_error ("Trying to force_reg no_new_pseudos == 1");
+ from = copy_to_mode_reg (mode, from);
+ }
+
+ operands[0] = to;
+ operands[1] = from;
+ return 0;
+}
+
+/* Divide Support */
+
+/*
+ If -O3 is used, we want to output a table lookup for
+ divides between small numbers (both num and den >= 0
+ and < 0x10). The overhead of this method in the worse
+ case is 40 bytes in the text section (10 insns) and
+ 256 bytes in the data section. Additional divides do
+ not incur additional penalties in the data section.
+
+ Code speed is improved for small divides by about 5x
+ when using this method in the worse case (~9 cycles
+ vs ~45). And in the worse case divides not within the
+ table are penalized by about 10% (~5 cycles vs ~45).
+ However in the typical case the penalty is not as bad
+ because doing the long divide in only 45 cycles is
+ quite optimistic.
+
+ ??? It would be nice to have some benchmarks other
+ than Dhrystone to back this up.
+
+ This bit of expansion is to create this instruction
+ sequence as rtl.
+ or $8, $4, $5
+ slli $9, $4, 4
+ cmpgeui $3, $8, 16
+ beq $3, $0, .L3
+ or $10, $9, $5
+ add $12, $11, divide_table
+ ldbu $2, 0($12)
+ br .L1
+.L3:
+ call slow_div
+.L1:
+# continue here with result in $2
+
+ ??? Ideally I would like the emit libcall block to contain
+ all of this code, but I don't know how to do that. What it
+ means is that if the divide can be eliminated, it may not
+ completely disappear.
+
+ ??? The __divsi3_table label should ideally be moved out
+ of this block and into a global. If it is placed into the
+ sdata section we can save even more cycles by doing things
+ gp relative.
+*/
+int
+nios2_emit_expensive_div (rtx *operands, enum machine_mode mode)
+{
+ rtx or_result, shift_left_result;
+ rtx lookup_value;
+ rtx lab1, lab3;
+ rtx insns;
+ rtx libfunc;
+ rtx final_result;
+ rtx tmp;
+
+ /* it may look a little generic, but only SImode
+ is supported for now */
+ if (mode != SImode)
+ abort ();
+
+ libfunc = sdiv_optab->handlers[(int) SImode].libfunc;
+
+
+
+ lab1 = gen_label_rtx ();
+ lab3 = gen_label_rtx ();
+
+ or_result = expand_simple_binop (SImode, IOR,
+ operands[1], operands[2],
+ 0, 0, OPTAB_LIB_WIDEN);
+
+ emit_cmp_and_jump_insns (or_result, GEN_INT (15), GTU, 0,
+ GET_MODE (or_result), 0, lab3);
+ JUMP_LABEL (get_last_insn ()) = lab3;
+
+ shift_left_result = expand_simple_binop (SImode, ASHIFT,
+ operands[1], GEN_INT (4),
+ 0, 0, OPTAB_LIB_WIDEN);
+
+ lookup_value = expand_simple_binop (SImode, IOR,
+ shift_left_result, operands[2],
+ 0, 0, OPTAB_LIB_WIDEN);
+
+ convert_move (operands[0],
+ gen_rtx (MEM, QImode,
+ gen_rtx (PLUS, SImode,
+ lookup_value,
+ gen_rtx_SYMBOL_REF (SImode, "__divsi3_table"))),
+ 1);
+
+
+ tmp = emit_jump_insn (gen_jump (lab1));
+ JUMP_LABEL (tmp) = lab1;
+ emit_barrier ();
+
+ emit_label (lab3);
+ LABEL_NUSES (lab3) = 1;
+
+ start_sequence ();
+ final_result = emit_library_call_value (libfunc, NULL_RTX,
+ LCT_CONST, SImode, 2,
+ operands[1], SImode,
+ operands[2], SImode);
+
+
+ insns = get_insns ();
+ end_sequence ();
+ emit_libcall_block (insns, operands[0], final_result,
+ gen_rtx (DIV, SImode, operands[1], operands[2]));
+
+ emit_label (lab1);
+ LABEL_NUSES (lab1) = 1;
+ return 1;
+}
+
+/* Branches/Compares */
+
+/* the way of handling branches/compares
+ in gcc is heavily borrowed from MIPS */
+
+enum internal_test
+{
+ ITEST_EQ,
+ ITEST_NE,
+ ITEST_GT,
+ ITEST_GE,
+ ITEST_LT,
+ ITEST_LE,
+ ITEST_GTU,
+ ITEST_GEU,
+ ITEST_LTU,
+ ITEST_LEU,
+ ITEST_MAX
+};
+
+static enum internal_test map_test_to_internal_test (enum rtx_code);
+
+/* Cached operands, and operator to compare for use in set/branch/trap
+ on condition codes. */
+rtx branch_cmp[2];
+enum cmp_type branch_type;
+
+/* Make normal rtx_code into something we can index from an array */
+
+static enum internal_test
+map_test_to_internal_test (enum rtx_code test_code)
+{
+ enum internal_test test = ITEST_MAX;
+
+ switch (test_code)
+ {
+ case EQ:
+ test = ITEST_EQ;
+ break;
+ case NE:
+ test = ITEST_NE;
+ break;
+ case GT:
+ test = ITEST_GT;
+ break;
+ case GE:
+ test = ITEST_GE;
+ break;
+ case LT:
+ test = ITEST_LT;
+ break;
+ case LE:
+ test = ITEST_LE;
+ break;
+ case GTU:
+ test = ITEST_GTU;
+ break;
+ case GEU:
+ test = ITEST_GEU;
+ break;
+ case LTU:
+ test = ITEST_LTU;
+ break;
+ case LEU:
+ test = ITEST_LEU;
+ break;
+ default:
+ break;
+ }
+
+ return test;
+}
+
+/* Generate the code to compare (and possibly branch) two integer values
+ TEST_CODE is the comparison code we are trying to emulate
+ (or implement directly)
+ RESULT is where to store the result of the comparison,
+ or null to emit a branch
+ CMP0 CMP1 are the two comparison operands
+ DESTINATION is the destination of the branch, or null to only compare
+ */
+
+void
+gen_int_relational (enum rtx_code test_code, /* relational test (EQ, etc) */
+ rtx result, /* result to store comp. or 0 if branch */
+ rtx cmp0, /* first operand to compare */
+ rtx cmp1, /* second operand to compare */
+ rtx destination) /* destination of the branch, or 0 if compare */
+{
+ struct cmp_info
+ {
+ /* for register (or 0) compares */
+ enum rtx_code test_code_reg; /* code to use in instruction (LT vs. LTU) */
+ int reverse_regs; /* reverse registers in test */
+
+ /* for immediate compares */
+ enum rtx_code test_code_const;
+ /* code to use in instruction (LT vs. LTU) */
+ int const_low; /* low bound of constant we can accept */
+ int const_high; /* high bound of constant we can accept */
+ int const_add; /* constant to add */
+
+ /* generic info */
+ int unsignedp; /* != 0 for unsigned comparisons. */
+ };
+
+ static const struct cmp_info info[(int) ITEST_MAX] = {
+
+ {EQ, 0, EQ, -32768, 32767, 0, 0}, /* EQ */
+ {NE, 0, NE, -32768, 32767, 0, 0}, /* NE */
+
+ {LT, 1, GE, -32769, 32766, 1, 0}, /* GT */
+ {GE, 0, GE, -32768, 32767, 0, 0}, /* GE */
+ {LT, 0, LT, -32768, 32767, 0, 0}, /* LT */
+ {GE, 1, LT, -32769, 32766, 1, 0}, /* LE */
+
+ {LTU, 1, GEU, 0, 65534, 1, 0}, /* GTU */
+ {GEU, 0, GEU, 0, 65535, 0, 0}, /* GEU */
+ {LTU, 0, LTU, 0, 65535, 0, 0}, /* LTU */
+ {GEU, 1, LTU, 0, 65534, 1, 0}, /* LEU */
+ };
+
+ enum internal_test test;
+ enum machine_mode mode;
+ const struct cmp_info *p_info;
+ int branch_p;
+
+
+
+
+ test = map_test_to_internal_test (test_code);
+ if (test == ITEST_MAX)
+ abort ();
+
+ p_info = &info[(int) test];
+
+ mode = GET_MODE (cmp0);
+ if (mode == VOIDmode)
+ mode = GET_MODE (cmp1);
+
+ branch_p = (destination != 0);
+
+ /* We can't, under any circumstances, have const_ints in cmp0
+ ??? Actually we could have const0 */
+ if (GET_CODE (cmp0) == CONST_INT)
+ cmp0 = force_reg (mode, cmp0);
+
+ /* if the comparison is against an int not in legal range
+ move it into a register */
+ if (GET_CODE (cmp1) == CONST_INT)
+ {
+ HOST_WIDE_INT value = INTVAL (cmp1);
+
+ if (value < p_info->const_low || value > p_info->const_high)
+ cmp1 = force_reg (mode, cmp1);
+ }
+
+ /* Comparison to constants, may involve adding 1 to change a GT into GE.
+ Comparison between two registers, may involve switching operands. */
+ if (GET_CODE (cmp1) == CONST_INT)
+ {
+ if (p_info->const_add != 0)
+ {
+ HOST_WIDE_INT new = INTVAL (cmp1) + p_info->const_add;
+
+ /* If modification of cmp1 caused overflow,
+ we would get the wrong answer if we follow the usual path;
+ thus, x > 0xffffffffU would turn into x > 0U. */
+ if ((p_info->unsignedp
+ ? (unsigned HOST_WIDE_INT) new >
+ (unsigned HOST_WIDE_INT) INTVAL (cmp1)
+ : new > INTVAL (cmp1)) != (p_info->const_add > 0))
+ {
+ /* ??? This case can never happen with the current numbers,
+ but I am paranoid and would rather an abort than
+ a bug I will never find */
+ abort ();
+ }
+ else
+ cmp1 = GEN_INT (new);
+ }
+ }
+
+ else if (p_info->reverse_regs)
+ {
+ rtx temp = cmp0;
+ cmp0 = cmp1;
+ cmp1 = temp;
+ }
+
+
+
+ if (branch_p)
+ {
+ if (register_operand (cmp0, mode) && register_operand (cmp1, mode))
+ {
+ rtx insn;
+ rtx cond = gen_rtx (p_info->test_code_reg, mode, cmp0, cmp1);
+ rtx label = gen_rtx_LABEL_REF (VOIDmode, destination);
+
+ insn = gen_rtx_SET (VOIDmode, pc_rtx,
+ gen_rtx_IF_THEN_ELSE (VOIDmode,
+ cond, label, pc_rtx));
+ emit_jump_insn (insn);
+ }
+ else
+ {
+ rtx cond, label;
+
+ result = gen_reg_rtx (mode);
+
+ emit_move_insn (result,
+ gen_rtx (p_info->test_code_const, mode, cmp0,
+ cmp1));
+
+ cond = gen_rtx (NE, mode, result, const0_rtx);
+ label = gen_rtx_LABEL_REF (VOIDmode, destination);
+
+ emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
+ gen_rtx_IF_THEN_ELSE (VOIDmode,
+ cond,
+ label, pc_rtx)));
+ }
+ }
+ else
+ {
+ if (register_operand (cmp0, mode) && register_operand (cmp1, mode))
+ {
+ emit_move_insn (result,
+ gen_rtx (p_info->test_code_reg, mode, cmp0, cmp1));
+ }
+ else
+ {
+ emit_move_insn (result,
+ gen_rtx (p_info->test_code_const, mode, cmp0,
+ cmp1));
+ }
+ }
+
+}
+
+
+/* ??? For now conditional moves are only supported
+ when the mode of the operands being compared are
+ the same as the ones being moved */
+
+void
+gen_conditional_move (rtx *operands, enum machine_mode mode)
+{
+ rtx insn, cond;
+ rtx cmp_reg = gen_reg_rtx (mode);
+ enum rtx_code cmp_code = GET_CODE (operands[1]);
+ enum rtx_code move_code = EQ;
+
+ /* emit a comparison if it is not "simple".
+ Simple comparisons are X eq 0 and X ne 0 */
+ if ((cmp_code == EQ || cmp_code == NE) && branch_cmp[1] == const0_rtx)
+ {
+ cmp_reg = branch_cmp[0];
+ move_code = cmp_code;
+ }
+ else if ((cmp_code == EQ || cmp_code == NE) && branch_cmp[0] == const0_rtx)
+ {
+ cmp_reg = branch_cmp[1];
+ move_code = cmp_code == EQ ? NE : EQ;
+ }
+ else
+ gen_int_relational (cmp_code, cmp_reg, branch_cmp[0], branch_cmp[1],
+ NULL_RTX);
+
+ cond = gen_rtx (move_code, VOIDmode, cmp_reg, CONST0_RTX (mode));
+ insn = gen_rtx_SET (mode, operands[0],
+ gen_rtx_IF_THEN_ELSE (mode,
+ cond, operands[2], operands[3]));
+ emit_insn (insn);
+}
+
+/*******************
+ * Addressing Modes
+ *******************/
+
+int
+nios2_legitimate_address (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED,
+ int strict)
+{
+ int ret_val = 0;
+
+ switch (GET_CODE (operand))
+ {
+ /* direct. */
+ case SYMBOL_REF:
+ if (SYMBOL_REF_IN_NIOS2_SMALL_DATA_P (operand))
+ {
+ ret_val = 1;
+ break;
+ }
+ /* else, fall through */
+ case LABEL_REF:
+ case CONST_INT:
+ case CONST:
+ case CONST_DOUBLE:
+ /* ??? In here I need to add gp addressing */
+ ret_val = 0;
+
+ break;
+
+ /* Register indirect. */
+ case REG:
+ ret_val = REG_OK_FOR_BASE_P2 (operand, strict);
+ break;
+
+ /* Register indirect with displacement */
+ case PLUS:
+ {
+ rtx op0 = XEXP (operand, 0);
+ rtx op1 = XEXP (operand, 1);
+
+ if (REG_P (op0) && REG_P (op1))
+ ret_val = 0;
+ else if (REG_P (op0) && CONSTANT_P (op1))
+ ret_val = REG_OK_FOR_BASE_P2 (op0, strict)
+ && SMALL_INT (INTVAL (op1));
+ else if (REG_P (op1) && CONSTANT_P (op0))
+ ret_val = REG_OK_FOR_BASE_P2 (op1, strict)
+ && SMALL_INT (INTVAL (op0));
+ else
+ ret_val = 0;
+ }
+ break;
+
+ default:
+ ret_val = 0;
+ break;
+ }
+
+ return ret_val;
+}
+
+/* Return true if EXP should be placed in the small data section. */
+
+static bool
+nios2_in_small_data_p (tree exp)
+{
+ /* We want to merge strings, so we never consider them small data. */
+ if (TREE_CODE (exp) == STRING_CST)
+ return false;
+
+ if (TREE_CODE (exp) == VAR_DECL && DECL_SECTION_NAME (exp))
+ {
+ const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (exp));
+ /* ??? these string names need moving into
+ an array in some header file */
+ if (nios2_section_threshold > 0
+ && (strcmp (section, ".sbss") == 0
+ || strncmp (section, ".sbss.", 6) == 0
+ || strcmp (section, ".sdata") == 0
+ || strncmp (section, ".sdata.", 7) == 0))
+ return true;
+ }
+ else if (TREE_CODE (exp) == VAR_DECL)
+ {
+ HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp));
+
+ /* If this is an incomplete type with size 0, then we can't put it
+ in sdata because it might be too big when completed. */
+ if (size > 0 && size <= nios2_section_threshold)
+ return true;
+ }
+
+ return false;
+}
+
+static void
+nios2_encode_section_info (tree decl, rtx rtl, int first)
+{
+
+ rtx symbol;
+ int flags;
+
+ default_encode_section_info (decl, rtl, first);
+
+ /* Careful not to prod global register variables. */
+ if (GET_CODE (rtl) != MEM)
+ return;
+ symbol = XEXP (rtl, 0);
+ if (GET_CODE (symbol) != SYMBOL_REF)
+ return;
+
+ flags = SYMBOL_REF_FLAGS (symbol);
+
+ /* We don't want weak variables to be addressed with gp in case they end up with
+ value 0 which is not within 2^15 of $gp */
+ if (DECL_P (decl) && DECL_WEAK (decl))
+ flags |= SYMBOL_FLAG_WEAK_DECL;
+
+ SYMBOL_REF_FLAGS (symbol) = flags;
+}
+
+
+static unsigned int
+nios2_section_type_flags (tree decl, const char *name, int reloc)
+{
+ unsigned int flags;
+
+ flags = default_section_type_flags (decl, name, reloc);
+
+ /* ??? these string names need moving into an array in some header file */
+ if (strcmp (name, ".sbss") == 0
+ || strncmp (name, ".sbss.", 6) == 0
+ || strcmp (name, ".sdata") == 0
+ || strncmp (name, ".sdata.", 7) == 0)
+ flags |= SECTION_SMALL;
+
+ return flags;
+}
+
+
+
+
+/*****************************************
+ * Defining the Output Assembler Language
+ *****************************************/
+
+/* -------------- *
+ * Output of Data
+ * -------------- */
+
+
+/* -------------------------------- *
+ * Output of Assembler Instructions
+ * -------------------------------- */
+
+
+/* print the operand OP to file stream
+ FILE modified by LETTER. LETTER
+ can be one of:
+ i: print "i" if OP is an immediate, except 0
+ o: print "io" if OP is volatile
+
+ z: for const0_rtx print $0 instead of 0
+ H: for %hiadj
+ L: for %lo
+ U: for upper half of 32 bit value
+ */
+
+void
+nios2_print_operand (FILE *file, rtx op, int letter)
+{
+
+ switch (letter)
+ {
+ case 'i':
+ if (CONSTANT_P (op) && (op != const0_rtx))
+ fprintf (file, "i");
+ return;
+
+ case 'o':
+ if (GET_CODE (op) == MEM
+ && ((MEM_VOLATILE_P (op) && !TARGET_CACHE_VOLATILE)
+ || TARGET_BYPASS_CACHE))
+ fprintf (file, "io");
+ return;
+
+ default:
+ break;
+ }
+
+ if (comparison_operator (op, VOIDmode))
+ {
+ if (letter == 0)
+ {
+ fprintf (file, "%s", GET_RTX_NAME (GET_CODE (op)));
+ return;
+ }
+ }
+
+
+ switch (GET_CODE (op))
+ {
+ case REG:
+ if (letter == 0 || letter == 'z')
+ {
+ fprintf (file, "%s", reg_names[REGNO (op)]);
+ return;
+ }
+
+ case CONST_INT:
+ if (INTVAL (op) == 0 && letter == 'z')
+ {
+ fprintf (file, "zero");
+ return;
+ }
+ else if (letter == 'U')
+ {
+ HOST_WIDE_INT val = INTVAL (op);
+ rtx new_op;
+ val = (val / 65536) & 0xFFFF;
+ new_op = GEN_INT (val);
+ output_addr_const (file, new_op);
+ return;
+ }
+
+ /* else, fall through */
+ case CONST:
+ case LABEL_REF:
+ case SYMBOL_REF:
+ case CONST_DOUBLE:
+ if (letter == 0 || letter == 'z')
+ {
+ output_addr_const (file, op);
+ return;
+ }
+ else if (letter == 'H')
+ {
+ fprintf (file, "%%hiadj(");
+ output_addr_const (file, op);
+ fprintf (file, ")");
+ return;
+ }
+ else if (letter == 'L')
+ {
+ fprintf (file, "%%lo(");
+ output_addr_const (file, op);
+ fprintf (file, ")");
+ return;
+ }
+
+
+ case SUBREG:
+ case MEM:
+ if (letter == 0)
+ {
+ output_address (op);
+ return;
+ }
+
+ case CODE_LABEL:
+ if (letter == 0)
+ {
+ output_addr_const (file, op);
+ return;
+ }
+
+ default:
+ break;
+ }
+
+ fprintf (stderr, "Missing way to print (%c) ", letter);
+ debug_rtx (op);
+ abort ();
+}
+
+static int gprel_constant (rtx);
+
+static int
+gprel_constant (rtx op)
+{
+ if (GET_CODE (op) == SYMBOL_REF
+ && SYMBOL_REF_IN_NIOS2_SMALL_DATA_P (op))
+ {
+ return 1;
+ }
+ else if (GET_CODE (op) == CONST
+ && GET_CODE (XEXP (op, 0)) == PLUS)
+ {
+ return gprel_constant (XEXP (XEXP (op, 0), 0));
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+void
+nios2_print_operand_address (FILE *file, rtx op)
+{
+ switch (GET_CODE (op))
+ {
+ case CONST:
+ case CONST_INT:
+ case LABEL_REF:
+ case CONST_DOUBLE:
+ case SYMBOL_REF:
+ if (gprel_constant (op))
+ {
+ fprintf (file, "%%gprel(");
+ output_addr_const (file, op);
+ fprintf (file, ")(%s)", reg_names[GP_REGNO]);
+ return;
+ }
+
+ break;
+
+ case PLUS:
+ {
+ rtx op0 = XEXP (op, 0);
+ rtx op1 = XEXP (op, 1);
+
+ if (REG_P (op0) && CONSTANT_P (op1))
+ {
+ output_addr_const (file, op1);
+ fprintf (file, "(%s)", reg_names[REGNO (op0)]);
+ return;
+ }
+ else if (REG_P (op1) && CONSTANT_P (op0))
+ {
+ output_addr_const (file, op0);
+ fprintf (file, "(%s)", reg_names[REGNO (op1)]);
+ return;
+ }
+ }
+ break;
+
+ case REG:
+ fprintf (file, "0(%s)", reg_names[REGNO (op)]);
+ return;
+
+ case MEM:
+ {
+ rtx base = XEXP (op, 0);
+ PRINT_OPERAND_ADDRESS (file, base);
+ return;
+ }
+ default:
+ break;
+ }
+
+ fprintf (stderr, "Missing way to print address\n");
+ debug_rtx (op);
+ abort ();
+}
+
+
+
+
+
+/****************************
+ * Predicates
+ ****************************/
+
+int
+arith_operand (rtx op, enum machine_mode mode)
+{
+ if (GET_CODE (op) == CONST_INT && SMALL_INT (INTVAL (op)))
+ return 1;
+
+ return register_operand (op, mode);
+}
+
+int
+uns_arith_operand (rtx op, enum machine_mode mode)
+{
+ if (GET_CODE (op) == CONST_INT && SMALL_INT_UNSIGNED (INTVAL (op)))
+ return 1;
+
+ return register_operand (op, mode);
+}
+
+int
+logical_operand (rtx op, enum machine_mode mode)
+{
+ if (GET_CODE (op) == CONST_INT
+ && (SMALL_INT_UNSIGNED (INTVAL (op)) || UPPER16_INT (INTVAL (op))))
+ return 1;
+
+ return register_operand (op, mode);
+}
+
+int
+shift_operand (rtx op, enum machine_mode mode)
+{
+ if (GET_CODE (op) == CONST_INT && SHIFT_INT (INTVAL (op)))
+ return 1;
+
+ return register_operand (op, mode);
+}
+
+int
+rdwrctl_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+ return GET_CODE (op) == CONST_INT && RDWRCTL_INT (INTVAL (op));
+}
+
+/* Return truth value of whether OP is a register or the constant 0. */
+
+int
+reg_or_0_operand (rtx op, enum machine_mode mode)
+{
+ switch (GET_CODE (op))
+ {
+ case CONST_INT:
+ return INTVAL (op) == 0;
+
+ case CONST_DOUBLE:
+ return op == CONST0_RTX (mode);
+
+ default:
+ break;
+ }
+
+ return register_operand (op, mode);
+}
+
+
+int
+equality_op (rtx op, enum machine_mode mode)
+{
+ if (mode != GET_MODE (op))
+ return 0;
+
+ return GET_CODE (op) == EQ || GET_CODE (op) == NE;
+}
+
+int
+custom_insn_opcode (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+ return GET_CODE (op) == CONST_INT && CUSTOM_INSN_OPCODE (INTVAL (op));
+}
+
+
+
+
+
+
+
+/*****************************************************************************
+**
+** instruction scheduler
+**
+*****************************************************************************/
+static int
+nios2_use_dfa_pipeline_interface ()
+{
+ return 1;
+}
+
+
+static int
+nios2_issue_rate ()
+{
+#ifdef MAX_DFA_ISSUE_RATE
+ return MAX_DFA_ISSUE_RATE;
+#else
+ return 1;
+#endif
+}
+
+
+const char *
+asm_output_opcode (FILE *file ATTRIBUTE_UNUSED,
+ const char *ptr ATTRIBUTE_UNUSED)
+{
+ const char *p;
+
+ p = ptr;
+ return ptr;
+}
+
+
+
+/*****************************************************************************
+**
+** function arguments
+**
+*****************************************************************************/
+
+void
+init_cumulative_args (CUMULATIVE_ARGS *cum,
+ tree fntype ATTRIBUTE_UNUSED,
+ rtx libname ATTRIBUTE_UNUSED,
+ tree fndecl ATTRIBUTE_UNUSED,
+ int n_named_args ATTRIBUTE_UNUSED)
+{
+ cum->regs_used = 0;
+}
+
+
+/* Update the data in CUM to advance over an argument
+ of mode MODE and data type TYPE.
+ (TYPE is null for libcalls where that information may not be available.) */
+
+void
+function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+ tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED)
+{
+ HOST_WIDE_INT param_size;
+
+ if (mode == BLKmode)
+ {
+ param_size = int_size_in_bytes (type);
+ if (param_size < 0)
+ internal_error
+ ("Do not know how to handle large structs or variable length types");
+ }
+ else
+ {
+ param_size = GET_MODE_SIZE (mode);
+ }
+
+ /* convert to words (round up) */
+ param_size = (3 + param_size) / 4;
+
+ if (cum->regs_used + param_size > NUM_ARG_REGS)
+ {
+ cum->regs_used = NUM_ARG_REGS;
+ }
+ else
+ {
+ cum->regs_used += param_size;
+ }
+
+ return;
+}
+
+/* Define where to put the arguments to a function. Value is zero to
+ push the argument on the stack, or a hard register in which to
+ store the argument.
+
+ MODE is the argument's machine mode.
+ TYPE is the data type of the argument (as a tree).
+ This is null for libcalls where that information may
+ not be available.
+ CUM is a variable of type CUMULATIVE_ARGS which gives info about
+ the preceding args and about the function being called.
+ NAMED is nonzero if this argument is a named parameter
+ (otherwise it is an extra parameter matching an ellipsis). */
+rtx
+function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
+ tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED)
+{
+ rtx return_rtx = NULL_RTX;
+
+ if (cum->regs_used < NUM_ARG_REGS)
+ {
+ return_rtx = gen_rtx_REG (mode, FIRST_ARG_REGNO + cum->regs_used);
+ }
+
+ return return_rtx;
+}
+
+int
+function_arg_partial_nregs (const CUMULATIVE_ARGS *cum,
+ enum machine_mode mode, tree type,
+ int named ATTRIBUTE_UNUSED)
+{
+ HOST_WIDE_INT param_size;
+
+ if (mode == BLKmode)
+ {
+ param_size = int_size_in_bytes (type);
+ if (param_size < 0)
+ internal_error
+ ("Do not know how to handle large structs or variable length types");
+ }
+ else
+ {
+ param_size = GET_MODE_SIZE (mode);
+ }
+
+ /* convert to words (round up) */
+ param_size = (3 + param_size) / 4;
+
+ if (cum->regs_used < NUM_ARG_REGS
+ && cum->regs_used + param_size > NUM_ARG_REGS)
+ {
+ return NUM_ARG_REGS - cum->regs_used;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+
+int
+nios2_return_in_memory (tree type)
+{
+ int res = ((int_size_in_bytes (type) > (2 * UNITS_PER_WORD))
+ || (int_size_in_bytes (type) == -1));
+
+ return res;
+}
+
+/* ??? It may be possible to eliminate the copyback and implement
+ my own va_arg type, but that is more work for now. */
+int
+nios2_setup_incoming_varargs (const CUMULATIVE_ARGS *cum,
+ enum machine_mode mode, tree type,
+ int no_rtl)
+{
+ CUMULATIVE_ARGS local_cum;
+ int regs_to_push;
+
+ local_cum = *cum;
+ FUNCTION_ARG_ADVANCE (local_cum, mode, type, 1);
+
+ regs_to_push = NUM_ARG_REGS - local_cum.regs_used;
+
+ if (!no_rtl)
+ {
+ if (regs_to_push > 0)
+ {
+ rtx ptr, mem;
+
+ ptr = virtual_incoming_args_rtx;
+ mem = gen_rtx_MEM (BLKmode, ptr);
+
+ /* va_arg is an array access in this case, which causes
+ it to get MEM_IN_STRUCT_P set. We must set it here
+ so that the insn scheduler won't assume that these
+ stores can't possibly overlap with the va_arg loads. */
+ MEM_SET_IN_STRUCT_P (mem, 1);
+
+ emit_insn (gen_blockage ());
+ move_block_from_reg (local_cum.regs_used + FIRST_ARG_REGNO, mem,
+ regs_to_push);
+ emit_insn (gen_blockage ());
+ }
+ }
+
+ return regs_to_push * UNITS_PER_WORD;
+
+}
+
+
+
+/*****************************************************************************
+**
+** builtins
+**
+** This method for handling builtins is from CSP where _many_ more types of
+** expanders have already been written. Check there first before writing
+** new ones.
+**
+*****************************************************************************/
+
+enum nios2_builtins
+{
+ NIOS2_BUILTIN_LDBIO,
+ NIOS2_BUILTIN_LDBUIO,
+ NIOS2_BUILTIN_LDHIO,
+ NIOS2_BUILTIN_LDHUIO,
+ NIOS2_BUILTIN_LDWIO,
+ NIOS2_BUILTIN_STBIO,
+ NIOS2_BUILTIN_STHIO,
+ NIOS2_BUILTIN_STWIO,
+ NIOS2_BUILTIN_SYNC,
+ NIOS2_BUILTIN_RDCTL,
+ NIOS2_BUILTIN_WRCTL,
+
+ NIOS2_BUILTIN_CUSTOM_N,
+ NIOS2_BUILTIN_CUSTOM_NI,
+ NIOS2_BUILTIN_CUSTOM_NF,
+ NIOS2_BUILTIN_CUSTOM_NP,
+ NIOS2_BUILTIN_CUSTOM_NII,
+ NIOS2_BUILTIN_CUSTOM_NIF,
+ NIOS2_BUILTIN_CUSTOM_NIP,
+ NIOS2_BUILTIN_CUSTOM_NFI,
+ NIOS2_BUILTIN_CUSTOM_NFF,
+ NIOS2_BUILTIN_CUSTOM_NFP,
+ NIOS2_BUILTIN_CUSTOM_NPI,
+ NIOS2_BUILTIN_CUSTOM_NPF,
+ NIOS2_BUILTIN_CUSTOM_NPP,
+ NIOS2_BUILTIN_CUSTOM_IN,
+ NIOS2_BUILTIN_CUSTOM_INI,
+ NIOS2_BUILTIN_CUSTOM_INF,
+ NIOS2_BUILTIN_CUSTOM_INP,
+ NIOS2_BUILTIN_CUSTOM_INII,
+ NIOS2_BUILTIN_CUSTOM_INIF,
+ NIOS2_BUILTIN_CUSTOM_INIP,
+ NIOS2_BUILTIN_CUSTOM_INFI,
+ NIOS2_BUILTIN_CUSTOM_INFF,
+ NIOS2_BUILTIN_CUSTOM_INFP,
+ NIOS2_BUILTIN_CUSTOM_INPI,
+ NIOS2_BUILTIN_CUSTOM_INPF,
+ NIOS2_BUILTIN_CUSTOM_INPP,
+ NIOS2_BUILTIN_CUSTOM_FN,
+ NIOS2_BUILTIN_CUSTOM_FNI,
+ NIOS2_BUILTIN_CUSTOM_FNF,
+ NIOS2_BUILTIN_CUSTOM_FNP,
+ NIOS2_BUILTIN_CUSTOM_FNII,
+ NIOS2_BUILTIN_CUSTOM_FNIF,
+ NIOS2_BUILTIN_CUSTOM_FNIP,
+ NIOS2_BUILTIN_CUSTOM_FNFI,
+ NIOS2_BUILTIN_CUSTOM_FNFF,
+ NIOS2_BUILTIN_CUSTOM_FNFP,
+ NIOS2_BUILTIN_CUSTOM_FNPI,
+ NIOS2_BUILTIN_CUSTOM_FNPF,
+ NIOS2_BUILTIN_CUSTOM_FNPP,
+ NIOS2_BUILTIN_CUSTOM_PN,
+ NIOS2_BUILTIN_CUSTOM_PNI,
+ NIOS2_BUILTIN_CUSTOM_PNF,
+ NIOS2_BUILTIN_CUSTOM_PNP,
+ NIOS2_BUILTIN_CUSTOM_PNII,
+ NIOS2_BUILTIN_CUSTOM_PNIF,
+ NIOS2_BUILTIN_CUSTOM_PNIP,
+ NIOS2_BUILTIN_CUSTOM_PNFI,
+ NIOS2_BUILTIN_CUSTOM_PNFF,
+ NIOS2_BUILTIN_CUSTOM_PNFP,
+ NIOS2_BUILTIN_CUSTOM_PNPI,
+ NIOS2_BUILTIN_CUSTOM_PNPF,
+ NIOS2_BUILTIN_CUSTOM_PNPP,
+
+
+ LIM_NIOS2_BUILTINS
+};
+
+struct builtin_description
+{
+ const enum insn_code icode;
+ const char *const name;
+ const enum nios2_builtins code;
+ const tree *type;
+ rtx (* expander) PARAMS ((const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int));
+};
+
+static rtx nios2_expand_STXIO (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_LDXIO (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_sync (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_rdctl (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_wrctl (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+
+static rtx nios2_expand_custom_n (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_custom_Xn (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_custom_nX (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_custom_XnX (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_custom_nXX (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+static rtx nios2_expand_custom_XnXX (const struct builtin_description *,
+ tree, rtx, rtx, enum machine_mode, int);
+
+static tree endlink;
+
+/* int fn (volatile const void *)
+ */
+static tree int_ftype_volatile_const_void_p;
+
+/* int fn (int)
+ */
+static tree int_ftype_int;
+
+/* void fn (int, int)
+ */
+static tree void_ftype_int_int;
+
+/* void fn (volatile void *, int)
+ */
+static tree void_ftype_volatile_void_p_int;
+
+/* void fn (void)
+ */
+static tree void_ftype_void;
+
+static tree custom_n;
+static tree custom_ni;
+static tree custom_nf;
+static tree custom_np;
+static tree custom_nii;
+static tree custom_nif;
+static tree custom_nip;
+static tree custom_nfi;
+static tree custom_nff;
+static tree custom_nfp;
+static tree custom_npi;
+static tree custom_npf;
+static tree custom_npp;
+static tree custom_in;
+static tree custom_ini;
+static tree custom_inf;
+static tree custom_inp;
+static tree custom_inii;
+static tree custom_inif;
+static tree custom_inip;
+static tree custom_infi;
+static tree custom_inff;
+static tree custom_infp;
+static tree custom_inpi;
+static tree custom_inpf;
+static tree custom_inpp;
+static tree custom_fn;
+static tree custom_fni;
+static tree custom_fnf;
+static tree custom_fnp;
+static tree custom_fnii;
+static tree custom_fnif;
+static tree custom_fnip;
+static tree custom_fnfi;
+static tree custom_fnff;
+static tree custom_fnfp;
+static tree custom_fnpi;
+static tree custom_fnpf;
+static tree custom_fnpp;
+static tree custom_pn;
+static tree custom_pni;
+static tree custom_pnf;
+static tree custom_pnp;
+static tree custom_pnii;
+static tree custom_pnif;
+static tree custom_pnip;
+static tree custom_pnfi;
+static tree custom_pnff;
+static tree custom_pnfp;
+static tree custom_pnpi;
+static tree custom_pnpf;
+static tree custom_pnpp;
+
+
+static const struct builtin_description bdesc[] = {
+ {CODE_FOR_ldbio, "__builtin_ldbio", NIOS2_BUILTIN_LDBIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO},
+ {CODE_FOR_ldbuio, "__builtin_ldbuio", NIOS2_BUILTIN_LDBUIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO},
+ {CODE_FOR_ldhio, "__builtin_ldhio", NIOS2_BUILTIN_LDHIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO},
+ {CODE_FOR_ldhuio, "__builtin_ldhuio", NIOS2_BUILTIN_LDHUIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO},
+ {CODE_FOR_ldwio, "__builtin_ldwio", NIOS2_BUILTIN_LDWIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO},
+
+ {CODE_FOR_stbio, "__builtin_stbio", NIOS2_BUILTIN_STBIO, &void_ftype_volatile_void_p_int, nios2_expand_STXIO},
+ {CODE_FOR_sthio, "__builtin_sthio", NIOS2_BUILTIN_STHIO, &void_ftype_volatile_void_p_int, nios2_expand_STXIO},
+ {CODE_FOR_stwio, "__builtin_stwio", NIOS2_BUILTIN_STWIO, &void_ftype_volatile_void_p_int, nios2_expand_STXIO},
+
+ {CODE_FOR_sync, "__builtin_sync", NIOS2_BUILTIN_SYNC, &void_ftype_void, nios2_expand_sync},
+ {CODE_FOR_rdctl, "__builtin_rdctl", NIOS2_BUILTIN_RDCTL, &int_ftype_int, nios2_expand_rdctl},
+ {CODE_FOR_wrctl, "__builtin_wrctl", NIOS2_BUILTIN_WRCTL, &void_ftype_int_int, nios2_expand_wrctl},
+
+ {CODE_FOR_custom_n, "__builtin_custom_n", NIOS2_BUILTIN_CUSTOM_N, &custom_n, nios2_expand_custom_n},
+ {CODE_FOR_custom_ni, "__builtin_custom_ni", NIOS2_BUILTIN_CUSTOM_NI, &custom_ni, nios2_expand_custom_nX},
+ {CODE_FOR_custom_nf, "__builtin_custom_nf", NIOS2_BUILTIN_CUSTOM_NF, &custom_nf, nios2_expand_custom_nX},
+ {CODE_FOR_custom_np, "__builtin_custom_np", NIOS2_BUILTIN_CUSTOM_NP, &custom_np, nios2_expand_custom_nX},
+ {CODE_FOR_custom_nii, "__builtin_custom_nii", NIOS2_BUILTIN_CUSTOM_NII, &custom_nii, nios2_expand_custom_nXX},
+ {CODE_FOR_custom_nif, "__builtin_custom_nif", NIOS2_BUILTIN_CUSTOM_NIF, &custom_nif, nios2_expand_custom_nXX},
+ {CODE_FOR_custom_nip, "__builtin_custom_nip", NIOS2_BUILTIN_CUSTOM_NIP, &custom_nip, nios2_expand_custom_nXX},
+ {CODE_FOR_custom_nfi, "__builtin_custom_nfi", NIOS2_BUILTIN_CUSTOM_NFI, &custom_nfi, nios2_expand_custom_nXX},
+ {CODE_FOR_custom_nff, "__builtin_custom_nff", NIOS2_BUILTIN_CUSTOM_NFF, &custom_nff, nios2_expand_custom_nXX},
+ {CODE_FOR_custom_nfp, "__builtin_custom_nfp", NIOS2_BUILTIN_CUSTOM_NFP, &custom_nfp, nios2_expand_custom_nXX},
+ {CODE_FOR_custom_npi, "__builtin_custom_npi", NIOS2_BUILTIN_CUSTOM_NPI, &custom_npi, nios2_expand_custom_nXX},
+ {CODE_FOR_custom_npf, "__builtin_custom_npf", NIOS2_BUILTIN_CUSTOM_NPF, &custom_npf, nios2_expand_custom_nXX},
+ {CODE_FOR_custom_npp, "__builtin_custom_npp", NIOS2_BUILTIN_CUSTOM_NPP, &custom_npp, nios2_expand_custom_nXX},
+ {CODE_FOR_custom_in, "__builtin_custom_in", NIOS2_BUILTIN_CUSTOM_IN, &custom_in, nios2_expand_custom_Xn},
+ {CODE_FOR_custom_ini, "__builtin_custom_ini", NIOS2_BUILTIN_CUSTOM_INI, &custom_ini, nios2_expand_custom_XnX},
+ {CODE_FOR_custom_inf, "__builtin_custom_inf", NIOS2_BUILTIN_CUSTOM_INF, &custom_inf, nios2_expand_custom_XnX},
+ {CODE_FOR_custom_inp, "__builtin_custom_inp", NIOS2_BUILTIN_CUSTOM_INP, &custom_inp, nios2_expand_custom_XnX},
+ {CODE_FOR_custom_inii, "__builtin_custom_inii", NIOS2_BUILTIN_CUSTOM_INII, &custom_inii, nios2_expand_custom_XnXX},
+ {CODE_FOR_custom_inif, "__builtin_custom_inif", NIOS2_BUILTIN_CUSTOM_INIF, &custom_inif, nios2_expand_custom_XnXX},
+ {CODE_FOR_custom_inip, "__builtin_custom_inip", NIOS2_BUILTIN_CUSTOM_INIP, &custom_inip, nios2_expand_custom_XnXX},
+ {CODE_FOR_custom_infi, "__builtin_custom_infi", NIOS2_BUILTIN_CUSTOM_INFI, &custom_infi, nios2_expand_custom_XnXX},
+ {CODE_FOR_custom_inff, "__builtin_custom_inff", NIOS2_BUILTIN_CUSTOM_INFF, &custom_inff, nios2_expand_custom_XnXX},
+ {CODE_FOR_custom_infp, "__builtin_custom_infp", NIOS2_BUILTIN_CUSTOM_INFP, &custom_infp, nios2_expand_custom_XnXX},
+ {CODE_FOR_custom_inpi, "__builtin_custom_inpi", NIOS2_BUILTIN_CUSTOM_INPI, &custom_inpi, nios2_expand_custom_XnXX},
+ {CODE_FOR_custom_inpf, "__builtin_custom_inpf", NIOS2_BUILTIN_CUSTOM_INPF, &custom_inpf, nios2_expand_custom_XnXX},
+ {CODE_FOR_custom_inpp, "__builtin_custom_inpp", NIOS2_BUILTIN_CUSTOM_INPP, &custom_inpp, nios2_expand_custom_XnXX},
+ {CODE_FOR_custom_fn, "__builtin_custom_fn", NIOS2_BUILTIN_CUSTOM_FN, &custom_fn, nios2_expand_custom_Xn},
+ {CODE_FOR_custom_fni, "__builtin_custom_fni", NIOS2_BUILTIN_CUSTOM_FNI, &custom_fni, nios2_expand_custom_XnX},
+ {CODE_FOR_custom_fnf, "__builtin_custom_fnf", NIOS2_BUILTIN_CUSTOM_FNF, &custom_fnf, nios2_expand_custom_XnX},
+ {CODE_FOR_custom_fnp, "__builtin_custom_fnp", NIOS2_BUILTIN_CUSTOM_FNP, &custom_fnp, nios2_expand_custom_XnX},
+ {CODE_FOR_custom_fnii, "__builtin_custom_fnii", NIOS2_BUILTIN_CUSTOM_FNII, &custom_fnii, nios2_expand_custom_XnXX},
+ {CODE_FOR_custom_fnif, "__builtin_custom_fnif", NIOS2_BUILTIN_CUSTOM_FNIF, &custom_fnif, nios2_expand_custom_XnXX},
+ {CODE_FOR_custom_fnip, "__builtin_custom_fnip", NIOS2_BUILTIN_CUSTOM_FNIP, &custom_fnip, nios2_expand_custom_XnXX},
+ {CODE_FOR_custom_fnfi, "__builtin_custom_fnfi", NIOS2_BUILTIN_CUSTOM_FNFI, &custom_fnfi, nios2_expand_custom_XnXX},
+ {CODE_FOR_custom_fnff, "__builtin_custom_fnff", NIOS2_BUILTIN_CUSTOM_FNFF, &custom_fnff, nios2_expand_custom_XnXX},
+ {CODE_FOR_custom_fnfp, "__builtin_custom_fnfp", NIOS2_BUILTIN_CUSTOM_FNFP, &custom_fnfp, nios2_expand_custom_XnXX},
+ {CODE_FOR_custom_fnpi, "__builtin_custom_fnpi", NIOS2_BUILTIN_CUSTOM_FNPI, &custom_fnpi, nios2_expand_custom_XnXX},
+ {CODE_FOR_custom_fnpf, "__builtin_custom_fnpf", NIOS2_BUILTIN_CUSTOM_FNPF, &custom_fnpf, nios2_expand_custom_XnXX},
+ {CODE_FOR_custom_fnpp, "__builtin_custom_fnpp", NIOS2_BUILTIN_CUSTOM_FNPP, &custom_fnpp, nios2_expand_custom_XnXX},
+ {CODE_FOR_custom_pn, "__builtin_custom_pn", NIOS2_BUILTIN_CUSTOM_PN, &custom_pn, nios2_expand_custom_Xn},
+ {CODE_FOR_custom_pni, "__builtin_custom_pni", NIOS2_BUILTIN_CUSTOM_PNI, &custom_pni, nios2_expand_custom_XnX},
+ {CODE_FOR_custom_pnf, "__builtin_custom_pnf", NIOS2_BUILTIN_CUSTOM_PNF, &custom_pnf, nios2_expand_custom_XnX},
+ {CODE_FOR_custom_pnp, "__builtin_custom_pnp", NIOS2_BUILTIN_CUSTOM_PNP, &custom_pnp, nios2_expand_custom_XnX},
+ {CODE_FOR_custom_pnii, "__builtin_custom_pnii", NIOS2_BUILTIN_CUSTOM_PNII, &custom_pnii, nios2_expand_custom_XnXX},
+ {CODE_FOR_custom_pnif, "__builtin_custom_pnif", NIOS2_BUILTIN_CUSTOM_PNIF, &custom_pnif, nios2_expand_custom_XnXX},
+ {CODE_FOR_custom_pnip, "__builtin_custom_pnip", NIOS2_BUILTIN_CUSTOM_PNIP, &custom_pnip, nios2_expand_custom_XnXX},
+ {CODE_FOR_custom_pnfi, "__builtin_custom_pnfi", NIOS2_BUILTIN_CUSTOM_PNFI, &custom_pnfi, nios2_expand_custom_XnXX},
+ {CODE_FOR_custom_pnff, "__builtin_custom_pnff", NIOS2_BUILTIN_CUSTOM_PNFF, &custom_pnff, nios2_expand_custom_XnXX},
+ {CODE_FOR_custom_pnfp, "__builtin_custom_pnfp", NIOS2_BUILTIN_CUSTOM_PNFP, &custom_pnfp, nios2_expand_custom_XnXX},
+ {CODE_FOR_custom_pnpi, "__builtin_custom_pnpi", NIOS2_BUILTIN_CUSTOM_PNPI, &custom_pnpi, nios2_expand_custom_XnXX},
+ {CODE_FOR_custom_pnpf, "__builtin_custom_pnpf", NIOS2_BUILTIN_CUSTOM_PNPF, &custom_pnpf, nios2_expand_custom_XnXX},
+ {CODE_FOR_custom_pnpp, "__builtin_custom_pnpp", NIOS2_BUILTIN_CUSTOM_PNPP, &custom_pnpp, nios2_expand_custom_XnXX},
+
+
+ {0, 0, 0, 0, 0},
+};
+
+/* This does not have a closing bracket on purpose (see use) */
+#define def_param(TYPE) \
+ tree_cons (NULL_TREE, TYPE,
+
+static void
+nios2_init_builtins ()
+{
+ const struct builtin_description *d;
+
+
+ endlink = void_list_node;
+
+ /* Special indenting here because one of the brackets is in def_param */
+ /* *INDENT-OFF* */
+
+ /* int fn (volatile const void *)
+ */
+ int_ftype_volatile_const_void_p
+ = build_function_type (integer_type_node,
+ def_param (build_qualified_type (ptr_type_node,
+ TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE))
+ endlink));
+
+
+ /* void fn (volatile void *, int)
+ */
+ void_ftype_volatile_void_p_int
+ = build_function_type (void_type_node,
+ def_param (build_qualified_type (ptr_type_node,
+ TYPE_QUAL_VOLATILE))
+ def_param (integer_type_node)
+ endlink)));
+
+ /* void fn (void)
+ */
+ void_ftype_void
+ = build_function_type (void_type_node,
+ endlink);
+
+ /* int fn (int)
+ */
+ int_ftype_int
+ = build_function_type (integer_type_node,
+ def_param (integer_type_node)
+ endlink));
+
+ /* void fn (int, int)
+ */
+ void_ftype_int_int
+ = build_function_type (void_type_node,
+ def_param (integer_type_node)
+ def_param (integer_type_node)
+ endlink)));
+
+
+#define CUSTOM_NUM def_param (integer_type_node)
+
+ custom_n
+ = build_function_type (void_type_node,
+ CUSTOM_NUM
+ endlink));
+ custom_ni
+ = build_function_type (void_type_node,
+ CUSTOM_NUM
+ def_param (integer_type_node)
+ endlink)));
+ custom_nf
+ = build_function_type (void_type_node,
+ CUSTOM_NUM
+ def_param (float_type_node)
+ endlink)));
+ custom_np
+ = build_function_type (void_type_node,
+ CUSTOM_NUM
+ def_param (ptr_type_node)
+ endlink)));
+ custom_nii
+ = build_function_type (void_type_node,
+ CUSTOM_NUM
+ def_param (integer_type_node)
+ def_param (integer_type_node)
+ endlink))));
+ custom_nif
+ = build_function_type (void_type_node,
+ CUSTOM_NUM
+ def_param (integer_type_node)
+ def_param (float_type_node)
+ endlink))));
+ custom_nip
+ = build_function_type (void_type_node,
+ CUSTOM_NUM
+ def_param (integer_type_node)
+ def_param (ptr_type_node)
+ endlink))));
+ custom_nfi
+ = build_function_type (void_type_node,
+ CUSTOM_NUM
+ def_param (float_type_node)
+ def_param (integer_type_node)
+ endlink))));
+ custom_nff
+ = build_function_type (void_type_node,
+ CUSTOM_NUM
+ def_param (float_type_node)
+ def_param (float_type_node)
+ endlink))));
+ custom_nfp
+ = build_function_type (void_type_node,
+ CUSTOM_NUM
+ def_param (float_type_node)
+ def_param (ptr_type_node)
+ endlink))));
+ custom_npi
+ = build_function_type (void_type_node,
+ CUSTOM_NUM
+ def_param (ptr_type_node)
+ def_param (integer_type_node)
+ endlink))));
+ custom_npf
+ = build_function_type (void_type_node,
+ CUSTOM_NUM
+ def_param (ptr_type_node)
+ def_param (float_type_node)
+ endlink))));
+ custom_npp
+ = build_function_type (void_type_node,
+ CUSTOM_NUM
+ def_param (ptr_type_node)
+ def_param (ptr_type_node)
+ endlink))));
+
+ custom_in
+ = build_function_type (integer_type_node,
+ CUSTOM_NUM
+ endlink));
+ custom_ini
+ = build_function_type (integer_type_node,
+ CUSTOM_NUM
+ def_param (integer_type_node)
+ endlink)));
+ custom_inf
+ = build_function_type (integer_type_node,
+ CUSTOM_NUM
+ def_param (float_type_node)
+ endlink)));
+ custom_inp
+ = build_function_type (integer_type_node,
+ CUSTOM_NUM
+ def_param (ptr_type_node)
+ endlink)));
+ custom_inii
+ = build_function_type (integer_type_node,
+ CUSTOM_NUM
+ def_param (integer_type_node)
+ def_param (integer_type_node)
+ endlink))));
+ custom_inif
+ = build_function_type (integer_type_node,
+ CUSTOM_NUM
+ def_param (integer_type_node)
+ def_param (float_type_node)
+ endlink))));
+ custom_inip
+ = build_function_type (integer_type_node,
+ CUSTOM_NUM
+ def_param (integer_type_node)
+ def_param (ptr_type_node)
+ endlink))));
+ custom_infi
+ = build_function_type (integer_type_node,
+ CUSTOM_NUM
+ def_param (float_type_node)
+ def_param (integer_type_node)
+ endlink))));
+ custom_inff
+ = build_function_type (integer_type_node,
+ CUSTOM_NUM
+ def_param (float_type_node)
+ def_param (float_type_node)
+ endlink))));
+ custom_infp
+ = build_function_type (integer_type_node,
+ CUSTOM_NUM
+ def_param (float_type_node)
+ def_param (ptr_type_node)
+ endlink))));
+ custom_inpi
+ = build_function_type (integer_type_node,
+ CUSTOM_NUM
+ def_param (ptr_type_node)
+ def_param (integer_type_node)
+ endlink))));
+ custom_inpf
+ = build_function_type (integer_type_node,
+ CUSTOM_NUM
+ def_param (ptr_type_node)
+ def_param (float_type_node)
+ endlink))));
+ custom_inpp
+ = build_function_type (integer_type_node,
+ CUSTOM_NUM
+ def_param (ptr_type_node)
+ def_param (ptr_type_node)
+ endlink))));
+
+ custom_fn
+ = build_function_type (float_type_node,
+ CUSTOM_NUM
+ endlink));
+ custom_fni
+ = build_function_type (float_type_node,
+ CUSTOM_NUM
+ def_param (integer_type_node)
+ endlink)));
+ custom_fnf
+ = build_function_type (float_type_node,
+ CUSTOM_NUM
+ def_param (float_type_node)
+ endlink)));
+ custom_fnp
+ = build_function_type (float_type_node,
+ CUSTOM_NUM
+ def_param (ptr_type_node)
+ endlink)));
+ custom_fnii
+ = build_function_type (float_type_node,
+ CUSTOM_NUM
+ def_param (integer_type_node)
+ def_param (integer_type_node)
+ endlink))));
+ custom_fnif
+ = build_function_type (float_type_node,
+ CUSTOM_NUM
+ def_param (integer_type_node)
+ def_param (float_type_node)
+ endlink))));
+ custom_fnip
+ = build_function_type (float_type_node,
+ CUSTOM_NUM
+ def_param (integer_type_node)
+ def_param (ptr_type_node)
+ endlink))));
+ custom_fnfi
+ = build_function_type (float_type_node,
+ CUSTOM_NUM
+ def_param (float_type_node)
+ def_param (integer_type_node)
+ endlink))));
+ custom_fnff
+ = build_function_type (float_type_node,
+ CUSTOM_NUM
+ def_param (float_type_node)
+ def_param (float_type_node)
+ endlink))));
+ custom_fnfp
+ = build_function_type (float_type_node,
+ CUSTOM_NUM
+ def_param (float_type_node)
+ def_param (ptr_type_node)
+ endlink))));
+ custom_fnpi
+ = build_function_type (float_type_node,
+ CUSTOM_NUM
+ def_param (ptr_type_node)
+ def_param (integer_type_node)
+ endlink))));
+ custom_fnpf
+ = build_function_type (float_type_node,
+ CUSTOM_NUM
+ def_param (ptr_type_node)
+ def_param (float_type_node)
+ endlink))));
+ custom_fnpp
+ = build_function_type (float_type_node,
+ CUSTOM_NUM
+ def_param (ptr_type_node)
+ def_param (ptr_type_node)
+ endlink))));
+
+
+ custom_pn
+ = build_function_type (ptr_type_node,
+ CUSTOM_NUM
+ endlink));
+ custom_pni
+ = build_function_type (ptr_type_node,
+ CUSTOM_NUM
+ def_param (integer_type_node)
+ endlink)));
+ custom_pnf
+ = build_function_type (ptr_type_node,
+ CUSTOM_NUM
+ def_param (float_type_node)
+ endlink)));
+ custom_pnp
+ = build_function_type (ptr_type_node,
+ CUSTOM_NUM
+ def_param (ptr_type_node)
+ endlink)));
+ custom_pnii
+ = build_function_type (ptr_type_node,
+ CUSTOM_NUM
+ def_param (integer_type_node)
+ def_param (integer_type_node)
+ endlink))));
+ custom_pnif
+ = build_function_type (ptr_type_node,
+ CUSTOM_NUM
+ def_param (integer_type_node)
+ def_param (float_type_node)
+ endlink))));
+ custom_pnip
+ = build_function_type (ptr_type_node,
+ CUSTOM_NUM
+ def_param (integer_type_node)
+ def_param (ptr_type_node)
+ endlink))));
+ custom_pnfi
+ = build_function_type (ptr_type_node,
+ CUSTOM_NUM
+ def_param (float_type_node)
+ def_param (integer_type_node)
+ endlink))));
+ custom_pnff
+ = build_function_type (ptr_type_node,
+ CUSTOM_NUM
+ def_param (float_type_node)
+ def_param (float_type_node)
+ endlink))));
+ custom_pnfp
+ = build_function_type (ptr_type_node,
+ CUSTOM_NUM
+ def_param (float_type_node)
+ def_param (ptr_type_node)
+ endlink))));
+ custom_pnpi
+ = build_function_type (ptr_type_node,
+ CUSTOM_NUM
+ def_param (ptr_type_node)
+ def_param (integer_type_node)
+ endlink))));
+ custom_pnpf
+ = build_function_type (ptr_type_node,
+ CUSTOM_NUM
+ def_param (ptr_type_node)
+ def_param (float_type_node)
+ endlink))));
+ custom_pnpp
+ = build_function_type (ptr_type_node,
+ CUSTOM_NUM
+ def_param (ptr_type_node)
+ def_param (ptr_type_node)
+ endlink))));
+
+
+
+ /* *INDENT-ON* */
+
+
+ for (d = bdesc; d->name; d++)
+ {
+ builtin_function (d->name, *d->type, d->code,
+ BUILT_IN_MD, NULL, NULL);
+ }
+}
+
+/* Expand an expression EXP that calls a built-in function,
+ with result going to TARGET if that's convenient
+ (and in mode MODE if that's convenient).
+ SUBTARGET may be used as the target for computing one of EXP's operands.
+ IGNORE is nonzero if the value is to be ignored. */
+
+static rtx
+nios2_expand_builtin (tree exp, rtx target, rtx subtarget,
+ enum machine_mode mode, int ignore)
+{
+ const struct builtin_description *d;
+ tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+ unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
+
+ for (d = bdesc; d->name; d++)
+ if (d->code == fcode)
+ return (d->expander) (d, exp, target, subtarget, mode, ignore);
+
+ /* we should have seen one of the functins we registered */
+ abort ();
+}
+
+static rtx nios2_create_target (const struct builtin_description *, rtx);
+
+
+static rtx
+nios2_create_target (const struct builtin_description *d, rtx target)
+{
+ if (!target
+ || !(*insn_data[d->icode].operand[0].predicate) (target,
+ insn_data[d->icode].operand[0].mode))
+ {
+ target = gen_reg_rtx (insn_data[d->icode].operand[0].mode);
+ }
+
+ return target;
+}
+
+
+static rtx nios2_extract_opcode (const struct builtin_description *, int, tree);
+static rtx nios2_extract_operand (const struct builtin_description *, int, int, tree);
+
+static rtx
+nios2_extract_opcode (const struct builtin_description *d, int op, tree arglist)
+{
+ enum machine_mode mode = insn_data[d->icode].operand[op].mode;
+ tree arg = TREE_VALUE (arglist);
+ rtx opcode = expand_expr (arg, NULL_RTX, mode, 0);
+ opcode = protect_from_queue (opcode, 0);
+
+ if (!(*insn_data[d->icode].operand[op].predicate) (opcode, mode))
+ error ("Custom instruction opcode must be compile time constant in the range 0-255 for %s", d->name);
+
+ return opcode;
+}
+
+static rtx
+nios2_extract_operand (const struct builtin_description *d, int op, int argnum, tree arglist)
+{
+ enum machine_mode mode = insn_data[d->icode].operand[op].mode;
+ tree arg = TREE_VALUE (arglist);
+ rtx operand = expand_expr (arg, NULL_RTX, mode, 0);
+ operand = protect_from_queue (operand, 0);
+
+ if (!(*insn_data[d->icode].operand[op].predicate) (operand, mode))
+ operand = copy_to_mode_reg (mode, operand);
+
+ /* ??? Better errors would be nice */
+ if (!(*insn_data[d->icode].operand[op].predicate) (operand, mode))
+ error ("Invalid argument %d to %s", argnum, d->name);
+
+ return operand;
+}
+
+
+static rtx
+nios2_expand_custom_n (const struct builtin_description *d, tree exp,
+ rtx target ATTRIBUTE_UNUSED, rtx subtarget ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED, int ignore ATTRIBUTE_UNUSED)
+{
+ tree arglist = TREE_OPERAND (exp, 1);
+ rtx pat;
+ rtx opcode;
+
+ /* custom_n should have exactly one operand */
+ if (insn_data[d->icode].n_operands != 1)
+ abort ();
+
+ opcode = nios2_extract_opcode (d, 0, arglist);
+
+ pat = GEN_FCN (d->icode) (opcode);
+ if (!pat)
+ return 0;
+ emit_insn (pat);
+ return 0;
+}
+
+static rtx
+nios2_expand_custom_Xn (const struct builtin_description *d, tree exp,
+ rtx target, rtx subtarget ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ tree arglist = TREE_OPERAND (exp, 1);
+ rtx pat;
+ rtx opcode;
+
+ /* custom_Xn should have exactly two operands */
+ if (insn_data[d->icode].n_operands != 2)
+ abort ();
+
+ target = nios2_create_target (d, target);
+ opcode = nios2_extract_opcode (d, 1, arglist);
+
+ pat = GEN_FCN (d->icode) (target, opcode);
+ if (!pat)
+ return 0;
+ emit_insn (pat);
+ return target;
+}
+
+static rtx
+nios2_expand_custom_nX (const struct builtin_description *d, tree exp,
+ rtx target ATTRIBUTE_UNUSED, rtx subtarget ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED, int ignore ATTRIBUTE_UNUSED)
+{
+ tree arglist = TREE_OPERAND (exp, 1);
+ rtx pat;
+ rtx opcode;
+ rtx operands[1];
+ int i;
+
+
+ /* custom_nX should have exactly two operands */
+ if (insn_data[d->icode].n_operands != 2)
+ abort ();
+
+ opcode = nios2_extract_opcode (d, 0, arglist);
+ for (i = 0; i < 1; i++)
+ {
+ arglist = TREE_CHAIN (arglist);
+ operands[i] = nios2_extract_operand (d, i + 1, i + 1, arglist);
+ }
+
+ pat = GEN_FCN (d->icode) (opcode, operands[0]);
+ if (!pat)
+ return 0;
+ emit_insn (pat);
+ return 0;
+}
+
+static rtx
+nios2_expand_custom_XnX (const struct builtin_description *d, tree exp, rtx target,
+ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ tree arglist = TREE_OPERAND (exp, 1);
+ rtx pat;
+ rtx opcode;
+ rtx operands[1];
+ int i;
+
+ /* custom_Xn should have exactly three operands */
+ if (insn_data[d->icode].n_operands != 3)
+ abort ();
+
+ target = nios2_create_target (d, target);
+ opcode = nios2_extract_opcode (d, 1, arglist);
+
+ for (i = 0; i < 1; i++)
+ {
+ arglist = TREE_CHAIN (arglist);
+ operands[i] = nios2_extract_operand (d, i + 2, i + 1, arglist);
+ }
+
+ pat = GEN_FCN (d->icode) (target, opcode, operands[0]);
+
+ if (!pat)
+ return 0;
+ emit_insn (pat);
+ return target;
+}
+
+static rtx
+nios2_expand_custom_nXX (const struct builtin_description *d, tree exp, rtx target ATTRIBUTE_UNUSED,
+ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ tree arglist = TREE_OPERAND (exp, 1);
+ rtx pat;
+ rtx opcode;
+ rtx operands[2];
+ int i;
+
+
+ /* custom_nX should have exactly three operands */
+ if (insn_data[d->icode].n_operands != 3)
+ abort ();
+
+ opcode = nios2_extract_opcode (d, 0, arglist);
+ for (i = 0; i < 2; i++)
+ {
+ arglist = TREE_CHAIN (arglist);
+ operands[i] = nios2_extract_operand (d, i + 1, i + 1, arglist);
+ }
+
+ pat = GEN_FCN (d->icode) (opcode, operands[0], operands[1]);
+ if (!pat)
+ return 0;
+ emit_insn (pat);
+ return 0;
+}
+
+static rtx
+nios2_expand_custom_XnXX (const struct builtin_description *d, tree exp, rtx target,
+ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ tree arglist = TREE_OPERAND (exp, 1);
+ rtx pat;
+ rtx opcode;
+ rtx operands[2];
+ int i;
+
+
+ /* custom_XnX should have exactly four operands */
+ if (insn_data[d->icode].n_operands != 4)
+ abort ();
+
+ target = nios2_create_target (d, target);
+ opcode = nios2_extract_opcode (d, 1, arglist);
+ for (i = 0; i < 2; i++)
+ {
+ arglist = TREE_CHAIN (arglist);
+ operands[i] = nios2_extract_operand (d, i + 2, i + 1, arglist);
+ }
+
+ pat = GEN_FCN (d->icode) (target, opcode, operands[0], operands[1]);
+
+ if (!pat)
+ return 0;
+ emit_insn (pat);
+ return target;
+}
+
+
+
+static rtx
+nios2_expand_STXIO (const struct builtin_description *d, tree exp, rtx target ATTRIBUTE_UNUSED,
+ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ tree arglist = TREE_OPERAND (exp, 1);
+ rtx pat;
+ rtx store_dest, store_val;
+ enum insn_code icode = d->icode;
+
+ /* stores should have exactly two operands */
+ if (insn_data[icode].n_operands != 2)
+ abort ();
+
+ /* process the destination of the store */
+ {
+ enum machine_mode mode = insn_data[icode].operand[0].mode;
+ tree arg = TREE_VALUE (arglist);
+ store_dest = expand_expr (arg, NULL_RTX, VOIDmode, 0);
+ store_dest = protect_from_queue (store_dest, 0);
+
+ store_dest = gen_rtx_MEM (mode, copy_to_mode_reg (Pmode, store_dest));
+
+ /* ??? Better errors would be nice */
+ if (!(*insn_data[icode].operand[0].predicate) (store_dest, mode))
+ error ("Invalid argument 1 to %s", d->name);
+ }
+
+
+ /* process the value to store */
+ {
+ enum machine_mode mode = insn_data[icode].operand[1].mode;
+ tree arg = TREE_VALUE (TREE_CHAIN (arglist));
+ store_val = expand_expr (arg, NULL_RTX, mode, 0);
+ store_val = protect_from_queue (store_val, 0);
+
+ if (!(*insn_data[icode].operand[1].predicate) (store_val, mode))
+ store_val = copy_to_mode_reg (mode, store_val);
+
+ /* ??? Better errors would be nice */
+ if (!(*insn_data[icode].operand[1].predicate) (store_val, mode))
+ error ("Invalid argument 2 to %s", d->name);
+ }
+
+ pat = GEN_FCN (d->icode) (store_dest, store_val);
+ if (!pat)
+ return 0;
+ emit_insn (pat);
+ return 0;
+}
+
+
+static rtx
+nios2_expand_LDXIO (const struct builtin_description * d, tree exp, rtx target,
+ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ tree arglist = TREE_OPERAND (exp, 1);
+ rtx pat;
+ rtx ld_src;
+ enum insn_code icode = d->icode;
+
+ /* loads should have exactly two operands */
+ if (insn_data[icode].n_operands != 2)
+ abort ();
+
+ target = nios2_create_target (d, target);
+
+ {
+ enum machine_mode mode = insn_data[icode].operand[1].mode;
+ tree arg = TREE_VALUE (arglist);
+ ld_src = expand_expr (arg, NULL_RTX, VOIDmode, 0);
+ ld_src = protect_from_queue (ld_src, 0);
+
+ ld_src = gen_rtx_MEM (mode, copy_to_mode_reg (Pmode, ld_src));
+
+ /* ??? Better errors would be nice */
+ if (!(*insn_data[icode].operand[1].predicate) (ld_src, mode))
+ {
+ error ("Invalid argument 1 to %s", d->name);
+ }
+ }
+
+ pat = GEN_FCN (d->icode) (target, ld_src);
+ if (!pat)
+ return 0;
+ emit_insn (pat);
+ return target;
+}
+
+
+static rtx
+nios2_expand_sync (const struct builtin_description * d ATTRIBUTE_UNUSED,
+ tree exp ATTRIBUTE_UNUSED, rtx target ATTRIBUTE_UNUSED,
+ rtx subtarget ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ emit_insn (gen_sync ());
+ return 0;
+}
+
+static rtx
+nios2_expand_rdctl (const struct builtin_description * d ATTRIBUTE_UNUSED,
+ tree exp ATTRIBUTE_UNUSED, rtx target ATTRIBUTE_UNUSED,
+ rtx subtarget ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ tree arglist = TREE_OPERAND (exp, 1);
+ rtx pat;
+ rtx rdctl_reg;
+ enum insn_code icode = d->icode;
+
+ /* rdctl should have exactly two operands */
+ if (insn_data[icode].n_operands != 2)
+ abort ();
+
+ target = nios2_create_target (d, target);
+
+ {
+ enum machine_mode mode = insn_data[icode].operand[1].mode;
+ tree arg = TREE_VALUE (arglist);
+ rdctl_reg = expand_expr (arg, NULL_RTX, VOIDmode, 0);
+ rdctl_reg = protect_from_queue (rdctl_reg, 0);
+
+ if (!(*insn_data[icode].operand[1].predicate) (rdctl_reg, mode))
+ {
+ error ("Control register number must be in range 0-31 for %s", d->name);
+ }
+ }
+
+ pat = GEN_FCN (d->icode) (target, rdctl_reg);
+ if (!pat)
+ return 0;
+ emit_insn (pat);
+ return target;
+}
+
+static rtx
+nios2_expand_wrctl (const struct builtin_description * d ATTRIBUTE_UNUSED,
+ tree exp ATTRIBUTE_UNUSED, rtx target ATTRIBUTE_UNUSED,
+ rtx subtarget ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ tree arglist = TREE_OPERAND (exp, 1);
+ rtx pat;
+ rtx wrctl_reg, store_val;
+ enum insn_code icode = d->icode;
+
+ /* stores should have exactly two operands */
+ if (insn_data[icode].n_operands != 2)
+ abort ();
+
+ /* process the destination of the store */
+ {
+ enum machine_mode mode = insn_data[icode].operand[0].mode;
+ tree arg = TREE_VALUE (arglist);
+ wrctl_reg = expand_expr (arg, NULL_RTX, VOIDmode, 0);
+ wrctl_reg = protect_from_queue (wrctl_reg, 0);
+
+ if (!(*insn_data[icode].operand[0].predicate) (wrctl_reg, mode))
+ error ("Control register number must be in range 0-31 for %s", d->name);
+ }
+
+
+ /* process the value to store */
+ {
+ enum machine_mode mode = insn_data[icode].operand[1].mode;
+ tree arg = TREE_VALUE (TREE_CHAIN (arglist));
+ store_val = expand_expr (arg, NULL_RTX, mode, 0);
+ store_val = protect_from_queue (store_val, 0);
+
+ if (!(*insn_data[icode].operand[1].predicate) (store_val, mode))
+ store_val = copy_to_mode_reg (mode, store_val);
+
+ /* ??? Better errors would be nice */
+ if (!(*insn_data[icode].operand[1].predicate) (store_val, mode))
+ error ("Invalid argument 2 to %s", d->name);
+ }
+
+ pat = GEN_FCN (d->icode) (wrctl_reg, store_val);
+ if (!pat)
+ return 0;
+ emit_insn (pat);
+ return 0;
+}
+
+
+#include "gt-nios2.h"
+
diff -durN gcc-3.4.6.orig/gcc/config/nios2/nios2-dp-bit.c gcc-3.4.6/gcc/config/nios2/nios2-dp-bit.c
--- gcc-3.4.6.orig/gcc/config/nios2/nios2-dp-bit.c 1970-01-01 01:00:00.000000000 +0100
+++ gcc-3.4.6/gcc/config/nios2/nios2-dp-bit.c 2007-08-15 23:09:36.000000000 +0200
@@ -0,0 +1,1652 @@
+
+/* This is a software floating point library which can be used
+ for targets without hardware floating point.
+ Copyright (C) 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004
+ Free Software Foundation, Inc.
+
+This file is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file with other programs, and to distribute
+those programs without any restriction coming from the use of this
+file. (The General Public License restrictions do apply in other
+respects; for example, they cover modification of the file, and
+distribution when not linked into another program.)
+
+This file is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* As a special exception, if you link this library with other files,
+ some of which are compiled with GCC, to produce an executable,
+ this library does not by itself cause the resulting executable
+ to be covered by the GNU General Public License.
+ This exception does not however invalidate any other reasons why
+ the executable file might be covered by the GNU General Public License. */
+
+/* This implements IEEE 754 format arithmetic, but does not provide a
+ mechanism for setting the rounding mode, or for generating or handling
+ exceptions.
+
+ The original code by Steve Chamberlain, hacked by Mark Eichin and Jim
+ Wilson, all of Cygnus Support. */
+
+/* The intended way to use this file is to make two copies, add `#define FLOAT'
+ to one copy, then compile both copies and add them to libgcc.a. */
+
+#include "tconfig.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "config/fp-bit.h"
+
+/* The following macros can be defined to change the behavior of this file:
+ FLOAT: Implement a `float', aka SFmode, fp library. If this is not
+ defined, then this file implements a `double', aka DFmode, fp library.
+ FLOAT_ONLY: Used with FLOAT, to implement a `float' only library, i.e.
+ don't include float->double conversion which requires the double library.
+ This is useful only for machines which can't support doubles, e.g. some
+ 8-bit processors.
+ CMPtype: Specify the type that floating point compares should return.
+ This defaults to SItype, aka int.
+ US_SOFTWARE_GOFAST: This makes all entry points use the same names as the
+ US Software goFast library.
+ _DEBUG_BITFLOAT: This makes debugging the code a little easier, by adding
+ two integers to the FLO_union_type.
+ NO_DENORMALS: Disable handling of denormals.
+ NO_NANS: Disable nan and infinity handling
+ SMALL_MACHINE: Useful when operations on QIs and HIs are faster
+ than on an SI */
+
+/* We don't currently support extended floats (long doubles) on machines
+ without hardware to deal with them.
+
+ These stubs are just to keep the linker from complaining about unresolved
+ references which can be pulled in from libio & libstdc++, even if the
+ user isn't using long doubles. However, they may generate an unresolved
+ external to abort if abort is not used by the function, and the stubs
+ are referenced from within libc, since libgcc goes before and after the
+ system library. */
+
+#ifdef DECLARE_LIBRARY_RENAMES
+ DECLARE_LIBRARY_RENAMES
+#endif
+
+#ifdef EXTENDED_FLOAT_STUBS
+extern void abort (void);
+void __extendsfxf2 (void) { abort(); }
+void __extenddfxf2 (void) { abort(); }
+void __truncxfdf2 (void) { abort(); }
+void __truncxfsf2 (void) { abort(); }
+void __fixxfsi (void) { abort(); }
+void __floatsixf (void) { abort(); }
+void __addxf3 (void) { abort(); }
+void __subxf3 (void) { abort(); }
+void __mulxf3 (void) { abort(); }
+void __divxf3 (void) { abort(); }
+void __negxf2 (void) { abort(); }
+void __eqxf2 (void) { abort(); }
+void __nexf2 (void) { abort(); }
+void __gtxf2 (void) { abort(); }
+void __gexf2 (void) { abort(); }
+void __lexf2 (void) { abort(); }
+void __ltxf2 (void) { abort(); }
+
+void __extendsftf2 (void) { abort(); }
+void __extenddftf2 (void) { abort(); }
+void __trunctfdf2 (void) { abort(); }
+void __trunctfsf2 (void) { abort(); }
+void __fixtfsi (void) { abort(); }
+void __floatsitf (void) { abort(); }
+void __addtf3 (void) { abort(); }
+void __subtf3 (void) { abort(); }
+void __multf3 (void) { abort(); }
+void __divtf3 (void) { abort(); }
+void __negtf2 (void) { abort(); }
+void __eqtf2 (void) { abort(); }
+void __netf2 (void) { abort(); }
+void __gttf2 (void) { abort(); }
+void __getf2 (void) { abort(); }
+void __letf2 (void) { abort(); }
+void __lttf2 (void) { abort(); }
+#else /* !EXTENDED_FLOAT_STUBS, rest of file */
+
+/* IEEE "special" number predicates */
+
+#ifdef NO_NANS
+
+#define nan() 0
+#define isnan(x) 0
+#define isinf(x) 0
+#else
+
+#if defined L_thenan_sf
+const fp_number_type __thenan_sf = { CLASS_SNAN, 0, 0, {(fractype) 0} };
+#elif defined L_thenan_df
+const fp_number_type __thenan_df = { CLASS_SNAN, 0, 0, {(fractype) 0} };
+#elif defined L_thenan_tf
+const fp_number_type __thenan_tf = { CLASS_SNAN, 0, 0, {(fractype) 0} };
+#elif defined TFLOAT
+extern const fp_number_type __thenan_tf;
+#elif defined FLOAT
+extern const fp_number_type __thenan_sf;
+#else
+extern const fp_number_type __thenan_df;
+#endif
+
+INLINE
+static fp_number_type *
+nan (void)
+{
+ /* Discard the const qualifier... */
+#ifdef TFLOAT
+ return (fp_number_type *) (& __thenan_tf);
+#elif defined FLOAT
+ return (fp_number_type *) (& __thenan_sf);
+#else
+ return (fp_number_type *) (& __thenan_df);
+#endif
+}
+
+INLINE
+static int
+isnan ( fp_number_type * x)
+{
+ return x->class == CLASS_SNAN || x->class == CLASS_QNAN;
+}
+
+INLINE
+static int
+isinf ( fp_number_type * x)
+{
+ return x->class == CLASS_INFINITY;
+}
+
+#endif /* NO_NANS */
+
+INLINE
+static int
+iszero ( fp_number_type * x)
+{
+ return x->class == CLASS_ZERO;
+}
+
+INLINE
+static void
+flip_sign ( fp_number_type * x)
+{
+ x->sign = !x->sign;
+}
+
+extern FLO_type pack_d ( fp_number_type * );
+
+#if defined(L_pack_df) || defined(L_pack_sf) || defined(L_pack_tf)
+FLO_type
+pack_d ( fp_number_type * src)
+{
+ FLO_union_type dst;
+ fractype fraction = src->fraction.ll; /* wasn't unsigned before? */
+ int sign = src->sign;
+ int exp = 0;
+
+ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && (isnan (src) || isinf (src)))
+ {
+ /* We can't represent these values accurately. By using the
+ largest possible magnitude, we guarantee that the conversion
+ of infinity is at least as big as any finite number. */
+ exp = EXPMAX;
+ fraction = ((fractype) 1 << FRACBITS) - 1;
+ }
+ else if (isnan (src))
+ {
+ exp = EXPMAX;
+ if (src->class == CLASS_QNAN || 1)
+ {
+#ifdef QUIET_NAN_NEGATED
+ fraction |= QUIET_NAN - 1;
+#else
+ fraction |= QUIET_NAN;
+#endif
+ }
+ }
+ else if (isinf (src))
+ {
+ exp = EXPMAX;
+ fraction = 0;
+ }
+ else if (iszero (src))
+ {
+ exp = 0;
+ fraction = 0;
+ }
+ else if (fraction == 0)
+ {
+ exp = 0;
+ }
+ else
+ {
+ if (src->normal_exp < NORMAL_EXPMIN)
+ {
+#ifdef NO_DENORMALS
+ /* Go straight to a zero representation if denormals are not
+ supported. The denormal handling would be harmless but
+ isn't unnecessary. */
+ exp = 0;
+ fraction = 0;
+#else /* NO_DENORMALS */
+ /* This number's exponent is too low to fit into the bits
+ available in the number, so we'll store 0 in the exponent and
+ shift the fraction to the right to make up for it. */
+
+ int shift = NORMAL_EXPMIN - src->normal_exp;
+
+ exp = 0;
+
+ if (shift > FRAC_NBITS - NGARDS)
+ {
+ /* No point shifting, since it's more that 64 out. */
+ fraction = 0;
+ }
+ else
+ {
+ int lowbit = (fraction & (((fractype)1 << shift) - 1)) ? 1 : 0;
+ fraction = (fraction >> shift) | lowbit;
+ }
+ if ((fraction & GARDMASK) == GARDMSB)
+ {
+ if ((fraction & (1 << NGARDS)))
+ fraction += GARDROUND + 1;
+ }
+ else
+ {
+ /* Add to the guards to round up. */
+ fraction += GARDROUND;
+ }
+ /* Perhaps the rounding means we now need to change the
+ exponent, because the fraction is no longer denormal. */
+ if (fraction >= IMPLICIT_1)
+ {
+ exp += 1;
+ }
+ fraction >>= NGARDS;
+#endif /* NO_DENORMALS */
+ }
+ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS)
+ && src->normal_exp > EXPBIAS)
+ {
+ exp = EXPMAX;
+ fraction = 0;
+ }
+ else
+ {
+ exp = src->normal_exp + EXPBIAS;
+ if (!ROUND_TOWARDS_ZERO)
+ {
+ /* IF the gard bits are the all zero, but the first, then we're
+ half way between two numbers, choose the one which makes the
+ lsb of the answer 0. */
+ if ((fraction & GARDMASK) == GARDMSB)
+ {
+ if (fraction & (1 << NGARDS))
+ fraction += GARDROUND + 1;
+ }
+ else
+ {
+ /* Add a one to the guards to round up */
+ fraction += GARDROUND;
+ }
+ if (fraction >= IMPLICIT_2)
+ {
+ fraction >>= 1;
+ exp += 1;
+ }
+ }
+ fraction >>= NGARDS;
+
+ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp > EXPMAX)
+ {
+ /* Saturate on overflow. */
+ exp = EXPMAX;
+ fraction = ((fractype) 1 << FRACBITS) - 1;
+ }
+ }
+ }
+
+ /* We previously used bitfields to store the number, but this doesn't
+ handle little/big endian systems conveniently, so use shifts and
+ masks */
+#ifdef FLOAT_BIT_ORDER_MISMATCH
+ dst.bits.fraction = fraction;
+ dst.bits.exp = exp;
+ dst.bits.sign = sign;
+#else
+# if defined TFLOAT && defined HALFFRACBITS
+ {
+ halffractype high, low, unity;
+ int lowsign, lowexp;
+
+ unity = (halffractype) 1 << HALFFRACBITS;
+
+ /* Set HIGH to the high double's significand, masking out the implicit 1.
+ Set LOW to the low double's full significand. */
+ high = (fraction >> (FRACBITS - HALFFRACBITS)) & (unity - 1);
+ low = fraction & (unity * 2 - 1);
+
+ /* Get the initial sign and exponent of the low double. */
+ lowexp = exp - HALFFRACBITS - 1;
+ lowsign = sign;
+
+ /* HIGH should be rounded like a normal double, making |LOW| <=
+ 0.5 ULP of HIGH. Assume round-to-nearest. */
+ if (exp < EXPMAX)
+ if (low > unity || (low == unity && (high & 1) == 1))
+ {
+ /* Round HIGH up and adjust LOW to match. */
+ high++;
+ if (high == unity)
+ {
+ /* May make it infinite, but that's OK. */
+ high = 0;
+ exp++;
+ }
+ low = unity * 2 - low;
+ lowsign ^= 1;
+ }
+
+ high |= (halffractype) exp << HALFFRACBITS;
+ high |= (halffractype) sign << (HALFFRACBITS + EXPBITS);
+
+ if (exp == EXPMAX || exp == 0 || low == 0)
+ low = 0;
+ else
+ {
+ while (lowexp > 0 && low < unity)
+ {
+ low <<= 1;
+ lowexp--;
+ }
+
+ if (lowexp <= 0)
+ {
+ halffractype roundmsb, round;
+ int shift;
+
+ shift = 1 - lowexp;
+ roundmsb = (1 << (shift - 1));
+ round = low & ((roundmsb << 1) - 1);
+
+ low >>= shift;
+ lowexp = 0;
+
+ if (round > roundmsb || (round == roundmsb && (low & 1) == 1))
+ {
+ low++;
+ if (low == unity)
+ /* LOW rounds up to the smallest normal number. */
+ lowexp++;
+ }
+ }
+
+ low &= unity - 1;
+ low |= (halffractype) lowexp << HALFFRACBITS;
+ low |= (halffractype) lowsign << (HALFFRACBITS + EXPBITS);
+ }
+ dst.value_raw = ((fractype) high << HALFSHIFT) | low;
+ }
+# else
+ dst.value_raw = fraction & ((((fractype)1) << FRACBITS) - (fractype)1);
+ dst.value_raw |= ((fractype) (exp & ((1 << EXPBITS) - 1))) << FRACBITS;
+ dst.value_raw |= ((fractype) (sign & 1)) << (FRACBITS | EXPBITS);
+# endif
+#endif
+
+#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT)
+#ifdef TFLOAT
+ {
+ qrtrfractype tmp1 = dst.words[0];
+ qrtrfractype tmp2 = dst.words[1];
+ dst.words[0] = dst.words[3];
+ dst.words[1] = dst.words[2];
+ dst.words[2] = tmp2;
+ dst.words[3] = tmp1;
+ }
+#else
+ {
+ halffractype tmp = dst.words[0];
+ dst.words[0] = dst.words[1];
+ dst.words[1] = tmp;
+ }
+#endif
+#endif
+
+ return dst.value;
+}
+#endif
+
+#if defined(L_unpack_df) || defined(L_unpack_sf) || defined(L_unpack_tf)
+void
+unpack_d (FLO_union_type * src, fp_number_type * dst)
+{
+ /* We previously used bitfields to store the number, but this doesn't
+ handle little/big endian systems conveniently, so use shifts and
+ masks */
+ fractype fraction;
+ int exp;
+ int sign;
+
+#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT)
+ FLO_union_type swapped;
+
+#ifdef TFLOAT
+ swapped.words[0] = src->words[3];
+ swapped.words[1] = src->words[2];
+ swapped.words[2] = src->words[1];
+ swapped.words[3] = src->words[0];
+#else
+ swapped.words[0] = src->words[1];
+ swapped.words[1] = src->words[0];
+#endif
+ src = &swapped;
+#endif
+
+#ifdef FLOAT_BIT_ORDER_MISMATCH
+ fraction = src->bits.fraction;
+ exp = src->bits.exp;
+ sign = src->bits.sign;
+#else
+# if defined TFLOAT && defined HALFFRACBITS
+ {
+ halffractype high, low;
+
+ high = src->value_raw >> HALFSHIFT;
+ low = src->value_raw & (((fractype)1 << HALFSHIFT) - 1);
+
+ fraction = high & ((((fractype)1) << HALFFRACBITS) - 1);
+ fraction <<= FRACBITS - HALFFRACBITS;
+ exp = ((int)(high >> HALFFRACBITS)) & ((1 << EXPBITS) - 1);
+ sign = ((int)(high >> (((HALFFRACBITS + EXPBITS))))) & 1;
+
+ if (exp != EXPMAX && exp != 0 && low != 0)
+ {
+ int lowexp = ((int)(low >> HALFFRACBITS)) & ((1 << EXPBITS) - 1);
+ int lowsign = ((int)(low >> (((HALFFRACBITS + EXPBITS))))) & 1;
+ int shift;
+ fractype xlow;
+
+ xlow = low & ((((fractype)1) << HALFFRACBITS) - 1);
+ if (lowexp)
+ xlow |= (((halffractype)1) << HALFFRACBITS);
+ else
+ lowexp = 1;
+ shift = (FRACBITS - HALFFRACBITS) - (exp - lowexp);
+ if (shift > 0)
+ xlow <<= shift;
+ else if (shift < 0)
+ xlow >>= -shift;
+ if (sign == lowsign)
+ fraction += xlow;
+ else if (fraction >= xlow)
+ fraction -= xlow;
+ else
+ {
+ /* The high part is a power of two but the full number is lower.
+ This code will leave the implicit 1 in FRACTION, but we'd
+ have added that below anyway. */
+ fraction = (((fractype) 1 << FRACBITS) - xlow) << 1;
+ exp--;
+ }
+ }
+ }
+# else
+ fraction = src->value_raw & ((((fractype)1) << FRACBITS) - 1);
+ exp = ((int)(src->value_raw >> FRACBITS)) & ((1 << EXPBITS) - 1);
+ sign = ((int)(src->value_raw >> (FRACBITS + EXPBITS))) & 1;
+# endif
+#endif
+
+ dst->sign = sign;
+ if (exp == 0)
+ {
+ /* Hmm. Looks like 0 */
+ if (fraction == 0
+#ifdef NO_DENORMALS
+ || 1
+#endif
+ )
+ {
+ /* tastes like zero */
+ dst->class = CLASS_ZERO;
+ }
+ else
+ {
+ /* Zero exponent with nonzero fraction - it's denormalized,
+ so there isn't a leading implicit one - we'll shift it so
+ it gets one. */
+ dst->normal_exp = exp - EXPBIAS + 1;
+ fraction <<= NGARDS;
+
+ dst->class = CLASS_NUMBER;
+#if 1
+ while (fraction < IMPLICIT_1)
+ {
+ fraction <<= 1;
+ dst->normal_exp--;
+ }
+#endif
+ dst->fraction.ll = fraction;
+ }
+ }
+ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp == EXPMAX)
+ {
+ /* Huge exponent*/
+ if (fraction == 0)
+ {
+ /* Attached to a zero fraction - means infinity */
+ dst->class = CLASS_INFINITY;
+ }
+ else
+ {
+ /* Nonzero fraction, means nan */
+#ifdef QUIET_NAN_NEGATED
+ if ((fraction & QUIET_NAN) == 0)
+#else
+ if (fraction & QUIET_NAN)
+#endif
+ {
+ dst->class = CLASS_QNAN;
+ }
+ else
+ {
+ dst->class = CLASS_SNAN;
+ }
+ /* Keep the fraction part as the nan number */
+ dst->fraction.ll = fraction;
+ }
+ }
+ else
+ {
+ /* Nothing strange about this number */
+ dst->normal_exp = exp - EXPBIAS;
+ dst->class = CLASS_NUMBER;
+ dst->fraction.ll = (fraction << NGARDS) | IMPLICIT_1;
+ }
+}
+#endif /* L_unpack_df || L_unpack_sf */
+
+#if defined(L_addsub_sf) || defined(L_addsub_df) || defined(L_addsub_tf)
+static fp_number_type *
+_fpadd_parts (fp_number_type * a,
+ fp_number_type * b,
+ fp_number_type * tmp)
+{
+ intfrac tfraction;
+
+ /* Put commonly used fields in local variables. */
+ int a_normal_exp;
+ int b_normal_exp;
+ fractype a_fraction;
+ fractype b_fraction;
+
+ if (isnan (a))
+ {
+ return a;
+ }
+ if (isnan (b))
+ {
+ return b;
+ }
+ if (isinf (a))
+ {
+ /* Adding infinities with opposite signs yields a NaN. */
+ if (isinf (b) && a->sign != b->sign)
+ return nan ();
+ return a;
+ }
+ if (isinf (b))
+ {
+ return b;
+ }
+ if (iszero (b))
+ {
+ if (iszero (a))
+ {
+ *tmp = *a;
+ tmp->sign = a->sign & b->sign;
+ return tmp;
+ }
+ return a;
+ }
+ if (iszero (a))
+ {
+ return b;
+ }
+
+ /* Got two numbers. shift the smaller and increment the exponent till
+ they're the same */
+ {
+ int diff;
+
+ a_normal_exp = a->normal_exp;
+ b_normal_exp = b->normal_exp;
+ a_fraction = a->fraction.ll;
+ b_fraction = b->fraction.ll;
+
+ diff = a_normal_exp - b_normal_exp;
+
+ if (diff < 0)
+ diff = -diff;
+ if (diff < FRAC_NBITS)
+ {
+ /* ??? This does shifts one bit at a time. Optimize. */
+ while (a_normal_exp > b_normal_exp)
+ {
+ b_normal_exp++;
+ LSHIFT (b_fraction);
+ }
+ while (b_normal_exp > a_normal_exp)
+ {
+ a_normal_exp++;
+ LSHIFT (a_fraction);
+ }
+ }
+ else
+ {
+ /* Somethings's up.. choose the biggest */
+ if (a_normal_exp > b_normal_exp)
+ {
+ b_normal_exp = a_normal_exp;
+ b_fraction = 0;
+ }
+ else
+ {
+ a_normal_exp = b_normal_exp;
+ a_fraction = 0;
+ }
+ }
+ }
+
+ if (a->sign != b->sign)
+ {
+ if (a->sign)
+ {
+ tfraction = -a_fraction + b_fraction;
+ }
+ else
+ {
+ tfraction = a_fraction - b_fraction;
+ }
+ if (tfraction >= 0)
+ {
+ tmp->sign = 0;
+ tmp->normal_exp = a_normal_exp;
+ tmp->fraction.ll = tfraction;
+ }
+ else
+ {
+ tmp->sign = 1;
+ tmp->normal_exp = a_normal_exp;
+ tmp->fraction.ll = -tfraction;
+ }
+ /* and renormalize it */
+
+ while (tmp->fraction.ll < IMPLICIT_1 && tmp->fraction.ll)
+ {
+ tmp->fraction.ll <<= 1;
+ tmp->normal_exp--;
+ }
+ }
+ else
+ {
+ tmp->sign = a->sign;
+ tmp->normal_exp = a_normal_exp;
+ tmp->fraction.ll = a_fraction + b_fraction;
+ }
+ tmp->class = CLASS_NUMBER;
+ /* Now the fraction is added, we have to shift down to renormalize the
+ number */
+
+ if (tmp->fraction.ll >= IMPLICIT_2)
+ {
+ LSHIFT (tmp->fraction.ll);
+ tmp->normal_exp++;
+ }
+ return tmp;
+
+}
+
+FLO_type
+add (FLO_type arg_a, FLO_type arg_b)
+{
+ fp_number_type a;
+ fp_number_type b;
+ fp_number_type tmp;
+ fp_number_type *res;
+ FLO_union_type au, bu;
+
+ au.value = arg_a;
+ bu.value = arg_b;
+
+ unpack_d (&au, &a);
+ unpack_d (&bu, &b);
+
+ res = _fpadd_parts (&a, &b, &tmp);
+
+ return pack_d (res);
+}
+
+FLO_type
+sub (FLO_type arg_a, FLO_type arg_b)
+{
+ fp_number_type a;
+ fp_number_type b;
+ fp_number_type tmp;
+ fp_number_type *res;
+ FLO_union_type au, bu;
+
+ au.value = arg_a;
+ bu.value = arg_b;
+
+ unpack_d (&au, &a);
+ unpack_d (&bu, &b);
+
+ b.sign ^= 1;
+
+ res = _fpadd_parts (&a, &b, &tmp);
+
+ return pack_d (res);
+}
+#endif /* L_addsub_sf || L_addsub_df */
+
+#if defined(L_mul_sf) || defined(L_mul_df) || defined(L_mul_tf)
+static inline __attribute__ ((__always_inline__)) fp_number_type *
+_fpmul_parts ( fp_number_type * a,
+ fp_number_type * b,
+ fp_number_type * tmp)
+{
+ fractype low = 0;
+ fractype high = 0;
+
+ if (isnan (a))
+ {
+ a->sign = a->sign != b->sign;
+ return a;
+ }
+ if (isnan (b))
+ {
+ b->sign = a->sign != b->sign;
+ return b;
+ }
+ if (isinf (a))
+ {
+ if (iszero (b))
+ return nan ();
+ a->sign = a->sign != b->sign;
+ return a;
+ }
+ if (isinf (b))
+ {
+ if (iszero (a))
+ {
+ return nan ();
+ }
+ b->sign = a->sign != b->sign;
+ return b;
+ }
+ if (iszero (a))
+ {
+ a->sign = a->sign != b->sign;
+ return a;
+ }
+ if (iszero (b))
+ {
+ b->sign = a->sign != b->sign;
+ return b;
+ }
+
+ /* Calculate the mantissa by multiplying both numbers to get a
+ twice-as-wide number. */
+ {
+#if defined(NO_DI_MODE) || defined(TFLOAT)
+ {
+ fractype x = a->fraction.ll;
+ fractype ylow = b->fraction.ll;
+ fractype yhigh = 0;
+ int bit;
+
+ /* ??? This does multiplies one bit at a time. Optimize. */
+ for (bit = 0; bit < FRAC_NBITS; bit++)
+ {
+ int carry;
+
+ if (x & 1)
+ {
+ carry = (low += ylow) < ylow;
+ high += yhigh + carry;
+ }
+ yhigh <<= 1;
+ if (ylow & FRACHIGH)
+ {
+ yhigh |= 1;
+ }
+ ylow <<= 1;
+ x >>= 1;
+ }
+ }
+#elif defined(FLOAT)
+ /* Multiplying two USIs to get a UDI, we're safe. */
+ {
+ UDItype answer = (UDItype)a->fraction.ll * (UDItype)b->fraction.ll;
+
+ high = answer >> BITS_PER_SI;
+ low = answer;
+ }
+#else
+ /* fractype is DImode, but we need the result to be twice as wide.
+ Assuming a widening multiply from DImode to TImode is not
+ available, build one by hand. */
+ {
+ USItype nl = a->fraction.ll;
+ USItype nh = a->fraction.ll >> BITS_PER_SI;
+ USItype ml = b->fraction.ll;
+ USItype mh = b->fraction.ll >> BITS_PER_SI;
+ UDItype pp_ll = (UDItype) ml * nl;
+ UDItype pp_hl = (UDItype) mh * nl;
+ UDItype pp_lh = (UDItype) ml * nh;
+ UDItype pp_hh = (UDItype) mh * nh;
+ UDItype res2 = 0;
+ UDItype res0 = 0;
+ UDItype ps_hh__ = pp_hl + pp_lh;
+ if (ps_hh__ < pp_hl)
+ res2 += (UDItype)1 << BITS_PER_SI;
+ pp_hl = (UDItype)(USItype)ps_hh__ << BITS_PER_SI;
+ res0 = pp_ll + pp_hl;
+ if (res0 < pp_ll)
+ res2++;
+ res2 += (ps_hh__ >> BITS_PER_SI) + pp_hh;
+ high = res2;
+ low = res0;
+ }
+#endif
+ }
+
+ tmp->normal_exp = a->normal_exp + b->normal_exp
+ + FRAC_NBITS - (FRACBITS + NGARDS);
+ tmp->sign = a->sign != b->sign;
+ while (high >= IMPLICIT_2)
+ {
+ tmp->normal_exp++;
+ if (high & 1)
+ {
+ low >>= 1;
+ low |= FRACHIGH;
+ }
+ high >>= 1;
+ }
+ while (high < IMPLICIT_1)
+ {
+ tmp->normal_exp--;
+
+ high <<= 1;
+ if (low & FRACHIGH)
+ high |= 1;
+ low <<= 1;
+ }
+ /* rounding is tricky. if we only round if it won't make us round later. */
+#if 0
+ if (low & FRACHIGH2)
+ {
+ if (((high & GARDMASK) != GARDMSB)
+ && (((high + 1) & GARDMASK) == GARDMSB))
+ {
+ /* don't round, it gets done again later. */
+ }
+ else
+ {
+ high++;
+ }
+ }
+#endif
+ if (!ROUND_TOWARDS_ZERO && (high & GARDMASK) == GARDMSB)
+ {
+ if (high & (1 << NGARDS))
+ {
+ /* half way, so round to even */
+ high += GARDROUND + 1;
+ }
+ else if (low)
+ {
+ /* but we really weren't half way */
+ high += GARDROUND + 1;
+ }
+ }
+ tmp->fraction.ll = high;
+ tmp->class = CLASS_NUMBER;
+ return tmp;
+}
+
+FLO_type
+multiply (FLO_type arg_a, FLO_type arg_b)
+{
+ fp_number_type a;
+ fp_number_type b;
+ fp_number_type tmp;
+ fp_number_type *res;
+ FLO_union_type au, bu;
+
+ au.value = arg_a;
+ bu.value = arg_b;
+
+ unpack_d (&au, &a);
+ unpack_d (&bu, &b);
+
+ res = _fpmul_parts (&a, &b, &tmp);
+
+ return pack_d (res);
+}
+#endif /* L_mul_sf || L_mul_df */
+
+#if defined(L_div_sf) || defined(L_div_df) || defined(L_div_tf)
+static inline __attribute__ ((__always_inline__)) fp_number_type *
+_fpdiv_parts (fp_number_type * a,
+ fp_number_type * b)
+{
+ fractype bit;
+ fractype numerator;
+ fractype denominator;
+ fractype quotient;
+
+ if (isnan (a))
+ {
+ return a;
+ }
+ if (isnan (b))
+ {
+ return b;
+ }
+
+ a->sign = a->sign ^ b->sign;
+
+ if (isinf (a) || iszero (a))
+ {
+ if (a->class == b->class)
+ return nan ();
+ return a;
+ }
+
+ if (isinf (b))
+ {
+ a->fraction.ll = 0;
+ a->normal_exp = 0;
+ return a;
+ }
+ if (iszero (b))
+ {
+ a->class = CLASS_INFINITY;
+ return a;
+ }
+
+ /* Calculate the mantissa by multiplying both 64bit numbers to get a
+ 128 bit number */
+ {
+ /* quotient =
+ ( numerator / denominator) * 2^(numerator exponent - denominator exponent)
+ */
+
+ a->normal_exp = a->normal_exp - b->normal_exp;
+ numerator = a->fraction.ll;
+ denominator = b->fraction.ll;
+
+ if (numerator < denominator)
+ {
+ /* Fraction will be less than 1.0 */
+ numerator *= 2;
+ a->normal_exp--;
+ }
+ bit = IMPLICIT_1;
+ quotient = 0;
+ /* ??? Does divide one bit at a time. Optimize. */
+ while (bit)
+ {
+ if (numerator >= denominator)
+ {
+ quotient |= bit;
+ numerator -= denominator;
+ }
+ bit >>= 1;
+ numerator *= 2;
+ }
+
+ if (!ROUND_TOWARDS_ZERO && (quotient & GARDMASK) == GARDMSB)
+ {
+ if (quotient & (1 << NGARDS))
+ {
+ /* half way, so round to even */
+ quotient += GARDROUND + 1;
+ }
+ else if (numerator)
+ {
+ /* but we really weren't half way, more bits exist */
+ quotient += GARDROUND + 1;
+ }
+ }
+
+ a->fraction.ll = quotient;
+ return (a);
+ }
+}
+
+FLO_type
+divide (FLO_type arg_a, FLO_type arg_b)
+{
+ fp_number_type a;
+ fp_number_type b;
+ fp_number_type *res;
+ FLO_union_type au, bu;
+
+ au.value = arg_a;
+ bu.value = arg_b;
+
+ unpack_d (&au, &a);
+ unpack_d (&bu, &b);
+
+ res = _fpdiv_parts (&a, &b);
+
+ return pack_d (res);
+}
+#endif /* L_div_sf || L_div_df */
+
+#if defined(L_fpcmp_parts_sf) || defined(L_fpcmp_parts_df) \
+ || defined(L_fpcmp_parts_tf)
+/* according to the demo, fpcmp returns a comparison with 0... thus
+ a<b -> -1
+ a==b -> 0
+ a>b -> +1
+ */
+
+int
+__fpcmp_parts (fp_number_type * a, fp_number_type * b)
+{
+#if 0
+ /* either nan -> unordered. Must be checked outside of this routine. */
+ if (isnan (a) && isnan (b))
+ {
+ return 1; /* still unordered! */
+ }
+#endif
+
+ if (isnan (a) || isnan (b))
+ {
+ return 1; /* how to indicate unordered compare? */
+ }
+ if (isinf (a) && isinf (b))
+ {
+ /* +inf > -inf, but +inf != +inf */
+ /* b \a| +inf(0)| -inf(1)
+ ______\+--------+--------
+ +inf(0)| a==b(0)| a<b(-1)
+ -------+--------+--------
+ -inf(1)| a>b(1) | a==b(0)
+ -------+--------+--------
+ So since unordered must be nonzero, just line up the columns...
+ */
+ return b->sign - a->sign;
+ }
+ /* but not both... */
+ if (isinf (a))
+ {
+ return a->sign ? -1 : 1;
+ }
+ if (isinf (b))
+ {
+ return b->sign ? 1 : -1;
+ }
+ if (iszero (a) && iszero (b))
+ {
+ return 0;
+ }
+ if (iszero (a))
+ {
+ return b->sign ? 1 : -1;
+ }
+ if (iszero (b))
+ {
+ return a->sign ? -1 : 1;
+ }
+ /* now both are "normal". */
+ if (a->sign != b->sign)
+ {
+ /* opposite signs */
+ return a->sign ? -1 : 1;
+ }
+ /* same sign; exponents? */
+ if (a->normal_exp > b->normal_exp)
+ {
+ return a->sign ? -1 : 1;
+ }
+ if (a->normal_exp < b->normal_exp)
+ {
+ return a->sign ? 1 : -1;
+ }
+ /* same exponents; check size. */
+ if (a->fraction.ll > b->fraction.ll)
+ {
+ return a->sign ? -1 : 1;
+ }
+ if (a->fraction.ll < b->fraction.ll)
+ {
+ return a->sign ? 1 : -1;
+ }
+ /* after all that, they're equal. */
+ return 0;
+}
+#endif
+
+#if defined(L_compare_sf) || defined(L_compare_df) || defined(L_compoare_tf)
+CMPtype
+compare (FLO_type arg_a, FLO_type arg_b)
+{
+ fp_number_type a;
+ fp_number_type b;
+ FLO_union_type au, bu;
+
+ au.value = arg_a;
+ bu.value = arg_b;
+
+ unpack_d (&au, &a);
+ unpack_d (&bu, &b);
+
+ return __fpcmp_parts (&a, &b);
+}
+#endif /* L_compare_sf || L_compare_df */
+
+#ifndef US_SOFTWARE_GOFAST
+
+/* These should be optimized for their specific tasks someday. */
+
+#if defined(L_eq_sf) || defined(L_eq_df) || defined(L_eq_tf)
+CMPtype
+_eq_f2 (FLO_type arg_a, FLO_type arg_b)
+{
+ fp_number_type a;
+ fp_number_type b;
+ FLO_union_type au, bu;
+
+ au.value = arg_a;
+ bu.value = arg_b;
+
+ unpack_d (&au, &a);
+ unpack_d (&bu, &b);
+
+ if (isnan (&a) || isnan (&b))
+ return 1; /* false, truth == 0 */
+
+ return __fpcmp_parts (&a, &b) ;
+}
+#endif /* L_eq_sf || L_eq_df */
+
+#if defined(L_ne_sf) || defined(L_ne_df) || defined(L_ne_tf)
+CMPtype
+_ne_f2 (FLO_type arg_a, FLO_type arg_b)
+{
+ fp_number_type a;
+ fp_number_type b;
+ FLO_union_type au, bu;
+
+ au.value = arg_a;
+ bu.value = arg_b;
+
+ unpack_d (&au, &a);
+ unpack_d (&bu, &b);
+
+ if (isnan (&a) || isnan (&b))
+ return 1; /* true, truth != 0 */
+
+ return __fpcmp_parts (&a, &b) ;
+}
+#endif /* L_ne_sf || L_ne_df */
+
+#if defined(L_gt_sf) || defined(L_gt_df) || defined(L_gt_tf)
+CMPtype
+_gt_f2 (FLO_type arg_a, FLO_type arg_b)
+{
+ fp_number_type a;
+ fp_number_type b;
+ FLO_union_type au, bu;
+
+ au.value = arg_a;
+ bu.value = arg_b;
+
+ unpack_d (&au, &a);
+ unpack_d (&bu, &b);
+
+ if (isnan (&a) || isnan (&b))
+ return -1; /* false, truth > 0 */
+
+ return __fpcmp_parts (&a, &b);
+}
+#endif /* L_gt_sf || L_gt_df */
+
+#if defined(L_ge_sf) || defined(L_ge_df) || defined(L_ge_tf)
+CMPtype
+_ge_f2 (FLO_type arg_a, FLO_type arg_b)
+{
+ fp_number_type a;
+ fp_number_type b;
+ FLO_union_type au, bu;
+
+ au.value = arg_a;
+ bu.value = arg_b;
+
+ unpack_d (&au, &a);
+ unpack_d (&bu, &b);
+
+ if (isnan (&a) || isnan (&b))
+ return -1; /* false, truth >= 0 */
+ return __fpcmp_parts (&a, &b) ;
+}
+#endif /* L_ge_sf || L_ge_df */
+
+#if defined(L_lt_sf) || defined(L_lt_df) || defined(L_lt_tf)
+CMPtype
+_lt_f2 (FLO_type arg_a, FLO_type arg_b)
+{
+ fp_number_type a;
+ fp_number_type b;
+ FLO_union_type au, bu;
+
+ au.value = arg_a;
+ bu.value = arg_b;
+
+ unpack_d (&au, &a);
+ unpack_d (&bu, &b);
+
+ if (isnan (&a) || isnan (&b))
+ return 1; /* false, truth < 0 */
+
+ return __fpcmp_parts (&a, &b);
+}
+#endif /* L_lt_sf || L_lt_df */
+
+#if defined(L_le_sf) || defined(L_le_df) || defined(L_le_tf)
+CMPtype
+_le_f2 (FLO_type arg_a, FLO_type arg_b)
+{
+ fp_number_type a;
+ fp_number_type b;
+ FLO_union_type au, bu;
+
+ au.value = arg_a;
+ bu.value = arg_b;
+
+ unpack_d (&au, &a);
+ unpack_d (&bu, &b);
+
+ if (isnan (&a) || isnan (&b))
+ return 1; /* false, truth <= 0 */
+
+ return __fpcmp_parts (&a, &b) ;
+}
+#endif /* L_le_sf || L_le_df */
+
+#endif /* ! US_SOFTWARE_GOFAST */
+
+#if defined(L_unord_sf) || defined(L_unord_df) || defined(L_unord_tf)
+CMPtype
+_unord_f2 (FLO_type arg_a, FLO_type arg_b)
+{
+ fp_number_type a;
+ fp_number_type b;
+ FLO_union_type au, bu;
+
+ au.value = arg_a;
+ bu.value = arg_b;
+
+ unpack_d (&au, &a);
+ unpack_d (&bu, &b);
+
+ return (isnan (&a) || isnan (&b));
+}
+#endif /* L_unord_sf || L_unord_df */
+
+#if defined(L_si_to_sf) || defined(L_si_to_df) || defined(L_si_to_tf)
+FLO_type
+si_to_float (SItype arg_a)
+{
+ fp_number_type in;
+
+ in.class = CLASS_NUMBER;
+ in.sign = arg_a < 0;
+ if (!arg_a)
+ {
+ in.class = CLASS_ZERO;
+ }
+ else
+ {
+ in.normal_exp = FRACBITS + NGARDS;
+ if (in.sign)
+ {
+ /* Special case for minint, since there is no +ve integer
+ representation for it */
+ if (arg_a == (- MAX_SI_INT - 1))
+ {
+ return (FLO_type)(- MAX_SI_INT - 1);
+ }
+ in.fraction.ll = (-arg_a);
+ }
+ else
+ in.fraction.ll = arg_a;
+
+ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS)))
+ {
+ in.fraction.ll <<= 1;
+ in.normal_exp -= 1;
+ }
+ }
+ return pack_d (&in);
+}
+#endif /* L_si_to_sf || L_si_to_df */
+
+#if defined(L_usi_to_sf) || defined(L_usi_to_df) || defined(L_usi_to_tf)
+FLO_type
+usi_to_float (USItype arg_a)
+{
+ fp_number_type in;
+
+ in.sign = 0;
+ if (!arg_a)
+ {
+ in.class = CLASS_ZERO;
+ }
+ else
+ {
+ in.class = CLASS_NUMBER;
+ in.normal_exp = FRACBITS + NGARDS;
+ in.fraction.ll = arg_a;
+
+ while (in.fraction.ll > ((fractype)1 << (FRACBITS + NGARDS)))
+ {
+ in.fraction.ll >>= 1;
+ in.normal_exp += 1;
+ }
+ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS)))
+ {
+ in.fraction.ll <<= 1;
+ in.normal_exp -= 1;
+ }
+ }
+ return pack_d (&in);
+}
+#endif
+
+#if defined(L_sf_to_si) || defined(L_df_to_si) || defined(L_tf_to_si)
+SItype
+float_to_si (FLO_type arg_a)
+{
+ fp_number_type a;
+ SItype tmp;
+ FLO_union_type au;
+
+ au.value = arg_a;
+ unpack_d (&au, &a);
+
+ if (iszero (&a))
+ return 0;
+ if (isnan (&a))
+ return 0;
+ /* get reasonable MAX_SI_INT... */
+ if (isinf (&a))
+ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT;
+ /* it is a number, but a small one */
+ if (a.normal_exp < 0)
+ return 0;
+ if (a.normal_exp > BITS_PER_SI - 2)
+ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT;
+ tmp = a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp);
+ return a.sign ? (-tmp) : (tmp);
+}
+#endif /* L_sf_to_si || L_df_to_si */
+
+#if defined(L_sf_to_usi) || defined(L_df_to_usi) || defined(L_tf_to_usi)
+#if defined US_SOFTWARE_GOFAST || defined(L_tf_to_usi)
+/* While libgcc2.c defines its own __fixunssfsi and __fixunsdfsi routines,
+ we also define them for GOFAST because the ones in libgcc2.c have the
+ wrong names and I'd rather define these here and keep GOFAST CYG-LOC's
+ out of libgcc2.c. We can't define these here if not GOFAST because then
+ there'd be duplicate copies. */
+
+USItype
+float_to_usi (FLO_type arg_a)
+{
+ fp_number_type a;
+ FLO_union_type au;
+
+ au.value = arg_a;
+ unpack_d (&au, &a);
+
+ if (iszero (&a))
+ return 0;
+ if (isnan (&a))
+ return 0;
+ /* it is a negative number */
+ if (a.sign)
+ return 0;
+ /* get reasonable MAX_USI_INT... */
+ if (isinf (&a))
+ return MAX_USI_INT;
+ /* it is a number, but a small one */
+ if (a.normal_exp < 0)
+ return 0;
+ if (a.normal_exp > BITS_PER_SI - 1)
+ return MAX_USI_INT;
+ else if (a.normal_exp > (FRACBITS + NGARDS))
+ return a.fraction.ll << (a.normal_exp - (FRACBITS + NGARDS));
+ else
+ return a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp);
+}
+#endif /* US_SOFTWARE_GOFAST */
+#endif /* L_sf_to_usi || L_df_to_usi */
+
+#if defined(L_negate_sf) || defined(L_negate_df) || defined(L_negate_tf)
+FLO_type
+negate (FLO_type arg_a)
+{
+ fp_number_type a;
+ FLO_union_type au;
+
+ au.value = arg_a;
+ unpack_d (&au, &a);
+
+ flip_sign (&a);
+ return pack_d (&a);
+}
+#endif /* L_negate_sf || L_negate_df */
+
+#ifdef FLOAT
+
+#if defined(L_make_sf)
+SFtype
+__make_fp(fp_class_type class,
+ unsigned int sign,
+ int exp,
+ USItype frac)
+{
+ fp_number_type in;
+
+ in.class = class;
+ in.sign = sign;
+ in.normal_exp = exp;
+ in.fraction.ll = frac;
+ return pack_d (&in);
+}
+#endif /* L_make_sf */
+
+#ifndef FLOAT_ONLY
+
+/* This enables one to build an fp library that supports float but not double.
+ Otherwise, we would get an undefined reference to __make_dp.
+ This is needed for some 8-bit ports that can't handle well values that
+ are 8-bytes in size, so we just don't support double for them at all. */
+
+#if defined(L_sf_to_df)
+DFtype
+sf_to_df (SFtype arg_a)
+{
+ fp_number_type in;
+ FLO_union_type au;
+
+ au.value = arg_a;
+ unpack_d (&au, &in);
+
+ return __make_dp (in.class, in.sign, in.normal_exp,
+ ((UDItype) in.fraction.ll) << F_D_BITOFF);
+}
+#endif /* L_sf_to_df */
+
+#if defined(L_sf_to_tf) && defined(TMODES)
+TFtype
+sf_to_tf (SFtype arg_a)
+{
+ fp_number_type in;
+ FLO_union_type au;
+
+ au.value = arg_a;
+ unpack_d (&au, &in);
+
+ return __make_tp (in.class, in.sign, in.normal_exp,
+ ((UTItype) in.fraction.ll) << F_T_BITOFF);
+}
+#endif /* L_sf_to_df */
+
+#endif /* ! FLOAT_ONLY */
+#endif /* FLOAT */
+
+#ifndef FLOAT
+
+extern SFtype __make_fp (fp_class_type, unsigned int, int, USItype);
+
+#if defined(L_make_df)
+DFtype
+__make_dp (fp_class_type class, unsigned int sign, int exp, UDItype frac)
+{
+ fp_number_type in;
+
+ in.class = class;
+ in.sign = sign;
+ in.normal_exp = exp;
+ in.fraction.ll = frac;
+ return pack_d (&in);
+}
+#endif /* L_make_df */
+
+#if defined(L_df_to_sf)
+SFtype
+df_to_sf (DFtype arg_a)
+{
+ fp_number_type in;
+ USItype sffrac;
+ FLO_union_type au;
+
+ au.value = arg_a;
+ unpack_d (&au, &in);
+
+ sffrac = in.fraction.ll >> F_D_BITOFF;
+
+ /* We set the lowest guard bit in SFFRAC if we discarded any non
+ zero bits. */
+ if ((in.fraction.ll & (((USItype) 1 << F_D_BITOFF) - 1)) != 0)
+ sffrac |= 1;
+
+ return __make_fp (in.class, in.sign, in.normal_exp, sffrac);
+}
+#endif /* L_df_to_sf */
+
+#if defined(L_df_to_tf) && defined(TMODES) \
+ && !defined(FLOAT) && !defined(TFLOAT)
+TFtype
+df_to_tf (DFtype arg_a)
+{
+ fp_number_type in;
+ FLO_union_type au;
+
+ au.value = arg_a;
+ unpack_d (&au, &in);
+
+ return __make_tp (in.class, in.sign, in.normal_exp,
+ ((UTItype) in.fraction.ll) << D_T_BITOFF);
+}
+#endif /* L_sf_to_df */
+
+#ifdef TFLOAT
+#if defined(L_make_tf)
+TFtype
+__make_tp(fp_class_type class,
+ unsigned int sign,
+ int exp,
+ UTItype frac)
+{
+ fp_number_type in;
+
+ in.class = class;
+ in.sign = sign;
+ in.normal_exp = exp;
+ in.fraction.ll = frac;
+ return pack_d (&in);
+}
+#endif /* L_make_tf */
+
+#if defined(L_tf_to_df)
+DFtype
+tf_to_df (TFtype arg_a)
+{
+ fp_number_type in;
+ UDItype sffrac;
+ FLO_union_type au;
+
+ au.value = arg_a;
+ unpack_d (&au, &in);
+
+ sffrac = in.fraction.ll >> D_T_BITOFF;
+
+ /* We set the lowest guard bit in SFFRAC if we discarded any non
+ zero bits. */
+ if ((in.fraction.ll & (((UTItype) 1 << D_T_BITOFF) - 1)) != 0)
+ sffrac |= 1;
+
+ return __make_dp (in.class, in.sign, in.normal_exp, sffrac);
+}
+#endif /* L_tf_to_df */
+
+#if defined(L_tf_to_sf)
+SFtype
+tf_to_sf (TFtype arg_a)
+{
+ fp_number_type in;
+ USItype sffrac;
+ FLO_union_type au;
+
+ au.value = arg_a;
+ unpack_d (&au, &in);
+
+ sffrac = in.fraction.ll >> F_T_BITOFF;
+
+ /* We set the lowest guard bit in SFFRAC if we discarded any non
+ zero bits. */
+ if ((in.fraction.ll & (((UTItype) 1 << F_T_BITOFF) - 1)) != 0)
+ sffrac |= 1;
+
+ return __make_fp (in.class, in.sign, in.normal_exp, sffrac);
+}
+#endif /* L_tf_to_sf */
+#endif /* TFLOAT */
+
+#endif /* ! FLOAT */
+#endif /* !EXTENDED_FLOAT_STUBS */
diff -durN gcc-3.4.6.orig/gcc/config/nios2/nios2-fp-bit.c gcc-3.4.6/gcc/config/nios2/nios2-fp-bit.c
--- gcc-3.4.6.orig/gcc/config/nios2/nios2-fp-bit.c 1970-01-01 01:00:00.000000000 +0100
+++ gcc-3.4.6/gcc/config/nios2/nios2-fp-bit.c 2007-08-15 23:09:36.000000000 +0200
@@ -0,0 +1,1652 @@
+#define FLOAT
+/* This is a software floating point library which can be used
+ for targets without hardware floating point.
+ Copyright (C) 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004
+ Free Software Foundation, Inc.
+
+This file is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+In addition to the permissions in the GNU General Public License, the
+Free Software Foundation gives you unlimited permission to link the
+compiled version of this file with other programs, and to distribute
+those programs without any restriction coming from the use of this
+file. (The General Public License restrictions do apply in other
+respects; for example, they cover modification of the file, and
+distribution when not linked into another program.)
+
+This file is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* As a special exception, if you link this library with other files,
+ some of which are compiled with GCC, to produce an executable,
+ this library does not by itself cause the resulting executable
+ to be covered by the GNU General Public License.
+ This exception does not however invalidate any other reasons why
+ the executable file might be covered by the GNU General Public License. */
+
+/* This implements IEEE 754 format arithmetic, but does not provide a
+ mechanism for setting the rounding mode, or for generating or handling
+ exceptions.
+
+ The original code by Steve Chamberlain, hacked by Mark Eichin and Jim
+ Wilson, all of Cygnus Support. */
+
+/* The intended way to use this file is to make two copies, add `#define FLOAT'
+ to one copy, then compile both copies and add them to libgcc.a. */
+
+#include "tconfig.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "config/fp-bit.h"
+
+/* The following macros can be defined to change the behavior of this file:
+ FLOAT: Implement a `float', aka SFmode, fp library. If this is not
+ defined, then this file implements a `double', aka DFmode, fp library.
+ FLOAT_ONLY: Used with FLOAT, to implement a `float' only library, i.e.
+ don't include float->double conversion which requires the double library.
+ This is useful only for machines which can't support doubles, e.g. some
+ 8-bit processors.
+ CMPtype: Specify the type that floating point compares should return.
+ This defaults to SItype, aka int.
+ US_SOFTWARE_GOFAST: This makes all entry points use the same names as the
+ US Software goFast library.
+ _DEBUG_BITFLOAT: This makes debugging the code a little easier, by adding
+ two integers to the FLO_union_type.
+ NO_DENORMALS: Disable handling of denormals.
+ NO_NANS: Disable nan and infinity handling
+ SMALL_MACHINE: Useful when operations on QIs and HIs are faster
+ than on an SI */
+
+/* We don't currently support extended floats (long doubles) on machines
+ without hardware to deal with them.
+
+ These stubs are just to keep the linker from complaining about unresolved
+ references which can be pulled in from libio & libstdc++, even if the
+ user isn't using long doubles. However, they may generate an unresolved
+ external to abort if abort is not used by the function, and the stubs
+ are referenced from within libc, since libgcc goes before and after the
+ system library. */
+
+#ifdef DECLARE_LIBRARY_RENAMES
+ DECLARE_LIBRARY_RENAMES
+#endif
+
+#ifdef EXTENDED_FLOAT_STUBS
+extern void abort (void);
+void __extendsfxf2 (void) { abort(); }
+void __extenddfxf2 (void) { abort(); }
+void __truncxfdf2 (void) { abort(); }
+void __truncxfsf2 (void) { abort(); }
+void __fixxfsi (void) { abort(); }
+void __floatsixf (void) { abort(); }
+void __addxf3 (void) { abort(); }
+void __subxf3 (void) { abort(); }
+void __mulxf3 (void) { abort(); }
+void __divxf3 (void) { abort(); }
+void __negxf2 (void) { abort(); }
+void __eqxf2 (void) { abort(); }
+void __nexf2 (void) { abort(); }
+void __gtxf2 (void) { abort(); }
+void __gexf2 (void) { abort(); }
+void __lexf2 (void) { abort(); }
+void __ltxf2 (void) { abort(); }
+
+void __extendsftf2 (void) { abort(); }
+void __extenddftf2 (void) { abort(); }
+void __trunctfdf2 (void) { abort(); }
+void __trunctfsf2 (void) { abort(); }
+void __fixtfsi (void) { abort(); }
+void __floatsitf (void) { abort(); }
+void __addtf3 (void) { abort(); }
+void __subtf3 (void) { abort(); }
+void __multf3 (void) { abort(); }
+void __divtf3 (void) { abort(); }
+void __negtf2 (void) { abort(); }
+void __eqtf2 (void) { abort(); }
+void __netf2 (void) { abort(); }
+void __gttf2 (void) { abort(); }
+void __getf2 (void) { abort(); }
+void __letf2 (void) { abort(); }
+void __lttf2 (void) { abort(); }
+#else /* !EXTENDED_FLOAT_STUBS, rest of file */
+
+/* IEEE "special" number predicates */
+
+#ifdef NO_NANS
+
+#define nan() 0
+#define isnan(x) 0
+#define isinf(x) 0
+#else
+
+#if defined L_thenan_sf
+const fp_number_type __thenan_sf = { CLASS_SNAN, 0, 0, {(fractype) 0} };
+#elif defined L_thenan_df
+const fp_number_type __thenan_df = { CLASS_SNAN, 0, 0, {(fractype) 0} };
+#elif defined L_thenan_tf
+const fp_number_type __thenan_tf = { CLASS_SNAN, 0, 0, {(fractype) 0} };
+#elif defined TFLOAT
+extern const fp_number_type __thenan_tf;
+#elif defined FLOAT
+extern const fp_number_type __thenan_sf;
+#else
+extern const fp_number_type __thenan_df;
+#endif
+
+INLINE
+static fp_number_type *
+nan (void)
+{
+ /* Discard the const qualifier... */
+#ifdef TFLOAT
+ return (fp_number_type *) (& __thenan_tf);
+#elif defined FLOAT
+ return (fp_number_type *) (& __thenan_sf);
+#else
+ return (fp_number_type *) (& __thenan_df);
+#endif
+}
+
+INLINE
+static int
+isnan ( fp_number_type * x)
+{
+ return x->class == CLASS_SNAN || x->class == CLASS_QNAN;
+}
+
+INLINE
+static int
+isinf ( fp_number_type * x)
+{
+ return x->class == CLASS_INFINITY;
+}
+
+#endif /* NO_NANS */
+
+INLINE
+static int
+iszero ( fp_number_type * x)
+{
+ return x->class == CLASS_ZERO;
+}
+
+INLINE
+static void
+flip_sign ( fp_number_type * x)
+{
+ x->sign = !x->sign;
+}
+
+extern FLO_type pack_d ( fp_number_type * );
+
+#if defined(L_pack_df) || defined(L_pack_sf) || defined(L_pack_tf)
+FLO_type
+pack_d ( fp_number_type * src)
+{
+ FLO_union_type dst;
+ fractype fraction = src->fraction.ll; /* wasn't unsigned before? */
+ int sign = src->sign;
+ int exp = 0;
+
+ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && (isnan (src) || isinf (src)))
+ {
+ /* We can't represent these values accurately. By using the
+ largest possible magnitude, we guarantee that the conversion
+ of infinity is at least as big as any finite number. */
+ exp = EXPMAX;
+ fraction = ((fractype) 1 << FRACBITS) - 1;
+ }
+ else if (isnan (src))
+ {
+ exp = EXPMAX;
+ if (src->class == CLASS_QNAN || 1)
+ {
+#ifdef QUIET_NAN_NEGATED
+ fraction |= QUIET_NAN - 1;
+#else
+ fraction |= QUIET_NAN;
+#endif
+ }
+ }
+ else if (isinf (src))
+ {
+ exp = EXPMAX;
+ fraction = 0;
+ }
+ else if (iszero (src))
+ {
+ exp = 0;
+ fraction = 0;
+ }
+ else if (fraction == 0)
+ {
+ exp = 0;
+ }
+ else
+ {
+ if (src->normal_exp < NORMAL_EXPMIN)
+ {
+#ifdef NO_DENORMALS
+ /* Go straight to a zero representation if denormals are not
+ supported. The denormal handling would be harmless but
+ isn't unnecessary. */
+ exp = 0;
+ fraction = 0;
+#else /* NO_DENORMALS */
+ /* This number's exponent is too low to fit into the bits
+ available in the number, so we'll store 0 in the exponent and
+ shift the fraction to the right to make up for it. */
+
+ int shift = NORMAL_EXPMIN - src->normal_exp;
+
+ exp = 0;
+
+ if (shift > FRAC_NBITS - NGARDS)
+ {
+ /* No point shifting, since it's more that 64 out. */
+ fraction = 0;
+ }
+ else
+ {
+ int lowbit = (fraction & (((fractype)1 << shift) - 1)) ? 1 : 0;
+ fraction = (fraction >> shift) | lowbit;
+ }
+ if ((fraction & GARDMASK) == GARDMSB)
+ {
+ if ((fraction & (1 << NGARDS)))
+ fraction += GARDROUND + 1;
+ }
+ else
+ {
+ /* Add to the guards to round up. */
+ fraction += GARDROUND;
+ }
+ /* Perhaps the rounding means we now need to change the
+ exponent, because the fraction is no longer denormal. */
+ if (fraction >= IMPLICIT_1)
+ {
+ exp += 1;
+ }
+ fraction >>= NGARDS;
+#endif /* NO_DENORMALS */
+ }
+ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS)
+ && src->normal_exp > EXPBIAS)
+ {
+ exp = EXPMAX;
+ fraction = 0;
+ }
+ else
+ {
+ exp = src->normal_exp + EXPBIAS;
+ if (!ROUND_TOWARDS_ZERO)
+ {
+ /* IF the gard bits are the all zero, but the first, then we're
+ half way between two numbers, choose the one which makes the
+ lsb of the answer 0. */
+ if ((fraction & GARDMASK) == GARDMSB)
+ {
+ if (fraction & (1 << NGARDS))
+ fraction += GARDROUND + 1;
+ }
+ else
+ {
+ /* Add a one to the guards to round up */
+ fraction += GARDROUND;
+ }
+ if (fraction >= IMPLICIT_2)
+ {
+ fraction >>= 1;
+ exp += 1;
+ }
+ }
+ fraction >>= NGARDS;
+
+ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp > EXPMAX)
+ {
+ /* Saturate on overflow. */
+ exp = EXPMAX;
+ fraction = ((fractype) 1 << FRACBITS) - 1;
+ }
+ }
+ }
+
+ /* We previously used bitfields to store the number, but this doesn't
+ handle little/big endian systems conveniently, so use shifts and
+ masks */
+#ifdef FLOAT_BIT_ORDER_MISMATCH
+ dst.bits.fraction = fraction;
+ dst.bits.exp = exp;
+ dst.bits.sign = sign;
+#else
+# if defined TFLOAT && defined HALFFRACBITS
+ {
+ halffractype high, low, unity;
+ int lowsign, lowexp;
+
+ unity = (halffractype) 1 << HALFFRACBITS;
+
+ /* Set HIGH to the high double's significand, masking out the implicit 1.
+ Set LOW to the low double's full significand. */
+ high = (fraction >> (FRACBITS - HALFFRACBITS)) & (unity - 1);
+ low = fraction & (unity * 2 - 1);
+
+ /* Get the initial sign and exponent of the low double. */
+ lowexp = exp - HALFFRACBITS - 1;
+ lowsign = sign;
+
+ /* HIGH should be rounded like a normal double, making |LOW| <=
+ 0.5 ULP of HIGH. Assume round-to-nearest. */
+ if (exp < EXPMAX)
+ if (low > unity || (low == unity && (high & 1) == 1))
+ {
+ /* Round HIGH up and adjust LOW to match. */
+ high++;
+ if (high == unity)
+ {
+ /* May make it infinite, but that's OK. */
+ high = 0;
+ exp++;
+ }
+ low = unity * 2 - low;
+ lowsign ^= 1;
+ }
+
+ high |= (halffractype) exp << HALFFRACBITS;
+ high |= (halffractype) sign << (HALFFRACBITS + EXPBITS);
+
+ if (exp == EXPMAX || exp == 0 || low == 0)
+ low = 0;
+ else
+ {
+ while (lowexp > 0 && low < unity)
+ {
+ low <<= 1;
+ lowexp--;
+ }
+
+ if (lowexp <= 0)
+ {
+ halffractype roundmsb, round;
+ int shift;
+
+ shift = 1 - lowexp;
+ roundmsb = (1 << (shift - 1));
+ round = low & ((roundmsb << 1) - 1);
+
+ low >>= shift;
+ lowexp = 0;
+
+ if (round > roundmsb || (round == roundmsb && (low & 1) == 1))
+ {
+ low++;
+ if (low == unity)
+ /* LOW rounds up to the smallest normal number. */
+ lowexp++;
+ }
+ }
+
+ low &= unity - 1;
+ low |= (halffractype) lowexp << HALFFRACBITS;
+ low |= (halffractype) lowsign << (HALFFRACBITS + EXPBITS);
+ }
+ dst.value_raw = ((fractype) high << HALFSHIFT) | low;
+ }
+# else
+ dst.value_raw = fraction & ((((fractype)1) << FRACBITS) - (fractype)1);
+ dst.value_raw |= ((fractype) (exp & ((1 << EXPBITS) - 1))) << FRACBITS;
+ dst.value_raw |= ((fractype) (sign & 1)) << (FRACBITS | EXPBITS);
+# endif
+#endif
+
+#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT)
+#ifdef TFLOAT
+ {
+ qrtrfractype tmp1 = dst.words[0];
+ qrtrfractype tmp2 = dst.words[1];
+ dst.words[0] = dst.words[3];
+ dst.words[1] = dst.words[2];
+ dst.words[2] = tmp2;
+ dst.words[3] = tmp1;
+ }
+#else
+ {
+ halffractype tmp = dst.words[0];
+ dst.words[0] = dst.words[1];
+ dst.words[1] = tmp;
+ }
+#endif
+#endif
+
+ return dst.value;
+}
+#endif
+
+#if defined(L_unpack_df) || defined(L_unpack_sf) || defined(L_unpack_tf)
+void
+unpack_d (FLO_union_type * src, fp_number_type * dst)
+{
+ /* We previously used bitfields to store the number, but this doesn't
+ handle little/big endian systems conveniently, so use shifts and
+ masks */
+ fractype fraction;
+ int exp;
+ int sign;
+
+#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT)
+ FLO_union_type swapped;
+
+#ifdef TFLOAT
+ swapped.words[0] = src->words[3];
+ swapped.words[1] = src->words[2];
+ swapped.words[2] = src->words[1];
+ swapped.words[3] = src->words[0];
+#else
+ swapped.words[0] = src->words[1];
+ swapped.words[1] = src->words[0];
+#endif
+ src = &swapped;
+#endif
+
+#ifdef FLOAT_BIT_ORDER_MISMATCH
+ fraction = src->bits.fraction;
+ exp = src->bits.exp;
+ sign = src->bits.sign;
+#else
+# if defined TFLOAT && defined HALFFRACBITS
+ {
+ halffractype high, low;
+
+ high = src->value_raw >> HALFSHIFT;
+ low = src->value_raw & (((fractype)1 << HALFSHIFT) - 1);
+
+ fraction = high & ((((fractype)1) << HALFFRACBITS) - 1);
+ fraction <<= FRACBITS - HALFFRACBITS;
+ exp = ((int)(high >> HALFFRACBITS)) & ((1 << EXPBITS) - 1);
+ sign = ((int)(high >> (((HALFFRACBITS + EXPBITS))))) & 1;
+
+ if (exp != EXPMAX && exp != 0 && low != 0)
+ {
+ int lowexp = ((int)(low >> HALFFRACBITS)) & ((1 << EXPBITS) - 1);
+ int lowsign = ((int)(low >> (((HALFFRACBITS + EXPBITS))))) & 1;
+ int shift;
+ fractype xlow;
+
+ xlow = low & ((((fractype)1) << HALFFRACBITS) - 1);
+ if (lowexp)
+ xlow |= (((halffractype)1) << HALFFRACBITS);
+ else
+ lowexp = 1;
+ shift = (FRACBITS - HALFFRACBITS) - (exp - lowexp);
+ if (shift > 0)
+ xlow <<= shift;
+ else if (shift < 0)
+ xlow >>= -shift;
+ if (sign == lowsign)
+ fraction += xlow;
+ else if (fraction >= xlow)
+ fraction -= xlow;
+ else
+ {
+ /* The high part is a power of two but the full number is lower.
+ This code will leave the implicit 1 in FRACTION, but we'd
+ have added that below anyway. */
+ fraction = (((fractype) 1 << FRACBITS) - xlow) << 1;
+ exp--;
+ }
+ }
+ }
+# else
+ fraction = src->value_raw & ((((fractype)1) << FRACBITS) - 1);
+ exp = ((int)(src->value_raw >> FRACBITS)) & ((1 << EXPBITS) - 1);
+ sign = ((int)(src->value_raw >> (FRACBITS + EXPBITS))) & 1;
+# endif
+#endif
+
+ dst->sign = sign;
+ if (exp == 0)
+ {
+ /* Hmm. Looks like 0 */
+ if (fraction == 0
+#ifdef NO_DENORMALS
+ || 1
+#endif
+ )
+ {
+ /* tastes like zero */
+ dst->class = CLASS_ZERO;
+ }
+ else
+ {
+ /* Zero exponent with nonzero fraction - it's denormalized,
+ so there isn't a leading implicit one - we'll shift it so
+ it gets one. */
+ dst->normal_exp = exp - EXPBIAS + 1;
+ fraction <<= NGARDS;
+
+ dst->class = CLASS_NUMBER;
+#if 1
+ while (fraction < IMPLICIT_1)
+ {
+ fraction <<= 1;
+ dst->normal_exp--;
+ }
+#endif
+ dst->fraction.ll = fraction;
+ }
+ }
+ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp == EXPMAX)
+ {
+ /* Huge exponent*/
+ if (fraction == 0)
+ {
+ /* Attached to a zero fraction - means infinity */
+ dst->class = CLASS_INFINITY;
+ }
+ else
+ {
+ /* Nonzero fraction, means nan */
+#ifdef QUIET_NAN_NEGATED
+ if ((fraction & QUIET_NAN) == 0)
+#else
+ if (fraction & QUIET_NAN)
+#endif
+ {
+ dst->class = CLASS_QNAN;
+ }
+ else
+ {
+ dst->class = CLASS_SNAN;
+ }
+ /* Keep the fraction part as the nan number */
+ dst->fraction.ll = fraction;
+ }
+ }
+ else
+ {
+ /* Nothing strange about this number */
+ dst->normal_exp = exp - EXPBIAS;
+ dst->class = CLASS_NUMBER;
+ dst->fraction.ll = (fraction << NGARDS) | IMPLICIT_1;
+ }
+}
+#endif /* L_unpack_df || L_unpack_sf */
+
+#if defined(L_addsub_sf) || defined(L_addsub_df) || defined(L_addsub_tf)
+static fp_number_type *
+_fpadd_parts (fp_number_type * a,
+ fp_number_type * b,
+ fp_number_type * tmp)
+{
+ intfrac tfraction;
+
+ /* Put commonly used fields in local variables. */
+ int a_normal_exp;
+ int b_normal_exp;
+ fractype a_fraction;
+ fractype b_fraction;
+
+ if (isnan (a))
+ {
+ return a;
+ }
+ if (isnan (b))
+ {
+ return b;
+ }
+ if (isinf (a))
+ {
+ /* Adding infinities with opposite signs yields a NaN. */
+ if (isinf (b) && a->sign != b->sign)
+ return nan ();
+ return a;
+ }
+ if (isinf (b))
+ {
+ return b;
+ }
+ if (iszero (b))
+ {
+ if (iszero (a))
+ {
+ *tmp = *a;
+ tmp->sign = a->sign & b->sign;
+ return tmp;
+ }
+ return a;
+ }
+ if (iszero (a))
+ {
+ return b;
+ }
+
+ /* Got two numbers. shift the smaller and increment the exponent till
+ they're the same */
+ {
+ int diff;
+
+ a_normal_exp = a->normal_exp;
+ b_normal_exp = b->normal_exp;
+ a_fraction = a->fraction.ll;
+ b_fraction = b->fraction.ll;
+
+ diff = a_normal_exp - b_normal_exp;
+
+ if (diff < 0)
+ diff = -diff;
+ if (diff < FRAC_NBITS)
+ {
+ /* ??? This does shifts one bit at a time. Optimize. */
+ while (a_normal_exp > b_normal_exp)
+ {
+ b_normal_exp++;
+ LSHIFT (b_fraction);
+ }
+ while (b_normal_exp > a_normal_exp)
+ {
+ a_normal_exp++;
+ LSHIFT (a_fraction);
+ }
+ }
+ else
+ {
+ /* Somethings's up.. choose the biggest */
+ if (a_normal_exp > b_normal_exp)
+ {
+ b_normal_exp = a_normal_exp;
+ b_fraction = 0;
+ }
+ else
+ {
+ a_normal_exp = b_normal_exp;
+ a_fraction = 0;
+ }
+ }
+ }
+
+ if (a->sign != b->sign)
+ {
+ if (a->sign)
+ {
+ tfraction = -a_fraction + b_fraction;
+ }
+ else
+ {
+ tfraction = a_fraction - b_fraction;
+ }
+ if (tfraction >= 0)
+ {
+ tmp->sign = 0;
+ tmp->normal_exp = a_normal_exp;
+ tmp->fraction.ll = tfraction;
+ }
+ else
+ {
+ tmp->sign = 1;
+ tmp->normal_exp = a_normal_exp;
+ tmp->fraction.ll = -tfraction;
+ }
+ /* and renormalize it */
+
+ while (tmp->fraction.ll < IMPLICIT_1 && tmp->fraction.ll)
+ {
+ tmp->fraction.ll <<= 1;
+ tmp->normal_exp--;
+ }
+ }
+ else
+ {
+ tmp->sign = a->sign;
+ tmp->normal_exp = a_normal_exp;
+ tmp->fraction.ll = a_fraction + b_fraction;
+ }
+ tmp->class = CLASS_NUMBER;
+ /* Now the fraction is added, we have to shift down to renormalize the
+ number */
+
+ if (tmp->fraction.ll >= IMPLICIT_2)
+ {
+ LSHIFT (tmp->fraction.ll);
+ tmp->normal_exp++;
+ }
+ return tmp;
+
+}
+
+FLO_type
+add (FLO_type arg_a, FLO_type arg_b)
+{
+ fp_number_type a;
+ fp_number_type b;
+ fp_number_type tmp;
+ fp_number_type *res;
+ FLO_union_type au, bu;
+
+ au.value = arg_a;
+ bu.value = arg_b;
+
+ unpack_d (&au, &a);
+ unpack_d (&bu, &b);
+
+ res = _fpadd_parts (&a, &b, &tmp);
+
+ return pack_d (res);
+}
+
+FLO_type
+sub (FLO_type arg_a, FLO_type arg_b)
+{
+ fp_number_type a;
+ fp_number_type b;
+ fp_number_type tmp;
+ fp_number_type *res;
+ FLO_union_type au, bu;
+
+ au.value = arg_a;
+ bu.value = arg_b;
+
+ unpack_d (&au, &a);
+ unpack_d (&bu, &b);
+
+ b.sign ^= 1;
+
+ res = _fpadd_parts (&a, &b, &tmp);
+
+ return pack_d (res);
+}
+#endif /* L_addsub_sf || L_addsub_df */
+
+#if defined(L_mul_sf) || defined(L_mul_df) || defined(L_mul_tf)
+static inline __attribute__ ((__always_inline__)) fp_number_type *
+_fpmul_parts ( fp_number_type * a,
+ fp_number_type * b,
+ fp_number_type * tmp)
+{
+ fractype low = 0;
+ fractype high = 0;
+
+ if (isnan (a))
+ {
+ a->sign = a->sign != b->sign;
+ return a;
+ }
+ if (isnan (b))
+ {
+ b->sign = a->sign != b->sign;
+ return b;
+ }
+ if (isinf (a))
+ {
+ if (iszero (b))
+ return nan ();
+ a->sign = a->sign != b->sign;
+ return a;
+ }
+ if (isinf (b))
+ {
+ if (iszero (a))
+ {
+ return nan ();
+ }
+ b->sign = a->sign != b->sign;
+ return b;
+ }
+ if (iszero (a))
+ {
+ a->sign = a->sign != b->sign;
+ return a;
+ }
+ if (iszero (b))
+ {
+ b->sign = a->sign != b->sign;
+ return b;
+ }
+
+ /* Calculate the mantissa by multiplying both numbers to get a
+ twice-as-wide number. */
+ {
+#if defined(NO_DI_MODE) || defined(TFLOAT)
+ {
+ fractype x = a->fraction.ll;
+ fractype ylow = b->fraction.ll;
+ fractype yhigh = 0;
+ int bit;
+
+ /* ??? This does multiplies one bit at a time. Optimize. */
+ for (bit = 0; bit < FRAC_NBITS; bit++)
+ {
+ int carry;
+
+ if (x & 1)
+ {
+ carry = (low += ylow) < ylow;
+ high += yhigh + carry;
+ }
+ yhigh <<= 1;
+ if (ylow & FRACHIGH)
+ {
+ yhigh |= 1;
+ }
+ ylow <<= 1;
+ x >>= 1;
+ }
+ }
+#elif defined(FLOAT)
+ /* Multiplying two USIs to get a UDI, we're safe. */
+ {
+ UDItype answer = (UDItype)a->fraction.ll * (UDItype)b->fraction.ll;
+
+ high = answer >> BITS_PER_SI;
+ low = answer;
+ }
+#else
+ /* fractype is DImode, but we need the result to be twice as wide.
+ Assuming a widening multiply from DImode to TImode is not
+ available, build one by hand. */
+ {
+ USItype nl = a->fraction.ll;
+ USItype nh = a->fraction.ll >> BITS_PER_SI;
+ USItype ml = b->fraction.ll;
+ USItype mh = b->fraction.ll >> BITS_PER_SI;
+ UDItype pp_ll = (UDItype) ml * nl;
+ UDItype pp_hl = (UDItype) mh * nl;
+ UDItype pp_lh = (UDItype) ml * nh;
+ UDItype pp_hh = (UDItype) mh * nh;
+ UDItype res2 = 0;
+ UDItype res0 = 0;
+ UDItype ps_hh__ = pp_hl + pp_lh;
+ if (ps_hh__ < pp_hl)
+ res2 += (UDItype)1 << BITS_PER_SI;
+ pp_hl = (UDItype)(USItype)ps_hh__ << BITS_PER_SI;
+ res0 = pp_ll + pp_hl;
+ if (res0 < pp_ll)
+ res2++;
+ res2 += (ps_hh__ >> BITS_PER_SI) + pp_hh;
+ high = res2;
+ low = res0;
+ }
+#endif
+ }
+
+ tmp->normal_exp = a->normal_exp + b->normal_exp
+ + FRAC_NBITS - (FRACBITS + NGARDS);
+ tmp->sign = a->sign != b->sign;
+ while (high >= IMPLICIT_2)
+ {
+ tmp->normal_exp++;
+ if (high & 1)
+ {
+ low >>= 1;
+ low |= FRACHIGH;
+ }
+ high >>= 1;
+ }
+ while (high < IMPLICIT_1)
+ {
+ tmp->normal_exp--;
+
+ high <<= 1;
+ if (low & FRACHIGH)
+ high |= 1;
+ low <<= 1;
+ }
+ /* rounding is tricky. if we only round if it won't make us round later. */
+#if 0
+ if (low & FRACHIGH2)
+ {
+ if (((high & GARDMASK) != GARDMSB)
+ && (((high + 1) & GARDMASK) == GARDMSB))
+ {
+ /* don't round, it gets done again later. */
+ }
+ else
+ {
+ high++;
+ }
+ }
+#endif
+ if (!ROUND_TOWARDS_ZERO && (high & GARDMASK) == GARDMSB)
+ {
+ if (high & (1 << NGARDS))
+ {
+ /* half way, so round to even */
+ high += GARDROUND + 1;
+ }
+ else if (low)
+ {
+ /* but we really weren't half way */
+ high += GARDROUND + 1;
+ }
+ }
+ tmp->fraction.ll = high;
+ tmp->class = CLASS_NUMBER;
+ return tmp;
+}
+
+FLO_type
+multiply (FLO_type arg_a, FLO_type arg_b)
+{
+ fp_number_type a;
+ fp_number_type b;
+ fp_number_type tmp;
+ fp_number_type *res;
+ FLO_union_type au, bu;
+
+ au.value = arg_a;
+ bu.value = arg_b;
+
+ unpack_d (&au, &a);
+ unpack_d (&bu, &b);
+
+ res = _fpmul_parts (&a, &b, &tmp);
+
+ return pack_d (res);
+}
+#endif /* L_mul_sf || L_mul_df */
+
+#if defined(L_div_sf) || defined(L_div_df) || defined(L_div_tf)
+static inline __attribute__ ((__always_inline__)) fp_number_type *
+_fpdiv_parts (fp_number_type * a,
+ fp_number_type * b)
+{
+ fractype bit;
+ fractype numerator;
+ fractype denominator;
+ fractype quotient;
+
+ if (isnan (a))
+ {
+ return a;
+ }
+ if (isnan (b))
+ {
+ return b;
+ }
+
+ a->sign = a->sign ^ b->sign;
+
+ if (isinf (a) || iszero (a))
+ {
+ if (a->class == b->class)
+ return nan ();
+ return a;
+ }
+
+ if (isinf (b))
+ {
+ a->fraction.ll = 0;
+ a->normal_exp = 0;
+ return a;
+ }
+ if (iszero (b))
+ {
+ a->class = CLASS_INFINITY;
+ return a;
+ }
+
+ /* Calculate the mantissa by multiplying both 64bit numbers to get a
+ 128 bit number */
+ {
+ /* quotient =
+ ( numerator / denominator) * 2^(numerator exponent - denominator exponent)
+ */
+
+ a->normal_exp = a->normal_exp - b->normal_exp;
+ numerator = a->fraction.ll;
+ denominator = b->fraction.ll;
+
+ if (numerator < denominator)
+ {
+ /* Fraction will be less than 1.0 */
+ numerator *= 2;
+ a->normal_exp--;
+ }
+ bit = IMPLICIT_1;
+ quotient = 0;
+ /* ??? Does divide one bit at a time. Optimize. */
+ while (bit)
+ {
+ if (numerator >= denominator)
+ {
+ quotient |= bit;
+ numerator -= denominator;
+ }
+ bit >>= 1;
+ numerator *= 2;
+ }
+
+ if (!ROUND_TOWARDS_ZERO && (quotient & GARDMASK) == GARDMSB)
+ {
+ if (quotient & (1 << NGARDS))
+ {
+ /* half way, so round to even */
+ quotient += GARDROUND + 1;
+ }
+ else if (numerator)
+ {
+ /* but we really weren't half way, more bits exist */
+ quotient += GARDROUND + 1;
+ }
+ }
+
+ a->fraction.ll = quotient;
+ return (a);
+ }
+}
+
+FLO_type
+divide (FLO_type arg_a, FLO_type arg_b)
+{
+ fp_number_type a;
+ fp_number_type b;
+ fp_number_type *res;
+ FLO_union_type au, bu;
+
+ au.value = arg_a;
+ bu.value = arg_b;
+
+ unpack_d (&au, &a);
+ unpack_d (&bu, &b);
+
+ res = _fpdiv_parts (&a, &b);
+
+ return pack_d (res);
+}
+#endif /* L_div_sf || L_div_df */
+
+#if defined(L_fpcmp_parts_sf) || defined(L_fpcmp_parts_df) \
+ || defined(L_fpcmp_parts_tf)
+/* according to the demo, fpcmp returns a comparison with 0... thus
+ a<b -> -1
+ a==b -> 0
+ a>b -> +1
+ */
+
+int
+__fpcmp_parts (fp_number_type * a, fp_number_type * b)
+{
+#if 0
+ /* either nan -> unordered. Must be checked outside of this routine. */
+ if (isnan (a) && isnan (b))
+ {
+ return 1; /* still unordered! */
+ }
+#endif
+
+ if (isnan (a) || isnan (b))
+ {
+ return 1; /* how to indicate unordered compare? */
+ }
+ if (isinf (a) && isinf (b))
+ {
+ /* +inf > -inf, but +inf != +inf */
+ /* b \a| +inf(0)| -inf(1)
+ ______\+--------+--------
+ +inf(0)| a==b(0)| a<b(-1)
+ -------+--------+--------
+ -inf(1)| a>b(1) | a==b(0)
+ -------+--------+--------
+ So since unordered must be nonzero, just line up the columns...
+ */
+ return b->sign - a->sign;
+ }
+ /* but not both... */
+ if (isinf (a))
+ {
+ return a->sign ? -1 : 1;
+ }
+ if (isinf (b))
+ {
+ return b->sign ? 1 : -1;
+ }
+ if (iszero (a) && iszero (b))
+ {
+ return 0;
+ }
+ if (iszero (a))
+ {
+ return b->sign ? 1 : -1;
+ }
+ if (iszero (b))
+ {
+ return a->sign ? -1 : 1;
+ }
+ /* now both are "normal". */
+ if (a->sign != b->sign)
+ {
+ /* opposite signs */
+ return a->sign ? -1 : 1;
+ }
+ /* same sign; exponents? */
+ if (a->normal_exp > b->normal_exp)
+ {
+ return a->sign ? -1 : 1;
+ }
+ if (a->normal_exp < b->normal_exp)
+ {
+ return a->sign ? 1 : -1;
+ }
+ /* same exponents; check size. */
+ if (a->fraction.ll > b->fraction.ll)
+ {
+ return a->sign ? -1 : 1;
+ }
+ if (a->fraction.ll < b->fraction.ll)
+ {
+ return a->sign ? 1 : -1;
+ }
+ /* after all that, they're equal. */
+ return 0;
+}
+#endif
+
+#if defined(L_compare_sf) || defined(L_compare_df) || defined(L_compoare_tf)
+CMPtype
+compare (FLO_type arg_a, FLO_type arg_b)
+{
+ fp_number_type a;
+ fp_number_type b;
+ FLO_union_type au, bu;
+
+ au.value = arg_a;
+ bu.value = arg_b;
+
+ unpack_d (&au, &a);
+ unpack_d (&bu, &b);
+
+ return __fpcmp_parts (&a, &b);
+}
+#endif /* L_compare_sf || L_compare_df */
+
+#ifndef US_SOFTWARE_GOFAST
+
+/* These should be optimized for their specific tasks someday. */
+
+#if defined(L_eq_sf) || defined(L_eq_df) || defined(L_eq_tf)
+CMPtype
+_eq_f2 (FLO_type arg_a, FLO_type arg_b)
+{
+ fp_number_type a;
+ fp_number_type b;
+ FLO_union_type au, bu;
+
+ au.value = arg_a;
+ bu.value = arg_b;
+
+ unpack_d (&au, &a);
+ unpack_d (&bu, &b);
+
+ if (isnan (&a) || isnan (&b))
+ return 1; /* false, truth == 0 */
+
+ return __fpcmp_parts (&a, &b) ;
+}
+#endif /* L_eq_sf || L_eq_df */
+
+#if defined(L_ne_sf) || defined(L_ne_df) || defined(L_ne_tf)
+CMPtype
+_ne_f2 (FLO_type arg_a, FLO_type arg_b)
+{
+ fp_number_type a;
+ fp_number_type b;
+ FLO_union_type au, bu;
+
+ au.value = arg_a;
+ bu.value = arg_b;
+
+ unpack_d (&au, &a);
+ unpack_d (&bu, &b);
+
+ if (isnan (&a) || isnan (&b))
+ return 1; /* true, truth != 0 */
+
+ return __fpcmp_parts (&a, &b) ;
+}
+#endif /* L_ne_sf || L_ne_df */
+
+#if defined(L_gt_sf) || defined(L_gt_df) || defined(L_gt_tf)
+CMPtype
+_gt_f2 (FLO_type arg_a, FLO_type arg_b)
+{
+ fp_number_type a;
+ fp_number_type b;
+ FLO_union_type au, bu;
+
+ au.value = arg_a;
+ bu.value = arg_b;
+
+ unpack_d (&au, &a);
+ unpack_d (&bu, &b);
+
+ if (isnan (&a) || isnan (&b))
+ return -1; /* false, truth > 0 */
+
+ return __fpcmp_parts (&a, &b);
+}
+#endif /* L_gt_sf || L_gt_df */
+
+#if defined(L_ge_sf) || defined(L_ge_df) || defined(L_ge_tf)
+CMPtype
+_ge_f2 (FLO_type arg_a, FLO_type arg_b)
+{
+ fp_number_type a;
+ fp_number_type b;
+ FLO_union_type au, bu;
+
+ au.value = arg_a;
+ bu.value = arg_b;
+
+ unpack_d (&au, &a);
+ unpack_d (&bu, &b);
+
+ if (isnan (&a) || isnan (&b))
+ return -1; /* false, truth >= 0 */
+ return __fpcmp_parts (&a, &b) ;
+}
+#endif /* L_ge_sf || L_ge_df */
+
+#if defined(L_lt_sf) || defined(L_lt_df) || defined(L_lt_tf)
+CMPtype
+_lt_f2 (FLO_type arg_a, FLO_type arg_b)
+{
+ fp_number_type a;
+ fp_number_type b;
+ FLO_union_type au, bu;
+
+ au.value = arg_a;
+ bu.value = arg_b;
+
+ unpack_d (&au, &a);
+ unpack_d (&bu, &b);
+
+ if (isnan (&a) || isnan (&b))
+ return 1; /* false, truth < 0 */
+
+ return __fpcmp_parts (&a, &b);
+}
+#endif /* L_lt_sf || L_lt_df */
+
+#if defined(L_le_sf) || defined(L_le_df) || defined(L_le_tf)
+CMPtype
+_le_f2 (FLO_type arg_a, FLO_type arg_b)
+{
+ fp_number_type a;
+ fp_number_type b;
+ FLO_union_type au, bu;
+
+ au.value = arg_a;
+ bu.value = arg_b;
+
+ unpack_d (&au, &a);
+ unpack_d (&bu, &b);
+
+ if (isnan (&a) || isnan (&b))
+ return 1; /* false, truth <= 0 */
+
+ return __fpcmp_parts (&a, &b) ;
+}
+#endif /* L_le_sf || L_le_df */
+
+#endif /* ! US_SOFTWARE_GOFAST */
+
+#if defined(L_unord_sf) || defined(L_unord_df) || defined(L_unord_tf)
+CMPtype
+_unord_f2 (FLO_type arg_a, FLO_type arg_b)
+{
+ fp_number_type a;
+ fp_number_type b;
+ FLO_union_type au, bu;
+
+ au.value = arg_a;
+ bu.value = arg_b;
+
+ unpack_d (&au, &a);
+ unpack_d (&bu, &b);
+
+ return (isnan (&a) || isnan (&b));
+}
+#endif /* L_unord_sf || L_unord_df */
+
+#if defined(L_si_to_sf) || defined(L_si_to_df) || defined(L_si_to_tf)
+FLO_type
+si_to_float (SItype arg_a)
+{
+ fp_number_type in;
+
+ in.class = CLASS_NUMBER;
+ in.sign = arg_a < 0;
+ if (!arg_a)
+ {
+ in.class = CLASS_ZERO;
+ }
+ else
+ {
+ in.normal_exp = FRACBITS + NGARDS;
+ if (in.sign)
+ {
+ /* Special case for minint, since there is no +ve integer
+ representation for it */
+ if (arg_a == (- MAX_SI_INT - 1))
+ {
+ return (FLO_type)(- MAX_SI_INT - 1);
+ }
+ in.fraction.ll = (-arg_a);
+ }
+ else
+ in.fraction.ll = arg_a;
+
+ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS)))
+ {
+ in.fraction.ll <<= 1;
+ in.normal_exp -= 1;
+ }
+ }
+ return pack_d (&in);
+}
+#endif /* L_si_to_sf || L_si_to_df */
+
+#if defined(L_usi_to_sf) || defined(L_usi_to_df) || defined(L_usi_to_tf)
+FLO_type
+usi_to_float (USItype arg_a)
+{
+ fp_number_type in;
+
+ in.sign = 0;
+ if (!arg_a)
+ {
+ in.class = CLASS_ZERO;
+ }
+ else
+ {
+ in.class = CLASS_NUMBER;
+ in.normal_exp = FRACBITS + NGARDS;
+ in.fraction.ll = arg_a;
+
+ while (in.fraction.ll > ((fractype)1 << (FRACBITS + NGARDS)))
+ {
+ in.fraction.ll >>= 1;
+ in.normal_exp += 1;
+ }
+ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS)))
+ {
+ in.fraction.ll <<= 1;
+ in.normal_exp -= 1;
+ }
+ }
+ return pack_d (&in);
+}
+#endif
+
+#if defined(L_sf_to_si) || defined(L_df_to_si) || defined(L_tf_to_si)
+SItype
+float_to_si (FLO_type arg_a)
+{
+ fp_number_type a;
+ SItype tmp;
+ FLO_union_type au;
+
+ au.value = arg_a;
+ unpack_d (&au, &a);
+
+ if (iszero (&a))
+ return 0;
+ if (isnan (&a))
+ return 0;
+ /* get reasonable MAX_SI_INT... */
+ if (isinf (&a))
+ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT;
+ /* it is a number, but a small one */
+ if (a.normal_exp < 0)
+ return 0;
+ if (a.normal_exp > BITS_PER_SI - 2)
+ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT;
+ tmp = a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp);
+ return a.sign ? (-tmp) : (tmp);
+}
+#endif /* L_sf_to_si || L_df_to_si */
+
+#if defined(L_sf_to_usi) || defined(L_df_to_usi) || defined(L_tf_to_usi)
+#if defined US_SOFTWARE_GOFAST || defined(L_tf_to_usi)
+/* While libgcc2.c defines its own __fixunssfsi and __fixunsdfsi routines,
+ we also define them for GOFAST because the ones in libgcc2.c have the
+ wrong names and I'd rather define these here and keep GOFAST CYG-LOC's
+ out of libgcc2.c. We can't define these here if not GOFAST because then
+ there'd be duplicate copies. */
+
+USItype
+float_to_usi (FLO_type arg_a)
+{
+ fp_number_type a;
+ FLO_union_type au;
+
+ au.value = arg_a;
+ unpack_d (&au, &a);
+
+ if (iszero (&a))
+ return 0;
+ if (isnan (&a))
+ return 0;
+ /* it is a negative number */
+ if (a.sign)
+ return 0;
+ /* get reasonable MAX_USI_INT... */
+ if (isinf (&a))
+ return MAX_USI_INT;
+ /* it is a number, but a small one */
+ if (a.normal_exp < 0)
+ return 0;
+ if (a.normal_exp > BITS_PER_SI - 1)
+ return MAX_USI_INT;
+ else if (a.normal_exp > (FRACBITS + NGARDS))
+ return a.fraction.ll << (a.normal_exp - (FRACBITS + NGARDS));
+ else
+ return a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp);
+}
+#endif /* US_SOFTWARE_GOFAST */
+#endif /* L_sf_to_usi || L_df_to_usi */
+
+#if defined(L_negate_sf) || defined(L_negate_df) || defined(L_negate_tf)
+FLO_type
+negate (FLO_type arg_a)
+{
+ fp_number_type a;
+ FLO_union_type au;
+
+ au.value = arg_a;
+ unpack_d (&au, &a);
+
+ flip_sign (&a);
+ return pack_d (&a);
+}
+#endif /* L_negate_sf || L_negate_df */
+
+#ifdef FLOAT
+
+#if defined(L_make_sf)
+SFtype
+__make_fp(fp_class_type class,
+ unsigned int sign,
+ int exp,
+ USItype frac)
+{
+ fp_number_type in;
+
+ in.class = class;
+ in.sign = sign;
+ in.normal_exp = exp;
+ in.fraction.ll = frac;
+ return pack_d (&in);
+}
+#endif /* L_make_sf */
+
+#ifndef FLOAT_ONLY
+
+/* This enables one to build an fp library that supports float but not double.
+ Otherwise, we would get an undefined reference to __make_dp.
+ This is needed for some 8-bit ports that can't handle well values that
+ are 8-bytes in size, so we just don't support double for them at all. */
+
+#if defined(L_sf_to_df)
+DFtype
+sf_to_df (SFtype arg_a)
+{
+ fp_number_type in;
+ FLO_union_type au;
+
+ au.value = arg_a;
+ unpack_d (&au, &in);
+
+ return __make_dp (in.class, in.sign, in.normal_exp,
+ ((UDItype) in.fraction.ll) << F_D_BITOFF);
+}
+#endif /* L_sf_to_df */
+
+#if defined(L_sf_to_tf) && defined(TMODES)
+TFtype
+sf_to_tf (SFtype arg_a)
+{
+ fp_number_type in;
+ FLO_union_type au;
+
+ au.value = arg_a;
+ unpack_d (&au, &in);
+
+ return __make_tp (in.class, in.sign, in.normal_exp,
+ ((UTItype) in.fraction.ll) << F_T_BITOFF);
+}
+#endif /* L_sf_to_df */
+
+#endif /* ! FLOAT_ONLY */
+#endif /* FLOAT */
+
+#ifndef FLOAT
+
+extern SFtype __make_fp (fp_class_type, unsigned int, int, USItype);
+
+#if defined(L_make_df)
+DFtype
+__make_dp (fp_class_type class, unsigned int sign, int exp, UDItype frac)
+{
+ fp_number_type in;
+
+ in.class = class;
+ in.sign = sign;
+ in.normal_exp = exp;
+ in.fraction.ll = frac;
+ return pack_d (&in);
+}
+#endif /* L_make_df */
+
+#if defined(L_df_to_sf)
+SFtype
+df_to_sf (DFtype arg_a)
+{
+ fp_number_type in;
+ USItype sffrac;
+ FLO_union_type au;
+
+ au.value = arg_a;
+ unpack_d (&au, &in);
+
+ sffrac = in.fraction.ll >> F_D_BITOFF;
+
+ /* We set the lowest guard bit in SFFRAC if we discarded any non
+ zero bits. */
+ if ((in.fraction.ll & (((USItype) 1 << F_D_BITOFF) - 1)) != 0)
+ sffrac |= 1;
+
+ return __make_fp (in.class, in.sign, in.normal_exp, sffrac);
+}
+#endif /* L_df_to_sf */
+
+#if defined(L_df_to_tf) && defined(TMODES) \
+ && !defined(FLOAT) && !defined(TFLOAT)
+TFtype
+df_to_tf (DFtype arg_a)
+{
+ fp_number_type in;
+ FLO_union_type au;
+
+ au.value = arg_a;
+ unpack_d (&au, &in);
+
+ return __make_tp (in.class, in.sign, in.normal_exp,
+ ((UTItype) in.fraction.ll) << D_T_BITOFF);
+}
+#endif /* L_sf_to_df */
+
+#ifdef TFLOAT
+#if defined(L_make_tf)
+TFtype
+__make_tp(fp_class_type class,
+ unsigned int sign,
+ int exp,
+ UTItype frac)
+{
+ fp_number_type in;
+
+ in.class = class;
+ in.sign = sign;
+ in.normal_exp = exp;
+ in.fraction.ll = frac;
+ return pack_d (&in);
+}
+#endif /* L_make_tf */
+
+#if defined(L_tf_to_df)
+DFtype
+tf_to_df (TFtype arg_a)
+{
+ fp_number_type in;
+ UDItype sffrac;
+ FLO_union_type au;
+
+ au.value = arg_a;
+ unpack_d (&au, &in);
+
+ sffrac = in.fraction.ll >> D_T_BITOFF;
+
+ /* We set the lowest guard bit in SFFRAC if we discarded any non
+ zero bits. */
+ if ((in.fraction.ll & (((UTItype) 1 << D_T_BITOFF) - 1)) != 0)
+ sffrac |= 1;
+
+ return __make_dp (in.class, in.sign, in.normal_exp, sffrac);
+}
+#endif /* L_tf_to_df */
+
+#if defined(L_tf_to_sf)
+SFtype
+tf_to_sf (TFtype arg_a)
+{
+ fp_number_type in;
+ USItype sffrac;
+ FLO_union_type au;
+
+ au.value = arg_a;
+ unpack_d (&au, &in);
+
+ sffrac = in.fraction.ll >> F_T_BITOFF;
+
+ /* We set the lowest guard bit in SFFRAC if we discarded any non
+ zero bits. */
+ if ((in.fraction.ll & (((UTItype) 1 << F_T_BITOFF) - 1)) != 0)
+ sffrac |= 1;
+
+ return __make_fp (in.class, in.sign, in.normal_exp, sffrac);
+}
+#endif /* L_tf_to_sf */
+#endif /* TFLOAT */
+
+#endif /* ! FLOAT */
+#endif /* !EXTENDED_FLOAT_STUBS */
diff -durN gcc-3.4.6.orig/gcc/config/nios2/nios2.h gcc-3.4.6/gcc/config/nios2/nios2.h
--- gcc-3.4.6.orig/gcc/config/nios2/nios2.h 1970-01-01 01:00:00.000000000 +0100
+++ gcc-3.4.6/gcc/config/nios2/nios2.h 2007-08-15 23:09:36.000000000 +0200
@@ -0,0 +1,824 @@
+/* Definitions of target machine for Altera NIOS 2G NIOS2 version.
+ Copyright (C) 2003 Altera
+ Contributed by Jonah Graham (jgraham@altera.com).
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+
+#define TARGET_CPU_CPP_BUILTINS() \
+ do \
+ { \
+ builtin_define_std ("NIOS2"); \
+ builtin_define_std ("nios2"); \
+ builtin_define ("_GNU_SOURCE"); \
+ } \
+ while (0)
+#define TARGET_VERSION fprintf (stderr, " (Altera Nios II)")
+
+
+
+
+
+/*********************************
+ * Run-time Target Specification
+ *********************************/
+
+#define HAS_DIV_FLAG 0x0001
+#define HAS_MUL_FLAG 0x0002
+#define HAS_MULX_FLAG 0x0004
+#define FAST_SW_DIV_FLAG 0x0008
+#define INLINE_MEMCPY_FLAG 0x00010
+#define CACHE_VOLATILE_FLAG 0x0020
+#define BYPASS_CACHE_FLAG 0x0040
+
+extern int target_flags;
+#define TARGET_HAS_DIV (target_flags & HAS_DIV_FLAG)
+#define TARGET_HAS_MUL (target_flags & HAS_MUL_FLAG)
+#define TARGET_HAS_MULX (target_flags & HAS_MULX_FLAG)
+#define TARGET_FAST_SW_DIV (target_flags & FAST_SW_DIV_FLAG)
+#define TARGET_INLINE_MEMCPY (target_flags & INLINE_MEMCPY_FLAG)
+#define TARGET_CACHE_VOLATILE (target_flags & CACHE_VOLATILE_FLAG)
+#define TARGET_BYPASS_CACHE (target_flags & BYPASS_CACHE_FLAG)
+
+#define TARGET_SWITCHES \
+{ \
+ { "hw-div", HAS_DIV_FLAG, \
+ N_("Enable DIV, DIVU") }, \
+ { "no-hw-div", -HAS_DIV_FLAG, \
+ N_("Disable DIV, DIVU (default)") }, \
+ { "hw-mul", HAS_MUL_FLAG, \
+ N_("Enable MUL instructions (default)") }, \
+ { "hw-mulx", HAS_MULX_FLAG, \
+ N_("Enable MULX instructions, assume fast shifter") }, \
+ { "no-hw-mul", -HAS_MUL_FLAG, \
+ N_("Disable MUL instructions") }, \
+ { "no-hw-mulx", -HAS_MULX_FLAG, \
+ N_("Disable MULX instructions, assume slow shifter (default and implied by -mno-hw-mul)") }, \
+ { "fast-sw-div", FAST_SW_DIV_FLAG, \
+ N_("Use table based fast divide (default at -O3)") }, \
+ { "no-fast-sw-div", -FAST_SW_DIV_FLAG, \
+ N_("Don't use table based fast divide ever") }, \
+ { "inline-memcpy", INLINE_MEMCPY_FLAG, \
+ N_("Inline small memcpy (default when optimizing)") }, \
+ { "no-inline-memcpy", -INLINE_MEMCPY_FLAG, \
+ N_("Don't Inline small memcpy") }, \
+ { "cache-volatile", CACHE_VOLATILE_FLAG, \
+ N_("Volatile accesses use non-io variants of instructions (default)") }, \
+ { "no-cache-volatile", -CACHE_VOLATILE_FLAG, \
+ N_("Volatile accesses use io variants of instructions") }, \
+ { "bypass-cache", BYPASS_CACHE_FLAG, \
+ N_("All ld/st instructins use io variants") }, \
+ { "no-bypass-cache", -BYPASS_CACHE_FLAG, \
+ N_("All ld/st instructins do not use io variants (default)") }, \
+ { "smallc", 0, \
+ N_("Link with a limited version of the C library") }, \
+ { "ctors-in-init", 0, \
+ "" /* undocumented: N_("Link with static constructors and destructors in init") */ }, \
+ { "", TARGET_DEFAULT, 0 } \
+}
+
+
+extern const char *nios2_sys_nosys_string; /* for -msys=nosys */
+extern const char *nios2_sys_lib_string; /* for -msys-lib= */
+extern const char *nios2_sys_crt0_string; /* for -msys-crt0= */
+
+#define TARGET_OPTIONS \
+{ \
+ { "sys=nosys", &nios2_sys_nosys_string, \
+ N_("Use stub versions of OS library calls (default)"), 0}, \
+ { "sys-lib=", &nios2_sys_lib_string, \
+ N_("Name of System Library to link against. (Converted to a -l option)"), 0}, \
+ { "sys-crt0=", &nios2_sys_crt0_string, \
+ N_("Name of the startfile. (default is a crt0 for the ISS only)"), 0}, \
+}
+
+
+/* Default target_flags if no switches specified. */
+#ifndef TARGET_DEFAULT
+# define TARGET_DEFAULT (HAS_MUL_FLAG | CACHE_VOLATILE_FLAG)
+#endif
+
+/* Switch Recognition by gcc.c. Add -G xx support */
+#undef SWITCH_TAKES_ARG
+#define SWITCH_TAKES_ARG(CHAR) \
+ (DEFAULT_SWITCH_TAKES_ARG (CHAR) || (CHAR) == 'G')
+
+#define OVERRIDE_OPTIONS override_options ()
+#define OPTIMIZATION_OPTIONS(LEVEL, SIZE) optimization_options (LEVEL, SIZE)
+#define CAN_DEBUG_WITHOUT_FP
+
+#define CC1_SPEC "\
+%{G*}"
+
+#undef LIB_SPEC
+#define LIB_SPEC \
+"--start-group %{msmallc: -lsmallc} %{!msmallc: -lc} -lgcc \
+ %{msys-lib=*: -l%*} \
+ %{!msys-lib=*: -lc } \
+ --end-group \
+ %{msys-lib=: %eYou need a library name for -msys-lib=} \
+"
+
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC \
+"%{msys-crt0=*: %*} %{!msys-crt0=*: crt1%O%s} \
+ %{msys-crt0=: %eYou need a C startup file for -msys-crt0=} \
+ %{mctors-in-init: crti%O%s crtbegin%O%s} \
+"
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC \
+ "%{mctors-in-init: crtend%O%s crtn%O%s}"
+
+
+/***********************
+ * Storage Layout
+ ***********************/
+
+#define DEFAULT_SIGNED_CHAR 1
+#define BITS_BIG_ENDIAN 0
+#define BYTES_BIG_ENDIAN 0
+#define WORDS_BIG_ENDIAN 0
+#define BITS_PER_UNIT 8
+#define BITS_PER_WORD 32
+#define UNITS_PER_WORD 4
+#define POINTER_SIZE 32
+#define BIGGEST_ALIGNMENT 32
+#define STRICT_ALIGNMENT 1
+#define FUNCTION_BOUNDARY 32
+#define PARM_BOUNDARY 32
+#define STACK_BOUNDARY 32
+#define PREFERRED_STACK_BOUNDARY 32
+#define MAX_FIXED_MODE_SIZE 64
+
+#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
+ ((TREE_CODE (EXP) == STRING_CST) \
+ && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
+
+
+/**********************
+ * Layout of Source Language Data Types
+ **********************/
+
+#define INT_TYPE_SIZE 32
+#define SHORT_TYPE_SIZE 16
+#define LONG_TYPE_SIZE 32
+#define LONG_LONG_TYPE_SIZE 64
+#define FLOAT_TYPE_SIZE 32
+#define DOUBLE_TYPE_SIZE 64
+#define LONG_DOUBLE_TYPE_SIZE DOUBLE_TYPE_SIZE
+
+
+/*************************
+ * Condition Code Status
+ ************************/
+
+/* comparison type */
+/* ??? currently only CMP_SI is used */
+enum cmp_type {
+ CMP_SI, /* compare four byte integers */
+ CMP_DI, /* compare eight byte integers */
+ CMP_SF, /* compare single precision floats */
+ CMP_DF, /* compare double precision floats */
+ CMP_MAX /* max comparison type */
+};
+
+extern GTY(()) rtx branch_cmp[2]; /* operands for compare */
+extern enum cmp_type branch_type; /* what type of branch to use */
+
+/**********************
+ * Register Usage
+ **********************/
+
+/* ---------------------------------- *
+ * Basic Characteristics of Registers
+ * ---------------------------------- */
+
+/*
+Register Number
+ Register Name
+ Alternate Name
+ Purpose
+0 r0 zero always zero
+1 r1 at Assembler Temporary
+2-3 r2-r3 Return Location
+4-7 r4-r7 Register Arguments
+8-15 r8-r15 Caller Saved Registers
+16-22 r16-r22 Callee Saved Registers
+23 r23 sc Static Chain (Callee Saved)
+ ??? Does $sc want to be caller or callee
+ saved. If caller, 15, else 23.
+24 r24 Exception Temporary
+25 r25 Breakpoint Temporary
+26 r26 gp Global Pointer
+27 r27 sp Stack Pointer
+28 r28 fp Frame Pointer
+29 r29 ea Exception Return Address
+30 r30 ba Breakpoint Return Address
+31 r31 ra Return Address
+
+32 ctl0 status
+33 ctl1 estatus STATUS saved by exception ?
+34 ctl2 bstatus STATUS saved by break ?
+35 ctl3 ipri Interrupt Priority Mask ?
+36 ctl4 ecause Exception Cause ?
+
+37 pc Not an actual register
+
+38 rap Return address pointer, this does not
+ actually exist and will be eliminated
+
+39 fake_fp Fake Frame Pointer which will always be eliminated.
+40 fake_ap Fake Argument Pointer which will always be eliminated.
+
+41 First Pseudo Register
+
+
+The definitions for all the hard register numbers
+are located in nios2.md.
+*/
+
+#define FIRST_PSEUDO_REGISTER 41
+#define NUM_ARG_REGS (LAST_ARG_REGNO - FIRST_ARG_REGNO + 1)
+
+
+
+/* also see CONDITIONAL_REGISTER_USAGE */
+#define FIXED_REGISTERS \
+ { \
+/* +0 1 2 3 4 5 6 7 8 9 */ \
+/* 0 */ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, \
+/* 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+/* 20 */ 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, \
+/* 30 */ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, \
+/* 40 */ 1, \
+ }
+
+/* call used is the same as caller saved
+ + fixed regs + args + ret vals */
+#define CALL_USED_REGISTERS \
+ { \
+/* +0 1 2 3 4 5 6 7 8 9 */ \
+/* 0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
+/* 10 */ 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, \
+/* 20 */ 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, \
+/* 30 */ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, \
+/* 40 */ 1, \
+ }
+
+#define HARD_REGNO_NREGS(REGNO, MODE) \
+ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \
+ / UNITS_PER_WORD)
+
+/* --------------------------- *
+ * How Values Fit in Registers
+ * --------------------------- */
+
+#define HARD_REGNO_MODE_OK(REGNO, MODE) 1
+
+#define MODES_TIEABLE_P(MODE1, MODE2) 1
+
+
+/*************************
+ * Register Classes
+ *************************/
+
+enum reg_class
+{
+ NO_REGS,
+ ALL_REGS,
+ LIM_REG_CLASSES
+};
+
+#define N_REG_CLASSES (int) LIM_REG_CLASSES
+
+#define REG_CLASS_NAMES \
+ {"NO_REGS", \
+ "ALL_REGS"}
+
+#define GENERAL_REGS ALL_REGS
+
+#define REG_CLASS_CONTENTS \
+/* NO_REGS */ {{ 0, 0}, \
+/* ALL_REGS */ {~0,~0}} \
+
+#define REGNO_REG_CLASS(REGNO) ALL_REGS
+
+#define BASE_REG_CLASS ALL_REGS
+#define INDEX_REG_CLASS ALL_REGS
+
+/* only one reg class, 'r', is handled automatically */
+#define REG_CLASS_FROM_LETTER(CHAR) NO_REGS
+
+#define REGNO_OK_FOR_BASE_P2(REGNO, STRICT) \
+ ((STRICT) \
+ ? (REGNO) < FIRST_PSEUDO_REGISTER \
+ : (REGNO) < FIRST_PSEUDO_REGISTER || (reg_renumber && reg_renumber[REGNO] < FIRST_PSEUDO_REGISTER))
+
+#define REGNO_OK_FOR_INDEX_P2(REGNO, STRICT) \
+ (REGNO_OK_FOR_BASE_P2 (REGNO, STRICT))
+
+#define REGNO_OK_FOR_BASE_P(REGNO) \
+ (REGNO_OK_FOR_BASE_P2 (REGNO, 1))
+
+#define REGNO_OK_FOR_INDEX_P(REGNO) \
+ (REGNO_OK_FOR_INDEX_P2 (REGNO, 1))
+
+#define REG_OK_FOR_BASE_P2(X, STRICT) \
+ (STRICT \
+ ? REGNO_OK_FOR_BASE_P2 (REGNO (X), 1) \
+ : REGNO_OK_FOR_BASE_P2 (REGNO (X), 1) || REGNO(X) >= FIRST_PSEUDO_REGISTER)
+
+#define REG_OK_FOR_INDEX_P2(X, STRICT) \
+ (STRICT \
+ ? REGNO_OK_FOR_INDEX_P2 (REGNO (X), 1) \
+ : REGNO_OK_FOR_INDEX_P2 (REGNO (X), 1) || REGNO(X) >= FIRST_PSEUDO_REGISTER)
+
+#define CLASS_MAX_NREGS(CLASS, MODE) \
+ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \
+ / UNITS_PER_WORD)
+
+
+#define SMALL_INT(X) ((unsigned HOST_WIDE_INT) ((X) + 0x8000) < 0x10000)
+#define SMALL_INT_UNSIGNED(X) ((unsigned HOST_WIDE_INT) (X) < 0x10000)
+#define UPPER16_INT(X) (((X) & 0xffff) == 0)
+#define SHIFT_INT(X) ((X) >= 0 && (X) <= 31)
+#define RDWRCTL_INT(X) ((X) >= 0 && (X) <= 31)
+#define CUSTOM_INSN_OPCODE(X) ((X) >= 0 && (X) <= 255)
+
+#define CONST_OK_FOR_LETTER_P(VALUE, C) \
+ ( \
+ (C) == 'I' ? SMALL_INT (VALUE) : \
+ (C) == 'J' ? SMALL_INT_UNSIGNED (VALUE) : \
+ (C) == 'K' ? UPPER16_INT (VALUE) : \
+ (C) == 'L' ? SHIFT_INT (VALUE) : \
+ (C) == 'M' ? (VALUE) == 0 : \
+ (C) == 'N' ? CUSTOM_INSN_OPCODE (VALUE) : \
+ (C) == 'O' ? RDWRCTL_INT (VALUE) : \
+ 0)
+
+#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) 0
+
+#define PREFERRED_RELOAD_CLASS(X, CLASS) \
+ ((CLASS) == NO_REGS ? GENERAL_REGS : (CLASS))
+
+/* 'S' matches immediates which are in small data
+ and therefore can be added to gp to create a
+ 32-bit value. */
+#define EXTRA_CONSTRAINT(VALUE, C) \
+ ((C) == 'S' \
+ && (GET_CODE (VALUE) == SYMBOL_REF) \
+ && SYMBOL_REF_IN_NIOS2_SMALL_DATA_P (VALUE))
+
+
+
+
+/* Say that the epilogue uses the return address register. Note that
+ in the case of sibcalls, the values "used by the epilogue" are
+ considered live at the start of the called function. */
+#define EPILOGUE_USES(REGNO) ((REGNO) == RA_REGNO)
+
+
+#define DEFAULT_MAIN_RETURN c_expand_return (integer_zero_node)
+
+/**********************************
+ * Trampolines for Nested Functions
+ ***********************************/
+
+#define TRAMPOLINE_TEMPLATE(FILE) \
+ error ("trampolines not yet implemented")
+#define TRAMPOLINE_SIZE 20
+#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \
+ error ("trampolines not yet implemented")
+
+/***************************
+ * Stack Layout and Calling Conventions
+ ***************************/
+
+/* ------------------ *
+ * Basic Stack Layout
+ * ------------------ */
+
+/* The downward variants are used by the compiler,
+ the upward ones serve as documentation */
+#define STACK_GROWS_DOWNWARD
+#define FRAME_GROWS_UPWARD
+#define ARGS_GROW_UPWARD
+
+#define STARTING_FRAME_OFFSET current_function_outgoing_args_size
+#define FIRST_PARM_OFFSET(FUNDECL) 0
+
+/* Before the prologue, RA lives in r31. */
+#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (VOIDmode, RA_REGNO)
+
+/* -------------------------------------- *
+ * Registers That Address the Stack Frame
+ * -------------------------------------- */
+
+#define STACK_POINTER_REGNUM SP_REGNO
+#define STATIC_CHAIN_REGNUM SC_REGNO
+#define PC_REGNUM PC_REGNO
+#define DWARF_FRAME_RETURN_COLUMN RA_REGNO
+
+/* Base register for access to local variables of the function. We
+ pretend that the frame pointer is a non-existent hard register, and
+ then eliminate it to HARD_FRAME_POINTER_REGNUM. */
+#define FRAME_POINTER_REGNUM FAKE_FP_REGNO
+
+#define HARD_FRAME_POINTER_REGNUM FP_REGNO
+#define RETURN_ADDRESS_POINTER_REGNUM RAP_REGNO
+/* the argumnet pointer needs to always be eliminated
+ so it is set to a fake hard register. */
+#define ARG_POINTER_REGNUM FAKE_AP_REGNO
+
+/* ----------------------------------------- *
+ * Eliminating Frame Pointer and Arg Pointer
+ * ----------------------------------------- */
+
+#define FRAME_POINTER_REQUIRED 0
+
+#define ELIMINABLE_REGS \
+{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
+ { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \
+ { RETURN_ADDRESS_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
+ { RETURN_ADDRESS_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \
+ { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
+ { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}}
+
+#define CAN_ELIMINATE(FROM, TO) 1
+
+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
+ (OFFSET) = nios2_initial_elimination_offset ((FROM), (TO))
+
+#define MUST_SAVE_REGISTER(regno) \
+ ((regs_ever_live[regno] && !call_used_regs[regno]) \
+ || (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed) \
+ || (regno == RA_REGNO && regs_ever_live[RA_REGNO]))
+
+/* Treat LOC as a byte offset from the stack pointer and round it up
+ to the next fully-aligned offset. */
+#define STACK_ALIGN(LOC) \
+ (((LOC) + ((PREFERRED_STACK_BOUNDARY / 8) - 1)) & ~((PREFERRED_STACK_BOUNDARY / 8) - 1))
+
+
+/* ------------------------------ *
+ * Passing Arguments in Registers
+ * ------------------------------ */
+
+/* see nios2.c */
+#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
+ (function_arg (&CUM, MODE, TYPE, NAMED))
+
+#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \
+ (function_arg_partial_nregs (&CUM, MODE, TYPE, NAMED))
+
+#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) 0
+
+#define FUNCTION_ARG_CALLEE_COPIES(CUM, MODE, TYPE, NAMED) 0
+
+typedef struct nios2_args
+{
+ int regs_used;
+} CUMULATIVE_ARGS;
+
+/* This is to initialize the above unused CUM data type */
+#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS) \
+ (init_cumulative_args (&CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS))
+
+#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \
+ (function_arg_advance (&CUM, MODE, TYPE, NAMED))
+
+#define FUNCTION_ARG_REGNO_P(REGNO) \
+ ((REGNO) >= FIRST_ARG_REGNO && (REGNO) <= LAST_ARG_REGNO)
+
+#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \
+ { \
+ int pret_size = nios2_setup_incoming_varargs (&(CUM), (MODE), \
+ (TYPE), (NO_RTL)); \
+ if (pret_size) \
+ (PRETEND_SIZE) = pret_size; \
+ }
+
+/* ----------------------------- *
+ * Generating Code for Profiling
+ * ----------------------------- */
+
+#define PROFILE_BEFORE_PROLOGUE
+
+#define FUNCTION_PROFILER(FILE, LABELNO) \
+ function_profiler ((FILE), (LABELNO))
+
+/* --------------------------------------- *
+ * Passing Function Arguments on the Stack
+ * --------------------------------------- */
+
+#define PROMOTE_PROTOTYPES 1
+
+#define PUSH_ARGS 0
+#define ACCUMULATE_OUTGOING_ARGS 1
+
+#define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, STACKSIZE) 0
+
+/* --------------------------------------- *
+ * How Scalar Function Values Are Returned
+ * --------------------------------------- */
+
+#define FUNCTION_VALUE(VALTYPE, FUNC) \
+ gen_rtx(REG, TYPE_MODE(VALTYPE), FIRST_RETVAL_REGNO)
+
+#define LIBCALL_VALUE(MODE) \
+ gen_rtx(REG, MODE, FIRST_RETVAL_REGNO)
+
+#define FUNCTION_VALUE_REGNO_P(REGNO) ((REGNO) == FIRST_RETVAL_REGNO)
+
+/* ----------------------------- *
+ * How Large Values Are Returned
+ * ----------------------------- */
+
+
+#define RETURN_IN_MEMORY(TYPE) \
+ nios2_return_in_memory (TYPE)
+
+
+#define STRUCT_VALUE 0
+
+#define DEFAULT_PCC_STRUCT_RETURN 0
+
+/*******************
+ * Addressing Modes
+ *******************/
+
+
+#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN)
+
+#define CONSTANT_ADDRESS_P(X) (CONSTANT_P (X))
+
+#define MAX_REGS_PER_ADDRESS 1
+
+/* Go to ADDR if X is a valid address. */
+#ifndef REG_OK_STRICT
+#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \
+ { \
+ if (nios2_legitimate_address ((X), (MODE), 0)) \
+ goto ADDR; \
+ }
+#else
+#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \
+ { \
+ if (nios2_legitimate_address ((X), (MODE), 1)) \
+ goto ADDR; \
+ }
+#endif
+
+#ifndef REG_OK_STRICT
+#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P2 (REGNO (X), 0)
+#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P2 (REGNO (X), 0)
+#else
+#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P2 (REGNO (X), 1)
+#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P2 (REGNO (X), 1)
+#endif
+
+#define LEGITIMATE_CONSTANT_P(X) 1
+
+/* Nios II has no mode dependent addresses. */
+#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL)
+
+/* Set if this has a weak declaration */
+#define SYMBOL_FLAG_WEAK_DECL (1 << SYMBOL_FLAG_MACH_DEP_SHIFT)
+#define SYMBOL_REF_WEAK_DECL_P(RTX) \
+ ((SYMBOL_REF_FLAGS (RTX) & SYMBOL_FLAG_WEAK_DECL) != 0)
+
+
+/* true if a symbol is both small and not weak. In this case, gp
+ relative access can be used */
+#define SYMBOL_REF_IN_NIOS2_SMALL_DATA_P(RTX) \
+ (SYMBOL_REF_SMALL_P(RTX) && !SYMBOL_REF_WEAK_DECL_P(RTX))
+
+/*****************
+ * Describing Relative Costs of Operations
+ *****************/
+
+#define SLOW_BYTE_ACCESS 1
+
+/* It is as good to call a constant function address as to call an address
+ kept in a register.
+ ??? Not true anymore really. Now that call cannot address full range
+ of memory callr may need to be used */
+
+#define NO_FUNCTION_CSE
+#define NO_RECURSIVE_FUNCTION_CSE
+
+
+
+/*****************************************
+ * Defining the Output Assembler Language
+ *****************************************/
+
+/* ------------------------------------------ *
+ * The Overall Framework of an Assembler File
+ * ------------------------------------------ */
+
+#define ASM_APP_ON "#APP\n"
+#define ASM_APP_OFF "#NO_APP\n"
+
+#define ASM_COMMENT_START "# "
+
+/* ------------------------------- *
+ * Output and Generation of Labels
+ * ------------------------------- */
+
+#define GLOBAL_ASM_OP "\t.global\t"
+
+
+/* -------------- *
+ * Output of Data
+ * -------------- */
+
+#define DWARF2_UNWIND_INFO 0
+
+
+/* -------------------------------- *
+ * Assembler Commands for Alignment
+ * -------------------------------- */
+
+#define ASM_OUTPUT_ALIGN(FILE, LOG) \
+ do { \
+ fprintf ((FILE), "%s%d\n", ALIGN_ASM_OP, (LOG)); \
+ } while (0)
+
+
+/* -------------------------------- *
+ * Output of Assembler Instructions
+ * -------------------------------- */
+
+#define REGISTER_NAMES \
+{ \
+ "zero", \
+ "at", \
+ "r2", \
+ "r3", \
+ "r4", \
+ "r5", \
+ "r6", \
+ "r7", \
+ "r8", \
+ "r9", \
+ "r10", \
+ "r11", \
+ "r12", \
+ "r13", \
+ "r14", \
+ "r15", \
+ "r16", \
+ "r17", \
+ "r18", \
+ "r19", \
+ "r20", \
+ "r21", \
+ "r22", \
+ "r23", \
+ "r24", \
+ "r25", \
+ "gp", \
+ "sp", \
+ "fp", \
+ "ta", \
+ "ba", \
+ "ra", \
+ "status", \
+ "estatus", \
+ "bstatus", \
+ "ipri", \
+ "ecause", \
+ "pc", \
+ "rap", \
+ "fake_fp", \
+ "fake_ap", \
+}
+
+#define ASM_OUTPUT_OPCODE(STREAM, PTR)\
+ (PTR) = asm_output_opcode (STREAM, PTR)
+
+#define PRINT_OPERAND(STREAM, X, CODE) \
+ nios2_print_operand (STREAM, X, CODE)
+
+#define PRINT_OPERAND_ADDRESS(STREAM, X) \
+ nios2_print_operand_address (STREAM, X)
+
+#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
+do { fputs (integer_asm_op (POINTER_SIZE / BITS_PER_UNIT, TRUE), FILE); \
+ fprintf (FILE, ".L%u\n", (unsigned) (VALUE)); \
+ } while (0)
+
+
+/* ------------ *
+ * Label Output
+ * ------------ */
+
+
+/* ---------------------------------------------------- *
+ * Dividing the Output into Sections (Texts, Data, ...)
+ * ---------------------------------------------------- */
+
+/* Output before read-only data. */
+#define TEXT_SECTION_ASM_OP ("\t.section\t.text")
+
+/* Output before writable data. */
+#define DATA_SECTION_ASM_OP ("\t.section\t.data")
+
+
+/* Default the definition of "small data" to 8 bytes. */
+/* ??? How come I can't use HOST_WIDE_INT here? */
+extern unsigned long nios2_section_threshold;
+#define NIOS2_DEFAULT_GVALUE 8
+
+
+
+/* This says how to output assembler code to declare an
+ uninitialized external linkage data object. Under SVR4,
+ the linker seems to want the alignment of data objects
+ to depend on their types. We do exactly that here. */
+
+#undef COMMON_ASM_OP
+#define COMMON_ASM_OP "\t.comm\t"
+
+#undef ASM_OUTPUT_ALIGNED_COMMON
+#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \
+do \
+{ \
+ if ((SIZE) <= nios2_section_threshold) \
+ { \
+ named_section (0, ".sbss", 0); \
+ (*targetm.asm_out.globalize_label) (FILE, NAME); \
+ ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object"); \
+ if (!flag_inhibit_size_directive) \
+ ASM_OUTPUT_SIZE_DIRECTIVE (FILE, NAME, SIZE); \
+ ASM_OUTPUT_ALIGN ((FILE), exact_log2((ALIGN) / BITS_PER_UNIT)); \
+ ASM_OUTPUT_LABEL(FILE, NAME); \
+ ASM_OUTPUT_SKIP((FILE), (SIZE) ? (SIZE) : 1); \
+ } \
+ else \
+ { \
+ fprintf ((FILE), "%s", COMMON_ASM_OP); \
+ assemble_name ((FILE), (NAME)); \
+ fprintf ((FILE), ","HOST_WIDE_INT_PRINT_UNSIGNED",%u\n", (SIZE), (ALIGN) / BITS_PER_UNIT); \
+ } \
+} \
+while (0)
+
+
+/* This says how to output assembler code to declare an
+ uninitialized internal linkage data object. Under SVR4,
+ the linker seems to want the alignment of data objects
+ to depend on their types. We do exactly that here. */
+
+#undef ASM_OUTPUT_ALIGNED_LOCAL
+#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \
+do { \
+ if ((SIZE) <= nios2_section_threshold) \
+ named_section (0, ".sbss", 0); \
+ else \
+ named_section (0, ".bss", 0); \
+ ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object"); \
+ if (!flag_inhibit_size_directive) \
+ ASM_OUTPUT_SIZE_DIRECTIVE (FILE, NAME, SIZE); \
+ ASM_OUTPUT_ALIGN ((FILE), exact_log2((ALIGN) / BITS_PER_UNIT)); \
+ ASM_OUTPUT_LABEL(FILE, NAME); \
+ ASM_OUTPUT_SKIP((FILE), (SIZE) ? (SIZE) : 1); \
+} while (0)
+
+
+
+/***************************
+ * Miscellaneous Parameters
+ ***************************/
+
+#define MOVE_MAX 4
+
+#define Pmode SImode
+#define FUNCTION_MODE QImode
+
+#define CASE_VECTOR_MODE Pmode
+
+#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
+
+#define LOAD_EXTEND_OP(MODE) (ZERO_EXTEND)
+
+#define WORD_REGISTER_OPERATIONS
diff -durN gcc-3.4.6.orig/gcc/config/nios2/nios2.md gcc-3.4.6/gcc/config/nios2/nios2.md
--- gcc-3.4.6.orig/gcc/config/nios2/nios2.md 1970-01-01 01:00:00.000000000 +0100
+++ gcc-3.4.6/gcc/config/nios2/nios2.md 2007-08-15 23:09:36.000000000 +0200
@@ -0,0 +1,2078 @@
+;; Machine Description for Altera NIOS 2G NIOS2 version.
+;; Copyright (C) 2003 Altera
+;; Contributed by Jonah Graham (jgraham@altera.com).
+;;
+;; This file is part of GNU CC.
+;;
+;; GNU CC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+;;
+;; GNU CC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GNU CC; see the file COPYING. If not, write to
+;; the Free Software Foundation, 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA. */
+
+
+
+;*****************************************************************************
+;*
+;* constants
+;*
+;*****************************************************************************
+(define_constants [
+ (GP_REGNO 26)
+ (SP_REGNO 27)
+ (FP_REGNO 28)
+ (RA_REGNO 31)
+ (RAP_REGNO 38)
+ (FIRST_RETVAL_REGNO 2)
+ (LAST_RETVAL_REGNO 3)
+ (FIRST_ARG_REGNO 4)
+ (LAST_ARG_REGNO 7)
+ (SC_REGNO 23)
+ (PC_REGNO 37)
+ (FAKE_FP_REGNO 39)
+ (FAKE_AP_REGNO 40)
+
+
+ (UNSPEC_BLOCKAGE 0)
+ (UNSPEC_LDBIO 1)
+ (UNSPEC_LDBUIO 2)
+ (UNSPEC_LDHIO 3)
+ (UNSPEC_LDHUIO 4)
+ (UNSPEC_LDWIO 5)
+ (UNSPEC_STBIO 6)
+ (UNSPEC_STHIO 7)
+ (UNSPEC_STWIO 8)
+ (UNSPEC_SYNC 9)
+ (UNSPEC_WRCTL 10)
+ (UNSPEC_RDCTL 11)
+
+])
+
+
+
+;*****************************************************************************
+;*
+;* instruction scheduler
+;*
+;*****************************************************************************
+
+; No schedule info is currently available, using an assumption that no
+; instruction can use the results of the previous instruction without
+; incuring a stall.
+
+; length of an instruction (in bytes)
+(define_attr "length" "" (const_int 4))
+(define_attr "type" "unknown,complex,control,alu,cond_alu,st,ld,shift,mul,div,custom" (const_string "complex"))
+
+(define_asm_attributes
+ [(set_attr "length" "4")
+ (set_attr "type" "complex")])
+
+(define_automaton "nios2")
+(automata_option "v")
+;(automata_option "no-minimization")
+(automata_option "ndfa")
+
+; The nios2 pipeline is fairly straightforward for the fast model.
+; Every alu operation is pipelined so that an instruction can
+; be issued every cycle. However, there are still potential
+; stalls which this description tries to deal with.
+
+(define_cpu_unit "cpu" "nios2")
+
+(define_insn_reservation "complex" 1
+ (eq_attr "type" "complex")
+ "cpu")
+
+(define_insn_reservation "control" 1
+ (eq_attr "type" "control")
+ "cpu")
+
+(define_insn_reservation "alu" 1
+ (eq_attr "type" "alu")
+ "cpu")
+
+(define_insn_reservation "cond_alu" 1
+ (eq_attr "type" "cond_alu")
+ "cpu")
+
+(define_insn_reservation "st" 1
+ (eq_attr "type" "st")
+ "cpu")
+
+(define_insn_reservation "custom" 1
+ (eq_attr "type" "custom")
+ "cpu")
+
+; shifts, muls and lds have three cycle latency
+(define_insn_reservation "ld" 3
+ (eq_attr "type" "ld")
+ "cpu")
+
+(define_insn_reservation "shift" 3
+ (eq_attr "type" "shift")
+ "cpu")
+
+(define_insn_reservation "mul" 3
+ (eq_attr "type" "mul")
+ "cpu")
+
+(define_insn_reservation "div" 1
+ (eq_attr "type" "div")
+ "cpu")
+
+
+;*****************************************************************************
+;*
+;* MOV Instructions
+;*
+;*****************************************************************************
+
+(define_expand "movqi"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "")
+ (match_operand:QI 1 "general_operand" ""))]
+ ""
+{
+ if (nios2_emit_move_sequence (operands, QImode))
+ DONE;
+})
+
+(define_insn "movqi_internal"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=m, r,r, r")
+ (match_operand:QI 1 "general_operand" "rM,m,rM,I"))]
+ "(register_operand (operands[0], QImode)
+ || register_operand (operands[1], QImode)
+ || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
+ "@
+ stb%o0\\t%z1, %0
+ ldbu%o1\\t%0, %1
+ mov\\t%0, %z1
+ movi\\t%0, %1"
+ [(set_attr "type" "st,ld,alu,alu")])
+
+(define_insn "ldbio"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDBIO))
+ (use (match_operand:SI 1 "memory_operand" "m"))]
+ ""
+ "ldbio\\t%0, %1"
+ [(set_attr "type" "ld")])
+
+(define_insn "ldbuio"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDBUIO))
+ (use (match_operand:SI 1 "memory_operand" "m"))]
+ ""
+ "ldbuio\\t%0, %1"
+ [(set_attr "type" "ld")])
+
+(define_insn "stbio"
+ [(set (match_operand:SI 0 "memory_operand" "=m")
+ (match_operand:SI 1 "register_operand" "r"))
+ (unspec_volatile:SI [(const_int 0)] UNSPEC_STBIO)]
+ ""
+ "stbio\\t%z1, %0"
+ [(set_attr "type" "st")])
+
+
+(define_expand "movhi"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "")
+ (match_operand:HI 1 "general_operand" ""))]
+ ""
+{
+ if (nios2_emit_move_sequence (operands, HImode))
+ DONE;
+})
+
+(define_insn "movhi_internal"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=m, r,r, r,r")
+ (match_operand:HI 1 "general_operand" "rM,m,rM,I,J"))]
+ "(register_operand (operands[0], HImode)
+ || register_operand (operands[1], HImode)
+ || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
+ "@
+ sth%o0\\t%z1, %0
+ ldhu%o1\\t%0, %1
+ mov\\t%0, %z1
+ movi\\t%0, %1
+ movui\\t%0, %1"
+ [(set_attr "type" "st,ld,alu,alu,alu")])
+
+(define_insn "ldhio"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDHIO))
+ (use (match_operand:SI 1 "memory_operand" "m"))]
+ ""
+ "ldhio\\t%0, %1"
+ [(set_attr "type" "ld")])
+
+(define_insn "ldhuio"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDHUIO))
+ (use (match_operand:SI 1 "memory_operand" "m"))]
+ ""
+ "ldhuio\\t%0, %1"
+ [(set_attr "type" "ld")])
+
+(define_insn "sthio"
+ [(set (match_operand:SI 0 "memory_operand" "=m")
+ (match_operand:SI 1 "register_operand" "r"))
+ (unspec_volatile:SI [(const_int 0)] UNSPEC_STHIO)]
+ ""
+ "sthio\\t%z1, %0"
+ [(set_attr "type" "st")])
+
+(define_expand "movsi"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "")
+ (match_operand:SI 1 "general_operand" ""))]
+ ""
+{
+ if (nios2_emit_move_sequence (operands, SImode))
+ DONE;
+})
+
+(define_insn "movsi_internal"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=m, r,r, r,r,r,r")
+ (match_operand:SI 1 "general_operand" "rM,m,rM,I,J,S,i"))]
+ "(register_operand (operands[0], SImode)
+ || register_operand (operands[1], SImode)
+ || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))"
+ "@
+ stw%o0\\t%z1, %0
+ ldw%o1\\t%0, %1
+ mov\\t%0, %z1
+ movi\\t%0, %1
+ movui\\t%0, %1
+ addi\\t%0, gp, %%gprel(%1)
+ movhi\\t%0, %H1\;addi\\t%0, %0, %L1"
+ [(set_attr "type" "st,ld,alu,alu,alu,alu,alu")])
+
+(define_insn "ldwio"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDWIO))
+ (use (match_operand:SI 1 "memory_operand" "m"))]
+ ""
+ "ldwio\\t%0, %1"
+ [(set_attr "type" "ld")])
+
+(define_insn "stwio"
+ [(set (match_operand:SI 0 "memory_operand" "=m")
+ (match_operand:SI 1 "register_operand" "r"))
+ (unspec_volatile:SI [(const_int 0)] UNSPEC_STWIO)]
+ ""
+ "stwio\\t%z1, %0"
+ [(set_attr "type" "st")])
+
+
+
+;*****************************************************************************
+;*
+;* zero extension
+;*
+;*****************************************************************************
+
+
+(define_insn "zero_extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))]
+ ""
+ "@
+ andi\\t%0, %1, 0xffff
+ ldhu%o1\\t%0, %1"
+ [(set_attr "type" "alu,ld")])
+
+(define_insn "zero_extendqihi2"
+ [(set (match_operand:HI 0 "register_operand" "=r,r")
+ (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
+ ""
+ "@
+ andi\\t%0, %1, 0xff
+ ldbu%o1\\t%0, %1"
+ [(set_attr "type" "alu,ld")])
+
+(define_insn "zero_extendqisi2"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
+ ""
+ "@
+ andi\\t%0, %1, 0xff
+ ldbu%o1\\t%0, %1"
+ [(set_attr "type" "alu,ld")])
+
+
+
+;*****************************************************************************
+;*
+;* sign extension
+;*
+;*****************************************************************************
+
+(define_expand "extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))]
+ ""
+{
+ if (optimize && GET_CODE (operands[1]) == MEM)
+ operands[1] = force_not_mem (operands[1]);
+
+ if (GET_CODE (operands[1]) != MEM)
+ {
+ rtx op1 = gen_lowpart (SImode, operands[1]);
+ rtx temp = gen_reg_rtx (SImode);
+ rtx shift = GEN_INT (16);
+
+ emit_insn (gen_ashlsi3 (temp, op1, shift));
+ emit_insn (gen_ashrsi3 (operands[0], temp, shift));
+ DONE;
+ }
+})
+
+(define_insn "extendhisi2_internal"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))]
+ ""
+ "ldh%o1\\t%0, %1"
+ [(set_attr "type" "ld")])
+
+(define_expand "extendqihi2"
+ [(set (match_operand:HI 0 "register_operand" "")
+ (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))]
+ ""
+{
+ if (optimize && GET_CODE (operands[1]) == MEM)
+ operands[1] = force_not_mem (operands[1]);
+
+ if (GET_CODE (operands[1]) != MEM)
+ {
+ rtx op0 = gen_lowpart (SImode, operands[0]);
+ rtx op1 = gen_lowpart (SImode, operands[1]);
+ rtx temp = gen_reg_rtx (SImode);
+ rtx shift = GEN_INT (24);
+
+ emit_insn (gen_ashlsi3 (temp, op1, shift));
+ emit_insn (gen_ashrsi3 (op0, temp, shift));
+ DONE;
+ }
+})
+
+(define_insn "extendqihi2_internal"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))]
+ ""
+ "ldb%o1\\t%0, %1"
+ [(set_attr "type" "ld")])
+
+
+(define_expand "extendqisi2"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))]
+ ""
+{
+ if (optimize && GET_CODE (operands[1]) == MEM)
+ operands[1] = force_not_mem (operands[1]);
+
+ if (GET_CODE (operands[1]) != MEM)
+ {
+ rtx op1 = gen_lowpart (SImode, operands[1]);
+ rtx temp = gen_reg_rtx (SImode);
+ rtx shift = GEN_INT (24);
+
+ emit_insn (gen_ashlsi3 (temp, op1, shift));
+ emit_insn (gen_ashrsi3 (operands[0], temp, shift));
+ DONE;
+ }
+})
+
+(define_insn "extendqisi2_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))]
+ ""
+ "ldb%o1\\t%0, %1"
+ [(set_attr "type" "ld")])
+
+
+
+;*****************************************************************************
+;*
+;* Arithmetic Operations
+;*
+;*****************************************************************************
+
+(define_insn "addsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (plus:SI (match_operand:SI 1 "register_operand" "%r,r")
+ (match_operand:SI 2 "arith_operand" "r,I")))]
+ ""
+ "add%i2\\t%0, %1, %z2"
+ [(set_attr "type" "alu")])
+
+(define_insn "subsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
+ (match_operand:SI 2 "register_operand" "r")))]
+ ""
+ "sub\\t%0, %z1, %2"
+ [(set_attr "type" "alu")])
+
+(define_insn "mulsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (mult:SI (match_operand:SI 1 "register_operand" "r,r")
+ (match_operand:SI 2 "arith_operand" "r,I")))]
+ "TARGET_HAS_MUL"
+ "mul%i2\\t%0, %1, %z2"
+ [(set_attr "type" "mul")])
+
+(define_expand "divsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (div:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "register_operand" "r")))]
+ ""
+{
+ if (!TARGET_HAS_DIV)
+ {
+ if (!TARGET_FAST_SW_DIV)
+ FAIL;
+ else
+ {
+ if (nios2_emit_expensive_div (operands, SImode))
+ DONE;
+ }
+ }
+})
+
+(define_insn "divsi3_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (div:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "register_operand" "r")))]
+ "TARGET_HAS_DIV"
+ "div\\t%0, %1, %2"
+ [(set_attr "type" "div")])
+
+(define_insn "udivsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (udiv:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "register_operand" "r")))]
+ "TARGET_HAS_DIV"
+ "divu\\t%0, %1, %2"
+ [(set_attr "type" "div")])
+
+(define_insn "smulsi3_highpart"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (truncate:SI
+ (lshiftrt:DI
+ (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r"))
+ (sign_extend:DI (match_operand:SI 2 "register_operand" "r")))
+ (const_int 32))))]
+ "TARGET_HAS_MULX"
+ "mulxss\\t%0, %1, %2"
+ [(set_attr "type" "mul")])
+
+(define_insn "umulsi3_highpart"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (truncate:SI
+ (lshiftrt:DI
+ (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
+ (zero_extend:DI (match_operand:SI 2 "register_operand" "r")))
+ (const_int 32))))]
+ "TARGET_HAS_MULX"
+ "mulxuu\\t%0, %1, %2"
+ [(set_attr "type" "mul")])
+
+
+(define_expand "mulsidi3"
+ [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 0)
+ (mult:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "register_operand" "")))
+ (set (subreg:SI (match_dup 0) 4)
+ (truncate:SI (lshiftrt:DI (mult:DI (sign_extend:DI (match_dup 1))
+ (sign_extend:DI (match_dup 2)))
+ (const_int 32))))]
+ "TARGET_HAS_MULX"
+ "")
+
+(define_expand "umulsidi3"
+ [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 0)
+ (mult:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "register_operand" "")))
+ (set (subreg:SI (match_dup 0) 4)
+ (truncate:SI (lshiftrt:DI (mult:DI (zero_extend:DI (match_dup 1))
+ (zero_extend:DI (match_dup 2)))
+ (const_int 32))))]
+ "TARGET_HAS_MULX"
+ "")
+
+
+
+;*****************************************************************************
+;*
+;* Negate and ones complement
+;*
+;*****************************************************************************
+
+(define_insn "negsi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (neg:SI (match_operand:SI 1 "register_operand" "r")))]
+ ""
+{
+ operands[2] = const0_rtx;
+ return "sub\\t%0, %z2, %1";
+}
+ [(set_attr "type" "alu")])
+
+(define_insn "one_cmplsi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (not:SI (match_operand:SI 1 "register_operand" "r")))]
+ ""
+{
+ operands[2] = const0_rtx;
+ return "nor\\t%0, %z2, %1";
+}
+ [(set_attr "type" "alu")])
+
+
+
+; Logical Operantions
+
+(define_insn "andsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r, r,r")
+ (and:SI (match_operand:SI 1 "register_operand" "%r, r,r")
+ (match_operand:SI 2 "logical_operand" "rM,J,K")))]
+ ""
+ "@
+ and\\t%0, %1, %z2
+ and%i2\\t%0, %1, %2
+ andh%i2\\t%0, %1, %U2"
+ [(set_attr "type" "alu")])
+
+(define_insn "iorsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r, r,r")
+ (ior:SI (match_operand:SI 1 "register_operand" "%r, r,r")
+ (match_operand:SI 2 "logical_operand" "rM,J,K")))]
+ ""
+ "@
+ or\\t%0, %1, %z2
+ or%i2\\t%0, %1, %2
+ orh%i2\\t%0, %1, %U2"
+ [(set_attr "type" "alu")])
+
+(define_insn "*norsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (and:SI (not:SI (match_operand:SI 1 "register_operand" "%r"))
+ (not:SI (match_operand:SI 2 "reg_or_0_operand" "rM"))))]
+ ""
+ "nor\\t%0, %1, %z2"
+ [(set_attr "type" "alu")])
+
+(define_insn "xorsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r, r,r")
+ (xor:SI (match_operand:SI 1 "register_operand" "%r, r,r")
+ (match_operand:SI 2 "logical_operand" "rM,J,K")))]
+ ""
+ "@
+ xor\\t%0, %1, %z2
+ xor%i2\\t%0, %1, %2
+ xorh%i2\\t%0, %1, %U2"
+ [(set_attr "type" "alu")])
+
+
+
+;*****************************************************************************
+;*
+;* Shifts
+;*
+;*****************************************************************************
+
+(define_insn "ashlsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (ashift:SI (match_operand:SI 1 "register_operand" "r,r")
+ (match_operand:SI 2 "shift_operand" "r,L")))]
+ ""
+ "sll%i2\\t%0, %1, %z2"
+ [(set_attr "type" "shift")])
+
+(define_insn "ashrsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (ashiftrt:SI (match_operand:SI 1 "register_operand" "r,r")
+ (match_operand:SI 2 "shift_operand" "r,L")))]
+ ""
+ "sra%i2\\t%0, %1, %z2"
+ [(set_attr "type" "shift")])
+
+(define_insn "lshrsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (lshiftrt:SI (match_operand:SI 1 "register_operand" "r,r")
+ (match_operand:SI 2 "shift_operand" "r,L")))]
+ ""
+ "srl%i2\\t%0, %1, %z2"
+ [(set_attr "type" "shift")])
+
+(define_insn "rotlsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (rotate:SI (match_operand:SI 1 "register_operand" "r,r")
+ (match_operand:SI 2 "shift_operand" "r,L")))]
+ ""
+ "rol%i2\\t%0, %1, %z2"
+ [(set_attr "type" "shift")])
+
+(define_insn "rotrsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (rotatert:SI (match_operand:SI 1 "register_operand" "r,r")
+ (match_operand:SI 2 "register_operand" "r,r")))]
+ ""
+ "ror\\t%0, %1, %2"
+ [(set_attr "type" "shift")])
+
+(define_insn "*shift_mul_constants"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ashift:SI (mult:SI (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "const_int_operand" "I"))
+ (match_operand:SI 3 "const_int_operand" "I")))]
+ "TARGET_HAS_MUL && SMALL_INT (INTVAL (operands[2]) << INTVAL (operands[3]))"
+{
+ HOST_WIDE_INT mul = INTVAL (operands[2]) << INTVAL (operands[3]);
+ rtx ops[3];
+
+ ops[0] = operands[0];
+ ops[1] = operands[1];
+ ops[2] = GEN_INT (mul);
+
+ output_asm_insn ("muli\t%0, %1, %2", ops);
+ return "";
+}
+ [(set_attr "type" "mul")])
+
+
+
+
+;*****************************************************************************
+;*
+;* Prologue, Epilogue and Return
+;*
+;*****************************************************************************
+
+(define_expand "prologue"
+ [(const_int 1)]
+ ""
+{
+ expand_prologue ();
+ DONE;
+})
+
+(define_expand "epilogue"
+ [(return)]
+ ""
+{
+ expand_epilogue (false);
+ DONE;
+})
+
+(define_expand "sibcall_epilogue"
+ [(return)]
+ ""
+{
+ expand_epilogue (true);
+ DONE;
+})
+
+(define_insn "return"
+ [(return)]
+ "reload_completed && nios2_can_use_return_insn ()"
+ "ret\\t"
+)
+
+(define_insn "return_from_epilogue"
+ [(use (match_operand 0 "pmode_register_operand" ""))
+ (return)]
+ "reload_completed"
+ "ret\\t"
+)
+
+;; Block any insns from being moved before this point, since the
+;; profiling call to mcount can use various registers that aren't
+;; saved or used to pass arguments.
+
+(define_insn "blockage"
+ [(unspec_volatile [(const_int 0)] UNSPEC_BLOCKAGE)]
+ ""
+ ""
+ [(set_attr "type" "unknown")
+ (set_attr "length" "0")])
+
+
+
+;*****************************************************************************
+;*
+;* Jumps and Calls
+;*
+;*****************************************************************************
+
+(define_insn "indirect_jump"
+ [(set (pc) (match_operand:SI 0 "register_operand" "r"))]
+ ""
+ "jmp\\t%0"
+ [(set_attr "type" "control")])
+
+(define_insn "jump"
+ [(set (pc)
+ (label_ref (match_operand 0 "" "")))]
+ ""
+ "br\\t%0"
+ [(set_attr "type" "control")])
+
+
+(define_insn "indirect_call"
+ [(call (mem:QI (match_operand:SI 0 "register_operand" "r"))
+ (match_operand 1 "" ""))
+ (clobber (reg:SI RA_REGNO))]
+ ""
+ "callr\\t%0"
+ [(set_attr "type" "control")])
+
+(define_insn "indirect_call_value"
+ [(set (match_operand 0 "" "")
+ (call (mem:QI (match_operand:SI 1 "register_operand" "r"))
+ (match_operand 2 "" "")))
+ (clobber (reg:SI RA_REGNO))]
+ ""
+ "callr\\t%1"
+)
+
+(define_expand "call"
+ [(parallel [(call (match_operand 0 "" "")
+ (match_operand 1 "" ""))
+ (clobber (reg:SI RA_REGNO))])]
+ ""
+ "")
+
+(define_expand "call_value"
+ [(parallel [(set (match_operand 0 "" "")
+ (call (match_operand 1 "" "")
+ (match_operand 2 "" "")))
+ (clobber (reg:SI RA_REGNO))])]
+ ""
+ "")
+
+(define_insn "*call"
+ [(call (mem:QI (match_operand:SI 0 "immediate_operand" "i"))
+ (match_operand 1 "" ""))
+ (clobber (match_operand:SI 2 "register_operand" "=r"))]
+ ""
+ "call\\t%0"
+ [(set_attr "type" "control")])
+
+(define_insn "*call_value"
+ [(set (match_operand 0 "" "")
+ (call (mem:QI (match_operand:SI 1 "immediate_operand" "i"))
+ (match_operand 2 "" "")))
+ (clobber (match_operand:SI 3 "register_operand" "=r"))]
+ ""
+ "call\\t%1"
+ [(set_attr "type" "control")])
+
+(define_expand "sibcall"
+ [(parallel [(call (match_operand 0 "" "")
+ (match_operand 1 "" ""))
+ (return)
+ (use (match_operand 2 "" ""))])]
+ ""
+ {
+ XEXP (operands[0], 0) = copy_to_mode_reg (SImode, XEXP (operands[0], 0));
+
+ if (operands[2] == NULL_RTX)
+ operands[2] = const0_rtx;
+ }
+)
+
+(define_expand "sibcall_value"
+ [(parallel [(set (match_operand 0 "" "")
+ (call (match_operand 1 "" "")
+ (match_operand 2 "" "")))
+ (return)
+ (use (match_operand 3 "" ""))])]
+ ""
+ {
+ XEXP (operands[1], 0) = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
+
+ if (operands[3] == NULL_RTX)
+ operands[3] = const0_rtx;
+ }
+)
+
+(define_insn "sibcall_insn"
+ [(call (mem:QI (match_operand:SI 0 "register_operand" "r"))
+ (match_operand 1 "" ""))
+ (return)
+ (use (match_operand 2 "" ""))]
+ ""
+ "jmp\\t%0"
+)
+
+(define_insn "sibcall_value_insn"
+ [(set (match_operand 0 "register_operand" "")
+ (call (mem:QI (match_operand:SI 1 "register_operand" "r"))
+ (match_operand 2 "" "")))
+ (return)
+ (use (match_operand 3 "" ""))]
+ ""
+ "jmp\\t%1"
+)
+
+
+
+
+(define_expand "tablejump"
+ [(parallel [(set (pc) (match_operand 0 "register_operand" "r"))
+ (use (label_ref (match_operand 1 "" "")))])]
+ ""
+ ""
+)
+
+(define_insn "*tablejump"
+ [(set (pc)
+ (match_operand:SI 0 "register_operand" "r"))
+ (use (label_ref (match_operand 1 "" "")))]
+ ""
+ "jmp\\t%0"
+ [(set_attr "type" "control")])
+
+
+
+;*****************************************************************************
+;*
+;* Comparisons
+;*
+;*****************************************************************************
+;; Flow here is rather complex (based on MIPS):
+;;
+;; 1) The cmp{si,di,sf,df} routine is called. It deposits the
+;; arguments into the branch_cmp array, and the type into
+;; branch_type. No RTL is generated.
+;;
+;; 2) The appropriate branch define_expand is called, which then
+;; creates the appropriate RTL for the comparison and branch.
+;; Different CC modes are used, based on what type of branch is
+;; done, so that we can constrain things appropriately. There
+;; are assumptions in the rest of GCC that break if we fold the
+;; operands into the branchs for integer operations, and use cc0
+;; for floating point, so we use the fp status register instead.
+;; If needed, an appropriate temporary is created to hold the
+;; of the integer compare.
+
+(define_expand "cmpsi"
+ [(set (cc0)
+ (compare:CC (match_operand:SI 0 "register_operand" "")
+ (match_operand:SI 1 "arith_operand" "")))]
+ ""
+{
+ branch_cmp[0] = operands[0];
+ branch_cmp[1] = operands[1];
+ branch_type = CMP_SI;
+ DONE;
+})
+
+(define_expand "tstsi"
+ [(set (cc0)
+ (match_operand:SI 0 "register_operand" ""))]
+ ""
+{
+ branch_cmp[0] = operands[0];
+ branch_cmp[1] = const0_rtx;
+ branch_type = CMP_SI;
+ DONE;
+})
+
+
+;*****************************************************************************
+;*
+;* setting a register from a comparison
+;*
+;*****************************************************************************
+
+(define_expand "seq"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (eq:SI (match_dup 1)
+ (match_dup 2)))]
+ ""
+{
+ if (branch_type != CMP_SI)
+ FAIL;
+
+ /* set up operands from compare. */
+ operands[1] = branch_cmp[0];
+ operands[2] = branch_cmp[1];
+
+ gen_int_relational (EQ, operands[0], operands[1], operands[2], NULL_RTX);
+ DONE;
+})
+
+
+(define_insn "*seq"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (eq:SI (match_operand:SI 1 "reg_or_0_operand" "%rM")
+ (match_operand:SI 2 "arith_operand" "rI")))]
+ ""
+ "cmpeq%i2\\t%0, %z1, %z2"
+ [(set_attr "type" "alu")])
+
+
+(define_expand "sne"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ne:SI (match_dup 1)
+ (match_dup 2)))]
+ ""
+{
+ if (branch_type != CMP_SI)
+ FAIL;
+
+ /* set up operands from compare. */
+ operands[1] = branch_cmp[0];
+ operands[2] = branch_cmp[1];
+
+ gen_int_relational (NE, operands[0], operands[1], operands[2], NULL_RTX);
+ DONE;
+})
+
+
+(define_insn "*sne"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ne:SI (match_operand:SI 1 "reg_or_0_operand" "%rM")
+ (match_operand:SI 2 "arith_operand" "rI")))]
+ ""
+ "cmpne%i2\\t%0, %z1, %z2"
+ [(set_attr "type" "alu")])
+
+
+(define_expand "sgt"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (gt:SI (match_dup 1)
+ (match_dup 2)))]
+ ""
+{
+ if (branch_type != CMP_SI)
+ FAIL;
+
+ /* set up operands from compare. */
+ operands[1] = branch_cmp[0];
+ operands[2] = branch_cmp[1];
+
+ gen_int_relational (GT, operands[0], operands[1], operands[2], NULL_RTX);
+ DONE;
+})
+
+
+(define_insn "*sgt"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (gt:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
+ (match_operand:SI 2 "reg_or_0_operand" "rM")))]
+ ""
+ "cmplt\\t%0, %z2, %z1"
+ [(set_attr "type" "alu")])
+
+
+(define_expand "sge"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ge:SI (match_dup 1)
+ (match_dup 2)))]
+ ""
+{
+ if (branch_type != CMP_SI)
+ FAIL;
+
+ /* set up operands from compare. */
+ operands[1] = branch_cmp[0];
+ operands[2] = branch_cmp[1];
+
+ gen_int_relational (GE, operands[0], operands[1], operands[2], NULL_RTX);
+ DONE;
+})
+
+
+(define_insn "*sge"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ge:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
+ (match_operand:SI 2 "arith_operand" "rI")))]
+ ""
+ "cmpge%i2\\t%0, %z1, %z2"
+ [(set_attr "type" "alu")])
+
+(define_expand "sle"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (le:SI (match_dup 1)
+ (match_dup 2)))]
+ ""
+{
+ if (branch_type != CMP_SI)
+ FAIL;
+
+ /* set up operands from compare. */
+ operands[1] = branch_cmp[0];
+ operands[2] = branch_cmp[1];
+
+ gen_int_relational (LE, operands[0], operands[1], operands[2], NULL_RTX);
+ DONE;
+})
+
+
+(define_insn "*sle"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (le:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
+ (match_operand:SI 2 "reg_or_0_operand" "rM")))]
+ ""
+ "cmpge\\t%0, %z2, %z1"
+ [(set_attr "type" "alu")])
+
+
+(define_expand "slt"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (lt:SI (match_dup 1)
+ (match_dup 2)))]
+ ""
+{
+ if (branch_type != CMP_SI)
+ FAIL;
+
+ /* set up operands from compare. */
+ operands[1] = branch_cmp[0];
+ operands[2] = branch_cmp[1];
+
+ gen_int_relational (LT, operands[0], operands[1], operands[2], NULL_RTX);
+ DONE;
+})
+
+
+(define_insn "*slt"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (lt:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
+ (match_operand:SI 2 "arith_operand" "rI")))]
+ ""
+ "cmplt%i2\\t%0, %z1, %z2"
+ [(set_attr "type" "alu")])
+
+
+(define_expand "sgtu"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (gtu:SI (match_dup 1)
+ (match_dup 2)))]
+ ""
+{
+ if (branch_type != CMP_SI)
+ FAIL;
+
+ /* set up operands from compare. */
+ operands[1] = branch_cmp[0];
+ operands[2] = branch_cmp[1];
+
+ gen_int_relational (GTU, operands[0], operands[1], operands[2], NULL_RTX);
+ DONE;
+})
+
+
+(define_insn "*sgtu"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (gtu:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
+ (match_operand:SI 2 "reg_or_0_operand" "rM")))]
+ ""
+ "cmpltu\\t%0, %z2, %z1"
+ [(set_attr "type" "alu")])
+
+
+(define_expand "sgeu"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (geu:SI (match_dup 1)
+ (match_dup 2)))]
+ ""
+{
+ if (branch_type != CMP_SI)
+ FAIL;
+
+ /* set up operands from compare. */
+ operands[1] = branch_cmp[0];
+ operands[2] = branch_cmp[1];
+
+ gen_int_relational (GEU, operands[0], operands[1], operands[2], NULL_RTX);
+ DONE;
+})
+
+
+(define_insn "*sgeu"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (geu:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
+ (match_operand:SI 2 "uns_arith_operand" "rJ")))]
+ ""
+ "cmpgeu%i2\\t%0, %z1, %z2"
+ [(set_attr "type" "alu")])
+
+(define_expand "sleu"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (leu:SI (match_dup 1)
+ (match_dup 2)))]
+ ""
+{
+ if (branch_type != CMP_SI)
+ FAIL;
+
+ /* set up operands from compare. */
+ operands[1] = branch_cmp[0];
+ operands[2] = branch_cmp[1];
+
+ gen_int_relational (LEU, operands[0], operands[1], operands[2], NULL_RTX);
+ DONE;
+})
+
+
+(define_insn "*sleu"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (leu:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
+ (match_operand:SI 2 "reg_or_0_operand" "rM")))]
+ ""
+ "cmpgeu\\t%0, %z2, %z1"
+ [(set_attr "type" "alu")])
+
+
+(define_expand "sltu"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ltu:SI (match_dup 1)
+ (match_dup 2)))]
+ ""
+{
+ if (branch_type != CMP_SI)
+ FAIL;
+
+ /* set up operands from compare. */
+ operands[1] = branch_cmp[0];
+ operands[2] = branch_cmp[1];
+
+ gen_int_relational (LTU, operands[0], operands[1], operands[2], NULL_RTX);
+ DONE;
+})
+
+
+(define_insn "*sltu"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ltu:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
+ (match_operand:SI 2 "uns_arith_operand" "rJ")))]
+ ""
+ "cmpltu%i2\\t%0, %z1, %z2"
+ [(set_attr "type" "alu")])
+
+
+
+
+;*****************************************************************************
+;*
+;* branches
+;*
+;*****************************************************************************
+
+(define_insn "*cbranch"
+ [(set (pc)
+ (if_then_else
+ (match_operator:SI 0 "comparison_operator"
+ [(match_operand:SI 2 "reg_or_0_operand" "rM")
+ (match_operand:SI 3 "reg_or_0_operand" "rM")])
+ (label_ref (match_operand 1 "" ""))
+ (pc)))]
+ ""
+ "b%0\\t%z2, %z3, %l1"
+ [(set_attr "type" "control")])
+
+
+(define_expand "beq"
+ [(set (pc)
+ (if_then_else (eq:CC (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+{
+ gen_int_relational (EQ, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]);
+ DONE;
+})
+
+
+(define_expand "bne"
+ [(set (pc)
+ (if_then_else (ne:CC (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+{
+ gen_int_relational (NE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]);
+ DONE;
+})
+
+
+(define_expand "bgt"
+ [(set (pc)
+ (if_then_else (gt:CC (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+{
+ gen_int_relational (GT, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]);
+ DONE;
+})
+
+(define_expand "bge"
+ [(set (pc)
+ (if_then_else (ge:CC (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+{
+ gen_int_relational (GE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]);
+ DONE;
+})
+
+(define_expand "ble"
+ [(set (pc)
+ (if_then_else (le:CC (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+{
+ gen_int_relational (LE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]);
+ DONE;
+})
+
+(define_expand "blt"
+ [(set (pc)
+ (if_then_else (lt:CC (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+{
+ gen_int_relational (LT, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]);
+ DONE;
+})
+
+
+(define_expand "bgtu"
+ [(set (pc)
+ (if_then_else (gtu:CC (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+{
+ gen_int_relational (GTU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]);
+ DONE;
+})
+
+(define_expand "bgeu"
+ [(set (pc)
+ (if_then_else (geu:CC (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+{
+ gen_int_relational (GEU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]);
+ DONE;
+})
+
+(define_expand "bleu"
+ [(set (pc)
+ (if_then_else (leu:CC (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+{
+ gen_int_relational (LEU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]);
+ DONE;
+})
+
+(define_expand "bltu"
+ [(set (pc)
+ (if_then_else (ltu:CC (cc0)
+ (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+{
+ gen_int_relational (LTU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]);
+ DONE;
+})
+
+
+;*****************************************************************************
+;*
+;* String and Block Operations
+;*
+;*****************************************************************************
+
+; ??? This is all really a hack to get Dhrystone to work as fast as possible
+; things to be fixed:
+; * let the compiler core handle all of this, for that to work the extra
+; aliasing needs to be addressed.
+; * we use three temporary registers for loading and storing to ensure no
+; ld use stalls, this is excessive, because after the first ld/st only
+; two are needed. Only two would be needed all the way through if
+; we could schedule with other code. Consider:
+; 1 ld $1, 0($src)
+; 2 ld $2, 4($src)
+; 3 ld $3, 8($src)
+; 4 st $1, 0($dest)
+; 5 ld $1, 12($src)
+; 6 st $2, 4($src)
+; 7 etc.
+; The first store has to wait until 4. If it does not there will be one
+; cycle of stalling. However, if any other instruction could be placed
+; between 1 and 4, $3 would not be needed.
+; * In small we probably don't want to ever do this ourself because there
+; is no ld use stall.
+
+(define_expand "movstrsi"
+ [(parallel [(set (match_operand:BLK 0 "general_operand" "")
+ (match_operand:BLK 1 "general_operand" ""))
+ (use (match_operand:SI 2 "const_int_operand" ""))
+ (use (match_operand:SI 3 "const_int_operand" ""))
+ (clobber (match_scratch:SI 4 "=&r"))
+ (clobber (match_scratch:SI 5 "=&r"))
+ (clobber (match_scratch:SI 6 "=&r"))])]
+ "TARGET_INLINE_MEMCPY"
+{
+ rtx ld_addr_reg, st_addr_reg;
+
+ /* If the predicate for op2 fails in expr.c:emit_block_move_via_movstr
+ it trys to copy to a register, but does not re-try the predicate.
+ ??? Intead of fixing expr.c, I fix it here. */
+ if (!const_int_operand (operands[2], SImode))
+ FAIL;
+
+ /* ??? there are some magic numbers which need to be sorted out here.
+ the basis for them is not increasing code size hugely or going
+ out of range of offset addressing */
+ if (INTVAL (operands[3]) < 4)
+ FAIL;
+ if (!optimize
+ || (optimize_size && INTVAL (operands[2]) > 12)
+ || (optimize < 3 && INTVAL (operands[2]) > 100)
+ || INTVAL (operands[2]) > 200)
+ FAIL;
+
+ st_addr_reg
+ = replace_equiv_address (operands[0],
+ copy_to_mode_reg (Pmode, XEXP (operands[0], 0)));
+ ld_addr_reg
+ = replace_equiv_address (operands[1],
+ copy_to_mode_reg (Pmode, XEXP (operands[1], 0)));
+ emit_insn (gen_movstrsi_internal (st_addr_reg, ld_addr_reg,
+ operands[2], operands[3]));
+
+ DONE;
+})
+
+
+(define_insn "movstrsi_internal"
+ [(set (match_operand:BLK 0 "memory_operand" "=o")
+ (match_operand:BLK 1 "memory_operand" "o"))
+ (use (match_operand:SI 2 "const_int_operand" "i"))
+ (use (match_operand:SI 3 "const_int_operand" "i"))
+ (clobber (match_scratch:SI 4 "=&r"))
+ (clobber (match_scratch:SI 5 "=&r"))
+ (clobber (match_scratch:SI 6 "=&r"))]
+ "TARGET_INLINE_MEMCPY"
+{
+ int ld_offset = INTVAL (operands[2]);
+ int ld_len = INTVAL (operands[2]);
+ int ld_reg = 0;
+ rtx ld_addr_reg = XEXP (operands[1], 0);
+ int st_offset = INTVAL (operands[2]);
+ int st_len = INTVAL (operands[2]);
+ int st_reg = 0;
+ rtx st_addr_reg = XEXP (operands[0], 0);
+ int delay_count = 0;
+
+ /* ops[0] is the address used by the insn
+ ops[1] is the register being loaded or stored */
+ rtx ops[2];
+
+ if (INTVAL (operands[3]) < 4)
+ abort ();
+
+ while (ld_offset >= 4)
+ {
+ /* if the load use delay has been met, I can start
+ storing */
+ if (delay_count >= 3)
+ {
+ ops[0] = gen_rtx (MEM, SImode,
+ plus_constant (st_addr_reg, st_len - st_offset));
+ ops[1] = operands[st_reg + 4];
+ output_asm_insn ("stw\t%1, %0", ops);
+
+ st_reg = (st_reg + 1) % 3;
+ st_offset -= 4;
+ }
+
+ ops[0] = gen_rtx (MEM, SImode,
+ plus_constant (ld_addr_reg, ld_len - ld_offset));
+ ops[1] = operands[ld_reg + 4];
+ output_asm_insn ("ldw\t%1, %0", ops);
+
+ ld_reg = (ld_reg + 1) % 3;
+ ld_offset -= 4;
+ delay_count++;
+ }
+
+ if (ld_offset >= 2)
+ {
+ /* if the load use delay has been met, I can start
+ storing */
+ if (delay_count >= 3)
+ {
+ ops[0] = gen_rtx (MEM, SImode,
+ plus_constant (st_addr_reg, st_len - st_offset));
+ ops[1] = operands[st_reg + 4];
+ output_asm_insn ("stw\t%1, %0", ops);
+
+ st_reg = (st_reg + 1) % 3;
+ st_offset -= 4;
+ }
+
+ ops[0] = gen_rtx (MEM, HImode,
+ plus_constant (ld_addr_reg, ld_len - ld_offset));
+ ops[1] = operands[ld_reg + 4];
+ output_asm_insn ("ldh\t%1, %0", ops);
+
+ ld_reg = (ld_reg + 1) % 3;
+ ld_offset -= 2;
+ delay_count++;
+ }
+
+ if (ld_offset >= 1)
+ {
+ /* if the load use delay has been met, I can start
+ storing */
+ if (delay_count >= 3)
+ {
+ ops[0] = gen_rtx (MEM, SImode,
+ plus_constant (st_addr_reg, st_len - st_offset));
+ ops[1] = operands[st_reg + 4];
+ output_asm_insn ("stw\t%1, %0", ops);
+
+ st_reg = (st_reg + 1) % 3;
+ st_offset -= 4;
+ }
+
+ ops[0] = gen_rtx (MEM, QImode,
+ plus_constant (ld_addr_reg, ld_len - ld_offset));
+ ops[1] = operands[ld_reg + 4];
+ output_asm_insn ("ldb\t%1, %0", ops);
+
+ ld_reg = (ld_reg + 1) % 3;
+ ld_offset -= 1;
+ delay_count++;
+ }
+
+ while (st_offset >= 4)
+ {
+ ops[0] = gen_rtx (MEM, SImode,
+ plus_constant (st_addr_reg, st_len - st_offset));
+ ops[1] = operands[st_reg + 4];
+ output_asm_insn ("stw\t%1, %0", ops);
+
+ st_reg = (st_reg + 1) % 3;
+ st_offset -= 4;
+ }
+
+ while (st_offset >= 2)
+ {
+ ops[0] = gen_rtx (MEM, HImode,
+ plus_constant (st_addr_reg, st_len - st_offset));
+ ops[1] = operands[st_reg + 4];
+ output_asm_insn ("sth\t%1, %0", ops);
+
+ st_reg = (st_reg + 1) % 3;
+ st_offset -= 2;
+ }
+
+ while (st_offset >= 1)
+ {
+ ops[0] = gen_rtx (MEM, QImode,
+ plus_constant (st_addr_reg, st_len - st_offset));
+ ops[1] = operands[st_reg + 4];
+ output_asm_insn ("stb\t%1, %0", ops);
+
+ st_reg = (st_reg + 1) % 3;
+ st_offset -= 1;
+ }
+
+ return "";
+}
+; ??? lengths are not being used yet, but I will probably forget
+; to update this once I am using lengths, so set it to something
+; definetely big enough to cover it. 400 allows for 200 bytes
+; of motion.
+ [(set_attr "length" "400")])
+
+
+
+;*****************************************************************************
+;*
+;* Custom instructions
+;*
+;*****************************************************************************
+
+(define_constants [
+ (CUSTOM_N 100)
+ (CUSTOM_NI 101)
+ (CUSTOM_NF 102)
+ (CUSTOM_NP 103)
+ (CUSTOM_NII 104)
+ (CUSTOM_NIF 105)
+ (CUSTOM_NIP 106)
+ (CUSTOM_NFI 107)
+ (CUSTOM_NFF 108)
+ (CUSTOM_NFP 109)
+ (CUSTOM_NPI 110)
+ (CUSTOM_NPF 111)
+ (CUSTOM_NPP 112)
+ (CUSTOM_IN 113)
+ (CUSTOM_INI 114)
+ (CUSTOM_INF 115)
+ (CUSTOM_INP 116)
+ (CUSTOM_INII 117)
+ (CUSTOM_INIF 118)
+ (CUSTOM_INIP 119)
+ (CUSTOM_INFI 120)
+ (CUSTOM_INFF 121)
+ (CUSTOM_INFP 122)
+ (CUSTOM_INPI 123)
+ (CUSTOM_INPF 124)
+ (CUSTOM_INPP 125)
+ (CUSTOM_FN 126)
+ (CUSTOM_FNI 127)
+ (CUSTOM_FNF 128)
+ (CUSTOM_FNP 129)
+ (CUSTOM_FNII 130)
+ (CUSTOM_FNIF 131)
+ (CUSTOM_FNIP 132)
+ (CUSTOM_FNFI 133)
+ (CUSTOM_FNFF 134)
+ (CUSTOM_FNFP 135)
+ (CUSTOM_FNPI 136)
+ (CUSTOM_FNPF 137)
+ (CUSTOM_FNPP 138)
+ (CUSTOM_PN 139)
+ (CUSTOM_PNI 140)
+ (CUSTOM_PNF 141)
+ (CUSTOM_PNP 142)
+ (CUSTOM_PNII 143)
+ (CUSTOM_PNIF 144)
+ (CUSTOM_PNIP 145)
+ (CUSTOM_PNFI 146)
+ (CUSTOM_PNFF 147)
+ (CUSTOM_PNFP 148)
+ (CUSTOM_PNPI 149)
+ (CUSTOM_PNPF 150)
+ (CUSTOM_PNPP 151)
+])
+
+
+(define_insn "custom_n"
+ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")] CUSTOM_N)]
+ ""
+ "custom\\t%0, zero, zero, zero"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_ni"
+ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")
+ (match_operand:SI 1 "register_operand" "r")] CUSTOM_NI)]
+ ""
+ "custom\\t%0, zero, %1, zero"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_nf"
+ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")
+ (match_operand:SF 1 "register_operand" "r")] CUSTOM_NF)]
+ ""
+ "custom\\t%0, zero, %1, zero"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_np"
+ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")
+ (match_operand:SI 1 "register_operand" "r")] CUSTOM_NP)]
+ ""
+ "custom\\t%0, zero, %1, zero"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_nii"
+ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")
+ (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NII)]
+ ""
+ "custom\\t%0, zero, %1, %2"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_nif"
+ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")
+ (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SF 2 "register_operand" "r")] CUSTOM_NIF)]
+ ""
+ "custom\\t%0, zero, %1, %2"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_nip"
+ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")
+ (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NIP)]
+ ""
+ "custom\\t%0, zero, %1, %2"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_nfi"
+ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")
+ (match_operand:SF 1 "register_operand" "r")
+ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NFI)]
+ ""
+ "custom\\t%0, zero, %1, %2"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_nff"
+ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")
+ (match_operand:SF 1 "register_operand" "r")
+ (match_operand:SF 2 "register_operand" "r")] CUSTOM_NFF)]
+ ""
+ "custom\\t%0, zero, %1, %2"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_nfp"
+ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")
+ (match_operand:SF 1 "register_operand" "r")
+ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NFP)]
+ ""
+ "custom\\t%0, zero, %1, %2"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_npi"
+ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")
+ (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NPI)]
+ ""
+ "custom\\t%0, zero, %1, %2"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_npf"
+ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")
+ (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SF 2 "register_operand" "r")] CUSTOM_NPF)]
+ ""
+ "custom\\t%0, zero, %1, %2"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_npp"
+ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")
+ (match_operand:SI 1 "register_operand" "r")
+ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NPP)]
+ ""
+ "custom\\t%0, zero, %1, %2"
+ [(set_attr "type" "custom")])
+
+
+
+(define_insn "custom_in"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")] CUSTOM_IN))]
+ ""
+ "custom\\t%1, %0, zero, zero"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_ini"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SI 2 "register_operand" "r")] CUSTOM_INI))]
+ ""
+ "custom\\t%1, %0, %2, zero"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_inf"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SF 2 "register_operand" "r")] CUSTOM_INF))]
+ ""
+ "custom\\t%1, %0, %2, zero"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_inp"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SI 2 "register_operand" "r")] CUSTOM_INP))]
+ ""
+ "custom\\t%1, %0, %2, zero"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_inii"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INII))]
+ ""
+ "custom\\t%1, %0, %2, %3"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_inif"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SF 3 "register_operand" "r")] CUSTOM_INIF))]
+ ""
+ "custom\\t%1, %0, %2, %3"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_inip"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INIP))]
+ ""
+ "custom\\t%1, %0, %2, %3"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_infi"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SF 2 "register_operand" "r")
+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INFI))]
+ ""
+ "custom\\t%1, %0, %2, %3"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_inff"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SF 2 "register_operand" "r")
+ (match_operand:SF 3 "register_operand" "r")] CUSTOM_INFF))]
+ ""
+ "custom\\t%1, %0, %2, %3"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_infp"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SF 2 "register_operand" "r")
+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INFP))]
+ ""
+ "custom\\t%1, %0, %2, %3"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_inpi"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INPI))]
+ ""
+ "custom\\t%1, %0, %2, %3"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_inpf"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SF 3 "register_operand" "r")] CUSTOM_INPF))]
+ ""
+ "custom\\t%1, %0, %2, %3"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_inpp"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INPP))]
+ ""
+ "custom\\t%1, %0, %2, %3"
+ [(set_attr "type" "custom")])
+
+
+
+
+
+(define_insn "custom_fn"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")] CUSTOM_FN))]
+ ""
+ "custom\\t%1, %0, zero, zero"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_fni"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SI 2 "register_operand" "r")] CUSTOM_FNI))]
+ ""
+ "custom\\t%1, %0, %2, zero"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_fnf"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SF 2 "register_operand" "r")] CUSTOM_FNF))]
+ ""
+ "custom\\t%1, %0, %2, zero"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_fnp"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SI 2 "register_operand" "r")] CUSTOM_FNP))]
+ ""
+ "custom\\t%1, %0, %2, zero"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_fnii"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNII))]
+ ""
+ "custom\\t%1, %0, %2, %3"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_fnif"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SF 3 "register_operand" "r")] CUSTOM_FNIF))]
+ ""
+ "custom\\t%1, %0, %2, %3"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_fnip"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNIP))]
+ ""
+ "custom\\t%1, %0, %2, %3"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_fnfi"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SF 2 "register_operand" "r")
+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNFI))]
+ ""
+ "custom\\t%1, %0, %2, %3"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_fnff"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SF 2 "register_operand" "r")
+ (match_operand:SF 3 "register_operand" "r")] CUSTOM_FNFF))]
+ ""
+ "custom\\t%1, %0, %2, %3"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_fnfp"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SF 2 "register_operand" "r")
+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNFP))]
+ ""
+ "custom\\t%1, %0, %2, %3"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_fnpi"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNPI))]
+ ""
+ "custom\\t%1, %0, %2, %3"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_fnpf"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SF 3 "register_operand" "r")] CUSTOM_FNPF))]
+ ""
+ "custom\\t%1, %0, %2, %3"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_fnpp"
+ [(set (match_operand:SF 0 "register_operand" "=r")
+ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNPP))]
+ ""
+ "custom\\t%1, %0, %2, %3"
+ [(set_attr "type" "custom")])
+
+
+
+(define_insn "custom_pn"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")] CUSTOM_PN))]
+ ""
+ "custom\\t%1, %0, zero, zero"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_pni"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SI 2 "register_operand" "r")] CUSTOM_PNI))]
+ ""
+ "custom\\t%1, %0, %2, zero"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_pnf"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SF 2 "register_operand" "r")] CUSTOM_PNF))]
+ ""
+ "custom\\t%1, %0, %2, zero"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_pnp"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SI 2 "register_operand" "r")] CUSTOM_PNP))]
+ ""
+ "custom\\t%1, %0, %2, zero"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_pnii"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNII))]
+ ""
+ "custom\\t%1, %0, %2, %3"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_pnif"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SF 3 "register_operand" "r")] CUSTOM_PNIF))]
+ ""
+ "custom\\t%1, %0, %2, %3"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_pnip"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNIP))]
+ ""
+ "custom\\t%1, %0, %2, %3"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_pnfi"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SF 2 "register_operand" "r")
+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNFI))]
+ ""
+ "custom\\t%1, %0, %2, %3"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_pnff"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SF 2 "register_operand" "r")
+ (match_operand:SF 3 "register_operand" "r")] CUSTOM_PNFF))]
+ ""
+ "custom\\t%1, %0, %2, %3"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_pnfp"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SF 2 "register_operand" "r")
+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNFP))]
+ ""
+ "custom\\t%1, %0, %2, %3"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_pnpi"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNPI))]
+ ""
+ "custom\\t%1, %0, %2, %3"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_pnpf"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SF 3 "register_operand" "r")] CUSTOM_PNPF))]
+ ""
+ "custom\\t%1, %0, %2, %3"
+ [(set_attr "type" "custom")])
+
+(define_insn "custom_pnpp"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
+ (match_operand:SI 2 "register_operand" "r")
+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNPP))]
+ ""
+ "custom\\t%1, %0, %2, %3"
+ [(set_attr "type" "custom")])
+
+
+
+
+
+
+;*****************************************************************************
+;*
+;* Misc
+;*
+;*****************************************************************************
+
+(define_insn "nop"
+ [(const_int 0)]
+ ""
+ "nop\\t"
+ [(set_attr "type" "alu")])
+
+(define_insn "sync"
+ [(unspec_volatile [(const_int 0)] UNSPEC_SYNC)]
+ ""
+ "sync\\t"
+ [(set_attr "type" "control")])
+
+
+(define_insn "rdctl"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(match_operand:SI 1 "rdwrctl_operand" "O")] UNSPEC_RDCTL))]
+ ""
+ "rdctl\\t%0, ctl%1"
+ [(set_attr "type" "control")])
+
+(define_insn "wrctl"
+ [(unspec_volatile:SI [(match_operand:SI 0 "rdwrctl_operand" "O")
+ (match_operand:SI 1 "register_operand" "r")] UNSPEC_WRCTL)]
+ ""
+ "wrctl\\tctl%0, %1"
+ [(set_attr "type" "control")])
+
+
+
+;*****************************************************************************
+;*
+;* Peepholes
+;*
+;*****************************************************************************
+
+
diff -durN gcc-3.4.6.orig/gcc/config/nios2/nios2-protos.h gcc-3.4.6/gcc/config/nios2/nios2-protos.h
--- gcc-3.4.6.orig/gcc/config/nios2/nios2-protos.h 1970-01-01 01:00:00.000000000 +0100
+++ gcc-3.4.6/gcc/config/nios2/nios2-protos.h 2007-08-15 23:09:36.000000000 +0200
@@ -0,0 +1,70 @@
+/* Subroutines for assembler code output for Altera NIOS 2G NIOS2 version.
+ Copyright (C) 2003 Altera
+ Contributed by Jonah Graham (jgraham@altera.com).
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+extern void dump_frame_size (FILE *);
+extern HOST_WIDE_INT compute_frame_size (void);
+extern int nios2_initial_elimination_offset (int, int);
+extern void override_options (void);
+extern void optimization_options (int, int);
+extern int nios2_can_use_return_insn (void);
+extern void expand_prologue (void);
+extern void expand_epilogue (bool);
+extern void function_profiler (FILE *, int);
+
+
+#ifdef RTX_CODE
+extern int nios2_legitimate_address (rtx, enum machine_mode, int);
+extern void nios2_print_operand (FILE *, rtx, int);
+extern void nios2_print_operand_address (FILE *, rtx);
+
+extern int nios2_emit_move_sequence (rtx *, enum machine_mode);
+extern int nios2_emit_expensive_div (rtx *, enum machine_mode);
+
+extern void gen_int_relational (enum rtx_code, rtx, rtx, rtx, rtx);
+extern void gen_conditional_move (rtx *, enum machine_mode);
+extern const char *asm_output_opcode (FILE *, const char *);
+
+/* predicates */
+extern int arith_operand (rtx, enum machine_mode);
+extern int uns_arith_operand (rtx, enum machine_mode);
+extern int logical_operand (rtx, enum machine_mode);
+extern int shift_operand (rtx, enum machine_mode);
+extern int reg_or_0_operand (rtx, enum machine_mode);
+extern int equality_op (rtx, enum machine_mode);
+extern int custom_insn_opcode (rtx, enum machine_mode);
+extern int rdwrctl_operand (rtx, enum machine_mode);
+
+# ifdef HAVE_MACHINE_MODES
+# if defined TREE_CODE
+extern void function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode, tree, int);
+extern rtx function_arg (const CUMULATIVE_ARGS *, enum machine_mode, tree, int);
+extern int function_arg_partial_nregs (const CUMULATIVE_ARGS *, enum machine_mode, tree, int);
+extern void init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree, int);
+extern int nios2_setup_incoming_varargs (const CUMULATIVE_ARGS *, enum machine_mode, tree, int);
+
+# endif /* TREE_CODE */
+# endif /* HAVE_MACHINE_MODES */
+#endif
+
+#ifdef TREE_CODE
+extern int nios2_return_in_memory (tree);
+
+#endif /* TREE_CODE */
diff -durN gcc-3.4.6.orig/gcc/config/nios2/t-nios2 gcc-3.4.6/gcc/config/nios2/t-nios2
--- gcc-3.4.6.orig/gcc/config/nios2/t-nios2 1970-01-01 01:00:00.000000000 +0100
+++ gcc-3.4.6/gcc/config/nios2/t-nios2 2007-08-15 23:09:36.000000000 +0200
@@ -0,0 +1,123 @@
+##
+## Compiler flags to use when compiling libgcc2.c.
+##
+## LIB2FUNCS_EXTRA
+## A list of source file names to be compiled or assembled and inserted into libgcc.a.
+
+LIB2FUNCS_EXTRA=$(srcdir)/config/nios2/lib2-divmod.c \
+ $(srcdir)/config/nios2/lib2-divmod-hi.c \
+ $(srcdir)/config/nios2/lib2-divtable.c \
+ $(srcdir)/config/nios2/lib2-mul.c
+
+##
+## Floating Point Emulation
+## To have GCC include software floating point libraries in libgcc.a define FPBIT
+## and DPBIT along with a few rules as follows:
+##
+## # We want fine grained libraries, so use the new code
+## # to build the floating point emulation libraries.
+FPBIT=$(srcdir)/config/nios2/nios2-fp-bit.c
+DPBIT=$(srcdir)/config/nios2/nios2-dp-bit.c
+
+TARGET_LIBGCC2_CFLAGS = -O2
+
+# FLOAT_ONLY - no doubles
+# SMALL_MACHINE - QI/HI is faster than SI
+# Actually SMALL_MACHINE uses chars and shorts instead of ints
+# since ints (16-bit ones as they are today) are at least as fast
+# as chars and shorts, don't define SMALL_MACHINE
+# CMPtype - type returned by FP compare, i.e. INT (hard coded in fp-bit - see code )
+
+$(FPBIT): $(srcdir)/config/fp-bit.c Makefile
+ echo '#define FLOAT' > ${FPBIT}
+ cat $(srcdir)/config/fp-bit.c >> ${FPBIT}
+
+$(DPBIT): $(srcdir)/config/fp-bit.c Makefile
+ echo '' > ${DPBIT}
+ cat $(srcdir)/config/fp-bit.c >> ${DPBIT}
+
+EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o crti.o crtn.o
+
+# Assemble startup files.
+$(T)crti.o: $(srcdir)/config/nios2/crti.asm $(GCC_PASSES)
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \
+ -c -o $(T)crti.o -x assembler-with-cpp $(srcdir)/config/nios2/crti.asm
+
+$(T)crtn.o: $(srcdir)/config/nios2/crtn.asm $(GCC_PASSES)
+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \
+ -c -o $(T)crtn.o -x assembler-with-cpp $(srcdir)/config/nios2/crtn.asm
+
+
+## You may need to provide additional #defines at the beginning of
+## fp-bit.c and dp-bit.c to control target endianness and other options
+##
+## CRTSTUFF_T_CFLAGS
+## Special flags used when compiling crtstuff.c. See Initialization.
+##
+## CRTSTUFF_T_CFLAGS_S
+## Special flags used when compiling crtstuff.c for shared linking. Used
+## if you use crtbeginS.o and crtendS.o in EXTRA-PARTS. See Initialization.
+##
+## MULTILIB_OPTIONS
+## For some targets, invoking GCC in different ways produces objects that
+## can not be linked together. For example, for some targets GCC produces
+## both big and little endian code. For these targets, you must arrange
+## for multiple versions of libgcc.a to be compiled, one for each set of
+## incompatible options. When GCC invokes the linker, it arranges to link
+## in the right version of libgcc.a, based on the command line options
+## used.
+## The MULTILIB_OPTIONS macro lists the set of options for which special
+## versions of libgcc.a must be built. Write options that are mutually
+## incompatible side by side, separated by a slash. Write options that may
+## be used together separated by a space. The build procedure will build
+## all combinations of compatible options.
+##
+## For example, if you set MULTILIB_OPTIONS to m68000/m68020 msoft-float,
+## Makefile will build special versions of libgcc.a using the following
+## sets of options: -m68000, -m68020, -msoft-float, -m68000 -msoft-float,
+## and -m68020 -msoft-float.
+
+MULTILIB_OPTIONS = mno-hw-mul mhw-mulx
+
+## MULTILIB_DIRNAMES
+## If MULTILIB_OPTIONS is used, this variable specifies the directory names
+## that should be used to hold the various libraries. Write one element in
+## MULTILIB_DIRNAMES for each element in MULTILIB_OPTIONS. If
+## MULTILIB_DIRNAMES is not used, the default value will be
+## MULTILIB_OPTIONS, with all slashes treated as spaces.
+## For example, if MULTILIB_OPTIONS is set to m68000/m68020 msoft-float,
+## then the default value of MULTILIB_DIRNAMES is m68000 m68020
+## msoft-float. You may specify a different value if you desire a
+## different set of directory names.
+
+# MULTILIB_DIRNAMES =
+
+## MULTILIB_MATCHES
+## Sometimes the same option may be written in two different ways. If an
+## option is listed in MULTILIB_OPTIONS, GCC needs to know about any
+## synonyms. In that case, set MULTILIB_MATCHES to a list of items of the
+## form option=option to describe all relevant synonyms. For example,
+## m68000=mc68000 m68020=mc68020.
+##
+## MULTILIB_EXCEPTIONS
+## Sometimes when there are multiple sets of MULTILIB_OPTIONS being
+## specified, there are combinations that should not be built. In that
+## case, set MULTILIB_EXCEPTIONS to be all of the switch exceptions in
+## shell case syntax that should not be built.
+## For example, in the PowerPC embedded ABI support, it is not desirable to
+## build libraries compiled with the -mcall-aix option and either of the
+## -fleading-underscore or -mlittle options at the same time. Therefore
+## MULTILIB_EXCEPTIONS is set to
+##
+## *mcall-aix/*fleading-underscore* *mlittle/*mcall-aix*
+##
+
+MULTILIB_EXCEPTIONS = *mno-hw-mul/*mhw-mulx*
+
+##
+## MULTILIB_EXTRA_OPTS Sometimes it is desirable that when building
+## multiple versions of libgcc.a certain options should always be passed on
+## to the compiler. In that case, set MULTILIB_EXTRA_OPTS to be the list
+## of options to be used for all builds.
+##
+
diff -durN gcc-3.4.6.orig/gcc/config.gcc gcc-3.4.6/gcc/config.gcc
--- gcc-3.4.6.orig/gcc/config.gcc 2007-08-15 23:07:00.000000000 +0200
+++ gcc-3.4.6/gcc/config.gcc 2007-08-15 23:09:36.000000000 +0200
@@ -1342,6 +1342,10 @@
thread_file='posix'
fi
;;
+# JBG
+nios2-*-* | nios2-*-*)
+ tm_file="elfos.h ${tm_file}"
+ ;;
# m68hc11 and m68hc12 share the same machine description.
m68hc11-*-*|m6811-*-*)
tm_file="dbxelf.h elfos.h m68hc11/m68hc11.h"
diff -durN gcc-3.4.6.orig/gcc/cse.c gcc-3.4.6/gcc/cse.c
--- gcc-3.4.6.orig/gcc/cse.c 2005-12-31 01:39:42.000000000 +0100
+++ gcc-3.4.6/gcc/cse.c 2007-08-15 23:09:36.000000000 +0200
@@ -3134,6 +3134,10 @@
#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 -durN gcc-3.4.6.orig/gcc/doc/extend.texi gcc-3.4.6/gcc/doc/extend.texi
--- gcc-3.4.6.orig/gcc/doc/extend.texi 2005-02-26 23:17:26.000000000 +0100
+++ gcc-3.4.6/gcc/doc/extend.texi 2007-08-15 23:09:36.000000000 +0200
@@ -5638,12 +5638,118 @@
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
diff -durN gcc-3.4.6.orig/gcc/doc/invoke.texi gcc-3.4.6/gcc/doc/invoke.texi
--- gcc-3.4.6.orig/gcc/doc/invoke.texi 2005-10-08 02:22:20.000000000 +0200
+++ gcc-3.4.6/gcc/doc/invoke.texi 2007-08-15 23:09:36.000000000 +0200
@@ -337,6 +337,14 @@
@item Machine Dependent Options
@xref{Submodel Options,,Hardware Models and Configurations}.
+@emph{Altera Nios II Options}
+@gccoptlist{-msmallc -mno-bypass-cache -mbypass-cache @gol
+-mno-cache-volatile -mcache-volatile -mno-inline-memcpy @gol
+-minline-memcpy -mno-fast-sw-div -mfast-sw-div @gol
+-mhw-mul -mno-hw-mul -mhw-mulx -mno-hw-mulx @gol
+-mno-hw-div -mhw-div @gol
+-msys-crt0= -msys-lib= -msys=nosys }
+
@emph{M680x0 Options}
@gccoptlist{-m68000 -m68020 -m68020-40 -m68020-60 -m68030 -m68040 @gol
-m68060 -mcpu32 -m5200 -m68881 -mbitfield -mc68000 -mc68020 @gol
@@ -5839,6 +5847,7 @@
that macro, which enables you to change the defaults.
@menu
+* Altera Nios II Options::
* M680x0 Options::
* M68hc1x Options::
* VAX Options::
@@ -5874,6 +5883,103 @@
* FRV Options::
@end menu
+
+@node Altera Nios II Options
+@subsection Altera Nios II Options
+@cindex Altera Nios II options
+
+These are the @samp{-m} options defined for the Altera Nios II
+processor.
+
+@table @gcctabopt
+
+@item -msmallc
+@opindex msmallc
+
+Link with a limited version of the C library, -lsmallc. For more
+information see the C Library Documentation.
+
+
+@item -mbypass-cache
+@itemx -mno-bypass-cache
+@opindex mno-bypass-cache
+@opindex mbypass-cache
+
+Force all load and store instructions to always bypass cache by
+using io variants of the instructions. The default is to not
+bypass the cache.
+
+@item -mno-cache-volatile
+@itemx -mcache-volatile
+@opindex mcache-volatile
+@opindex mno-cache-volatile
+
+Volatile memory access bypass the cache using the io variants of
+the ld and st instructions. The default is to cache volatile
+accesses.
+
+-mno-cache-volatile is deprecated and will be deleted in a
+future GCC release.
+
+
+@item -mno-inline-memcpy
+@itemx -minline-memcpy
+@opindex mno-inline-memcpy
+@opindex minline-memcpy
+
+Do not inline memcpy. The default is to inline when -O is on.
+
+
+@item -mno-fast-sw-div
+@itemx -mfast-sw-div
+@opindex mno-fast-sw-div
+@opindex mfast-sw-div
+
+Do no use table based fast divide for small numbers. The default
+is to use the fast divide at -O3 and above.
+
+
+@item -mno-hw-mul
+@itemx -mhw-mul
+@itemx -mno-hw-mulx
+@itemx -mhw-mulx
+@itemx -mno-hw-div
+@itemx -mhw-div
+@opindex mno-hw-mul
+@opindex mhw-mul
+@opindex mno-hw-mulx
+@opindex mhw-mulx
+@opindex mno-hw-div
+@opindex mhw-div
+
+Enable or disable emitting @code{mul}, @code{mulx} and @code{div} family of
+instructions by the compiler. The default is to emit @code{mul}
+and not emit @code{div} and @code{mulx}.
+
+The different combinations of @code{mul} and @code{mulx} instructions
+generate a different multilib options.
+
+
+@item -msys-crt0=@var{startfile}
+@opindex msys-crt0
+
+@var{startfile} is the file name of the startfile (crt0) to use
+when linking. The default is crt0.o that comes with libgloss
+and is only suitable for use with the instruction set
+simulator.
+
+@item -msys-lib=@var{systemlib}
+@itemx -msys-lib=nosys
+@opindex msys-lib
+
+@var{systemlib} is the library name of the library which provides
+the system calls required by the C library, e.g. @code{read}, @code{write}
+etc. The default is to use nosys, this library provides
+stub implementations of the calls and is part of libgloss.
+
+@end table
+
+
@node M680x0 Options
@subsection M680x0 Options
@cindex M680x0 options
diff -durN gcc-3.4.6.orig/gcc/doc/md.texi gcc-3.4.6/gcc/doc/md.texi
--- gcc-3.4.6.orig/gcc/doc/md.texi 2004-11-13 23:31:42.000000000 +0100
+++ gcc-3.4.6/gcc/doc/md.texi 2007-08-15 23:09:36.000000000 +0200
@@ -1337,6 +1337,49 @@
available on some particular machines.
@table @emph
+
+@item Altera Nios II family---@file{nios2.h}
+@table @code
+
+@item I
+Integer that is valid as an immediate operand in an
+instruction taking a signed 16-bit number. Range
+@minus{}32768 to 32767.
+
+@item J
+Integer that is valid as an immediate operand in an
+instruction taking an unsigned 16-bit number. Range
+0 to 65535.
+
+@item K
+Integer that is valid as an immediate operand in an
+instruction taking only the upper 16-bits of a
+32-bit number. Range 32-bit numbers with the lower
+16-bits being 0.
+
+@item L
+Integer that is valid as an immediate operand for a
+shift instruction. Range 0 to 31.
+
+
+@item M
+Integer that is valid as an immediate operand for
+only the value 0. Can be used in conjunction with
+the format modifier @code{z} to use @code{r0}
+instead of @code{0} in the assembly output.
+
+@item N
+Integer that is valid as an immediate operand for
+a custom instruction opcode. Range 0 to 255.
+
+@item S
+Matches immediates which are addresses in the small
+data section and therefore can be added to @code{gp}
+as a 16-bit immediate to re-create their 32-bit value.
+
+@end table
+
+
@item ARM family---@file{arm.h}
@table @code
@item f
diff -durN gcc-3.4.6.orig/gcc/Makefile.in gcc-3.4.6/gcc/Makefile.in
--- gcc-3.4.6.orig/gcc/Makefile.in 2005-02-24 10:26:59.000000000 +0100
+++ gcc-3.4.6/gcc/Makefile.in 2007-08-15 23:09:36.000000000 +0200
@@ -3094,7 +3094,7 @@
$(INSTALL_DATA) $(srcdir)/README-fixinc \
$(DESTDIR)$(itoolsdatadir)/include/README ; \
$(INSTALL_SCRIPT) fixinc.sh $(DESTDIR)$(itoolsdir)/fixinc.sh ; \
- $(INSTALL_PROGRAM) fixinc/fixincl $(DESTDIR)$(itoolsdir)/fixincl ; \
+ $(INSTALL_PROGRAM) fixinc/fixincl$(build_exeext) $(DESTDIR)$(itoolsdir)/fixincl$(build_exeext) ; \
$(INSTALL_DATA) $(srcdir)/gsyslimits.h \
$(DESTDIR)$(itoolsdatadir)/gsyslimits.h ; \
else :; fi