|
@@ -1,14377 +0,0 @@
|
|
|
-diff --git a/config.sub b/config.sub
|
|
|
-index d2e3557..2297c30 100755
|
|
|
---- a/config.sub
|
|
|
-+++ b/config.sub
|
|
|
-@@ -276,6 +276,15 @@ case $basic_machine in
|
|
|
- basic_machine=$basic_machine-unknown
|
|
|
- os=-none
|
|
|
- ;;
|
|
|
-+ # JBG
|
|
|
-+ nios2 | nios2-* | nios2el | nios2el-*)
|
|
|
-+ basic_machine=nios2-altera
|
|
|
-+ os=-none_el
|
|
|
-+ ;;
|
|
|
-+ nios2eb | nios2eb-*)
|
|
|
-+ basic_machine=nios2-altera
|
|
|
-+ os=-none_eb
|
|
|
-+ ;;
|
|
|
- m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
|
|
|
- ;;
|
|
|
-
|
|
|
-diff --git a/gcc/combine.c b/gcc/combine.c
|
|
|
-index 8f43c23..02648b1 100644
|
|
|
---- a/gcc/combine.c
|
|
|
-+++ b/gcc/combine.c
|
|
|
-@@ -4381,6 +4381,14 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
|
|
|
- mode);
|
|
|
- }
|
|
|
-
|
|
|
-+#ifndef __nios2__
|
|
|
-+/* This screws up Nios II in this test case:
|
|
|
-+
|
|
|
-+if (x & 1)
|
|
|
-+ return 2;
|
|
|
-+else
|
|
|
-+ return 3;
|
|
|
-+*/
|
|
|
- else if (STORE_FLAG_VALUE == 1
|
|
|
- && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
|
|
|
- && op1 == const0_rtx
|
|
|
-@@ -4392,6 +4400,7 @@ combine_simplify_rtx (rtx x, enum machine_mode op0_mode, int last,
|
|
|
- gen_lowpart_for_combine (mode, op0),
|
|
|
- const1_rtx);
|
|
|
- }
|
|
|
-+#endif
|
|
|
-
|
|
|
- else if (STORE_FLAG_VALUE == 1
|
|
|
- && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT
|
|
|
-diff --git a/gcc/config.gcc b/gcc/config.gcc
|
|
|
-index d22f34b..4ecb6e9 100644
|
|
|
---- a/gcc/config.gcc
|
|
|
-+++ b/gcc/config.gcc
|
|
|
-@@ -1337,6 +1337,17 @@ m32rle-*-linux*)
|
|
|
- thread_file='posix'
|
|
|
- fi
|
|
|
- ;;
|
|
|
-+# JBG
|
|
|
-+nios2-*-elf*_eb)
|
|
|
-+ tm_file="elfos.h nios2/big.h ${tm_file}"
|
|
|
-+ ;;
|
|
|
-+nios2-*-elf*)
|
|
|
-+ tm_file="elfos.h ${tm_file}"
|
|
|
-+ ;;
|
|
|
-+nios2-*-uclibc*) # Altera Nios2 running uClinux with uClibc
|
|
|
-+ tm_file="elfos.h ${tm_file} nios2/nios2-uclibc.h"
|
|
|
-+ tmake_file=nios2/t-nios2-uclibc
|
|
|
-+ ;;
|
|
|
- # m68hc11 and m68hc12 share the same machine description.
|
|
|
- m68hc11-*-*|m6811-*-*)
|
|
|
- tm_file="dbxelf.h elfos.h m68hc11/m68hc11.h"
|
|
|
-diff --git a/gcc/config/nios2/big.h b/gcc/config/nios2/big.h
|
|
|
-new file mode 100644
|
|
|
-index 0000000..b7b1731
|
|
|
---- /dev/null
|
|
|
-+++ b/gcc/config/nios2/big.h
|
|
|
-@@ -0,0 +1,23 @@
|
|
|
-+/*
|
|
|
-+ big.h - Additional definitions for nios2 targets that default to big-endian
|
|
|
-+
|
|
|
-+ Copyright (C) 2006 Altera
|
|
|
-+
|
|
|
-+This file is part of GNU CC.
|
|
|
-+
|
|
|
-+GNU CC is free software; you can redistribute it and/or modify
|
|
|
-+it under the terms of the GNU General Public License as published by
|
|
|
-+the Free Software Foundation; either version 2, or (at your option)
|
|
|
-+any later version.
|
|
|
-+
|
|
|
-+GNU CC is distributed in the hope that it will be useful,
|
|
|
-+but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
-+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
-+GNU General Public License for more details.
|
|
|
-+
|
|
|
-+You should have received a copy of the GNU General Public License
|
|
|
-+along with GNU CC; see the file COPYING. If not, write to
|
|
|
-+the Free Software Foundation, 59 Temple Place - Suite 330,
|
|
|
-+Boston, MA 02111-1307, USA. */
|
|
|
-+
|
|
|
-+#define TARGET_ENDIAN_DEFAULT BIG_ENDIAN_FLAG
|
|
|
-diff --git a/gcc/config/nios2/crti.asm b/gcc/config/nios2/crti.asm
|
|
|
-new file mode 100644
|
|
|
-index 0000000..1fcfeb2
|
|
|
---- /dev/null
|
|
|
-+++ b/gcc/config/nios2/crti.asm
|
|
|
-@@ -0,0 +1,88 @@
|
|
|
-+/*
|
|
|
-+ Copyright (C) 2003
|
|
|
-+ by Jonah Graham (jgraham@altera.com)
|
|
|
-+
|
|
|
-+This file is free software; you can redistribute it and/or modify it
|
|
|
-+under the terms of the GNU General Public License as published by the
|
|
|
-+Free Software Foundation; either version 2, or (at your option) any
|
|
|
-+later version.
|
|
|
-+
|
|
|
-+In addition to the permissions in the GNU General Public License, the
|
|
|
-+Free Software Foundation gives you unlimited permission to link the
|
|
|
-+compiled version of this file with other programs, and to distribute
|
|
|
-+those programs without any restriction coming from the use of this
|
|
|
-+file. (The General Public License restrictions do apply in other
|
|
|
-+respects; for example, they cover modification of the file, and
|
|
|
-+distribution when not linked into another program.)
|
|
|
-+
|
|
|
-+This file is distributed in the hope that it will be useful, but
|
|
|
-+WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
-+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
-+General Public License for more details.
|
|
|
-+
|
|
|
-+You should have received a copy of the GNU General Public License
|
|
|
-+along with this program; see the file COPYING. If not, write to
|
|
|
-+the Free Software Foundation, 59 Temple Place - Suite 330,
|
|
|
-+Boston, MA 02111-1307, USA.
|
|
|
-+
|
|
|
-+ As a special exception, if you link this library with files
|
|
|
-+ compiled with GCC to produce an executable, this does not cause
|
|
|
-+ the resulting executable to be covered by the GNU General Public License.
|
|
|
-+ This exception does not however invalidate any other reasons why
|
|
|
-+ the executable file might be covered by the GNU General Public License.
|
|
|
-+
|
|
|
-+
|
|
|
-+This file just make a stack frame for the contents of the .fini and
|
|
|
-+.init sections. Users may put any desired instructions in those
|
|
|
-+sections.
|
|
|
-+
|
|
|
-+
|
|
|
-+While technically any code can be put in the init and fini sections
|
|
|
-+most stuff will not work other than stuff which obeys the call frame
|
|
|
-+and ABI. All the call-preserved registers are saved, the call clobbered
|
|
|
-+registers should have been saved by the code calling init and fini.
|
|
|
-+
|
|
|
-+See crtstuff.c for an example of code that inserts itself in the
|
|
|
-+init and fini sections.
|
|
|
-+
|
|
|
-+See crt0.s for the code that calls init and fini.
|
|
|
-+*/
|
|
|
-+
|
|
|
-+ .file "crti.asm"
|
|
|
-+
|
|
|
-+ .section ".init"
|
|
|
-+ .align 2
|
|
|
-+ .global _init
|
|
|
-+_init:
|
|
|
-+ addi sp, sp, -48
|
|
|
-+ stw ra, 44(sp)
|
|
|
-+ stw r23, 40(sp)
|
|
|
-+ stw r22, 36(sp)
|
|
|
-+ stw r21, 32(sp)
|
|
|
-+ stw r20, 28(sp)
|
|
|
-+ stw r19, 24(sp)
|
|
|
-+ stw r18, 20(sp)
|
|
|
-+ stw r17, 16(sp)
|
|
|
-+ stw r16, 12(sp)
|
|
|
-+ stw fp, 8(sp)
|
|
|
-+ mov fp, sp
|
|
|
-+
|
|
|
-+
|
|
|
-+ .section ".fini"
|
|
|
-+ .align 2
|
|
|
-+ .global _fini
|
|
|
-+_fini:
|
|
|
-+ addi sp, sp, -48
|
|
|
-+ stw ra, 44(sp)
|
|
|
-+ stw r23, 40(sp)
|
|
|
-+ stw r22, 36(sp)
|
|
|
-+ stw r21, 32(sp)
|
|
|
-+ stw r20, 28(sp)
|
|
|
-+ stw r19, 24(sp)
|
|
|
-+ stw r18, 20(sp)
|
|
|
-+ stw r17, 16(sp)
|
|
|
-+ stw r16, 12(sp)
|
|
|
-+ stw fp, 8(sp)
|
|
|
-+ mov fp, sp
|
|
|
-+
|
|
|
-+
|
|
|
-diff --git a/gcc/config/nios2/crtn.asm b/gcc/config/nios2/crtn.asm
|
|
|
-new file mode 100644
|
|
|
-index 0000000..e337480
|
|
|
---- /dev/null
|
|
|
-+++ b/gcc/config/nios2/crtn.asm
|
|
|
-@@ -0,0 +1,70 @@
|
|
|
-+/*
|
|
|
-+ Copyright (C) 2003
|
|
|
-+ by Jonah Graham (jgraham@altera.com)
|
|
|
-+
|
|
|
-+This file is free software; you can redistribute it and/or modify it
|
|
|
-+under the terms of the GNU General Public License as published by the
|
|
|
-+Free Software Foundation; either version 2, or (at your option) any
|
|
|
-+later version.
|
|
|
-+
|
|
|
-+In addition to the permissions in the GNU General Public License, the
|
|
|
-+Free Software Foundation gives you unlimited permission to link the
|
|
|
-+compiled version of this file with other programs, and to distribute
|
|
|
-+those programs without any restriction coming from the use of this
|
|
|
-+file. (The General Public License restrictions do apply in other
|
|
|
-+respects; for example, they cover modification of the file, and
|
|
|
-+distribution when not linked into another program.)
|
|
|
-+
|
|
|
-+This file is distributed in the hope that it will be useful, but
|
|
|
-+WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
-+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
-+General Public License for more details.
|
|
|
-+
|
|
|
-+You should have received a copy of the GNU General Public License
|
|
|
-+along with this program; see the file COPYING. If not, write to
|
|
|
-+the Free Software Foundation, 59 Temple Place - Suite 330,
|
|
|
-+Boston, MA 02111-1307, USA.
|
|
|
-+
|
|
|
-+ As a special exception, if you link this library with files
|
|
|
-+ compiled with GCC to produce an executable, this does not cause
|
|
|
-+ the resulting executable to be covered by the GNU General Public License.
|
|
|
-+ This exception does not however invalidate any other reasons why
|
|
|
-+ the executable file might be covered by the GNU General Public License.
|
|
|
-+
|
|
|
-+
|
|
|
-+This file just makes sure that the .fini and .init sections do in
|
|
|
-+fact return. Users may put any desired instructions in those sections.
|
|
|
-+This file is the last thing linked into any executable.
|
|
|
-+*/
|
|
|
-+ .file "crtn.asm"
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+ .section ".init"
|
|
|
-+ ldw ra, 44(sp)
|
|
|
-+ ldw r23, 40(sp)
|
|
|
-+ ldw r22, 36(sp)
|
|
|
-+ ldw r21, 32(sp)
|
|
|
-+ ldw r20, 28(sp)
|
|
|
-+ ldw r19, 24(sp)
|
|
|
-+ ldw r18, 20(sp)
|
|
|
-+ ldw r17, 16(sp)
|
|
|
-+ ldw r16, 12(sp)
|
|
|
-+ ldw fp, 8(sp)
|
|
|
-+ addi sp, sp, -48
|
|
|
-+ ret
|
|
|
-+
|
|
|
-+ .section ".fini"
|
|
|
-+ ldw ra, 44(sp)
|
|
|
-+ ldw r23, 40(sp)
|
|
|
-+ ldw r22, 36(sp)
|
|
|
-+ ldw r21, 32(sp)
|
|
|
-+ ldw r20, 28(sp)
|
|
|
-+ ldw r19, 24(sp)
|
|
|
-+ ldw r18, 20(sp)
|
|
|
-+ ldw r17, 16(sp)
|
|
|
-+ ldw r16, 12(sp)
|
|
|
-+ ldw fp, 8(sp)
|
|
|
-+ addi sp, sp, -48
|
|
|
-+ ret
|
|
|
-+
|
|
|
-diff --git a/gcc/config/nios2/lib2-divmod-hi.c b/gcc/config/nios2/lib2-divmod-hi.c
|
|
|
-new file mode 100644
|
|
|
-index 0000000..10bd6e4
|
|
|
---- /dev/null
|
|
|
-+++ b/gcc/config/nios2/lib2-divmod-hi.c
|
|
|
-@@ -0,0 +1,123 @@
|
|
|
-+
|
|
|
-+/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is
|
|
|
-+ supposedly valid even though this is a "target" file. */
|
|
|
-+#include "auto-host.h"
|
|
|
-+
|
|
|
-+
|
|
|
-+#include "tconfig.h"
|
|
|
-+#include "tsystem.h"
|
|
|
-+#include "coretypes.h"
|
|
|
-+#include "tm.h"
|
|
|
-+
|
|
|
-+
|
|
|
-+/* Don't use `fancy_abort' here even if config.h says to use it. */
|
|
|
-+#ifdef abort
|
|
|
-+#undef abort
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+
|
|
|
-+#ifdef HAVE_GAS_HIDDEN
|
|
|
-+#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden")))
|
|
|
-+#else
|
|
|
-+#define ATTRIBUTE_HIDDEN
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+#include "libgcc2.h"
|
|
|
-+
|
|
|
-+extern HItype __modhi3 (HItype, HItype);
|
|
|
-+extern HItype __divhi3 (HItype, HItype);
|
|
|
-+extern HItype __umodhi3 (HItype, HItype);
|
|
|
-+extern HItype __udivhi3 (HItype, HItype);
|
|
|
-+
|
|
|
-+static UHItype udivmodhi4(UHItype, UHItype, word_type);
|
|
|
-+
|
|
|
-+static UHItype
|
|
|
-+udivmodhi4(UHItype num, UHItype den, word_type modwanted)
|
|
|
-+{
|
|
|
-+ UHItype bit = 1;
|
|
|
-+ UHItype res = 0;
|
|
|
-+
|
|
|
-+ while (den < num && bit && !(den & (1L<<15)))
|
|
|
-+ {
|
|
|
-+ den <<=1;
|
|
|
-+ bit <<=1;
|
|
|
-+ }
|
|
|
-+ while (bit)
|
|
|
-+ {
|
|
|
-+ if (num >= den)
|
|
|
-+ {
|
|
|
-+ num -= den;
|
|
|
-+ res |= bit;
|
|
|
-+ }
|
|
|
-+ bit >>=1;
|
|
|
-+ den >>=1;
|
|
|
-+ }
|
|
|
-+ if (modwanted) return num;
|
|
|
-+ return res;
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+HItype
|
|
|
-+__divhi3 (HItype a, HItype b)
|
|
|
-+{
|
|
|
-+ word_type neg = 0;
|
|
|
-+ HItype res;
|
|
|
-+
|
|
|
-+ if (a < 0)
|
|
|
-+ {
|
|
|
-+ a = -a;
|
|
|
-+ neg = !neg;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (b < 0)
|
|
|
-+ {
|
|
|
-+ b = -b;
|
|
|
-+ neg = !neg;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ res = udivmodhi4 (a, b, 0);
|
|
|
-+
|
|
|
-+ if (neg)
|
|
|
-+ res = -res;
|
|
|
-+
|
|
|
-+ return res;
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+HItype
|
|
|
-+__modhi3 (HItype a, HItype b)
|
|
|
-+{
|
|
|
-+ word_type neg = 0;
|
|
|
-+ HItype res;
|
|
|
-+
|
|
|
-+ if (a < 0)
|
|
|
-+ {
|
|
|
-+ a = -a;
|
|
|
-+ neg = 1;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (b < 0)
|
|
|
-+ b = -b;
|
|
|
-+
|
|
|
-+ res = udivmodhi4 (a, b, 1);
|
|
|
-+
|
|
|
-+ if (neg)
|
|
|
-+ res = -res;
|
|
|
-+
|
|
|
-+ return res;
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+HItype
|
|
|
-+__udivhi3 (HItype a, HItype b)
|
|
|
-+{
|
|
|
-+ return udivmodhi4 (a, b, 0);
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+HItype
|
|
|
-+__umodhi3 (HItype a, HItype b)
|
|
|
-+{
|
|
|
-+ return udivmodhi4 (a, b, 1);
|
|
|
-+}
|
|
|
-+
|
|
|
-diff --git a/gcc/config/nios2/lib2-divmod.c b/gcc/config/nios2/lib2-divmod.c
|
|
|
-new file mode 100644
|
|
|
-index 0000000..00e730d
|
|
|
---- /dev/null
|
|
|
-+++ b/gcc/config/nios2/lib2-divmod.c
|
|
|
-@@ -0,0 +1,126 @@
|
|
|
-+
|
|
|
-+/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is
|
|
|
-+ supposedly valid even though this is a "target" file. */
|
|
|
-+#include "auto-host.h"
|
|
|
-+
|
|
|
-+
|
|
|
-+#include "tconfig.h"
|
|
|
-+#include "tsystem.h"
|
|
|
-+#include "coretypes.h"
|
|
|
-+#include "tm.h"
|
|
|
-+
|
|
|
-+
|
|
|
-+/* Don't use `fancy_abort' here even if config.h says to use it. */
|
|
|
-+#ifdef abort
|
|
|
-+#undef abort
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+
|
|
|
-+#ifdef HAVE_GAS_HIDDEN
|
|
|
-+#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden")))
|
|
|
-+#else
|
|
|
-+#define ATTRIBUTE_HIDDEN
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+#include "libgcc2.h"
|
|
|
-+
|
|
|
-+extern SItype __modsi3 (SItype, SItype);
|
|
|
-+extern SItype __divsi3 (SItype, SItype);
|
|
|
-+extern SItype __umodsi3 (SItype, SItype);
|
|
|
-+extern SItype __udivsi3 (SItype, SItype);
|
|
|
-+
|
|
|
-+static USItype udivmodsi4(USItype, USItype, word_type);
|
|
|
-+
|
|
|
-+/* 16-bit SI divide and modulo as used in NIOS */
|
|
|
-+
|
|
|
-+
|
|
|
-+static USItype
|
|
|
-+udivmodsi4(USItype num, USItype den, word_type modwanted)
|
|
|
-+{
|
|
|
-+ USItype bit = 1;
|
|
|
-+ USItype res = 0;
|
|
|
-+
|
|
|
-+ while (den < num && bit && !(den & (1L<<31)))
|
|
|
-+ {
|
|
|
-+ den <<=1;
|
|
|
-+ bit <<=1;
|
|
|
-+ }
|
|
|
-+ while (bit)
|
|
|
-+ {
|
|
|
-+ if (num >= den)
|
|
|
-+ {
|
|
|
-+ num -= den;
|
|
|
-+ res |= bit;
|
|
|
-+ }
|
|
|
-+ bit >>=1;
|
|
|
-+ den >>=1;
|
|
|
-+ }
|
|
|
-+ if (modwanted) return num;
|
|
|
-+ return res;
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+SItype
|
|
|
-+__divsi3 (SItype a, SItype b)
|
|
|
-+{
|
|
|
-+ word_type neg = 0;
|
|
|
-+ SItype res;
|
|
|
-+
|
|
|
-+ if (a < 0)
|
|
|
-+ {
|
|
|
-+ a = -a;
|
|
|
-+ neg = !neg;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (b < 0)
|
|
|
-+ {
|
|
|
-+ b = -b;
|
|
|
-+ neg = !neg;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ res = udivmodsi4 (a, b, 0);
|
|
|
-+
|
|
|
-+ if (neg)
|
|
|
-+ res = -res;
|
|
|
-+
|
|
|
-+ return res;
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+SItype
|
|
|
-+__modsi3 (SItype a, SItype b)
|
|
|
-+{
|
|
|
-+ word_type neg = 0;
|
|
|
-+ SItype res;
|
|
|
-+
|
|
|
-+ if (a < 0)
|
|
|
-+ {
|
|
|
-+ a = -a;
|
|
|
-+ neg = 1;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (b < 0)
|
|
|
-+ b = -b;
|
|
|
-+
|
|
|
-+ res = udivmodsi4 (a, b, 1);
|
|
|
-+
|
|
|
-+ if (neg)
|
|
|
-+ res = -res;
|
|
|
-+
|
|
|
-+ return res;
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+SItype
|
|
|
-+__udivsi3 (SItype a, SItype b)
|
|
|
-+{
|
|
|
-+ return udivmodsi4 (a, b, 0);
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+SItype
|
|
|
-+__umodsi3 (SItype a, SItype b)
|
|
|
-+{
|
|
|
-+ return udivmodsi4 (a, b, 1);
|
|
|
-+}
|
|
|
-+
|
|
|
-diff --git a/gcc/config/nios2/lib2-divtable.c b/gcc/config/nios2/lib2-divtable.c
|
|
|
-new file mode 100644
|
|
|
-index 0000000..48a7bd7
|
|
|
---- /dev/null
|
|
|
-+++ b/gcc/config/nios2/lib2-divtable.c
|
|
|
-@@ -0,0 +1,46 @@
|
|
|
-+
|
|
|
-+/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is
|
|
|
-+ supposedly valid even though this is a "target" file. */
|
|
|
-+#include "auto-host.h"
|
|
|
-+
|
|
|
-+
|
|
|
-+#include "tconfig.h"
|
|
|
-+#include "tsystem.h"
|
|
|
-+#include "coretypes.h"
|
|
|
-+#include "tm.h"
|
|
|
-+
|
|
|
-+
|
|
|
-+/* Don't use `fancy_abort' here even if config.h says to use it. */
|
|
|
-+#ifdef abort
|
|
|
-+#undef abort
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+
|
|
|
-+#ifdef HAVE_GAS_HIDDEN
|
|
|
-+#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden")))
|
|
|
-+#else
|
|
|
-+#define ATTRIBUTE_HIDDEN
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+#include "libgcc2.h"
|
|
|
-+
|
|
|
-+UQItype __divsi3_table[] =
|
|
|
-+{
|
|
|
-+ 0, 0/1, 0/2, 0/3, 0/4, 0/5, 0/6, 0/7, 0/8, 0/9, 0/10, 0/11, 0/12, 0/13, 0/14, 0/15,
|
|
|
-+ 0, 1/1, 1/2, 1/3, 1/4, 1/5, 1/6, 1/7, 1/8, 1/9, 1/10, 1/11, 1/12, 1/13, 1/14, 1/15,
|
|
|
-+ 0, 2/1, 2/2, 2/3, 2/4, 2/5, 2/6, 2/7, 2/8, 2/9, 2/10, 2/11, 2/12, 2/13, 2/14, 2/15,
|
|
|
-+ 0, 3/1, 3/2, 3/3, 3/4, 3/5, 3/6, 3/7, 3/8, 3/9, 3/10, 3/11, 3/12, 3/13, 3/14, 3/15,
|
|
|
-+ 0, 4/1, 4/2, 4/3, 4/4, 4/5, 4/6, 4/7, 4/8, 4/9, 4/10, 4/11, 4/12, 4/13, 4/14, 4/15,
|
|
|
-+ 0, 5/1, 5/2, 5/3, 5/4, 5/5, 5/6, 5/7, 5/8, 5/9, 5/10, 5/11, 5/12, 5/13, 5/14, 5/15,
|
|
|
-+ 0, 6/1, 6/2, 6/3, 6/4, 6/5, 6/6, 6/7, 6/8, 6/9, 6/10, 6/11, 6/12, 6/13, 6/14, 6/15,
|
|
|
-+ 0, 7/1, 7/2, 7/3, 7/4, 7/5, 7/6, 7/7, 7/8, 7/9, 7/10, 7/11, 7/12, 7/13, 7/14, 7/15,
|
|
|
-+ 0, 8/1, 8/2, 8/3, 8/4, 8/5, 8/6, 8/7, 8/8, 8/9, 8/10, 8/11, 8/12, 8/13, 8/14, 8/15,
|
|
|
-+ 0, 9/1, 9/2, 9/3, 9/4, 9/5, 9/6, 9/7, 9/8, 9/9, 9/10, 9/11, 9/12, 9/13, 9/14, 9/15,
|
|
|
-+ 0, 10/1, 10/2, 10/3, 10/4, 10/5, 10/6, 10/7, 10/8, 10/9, 10/10, 10/11, 10/12, 10/13, 10/14, 10/15,
|
|
|
-+ 0, 11/1, 11/2, 11/3, 11/4, 11/5, 11/6, 11/7, 11/8, 11/9, 11/10, 11/11, 11/12, 11/13, 11/14, 11/15,
|
|
|
-+ 0, 12/1, 12/2, 12/3, 12/4, 12/5, 12/6, 12/7, 12/8, 12/9, 12/10, 12/11, 12/12, 12/13, 12/14, 12/15,
|
|
|
-+ 0, 13/1, 13/2, 13/3, 13/4, 13/5, 13/6, 13/7, 13/8, 13/9, 13/10, 13/11, 13/12, 13/13, 13/14, 13/15,
|
|
|
-+ 0, 14/1, 14/2, 14/3, 14/4, 14/5, 14/6, 14/7, 14/8, 14/9, 14/10, 14/11, 14/12, 14/13, 14/14, 14/15,
|
|
|
-+ 0, 15/1, 15/2, 15/3, 15/4, 15/5, 15/6, 15/7, 15/8, 15/9, 15/10, 15/11, 15/12, 15/13, 15/14, 15/15,
|
|
|
-+};
|
|
|
-+
|
|
|
-diff --git a/gcc/config/nios2/lib2-mul.c b/gcc/config/nios2/lib2-mul.c
|
|
|
-new file mode 100644
|
|
|
-index 0000000..8511b33
|
|
|
---- /dev/null
|
|
|
-+++ b/gcc/config/nios2/lib2-mul.c
|
|
|
-@@ -0,0 +1,103 @@
|
|
|
-+/* while we are debugging (ie compile outside of gcc build)
|
|
|
-+ disable gcc specific headers */
|
|
|
-+#ifndef DEBUG_MULSI3
|
|
|
-+
|
|
|
-+
|
|
|
-+/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is
|
|
|
-+ supposedly valid even though this is a "target" file. */
|
|
|
-+#include "auto-host.h"
|
|
|
-+
|
|
|
-+
|
|
|
-+#include "tconfig.h"
|
|
|
-+#include "tsystem.h"
|
|
|
-+#include "coretypes.h"
|
|
|
-+#include "tm.h"
|
|
|
-+
|
|
|
-+
|
|
|
-+/* Don't use `fancy_abort' here even if config.h says to use it. */
|
|
|
-+#ifdef abort
|
|
|
-+#undef abort
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+
|
|
|
-+#ifdef HAVE_GAS_HIDDEN
|
|
|
-+#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden")))
|
|
|
-+#else
|
|
|
-+#define ATTRIBUTE_HIDDEN
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+#include "libgcc2.h"
|
|
|
-+
|
|
|
-+#else
|
|
|
-+#define SItype int
|
|
|
-+#define USItype unsigned int
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+
|
|
|
-+extern SItype __mulsi3 (SItype, SItype);
|
|
|
-+
|
|
|
-+SItype
|
|
|
-+__mulsi3 (SItype a, SItype b)
|
|
|
-+{
|
|
|
-+ SItype res = 0;
|
|
|
-+ USItype cnt = a;
|
|
|
-+
|
|
|
-+ while (cnt)
|
|
|
-+ {
|
|
|
-+ if (cnt & 1)
|
|
|
-+ {
|
|
|
-+ res += b;
|
|
|
-+ }
|
|
|
-+ b <<= 1;
|
|
|
-+ cnt >>= 1;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return res;
|
|
|
-+}
|
|
|
-+/*
|
|
|
-+TODO: Choose best alternative implementation.
|
|
|
-+
|
|
|
-+SItype
|
|
|
-+__divsi3 (SItype a, SItype b)
|
|
|
-+{
|
|
|
-+ SItype res = 0;
|
|
|
-+ USItype cnt = 0;
|
|
|
-+
|
|
|
-+ while (cnt < 32)
|
|
|
-+ {
|
|
|
-+ if (a & (1L << cnt))
|
|
|
-+ {
|
|
|
-+ res += b;
|
|
|
-+ }
|
|
|
-+ b <<= 1;
|
|
|
-+ cnt++;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return res;
|
|
|
-+}
|
|
|
-+*/
|
|
|
-+
|
|
|
-+
|
|
|
-+#ifdef DEBUG_MULSI3
|
|
|
-+
|
|
|
-+int
|
|
|
-+main ()
|
|
|
-+{
|
|
|
-+ int i, j;
|
|
|
-+ int error = 0;
|
|
|
-+
|
|
|
-+ for (i = -1000; i < 1000; i++)
|
|
|
-+ for (j = -1000; j < 1000; j++)
|
|
|
-+ {
|
|
|
-+ int expect = i * j;
|
|
|
-+ int actual = A__divsi3 (i, j);
|
|
|
-+ if (expect != actual)
|
|
|
-+ {
|
|
|
-+ printf ("error: %d * %d = %d not %d\n", i, j, expect, actual);
|
|
|
-+ error = 1;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return error;
|
|
|
-+}
|
|
|
-+#endif
|
|
|
-diff --git a/gcc/config/nios2/nios2-dp-bit.c b/gcc/config/nios2/nios2-dp-bit.c
|
|
|
-new file mode 100644
|
|
|
-index 0000000..4d63748
|
|
|
---- /dev/null
|
|
|
-+++ b/gcc/config/nios2/nios2-dp-bit.c
|
|
|
-@@ -0,0 +1,1655 @@
|
|
|
-+
|
|
|
-+#ifndef __nios2_big_endian__
|
|
|
-+#define FLOAT_BIT_ORDER_MISMATCH
|
|
|
-+#endif
|
|
|
-+/* This is a software floating point library which can be used
|
|
|
-+ for targets without hardware floating point.
|
|
|
-+ Copyright (C) 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004
|
|
|
-+ Free Software Foundation, Inc.
|
|
|
-+
|
|
|
-+This file is free software; you can redistribute it and/or modify it
|
|
|
-+under the terms of the GNU General Public License as published by the
|
|
|
-+Free Software Foundation; either version 2, or (at your option) any
|
|
|
-+later version.
|
|
|
-+
|
|
|
-+In addition to the permissions in the GNU General Public License, the
|
|
|
-+Free Software Foundation gives you unlimited permission to link the
|
|
|
-+compiled version of this file with other programs, and to distribute
|
|
|
-+those programs without any restriction coming from the use of this
|
|
|
-+file. (The General Public License restrictions do apply in other
|
|
|
-+respects; for example, they cover modification of the file, and
|
|
|
-+distribution when not linked into another program.)
|
|
|
-+
|
|
|
-+This file is distributed in the hope that it will be useful, but
|
|
|
-+WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
-+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
-+General Public License for more details.
|
|
|
-+
|
|
|
-+You should have received a copy of the GNU General Public License
|
|
|
-+along with this program; see the file COPYING. If not, write to
|
|
|
-+the Free Software Foundation, 59 Temple Place - Suite 330,
|
|
|
-+Boston, MA 02111-1307, USA. */
|
|
|
-+
|
|
|
-+/* As a special exception, if you link this library with other files,
|
|
|
-+ some of which are compiled with GCC, to produce an executable,
|
|
|
-+ this library does not by itself cause the resulting executable
|
|
|
-+ to be covered by the GNU General Public License.
|
|
|
-+ This exception does not however invalidate any other reasons why
|
|
|
-+ the executable file might be covered by the GNU General Public License. */
|
|
|
-+
|
|
|
-+/* This implements IEEE 754 format arithmetic, but does not provide a
|
|
|
-+ mechanism for setting the rounding mode, or for generating or handling
|
|
|
-+ exceptions.
|
|
|
-+
|
|
|
-+ The original code by Steve Chamberlain, hacked by Mark Eichin and Jim
|
|
|
-+ Wilson, all of Cygnus Support. */
|
|
|
-+
|
|
|
-+/* The intended way to use this file is to make two copies, add `#define FLOAT'
|
|
|
-+ to one copy, then compile both copies and add them to libgcc.a. */
|
|
|
-+
|
|
|
-+#include "tconfig.h"
|
|
|
-+#include "coretypes.h"
|
|
|
-+#include "tm.h"
|
|
|
-+#include "config/fp-bit.h"
|
|
|
-+
|
|
|
-+/* The following macros can be defined to change the behavior of this file:
|
|
|
-+ FLOAT: Implement a `float', aka SFmode, fp library. If this is not
|
|
|
-+ defined, then this file implements a `double', aka DFmode, fp library.
|
|
|
-+ FLOAT_ONLY: Used with FLOAT, to implement a `float' only library, i.e.
|
|
|
-+ don't include float->double conversion which requires the double library.
|
|
|
-+ This is useful only for machines which can't support doubles, e.g. some
|
|
|
-+ 8-bit processors.
|
|
|
-+ CMPtype: Specify the type that floating point compares should return.
|
|
|
-+ This defaults to SItype, aka int.
|
|
|
-+ US_SOFTWARE_GOFAST: This makes all entry points use the same names as the
|
|
|
-+ US Software goFast library.
|
|
|
-+ _DEBUG_BITFLOAT: This makes debugging the code a little easier, by adding
|
|
|
-+ two integers to the FLO_union_type.
|
|
|
-+ NO_DENORMALS: Disable handling of denormals.
|
|
|
-+ NO_NANS: Disable nan and infinity handling
|
|
|
-+ SMALL_MACHINE: Useful when operations on QIs and HIs are faster
|
|
|
-+ than on an SI */
|
|
|
-+
|
|
|
-+/* We don't currently support extended floats (long doubles) on machines
|
|
|
-+ without hardware to deal with them.
|
|
|
-+
|
|
|
-+ These stubs are just to keep the linker from complaining about unresolved
|
|
|
-+ references which can be pulled in from libio & libstdc++, even if the
|
|
|
-+ user isn't using long doubles. However, they may generate an unresolved
|
|
|
-+ external to abort if abort is not used by the function, and the stubs
|
|
|
-+ are referenced from within libc, since libgcc goes before and after the
|
|
|
-+ system library. */
|
|
|
-+
|
|
|
-+#ifdef DECLARE_LIBRARY_RENAMES
|
|
|
-+ DECLARE_LIBRARY_RENAMES
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+#ifdef EXTENDED_FLOAT_STUBS
|
|
|
-+extern void abort (void);
|
|
|
-+void __extendsfxf2 (void) { abort(); }
|
|
|
-+void __extenddfxf2 (void) { abort(); }
|
|
|
-+void __truncxfdf2 (void) { abort(); }
|
|
|
-+void __truncxfsf2 (void) { abort(); }
|
|
|
-+void __fixxfsi (void) { abort(); }
|
|
|
-+void __floatsixf (void) { abort(); }
|
|
|
-+void __addxf3 (void) { abort(); }
|
|
|
-+void __subxf3 (void) { abort(); }
|
|
|
-+void __mulxf3 (void) { abort(); }
|
|
|
-+void __divxf3 (void) { abort(); }
|
|
|
-+void __negxf2 (void) { abort(); }
|
|
|
-+void __eqxf2 (void) { abort(); }
|
|
|
-+void __nexf2 (void) { abort(); }
|
|
|
-+void __gtxf2 (void) { abort(); }
|
|
|
-+void __gexf2 (void) { abort(); }
|
|
|
-+void __lexf2 (void) { abort(); }
|
|
|
-+void __ltxf2 (void) { abort(); }
|
|
|
-+
|
|
|
-+void __extendsftf2 (void) { abort(); }
|
|
|
-+void __extenddftf2 (void) { abort(); }
|
|
|
-+void __trunctfdf2 (void) { abort(); }
|
|
|
-+void __trunctfsf2 (void) { abort(); }
|
|
|
-+void __fixtfsi (void) { abort(); }
|
|
|
-+void __floatsitf (void) { abort(); }
|
|
|
-+void __addtf3 (void) { abort(); }
|
|
|
-+void __subtf3 (void) { abort(); }
|
|
|
-+void __multf3 (void) { abort(); }
|
|
|
-+void __divtf3 (void) { abort(); }
|
|
|
-+void __negtf2 (void) { abort(); }
|
|
|
-+void __eqtf2 (void) { abort(); }
|
|
|
-+void __netf2 (void) { abort(); }
|
|
|
-+void __gttf2 (void) { abort(); }
|
|
|
-+void __getf2 (void) { abort(); }
|
|
|
-+void __letf2 (void) { abort(); }
|
|
|
-+void __lttf2 (void) { abort(); }
|
|
|
-+#else /* !EXTENDED_FLOAT_STUBS, rest of file */
|
|
|
-+
|
|
|
-+/* IEEE "special" number predicates */
|
|
|
-+
|
|
|
-+#ifdef NO_NANS
|
|
|
-+
|
|
|
-+#define nan() 0
|
|
|
-+#define isnan(x) 0
|
|
|
-+#define isinf(x) 0
|
|
|
-+#else
|
|
|
-+
|
|
|
-+#if defined L_thenan_sf
|
|
|
-+const fp_number_type __thenan_sf = { CLASS_SNAN, 0, 0, {(fractype) 0} };
|
|
|
-+#elif defined L_thenan_df
|
|
|
-+const fp_number_type __thenan_df = { CLASS_SNAN, 0, 0, {(fractype) 0} };
|
|
|
-+#elif defined L_thenan_tf
|
|
|
-+const fp_number_type __thenan_tf = { CLASS_SNAN, 0, 0, {(fractype) 0} };
|
|
|
-+#elif defined TFLOAT
|
|
|
-+extern const fp_number_type __thenan_tf;
|
|
|
-+#elif defined FLOAT
|
|
|
-+extern const fp_number_type __thenan_sf;
|
|
|
-+#else
|
|
|
-+extern const fp_number_type __thenan_df;
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+INLINE
|
|
|
-+static fp_number_type *
|
|
|
-+nan (void)
|
|
|
-+{
|
|
|
-+ /* Discard the const qualifier... */
|
|
|
-+#ifdef TFLOAT
|
|
|
-+ return (fp_number_type *) (& __thenan_tf);
|
|
|
-+#elif defined FLOAT
|
|
|
-+ return (fp_number_type *) (& __thenan_sf);
|
|
|
-+#else
|
|
|
-+ return (fp_number_type *) (& __thenan_df);
|
|
|
-+#endif
|
|
|
-+}
|
|
|
-+
|
|
|
-+INLINE
|
|
|
-+static int
|
|
|
-+isnan ( fp_number_type * x)
|
|
|
-+{
|
|
|
-+ return x->class == CLASS_SNAN || x->class == CLASS_QNAN;
|
|
|
-+}
|
|
|
-+
|
|
|
-+INLINE
|
|
|
-+static int
|
|
|
-+isinf ( fp_number_type * x)
|
|
|
-+{
|
|
|
-+ return x->class == CLASS_INFINITY;
|
|
|
-+}
|
|
|
-+
|
|
|
-+#endif /* NO_NANS */
|
|
|
-+
|
|
|
-+INLINE
|
|
|
-+static int
|
|
|
-+iszero ( fp_number_type * x)
|
|
|
-+{
|
|
|
-+ return x->class == CLASS_ZERO;
|
|
|
-+}
|
|
|
-+
|
|
|
-+INLINE
|
|
|
-+static void
|
|
|
-+flip_sign ( fp_number_type * x)
|
|
|
-+{
|
|
|
-+ x->sign = !x->sign;
|
|
|
-+}
|
|
|
-+
|
|
|
-+extern FLO_type pack_d ( fp_number_type * );
|
|
|
-+
|
|
|
-+#if defined(L_pack_df) || defined(L_pack_sf) || defined(L_pack_tf)
|
|
|
-+FLO_type
|
|
|
-+pack_d ( fp_number_type * src)
|
|
|
-+{
|
|
|
-+ FLO_union_type dst;
|
|
|
-+ fractype fraction = src->fraction.ll; /* wasn't unsigned before? */
|
|
|
-+ int sign = src->sign;
|
|
|
-+ int exp = 0;
|
|
|
-+
|
|
|
-+ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && (isnan (src) || isinf (src)))
|
|
|
-+ {
|
|
|
-+ /* We can't represent these values accurately. By using the
|
|
|
-+ largest possible magnitude, we guarantee that the conversion
|
|
|
-+ of infinity is at least as big as any finite number. */
|
|
|
-+ exp = EXPMAX;
|
|
|
-+ fraction = ((fractype) 1 << FRACBITS) - 1;
|
|
|
-+ }
|
|
|
-+ else if (isnan (src))
|
|
|
-+ {
|
|
|
-+ exp = EXPMAX;
|
|
|
-+ if (src->class == CLASS_QNAN || 1)
|
|
|
-+ {
|
|
|
-+#ifdef QUIET_NAN_NEGATED
|
|
|
-+ fraction |= QUIET_NAN - 1;
|
|
|
-+#else
|
|
|
-+ fraction |= QUIET_NAN;
|
|
|
-+#endif
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ else if (isinf (src))
|
|
|
-+ {
|
|
|
-+ exp = EXPMAX;
|
|
|
-+ fraction = 0;
|
|
|
-+ }
|
|
|
-+ else if (iszero (src))
|
|
|
-+ {
|
|
|
-+ exp = 0;
|
|
|
-+ fraction = 0;
|
|
|
-+ }
|
|
|
-+ else if (fraction == 0)
|
|
|
-+ {
|
|
|
-+ exp = 0;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ if (src->normal_exp < NORMAL_EXPMIN)
|
|
|
-+ {
|
|
|
-+#ifdef NO_DENORMALS
|
|
|
-+ /* Go straight to a zero representation if denormals are not
|
|
|
-+ supported. The denormal handling would be harmless but
|
|
|
-+ isn't unnecessary. */
|
|
|
-+ exp = 0;
|
|
|
-+ fraction = 0;
|
|
|
-+#else /* NO_DENORMALS */
|
|
|
-+ /* This number's exponent is too low to fit into the bits
|
|
|
-+ available in the number, so we'll store 0 in the exponent and
|
|
|
-+ shift the fraction to the right to make up for it. */
|
|
|
-+
|
|
|
-+ int shift = NORMAL_EXPMIN - src->normal_exp;
|
|
|
-+
|
|
|
-+ exp = 0;
|
|
|
-+
|
|
|
-+ if (shift > FRAC_NBITS - NGARDS)
|
|
|
-+ {
|
|
|
-+ /* No point shifting, since it's more that 64 out. */
|
|
|
-+ fraction = 0;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ int lowbit = (fraction & (((fractype)1 << shift) - 1)) ? 1 : 0;
|
|
|
-+ fraction = (fraction >> shift) | lowbit;
|
|
|
-+ }
|
|
|
-+ if ((fraction & GARDMASK) == GARDMSB)
|
|
|
-+ {
|
|
|
-+ if ((fraction & (1 << NGARDS)))
|
|
|
-+ fraction += GARDROUND + 1;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ /* Add to the guards to round up. */
|
|
|
-+ fraction += GARDROUND;
|
|
|
-+ }
|
|
|
-+ /* Perhaps the rounding means we now need to change the
|
|
|
-+ exponent, because the fraction is no longer denormal. */
|
|
|
-+ if (fraction >= IMPLICIT_1)
|
|
|
-+ {
|
|
|
-+ exp += 1;
|
|
|
-+ }
|
|
|
-+ fraction >>= NGARDS;
|
|
|
-+#endif /* NO_DENORMALS */
|
|
|
-+ }
|
|
|
-+ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS)
|
|
|
-+ && src->normal_exp > EXPBIAS)
|
|
|
-+ {
|
|
|
-+ exp = EXPMAX;
|
|
|
-+ fraction = 0;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ exp = src->normal_exp + EXPBIAS;
|
|
|
-+ if (!ROUND_TOWARDS_ZERO)
|
|
|
-+ {
|
|
|
-+ /* IF the gard bits are the all zero, but the first, then we're
|
|
|
-+ half way between two numbers, choose the one which makes the
|
|
|
-+ lsb of the answer 0. */
|
|
|
-+ if ((fraction & GARDMASK) == GARDMSB)
|
|
|
-+ {
|
|
|
-+ if (fraction & (1 << NGARDS))
|
|
|
-+ fraction += GARDROUND + 1;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ /* Add a one to the guards to round up */
|
|
|
-+ fraction += GARDROUND;
|
|
|
-+ }
|
|
|
-+ if (fraction >= IMPLICIT_2)
|
|
|
-+ {
|
|
|
-+ fraction >>= 1;
|
|
|
-+ exp += 1;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ fraction >>= NGARDS;
|
|
|
-+
|
|
|
-+ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp > EXPMAX)
|
|
|
-+ {
|
|
|
-+ /* Saturate on overflow. */
|
|
|
-+ exp = EXPMAX;
|
|
|
-+ fraction = ((fractype) 1 << FRACBITS) - 1;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* We previously used bitfields to store the number, but this doesn't
|
|
|
-+ handle little/big endian systems conveniently, so use shifts and
|
|
|
-+ masks */
|
|
|
-+#ifdef FLOAT_BIT_ORDER_MISMATCH
|
|
|
-+ dst.bits.fraction = fraction;
|
|
|
-+ dst.bits.exp = exp;
|
|
|
-+ dst.bits.sign = sign;
|
|
|
-+#else
|
|
|
-+# if defined TFLOAT && defined HALFFRACBITS
|
|
|
-+ {
|
|
|
-+ halffractype high, low, unity;
|
|
|
-+ int lowsign, lowexp;
|
|
|
-+
|
|
|
-+ unity = (halffractype) 1 << HALFFRACBITS;
|
|
|
-+
|
|
|
-+ /* Set HIGH to the high double's significand, masking out the implicit 1.
|
|
|
-+ Set LOW to the low double's full significand. */
|
|
|
-+ high = (fraction >> (FRACBITS - HALFFRACBITS)) & (unity - 1);
|
|
|
-+ low = fraction & (unity * 2 - 1);
|
|
|
-+
|
|
|
-+ /* Get the initial sign and exponent of the low double. */
|
|
|
-+ lowexp = exp - HALFFRACBITS - 1;
|
|
|
-+ lowsign = sign;
|
|
|
-+
|
|
|
-+ /* HIGH should be rounded like a normal double, making |LOW| <=
|
|
|
-+ 0.5 ULP of HIGH. Assume round-to-nearest. */
|
|
|
-+ if (exp < EXPMAX)
|
|
|
-+ if (low > unity || (low == unity && (high & 1) == 1))
|
|
|
-+ {
|
|
|
-+ /* Round HIGH up and adjust LOW to match. */
|
|
|
-+ high++;
|
|
|
-+ if (high == unity)
|
|
|
-+ {
|
|
|
-+ /* May make it infinite, but that's OK. */
|
|
|
-+ high = 0;
|
|
|
-+ exp++;
|
|
|
-+ }
|
|
|
-+ low = unity * 2 - low;
|
|
|
-+ lowsign ^= 1;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ high |= (halffractype) exp << HALFFRACBITS;
|
|
|
-+ high |= (halffractype) sign << (HALFFRACBITS + EXPBITS);
|
|
|
-+
|
|
|
-+ if (exp == EXPMAX || exp == 0 || low == 0)
|
|
|
-+ low = 0;
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ while (lowexp > 0 && low < unity)
|
|
|
-+ {
|
|
|
-+ low <<= 1;
|
|
|
-+ lowexp--;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (lowexp <= 0)
|
|
|
-+ {
|
|
|
-+ halffractype roundmsb, round;
|
|
|
-+ int shift;
|
|
|
-+
|
|
|
-+ shift = 1 - lowexp;
|
|
|
-+ roundmsb = (1 << (shift - 1));
|
|
|
-+ round = low & ((roundmsb << 1) - 1);
|
|
|
-+
|
|
|
-+ low >>= shift;
|
|
|
-+ lowexp = 0;
|
|
|
-+
|
|
|
-+ if (round > roundmsb || (round == roundmsb && (low & 1) == 1))
|
|
|
-+ {
|
|
|
-+ low++;
|
|
|
-+ if (low == unity)
|
|
|
-+ /* LOW rounds up to the smallest normal number. */
|
|
|
-+ lowexp++;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ low &= unity - 1;
|
|
|
-+ low |= (halffractype) lowexp << HALFFRACBITS;
|
|
|
-+ low |= (halffractype) lowsign << (HALFFRACBITS + EXPBITS);
|
|
|
-+ }
|
|
|
-+ dst.value_raw = ((fractype) high << HALFSHIFT) | low;
|
|
|
-+ }
|
|
|
-+# else
|
|
|
-+ dst.value_raw = fraction & ((((fractype)1) << FRACBITS) - (fractype)1);
|
|
|
-+ dst.value_raw |= ((fractype) (exp & ((1 << EXPBITS) - 1))) << FRACBITS;
|
|
|
-+ dst.value_raw |= ((fractype) (sign & 1)) << (FRACBITS | EXPBITS);
|
|
|
-+# endif
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT)
|
|
|
-+#ifdef TFLOAT
|
|
|
-+ {
|
|
|
-+ qrtrfractype tmp1 = dst.words[0];
|
|
|
-+ qrtrfractype tmp2 = dst.words[1];
|
|
|
-+ dst.words[0] = dst.words[3];
|
|
|
-+ dst.words[1] = dst.words[2];
|
|
|
-+ dst.words[2] = tmp2;
|
|
|
-+ dst.words[3] = tmp1;
|
|
|
-+ }
|
|
|
-+#else
|
|
|
-+ {
|
|
|
-+ halffractype tmp = dst.words[0];
|
|
|
-+ dst.words[0] = dst.words[1];
|
|
|
-+ dst.words[1] = tmp;
|
|
|
-+ }
|
|
|
-+#endif
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+ return dst.value;
|
|
|
-+}
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+#if defined(L_unpack_df) || defined(L_unpack_sf) || defined(L_unpack_tf)
|
|
|
-+void
|
|
|
-+unpack_d (FLO_union_type * src, fp_number_type * dst)
|
|
|
-+{
|
|
|
-+ /* We previously used bitfields to store the number, but this doesn't
|
|
|
-+ handle little/big endian systems conveniently, so use shifts and
|
|
|
-+ masks */
|
|
|
-+ fractype fraction;
|
|
|
-+ int exp;
|
|
|
-+ int sign;
|
|
|
-+
|
|
|
-+#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT)
|
|
|
-+ FLO_union_type swapped;
|
|
|
-+
|
|
|
-+#ifdef TFLOAT
|
|
|
-+ swapped.words[0] = src->words[3];
|
|
|
-+ swapped.words[1] = src->words[2];
|
|
|
-+ swapped.words[2] = src->words[1];
|
|
|
-+ swapped.words[3] = src->words[0];
|
|
|
-+#else
|
|
|
-+ swapped.words[0] = src->words[1];
|
|
|
-+ swapped.words[1] = src->words[0];
|
|
|
-+#endif
|
|
|
-+ src = &swapped;
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+#ifdef FLOAT_BIT_ORDER_MISMATCH
|
|
|
-+ fraction = src->bits.fraction;
|
|
|
-+ exp = src->bits.exp;
|
|
|
-+ sign = src->bits.sign;
|
|
|
-+#else
|
|
|
-+# if defined TFLOAT && defined HALFFRACBITS
|
|
|
-+ {
|
|
|
-+ halffractype high, low;
|
|
|
-+
|
|
|
-+ high = src->value_raw >> HALFSHIFT;
|
|
|
-+ low = src->value_raw & (((fractype)1 << HALFSHIFT) - 1);
|
|
|
-+
|
|
|
-+ fraction = high & ((((fractype)1) << HALFFRACBITS) - 1);
|
|
|
-+ fraction <<= FRACBITS - HALFFRACBITS;
|
|
|
-+ exp = ((int)(high >> HALFFRACBITS)) & ((1 << EXPBITS) - 1);
|
|
|
-+ sign = ((int)(high >> (((HALFFRACBITS + EXPBITS))))) & 1;
|
|
|
-+
|
|
|
-+ if (exp != EXPMAX && exp != 0 && low != 0)
|
|
|
-+ {
|
|
|
-+ int lowexp = ((int)(low >> HALFFRACBITS)) & ((1 << EXPBITS) - 1);
|
|
|
-+ int lowsign = ((int)(low >> (((HALFFRACBITS + EXPBITS))))) & 1;
|
|
|
-+ int shift;
|
|
|
-+ fractype xlow;
|
|
|
-+
|
|
|
-+ xlow = low & ((((fractype)1) << HALFFRACBITS) - 1);
|
|
|
-+ if (lowexp)
|
|
|
-+ xlow |= (((halffractype)1) << HALFFRACBITS);
|
|
|
-+ else
|
|
|
-+ lowexp = 1;
|
|
|
-+ shift = (FRACBITS - HALFFRACBITS) - (exp - lowexp);
|
|
|
-+ if (shift > 0)
|
|
|
-+ xlow <<= shift;
|
|
|
-+ else if (shift < 0)
|
|
|
-+ xlow >>= -shift;
|
|
|
-+ if (sign == lowsign)
|
|
|
-+ fraction += xlow;
|
|
|
-+ else if (fraction >= xlow)
|
|
|
-+ fraction -= xlow;
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ /* The high part is a power of two but the full number is lower.
|
|
|
-+ This code will leave the implicit 1 in FRACTION, but we'd
|
|
|
-+ have added that below anyway. */
|
|
|
-+ fraction = (((fractype) 1 << FRACBITS) - xlow) << 1;
|
|
|
-+ exp--;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+# else
|
|
|
-+ fraction = src->value_raw & ((((fractype)1) << FRACBITS) - 1);
|
|
|
-+ exp = ((int)(src->value_raw >> FRACBITS)) & ((1 << EXPBITS) - 1);
|
|
|
-+ sign = ((int)(src->value_raw >> (FRACBITS + EXPBITS))) & 1;
|
|
|
-+# endif
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+ dst->sign = sign;
|
|
|
-+ if (exp == 0)
|
|
|
-+ {
|
|
|
-+ /* Hmm. Looks like 0 */
|
|
|
-+ if (fraction == 0
|
|
|
-+#ifdef NO_DENORMALS
|
|
|
-+ || 1
|
|
|
-+#endif
|
|
|
-+ )
|
|
|
-+ {
|
|
|
-+ /* tastes like zero */
|
|
|
-+ dst->class = CLASS_ZERO;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ /* Zero exponent with nonzero fraction - it's denormalized,
|
|
|
-+ so there isn't a leading implicit one - we'll shift it so
|
|
|
-+ it gets one. */
|
|
|
-+ dst->normal_exp = exp - EXPBIAS + 1;
|
|
|
-+ fraction <<= NGARDS;
|
|
|
-+
|
|
|
-+ dst->class = CLASS_NUMBER;
|
|
|
-+#if 1
|
|
|
-+ while (fraction < IMPLICIT_1)
|
|
|
-+ {
|
|
|
-+ fraction <<= 1;
|
|
|
-+ dst->normal_exp--;
|
|
|
-+ }
|
|
|
-+#endif
|
|
|
-+ dst->fraction.ll = fraction;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp == EXPMAX)
|
|
|
-+ {
|
|
|
-+ /* Huge exponent*/
|
|
|
-+ if (fraction == 0)
|
|
|
-+ {
|
|
|
-+ /* Attached to a zero fraction - means infinity */
|
|
|
-+ dst->class = CLASS_INFINITY;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ /* Nonzero fraction, means nan */
|
|
|
-+#ifdef QUIET_NAN_NEGATED
|
|
|
-+ if ((fraction & QUIET_NAN) == 0)
|
|
|
-+#else
|
|
|
-+ if (fraction & QUIET_NAN)
|
|
|
-+#endif
|
|
|
-+ {
|
|
|
-+ dst->class = CLASS_QNAN;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ dst->class = CLASS_SNAN;
|
|
|
-+ }
|
|
|
-+ /* Keep the fraction part as the nan number */
|
|
|
-+ dst->fraction.ll = fraction;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ /* Nothing strange about this number */
|
|
|
-+ dst->normal_exp = exp - EXPBIAS;
|
|
|
-+ dst->class = CLASS_NUMBER;
|
|
|
-+ dst->fraction.ll = (fraction << NGARDS) | IMPLICIT_1;
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+#endif /* L_unpack_df || L_unpack_sf */
|
|
|
-+
|
|
|
-+#if defined(L_addsub_sf) || defined(L_addsub_df) || defined(L_addsub_tf)
|
|
|
-+static fp_number_type *
|
|
|
-+_fpadd_parts (fp_number_type * a,
|
|
|
-+ fp_number_type * b,
|
|
|
-+ fp_number_type * tmp)
|
|
|
-+{
|
|
|
-+ intfrac tfraction;
|
|
|
-+
|
|
|
-+ /* Put commonly used fields in local variables. */
|
|
|
-+ int a_normal_exp;
|
|
|
-+ int b_normal_exp;
|
|
|
-+ fractype a_fraction;
|
|
|
-+ fractype b_fraction;
|
|
|
-+
|
|
|
-+ if (isnan (a))
|
|
|
-+ {
|
|
|
-+ return a;
|
|
|
-+ }
|
|
|
-+ if (isnan (b))
|
|
|
-+ {
|
|
|
-+ return b;
|
|
|
-+ }
|
|
|
-+ if (isinf (a))
|
|
|
-+ {
|
|
|
-+ /* Adding infinities with opposite signs yields a NaN. */
|
|
|
-+ if (isinf (b) && a->sign != b->sign)
|
|
|
-+ return nan ();
|
|
|
-+ return a;
|
|
|
-+ }
|
|
|
-+ if (isinf (b))
|
|
|
-+ {
|
|
|
-+ return b;
|
|
|
-+ }
|
|
|
-+ if (iszero (b))
|
|
|
-+ {
|
|
|
-+ if (iszero (a))
|
|
|
-+ {
|
|
|
-+ *tmp = *a;
|
|
|
-+ tmp->sign = a->sign & b->sign;
|
|
|
-+ return tmp;
|
|
|
-+ }
|
|
|
-+ return a;
|
|
|
-+ }
|
|
|
-+ if (iszero (a))
|
|
|
-+ {
|
|
|
-+ return b;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* Got two numbers. shift the smaller and increment the exponent till
|
|
|
-+ they're the same */
|
|
|
-+ {
|
|
|
-+ int diff;
|
|
|
-+
|
|
|
-+ a_normal_exp = a->normal_exp;
|
|
|
-+ b_normal_exp = b->normal_exp;
|
|
|
-+ a_fraction = a->fraction.ll;
|
|
|
-+ b_fraction = b->fraction.ll;
|
|
|
-+
|
|
|
-+ diff = a_normal_exp - b_normal_exp;
|
|
|
-+
|
|
|
-+ if (diff < 0)
|
|
|
-+ diff = -diff;
|
|
|
-+ if (diff < FRAC_NBITS)
|
|
|
-+ {
|
|
|
-+ /* ??? This does shifts one bit at a time. Optimize. */
|
|
|
-+ while (a_normal_exp > b_normal_exp)
|
|
|
-+ {
|
|
|
-+ b_normal_exp++;
|
|
|
-+ LSHIFT (b_fraction);
|
|
|
-+ }
|
|
|
-+ while (b_normal_exp > a_normal_exp)
|
|
|
-+ {
|
|
|
-+ a_normal_exp++;
|
|
|
-+ LSHIFT (a_fraction);
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ /* Somethings's up.. choose the biggest */
|
|
|
-+ if (a_normal_exp > b_normal_exp)
|
|
|
-+ {
|
|
|
-+ b_normal_exp = a_normal_exp;
|
|
|
-+ b_fraction = 0;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ a_normal_exp = b_normal_exp;
|
|
|
-+ a_fraction = 0;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (a->sign != b->sign)
|
|
|
-+ {
|
|
|
-+ if (a->sign)
|
|
|
-+ {
|
|
|
-+ tfraction = -a_fraction + b_fraction;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ tfraction = a_fraction - b_fraction;
|
|
|
-+ }
|
|
|
-+ if (tfraction >= 0)
|
|
|
-+ {
|
|
|
-+ tmp->sign = 0;
|
|
|
-+ tmp->normal_exp = a_normal_exp;
|
|
|
-+ tmp->fraction.ll = tfraction;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ tmp->sign = 1;
|
|
|
-+ tmp->normal_exp = a_normal_exp;
|
|
|
-+ tmp->fraction.ll = -tfraction;
|
|
|
-+ }
|
|
|
-+ /* and renormalize it */
|
|
|
-+
|
|
|
-+ while (tmp->fraction.ll < IMPLICIT_1 && tmp->fraction.ll)
|
|
|
-+ {
|
|
|
-+ tmp->fraction.ll <<= 1;
|
|
|
-+ tmp->normal_exp--;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ tmp->sign = a->sign;
|
|
|
-+ tmp->normal_exp = a_normal_exp;
|
|
|
-+ tmp->fraction.ll = a_fraction + b_fraction;
|
|
|
-+ }
|
|
|
-+ tmp->class = CLASS_NUMBER;
|
|
|
-+ /* Now the fraction is added, we have to shift down to renormalize the
|
|
|
-+ number */
|
|
|
-+
|
|
|
-+ if (tmp->fraction.ll >= IMPLICIT_2)
|
|
|
-+ {
|
|
|
-+ LSHIFT (tmp->fraction.ll);
|
|
|
-+ tmp->normal_exp++;
|
|
|
-+ }
|
|
|
-+ return tmp;
|
|
|
-+
|
|
|
-+}
|
|
|
-+
|
|
|
-+FLO_type
|
|
|
-+add (FLO_type arg_a, FLO_type arg_b)
|
|
|
-+{
|
|
|
-+ fp_number_type a;
|
|
|
-+ fp_number_type b;
|
|
|
-+ fp_number_type tmp;
|
|
|
-+ fp_number_type *res;
|
|
|
-+ FLO_union_type au, bu;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ bu.value = arg_b;
|
|
|
-+
|
|
|
-+ unpack_d (&au, &a);
|
|
|
-+ unpack_d (&bu, &b);
|
|
|
-+
|
|
|
-+ res = _fpadd_parts (&a, &b, &tmp);
|
|
|
-+
|
|
|
-+ return pack_d (res);
|
|
|
-+}
|
|
|
-+
|
|
|
-+FLO_type
|
|
|
-+sub (FLO_type arg_a, FLO_type arg_b)
|
|
|
-+{
|
|
|
-+ fp_number_type a;
|
|
|
-+ fp_number_type b;
|
|
|
-+ fp_number_type tmp;
|
|
|
-+ fp_number_type *res;
|
|
|
-+ FLO_union_type au, bu;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ bu.value = arg_b;
|
|
|
-+
|
|
|
-+ unpack_d (&au, &a);
|
|
|
-+ unpack_d (&bu, &b);
|
|
|
-+
|
|
|
-+ b.sign ^= 1;
|
|
|
-+
|
|
|
-+ res = _fpadd_parts (&a, &b, &tmp);
|
|
|
-+
|
|
|
-+ return pack_d (res);
|
|
|
-+}
|
|
|
-+#endif /* L_addsub_sf || L_addsub_df */
|
|
|
-+
|
|
|
-+#if defined(L_mul_sf) || defined(L_mul_df) || defined(L_mul_tf)
|
|
|
-+static inline __attribute__ ((__always_inline__)) fp_number_type *
|
|
|
-+_fpmul_parts ( fp_number_type * a,
|
|
|
-+ fp_number_type * b,
|
|
|
-+ fp_number_type * tmp)
|
|
|
-+{
|
|
|
-+ fractype low = 0;
|
|
|
-+ fractype high = 0;
|
|
|
-+
|
|
|
-+ if (isnan (a))
|
|
|
-+ {
|
|
|
-+ a->sign = a->sign != b->sign;
|
|
|
-+ return a;
|
|
|
-+ }
|
|
|
-+ if (isnan (b))
|
|
|
-+ {
|
|
|
-+ b->sign = a->sign != b->sign;
|
|
|
-+ return b;
|
|
|
-+ }
|
|
|
-+ if (isinf (a))
|
|
|
-+ {
|
|
|
-+ if (iszero (b))
|
|
|
-+ return nan ();
|
|
|
-+ a->sign = a->sign != b->sign;
|
|
|
-+ return a;
|
|
|
-+ }
|
|
|
-+ if (isinf (b))
|
|
|
-+ {
|
|
|
-+ if (iszero (a))
|
|
|
-+ {
|
|
|
-+ return nan ();
|
|
|
-+ }
|
|
|
-+ b->sign = a->sign != b->sign;
|
|
|
-+ return b;
|
|
|
-+ }
|
|
|
-+ if (iszero (a))
|
|
|
-+ {
|
|
|
-+ a->sign = a->sign != b->sign;
|
|
|
-+ return a;
|
|
|
-+ }
|
|
|
-+ if (iszero (b))
|
|
|
-+ {
|
|
|
-+ b->sign = a->sign != b->sign;
|
|
|
-+ return b;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* Calculate the mantissa by multiplying both numbers to get a
|
|
|
-+ twice-as-wide number. */
|
|
|
-+ {
|
|
|
-+#if defined(NO_DI_MODE) || defined(TFLOAT)
|
|
|
-+ {
|
|
|
-+ fractype x = a->fraction.ll;
|
|
|
-+ fractype ylow = b->fraction.ll;
|
|
|
-+ fractype yhigh = 0;
|
|
|
-+ int bit;
|
|
|
-+
|
|
|
-+ /* ??? This does multiplies one bit at a time. Optimize. */
|
|
|
-+ for (bit = 0; bit < FRAC_NBITS; bit++)
|
|
|
-+ {
|
|
|
-+ int carry;
|
|
|
-+
|
|
|
-+ if (x & 1)
|
|
|
-+ {
|
|
|
-+ carry = (low += ylow) < ylow;
|
|
|
-+ high += yhigh + carry;
|
|
|
-+ }
|
|
|
-+ yhigh <<= 1;
|
|
|
-+ if (ylow & FRACHIGH)
|
|
|
-+ {
|
|
|
-+ yhigh |= 1;
|
|
|
-+ }
|
|
|
-+ ylow <<= 1;
|
|
|
-+ x >>= 1;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+#elif defined(FLOAT)
|
|
|
-+ /* Multiplying two USIs to get a UDI, we're safe. */
|
|
|
-+ {
|
|
|
-+ UDItype answer = (UDItype)a->fraction.ll * (UDItype)b->fraction.ll;
|
|
|
-+
|
|
|
-+ high = answer >> BITS_PER_SI;
|
|
|
-+ low = answer;
|
|
|
-+ }
|
|
|
-+#else
|
|
|
-+ /* fractype is DImode, but we need the result to be twice as wide.
|
|
|
-+ Assuming a widening multiply from DImode to TImode is not
|
|
|
-+ available, build one by hand. */
|
|
|
-+ {
|
|
|
-+ USItype nl = a->fraction.ll;
|
|
|
-+ USItype nh = a->fraction.ll >> BITS_PER_SI;
|
|
|
-+ USItype ml = b->fraction.ll;
|
|
|
-+ USItype mh = b->fraction.ll >> BITS_PER_SI;
|
|
|
-+ UDItype pp_ll = (UDItype) ml * nl;
|
|
|
-+ UDItype pp_hl = (UDItype) mh * nl;
|
|
|
-+ UDItype pp_lh = (UDItype) ml * nh;
|
|
|
-+ UDItype pp_hh = (UDItype) mh * nh;
|
|
|
-+ UDItype res2 = 0;
|
|
|
-+ UDItype res0 = 0;
|
|
|
-+ UDItype ps_hh__ = pp_hl + pp_lh;
|
|
|
-+ if (ps_hh__ < pp_hl)
|
|
|
-+ res2 += (UDItype)1 << BITS_PER_SI;
|
|
|
-+ pp_hl = (UDItype)(USItype)ps_hh__ << BITS_PER_SI;
|
|
|
-+ res0 = pp_ll + pp_hl;
|
|
|
-+ if (res0 < pp_ll)
|
|
|
-+ res2++;
|
|
|
-+ res2 += (ps_hh__ >> BITS_PER_SI) + pp_hh;
|
|
|
-+ high = res2;
|
|
|
-+ low = res0;
|
|
|
-+ }
|
|
|
-+#endif
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ tmp->normal_exp = a->normal_exp + b->normal_exp
|
|
|
-+ + FRAC_NBITS - (FRACBITS + NGARDS);
|
|
|
-+ tmp->sign = a->sign != b->sign;
|
|
|
-+ while (high >= IMPLICIT_2)
|
|
|
-+ {
|
|
|
-+ tmp->normal_exp++;
|
|
|
-+ if (high & 1)
|
|
|
-+ {
|
|
|
-+ low >>= 1;
|
|
|
-+ low |= FRACHIGH;
|
|
|
-+ }
|
|
|
-+ high >>= 1;
|
|
|
-+ }
|
|
|
-+ while (high < IMPLICIT_1)
|
|
|
-+ {
|
|
|
-+ tmp->normal_exp--;
|
|
|
-+
|
|
|
-+ high <<= 1;
|
|
|
-+ if (low & FRACHIGH)
|
|
|
-+ high |= 1;
|
|
|
-+ low <<= 1;
|
|
|
-+ }
|
|
|
-+ /* rounding is tricky. if we only round if it won't make us round later. */
|
|
|
-+#if 0
|
|
|
-+ if (low & FRACHIGH2)
|
|
|
-+ {
|
|
|
-+ if (((high & GARDMASK) != GARDMSB)
|
|
|
-+ && (((high + 1) & GARDMASK) == GARDMSB))
|
|
|
-+ {
|
|
|
-+ /* don't round, it gets done again later. */
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ high++;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+#endif
|
|
|
-+ if (!ROUND_TOWARDS_ZERO && (high & GARDMASK) == GARDMSB)
|
|
|
-+ {
|
|
|
-+ if (high & (1 << NGARDS))
|
|
|
-+ {
|
|
|
-+ /* half way, so round to even */
|
|
|
-+ high += GARDROUND + 1;
|
|
|
-+ }
|
|
|
-+ else if (low)
|
|
|
-+ {
|
|
|
-+ /* but we really weren't half way */
|
|
|
-+ high += GARDROUND + 1;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ tmp->fraction.ll = high;
|
|
|
-+ tmp->class = CLASS_NUMBER;
|
|
|
-+ return tmp;
|
|
|
-+}
|
|
|
-+
|
|
|
-+FLO_type
|
|
|
-+multiply (FLO_type arg_a, FLO_type arg_b)
|
|
|
-+{
|
|
|
-+ fp_number_type a;
|
|
|
-+ fp_number_type b;
|
|
|
-+ fp_number_type tmp;
|
|
|
-+ fp_number_type *res;
|
|
|
-+ FLO_union_type au, bu;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ bu.value = arg_b;
|
|
|
-+
|
|
|
-+ unpack_d (&au, &a);
|
|
|
-+ unpack_d (&bu, &b);
|
|
|
-+
|
|
|
-+ res = _fpmul_parts (&a, &b, &tmp);
|
|
|
-+
|
|
|
-+ return pack_d (res);
|
|
|
-+}
|
|
|
-+#endif /* L_mul_sf || L_mul_df */
|
|
|
-+
|
|
|
-+#if defined(L_div_sf) || defined(L_div_df) || defined(L_div_tf)
|
|
|
-+static inline __attribute__ ((__always_inline__)) fp_number_type *
|
|
|
-+_fpdiv_parts (fp_number_type * a,
|
|
|
-+ fp_number_type * b)
|
|
|
-+{
|
|
|
-+ fractype bit;
|
|
|
-+ fractype numerator;
|
|
|
-+ fractype denominator;
|
|
|
-+ fractype quotient;
|
|
|
-+
|
|
|
-+ if (isnan (a))
|
|
|
-+ {
|
|
|
-+ return a;
|
|
|
-+ }
|
|
|
-+ if (isnan (b))
|
|
|
-+ {
|
|
|
-+ return b;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ a->sign = a->sign ^ b->sign;
|
|
|
-+
|
|
|
-+ if (isinf (a) || iszero (a))
|
|
|
-+ {
|
|
|
-+ if (a->class == b->class)
|
|
|
-+ return nan ();
|
|
|
-+ return a;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (isinf (b))
|
|
|
-+ {
|
|
|
-+ a->fraction.ll = 0;
|
|
|
-+ a->normal_exp = 0;
|
|
|
-+ return a;
|
|
|
-+ }
|
|
|
-+ if (iszero (b))
|
|
|
-+ {
|
|
|
-+ a->class = CLASS_INFINITY;
|
|
|
-+ return a;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* Calculate the mantissa by multiplying both 64bit numbers to get a
|
|
|
-+ 128 bit number */
|
|
|
-+ {
|
|
|
-+ /* quotient =
|
|
|
-+ ( numerator / denominator) * 2^(numerator exponent - denominator exponent)
|
|
|
-+ */
|
|
|
-+
|
|
|
-+ a->normal_exp = a->normal_exp - b->normal_exp;
|
|
|
-+ numerator = a->fraction.ll;
|
|
|
-+ denominator = b->fraction.ll;
|
|
|
-+
|
|
|
-+ if (numerator < denominator)
|
|
|
-+ {
|
|
|
-+ /* Fraction will be less than 1.0 */
|
|
|
-+ numerator *= 2;
|
|
|
-+ a->normal_exp--;
|
|
|
-+ }
|
|
|
-+ bit = IMPLICIT_1;
|
|
|
-+ quotient = 0;
|
|
|
-+ /* ??? Does divide one bit at a time. Optimize. */
|
|
|
-+ while (bit)
|
|
|
-+ {
|
|
|
-+ if (numerator >= denominator)
|
|
|
-+ {
|
|
|
-+ quotient |= bit;
|
|
|
-+ numerator -= denominator;
|
|
|
-+ }
|
|
|
-+ bit >>= 1;
|
|
|
-+ numerator *= 2;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (!ROUND_TOWARDS_ZERO && (quotient & GARDMASK) == GARDMSB)
|
|
|
-+ {
|
|
|
-+ if (quotient & (1 << NGARDS))
|
|
|
-+ {
|
|
|
-+ /* half way, so round to even */
|
|
|
-+ quotient += GARDROUND + 1;
|
|
|
-+ }
|
|
|
-+ else if (numerator)
|
|
|
-+ {
|
|
|
-+ /* but we really weren't half way, more bits exist */
|
|
|
-+ quotient += GARDROUND + 1;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ a->fraction.ll = quotient;
|
|
|
-+ return (a);
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+
|
|
|
-+FLO_type
|
|
|
-+divide (FLO_type arg_a, FLO_type arg_b)
|
|
|
-+{
|
|
|
-+ fp_number_type a;
|
|
|
-+ fp_number_type b;
|
|
|
-+ fp_number_type *res;
|
|
|
-+ FLO_union_type au, bu;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ bu.value = arg_b;
|
|
|
-+
|
|
|
-+ unpack_d (&au, &a);
|
|
|
-+ unpack_d (&bu, &b);
|
|
|
-+
|
|
|
-+ res = _fpdiv_parts (&a, &b);
|
|
|
-+
|
|
|
-+ return pack_d (res);
|
|
|
-+}
|
|
|
-+#endif /* L_div_sf || L_div_df */
|
|
|
-+
|
|
|
-+#if defined(L_fpcmp_parts_sf) || defined(L_fpcmp_parts_df) \
|
|
|
-+ || defined(L_fpcmp_parts_tf)
|
|
|
-+/* according to the demo, fpcmp returns a comparison with 0... thus
|
|
|
-+ a<b -> -1
|
|
|
-+ a==b -> 0
|
|
|
-+ a>b -> +1
|
|
|
-+ */
|
|
|
-+
|
|
|
-+int
|
|
|
-+__fpcmp_parts (fp_number_type * a, fp_number_type * b)
|
|
|
-+{
|
|
|
-+#if 0
|
|
|
-+ /* either nan -> unordered. Must be checked outside of this routine. */
|
|
|
-+ if (isnan (a) && isnan (b))
|
|
|
-+ {
|
|
|
-+ return 1; /* still unordered! */
|
|
|
-+ }
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+ if (isnan (a) || isnan (b))
|
|
|
-+ {
|
|
|
-+ return 1; /* how to indicate unordered compare? */
|
|
|
-+ }
|
|
|
-+ if (isinf (a) && isinf (b))
|
|
|
-+ {
|
|
|
-+ /* +inf > -inf, but +inf != +inf */
|
|
|
-+ /* b \a| +inf(0)| -inf(1)
|
|
|
-+ ______\+--------+--------
|
|
|
-+ +inf(0)| a==b(0)| a<b(-1)
|
|
|
-+ -------+--------+--------
|
|
|
-+ -inf(1)| a>b(1) | a==b(0)
|
|
|
-+ -------+--------+--------
|
|
|
-+ So since unordered must be nonzero, just line up the columns...
|
|
|
-+ */
|
|
|
-+ return b->sign - a->sign;
|
|
|
-+ }
|
|
|
-+ /* but not both... */
|
|
|
-+ if (isinf (a))
|
|
|
-+ {
|
|
|
-+ return a->sign ? -1 : 1;
|
|
|
-+ }
|
|
|
-+ if (isinf (b))
|
|
|
-+ {
|
|
|
-+ return b->sign ? 1 : -1;
|
|
|
-+ }
|
|
|
-+ if (iszero (a) && iszero (b))
|
|
|
-+ {
|
|
|
-+ return 0;
|
|
|
-+ }
|
|
|
-+ if (iszero (a))
|
|
|
-+ {
|
|
|
-+ return b->sign ? 1 : -1;
|
|
|
-+ }
|
|
|
-+ if (iszero (b))
|
|
|
-+ {
|
|
|
-+ return a->sign ? -1 : 1;
|
|
|
-+ }
|
|
|
-+ /* now both are "normal". */
|
|
|
-+ if (a->sign != b->sign)
|
|
|
-+ {
|
|
|
-+ /* opposite signs */
|
|
|
-+ return a->sign ? -1 : 1;
|
|
|
-+ }
|
|
|
-+ /* same sign; exponents? */
|
|
|
-+ if (a->normal_exp > b->normal_exp)
|
|
|
-+ {
|
|
|
-+ return a->sign ? -1 : 1;
|
|
|
-+ }
|
|
|
-+ if (a->normal_exp < b->normal_exp)
|
|
|
-+ {
|
|
|
-+ return a->sign ? 1 : -1;
|
|
|
-+ }
|
|
|
-+ /* same exponents; check size. */
|
|
|
-+ if (a->fraction.ll > b->fraction.ll)
|
|
|
-+ {
|
|
|
-+ return a->sign ? -1 : 1;
|
|
|
-+ }
|
|
|
-+ if (a->fraction.ll < b->fraction.ll)
|
|
|
-+ {
|
|
|
-+ return a->sign ? 1 : -1;
|
|
|
-+ }
|
|
|
-+ /* after all that, they're equal. */
|
|
|
-+ return 0;
|
|
|
-+}
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+#if defined(L_compare_sf) || defined(L_compare_df) || defined(L_compoare_tf)
|
|
|
-+CMPtype
|
|
|
-+compare (FLO_type arg_a, FLO_type arg_b)
|
|
|
-+{
|
|
|
-+ fp_number_type a;
|
|
|
-+ fp_number_type b;
|
|
|
-+ FLO_union_type au, bu;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ bu.value = arg_b;
|
|
|
-+
|
|
|
-+ unpack_d (&au, &a);
|
|
|
-+ unpack_d (&bu, &b);
|
|
|
-+
|
|
|
-+ return __fpcmp_parts (&a, &b);
|
|
|
-+}
|
|
|
-+#endif /* L_compare_sf || L_compare_df */
|
|
|
-+
|
|
|
-+#ifndef US_SOFTWARE_GOFAST
|
|
|
-+
|
|
|
-+/* These should be optimized for their specific tasks someday. */
|
|
|
-+
|
|
|
-+#if defined(L_eq_sf) || defined(L_eq_df) || defined(L_eq_tf)
|
|
|
-+CMPtype
|
|
|
-+_eq_f2 (FLO_type arg_a, FLO_type arg_b)
|
|
|
-+{
|
|
|
-+ fp_number_type a;
|
|
|
-+ fp_number_type b;
|
|
|
-+ FLO_union_type au, bu;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ bu.value = arg_b;
|
|
|
-+
|
|
|
-+ unpack_d (&au, &a);
|
|
|
-+ unpack_d (&bu, &b);
|
|
|
-+
|
|
|
-+ if (isnan (&a) || isnan (&b))
|
|
|
-+ return 1; /* false, truth == 0 */
|
|
|
-+
|
|
|
-+ return __fpcmp_parts (&a, &b) ;
|
|
|
-+}
|
|
|
-+#endif /* L_eq_sf || L_eq_df */
|
|
|
-+
|
|
|
-+#if defined(L_ne_sf) || defined(L_ne_df) || defined(L_ne_tf)
|
|
|
-+CMPtype
|
|
|
-+_ne_f2 (FLO_type arg_a, FLO_type arg_b)
|
|
|
-+{
|
|
|
-+ fp_number_type a;
|
|
|
-+ fp_number_type b;
|
|
|
-+ FLO_union_type au, bu;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ bu.value = arg_b;
|
|
|
-+
|
|
|
-+ unpack_d (&au, &a);
|
|
|
-+ unpack_d (&bu, &b);
|
|
|
-+
|
|
|
-+ if (isnan (&a) || isnan (&b))
|
|
|
-+ return 1; /* true, truth != 0 */
|
|
|
-+
|
|
|
-+ return __fpcmp_parts (&a, &b) ;
|
|
|
-+}
|
|
|
-+#endif /* L_ne_sf || L_ne_df */
|
|
|
-+
|
|
|
-+#if defined(L_gt_sf) || defined(L_gt_df) || defined(L_gt_tf)
|
|
|
-+CMPtype
|
|
|
-+_gt_f2 (FLO_type arg_a, FLO_type arg_b)
|
|
|
-+{
|
|
|
-+ fp_number_type a;
|
|
|
-+ fp_number_type b;
|
|
|
-+ FLO_union_type au, bu;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ bu.value = arg_b;
|
|
|
-+
|
|
|
-+ unpack_d (&au, &a);
|
|
|
-+ unpack_d (&bu, &b);
|
|
|
-+
|
|
|
-+ if (isnan (&a) || isnan (&b))
|
|
|
-+ return -1; /* false, truth > 0 */
|
|
|
-+
|
|
|
-+ return __fpcmp_parts (&a, &b);
|
|
|
-+}
|
|
|
-+#endif /* L_gt_sf || L_gt_df */
|
|
|
-+
|
|
|
-+#if defined(L_ge_sf) || defined(L_ge_df) || defined(L_ge_tf)
|
|
|
-+CMPtype
|
|
|
-+_ge_f2 (FLO_type arg_a, FLO_type arg_b)
|
|
|
-+{
|
|
|
-+ fp_number_type a;
|
|
|
-+ fp_number_type b;
|
|
|
-+ FLO_union_type au, bu;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ bu.value = arg_b;
|
|
|
-+
|
|
|
-+ unpack_d (&au, &a);
|
|
|
-+ unpack_d (&bu, &b);
|
|
|
-+
|
|
|
-+ if (isnan (&a) || isnan (&b))
|
|
|
-+ return -1; /* false, truth >= 0 */
|
|
|
-+ return __fpcmp_parts (&a, &b) ;
|
|
|
-+}
|
|
|
-+#endif /* L_ge_sf || L_ge_df */
|
|
|
-+
|
|
|
-+#if defined(L_lt_sf) || defined(L_lt_df) || defined(L_lt_tf)
|
|
|
-+CMPtype
|
|
|
-+_lt_f2 (FLO_type arg_a, FLO_type arg_b)
|
|
|
-+{
|
|
|
-+ fp_number_type a;
|
|
|
-+ fp_number_type b;
|
|
|
-+ FLO_union_type au, bu;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ bu.value = arg_b;
|
|
|
-+
|
|
|
-+ unpack_d (&au, &a);
|
|
|
-+ unpack_d (&bu, &b);
|
|
|
-+
|
|
|
-+ if (isnan (&a) || isnan (&b))
|
|
|
-+ return 1; /* false, truth < 0 */
|
|
|
-+
|
|
|
-+ return __fpcmp_parts (&a, &b);
|
|
|
-+}
|
|
|
-+#endif /* L_lt_sf || L_lt_df */
|
|
|
-+
|
|
|
-+#if defined(L_le_sf) || defined(L_le_df) || defined(L_le_tf)
|
|
|
-+CMPtype
|
|
|
-+_le_f2 (FLO_type arg_a, FLO_type arg_b)
|
|
|
-+{
|
|
|
-+ fp_number_type a;
|
|
|
-+ fp_number_type b;
|
|
|
-+ FLO_union_type au, bu;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ bu.value = arg_b;
|
|
|
-+
|
|
|
-+ unpack_d (&au, &a);
|
|
|
-+ unpack_d (&bu, &b);
|
|
|
-+
|
|
|
-+ if (isnan (&a) || isnan (&b))
|
|
|
-+ return 1; /* false, truth <= 0 */
|
|
|
-+
|
|
|
-+ return __fpcmp_parts (&a, &b) ;
|
|
|
-+}
|
|
|
-+#endif /* L_le_sf || L_le_df */
|
|
|
-+
|
|
|
-+#endif /* ! US_SOFTWARE_GOFAST */
|
|
|
-+
|
|
|
-+#if defined(L_unord_sf) || defined(L_unord_df) || defined(L_unord_tf)
|
|
|
-+CMPtype
|
|
|
-+_unord_f2 (FLO_type arg_a, FLO_type arg_b)
|
|
|
-+{
|
|
|
-+ fp_number_type a;
|
|
|
-+ fp_number_type b;
|
|
|
-+ FLO_union_type au, bu;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ bu.value = arg_b;
|
|
|
-+
|
|
|
-+ unpack_d (&au, &a);
|
|
|
-+ unpack_d (&bu, &b);
|
|
|
-+
|
|
|
-+ return (isnan (&a) || isnan (&b));
|
|
|
-+}
|
|
|
-+#endif /* L_unord_sf || L_unord_df */
|
|
|
-+
|
|
|
-+#if defined(L_si_to_sf) || defined(L_si_to_df) || defined(L_si_to_tf)
|
|
|
-+FLO_type
|
|
|
-+si_to_float (SItype arg_a)
|
|
|
-+{
|
|
|
-+ fp_number_type in;
|
|
|
-+
|
|
|
-+ in.class = CLASS_NUMBER;
|
|
|
-+ in.sign = arg_a < 0;
|
|
|
-+ if (!arg_a)
|
|
|
-+ {
|
|
|
-+ in.class = CLASS_ZERO;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ in.normal_exp = FRACBITS + NGARDS;
|
|
|
-+ if (in.sign)
|
|
|
-+ {
|
|
|
-+ /* Special case for minint, since there is no +ve integer
|
|
|
-+ representation for it */
|
|
|
-+ if (arg_a == (- MAX_SI_INT - 1))
|
|
|
-+ {
|
|
|
-+ return (FLO_type)(- MAX_SI_INT - 1);
|
|
|
-+ }
|
|
|
-+ in.fraction.ll = (-arg_a);
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ in.fraction.ll = arg_a;
|
|
|
-+
|
|
|
-+ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS)))
|
|
|
-+ {
|
|
|
-+ in.fraction.ll <<= 1;
|
|
|
-+ in.normal_exp -= 1;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ return pack_d (&in);
|
|
|
-+}
|
|
|
-+#endif /* L_si_to_sf || L_si_to_df */
|
|
|
-+
|
|
|
-+#if defined(L_usi_to_sf) || defined(L_usi_to_df) || defined(L_usi_to_tf)
|
|
|
-+FLO_type
|
|
|
-+usi_to_float (USItype arg_a)
|
|
|
-+{
|
|
|
-+ fp_number_type in;
|
|
|
-+
|
|
|
-+ in.sign = 0;
|
|
|
-+ if (!arg_a)
|
|
|
-+ {
|
|
|
-+ in.class = CLASS_ZERO;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ in.class = CLASS_NUMBER;
|
|
|
-+ in.normal_exp = FRACBITS + NGARDS;
|
|
|
-+ in.fraction.ll = arg_a;
|
|
|
-+
|
|
|
-+ while (in.fraction.ll > ((fractype)1 << (FRACBITS + NGARDS)))
|
|
|
-+ {
|
|
|
-+ in.fraction.ll >>= 1;
|
|
|
-+ in.normal_exp += 1;
|
|
|
-+ }
|
|
|
-+ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS)))
|
|
|
-+ {
|
|
|
-+ in.fraction.ll <<= 1;
|
|
|
-+ in.normal_exp -= 1;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ return pack_d (&in);
|
|
|
-+}
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+#if defined(L_sf_to_si) || defined(L_df_to_si) || defined(L_tf_to_si)
|
|
|
-+SItype
|
|
|
-+float_to_si (FLO_type arg_a)
|
|
|
-+{
|
|
|
-+ fp_number_type a;
|
|
|
-+ SItype tmp;
|
|
|
-+ FLO_union_type au;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ unpack_d (&au, &a);
|
|
|
-+
|
|
|
-+ if (iszero (&a))
|
|
|
-+ return 0;
|
|
|
-+ if (isnan (&a))
|
|
|
-+ return 0;
|
|
|
-+ /* get reasonable MAX_SI_INT... */
|
|
|
-+ if (isinf (&a))
|
|
|
-+ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT;
|
|
|
-+ /* it is a number, but a small one */
|
|
|
-+ if (a.normal_exp < 0)
|
|
|
-+ return 0;
|
|
|
-+ if (a.normal_exp > BITS_PER_SI - 2)
|
|
|
-+ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT;
|
|
|
-+ tmp = a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp);
|
|
|
-+ return a.sign ? (-tmp) : (tmp);
|
|
|
-+}
|
|
|
-+#endif /* L_sf_to_si || L_df_to_si */
|
|
|
-+
|
|
|
-+#if defined(L_sf_to_usi) || defined(L_df_to_usi) || defined(L_tf_to_usi)
|
|
|
-+#if defined US_SOFTWARE_GOFAST || defined(L_tf_to_usi)
|
|
|
-+/* While libgcc2.c defines its own __fixunssfsi and __fixunsdfsi routines,
|
|
|
-+ we also define them for GOFAST because the ones in libgcc2.c have the
|
|
|
-+ wrong names and I'd rather define these here and keep GOFAST CYG-LOC's
|
|
|
-+ out of libgcc2.c. We can't define these here if not GOFAST because then
|
|
|
-+ there'd be duplicate copies. */
|
|
|
-+
|
|
|
-+USItype
|
|
|
-+float_to_usi (FLO_type arg_a)
|
|
|
-+{
|
|
|
-+ fp_number_type a;
|
|
|
-+ FLO_union_type au;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ unpack_d (&au, &a);
|
|
|
-+
|
|
|
-+ if (iszero (&a))
|
|
|
-+ return 0;
|
|
|
-+ if (isnan (&a))
|
|
|
-+ return 0;
|
|
|
-+ /* it is a negative number */
|
|
|
-+ if (a.sign)
|
|
|
-+ return 0;
|
|
|
-+ /* get reasonable MAX_USI_INT... */
|
|
|
-+ if (isinf (&a))
|
|
|
-+ return MAX_USI_INT;
|
|
|
-+ /* it is a number, but a small one */
|
|
|
-+ if (a.normal_exp < 0)
|
|
|
-+ return 0;
|
|
|
-+ if (a.normal_exp > BITS_PER_SI - 1)
|
|
|
-+ return MAX_USI_INT;
|
|
|
-+ else if (a.normal_exp > (FRACBITS + NGARDS))
|
|
|
-+ return a.fraction.ll << (a.normal_exp - (FRACBITS + NGARDS));
|
|
|
-+ else
|
|
|
-+ return a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp);
|
|
|
-+}
|
|
|
-+#endif /* US_SOFTWARE_GOFAST */
|
|
|
-+#endif /* L_sf_to_usi || L_df_to_usi */
|
|
|
-+
|
|
|
-+#if defined(L_negate_sf) || defined(L_negate_df) || defined(L_negate_tf)
|
|
|
-+FLO_type
|
|
|
-+negate (FLO_type arg_a)
|
|
|
-+{
|
|
|
-+ fp_number_type a;
|
|
|
-+ FLO_union_type au;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ unpack_d (&au, &a);
|
|
|
-+
|
|
|
-+ flip_sign (&a);
|
|
|
-+ return pack_d (&a);
|
|
|
-+}
|
|
|
-+#endif /* L_negate_sf || L_negate_df */
|
|
|
-+
|
|
|
-+#ifdef FLOAT
|
|
|
-+
|
|
|
-+#if defined(L_make_sf)
|
|
|
-+SFtype
|
|
|
-+__make_fp(fp_class_type class,
|
|
|
-+ unsigned int sign,
|
|
|
-+ int exp,
|
|
|
-+ USItype frac)
|
|
|
-+{
|
|
|
-+ fp_number_type in;
|
|
|
-+
|
|
|
-+ in.class = class;
|
|
|
-+ in.sign = sign;
|
|
|
-+ in.normal_exp = exp;
|
|
|
-+ in.fraction.ll = frac;
|
|
|
-+ return pack_d (&in);
|
|
|
-+}
|
|
|
-+#endif /* L_make_sf */
|
|
|
-+
|
|
|
-+#ifndef FLOAT_ONLY
|
|
|
-+
|
|
|
-+/* This enables one to build an fp library that supports float but not double.
|
|
|
-+ Otherwise, we would get an undefined reference to __make_dp.
|
|
|
-+ This is needed for some 8-bit ports that can't handle well values that
|
|
|
-+ are 8-bytes in size, so we just don't support double for them at all. */
|
|
|
-+
|
|
|
-+#if defined(L_sf_to_df)
|
|
|
-+DFtype
|
|
|
-+sf_to_df (SFtype arg_a)
|
|
|
-+{
|
|
|
-+ fp_number_type in;
|
|
|
-+ FLO_union_type au;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ unpack_d (&au, &in);
|
|
|
-+
|
|
|
-+ return __make_dp (in.class, in.sign, in.normal_exp,
|
|
|
-+ ((UDItype) in.fraction.ll) << F_D_BITOFF);
|
|
|
-+}
|
|
|
-+#endif /* L_sf_to_df */
|
|
|
-+
|
|
|
-+#if defined(L_sf_to_tf) && defined(TMODES)
|
|
|
-+TFtype
|
|
|
-+sf_to_tf (SFtype arg_a)
|
|
|
-+{
|
|
|
-+ fp_number_type in;
|
|
|
-+ FLO_union_type au;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ unpack_d (&au, &in);
|
|
|
-+
|
|
|
-+ return __make_tp (in.class, in.sign, in.normal_exp,
|
|
|
-+ ((UTItype) in.fraction.ll) << F_T_BITOFF);
|
|
|
-+}
|
|
|
-+#endif /* L_sf_to_df */
|
|
|
-+
|
|
|
-+#endif /* ! FLOAT_ONLY */
|
|
|
-+#endif /* FLOAT */
|
|
|
-+
|
|
|
-+#ifndef FLOAT
|
|
|
-+
|
|
|
-+extern SFtype __make_fp (fp_class_type, unsigned int, int, USItype);
|
|
|
-+
|
|
|
-+#if defined(L_make_df)
|
|
|
-+DFtype
|
|
|
-+__make_dp (fp_class_type class, unsigned int sign, int exp, UDItype frac)
|
|
|
-+{
|
|
|
-+ fp_number_type in;
|
|
|
-+
|
|
|
-+ in.class = class;
|
|
|
-+ in.sign = sign;
|
|
|
-+ in.normal_exp = exp;
|
|
|
-+ in.fraction.ll = frac;
|
|
|
-+ return pack_d (&in);
|
|
|
-+}
|
|
|
-+#endif /* L_make_df */
|
|
|
-+
|
|
|
-+#if defined(L_df_to_sf)
|
|
|
-+SFtype
|
|
|
-+df_to_sf (DFtype arg_a)
|
|
|
-+{
|
|
|
-+ fp_number_type in;
|
|
|
-+ USItype sffrac;
|
|
|
-+ FLO_union_type au;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ unpack_d (&au, &in);
|
|
|
-+
|
|
|
-+ sffrac = in.fraction.ll >> F_D_BITOFF;
|
|
|
-+
|
|
|
-+ /* We set the lowest guard bit in SFFRAC if we discarded any non
|
|
|
-+ zero bits. */
|
|
|
-+ if ((in.fraction.ll & (((USItype) 1 << F_D_BITOFF) - 1)) != 0)
|
|
|
-+ sffrac |= 1;
|
|
|
-+
|
|
|
-+ return __make_fp (in.class, in.sign, in.normal_exp, sffrac);
|
|
|
-+}
|
|
|
-+#endif /* L_df_to_sf */
|
|
|
-+
|
|
|
-+#if defined(L_df_to_tf) && defined(TMODES) \
|
|
|
-+ && !defined(FLOAT) && !defined(TFLOAT)
|
|
|
-+TFtype
|
|
|
-+df_to_tf (DFtype arg_a)
|
|
|
-+{
|
|
|
-+ fp_number_type in;
|
|
|
-+ FLO_union_type au;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ unpack_d (&au, &in);
|
|
|
-+
|
|
|
-+ return __make_tp (in.class, in.sign, in.normal_exp,
|
|
|
-+ ((UTItype) in.fraction.ll) << D_T_BITOFF);
|
|
|
-+}
|
|
|
-+#endif /* L_sf_to_df */
|
|
|
-+
|
|
|
-+#ifdef TFLOAT
|
|
|
-+#if defined(L_make_tf)
|
|
|
-+TFtype
|
|
|
-+__make_tp(fp_class_type class,
|
|
|
-+ unsigned int sign,
|
|
|
-+ int exp,
|
|
|
-+ UTItype frac)
|
|
|
-+{
|
|
|
-+ fp_number_type in;
|
|
|
-+
|
|
|
-+ in.class = class;
|
|
|
-+ in.sign = sign;
|
|
|
-+ in.normal_exp = exp;
|
|
|
-+ in.fraction.ll = frac;
|
|
|
-+ return pack_d (&in);
|
|
|
-+}
|
|
|
-+#endif /* L_make_tf */
|
|
|
-+
|
|
|
-+#if defined(L_tf_to_df)
|
|
|
-+DFtype
|
|
|
-+tf_to_df (TFtype arg_a)
|
|
|
-+{
|
|
|
-+ fp_number_type in;
|
|
|
-+ UDItype sffrac;
|
|
|
-+ FLO_union_type au;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ unpack_d (&au, &in);
|
|
|
-+
|
|
|
-+ sffrac = in.fraction.ll >> D_T_BITOFF;
|
|
|
-+
|
|
|
-+ /* We set the lowest guard bit in SFFRAC if we discarded any non
|
|
|
-+ zero bits. */
|
|
|
-+ if ((in.fraction.ll & (((UTItype) 1 << D_T_BITOFF) - 1)) != 0)
|
|
|
-+ sffrac |= 1;
|
|
|
-+
|
|
|
-+ return __make_dp (in.class, in.sign, in.normal_exp, sffrac);
|
|
|
-+}
|
|
|
-+#endif /* L_tf_to_df */
|
|
|
-+
|
|
|
-+#if defined(L_tf_to_sf)
|
|
|
-+SFtype
|
|
|
-+tf_to_sf (TFtype arg_a)
|
|
|
-+{
|
|
|
-+ fp_number_type in;
|
|
|
-+ USItype sffrac;
|
|
|
-+ FLO_union_type au;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ unpack_d (&au, &in);
|
|
|
-+
|
|
|
-+ sffrac = in.fraction.ll >> F_T_BITOFF;
|
|
|
-+
|
|
|
-+ /* We set the lowest guard bit in SFFRAC if we discarded any non
|
|
|
-+ zero bits. */
|
|
|
-+ if ((in.fraction.ll & (((UTItype) 1 << F_T_BITOFF) - 1)) != 0)
|
|
|
-+ sffrac |= 1;
|
|
|
-+
|
|
|
-+ return __make_fp (in.class, in.sign, in.normal_exp, sffrac);
|
|
|
-+}
|
|
|
-+#endif /* L_tf_to_sf */
|
|
|
-+#endif /* TFLOAT */
|
|
|
-+
|
|
|
-+#endif /* ! FLOAT */
|
|
|
-+#endif /* !EXTENDED_FLOAT_STUBS */
|
|
|
-diff --git a/gcc/config/nios2/nios2-fp-bit.c b/gcc/config/nios2/nios2-fp-bit.c
|
|
|
-new file mode 100644
|
|
|
-index 0000000..839ffcc
|
|
|
---- /dev/null
|
|
|
-+++ b/gcc/config/nios2/nios2-fp-bit.c
|
|
|
-@@ -0,0 +1,1655 @@
|
|
|
-+#define FLOAT
|
|
|
-+#ifndef __nios2_big_endian__
|
|
|
-+#define FLOAT_BIT_ORDER_MISMATCH
|
|
|
-+#endif
|
|
|
-+/* This is a software floating point library which can be used
|
|
|
-+ for targets without hardware floating point.
|
|
|
-+ Copyright (C) 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004
|
|
|
-+ Free Software Foundation, Inc.
|
|
|
-+
|
|
|
-+This file is free software; you can redistribute it and/or modify it
|
|
|
-+under the terms of the GNU General Public License as published by the
|
|
|
-+Free Software Foundation; either version 2, or (at your option) any
|
|
|
-+later version.
|
|
|
-+
|
|
|
-+In addition to the permissions in the GNU General Public License, the
|
|
|
-+Free Software Foundation gives you unlimited permission to link the
|
|
|
-+compiled version of this file with other programs, and to distribute
|
|
|
-+those programs without any restriction coming from the use of this
|
|
|
-+file. (The General Public License restrictions do apply in other
|
|
|
-+respects; for example, they cover modification of the file, and
|
|
|
-+distribution when not linked into another program.)
|
|
|
-+
|
|
|
-+This file is distributed in the hope that it will be useful, but
|
|
|
-+WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
-+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
-+General Public License for more details.
|
|
|
-+
|
|
|
-+You should have received a copy of the GNU General Public License
|
|
|
-+along with this program; see the file COPYING. If not, write to
|
|
|
-+the Free Software Foundation, 59 Temple Place - Suite 330,
|
|
|
-+Boston, MA 02111-1307, USA. */
|
|
|
-+
|
|
|
-+/* As a special exception, if you link this library with other files,
|
|
|
-+ some of which are compiled with GCC, to produce an executable,
|
|
|
-+ this library does not by itself cause the resulting executable
|
|
|
-+ to be covered by the GNU General Public License.
|
|
|
-+ This exception does not however invalidate any other reasons why
|
|
|
-+ the executable file might be covered by the GNU General Public License. */
|
|
|
-+
|
|
|
-+/* This implements IEEE 754 format arithmetic, but does not provide a
|
|
|
-+ mechanism for setting the rounding mode, or for generating or handling
|
|
|
-+ exceptions.
|
|
|
-+
|
|
|
-+ The original code by Steve Chamberlain, hacked by Mark Eichin and Jim
|
|
|
-+ Wilson, all of Cygnus Support. */
|
|
|
-+
|
|
|
-+/* The intended way to use this file is to make two copies, add `#define FLOAT'
|
|
|
-+ to one copy, then compile both copies and add them to libgcc.a. */
|
|
|
-+
|
|
|
-+#include "tconfig.h"
|
|
|
-+#include "coretypes.h"
|
|
|
-+#include "tm.h"
|
|
|
-+#include "config/fp-bit.h"
|
|
|
-+
|
|
|
-+/* The following macros can be defined to change the behavior of this file:
|
|
|
-+ FLOAT: Implement a `float', aka SFmode, fp library. If this is not
|
|
|
-+ defined, then this file implements a `double', aka DFmode, fp library.
|
|
|
-+ FLOAT_ONLY: Used with FLOAT, to implement a `float' only library, i.e.
|
|
|
-+ don't include float->double conversion which requires the double library.
|
|
|
-+ This is useful only for machines which can't support doubles, e.g. some
|
|
|
-+ 8-bit processors.
|
|
|
-+ CMPtype: Specify the type that floating point compares should return.
|
|
|
-+ This defaults to SItype, aka int.
|
|
|
-+ US_SOFTWARE_GOFAST: This makes all entry points use the same names as the
|
|
|
-+ US Software goFast library.
|
|
|
-+ _DEBUG_BITFLOAT: This makes debugging the code a little easier, by adding
|
|
|
-+ two integers to the FLO_union_type.
|
|
|
-+ NO_DENORMALS: Disable handling of denormals.
|
|
|
-+ NO_NANS: Disable nan and infinity handling
|
|
|
-+ SMALL_MACHINE: Useful when operations on QIs and HIs are faster
|
|
|
-+ than on an SI */
|
|
|
-+
|
|
|
-+/* We don't currently support extended floats (long doubles) on machines
|
|
|
-+ without hardware to deal with them.
|
|
|
-+
|
|
|
-+ These stubs are just to keep the linker from complaining about unresolved
|
|
|
-+ references which can be pulled in from libio & libstdc++, even if the
|
|
|
-+ user isn't using long doubles. However, they may generate an unresolved
|
|
|
-+ external to abort if abort is not used by the function, and the stubs
|
|
|
-+ are referenced from within libc, since libgcc goes before and after the
|
|
|
-+ system library. */
|
|
|
-+
|
|
|
-+#ifdef DECLARE_LIBRARY_RENAMES
|
|
|
-+ DECLARE_LIBRARY_RENAMES
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+#ifdef EXTENDED_FLOAT_STUBS
|
|
|
-+extern void abort (void);
|
|
|
-+void __extendsfxf2 (void) { abort(); }
|
|
|
-+void __extenddfxf2 (void) { abort(); }
|
|
|
-+void __truncxfdf2 (void) { abort(); }
|
|
|
-+void __truncxfsf2 (void) { abort(); }
|
|
|
-+void __fixxfsi (void) { abort(); }
|
|
|
-+void __floatsixf (void) { abort(); }
|
|
|
-+void __addxf3 (void) { abort(); }
|
|
|
-+void __subxf3 (void) { abort(); }
|
|
|
-+void __mulxf3 (void) { abort(); }
|
|
|
-+void __divxf3 (void) { abort(); }
|
|
|
-+void __negxf2 (void) { abort(); }
|
|
|
-+void __eqxf2 (void) { abort(); }
|
|
|
-+void __nexf2 (void) { abort(); }
|
|
|
-+void __gtxf2 (void) { abort(); }
|
|
|
-+void __gexf2 (void) { abort(); }
|
|
|
-+void __lexf2 (void) { abort(); }
|
|
|
-+void __ltxf2 (void) { abort(); }
|
|
|
-+
|
|
|
-+void __extendsftf2 (void) { abort(); }
|
|
|
-+void __extenddftf2 (void) { abort(); }
|
|
|
-+void __trunctfdf2 (void) { abort(); }
|
|
|
-+void __trunctfsf2 (void) { abort(); }
|
|
|
-+void __fixtfsi (void) { abort(); }
|
|
|
-+void __floatsitf (void) { abort(); }
|
|
|
-+void __addtf3 (void) { abort(); }
|
|
|
-+void __subtf3 (void) { abort(); }
|
|
|
-+void __multf3 (void) { abort(); }
|
|
|
-+void __divtf3 (void) { abort(); }
|
|
|
-+void __negtf2 (void) { abort(); }
|
|
|
-+void __eqtf2 (void) { abort(); }
|
|
|
-+void __netf2 (void) { abort(); }
|
|
|
-+void __gttf2 (void) { abort(); }
|
|
|
-+void __getf2 (void) { abort(); }
|
|
|
-+void __letf2 (void) { abort(); }
|
|
|
-+void __lttf2 (void) { abort(); }
|
|
|
-+#else /* !EXTENDED_FLOAT_STUBS, rest of file */
|
|
|
-+
|
|
|
-+/* IEEE "special" number predicates */
|
|
|
-+
|
|
|
-+#ifdef NO_NANS
|
|
|
-+
|
|
|
-+#define nan() 0
|
|
|
-+#define isnan(x) 0
|
|
|
-+#define isinf(x) 0
|
|
|
-+#else
|
|
|
-+
|
|
|
-+#if defined L_thenan_sf
|
|
|
-+const fp_number_type __thenan_sf = { CLASS_SNAN, 0, 0, {(fractype) 0} };
|
|
|
-+#elif defined L_thenan_df
|
|
|
-+const fp_number_type __thenan_df = { CLASS_SNAN, 0, 0, {(fractype) 0} };
|
|
|
-+#elif defined L_thenan_tf
|
|
|
-+const fp_number_type __thenan_tf = { CLASS_SNAN, 0, 0, {(fractype) 0} };
|
|
|
-+#elif defined TFLOAT
|
|
|
-+extern const fp_number_type __thenan_tf;
|
|
|
-+#elif defined FLOAT
|
|
|
-+extern const fp_number_type __thenan_sf;
|
|
|
-+#else
|
|
|
-+extern const fp_number_type __thenan_df;
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+INLINE
|
|
|
-+static fp_number_type *
|
|
|
-+nan (void)
|
|
|
-+{
|
|
|
-+ /* Discard the const qualifier... */
|
|
|
-+#ifdef TFLOAT
|
|
|
-+ return (fp_number_type *) (& __thenan_tf);
|
|
|
-+#elif defined FLOAT
|
|
|
-+ return (fp_number_type *) (& __thenan_sf);
|
|
|
-+#else
|
|
|
-+ return (fp_number_type *) (& __thenan_df);
|
|
|
-+#endif
|
|
|
-+}
|
|
|
-+
|
|
|
-+INLINE
|
|
|
-+static int
|
|
|
-+isnan ( fp_number_type * x)
|
|
|
-+{
|
|
|
-+ return x->class == CLASS_SNAN || x->class == CLASS_QNAN;
|
|
|
-+}
|
|
|
-+
|
|
|
-+INLINE
|
|
|
-+static int
|
|
|
-+isinf ( fp_number_type * x)
|
|
|
-+{
|
|
|
-+ return x->class == CLASS_INFINITY;
|
|
|
-+}
|
|
|
-+
|
|
|
-+#endif /* NO_NANS */
|
|
|
-+
|
|
|
-+INLINE
|
|
|
-+static int
|
|
|
-+iszero ( fp_number_type * x)
|
|
|
-+{
|
|
|
-+ return x->class == CLASS_ZERO;
|
|
|
-+}
|
|
|
-+
|
|
|
-+INLINE
|
|
|
-+static void
|
|
|
-+flip_sign ( fp_number_type * x)
|
|
|
-+{
|
|
|
-+ x->sign = !x->sign;
|
|
|
-+}
|
|
|
-+
|
|
|
-+extern FLO_type pack_d ( fp_number_type * );
|
|
|
-+
|
|
|
-+#if defined(L_pack_df) || defined(L_pack_sf) || defined(L_pack_tf)
|
|
|
-+FLO_type
|
|
|
-+pack_d ( fp_number_type * src)
|
|
|
-+{
|
|
|
-+ FLO_union_type dst;
|
|
|
-+ fractype fraction = src->fraction.ll; /* wasn't unsigned before? */
|
|
|
-+ int sign = src->sign;
|
|
|
-+ int exp = 0;
|
|
|
-+
|
|
|
-+ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && (isnan (src) || isinf (src)))
|
|
|
-+ {
|
|
|
-+ /* We can't represent these values accurately. By using the
|
|
|
-+ largest possible magnitude, we guarantee that the conversion
|
|
|
-+ of infinity is at least as big as any finite number. */
|
|
|
-+ exp = EXPMAX;
|
|
|
-+ fraction = ((fractype) 1 << FRACBITS) - 1;
|
|
|
-+ }
|
|
|
-+ else if (isnan (src))
|
|
|
-+ {
|
|
|
-+ exp = EXPMAX;
|
|
|
-+ if (src->class == CLASS_QNAN || 1)
|
|
|
-+ {
|
|
|
-+#ifdef QUIET_NAN_NEGATED
|
|
|
-+ fraction |= QUIET_NAN - 1;
|
|
|
-+#else
|
|
|
-+ fraction |= QUIET_NAN;
|
|
|
-+#endif
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ else if (isinf (src))
|
|
|
-+ {
|
|
|
-+ exp = EXPMAX;
|
|
|
-+ fraction = 0;
|
|
|
-+ }
|
|
|
-+ else if (iszero (src))
|
|
|
-+ {
|
|
|
-+ exp = 0;
|
|
|
-+ fraction = 0;
|
|
|
-+ }
|
|
|
-+ else if (fraction == 0)
|
|
|
-+ {
|
|
|
-+ exp = 0;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ if (src->normal_exp < NORMAL_EXPMIN)
|
|
|
-+ {
|
|
|
-+#ifdef NO_DENORMALS
|
|
|
-+ /* Go straight to a zero representation if denormals are not
|
|
|
-+ supported. The denormal handling would be harmless but
|
|
|
-+ isn't unnecessary. */
|
|
|
-+ exp = 0;
|
|
|
-+ fraction = 0;
|
|
|
-+#else /* NO_DENORMALS */
|
|
|
-+ /* This number's exponent is too low to fit into the bits
|
|
|
-+ available in the number, so we'll store 0 in the exponent and
|
|
|
-+ shift the fraction to the right to make up for it. */
|
|
|
-+
|
|
|
-+ int shift = NORMAL_EXPMIN - src->normal_exp;
|
|
|
-+
|
|
|
-+ exp = 0;
|
|
|
-+
|
|
|
-+ if (shift > FRAC_NBITS - NGARDS)
|
|
|
-+ {
|
|
|
-+ /* No point shifting, since it's more that 64 out. */
|
|
|
-+ fraction = 0;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ int lowbit = (fraction & (((fractype)1 << shift) - 1)) ? 1 : 0;
|
|
|
-+ fraction = (fraction >> shift) | lowbit;
|
|
|
-+ }
|
|
|
-+ if ((fraction & GARDMASK) == GARDMSB)
|
|
|
-+ {
|
|
|
-+ if ((fraction & (1 << NGARDS)))
|
|
|
-+ fraction += GARDROUND + 1;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ /* Add to the guards to round up. */
|
|
|
-+ fraction += GARDROUND;
|
|
|
-+ }
|
|
|
-+ /* Perhaps the rounding means we now need to change the
|
|
|
-+ exponent, because the fraction is no longer denormal. */
|
|
|
-+ if (fraction >= IMPLICIT_1)
|
|
|
-+ {
|
|
|
-+ exp += 1;
|
|
|
-+ }
|
|
|
-+ fraction >>= NGARDS;
|
|
|
-+#endif /* NO_DENORMALS */
|
|
|
-+ }
|
|
|
-+ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS)
|
|
|
-+ && src->normal_exp > EXPBIAS)
|
|
|
-+ {
|
|
|
-+ exp = EXPMAX;
|
|
|
-+ fraction = 0;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ exp = src->normal_exp + EXPBIAS;
|
|
|
-+ if (!ROUND_TOWARDS_ZERO)
|
|
|
-+ {
|
|
|
-+ /* IF the gard bits are the all zero, but the first, then we're
|
|
|
-+ half way between two numbers, choose the one which makes the
|
|
|
-+ lsb of the answer 0. */
|
|
|
-+ if ((fraction & GARDMASK) == GARDMSB)
|
|
|
-+ {
|
|
|
-+ if (fraction & (1 << NGARDS))
|
|
|
-+ fraction += GARDROUND + 1;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ /* Add a one to the guards to round up */
|
|
|
-+ fraction += GARDROUND;
|
|
|
-+ }
|
|
|
-+ if (fraction >= IMPLICIT_2)
|
|
|
-+ {
|
|
|
-+ fraction >>= 1;
|
|
|
-+ exp += 1;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ fraction >>= NGARDS;
|
|
|
-+
|
|
|
-+ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp > EXPMAX)
|
|
|
-+ {
|
|
|
-+ /* Saturate on overflow. */
|
|
|
-+ exp = EXPMAX;
|
|
|
-+ fraction = ((fractype) 1 << FRACBITS) - 1;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* We previously used bitfields to store the number, but this doesn't
|
|
|
-+ handle little/big endian systems conveniently, so use shifts and
|
|
|
-+ masks */
|
|
|
-+#ifdef FLOAT_BIT_ORDER_MISMATCH
|
|
|
-+ dst.bits.fraction = fraction;
|
|
|
-+ dst.bits.exp = exp;
|
|
|
-+ dst.bits.sign = sign;
|
|
|
-+#else
|
|
|
-+# if defined TFLOAT && defined HALFFRACBITS
|
|
|
-+ {
|
|
|
-+ halffractype high, low, unity;
|
|
|
-+ int lowsign, lowexp;
|
|
|
-+
|
|
|
-+ unity = (halffractype) 1 << HALFFRACBITS;
|
|
|
-+
|
|
|
-+ /* Set HIGH to the high double's significand, masking out the implicit 1.
|
|
|
-+ Set LOW to the low double's full significand. */
|
|
|
-+ high = (fraction >> (FRACBITS - HALFFRACBITS)) & (unity - 1);
|
|
|
-+ low = fraction & (unity * 2 - 1);
|
|
|
-+
|
|
|
-+ /* Get the initial sign and exponent of the low double. */
|
|
|
-+ lowexp = exp - HALFFRACBITS - 1;
|
|
|
-+ lowsign = sign;
|
|
|
-+
|
|
|
-+ /* HIGH should be rounded like a normal double, making |LOW| <=
|
|
|
-+ 0.5 ULP of HIGH. Assume round-to-nearest. */
|
|
|
-+ if (exp < EXPMAX)
|
|
|
-+ if (low > unity || (low == unity && (high & 1) == 1))
|
|
|
-+ {
|
|
|
-+ /* Round HIGH up and adjust LOW to match. */
|
|
|
-+ high++;
|
|
|
-+ if (high == unity)
|
|
|
-+ {
|
|
|
-+ /* May make it infinite, but that's OK. */
|
|
|
-+ high = 0;
|
|
|
-+ exp++;
|
|
|
-+ }
|
|
|
-+ low = unity * 2 - low;
|
|
|
-+ lowsign ^= 1;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ high |= (halffractype) exp << HALFFRACBITS;
|
|
|
-+ high |= (halffractype) sign << (HALFFRACBITS + EXPBITS);
|
|
|
-+
|
|
|
-+ if (exp == EXPMAX || exp == 0 || low == 0)
|
|
|
-+ low = 0;
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ while (lowexp > 0 && low < unity)
|
|
|
-+ {
|
|
|
-+ low <<= 1;
|
|
|
-+ lowexp--;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (lowexp <= 0)
|
|
|
-+ {
|
|
|
-+ halffractype roundmsb, round;
|
|
|
-+ int shift;
|
|
|
-+
|
|
|
-+ shift = 1 - lowexp;
|
|
|
-+ roundmsb = (1 << (shift - 1));
|
|
|
-+ round = low & ((roundmsb << 1) - 1);
|
|
|
-+
|
|
|
-+ low >>= shift;
|
|
|
-+ lowexp = 0;
|
|
|
-+
|
|
|
-+ if (round > roundmsb || (round == roundmsb && (low & 1) == 1))
|
|
|
-+ {
|
|
|
-+ low++;
|
|
|
-+ if (low == unity)
|
|
|
-+ /* LOW rounds up to the smallest normal number. */
|
|
|
-+ lowexp++;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ low &= unity - 1;
|
|
|
-+ low |= (halffractype) lowexp << HALFFRACBITS;
|
|
|
-+ low |= (halffractype) lowsign << (HALFFRACBITS + EXPBITS);
|
|
|
-+ }
|
|
|
-+ dst.value_raw = ((fractype) high << HALFSHIFT) | low;
|
|
|
-+ }
|
|
|
-+# else
|
|
|
-+ dst.value_raw = fraction & ((((fractype)1) << FRACBITS) - (fractype)1);
|
|
|
-+ dst.value_raw |= ((fractype) (exp & ((1 << EXPBITS) - 1))) << FRACBITS;
|
|
|
-+ dst.value_raw |= ((fractype) (sign & 1)) << (FRACBITS | EXPBITS);
|
|
|
-+# endif
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT)
|
|
|
-+#ifdef TFLOAT
|
|
|
-+ {
|
|
|
-+ qrtrfractype tmp1 = dst.words[0];
|
|
|
-+ qrtrfractype tmp2 = dst.words[1];
|
|
|
-+ dst.words[0] = dst.words[3];
|
|
|
-+ dst.words[1] = dst.words[2];
|
|
|
-+ dst.words[2] = tmp2;
|
|
|
-+ dst.words[3] = tmp1;
|
|
|
-+ }
|
|
|
-+#else
|
|
|
-+ {
|
|
|
-+ halffractype tmp = dst.words[0];
|
|
|
-+ dst.words[0] = dst.words[1];
|
|
|
-+ dst.words[1] = tmp;
|
|
|
-+ }
|
|
|
-+#endif
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+ return dst.value;
|
|
|
-+}
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+#if defined(L_unpack_df) || defined(L_unpack_sf) || defined(L_unpack_tf)
|
|
|
-+void
|
|
|
-+unpack_d (FLO_union_type * src, fp_number_type * dst)
|
|
|
-+{
|
|
|
-+ /* We previously used bitfields to store the number, but this doesn't
|
|
|
-+ handle little/big endian systems conveniently, so use shifts and
|
|
|
-+ masks */
|
|
|
-+ fractype fraction;
|
|
|
-+ int exp;
|
|
|
-+ int sign;
|
|
|
-+
|
|
|
-+#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT)
|
|
|
-+ FLO_union_type swapped;
|
|
|
-+
|
|
|
-+#ifdef TFLOAT
|
|
|
-+ swapped.words[0] = src->words[3];
|
|
|
-+ swapped.words[1] = src->words[2];
|
|
|
-+ swapped.words[2] = src->words[1];
|
|
|
-+ swapped.words[3] = src->words[0];
|
|
|
-+#else
|
|
|
-+ swapped.words[0] = src->words[1];
|
|
|
-+ swapped.words[1] = src->words[0];
|
|
|
-+#endif
|
|
|
-+ src = &swapped;
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+#ifdef FLOAT_BIT_ORDER_MISMATCH
|
|
|
-+ fraction = src->bits.fraction;
|
|
|
-+ exp = src->bits.exp;
|
|
|
-+ sign = src->bits.sign;
|
|
|
-+#else
|
|
|
-+# if defined TFLOAT && defined HALFFRACBITS
|
|
|
-+ {
|
|
|
-+ halffractype high, low;
|
|
|
-+
|
|
|
-+ high = src->value_raw >> HALFSHIFT;
|
|
|
-+ low = src->value_raw & (((fractype)1 << HALFSHIFT) - 1);
|
|
|
-+
|
|
|
-+ fraction = high & ((((fractype)1) << HALFFRACBITS) - 1);
|
|
|
-+ fraction <<= FRACBITS - HALFFRACBITS;
|
|
|
-+ exp = ((int)(high >> HALFFRACBITS)) & ((1 << EXPBITS) - 1);
|
|
|
-+ sign = ((int)(high >> (((HALFFRACBITS + EXPBITS))))) & 1;
|
|
|
-+
|
|
|
-+ if (exp != EXPMAX && exp != 0 && low != 0)
|
|
|
-+ {
|
|
|
-+ int lowexp = ((int)(low >> HALFFRACBITS)) & ((1 << EXPBITS) - 1);
|
|
|
-+ int lowsign = ((int)(low >> (((HALFFRACBITS + EXPBITS))))) & 1;
|
|
|
-+ int shift;
|
|
|
-+ fractype xlow;
|
|
|
-+
|
|
|
-+ xlow = low & ((((fractype)1) << HALFFRACBITS) - 1);
|
|
|
-+ if (lowexp)
|
|
|
-+ xlow |= (((halffractype)1) << HALFFRACBITS);
|
|
|
-+ else
|
|
|
-+ lowexp = 1;
|
|
|
-+ shift = (FRACBITS - HALFFRACBITS) - (exp - lowexp);
|
|
|
-+ if (shift > 0)
|
|
|
-+ xlow <<= shift;
|
|
|
-+ else if (shift < 0)
|
|
|
-+ xlow >>= -shift;
|
|
|
-+ if (sign == lowsign)
|
|
|
-+ fraction += xlow;
|
|
|
-+ else if (fraction >= xlow)
|
|
|
-+ fraction -= xlow;
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ /* The high part is a power of two but the full number is lower.
|
|
|
-+ This code will leave the implicit 1 in FRACTION, but we'd
|
|
|
-+ have added that below anyway. */
|
|
|
-+ fraction = (((fractype) 1 << FRACBITS) - xlow) << 1;
|
|
|
-+ exp--;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+# else
|
|
|
-+ fraction = src->value_raw & ((((fractype)1) << FRACBITS) - 1);
|
|
|
-+ exp = ((int)(src->value_raw >> FRACBITS)) & ((1 << EXPBITS) - 1);
|
|
|
-+ sign = ((int)(src->value_raw >> (FRACBITS + EXPBITS))) & 1;
|
|
|
-+# endif
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+ dst->sign = sign;
|
|
|
-+ if (exp == 0)
|
|
|
-+ {
|
|
|
-+ /* Hmm. Looks like 0 */
|
|
|
-+ if (fraction == 0
|
|
|
-+#ifdef NO_DENORMALS
|
|
|
-+ || 1
|
|
|
-+#endif
|
|
|
-+ )
|
|
|
-+ {
|
|
|
-+ /* tastes like zero */
|
|
|
-+ dst->class = CLASS_ZERO;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ /* Zero exponent with nonzero fraction - it's denormalized,
|
|
|
-+ so there isn't a leading implicit one - we'll shift it so
|
|
|
-+ it gets one. */
|
|
|
-+ dst->normal_exp = exp - EXPBIAS + 1;
|
|
|
-+ fraction <<= NGARDS;
|
|
|
-+
|
|
|
-+ dst->class = CLASS_NUMBER;
|
|
|
-+#if 1
|
|
|
-+ while (fraction < IMPLICIT_1)
|
|
|
-+ {
|
|
|
-+ fraction <<= 1;
|
|
|
-+ dst->normal_exp--;
|
|
|
-+ }
|
|
|
-+#endif
|
|
|
-+ dst->fraction.ll = fraction;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp == EXPMAX)
|
|
|
-+ {
|
|
|
-+ /* Huge exponent*/
|
|
|
-+ if (fraction == 0)
|
|
|
-+ {
|
|
|
-+ /* Attached to a zero fraction - means infinity */
|
|
|
-+ dst->class = CLASS_INFINITY;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ /* Nonzero fraction, means nan */
|
|
|
-+#ifdef QUIET_NAN_NEGATED
|
|
|
-+ if ((fraction & QUIET_NAN) == 0)
|
|
|
-+#else
|
|
|
-+ if (fraction & QUIET_NAN)
|
|
|
-+#endif
|
|
|
-+ {
|
|
|
-+ dst->class = CLASS_QNAN;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ dst->class = CLASS_SNAN;
|
|
|
-+ }
|
|
|
-+ /* Keep the fraction part as the nan number */
|
|
|
-+ dst->fraction.ll = fraction;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ /* Nothing strange about this number */
|
|
|
-+ dst->normal_exp = exp - EXPBIAS;
|
|
|
-+ dst->class = CLASS_NUMBER;
|
|
|
-+ dst->fraction.ll = (fraction << NGARDS) | IMPLICIT_1;
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+#endif /* L_unpack_df || L_unpack_sf */
|
|
|
-+
|
|
|
-+#if defined(L_addsub_sf) || defined(L_addsub_df) || defined(L_addsub_tf)
|
|
|
-+static fp_number_type *
|
|
|
-+_fpadd_parts (fp_number_type * a,
|
|
|
-+ fp_number_type * b,
|
|
|
-+ fp_number_type * tmp)
|
|
|
-+{
|
|
|
-+ intfrac tfraction;
|
|
|
-+
|
|
|
-+ /* Put commonly used fields in local variables. */
|
|
|
-+ int a_normal_exp;
|
|
|
-+ int b_normal_exp;
|
|
|
-+ fractype a_fraction;
|
|
|
-+ fractype b_fraction;
|
|
|
-+
|
|
|
-+ if (isnan (a))
|
|
|
-+ {
|
|
|
-+ return a;
|
|
|
-+ }
|
|
|
-+ if (isnan (b))
|
|
|
-+ {
|
|
|
-+ return b;
|
|
|
-+ }
|
|
|
-+ if (isinf (a))
|
|
|
-+ {
|
|
|
-+ /* Adding infinities with opposite signs yields a NaN. */
|
|
|
-+ if (isinf (b) && a->sign != b->sign)
|
|
|
-+ return nan ();
|
|
|
-+ return a;
|
|
|
-+ }
|
|
|
-+ if (isinf (b))
|
|
|
-+ {
|
|
|
-+ return b;
|
|
|
-+ }
|
|
|
-+ if (iszero (b))
|
|
|
-+ {
|
|
|
-+ if (iszero (a))
|
|
|
-+ {
|
|
|
-+ *tmp = *a;
|
|
|
-+ tmp->sign = a->sign & b->sign;
|
|
|
-+ return tmp;
|
|
|
-+ }
|
|
|
-+ return a;
|
|
|
-+ }
|
|
|
-+ if (iszero (a))
|
|
|
-+ {
|
|
|
-+ return b;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* Got two numbers. shift the smaller and increment the exponent till
|
|
|
-+ they're the same */
|
|
|
-+ {
|
|
|
-+ int diff;
|
|
|
-+
|
|
|
-+ a_normal_exp = a->normal_exp;
|
|
|
-+ b_normal_exp = b->normal_exp;
|
|
|
-+ a_fraction = a->fraction.ll;
|
|
|
-+ b_fraction = b->fraction.ll;
|
|
|
-+
|
|
|
-+ diff = a_normal_exp - b_normal_exp;
|
|
|
-+
|
|
|
-+ if (diff < 0)
|
|
|
-+ diff = -diff;
|
|
|
-+ if (diff < FRAC_NBITS)
|
|
|
-+ {
|
|
|
-+ /* ??? This does shifts one bit at a time. Optimize. */
|
|
|
-+ while (a_normal_exp > b_normal_exp)
|
|
|
-+ {
|
|
|
-+ b_normal_exp++;
|
|
|
-+ LSHIFT (b_fraction);
|
|
|
-+ }
|
|
|
-+ while (b_normal_exp > a_normal_exp)
|
|
|
-+ {
|
|
|
-+ a_normal_exp++;
|
|
|
-+ LSHIFT (a_fraction);
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ /* Somethings's up.. choose the biggest */
|
|
|
-+ if (a_normal_exp > b_normal_exp)
|
|
|
-+ {
|
|
|
-+ b_normal_exp = a_normal_exp;
|
|
|
-+ b_fraction = 0;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ a_normal_exp = b_normal_exp;
|
|
|
-+ a_fraction = 0;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (a->sign != b->sign)
|
|
|
-+ {
|
|
|
-+ if (a->sign)
|
|
|
-+ {
|
|
|
-+ tfraction = -a_fraction + b_fraction;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ tfraction = a_fraction - b_fraction;
|
|
|
-+ }
|
|
|
-+ if (tfraction >= 0)
|
|
|
-+ {
|
|
|
-+ tmp->sign = 0;
|
|
|
-+ tmp->normal_exp = a_normal_exp;
|
|
|
-+ tmp->fraction.ll = tfraction;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ tmp->sign = 1;
|
|
|
-+ tmp->normal_exp = a_normal_exp;
|
|
|
-+ tmp->fraction.ll = -tfraction;
|
|
|
-+ }
|
|
|
-+ /* and renormalize it */
|
|
|
-+
|
|
|
-+ while (tmp->fraction.ll < IMPLICIT_1 && tmp->fraction.ll)
|
|
|
-+ {
|
|
|
-+ tmp->fraction.ll <<= 1;
|
|
|
-+ tmp->normal_exp--;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ tmp->sign = a->sign;
|
|
|
-+ tmp->normal_exp = a_normal_exp;
|
|
|
-+ tmp->fraction.ll = a_fraction + b_fraction;
|
|
|
-+ }
|
|
|
-+ tmp->class = CLASS_NUMBER;
|
|
|
-+ /* Now the fraction is added, we have to shift down to renormalize the
|
|
|
-+ number */
|
|
|
-+
|
|
|
-+ if (tmp->fraction.ll >= IMPLICIT_2)
|
|
|
-+ {
|
|
|
-+ LSHIFT (tmp->fraction.ll);
|
|
|
-+ tmp->normal_exp++;
|
|
|
-+ }
|
|
|
-+ return tmp;
|
|
|
-+
|
|
|
-+}
|
|
|
-+
|
|
|
-+FLO_type
|
|
|
-+add (FLO_type arg_a, FLO_type arg_b)
|
|
|
-+{
|
|
|
-+ fp_number_type a;
|
|
|
-+ fp_number_type b;
|
|
|
-+ fp_number_type tmp;
|
|
|
-+ fp_number_type *res;
|
|
|
-+ FLO_union_type au, bu;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ bu.value = arg_b;
|
|
|
-+
|
|
|
-+ unpack_d (&au, &a);
|
|
|
-+ unpack_d (&bu, &b);
|
|
|
-+
|
|
|
-+ res = _fpadd_parts (&a, &b, &tmp);
|
|
|
-+
|
|
|
-+ return pack_d (res);
|
|
|
-+}
|
|
|
-+
|
|
|
-+FLO_type
|
|
|
-+sub (FLO_type arg_a, FLO_type arg_b)
|
|
|
-+{
|
|
|
-+ fp_number_type a;
|
|
|
-+ fp_number_type b;
|
|
|
-+ fp_number_type tmp;
|
|
|
-+ fp_number_type *res;
|
|
|
-+ FLO_union_type au, bu;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ bu.value = arg_b;
|
|
|
-+
|
|
|
-+ unpack_d (&au, &a);
|
|
|
-+ unpack_d (&bu, &b);
|
|
|
-+
|
|
|
-+ b.sign ^= 1;
|
|
|
-+
|
|
|
-+ res = _fpadd_parts (&a, &b, &tmp);
|
|
|
-+
|
|
|
-+ return pack_d (res);
|
|
|
-+}
|
|
|
-+#endif /* L_addsub_sf || L_addsub_df */
|
|
|
-+
|
|
|
-+#if defined(L_mul_sf) || defined(L_mul_df) || defined(L_mul_tf)
|
|
|
-+static inline __attribute__ ((__always_inline__)) fp_number_type *
|
|
|
-+_fpmul_parts ( fp_number_type * a,
|
|
|
-+ fp_number_type * b,
|
|
|
-+ fp_number_type * tmp)
|
|
|
-+{
|
|
|
-+ fractype low = 0;
|
|
|
-+ fractype high = 0;
|
|
|
-+
|
|
|
-+ if (isnan (a))
|
|
|
-+ {
|
|
|
-+ a->sign = a->sign != b->sign;
|
|
|
-+ return a;
|
|
|
-+ }
|
|
|
-+ if (isnan (b))
|
|
|
-+ {
|
|
|
-+ b->sign = a->sign != b->sign;
|
|
|
-+ return b;
|
|
|
-+ }
|
|
|
-+ if (isinf (a))
|
|
|
-+ {
|
|
|
-+ if (iszero (b))
|
|
|
-+ return nan ();
|
|
|
-+ a->sign = a->sign != b->sign;
|
|
|
-+ return a;
|
|
|
-+ }
|
|
|
-+ if (isinf (b))
|
|
|
-+ {
|
|
|
-+ if (iszero (a))
|
|
|
-+ {
|
|
|
-+ return nan ();
|
|
|
-+ }
|
|
|
-+ b->sign = a->sign != b->sign;
|
|
|
-+ return b;
|
|
|
-+ }
|
|
|
-+ if (iszero (a))
|
|
|
-+ {
|
|
|
-+ a->sign = a->sign != b->sign;
|
|
|
-+ return a;
|
|
|
-+ }
|
|
|
-+ if (iszero (b))
|
|
|
-+ {
|
|
|
-+ b->sign = a->sign != b->sign;
|
|
|
-+ return b;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* Calculate the mantissa by multiplying both numbers to get a
|
|
|
-+ twice-as-wide number. */
|
|
|
-+ {
|
|
|
-+#if defined(NO_DI_MODE) || defined(TFLOAT)
|
|
|
-+ {
|
|
|
-+ fractype x = a->fraction.ll;
|
|
|
-+ fractype ylow = b->fraction.ll;
|
|
|
-+ fractype yhigh = 0;
|
|
|
-+ int bit;
|
|
|
-+
|
|
|
-+ /* ??? This does multiplies one bit at a time. Optimize. */
|
|
|
-+ for (bit = 0; bit < FRAC_NBITS; bit++)
|
|
|
-+ {
|
|
|
-+ int carry;
|
|
|
-+
|
|
|
-+ if (x & 1)
|
|
|
-+ {
|
|
|
-+ carry = (low += ylow) < ylow;
|
|
|
-+ high += yhigh + carry;
|
|
|
-+ }
|
|
|
-+ yhigh <<= 1;
|
|
|
-+ if (ylow & FRACHIGH)
|
|
|
-+ {
|
|
|
-+ yhigh |= 1;
|
|
|
-+ }
|
|
|
-+ ylow <<= 1;
|
|
|
-+ x >>= 1;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+#elif defined(FLOAT)
|
|
|
-+ /* Multiplying two USIs to get a UDI, we're safe. */
|
|
|
-+ {
|
|
|
-+ UDItype answer = (UDItype)a->fraction.ll * (UDItype)b->fraction.ll;
|
|
|
-+
|
|
|
-+ high = answer >> BITS_PER_SI;
|
|
|
-+ low = answer;
|
|
|
-+ }
|
|
|
-+#else
|
|
|
-+ /* fractype is DImode, but we need the result to be twice as wide.
|
|
|
-+ Assuming a widening multiply from DImode to TImode is not
|
|
|
-+ available, build one by hand. */
|
|
|
-+ {
|
|
|
-+ USItype nl = a->fraction.ll;
|
|
|
-+ USItype nh = a->fraction.ll >> BITS_PER_SI;
|
|
|
-+ USItype ml = b->fraction.ll;
|
|
|
-+ USItype mh = b->fraction.ll >> BITS_PER_SI;
|
|
|
-+ UDItype pp_ll = (UDItype) ml * nl;
|
|
|
-+ UDItype pp_hl = (UDItype) mh * nl;
|
|
|
-+ UDItype pp_lh = (UDItype) ml * nh;
|
|
|
-+ UDItype pp_hh = (UDItype) mh * nh;
|
|
|
-+ UDItype res2 = 0;
|
|
|
-+ UDItype res0 = 0;
|
|
|
-+ UDItype ps_hh__ = pp_hl + pp_lh;
|
|
|
-+ if (ps_hh__ < pp_hl)
|
|
|
-+ res2 += (UDItype)1 << BITS_PER_SI;
|
|
|
-+ pp_hl = (UDItype)(USItype)ps_hh__ << BITS_PER_SI;
|
|
|
-+ res0 = pp_ll + pp_hl;
|
|
|
-+ if (res0 < pp_ll)
|
|
|
-+ res2++;
|
|
|
-+ res2 += (ps_hh__ >> BITS_PER_SI) + pp_hh;
|
|
|
-+ high = res2;
|
|
|
-+ low = res0;
|
|
|
-+ }
|
|
|
-+#endif
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ tmp->normal_exp = a->normal_exp + b->normal_exp
|
|
|
-+ + FRAC_NBITS - (FRACBITS + NGARDS);
|
|
|
-+ tmp->sign = a->sign != b->sign;
|
|
|
-+ while (high >= IMPLICIT_2)
|
|
|
-+ {
|
|
|
-+ tmp->normal_exp++;
|
|
|
-+ if (high & 1)
|
|
|
-+ {
|
|
|
-+ low >>= 1;
|
|
|
-+ low |= FRACHIGH;
|
|
|
-+ }
|
|
|
-+ high >>= 1;
|
|
|
-+ }
|
|
|
-+ while (high < IMPLICIT_1)
|
|
|
-+ {
|
|
|
-+ tmp->normal_exp--;
|
|
|
-+
|
|
|
-+ high <<= 1;
|
|
|
-+ if (low & FRACHIGH)
|
|
|
-+ high |= 1;
|
|
|
-+ low <<= 1;
|
|
|
-+ }
|
|
|
-+ /* rounding is tricky. if we only round if it won't make us round later. */
|
|
|
-+#if 0
|
|
|
-+ if (low & FRACHIGH2)
|
|
|
-+ {
|
|
|
-+ if (((high & GARDMASK) != GARDMSB)
|
|
|
-+ && (((high + 1) & GARDMASK) == GARDMSB))
|
|
|
-+ {
|
|
|
-+ /* don't round, it gets done again later. */
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ high++;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+#endif
|
|
|
-+ if (!ROUND_TOWARDS_ZERO && (high & GARDMASK) == GARDMSB)
|
|
|
-+ {
|
|
|
-+ if (high & (1 << NGARDS))
|
|
|
-+ {
|
|
|
-+ /* half way, so round to even */
|
|
|
-+ high += GARDROUND + 1;
|
|
|
-+ }
|
|
|
-+ else if (low)
|
|
|
-+ {
|
|
|
-+ /* but we really weren't half way */
|
|
|
-+ high += GARDROUND + 1;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ tmp->fraction.ll = high;
|
|
|
-+ tmp->class = CLASS_NUMBER;
|
|
|
-+ return tmp;
|
|
|
-+}
|
|
|
-+
|
|
|
-+FLO_type
|
|
|
-+multiply (FLO_type arg_a, FLO_type arg_b)
|
|
|
-+{
|
|
|
-+ fp_number_type a;
|
|
|
-+ fp_number_type b;
|
|
|
-+ fp_number_type tmp;
|
|
|
-+ fp_number_type *res;
|
|
|
-+ FLO_union_type au, bu;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ bu.value = arg_b;
|
|
|
-+
|
|
|
-+ unpack_d (&au, &a);
|
|
|
-+ unpack_d (&bu, &b);
|
|
|
-+
|
|
|
-+ res = _fpmul_parts (&a, &b, &tmp);
|
|
|
-+
|
|
|
-+ return pack_d (res);
|
|
|
-+}
|
|
|
-+#endif /* L_mul_sf || L_mul_df */
|
|
|
-+
|
|
|
-+#if defined(L_div_sf) || defined(L_div_df) || defined(L_div_tf)
|
|
|
-+static inline __attribute__ ((__always_inline__)) fp_number_type *
|
|
|
-+_fpdiv_parts (fp_number_type * a,
|
|
|
-+ fp_number_type * b)
|
|
|
-+{
|
|
|
-+ fractype bit;
|
|
|
-+ fractype numerator;
|
|
|
-+ fractype denominator;
|
|
|
-+ fractype quotient;
|
|
|
-+
|
|
|
-+ if (isnan (a))
|
|
|
-+ {
|
|
|
-+ return a;
|
|
|
-+ }
|
|
|
-+ if (isnan (b))
|
|
|
-+ {
|
|
|
-+ return b;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ a->sign = a->sign ^ b->sign;
|
|
|
-+
|
|
|
-+ if (isinf (a) || iszero (a))
|
|
|
-+ {
|
|
|
-+ if (a->class == b->class)
|
|
|
-+ return nan ();
|
|
|
-+ return a;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (isinf (b))
|
|
|
-+ {
|
|
|
-+ a->fraction.ll = 0;
|
|
|
-+ a->normal_exp = 0;
|
|
|
-+ return a;
|
|
|
-+ }
|
|
|
-+ if (iszero (b))
|
|
|
-+ {
|
|
|
-+ a->class = CLASS_INFINITY;
|
|
|
-+ return a;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* Calculate the mantissa by multiplying both 64bit numbers to get a
|
|
|
-+ 128 bit number */
|
|
|
-+ {
|
|
|
-+ /* quotient =
|
|
|
-+ ( numerator / denominator) * 2^(numerator exponent - denominator exponent)
|
|
|
-+ */
|
|
|
-+
|
|
|
-+ a->normal_exp = a->normal_exp - b->normal_exp;
|
|
|
-+ numerator = a->fraction.ll;
|
|
|
-+ denominator = b->fraction.ll;
|
|
|
-+
|
|
|
-+ if (numerator < denominator)
|
|
|
-+ {
|
|
|
-+ /* Fraction will be less than 1.0 */
|
|
|
-+ numerator *= 2;
|
|
|
-+ a->normal_exp--;
|
|
|
-+ }
|
|
|
-+ bit = IMPLICIT_1;
|
|
|
-+ quotient = 0;
|
|
|
-+ /* ??? Does divide one bit at a time. Optimize. */
|
|
|
-+ while (bit)
|
|
|
-+ {
|
|
|
-+ if (numerator >= denominator)
|
|
|
-+ {
|
|
|
-+ quotient |= bit;
|
|
|
-+ numerator -= denominator;
|
|
|
-+ }
|
|
|
-+ bit >>= 1;
|
|
|
-+ numerator *= 2;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (!ROUND_TOWARDS_ZERO && (quotient & GARDMASK) == GARDMSB)
|
|
|
-+ {
|
|
|
-+ if (quotient & (1 << NGARDS))
|
|
|
-+ {
|
|
|
-+ /* half way, so round to even */
|
|
|
-+ quotient += GARDROUND + 1;
|
|
|
-+ }
|
|
|
-+ else if (numerator)
|
|
|
-+ {
|
|
|
-+ /* but we really weren't half way, more bits exist */
|
|
|
-+ quotient += GARDROUND + 1;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ a->fraction.ll = quotient;
|
|
|
-+ return (a);
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+
|
|
|
-+FLO_type
|
|
|
-+divide (FLO_type arg_a, FLO_type arg_b)
|
|
|
-+{
|
|
|
-+ fp_number_type a;
|
|
|
-+ fp_number_type b;
|
|
|
-+ fp_number_type *res;
|
|
|
-+ FLO_union_type au, bu;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ bu.value = arg_b;
|
|
|
-+
|
|
|
-+ unpack_d (&au, &a);
|
|
|
-+ unpack_d (&bu, &b);
|
|
|
-+
|
|
|
-+ res = _fpdiv_parts (&a, &b);
|
|
|
-+
|
|
|
-+ return pack_d (res);
|
|
|
-+}
|
|
|
-+#endif /* L_div_sf || L_div_df */
|
|
|
-+
|
|
|
-+#if defined(L_fpcmp_parts_sf) || defined(L_fpcmp_parts_df) \
|
|
|
-+ || defined(L_fpcmp_parts_tf)
|
|
|
-+/* according to the demo, fpcmp returns a comparison with 0... thus
|
|
|
-+ a<b -> -1
|
|
|
-+ a==b -> 0
|
|
|
-+ a>b -> +1
|
|
|
-+ */
|
|
|
-+
|
|
|
-+int
|
|
|
-+__fpcmp_parts (fp_number_type * a, fp_number_type * b)
|
|
|
-+{
|
|
|
-+#if 0
|
|
|
-+ /* either nan -> unordered. Must be checked outside of this routine. */
|
|
|
-+ if (isnan (a) && isnan (b))
|
|
|
-+ {
|
|
|
-+ return 1; /* still unordered! */
|
|
|
-+ }
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+ if (isnan (a) || isnan (b))
|
|
|
-+ {
|
|
|
-+ return 1; /* how to indicate unordered compare? */
|
|
|
-+ }
|
|
|
-+ if (isinf (a) && isinf (b))
|
|
|
-+ {
|
|
|
-+ /* +inf > -inf, but +inf != +inf */
|
|
|
-+ /* b \a| +inf(0)| -inf(1)
|
|
|
-+ ______\+--------+--------
|
|
|
-+ +inf(0)| a==b(0)| a<b(-1)
|
|
|
-+ -------+--------+--------
|
|
|
-+ -inf(1)| a>b(1) | a==b(0)
|
|
|
-+ -------+--------+--------
|
|
|
-+ So since unordered must be nonzero, just line up the columns...
|
|
|
-+ */
|
|
|
-+ return b->sign - a->sign;
|
|
|
-+ }
|
|
|
-+ /* but not both... */
|
|
|
-+ if (isinf (a))
|
|
|
-+ {
|
|
|
-+ return a->sign ? -1 : 1;
|
|
|
-+ }
|
|
|
-+ if (isinf (b))
|
|
|
-+ {
|
|
|
-+ return b->sign ? 1 : -1;
|
|
|
-+ }
|
|
|
-+ if (iszero (a) && iszero (b))
|
|
|
-+ {
|
|
|
-+ return 0;
|
|
|
-+ }
|
|
|
-+ if (iszero (a))
|
|
|
-+ {
|
|
|
-+ return b->sign ? 1 : -1;
|
|
|
-+ }
|
|
|
-+ if (iszero (b))
|
|
|
-+ {
|
|
|
-+ return a->sign ? -1 : 1;
|
|
|
-+ }
|
|
|
-+ /* now both are "normal". */
|
|
|
-+ if (a->sign != b->sign)
|
|
|
-+ {
|
|
|
-+ /* opposite signs */
|
|
|
-+ return a->sign ? -1 : 1;
|
|
|
-+ }
|
|
|
-+ /* same sign; exponents? */
|
|
|
-+ if (a->normal_exp > b->normal_exp)
|
|
|
-+ {
|
|
|
-+ return a->sign ? -1 : 1;
|
|
|
-+ }
|
|
|
-+ if (a->normal_exp < b->normal_exp)
|
|
|
-+ {
|
|
|
-+ return a->sign ? 1 : -1;
|
|
|
-+ }
|
|
|
-+ /* same exponents; check size. */
|
|
|
-+ if (a->fraction.ll > b->fraction.ll)
|
|
|
-+ {
|
|
|
-+ return a->sign ? -1 : 1;
|
|
|
-+ }
|
|
|
-+ if (a->fraction.ll < b->fraction.ll)
|
|
|
-+ {
|
|
|
-+ return a->sign ? 1 : -1;
|
|
|
-+ }
|
|
|
-+ /* after all that, they're equal. */
|
|
|
-+ return 0;
|
|
|
-+}
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+#if defined(L_compare_sf) || defined(L_compare_df) || defined(L_compoare_tf)
|
|
|
-+CMPtype
|
|
|
-+compare (FLO_type arg_a, FLO_type arg_b)
|
|
|
-+{
|
|
|
-+ fp_number_type a;
|
|
|
-+ fp_number_type b;
|
|
|
-+ FLO_union_type au, bu;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ bu.value = arg_b;
|
|
|
-+
|
|
|
-+ unpack_d (&au, &a);
|
|
|
-+ unpack_d (&bu, &b);
|
|
|
-+
|
|
|
-+ return __fpcmp_parts (&a, &b);
|
|
|
-+}
|
|
|
-+#endif /* L_compare_sf || L_compare_df */
|
|
|
-+
|
|
|
-+#ifndef US_SOFTWARE_GOFAST
|
|
|
-+
|
|
|
-+/* These should be optimized for their specific tasks someday. */
|
|
|
-+
|
|
|
-+#if defined(L_eq_sf) || defined(L_eq_df) || defined(L_eq_tf)
|
|
|
-+CMPtype
|
|
|
-+_eq_f2 (FLO_type arg_a, FLO_type arg_b)
|
|
|
-+{
|
|
|
-+ fp_number_type a;
|
|
|
-+ fp_number_type b;
|
|
|
-+ FLO_union_type au, bu;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ bu.value = arg_b;
|
|
|
-+
|
|
|
-+ unpack_d (&au, &a);
|
|
|
-+ unpack_d (&bu, &b);
|
|
|
-+
|
|
|
-+ if (isnan (&a) || isnan (&b))
|
|
|
-+ return 1; /* false, truth == 0 */
|
|
|
-+
|
|
|
-+ return __fpcmp_parts (&a, &b) ;
|
|
|
-+}
|
|
|
-+#endif /* L_eq_sf || L_eq_df */
|
|
|
-+
|
|
|
-+#if defined(L_ne_sf) || defined(L_ne_df) || defined(L_ne_tf)
|
|
|
-+CMPtype
|
|
|
-+_ne_f2 (FLO_type arg_a, FLO_type arg_b)
|
|
|
-+{
|
|
|
-+ fp_number_type a;
|
|
|
-+ fp_number_type b;
|
|
|
-+ FLO_union_type au, bu;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ bu.value = arg_b;
|
|
|
-+
|
|
|
-+ unpack_d (&au, &a);
|
|
|
-+ unpack_d (&bu, &b);
|
|
|
-+
|
|
|
-+ if (isnan (&a) || isnan (&b))
|
|
|
-+ return 1; /* true, truth != 0 */
|
|
|
-+
|
|
|
-+ return __fpcmp_parts (&a, &b) ;
|
|
|
-+}
|
|
|
-+#endif /* L_ne_sf || L_ne_df */
|
|
|
-+
|
|
|
-+#if defined(L_gt_sf) || defined(L_gt_df) || defined(L_gt_tf)
|
|
|
-+CMPtype
|
|
|
-+_gt_f2 (FLO_type arg_a, FLO_type arg_b)
|
|
|
-+{
|
|
|
-+ fp_number_type a;
|
|
|
-+ fp_number_type b;
|
|
|
-+ FLO_union_type au, bu;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ bu.value = arg_b;
|
|
|
-+
|
|
|
-+ unpack_d (&au, &a);
|
|
|
-+ unpack_d (&bu, &b);
|
|
|
-+
|
|
|
-+ if (isnan (&a) || isnan (&b))
|
|
|
-+ return -1; /* false, truth > 0 */
|
|
|
-+
|
|
|
-+ return __fpcmp_parts (&a, &b);
|
|
|
-+}
|
|
|
-+#endif /* L_gt_sf || L_gt_df */
|
|
|
-+
|
|
|
-+#if defined(L_ge_sf) || defined(L_ge_df) || defined(L_ge_tf)
|
|
|
-+CMPtype
|
|
|
-+_ge_f2 (FLO_type arg_a, FLO_type arg_b)
|
|
|
-+{
|
|
|
-+ fp_number_type a;
|
|
|
-+ fp_number_type b;
|
|
|
-+ FLO_union_type au, bu;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ bu.value = arg_b;
|
|
|
-+
|
|
|
-+ unpack_d (&au, &a);
|
|
|
-+ unpack_d (&bu, &b);
|
|
|
-+
|
|
|
-+ if (isnan (&a) || isnan (&b))
|
|
|
-+ return -1; /* false, truth >= 0 */
|
|
|
-+ return __fpcmp_parts (&a, &b) ;
|
|
|
-+}
|
|
|
-+#endif /* L_ge_sf || L_ge_df */
|
|
|
-+
|
|
|
-+#if defined(L_lt_sf) || defined(L_lt_df) || defined(L_lt_tf)
|
|
|
-+CMPtype
|
|
|
-+_lt_f2 (FLO_type arg_a, FLO_type arg_b)
|
|
|
-+{
|
|
|
-+ fp_number_type a;
|
|
|
-+ fp_number_type b;
|
|
|
-+ FLO_union_type au, bu;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ bu.value = arg_b;
|
|
|
-+
|
|
|
-+ unpack_d (&au, &a);
|
|
|
-+ unpack_d (&bu, &b);
|
|
|
-+
|
|
|
-+ if (isnan (&a) || isnan (&b))
|
|
|
-+ return 1; /* false, truth < 0 */
|
|
|
-+
|
|
|
-+ return __fpcmp_parts (&a, &b);
|
|
|
-+}
|
|
|
-+#endif /* L_lt_sf || L_lt_df */
|
|
|
-+
|
|
|
-+#if defined(L_le_sf) || defined(L_le_df) || defined(L_le_tf)
|
|
|
-+CMPtype
|
|
|
-+_le_f2 (FLO_type arg_a, FLO_type arg_b)
|
|
|
-+{
|
|
|
-+ fp_number_type a;
|
|
|
-+ fp_number_type b;
|
|
|
-+ FLO_union_type au, bu;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ bu.value = arg_b;
|
|
|
-+
|
|
|
-+ unpack_d (&au, &a);
|
|
|
-+ unpack_d (&bu, &b);
|
|
|
-+
|
|
|
-+ if (isnan (&a) || isnan (&b))
|
|
|
-+ return 1; /* false, truth <= 0 */
|
|
|
-+
|
|
|
-+ return __fpcmp_parts (&a, &b) ;
|
|
|
-+}
|
|
|
-+#endif /* L_le_sf || L_le_df */
|
|
|
-+
|
|
|
-+#endif /* ! US_SOFTWARE_GOFAST */
|
|
|
-+
|
|
|
-+#if defined(L_unord_sf) || defined(L_unord_df) || defined(L_unord_tf)
|
|
|
-+CMPtype
|
|
|
-+_unord_f2 (FLO_type arg_a, FLO_type arg_b)
|
|
|
-+{
|
|
|
-+ fp_number_type a;
|
|
|
-+ fp_number_type b;
|
|
|
-+ FLO_union_type au, bu;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ bu.value = arg_b;
|
|
|
-+
|
|
|
-+ unpack_d (&au, &a);
|
|
|
-+ unpack_d (&bu, &b);
|
|
|
-+
|
|
|
-+ return (isnan (&a) || isnan (&b));
|
|
|
-+}
|
|
|
-+#endif /* L_unord_sf || L_unord_df */
|
|
|
-+
|
|
|
-+#if defined(L_si_to_sf) || defined(L_si_to_df) || defined(L_si_to_tf)
|
|
|
-+FLO_type
|
|
|
-+si_to_float (SItype arg_a)
|
|
|
-+{
|
|
|
-+ fp_number_type in;
|
|
|
-+
|
|
|
-+ in.class = CLASS_NUMBER;
|
|
|
-+ in.sign = arg_a < 0;
|
|
|
-+ if (!arg_a)
|
|
|
-+ {
|
|
|
-+ in.class = CLASS_ZERO;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ in.normal_exp = FRACBITS + NGARDS;
|
|
|
-+ if (in.sign)
|
|
|
-+ {
|
|
|
-+ /* Special case for minint, since there is no +ve integer
|
|
|
-+ representation for it */
|
|
|
-+ if (arg_a == (- MAX_SI_INT - 1))
|
|
|
-+ {
|
|
|
-+ return (FLO_type)(- MAX_SI_INT - 1);
|
|
|
-+ }
|
|
|
-+ in.fraction.ll = (-arg_a);
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ in.fraction.ll = arg_a;
|
|
|
-+
|
|
|
-+ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS)))
|
|
|
-+ {
|
|
|
-+ in.fraction.ll <<= 1;
|
|
|
-+ in.normal_exp -= 1;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ return pack_d (&in);
|
|
|
-+}
|
|
|
-+#endif /* L_si_to_sf || L_si_to_df */
|
|
|
-+
|
|
|
-+#if defined(L_usi_to_sf) || defined(L_usi_to_df) || defined(L_usi_to_tf)
|
|
|
-+FLO_type
|
|
|
-+usi_to_float (USItype arg_a)
|
|
|
-+{
|
|
|
-+ fp_number_type in;
|
|
|
-+
|
|
|
-+ in.sign = 0;
|
|
|
-+ if (!arg_a)
|
|
|
-+ {
|
|
|
-+ in.class = CLASS_ZERO;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ in.class = CLASS_NUMBER;
|
|
|
-+ in.normal_exp = FRACBITS + NGARDS;
|
|
|
-+ in.fraction.ll = arg_a;
|
|
|
-+
|
|
|
-+ while (in.fraction.ll > ((fractype)1 << (FRACBITS + NGARDS)))
|
|
|
-+ {
|
|
|
-+ in.fraction.ll >>= 1;
|
|
|
-+ in.normal_exp += 1;
|
|
|
-+ }
|
|
|
-+ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS)))
|
|
|
-+ {
|
|
|
-+ in.fraction.ll <<= 1;
|
|
|
-+ in.normal_exp -= 1;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ return pack_d (&in);
|
|
|
-+}
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+#if defined(L_sf_to_si) || defined(L_df_to_si) || defined(L_tf_to_si)
|
|
|
-+SItype
|
|
|
-+float_to_si (FLO_type arg_a)
|
|
|
-+{
|
|
|
-+ fp_number_type a;
|
|
|
-+ SItype tmp;
|
|
|
-+ FLO_union_type au;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ unpack_d (&au, &a);
|
|
|
-+
|
|
|
-+ if (iszero (&a))
|
|
|
-+ return 0;
|
|
|
-+ if (isnan (&a))
|
|
|
-+ return 0;
|
|
|
-+ /* get reasonable MAX_SI_INT... */
|
|
|
-+ if (isinf (&a))
|
|
|
-+ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT;
|
|
|
-+ /* it is a number, but a small one */
|
|
|
-+ if (a.normal_exp < 0)
|
|
|
-+ return 0;
|
|
|
-+ if (a.normal_exp > BITS_PER_SI - 2)
|
|
|
-+ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT;
|
|
|
-+ tmp = a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp);
|
|
|
-+ return a.sign ? (-tmp) : (tmp);
|
|
|
-+}
|
|
|
-+#endif /* L_sf_to_si || L_df_to_si */
|
|
|
-+
|
|
|
-+#if defined(L_sf_to_usi) || defined(L_df_to_usi) || defined(L_tf_to_usi)
|
|
|
-+#if defined US_SOFTWARE_GOFAST || defined(L_tf_to_usi)
|
|
|
-+/* While libgcc2.c defines its own __fixunssfsi and __fixunsdfsi routines,
|
|
|
-+ we also define them for GOFAST because the ones in libgcc2.c have the
|
|
|
-+ wrong names and I'd rather define these here and keep GOFAST CYG-LOC's
|
|
|
-+ out of libgcc2.c. We can't define these here if not GOFAST because then
|
|
|
-+ there'd be duplicate copies. */
|
|
|
-+
|
|
|
-+USItype
|
|
|
-+float_to_usi (FLO_type arg_a)
|
|
|
-+{
|
|
|
-+ fp_number_type a;
|
|
|
-+ FLO_union_type au;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ unpack_d (&au, &a);
|
|
|
-+
|
|
|
-+ if (iszero (&a))
|
|
|
-+ return 0;
|
|
|
-+ if (isnan (&a))
|
|
|
-+ return 0;
|
|
|
-+ /* it is a negative number */
|
|
|
-+ if (a.sign)
|
|
|
-+ return 0;
|
|
|
-+ /* get reasonable MAX_USI_INT... */
|
|
|
-+ if (isinf (&a))
|
|
|
-+ return MAX_USI_INT;
|
|
|
-+ /* it is a number, but a small one */
|
|
|
-+ if (a.normal_exp < 0)
|
|
|
-+ return 0;
|
|
|
-+ if (a.normal_exp > BITS_PER_SI - 1)
|
|
|
-+ return MAX_USI_INT;
|
|
|
-+ else if (a.normal_exp > (FRACBITS + NGARDS))
|
|
|
-+ return a.fraction.ll << (a.normal_exp - (FRACBITS + NGARDS));
|
|
|
-+ else
|
|
|
-+ return a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp);
|
|
|
-+}
|
|
|
-+#endif /* US_SOFTWARE_GOFAST */
|
|
|
-+#endif /* L_sf_to_usi || L_df_to_usi */
|
|
|
-+
|
|
|
-+#if defined(L_negate_sf) || defined(L_negate_df) || defined(L_negate_tf)
|
|
|
-+FLO_type
|
|
|
-+negate (FLO_type arg_a)
|
|
|
-+{
|
|
|
-+ fp_number_type a;
|
|
|
-+ FLO_union_type au;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ unpack_d (&au, &a);
|
|
|
-+
|
|
|
-+ flip_sign (&a);
|
|
|
-+ return pack_d (&a);
|
|
|
-+}
|
|
|
-+#endif /* L_negate_sf || L_negate_df */
|
|
|
-+
|
|
|
-+#ifdef FLOAT
|
|
|
-+
|
|
|
-+#if defined(L_make_sf)
|
|
|
-+SFtype
|
|
|
-+__make_fp(fp_class_type class,
|
|
|
-+ unsigned int sign,
|
|
|
-+ int exp,
|
|
|
-+ USItype frac)
|
|
|
-+{
|
|
|
-+ fp_number_type in;
|
|
|
-+
|
|
|
-+ in.class = class;
|
|
|
-+ in.sign = sign;
|
|
|
-+ in.normal_exp = exp;
|
|
|
-+ in.fraction.ll = frac;
|
|
|
-+ return pack_d (&in);
|
|
|
-+}
|
|
|
-+#endif /* L_make_sf */
|
|
|
-+
|
|
|
-+#ifndef FLOAT_ONLY
|
|
|
-+
|
|
|
-+/* This enables one to build an fp library that supports float but not double.
|
|
|
-+ Otherwise, we would get an undefined reference to __make_dp.
|
|
|
-+ This is needed for some 8-bit ports that can't handle well values that
|
|
|
-+ are 8-bytes in size, so we just don't support double for them at all. */
|
|
|
-+
|
|
|
-+#if defined(L_sf_to_df)
|
|
|
-+DFtype
|
|
|
-+sf_to_df (SFtype arg_a)
|
|
|
-+{
|
|
|
-+ fp_number_type in;
|
|
|
-+ FLO_union_type au;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ unpack_d (&au, &in);
|
|
|
-+
|
|
|
-+ return __make_dp (in.class, in.sign, in.normal_exp,
|
|
|
-+ ((UDItype) in.fraction.ll) << F_D_BITOFF);
|
|
|
-+}
|
|
|
-+#endif /* L_sf_to_df */
|
|
|
-+
|
|
|
-+#if defined(L_sf_to_tf) && defined(TMODES)
|
|
|
-+TFtype
|
|
|
-+sf_to_tf (SFtype arg_a)
|
|
|
-+{
|
|
|
-+ fp_number_type in;
|
|
|
-+ FLO_union_type au;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ unpack_d (&au, &in);
|
|
|
-+
|
|
|
-+ return __make_tp (in.class, in.sign, in.normal_exp,
|
|
|
-+ ((UTItype) in.fraction.ll) << F_T_BITOFF);
|
|
|
-+}
|
|
|
-+#endif /* L_sf_to_df */
|
|
|
-+
|
|
|
-+#endif /* ! FLOAT_ONLY */
|
|
|
-+#endif /* FLOAT */
|
|
|
-+
|
|
|
-+#ifndef FLOAT
|
|
|
-+
|
|
|
-+extern SFtype __make_fp (fp_class_type, unsigned int, int, USItype);
|
|
|
-+
|
|
|
-+#if defined(L_make_df)
|
|
|
-+DFtype
|
|
|
-+__make_dp (fp_class_type class, unsigned int sign, int exp, UDItype frac)
|
|
|
-+{
|
|
|
-+ fp_number_type in;
|
|
|
-+
|
|
|
-+ in.class = class;
|
|
|
-+ in.sign = sign;
|
|
|
-+ in.normal_exp = exp;
|
|
|
-+ in.fraction.ll = frac;
|
|
|
-+ return pack_d (&in);
|
|
|
-+}
|
|
|
-+#endif /* L_make_df */
|
|
|
-+
|
|
|
-+#if defined(L_df_to_sf)
|
|
|
-+SFtype
|
|
|
-+df_to_sf (DFtype arg_a)
|
|
|
-+{
|
|
|
-+ fp_number_type in;
|
|
|
-+ USItype sffrac;
|
|
|
-+ FLO_union_type au;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ unpack_d (&au, &in);
|
|
|
-+
|
|
|
-+ sffrac = in.fraction.ll >> F_D_BITOFF;
|
|
|
-+
|
|
|
-+ /* We set the lowest guard bit in SFFRAC if we discarded any non
|
|
|
-+ zero bits. */
|
|
|
-+ if ((in.fraction.ll & (((USItype) 1 << F_D_BITOFF) - 1)) != 0)
|
|
|
-+ sffrac |= 1;
|
|
|
-+
|
|
|
-+ return __make_fp (in.class, in.sign, in.normal_exp, sffrac);
|
|
|
-+}
|
|
|
-+#endif /* L_df_to_sf */
|
|
|
-+
|
|
|
-+#if defined(L_df_to_tf) && defined(TMODES) \
|
|
|
-+ && !defined(FLOAT) && !defined(TFLOAT)
|
|
|
-+TFtype
|
|
|
-+df_to_tf (DFtype arg_a)
|
|
|
-+{
|
|
|
-+ fp_number_type in;
|
|
|
-+ FLO_union_type au;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ unpack_d (&au, &in);
|
|
|
-+
|
|
|
-+ return __make_tp (in.class, in.sign, in.normal_exp,
|
|
|
-+ ((UTItype) in.fraction.ll) << D_T_BITOFF);
|
|
|
-+}
|
|
|
-+#endif /* L_sf_to_df */
|
|
|
-+
|
|
|
-+#ifdef TFLOAT
|
|
|
-+#if defined(L_make_tf)
|
|
|
-+TFtype
|
|
|
-+__make_tp(fp_class_type class,
|
|
|
-+ unsigned int sign,
|
|
|
-+ int exp,
|
|
|
-+ UTItype frac)
|
|
|
-+{
|
|
|
-+ fp_number_type in;
|
|
|
-+
|
|
|
-+ in.class = class;
|
|
|
-+ in.sign = sign;
|
|
|
-+ in.normal_exp = exp;
|
|
|
-+ in.fraction.ll = frac;
|
|
|
-+ return pack_d (&in);
|
|
|
-+}
|
|
|
-+#endif /* L_make_tf */
|
|
|
-+
|
|
|
-+#if defined(L_tf_to_df)
|
|
|
-+DFtype
|
|
|
-+tf_to_df (TFtype arg_a)
|
|
|
-+{
|
|
|
-+ fp_number_type in;
|
|
|
-+ UDItype sffrac;
|
|
|
-+ FLO_union_type au;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ unpack_d (&au, &in);
|
|
|
-+
|
|
|
-+ sffrac = in.fraction.ll >> D_T_BITOFF;
|
|
|
-+
|
|
|
-+ /* We set the lowest guard bit in SFFRAC if we discarded any non
|
|
|
-+ zero bits. */
|
|
|
-+ if ((in.fraction.ll & (((UTItype) 1 << D_T_BITOFF) - 1)) != 0)
|
|
|
-+ sffrac |= 1;
|
|
|
-+
|
|
|
-+ return __make_dp (in.class, in.sign, in.normal_exp, sffrac);
|
|
|
-+}
|
|
|
-+#endif /* L_tf_to_df */
|
|
|
-+
|
|
|
-+#if defined(L_tf_to_sf)
|
|
|
-+SFtype
|
|
|
-+tf_to_sf (TFtype arg_a)
|
|
|
-+{
|
|
|
-+ fp_number_type in;
|
|
|
-+ USItype sffrac;
|
|
|
-+ FLO_union_type au;
|
|
|
-+
|
|
|
-+ au.value = arg_a;
|
|
|
-+ unpack_d (&au, &in);
|
|
|
-+
|
|
|
-+ sffrac = in.fraction.ll >> F_T_BITOFF;
|
|
|
-+
|
|
|
-+ /* We set the lowest guard bit in SFFRAC if we discarded any non
|
|
|
-+ zero bits. */
|
|
|
-+ if ((in.fraction.ll & (((UTItype) 1 << F_T_BITOFF) - 1)) != 0)
|
|
|
-+ sffrac |= 1;
|
|
|
-+
|
|
|
-+ return __make_fp (in.class, in.sign, in.normal_exp, sffrac);
|
|
|
-+}
|
|
|
-+#endif /* L_tf_to_sf */
|
|
|
-+#endif /* TFLOAT */
|
|
|
-+
|
|
|
-+#endif /* ! FLOAT */
|
|
|
-+#endif /* !EXTENDED_FLOAT_STUBS */
|
|
|
-diff --git a/gcc/config/nios2/nios2-protos.h b/gcc/config/nios2/nios2-protos.h
|
|
|
-new file mode 100644
|
|
|
-index 0000000..dc75c4f
|
|
|
---- /dev/null
|
|
|
-+++ b/gcc/config/nios2/nios2-protos.h
|
|
|
-@@ -0,0 +1,78 @@
|
|
|
-+/* Subroutines for assembler code output for Altera NIOS 2G NIOS2 version.
|
|
|
-+ Copyright (C) 2003 Altera
|
|
|
-+ Contributed by Jonah Graham (jgraham@altera.com).
|
|
|
-+
|
|
|
-+This file is part of GNU CC.
|
|
|
-+
|
|
|
-+GNU CC is free software; you can redistribute it and/or modify
|
|
|
-+it under the terms of the GNU General Public License as published by
|
|
|
-+the Free Software Foundation; either version 2, or (at your option)
|
|
|
-+any later version.
|
|
|
-+
|
|
|
-+GNU CC is distributed in the hope that it will be useful,
|
|
|
-+but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
-+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
-+GNU General Public License for more details.
|
|
|
-+
|
|
|
-+You should have received a copy of the GNU General Public License
|
|
|
-+along with GNU CC; see the file COPYING. If not, write to
|
|
|
-+the Free Software Foundation, 59 Temple Place - Suite 330,
|
|
|
-+Boston, MA 02111-1307, USA. */
|
|
|
-+
|
|
|
-+extern void dump_frame_size (FILE *);
|
|
|
-+extern HOST_WIDE_INT compute_frame_size (void);
|
|
|
-+extern int nios2_initial_elimination_offset (int, int);
|
|
|
-+extern void override_options (void);
|
|
|
-+extern void optimization_options (int, int);
|
|
|
-+extern int nios2_can_use_return_insn (void);
|
|
|
-+extern void expand_prologue (void);
|
|
|
-+extern void expand_epilogue (bool);
|
|
|
-+extern void function_profiler (FILE *, int);
|
|
|
-+extern enum reg_class reg_class_from_constraint (char, const char *);
|
|
|
-+extern void nios2_register_target_pragmas (void);
|
|
|
-+
|
|
|
-+#ifdef RTX_CODE
|
|
|
-+extern int nios2_legitimate_address (rtx, enum machine_mode, int);
|
|
|
-+extern void nios2_print_operand (FILE *, rtx, int);
|
|
|
-+extern void nios2_print_operand_address (FILE *, rtx);
|
|
|
-+
|
|
|
-+extern int nios2_emit_move_sequence (rtx *, enum machine_mode);
|
|
|
-+extern int nios2_emit_expensive_div (rtx *, enum machine_mode);
|
|
|
-+
|
|
|
-+extern void gen_int_relational (enum rtx_code, rtx, rtx, rtx, rtx);
|
|
|
-+extern void gen_conditional_move (rtx *, enum machine_mode);
|
|
|
-+extern const char *asm_output_opcode (FILE *, const char *);
|
|
|
-+
|
|
|
-+/* predicates */
|
|
|
-+extern int arith_operand (rtx, enum machine_mode);
|
|
|
-+extern int uns_arith_operand (rtx, enum machine_mode);
|
|
|
-+extern int logical_operand (rtx, enum machine_mode);
|
|
|
-+extern int shift_operand (rtx, enum machine_mode);
|
|
|
-+extern int reg_or_0_operand (rtx, enum machine_mode);
|
|
|
-+extern int equality_op (rtx, enum machine_mode);
|
|
|
-+extern int custom_insn_opcode (rtx, enum machine_mode);
|
|
|
-+extern int rdwrctl_operand (rtx, enum machine_mode);
|
|
|
-+
|
|
|
-+/* custom fpu instruction output */
|
|
|
-+extern const char *nios2_output_fpu_insn_cmps (rtx, enum rtx_code);
|
|
|
-+extern const char *nios2_output_fpu_insn_cmpd (rtx, enum rtx_code);
|
|
|
-+
|
|
|
-+# ifdef HAVE_MACHINE_MODES
|
|
|
-+# if defined TREE_CODE
|
|
|
-+extern rtx function_arg (const CUMULATIVE_ARGS *, enum machine_mode, tree, int);
|
|
|
-+extern int nios2_must_pass_in_stack (enum machine_mode, tree);
|
|
|
-+extern int function_arg_partial_nregs (const CUMULATIVE_ARGS *, enum machine_mode, tree, int);
|
|
|
-+extern void function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode, tree, int);
|
|
|
-+extern int nios2_function_arg_padding (enum machine_mode, tree);
|
|
|
-+extern int nios2_block_reg_padding (enum machine_mode, tree, int);
|
|
|
-+extern void init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree, int);
|
|
|
-+extern int nios2_setup_incoming_varargs (const CUMULATIVE_ARGS *, enum machine_mode, tree, int);
|
|
|
-+
|
|
|
-+# endif /* TREE_CODE */
|
|
|
-+# endif /* HAVE_MACHINE_MODES */
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+#ifdef TREE_CODE
|
|
|
-+extern int nios2_return_in_memory (tree);
|
|
|
-+
|
|
|
-+#endif /* TREE_CODE */
|
|
|
-diff --git a/gcc/config/nios2/nios2-uclibc.h b/gcc/config/nios2/nios2-uclibc.h
|
|
|
-new file mode 100644
|
|
|
-index 0000000..af98cdd
|
|
|
---- /dev/null
|
|
|
-+++ b/gcc/config/nios2/nios2-uclibc.h
|
|
|
-@@ -0,0 +1,75 @@
|
|
|
-+#ifdef USE_UCLIBC
|
|
|
-+
|
|
|
-+#undef TARGET_SWITCHES
|
|
|
-+#define TARGET_SWITCHES \
|
|
|
-+{ \
|
|
|
-+ { "hw-div", HAS_DIV_FLAG, \
|
|
|
-+ N_("Enable DIV, DIVU") }, \
|
|
|
-+ { "no-hw-div", -HAS_DIV_FLAG, \
|
|
|
-+ N_("Disable DIV, DIVU (default)") }, \
|
|
|
-+ { "hw-mul", HAS_MUL_FLAG, \
|
|
|
-+ N_("Enable MUL instructions (default)") }, \
|
|
|
-+ { "hw-mulx", HAS_MULX_FLAG, \
|
|
|
-+ N_("Enable MULX instructions, assume fast shifter") }, \
|
|
|
-+ { "no-hw-mul", -HAS_MUL_FLAG, \
|
|
|
-+ N_("Disable MUL instructions") }, \
|
|
|
-+ { "no-hw-mulx", -HAS_MULX_FLAG, \
|
|
|
-+ N_("Disable MULX instructions, assume slow shifter (default and implied by -mno-hw-mul)") }, \
|
|
|
-+ { "fast-sw-div", FAST_SW_DIV_FLAG, \
|
|
|
-+ N_("Use table based fast divide (default at -O3)") }, \
|
|
|
-+ { "no-fast-sw-div", -FAST_SW_DIV_FLAG, \
|
|
|
-+ N_("Don't use table based fast divide ever") }, \
|
|
|
-+ { "inline-memcpy", INLINE_MEMCPY_FLAG, \
|
|
|
-+ N_("Inline small memcpy (default when optimizing)") }, \
|
|
|
-+ { "no-inline-memcpy", -INLINE_MEMCPY_FLAG, \
|
|
|
-+ N_("Don't Inline small memcpy") }, \
|
|
|
-+ { "cache-volatile", CACHE_VOLATILE_FLAG, \
|
|
|
-+ N_("Volatile accesses use non-io variants of instructions (default)") }, \
|
|
|
-+ { "no-cache-volatile", -CACHE_VOLATILE_FLAG, \
|
|
|
-+ N_("Volatile accesses use io variants of instructions") }, \
|
|
|
-+ { "bypass-cache", BYPASS_CACHE_FLAG, \
|
|
|
-+ N_("All ld/st instructins use io variants") }, \
|
|
|
-+ { "no-bypass-cache", -BYPASS_CACHE_FLAG, \
|
|
|
-+ N_("All ld/st instructins do not use io variants (default)") }, \
|
|
|
-+ { "smallc", 0, \
|
|
|
-+ N_("Link with a limited version of the C library") }, \
|
|
|
-+ { "stack-check", STACK_CHECK_FLAG, \
|
|
|
-+ N_("Enable stack limit checking.") }, \
|
|
|
-+ { "no-stack-check", -STACK_CHECK_FLAG, \
|
|
|
-+ N_("Disable stack limit checking (default).") }, \
|
|
|
-+ { "reverse-bitfields", REVERSE_BITFIELDS_FLAG, \
|
|
|
-+ N_("Reverse the order of bitfields in a struct.") }, \
|
|
|
-+ { "no-reverse-bitfields", -REVERSE_BITFIELDS_FLAG, \
|
|
|
-+ N_("Use the normal order of bitfields in a struct (default).") }, \
|
|
|
-+ { "eb", BIG_ENDIAN_FLAG, \
|
|
|
-+ N_("Use big-endian byte order") }, \
|
|
|
-+ { "el", -BIG_ENDIAN_FLAG, \
|
|
|
-+ N_("Use little-endian byte order") }, \
|
|
|
-+ { "", TARGET_DEFAULT, 0 } \
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* The GNU C++ standard library requires that these macros be defined. */
|
|
|
-+#undef CPLUSPLUS_CPP_SPEC
|
|
|
-+#define CPLUSPLUS_CPP_SPEC "-D_GNU_SOURCE %(cpp)"
|
|
|
-+
|
|
|
-+#undef LIB_SPEC
|
|
|
-+#define LIB_SPEC \
|
|
|
-+"--start-group %{msmallc: -lsmallc} %{!msmallc: -lc} -lgcc \
|
|
|
-+ %{msys-lib=*: -l%*} \
|
|
|
-+ %{!msys-lib=*: -lc} \
|
|
|
-+ --end-group \
|
|
|
-+ %{msys-lib=: %eYou need a library name for -msys-lib=} \
|
|
|
-+"
|
|
|
-+
|
|
|
-+#undef STARTFILE_SPEC
|
|
|
-+#define STARTFILE_SPEC \
|
|
|
-+"%{msys-crt0=*: %*} %{!msys-crt0=*: crt1%O%s} \
|
|
|
-+ %{msys-crt0=: %eYou need a C startup file for -msys-crt0=} \
|
|
|
-+ crti%O%s crtbegin%O%s \
|
|
|
-+"
|
|
|
-+
|
|
|
-+#undef ENDFILE_SPEC
|
|
|
-+#define ENDFILE_SPEC \
|
|
|
-+ " crtend%O%s crtn%O%s"
|
|
|
-+
|
|
|
-+#endif /* USE_UCLIBC */
|
|
|
-diff --git a/gcc/config/nios2/nios2.c b/gcc/config/nios2/nios2.c
|
|
|
-new file mode 100644
|
|
|
-index 0000000..8723a86
|
|
|
---- /dev/null
|
|
|
-+++ b/gcc/config/nios2/nios2.c
|
|
|
-@@ -0,0 +1,4694 @@
|
|
|
-+/* Subroutines for assembler code output for Altera NIOS 2G NIOS2 version.
|
|
|
-+ Copyright (C) 2005 Altera
|
|
|
-+ Contributed by Jonah Graham (jgraham@altera.com) and Will Reece (wreece@altera.com).
|
|
|
-+
|
|
|
-+This file is part of GNU CC.
|
|
|
-+
|
|
|
-+GNU CC is free software; you can redistribute it and/or modify
|
|
|
-+it under the terms of the GNU General Public License as published by
|
|
|
-+the Free Software Foundation; either version 2, or (at your option)
|
|
|
-+any later version.
|
|
|
-+
|
|
|
-+GNU CC is distributed in the hope that it will be useful,
|
|
|
-+but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
-+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
-+GNU General Public License for more details.
|
|
|
-+
|
|
|
-+You should have received a copy of the GNU General Public License
|
|
|
-+along with GNU CC; see the file COPYING. If not, write to
|
|
|
-+the Free Software Foundation, 59 Temple Place - Suite 330,
|
|
|
-+Boston, MA 02111-1307, USA. */
|
|
|
-+
|
|
|
-+
|
|
|
-+#include <stdio.h>
|
|
|
-+#include "config.h"
|
|
|
-+#include "system.h"
|
|
|
-+#include "coretypes.h"
|
|
|
-+#include "tm.h"
|
|
|
-+#include "rtl.h"
|
|
|
-+#include "tree.h"
|
|
|
-+#include "tm_p.h"
|
|
|
-+#include "regs.h"
|
|
|
-+#include "hard-reg-set.h"
|
|
|
-+#include "real.h"
|
|
|
-+#include "insn-config.h"
|
|
|
-+#include "conditions.h"
|
|
|
-+#include "output.h"
|
|
|
-+#include "insn-attr.h"
|
|
|
-+#include "flags.h"
|
|
|
-+#include "recog.h"
|
|
|
-+#include "expr.h"
|
|
|
-+#include "toplev.h"
|
|
|
-+#include "basic-block.h"
|
|
|
-+#include "function.h"
|
|
|
-+#include "ggc.h"
|
|
|
-+#include "reload.h"
|
|
|
-+#include "debug.h"
|
|
|
-+#include "optabs.h"
|
|
|
-+#include "target.h"
|
|
|
-+#include "target-def.h"
|
|
|
-+#include "c-pragma.h" /* for c_register_pragma */
|
|
|
-+#include "cpplib.h" /* for CPP_NUMBER */
|
|
|
-+
|
|
|
-+/* local prototypes */
|
|
|
-+static bool nios2_rtx_costs (rtx, int, int, int *);
|
|
|
-+
|
|
|
-+static void nios2_asm_function_prologue (FILE *, HOST_WIDE_INT);
|
|
|
-+static int nios2_use_dfa_pipeline_interface (void);
|
|
|
-+static int nios2_issue_rate (void);
|
|
|
-+static struct machine_function *nios2_init_machine_status (void);
|
|
|
-+static bool nios2_in_small_data_p (tree);
|
|
|
-+static rtx save_reg (int, HOST_WIDE_INT, rtx);
|
|
|
-+static rtx restore_reg (int, HOST_WIDE_INT);
|
|
|
-+static unsigned int nios2_section_type_flags (tree, const char *, int);
|
|
|
-+
|
|
|
-+/* 0 --> no #pragma seen
|
|
|
-+ 1 --> in scope of #pragma reverse_bitfields
|
|
|
-+ -1 --> in scope of #pragma no_reverse_bitfields */
|
|
|
-+static int nios2_pragma_reverse_bitfields_flag = 0;
|
|
|
-+static void nios2_pragma_reverse_bitfields (struct cpp_reader *);
|
|
|
-+static void nios2_pragma_no_reverse_bitfields (struct cpp_reader *);
|
|
|
-+static tree nios2_handle_struct_attribute (tree *, tree, tree, int, bool *);
|
|
|
-+static void nios2_insert_attributes (tree, tree *);
|
|
|
-+static bool nios2_reverse_bitfield_layout_p (tree record_type);
|
|
|
-+static void nios2_init_builtins (void);
|
|
|
-+static rtx nios2_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+static bool nios2_function_ok_for_sibcall (tree, tree);
|
|
|
-+static void nios2_encode_section_info (tree, rtx, int);
|
|
|
-+
|
|
|
-+/* Initialize the GCC target structure. */
|
|
|
-+#undef TARGET_ASM_FUNCTION_PROLOGUE
|
|
|
-+#define TARGET_ASM_FUNCTION_PROLOGUE nios2_asm_function_prologue
|
|
|
-+
|
|
|
-+#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE
|
|
|
-+#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE \
|
|
|
-+ nios2_use_dfa_pipeline_interface
|
|
|
-+#undef TARGET_SCHED_ISSUE_RATE
|
|
|
-+#define TARGET_SCHED_ISSUE_RATE nios2_issue_rate
|
|
|
-+#undef TARGET_IN_SMALL_DATA_P
|
|
|
-+#define TARGET_IN_SMALL_DATA_P nios2_in_small_data_p
|
|
|
-+#undef TARGET_ENCODE_SECTION_INFO
|
|
|
-+#define TARGET_ENCODE_SECTION_INFO nios2_encode_section_info
|
|
|
-+#undef TARGET_SECTION_TYPE_FLAGS
|
|
|
-+#define TARGET_SECTION_TYPE_FLAGS nios2_section_type_flags
|
|
|
-+
|
|
|
-+#undef TARGET_REVERSE_BITFIELD_LAYOUT_P
|
|
|
-+#define TARGET_REVERSE_BITFIELD_LAYOUT_P nios2_reverse_bitfield_layout_p
|
|
|
-+
|
|
|
-+#undef TARGET_INIT_BUILTINS
|
|
|
-+#define TARGET_INIT_BUILTINS nios2_init_builtins
|
|
|
-+#undef TARGET_EXPAND_BUILTIN
|
|
|
-+#define TARGET_EXPAND_BUILTIN nios2_expand_builtin
|
|
|
-+
|
|
|
-+#undef TARGET_FUNCTION_OK_FOR_SIBCALL
|
|
|
-+#define TARGET_FUNCTION_OK_FOR_SIBCALL nios2_function_ok_for_sibcall
|
|
|
-+
|
|
|
-+#undef TARGET_RTX_COSTS
|
|
|
-+#define TARGET_RTX_COSTS nios2_rtx_costs
|
|
|
-+
|
|
|
-+const struct attribute_spec nios2_attribute_table[] =
|
|
|
-+{
|
|
|
-+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
|
|
|
-+ { "reverse_bitfields", 0, 0, false, false, false, nios2_handle_struct_attribute },
|
|
|
-+ { "no_reverse_bitfields", 0, 0, false, false, false, nios2_handle_struct_attribute },
|
|
|
-+ { "pragma_reverse_bitfields", 0, 0, false, false, false, NULL },
|
|
|
-+ { "pragma_no_reverse_bitfields", 0, 0, false, false, false, NULL },
|
|
|
-+ { NULL, 0, 0, false, false, false, NULL }
|
|
|
-+};
|
|
|
-+
|
|
|
-+#undef TARGET_ATTRIBUTE_TABLE
|
|
|
-+#define TARGET_ATTRIBUTE_TABLE nios2_attribute_table
|
|
|
-+
|
|
|
-+#undef TARGET_INSERT_ATTRIBUTES
|
|
|
-+#define TARGET_INSERT_ATTRIBUTES nios2_insert_attributes
|
|
|
-+
|
|
|
-+/* ??? Might want to redefine TARGET_RETURN_IN_MSB here to handle
|
|
|
-+ big-endian case; depends on what ABI we choose. */
|
|
|
-+
|
|
|
-+struct gcc_target targetm = TARGET_INITIALIZER;
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+/* Threshold for data being put into the small data/bss area, instead
|
|
|
-+ of the normal data area (references to the small data/bss area take
|
|
|
-+ 1 instruction, and use the global pointer, references to the normal
|
|
|
-+ data area takes 2 instructions). */
|
|
|
-+unsigned HOST_WIDE_INT nios2_section_threshold = NIOS2_DEFAULT_GVALUE;
|
|
|
-+
|
|
|
-+
|
|
|
-+/* Structure to be filled in by compute_frame_size with register
|
|
|
-+ save masks, and offsets for the current function. */
|
|
|
-+
|
|
|
-+struct nios2_frame_info
|
|
|
-+GTY (())
|
|
|
-+{
|
|
|
-+ long total_size; /* # bytes that the entire frame takes up */
|
|
|
-+ long var_size; /* # bytes that variables take up */
|
|
|
-+ long args_size; /* # bytes that outgoing arguments take up */
|
|
|
-+ int save_reg_size; /* # bytes needed to store gp regs */
|
|
|
-+ int save_reg_rounded; /* # bytes needed to store gp regs */
|
|
|
-+ long save_regs_offset; /* offset from new sp to store gp registers */
|
|
|
-+ int initialized; /* != 0 if frame size already calculated */
|
|
|
-+ int num_regs; /* number of gp registers saved */
|
|
|
-+};
|
|
|
-+
|
|
|
-+struct machine_function
|
|
|
-+GTY (())
|
|
|
-+{
|
|
|
-+
|
|
|
-+ /* Current frame information, calculated by compute_frame_size. */
|
|
|
-+ struct nios2_frame_info frame;
|
|
|
-+};
|
|
|
-+
|
|
|
-+
|
|
|
-+/***************************************
|
|
|
-+ * Register Classes
|
|
|
-+ ***************************************/
|
|
|
-+
|
|
|
-+enum reg_class
|
|
|
-+reg_class_from_constraint (char chr, const char *str)
|
|
|
-+{
|
|
|
-+ if (chr == 'D' && ISDIGIT (str[1]) && ISDIGIT (str[2]))
|
|
|
-+ {
|
|
|
-+ int regno;
|
|
|
-+ int ones = str[2] - '0';
|
|
|
-+ int tens = str[1] - '0';
|
|
|
-+
|
|
|
-+ regno = ones + (10 * tens);
|
|
|
-+ if (regno < 0 || regno > 31)
|
|
|
-+ return NO_REGS;
|
|
|
-+
|
|
|
-+ return D00_REG + regno;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return NO_REGS;
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+/***************************************
|
|
|
-+ * Stack Layout and Calling Conventions
|
|
|
-+ ***************************************/
|
|
|
-+
|
|
|
-+
|
|
|
-+#define TOO_BIG_OFFSET(X) ((X) > ((1 << 15) - 1))
|
|
|
-+#define TEMP_REG_NUM 8
|
|
|
-+
|
|
|
-+static void
|
|
|
-+nios2_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ if (flag_verbose_asm || flag_debug_asm)
|
|
|
-+ {
|
|
|
-+ compute_frame_size ();
|
|
|
-+ dump_frame_size (file);
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+save_reg (int regno, HOST_WIDE_INT offset, rtx cfa_store_reg)
|
|
|
-+{
|
|
|
-+ rtx insn, stack_slot;
|
|
|
-+
|
|
|
-+ stack_slot = gen_rtx_PLUS (SImode,
|
|
|
-+ cfa_store_reg,
|
|
|
-+ GEN_INT (offset));
|
|
|
-+
|
|
|
-+ insn = emit_insn (gen_rtx_SET (SImode,
|
|
|
-+ gen_rtx_MEM (SImode, stack_slot),
|
|
|
-+ gen_rtx_REG (SImode, regno)));
|
|
|
-+
|
|
|
-+ RTX_FRAME_RELATED_P (insn) = 1;
|
|
|
-+
|
|
|
-+ return insn;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+restore_reg (int regno, HOST_WIDE_INT offset)
|
|
|
-+{
|
|
|
-+ rtx insn, stack_slot;
|
|
|
-+
|
|
|
-+ if (TOO_BIG_OFFSET (offset))
|
|
|
-+ {
|
|
|
-+ stack_slot = gen_rtx_REG (SImode, TEMP_REG_NUM);
|
|
|
-+ insn = emit_insn (gen_rtx_SET (SImode,
|
|
|
-+ stack_slot,
|
|
|
-+ GEN_INT (offset)));
|
|
|
-+
|
|
|
-+ insn = emit_insn (gen_rtx_SET (SImode,
|
|
|
-+ stack_slot,
|
|
|
-+ gen_rtx_PLUS (SImode,
|
|
|
-+ stack_slot,
|
|
|
-+ stack_pointer_rtx)));
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ stack_slot = gen_rtx_PLUS (SImode,
|
|
|
-+ stack_pointer_rtx,
|
|
|
-+ GEN_INT (offset));
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ stack_slot = gen_rtx_MEM (SImode, stack_slot);
|
|
|
-+
|
|
|
-+ insn = emit_move_insn (gen_rtx_REG (SImode, regno), stack_slot);
|
|
|
-+
|
|
|
-+ return insn;
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+/* There are two possible paths for prologue expansion,
|
|
|
-+- the first is if the total frame size is < 2^15-1. In that
|
|
|
-+case all the immediates will fit into the 16-bit immediate
|
|
|
-+fields.
|
|
|
-+- the second is when the frame size is too big, in that
|
|
|
-+case an additional temporary register is used, first
|
|
|
-+as a cfa_temp to offset the sp, second as the cfa_store
|
|
|
-+register.
|
|
|
-+
|
|
|
-+See the comment above dwarf2out_frame_debug_expr in
|
|
|
-+dwarf2out.c for more explanation of the "rules."
|
|
|
-+
|
|
|
-+
|
|
|
-+Case 1:
|
|
|
-+Rule # Example Insn Effect
|
|
|
-+2 addi sp, sp, -total_frame_size cfa.reg=sp, cfa.offset=total_frame_size
|
|
|
-+ cfa_store.reg=sp, cfa_store.offset=total_frame_size
|
|
|
-+12 stw ra, offset(sp)
|
|
|
-+12 stw r16, offset(sp)
|
|
|
-+1 mov fp, sp
|
|
|
-+
|
|
|
-+Case 2:
|
|
|
-+Rule # Example Insn Effect
|
|
|
-+6 movi r8, total_frame_size cfa_temp.reg=r8, cfa_temp.offset=total_frame_size
|
|
|
-+2 sub sp, sp, r8 cfa.reg=sp, cfa.offset=total_frame_size
|
|
|
-+ cfa_store.reg=sp, cfa_store.offset=total_frame_size
|
|
|
-+5 add r8, r8, sp cfa_store.reg=r8, cfa_store.offset=0
|
|
|
-+12 stw ra, offset(r8)
|
|
|
-+12 stw r16, offset(r8)
|
|
|
-+1 mov fp, sp
|
|
|
-+
|
|
|
-+*/
|
|
|
-+
|
|
|
-+void
|
|
|
-+expand_prologue ()
|
|
|
-+{
|
|
|
-+ int i;
|
|
|
-+ HOST_WIDE_INT total_frame_size;
|
|
|
-+ int cfa_store_offset = 0;
|
|
|
-+ rtx insn;
|
|
|
-+ rtx cfa_store_reg = 0;
|
|
|
-+
|
|
|
-+ total_frame_size = compute_frame_size ();
|
|
|
-+
|
|
|
-+ if (total_frame_size)
|
|
|
-+ {
|
|
|
-+
|
|
|
-+ if (TOO_BIG_OFFSET (total_frame_size))
|
|
|
-+ {
|
|
|
-+ /* cfa_temp and cfa_store_reg are the same register,
|
|
|
-+ cfa_store_reg overwrites cfa_temp */
|
|
|
-+ cfa_store_reg = gen_rtx_REG (SImode, TEMP_REG_NUM);
|
|
|
-+ insn = emit_insn (gen_rtx_SET (SImode,
|
|
|
-+ cfa_store_reg,
|
|
|
-+ GEN_INT (total_frame_size)));
|
|
|
-+
|
|
|
-+ RTX_FRAME_RELATED_P (insn) = 1;
|
|
|
-+
|
|
|
-+
|
|
|
-+ insn = gen_rtx_SET (SImode,
|
|
|
-+ stack_pointer_rtx,
|
|
|
-+ gen_rtx_MINUS (SImode,
|
|
|
-+ stack_pointer_rtx,
|
|
|
-+ cfa_store_reg));
|
|
|
-+
|
|
|
-+ insn = emit_insn (insn);
|
|
|
-+ RTX_FRAME_RELATED_P (insn) = 1;
|
|
|
-+
|
|
|
-+
|
|
|
-+ /* if there are no registers to save, I don't need to
|
|
|
-+ create a cfa_store */
|
|
|
-+ if (cfun->machine->frame.save_reg_size)
|
|
|
-+ {
|
|
|
-+ insn = gen_rtx_SET (SImode,
|
|
|
-+ cfa_store_reg,
|
|
|
-+ gen_rtx_PLUS (SImode,
|
|
|
-+ cfa_store_reg,
|
|
|
-+ stack_pointer_rtx));
|
|
|
-+
|
|
|
-+ insn = emit_insn (insn);
|
|
|
-+ RTX_FRAME_RELATED_P (insn) = 1;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ cfa_store_offset
|
|
|
-+ = total_frame_size
|
|
|
-+ - (cfun->machine->frame.save_regs_offset
|
|
|
-+ + cfun->machine->frame.save_reg_rounded);
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ insn = gen_rtx_SET (SImode,
|
|
|
-+ stack_pointer_rtx,
|
|
|
-+ gen_rtx_PLUS (SImode,
|
|
|
-+ stack_pointer_rtx,
|
|
|
-+ GEN_INT (-total_frame_size)));
|
|
|
-+ insn = emit_insn (insn);
|
|
|
-+ RTX_FRAME_RELATED_P (insn) = 1;
|
|
|
-+
|
|
|
-+ cfa_store_reg = stack_pointer_rtx;
|
|
|
-+ cfa_store_offset
|
|
|
-+ = cfun->machine->frame.save_regs_offset
|
|
|
-+ + cfun->machine->frame.save_reg_rounded;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (current_function_limit_stack)
|
|
|
-+ {
|
|
|
-+ emit_insn (gen_stack_overflow_detect_and_trap ());
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (MUST_SAVE_REGISTER (RA_REGNO))
|
|
|
-+ {
|
|
|
-+ cfa_store_offset -= 4;
|
|
|
-+ save_reg (RA_REGNO, cfa_store_offset, cfa_store_reg);
|
|
|
-+ }
|
|
|
-+ if (MUST_SAVE_REGISTER (FP_REGNO))
|
|
|
-+ {
|
|
|
-+ cfa_store_offset -= 4;
|
|
|
-+ save_reg (FP_REGNO, cfa_store_offset, cfa_store_reg);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
|
|
|
-+ {
|
|
|
-+ if (MUST_SAVE_REGISTER (i) && i != FP_REGNO && i != RA_REGNO)
|
|
|
-+ {
|
|
|
-+ cfa_store_offset -= 4;
|
|
|
-+ save_reg (i, cfa_store_offset, cfa_store_reg);
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (frame_pointer_needed)
|
|
|
-+ {
|
|
|
-+ insn = emit_insn (gen_rtx_SET (SImode,
|
|
|
-+ gen_rtx_REG (SImode, FP_REGNO),
|
|
|
-+ gen_rtx_REG (SImode, SP_REGNO)));
|
|
|
-+
|
|
|
-+ RTX_FRAME_RELATED_P (insn) = 1;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* If we are profiling, make sure no instructions are scheduled before
|
|
|
-+ the call to mcount. */
|
|
|
-+ if (current_function_profile)
|
|
|
-+ emit_insn (gen_blockage ());
|
|
|
-+}
|
|
|
-+
|
|
|
-+void
|
|
|
-+expand_epilogue (bool sibcall_p)
|
|
|
-+{
|
|
|
-+ rtx insn;
|
|
|
-+ int i;
|
|
|
-+ HOST_WIDE_INT total_frame_size;
|
|
|
-+ int register_store_offset;
|
|
|
-+
|
|
|
-+ total_frame_size = compute_frame_size ();
|
|
|
-+
|
|
|
-+ if (!sibcall_p && nios2_can_use_return_insn ())
|
|
|
-+ {
|
|
|
-+ insn = emit_jump_insn (gen_return ());
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ emit_insn (gen_blockage ());
|
|
|
-+
|
|
|
-+ register_store_offset =
|
|
|
-+ cfun->machine->frame.save_regs_offset +
|
|
|
-+ cfun->machine->frame.save_reg_rounded;
|
|
|
-+
|
|
|
-+ if (MUST_SAVE_REGISTER (RA_REGNO))
|
|
|
-+ {
|
|
|
-+ register_store_offset -= 4;
|
|
|
-+ restore_reg (RA_REGNO, register_store_offset);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (MUST_SAVE_REGISTER (FP_REGNO))
|
|
|
-+ {
|
|
|
-+ register_store_offset -= 4;
|
|
|
-+ restore_reg (FP_REGNO, register_store_offset);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
|
|
|
-+ {
|
|
|
-+ if (MUST_SAVE_REGISTER (i) && i != FP_REGNO && i != RA_REGNO)
|
|
|
-+ {
|
|
|
-+ register_store_offset -= 4;
|
|
|
-+ restore_reg (i, register_store_offset);
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (total_frame_size)
|
|
|
-+ {
|
|
|
-+ rtx sp_adjust;
|
|
|
-+
|
|
|
-+ if (TOO_BIG_OFFSET (total_frame_size))
|
|
|
-+ {
|
|
|
-+ sp_adjust = gen_rtx_REG (SImode, TEMP_REG_NUM);
|
|
|
-+ insn = emit_insn (gen_rtx_SET (SImode,
|
|
|
-+ sp_adjust,
|
|
|
-+ GEN_INT (total_frame_size)));
|
|
|
-+
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ sp_adjust = GEN_INT (total_frame_size);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ insn = gen_rtx_SET (SImode,
|
|
|
-+ stack_pointer_rtx,
|
|
|
-+ gen_rtx_PLUS (SImode,
|
|
|
-+ stack_pointer_rtx,
|
|
|
-+ sp_adjust));
|
|
|
-+ insn = emit_insn (insn);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+
|
|
|
-+ if (!sibcall_p)
|
|
|
-+ {
|
|
|
-+ insn = emit_jump_insn (gen_return_from_epilogue (gen_rtx (REG, Pmode,
|
|
|
-+ RA_REGNO)));
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+bool
|
|
|
-+nios2_function_ok_for_sibcall (tree a ATTRIBUTE_UNUSED, tree b ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ return true;
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+/* ----------------------- *
|
|
|
-+ * Profiling
|
|
|
-+ * ----------------------- */
|
|
|
-+
|
|
|
-+void
|
|
|
-+function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ fprintf (file, "\tmov\tr8, ra\n");
|
|
|
-+ fprintf (file, "\tcall\tmcount\n");
|
|
|
-+ fprintf (file, "\tmov\tra, r8\n");
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+/***************************************
|
|
|
-+ * Stack Layout
|
|
|
-+ ***************************************/
|
|
|
-+
|
|
|
-+
|
|
|
-+void
|
|
|
-+dump_frame_size (FILE *file)
|
|
|
-+{
|
|
|
-+ fprintf (file, "\t%s Current Frame Info\n", ASM_COMMENT_START);
|
|
|
-+
|
|
|
-+ fprintf (file, "\t%s total_size = %ld\n", ASM_COMMENT_START,
|
|
|
-+ cfun->machine->frame.total_size);
|
|
|
-+ fprintf (file, "\t%s var_size = %ld\n", ASM_COMMENT_START,
|
|
|
-+ cfun->machine->frame.var_size);
|
|
|
-+ fprintf (file, "\t%s args_size = %ld\n", ASM_COMMENT_START,
|
|
|
-+ cfun->machine->frame.args_size);
|
|
|
-+ fprintf (file, "\t%s save_reg_size = %d\n", ASM_COMMENT_START,
|
|
|
-+ cfun->machine->frame.save_reg_size);
|
|
|
-+ fprintf (file, "\t%s save_reg_rounded = %d\n", ASM_COMMENT_START,
|
|
|
-+ cfun->machine->frame.save_reg_rounded);
|
|
|
-+ fprintf (file, "\t%s initialized = %d\n", ASM_COMMENT_START,
|
|
|
-+ cfun->machine->frame.initialized);
|
|
|
-+ fprintf (file, "\t%s num_regs = %d\n", ASM_COMMENT_START,
|
|
|
-+ cfun->machine->frame.num_regs);
|
|
|
-+ fprintf (file, "\t%s save_regs_offset = %ld\n", ASM_COMMENT_START,
|
|
|
-+ cfun->machine->frame.save_regs_offset);
|
|
|
-+ fprintf (file, "\t%s current_function_is_leaf = %d\n", ASM_COMMENT_START,
|
|
|
-+ current_function_is_leaf);
|
|
|
-+ fprintf (file, "\t%s frame_pointer_needed = %d\n", ASM_COMMENT_START,
|
|
|
-+ frame_pointer_needed);
|
|
|
-+ fprintf (file, "\t%s pretend_args_size = %d\n", ASM_COMMENT_START,
|
|
|
-+ current_function_pretend_args_size);
|
|
|
-+
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+/* Return the bytes needed to compute the frame pointer from the current
|
|
|
-+ stack pointer.
|
|
|
-+*/
|
|
|
-+
|
|
|
-+HOST_WIDE_INT
|
|
|
-+compute_frame_size ()
|
|
|
-+{
|
|
|
-+ unsigned int regno;
|
|
|
-+ HOST_WIDE_INT var_size; /* # of var. bytes allocated */
|
|
|
-+ HOST_WIDE_INT total_size; /* # bytes that the entire frame takes up */
|
|
|
-+ HOST_WIDE_INT save_reg_size; /* # bytes needed to store callee save regs */
|
|
|
-+ HOST_WIDE_INT save_reg_rounded;
|
|
|
-+ /* # bytes needed to store callee save regs (rounded) */
|
|
|
-+ HOST_WIDE_INT out_args_size; /* # bytes needed for outgoing args */
|
|
|
-+
|
|
|
-+ save_reg_size = 0;
|
|
|
-+ var_size = STACK_ALIGN (get_frame_size ());
|
|
|
-+ out_args_size = STACK_ALIGN (current_function_outgoing_args_size);
|
|
|
-+
|
|
|
-+ total_size = var_size + out_args_size;
|
|
|
-+
|
|
|
-+ /* Calculate space needed for gp registers. */
|
|
|
-+ for (regno = 0; regno <= FIRST_PSEUDO_REGISTER; regno++)
|
|
|
-+ {
|
|
|
-+ if (MUST_SAVE_REGISTER (regno))
|
|
|
-+ {
|
|
|
-+ save_reg_size += 4;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ save_reg_rounded = STACK_ALIGN (save_reg_size);
|
|
|
-+ total_size += save_reg_rounded;
|
|
|
-+
|
|
|
-+ total_size += STACK_ALIGN (current_function_pretend_args_size);
|
|
|
-+
|
|
|
-+ /* Save other computed information. */
|
|
|
-+ cfun->machine->frame.total_size = total_size;
|
|
|
-+ cfun->machine->frame.var_size = var_size;
|
|
|
-+ cfun->machine->frame.args_size = current_function_outgoing_args_size;
|
|
|
-+ cfun->machine->frame.save_reg_size = save_reg_size;
|
|
|
-+ cfun->machine->frame.save_reg_rounded = save_reg_rounded;
|
|
|
-+ cfun->machine->frame.initialized = reload_completed;
|
|
|
-+ cfun->machine->frame.num_regs = save_reg_size / UNITS_PER_WORD;
|
|
|
-+
|
|
|
-+ cfun->machine->frame.save_regs_offset
|
|
|
-+ = save_reg_rounded ? current_function_outgoing_args_size + var_size : 0;
|
|
|
-+
|
|
|
-+ return total_size;
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+int
|
|
|
-+nios2_initial_elimination_offset (int from, int to ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ int offset;
|
|
|
-+
|
|
|
-+ /* Set OFFSET to the offset from the stack pointer. */
|
|
|
-+ switch (from)
|
|
|
-+ {
|
|
|
-+ case FRAME_POINTER_REGNUM:
|
|
|
-+ offset = 0;
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case ARG_POINTER_REGNUM:
|
|
|
-+ compute_frame_size ();
|
|
|
-+ offset = cfun->machine->frame.total_size;
|
|
|
-+ offset -= current_function_pretend_args_size;
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case RETURN_ADDRESS_POINTER_REGNUM:
|
|
|
-+ compute_frame_size ();
|
|
|
-+ /* since the return address is always the first of the
|
|
|
-+ saved registers, return the offset to the beginning
|
|
|
-+ of the saved registers block */
|
|
|
-+ offset = cfun->machine->frame.save_regs_offset;
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ default:
|
|
|
-+ abort ();
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return offset;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Return nonzero if this function is known to have a null epilogue.
|
|
|
-+ This allows the optimizer to omit jumps to jumps if no stack
|
|
|
-+ was created. */
|
|
|
-+int
|
|
|
-+nios2_can_use_return_insn ()
|
|
|
-+{
|
|
|
-+ if (!reload_completed)
|
|
|
-+ return 0;
|
|
|
-+
|
|
|
-+ if (regs_ever_live[RA_REGNO] || current_function_profile)
|
|
|
-+ return 0;
|
|
|
-+
|
|
|
-+ if (cfun->machine->frame.initialized)
|
|
|
-+ return cfun->machine->frame.total_size == 0;
|
|
|
-+
|
|
|
-+ return compute_frame_size () == 0;
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+/***************************************
|
|
|
-+ *
|
|
|
-+ ***************************************/
|
|
|
-+
|
|
|
-+/*
|
|
|
-+ * Try to take a bit of tedium out of the __builtin_custom_<blah>
|
|
|
-+ * builtin functions, too.
|
|
|
-+ */
|
|
|
-+
|
|
|
-+#define NIOS2_FOR_ALL_CUSTOM_BUILTINS \
|
|
|
-+ NIOS2_DO_BUILTIN (N, n, n ) \
|
|
|
-+ NIOS2_DO_BUILTIN (NI, ni, nX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (NF, nf, nX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (NP, np, nX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (NII, nii, nXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (NIF, nif, nXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (NIP, nip, nXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (NFI, nfi, nXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (NFF, nff, nXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (NFP, nfp, nXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (NPI, npi, nXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (NPF, npf, nXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (NPP, npp, nXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (IN, in, Xn ) \
|
|
|
-+ NIOS2_DO_BUILTIN (INI, ini, XnX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (INF, inf, XnX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (INP, inp, XnX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (INII, inii, XnXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (INIF, inif, XnXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (INIP, inip, XnXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (INFI, infi, XnXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (INFF, inff, XnXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (INFP, infp, XnXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (INPI, inpi, XnXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (INPF, inpf, XnXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (INPP, inpp, XnXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (FN, fn, Xn ) \
|
|
|
-+ NIOS2_DO_BUILTIN (FNI, fni, XnX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (FNF, fnf, XnX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (FNP, fnp, XnX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (FNII, fnii, XnXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (FNIF, fnif, XnXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (FNIP, fnip, XnXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (FNFI, fnfi, XnXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (FNFF, fnff, XnXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (FNFP, fnfp, XnXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (FNPI, fnpi, XnXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (FNPF, fnpf, XnXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (FNPP, fnpp, XnXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (PN, pn, Xn ) \
|
|
|
-+ NIOS2_DO_BUILTIN (PNI, pni, XnX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (PNF, pnf, XnX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (PNP, pnp, XnX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (PNII, pnii, XnXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (PNIF, pnif, XnXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (PNIP, pnip, XnXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (PNFI, pnfi, XnXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (PNFF, pnff, XnXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (PNFP, pnfp, XnXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (PNPI, pnpi, XnXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (PNPF, pnpf, XnXX ) \
|
|
|
-+ NIOS2_DO_BUILTIN (PNPP, pnpp, XnXX )
|
|
|
-+
|
|
|
-+const char *nios2_sys_nosys_string; /* for -msys=nosys */
|
|
|
-+const char *nios2_sys_lib_string; /* for -msys-lib= */
|
|
|
-+const char *nios2_sys_crt0_string; /* for -msys-crt0= */
|
|
|
-+
|
|
|
-+#undef NIOS2_FPU_INSN
|
|
|
-+#define NIOS2_FPU_INSN(opt, insn, args) \
|
|
|
-+static const char *NIOS2_CONCAT (nios2_output_fpu_insn_, insn) (rtx); \
|
|
|
-+static void NIOS2_CONCAT (nios2_pragma_, insn) (struct cpp_reader *); \
|
|
|
-+static void NIOS2_CONCAT (nios2_pragma_no_, insn) (struct cpp_reader *);
|
|
|
-+NIOS2_FOR_ALL_FPU_INSNS
|
|
|
-+
|
|
|
-+nios2_fpu_info nios2_fpu_insns[nios2_fpu_max_insn] = {
|
|
|
-+#undef NIOS2_FPU_INSN
|
|
|
-+#define NIOS2_FPU_INSN(opt, insn, args) \
|
|
|
-+ { NIOS2_STRINGIFY (opt), \
|
|
|
-+ NIOS2_STRINGIFY (insn), \
|
|
|
-+ NIOS2_STRINGIFY (args), \
|
|
|
-+ 0, \
|
|
|
-+ -1, \
|
|
|
-+ NIOS2_CONCAT (nios2_output_fpu_insn_, insn), \
|
|
|
-+ "custom_" NIOS2_STRINGIFY (opt), \
|
|
|
-+ NIOS2_CONCAT (nios2_pragma_, insn), \
|
|
|
-+ "no_custom_" NIOS2_STRINGIFY (opt), \
|
|
|
-+ NIOS2_CONCAT (nios2_pragma_no_, insn), \
|
|
|
-+ 0, \
|
|
|
-+ 0, \
|
|
|
-+ 0, \
|
|
|
-+ 0, \
|
|
|
-+ 0 },
|
|
|
-+ NIOS2_FOR_ALL_FPU_INSNS
|
|
|
-+};
|
|
|
-+
|
|
|
-+const char *nios2_custom_fpu_cfg_string;
|
|
|
-+
|
|
|
-+static const char *builtin_custom_seen[256];
|
|
|
-+
|
|
|
-+static void
|
|
|
-+nios2_custom_switch (const char *parameter, int *value, const char *opt)
|
|
|
-+{
|
|
|
-+ /*
|
|
|
-+ * We only document values from 0-255, but we secretly allow -1 so
|
|
|
-+ * that the -mno-custom-<opt> switches work.
|
|
|
-+ */
|
|
|
-+ if (parameter && *parameter)
|
|
|
-+ {
|
|
|
-+ char *endptr;
|
|
|
-+ long v = strtol (parameter, &endptr, 0);
|
|
|
-+ if (*endptr)
|
|
|
-+ {
|
|
|
-+ error ("switch `-mcustom-%s' value `%s' must be a number between 0 and 255",
|
|
|
-+ opt, parameter);
|
|
|
-+ }
|
|
|
-+ if (v < -1 || v > 255)
|
|
|
-+ {
|
|
|
-+ error ("switch `-mcustom-%s' value %ld must be between 0 and 255",
|
|
|
-+ opt, v);
|
|
|
-+ }
|
|
|
-+ *value = (int)v;
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+
|
|
|
-+static void
|
|
|
-+nios2_custom_check_insns (int is_pragma)
|
|
|
-+{
|
|
|
-+ int i;
|
|
|
-+ int has_double = 0;
|
|
|
-+ int errors = 0;
|
|
|
-+ const char *ns[256];
|
|
|
-+ int ps[256];
|
|
|
-+
|
|
|
-+ for (i = 0; i < nios2_fpu_max_insn; i++)
|
|
|
-+ {
|
|
|
-+ if (nios2_fpu_insns[i].is_double && nios2_fpu_insns[i].N >= 0)
|
|
|
-+ {
|
|
|
-+ has_double = 1;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (has_double)
|
|
|
-+ {
|
|
|
-+ for (i = 0; i < nios2_fpu_max_insn; i++)
|
|
|
-+ {
|
|
|
-+ if (nios2_fpu_insns[i].needed_by_double
|
|
|
-+ && nios2_fpu_insns[i].N < 0)
|
|
|
-+ {
|
|
|
-+ if (is_pragma)
|
|
|
-+ {
|
|
|
-+ error ("either switch `-mcustom-%s' or `#pragma custom_%s' is required for double precision floating point",
|
|
|
-+ nios2_fpu_insns[i].option,
|
|
|
-+ nios2_fpu_insns[i].option);
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ error ("switch `-mcustom-%s' is required for double precision floating point",
|
|
|
-+ nios2_fpu_insns[i].option);
|
|
|
-+ }
|
|
|
-+ errors = 1;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /*
|
|
|
-+ * Warn if the user has certain exotic operations that won't get used
|
|
|
-+ * without -funsafe-math-optimizations, See expand_builtin () in
|
|
|
-+ * bulitins.c.
|
|
|
-+ */
|
|
|
-+ if (!flag_unsafe_math_optimizations)
|
|
|
-+ {
|
|
|
-+ for (i = 0; i < nios2_fpu_max_insn; i++)
|
|
|
-+ {
|
|
|
-+ if (nios2_fpu_insns[i].needs_unsafe && nios2_fpu_insns[i].N >= 0)
|
|
|
-+ {
|
|
|
-+ warning ("%s%s' has no effect unless -funsafe-math-optimizations is specified",
|
|
|
-+ is_pragma ? "`#pragma custom_" : "switch `-mcustom-",
|
|
|
-+ nios2_fpu_insns[i].option);
|
|
|
-+ /* Just one warning per function per compilation unit, please. */
|
|
|
-+ nios2_fpu_insns[i].needs_unsafe = 0;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /*
|
|
|
-+ * Warn if the user is trying to use -mcustom-fmins et. al, that won't
|
|
|
-+ * get used without -ffinite-math-only. See fold in fold () in
|
|
|
-+ * fold-const.c
|
|
|
-+ */
|
|
|
-+ if (!flag_finite_math_only)
|
|
|
-+ {
|
|
|
-+ for (i = 0; i < nios2_fpu_max_insn; i++)
|
|
|
-+ {
|
|
|
-+ if (nios2_fpu_insns[i].needs_finite && nios2_fpu_insns[i].N >= 0)
|
|
|
-+ {
|
|
|
-+ warning ("%s%s' has no effect unless -ffinite-math-only is specified",
|
|
|
-+ is_pragma ? "`#pragma custom_" : "switch `-mcustom-",
|
|
|
-+ nios2_fpu_insns[i].option);
|
|
|
-+ /* Just one warning per function per compilation unit, please. */
|
|
|
-+ nios2_fpu_insns[i].needs_finite = 0;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /*
|
|
|
-+ * Warn the user about double precision divide braindamage until we
|
|
|
-+ * can fix it properly. See the RDIV_EXPR case of expand_expr_real in
|
|
|
-+ * expr.c.
|
|
|
-+ */
|
|
|
-+ {
|
|
|
-+ static int warned = 0;
|
|
|
-+ if (flag_unsafe_math_optimizations
|
|
|
-+ && !optimize_size
|
|
|
-+ && nios2_fpu_insns[nios2_fpu_divdf3].N >= 0
|
|
|
-+ && !warned)
|
|
|
-+ {
|
|
|
-+ warning ("%s%s' behaves poorly without -Os",
|
|
|
-+ is_pragma ? "`#pragma custom_" : "switch `-mcustom-",
|
|
|
-+ nios2_fpu_insns[nios2_fpu_divdf3].option);
|
|
|
-+ warned = 1;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /*
|
|
|
-+ * The following bit of voodoo is lifted from the generated file
|
|
|
-+ * insn-opinit.c: to allow #pragmas to work properly, we have to tweak
|
|
|
-+ * the optab_table manually -- it only gets initialized once after the
|
|
|
-+ * switches are handled and before any #pragmas are seen.
|
|
|
-+ */
|
|
|
-+ if (is_pragma)
|
|
|
-+ {
|
|
|
-+ /* Only do this if the optabs have already been defined, not
|
|
|
-+ when we're handling command line switches. */
|
|
|
-+ addv_optab->handlers[SFmode].insn_code =
|
|
|
-+ add_optab->handlers[SFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ addv_optab->handlers[DFmode].insn_code =
|
|
|
-+ add_optab->handlers[DFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ subv_optab->handlers[SFmode].insn_code =
|
|
|
-+ sub_optab->handlers[SFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ subv_optab->handlers[DFmode].insn_code =
|
|
|
-+ sub_optab->handlers[DFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ smulv_optab->handlers[SFmode].insn_code =
|
|
|
-+ smul_optab->handlers[SFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ smulv_optab->handlers[DFmode].insn_code =
|
|
|
-+ smul_optab->handlers[DFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ sdiv_optab->handlers[SFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ sdiv_optab->handlers[DFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ negv_optab->handlers[SFmode].insn_code =
|
|
|
-+ neg_optab->handlers[SFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ negv_optab->handlers[DFmode].insn_code =
|
|
|
-+ neg_optab->handlers[DFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ smin_optab->handlers[SFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ smin_optab->handlers[DFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ smax_optab->handlers[SFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ smax_optab->handlers[DFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ absv_optab->handlers[SFmode].insn_code =
|
|
|
-+ abs_optab->handlers[SFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ absv_optab->handlers[DFmode].insn_code =
|
|
|
-+ abs_optab->handlers[DFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ sqrt_optab->handlers[SFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ sqrt_optab->handlers[DFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ cos_optab->handlers[SFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ cos_optab->handlers[DFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ sin_optab->handlers[SFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ sin_optab->handlers[DFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ tan_optab->handlers[SFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ tan_optab->handlers[DFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ atan_optab->handlers[SFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ atan_optab->handlers[DFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ exp_optab->handlers[SFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ exp_optab->handlers[DFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ log_optab->handlers[SFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ log_optab->handlers[DFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ sfloat_optab->handlers[SFmode][SImode].insn_code = CODE_FOR_nothing;
|
|
|
-+ sfloat_optab->handlers[DFmode][SImode].insn_code = CODE_FOR_nothing;
|
|
|
-+ ufloat_optab->handlers[SFmode][SImode].insn_code = CODE_FOR_nothing;
|
|
|
-+ ufloat_optab->handlers[DFmode][SImode].insn_code = CODE_FOR_nothing;
|
|
|
-+ sfix_optab->handlers[SImode][SFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ sfix_optab->handlers[SImode][DFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ ufix_optab->handlers[SImode][SFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ ufix_optab->handlers[SImode][DFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ sext_optab->handlers[DFmode][SFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ trunc_optab->handlers[SFmode][DFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ cmp_optab->handlers[SFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+ cmp_optab->handlers[DFmode].insn_code = CODE_FOR_nothing;
|
|
|
-+
|
|
|
-+ if (HAVE_addsf3)
|
|
|
-+ addv_optab->handlers[SFmode].insn_code =
|
|
|
-+ add_optab->handlers[SFmode].insn_code = CODE_FOR_addsf3;
|
|
|
-+ if (HAVE_adddf3)
|
|
|
-+ addv_optab->handlers[DFmode].insn_code =
|
|
|
-+ add_optab->handlers[DFmode].insn_code = CODE_FOR_adddf3;
|
|
|
-+ if (HAVE_subsf3)
|
|
|
-+ subv_optab->handlers[SFmode].insn_code =
|
|
|
-+ sub_optab->handlers[SFmode].insn_code = CODE_FOR_subsf3;
|
|
|
-+ if (HAVE_subdf3)
|
|
|
-+ subv_optab->handlers[DFmode].insn_code =
|
|
|
-+ sub_optab->handlers[DFmode].insn_code = CODE_FOR_subdf3;
|
|
|
-+ if (HAVE_mulsf3)
|
|
|
-+ smulv_optab->handlers[SFmode].insn_code =
|
|
|
-+ smul_optab->handlers[SFmode].insn_code = CODE_FOR_mulsf3;
|
|
|
-+ if (HAVE_muldf3)
|
|
|
-+ smulv_optab->handlers[DFmode].insn_code =
|
|
|
-+ smul_optab->handlers[DFmode].insn_code = CODE_FOR_muldf3;
|
|
|
-+ if (HAVE_divsf3)
|
|
|
-+ sdiv_optab->handlers[SFmode].insn_code = CODE_FOR_divsf3;
|
|
|
-+ if (HAVE_divdf3)
|
|
|
-+ sdiv_optab->handlers[DFmode].insn_code = CODE_FOR_divdf3;
|
|
|
-+ if (HAVE_negsf2)
|
|
|
-+ negv_optab->handlers[SFmode].insn_code =
|
|
|
-+ neg_optab->handlers[SFmode].insn_code = CODE_FOR_negsf2;
|
|
|
-+ if (HAVE_negdf2)
|
|
|
-+ negv_optab->handlers[DFmode].insn_code =
|
|
|
-+ neg_optab->handlers[DFmode].insn_code = CODE_FOR_negdf2;
|
|
|
-+ if (HAVE_minsf3)
|
|
|
-+ smin_optab->handlers[SFmode].insn_code = CODE_FOR_minsf3;
|
|
|
-+ if (HAVE_mindf3)
|
|
|
-+ smin_optab->handlers[DFmode].insn_code = CODE_FOR_mindf3;
|
|
|
-+ if (HAVE_maxsf3)
|
|
|
-+ smax_optab->handlers[SFmode].insn_code = CODE_FOR_maxsf3;
|
|
|
-+ if (HAVE_maxdf3)
|
|
|
-+ smax_optab->handlers[DFmode].insn_code = CODE_FOR_maxdf3;
|
|
|
-+ if (HAVE_abssf2)
|
|
|
-+ absv_optab->handlers[SFmode].insn_code =
|
|
|
-+ abs_optab->handlers[SFmode].insn_code = CODE_FOR_abssf2;
|
|
|
-+ if (HAVE_absdf2)
|
|
|
-+ absv_optab->handlers[DFmode].insn_code =
|
|
|
-+ abs_optab->handlers[DFmode].insn_code = CODE_FOR_absdf2;
|
|
|
-+ if (HAVE_sqrtsf2)
|
|
|
-+ sqrt_optab->handlers[SFmode].insn_code = CODE_FOR_sqrtsf2;
|
|
|
-+ if (HAVE_sqrtdf2)
|
|
|
-+ sqrt_optab->handlers[DFmode].insn_code = CODE_FOR_sqrtdf2;
|
|
|
-+ if (HAVE_cossf2)
|
|
|
-+ cos_optab->handlers[SFmode].insn_code = CODE_FOR_cossf2;
|
|
|
-+ if (HAVE_cosdf2)
|
|
|
-+ cos_optab->handlers[DFmode].insn_code = CODE_FOR_cosdf2;
|
|
|
-+ if (HAVE_sinsf2)
|
|
|
-+ sin_optab->handlers[SFmode].insn_code = CODE_FOR_sinsf2;
|
|
|
-+ if (HAVE_sindf2)
|
|
|
-+ sin_optab->handlers[DFmode].insn_code = CODE_FOR_sindf2;
|
|
|
-+ if (HAVE_tansf2)
|
|
|
-+ tan_optab->handlers[SFmode].insn_code = CODE_FOR_tansf2;
|
|
|
-+ if (HAVE_tandf2)
|
|
|
-+ tan_optab->handlers[DFmode].insn_code = CODE_FOR_tandf2;
|
|
|
-+ if (HAVE_atansf2)
|
|
|
-+ atan_optab->handlers[SFmode].insn_code = CODE_FOR_atansf2;
|
|
|
-+ if (HAVE_atandf2)
|
|
|
-+ atan_optab->handlers[DFmode].insn_code = CODE_FOR_atandf2;
|
|
|
-+ if (HAVE_expsf2)
|
|
|
-+ exp_optab->handlers[SFmode].insn_code = CODE_FOR_expsf2;
|
|
|
-+ if (HAVE_expdf2)
|
|
|
-+ exp_optab->handlers[DFmode].insn_code = CODE_FOR_expdf2;
|
|
|
-+ if (HAVE_logsf2)
|
|
|
-+ log_optab->handlers[SFmode].insn_code = CODE_FOR_logsf2;
|
|
|
-+ if (HAVE_logdf2)
|
|
|
-+ log_optab->handlers[DFmode].insn_code = CODE_FOR_logdf2;
|
|
|
-+ if (HAVE_floatsisf2)
|
|
|
-+ sfloat_optab->handlers[SFmode][SImode].insn_code = CODE_FOR_floatsisf2;
|
|
|
-+ if (HAVE_floatsidf2)
|
|
|
-+ sfloat_optab->handlers[DFmode][SImode].insn_code = CODE_FOR_floatsidf2;
|
|
|
-+ if (HAVE_floatunssisf2)
|
|
|
-+ ufloat_optab->handlers[SFmode][SImode].insn_code = CODE_FOR_floatunssisf2;
|
|
|
-+ if (HAVE_floatunssidf2)
|
|
|
-+ ufloat_optab->handlers[DFmode][SImode].insn_code = CODE_FOR_floatunssidf2;
|
|
|
-+ if (HAVE_fixsfsi2)
|
|
|
-+ sfix_optab->handlers[SImode][SFmode].insn_code = CODE_FOR_fixsfsi2;
|
|
|
-+ if (HAVE_fixdfsi2)
|
|
|
-+ sfix_optab->handlers[SImode][DFmode].insn_code = CODE_FOR_fixdfsi2;
|
|
|
-+ if (HAVE_fixunssfsi2)
|
|
|
-+ ufix_optab->handlers[SImode][SFmode].insn_code = CODE_FOR_fixunssfsi2;
|
|
|
-+ if (HAVE_fixunsdfsi2)
|
|
|
-+ ufix_optab->handlers[SImode][DFmode].insn_code = CODE_FOR_fixunsdfsi2;
|
|
|
-+ if (HAVE_extendsfdf2)
|
|
|
-+ sext_optab->handlers[DFmode][SFmode].insn_code = CODE_FOR_extendsfdf2;
|
|
|
-+ if (HAVE_truncdfsf2)
|
|
|
-+ trunc_optab->handlers[SFmode][DFmode].insn_code = CODE_FOR_truncdfsf2;
|
|
|
-+ if (HAVE_cmpsf)
|
|
|
-+ cmp_optab->handlers[SFmode].insn_code = CODE_FOR_cmpsf;
|
|
|
-+ if (HAVE_cmpdf)
|
|
|
-+ cmp_optab->handlers[DFmode].insn_code = CODE_FOR_cmpdf;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* Check for duplicate values of N */
|
|
|
-+ for (i = 0; i < 256; i++)
|
|
|
-+ {
|
|
|
-+ ns[i] = 0;
|
|
|
-+ ps[i] = 0;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ for (i = 0; i < nios2_fpu_max_insn; i++)
|
|
|
-+ {
|
|
|
-+ int N = nios2_fpu_insns[i].N;
|
|
|
-+ if (N >= 0)
|
|
|
-+ {
|
|
|
-+ if (ns[N])
|
|
|
-+ {
|
|
|
-+ error ("%s%s' conflicts with %s%s'",
|
|
|
-+ is_pragma ? "`#pragma custom_" : "switch `-mcustom-",
|
|
|
-+ nios2_fpu_insns[i].option,
|
|
|
-+ ps[N] ? "`#pragma custom_" : "switch `-mcustom-",
|
|
|
-+ ns[N]);
|
|
|
-+ errors = 1;
|
|
|
-+ }
|
|
|
-+ else if (builtin_custom_seen[N])
|
|
|
-+ {
|
|
|
-+ error ("call to `%s' conflicts with %s%s'",
|
|
|
-+ builtin_custom_seen[N],
|
|
|
-+ (nios2_fpu_insns[i].pragma_seen
|
|
|
-+ ? "`#pragma custom_" : "switch `-mcustom-"),
|
|
|
-+ nios2_fpu_insns[i].option);
|
|
|
-+ errors = 1;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ ns[N] = nios2_fpu_insns[i].option;
|
|
|
-+ ps[N] = nios2_fpu_insns[i].pragma_seen;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (errors)
|
|
|
-+ {
|
|
|
-+ fatal_error ("conflicting use of -mcustom switches, #pragmas, and/or __builtin_custom_ functions");
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+
|
|
|
-+static void
|
|
|
-+nios2_handle_custom_fpu_cfg (const char *cfg, int is_pragma)
|
|
|
-+{
|
|
|
-+#undef NIOS2_FPU_INSN
|
|
|
-+#define NIOS2_FPU_INSN(opt, insn, args) \
|
|
|
-+ int opt = nios2_fpu_insns[NIOS2_CONCAT (nios2_fpu_, insn)].N;
|
|
|
-+NIOS2_FOR_ALL_FPU_INSNS
|
|
|
-+
|
|
|
-+ /*
|
|
|
-+ * ??? These are just some sample possibilities. We'll change these
|
|
|
-+ * at the last minute to match the capabilities of the actual fpu.
|
|
|
-+ */
|
|
|
-+ if (!strcasecmp (cfg, "60-1"))
|
|
|
-+ {
|
|
|
-+ fmuls = 252;
|
|
|
-+ fadds = 253;
|
|
|
-+ fsubs = 254;
|
|
|
-+ flag_single_precision_constant = 1;
|
|
|
-+ }
|
|
|
-+ else if (!strcasecmp (cfg, "60-2"))
|
|
|
-+ {
|
|
|
-+ fmuls = 252;
|
|
|
-+ fadds = 253;
|
|
|
-+ fsubs = 254;
|
|
|
-+ fdivs = 255;
|
|
|
-+ flag_single_precision_constant = 1;
|
|
|
-+ }
|
|
|
-+ else if (!strcasecmp (cfg, "72-3"))
|
|
|
-+ {
|
|
|
-+ floatus = 243;
|
|
|
-+ fixsi = 244;
|
|
|
-+ floatis = 245;
|
|
|
-+ fcmpgts = 246;
|
|
|
-+ fcmples = 249;
|
|
|
-+ fcmpeqs = 250;
|
|
|
-+ fcmpnes = 251;
|
|
|
-+ fmuls = 252;
|
|
|
-+ fadds = 253;
|
|
|
-+ fsubs = 254;
|
|
|
-+ fdivs = 255;
|
|
|
-+ flag_single_precision_constant = 1;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ warning ("ignoring unrecognized %sfpu-cfg' value `%s'",
|
|
|
-+ is_pragma ? "`#pragma custom_" : "switch -mcustom-", cfg);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+#undef NIOS2_FPU_INSN
|
|
|
-+#define NIOS2_FPU_INSN(opt, insn, args) \
|
|
|
-+ nios2_fpu_insns[NIOS2_CONCAT (nios2_fpu_, insn)].N = opt;
|
|
|
-+NIOS2_FOR_ALL_FPU_INSNS
|
|
|
-+
|
|
|
-+ /* Guard against errors in the standard configurations. */
|
|
|
-+ nios2_custom_check_insns (is_pragma);
|
|
|
-+}
|
|
|
-+
|
|
|
-+void
|
|
|
-+override_options ()
|
|
|
-+{
|
|
|
-+ int i;
|
|
|
-+
|
|
|
-+ /* Function to allocate machine-dependent function status. */
|
|
|
-+ init_machine_status = &nios2_init_machine_status;
|
|
|
-+
|
|
|
-+ nios2_section_threshold
|
|
|
-+ = g_switch_set ? g_switch_value : NIOS2_DEFAULT_GVALUE;
|
|
|
-+
|
|
|
-+ if (nios2_sys_nosys_string && *nios2_sys_nosys_string)
|
|
|
-+ {
|
|
|
-+ error ("invalid option '-msys=nosys%s'", nios2_sys_nosys_string);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* If we don't have mul, we don't have mulx either! */
|
|
|
-+ if (!TARGET_HAS_MUL && TARGET_HAS_MULX)
|
|
|
-+ {
|
|
|
-+ target_flags &= ~HAS_MULX_FLAG;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* Set up for stack limit checking */
|
|
|
-+ if (TARGET_STACK_CHECK)
|
|
|
-+ {
|
|
|
-+ stack_limit_rtx = gen_rtx_REG(SImode, ET_REGNO);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ for (i = 0; i < nios2_fpu_max_insn; i++)
|
|
|
-+ {
|
|
|
-+ nios2_fpu_insns[i].is_double = (nios2_fpu_insns[i].args[0] == 'd'
|
|
|
-+ || nios2_fpu_insns[i].args[0] == 'd'
|
|
|
-+ || nios2_fpu_insns[i].args[0] == 'd');
|
|
|
-+ nios2_fpu_insns[i].needed_by_double = (i == nios2_fpu_nios2_fwrx
|
|
|
-+ || i == nios2_fpu_nios2_fwry
|
|
|
-+ || i == nios2_fpu_nios2_frdxlo
|
|
|
-+ || i == nios2_fpu_nios2_frdxhi
|
|
|
-+ || i == nios2_fpu_nios2_frdy);
|
|
|
-+ nios2_fpu_insns[i].needs_unsafe = (i == nios2_fpu_cossf2
|
|
|
-+ || i == nios2_fpu_cosdf2
|
|
|
-+ || i == nios2_fpu_sinsf2
|
|
|
-+ || i == nios2_fpu_sindf2
|
|
|
-+ || i == nios2_fpu_tansf2
|
|
|
-+ || i == nios2_fpu_tandf2
|
|
|
-+ || i == nios2_fpu_atansf2
|
|
|
-+ || i == nios2_fpu_atandf2
|
|
|
-+ || i == nios2_fpu_expsf2
|
|
|
-+ || i == nios2_fpu_expdf2
|
|
|
-+ || i == nios2_fpu_logsf2
|
|
|
-+ || i == nios2_fpu_logdf2);
|
|
|
-+ nios2_fpu_insns[i].needs_finite = (i == nios2_fpu_minsf3
|
|
|
-+ || i == nios2_fpu_maxsf3
|
|
|
-+ || i == nios2_fpu_mindf3
|
|
|
-+ || i == nios2_fpu_maxdf3);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /*
|
|
|
-+ * We haven't seen any __builtin_custom functions yet.
|
|
|
-+ */
|
|
|
-+ for (i = 0; i < 256; i++)
|
|
|
-+ {
|
|
|
-+ builtin_custom_seen[i] = 0;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /*
|
|
|
-+ * Set up default handling for floating point custom instructions.
|
|
|
-+ *
|
|
|
-+ * Putting things in this order means that the -mcustom-fpu-cfg=
|
|
|
-+ * switch will always be overridden by individual -mcustom-fadds=
|
|
|
-+ * switches, regardless of the order in which they were specified
|
|
|
-+ * on the command line. ??? Remember to document this.
|
|
|
-+ */
|
|
|
-+ if (nios2_custom_fpu_cfg_string && *nios2_custom_fpu_cfg_string)
|
|
|
-+ {
|
|
|
-+ nios2_handle_custom_fpu_cfg (nios2_custom_fpu_cfg_string, 0);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ for (i = 0; i < nios2_fpu_max_insn; i++)
|
|
|
-+ {
|
|
|
-+ nios2_custom_switch (nios2_fpu_insns[i].value,
|
|
|
-+ &nios2_fpu_insns[i].N,
|
|
|
-+ nios2_fpu_insns[i].option);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ nios2_custom_check_insns (0);
|
|
|
-+}
|
|
|
-+
|
|
|
-+void
|
|
|
-+optimization_options (int level, int size)
|
|
|
-+{
|
|
|
-+ if (level || size)
|
|
|
-+ {
|
|
|
-+ target_flags |= INLINE_MEMCPY_FLAG;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (level >= 3 && !size)
|
|
|
-+ {
|
|
|
-+ target_flags |= FAST_SW_DIV_FLAG;
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Allocate a chunk of memory for per-function machine-dependent data. */
|
|
|
-+static struct machine_function *
|
|
|
-+nios2_init_machine_status ()
|
|
|
-+{
|
|
|
-+ return ((struct machine_function *)
|
|
|
-+ ggc_alloc_cleared (sizeof (struct machine_function)));
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+/*****************
|
|
|
-+ * Describing Relative Costs of Operations
|
|
|
-+ *****************/
|
|
|
-+
|
|
|
-+/* Compute a (partial) cost for rtx X. Return true if the complete
|
|
|
-+ cost has been computed, and false if subexpressions should be
|
|
|
-+ scanned. In either case, *TOTAL contains the cost result. */
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+static bool
|
|
|
-+nios2_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total)
|
|
|
-+{
|
|
|
-+ switch (code)
|
|
|
-+ {
|
|
|
-+ case CONST_INT:
|
|
|
-+ if (INTVAL (x) == 0)
|
|
|
-+ {
|
|
|
-+ *total = COSTS_N_INSNS (0);
|
|
|
-+ return true;
|
|
|
-+ }
|
|
|
-+ else if (SMALL_INT (INTVAL (x))
|
|
|
-+ || SMALL_INT_UNSIGNED (INTVAL (x))
|
|
|
-+ || UPPER16_INT (INTVAL (x)))
|
|
|
-+ {
|
|
|
-+ *total = COSTS_N_INSNS (2);
|
|
|
-+ return true;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ *total = COSTS_N_INSNS (4);
|
|
|
-+ return true;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ case LABEL_REF:
|
|
|
-+ case SYMBOL_REF:
|
|
|
-+ /* ??? gp relative stuff will fit in here */
|
|
|
-+ /* fall through */
|
|
|
-+ case CONST:
|
|
|
-+ case CONST_DOUBLE:
|
|
|
-+ {
|
|
|
-+ *total = COSTS_N_INSNS (4);
|
|
|
-+ return true;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ case MULT:
|
|
|
-+ {
|
|
|
-+ *total = COSTS_N_INSNS (1);
|
|
|
-+ return false;
|
|
|
-+ }
|
|
|
-+ case SIGN_EXTEND:
|
|
|
-+ {
|
|
|
-+ *total = COSTS_N_INSNS (3);
|
|
|
-+ return false;
|
|
|
-+ }
|
|
|
-+ case ZERO_EXTEND:
|
|
|
-+ {
|
|
|
-+ *total = COSTS_N_INSNS (1);
|
|
|
-+ return false;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ default:
|
|
|
-+ return false;
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+/***************************************
|
|
|
-+ * INSTRUCTION SUPPORT
|
|
|
-+ *
|
|
|
-+ * These functions are used within the Machine Description to
|
|
|
-+ * handle common or complicated output and expansions from
|
|
|
-+ * instructions.
|
|
|
-+ ***************************************/
|
|
|
-+
|
|
|
-+int
|
|
|
-+nios2_emit_move_sequence (rtx *operands, enum machine_mode mode)
|
|
|
-+{
|
|
|
-+ rtx to = operands[0];
|
|
|
-+ rtx from = operands[1];
|
|
|
-+
|
|
|
-+ if (!register_operand (to, mode) && !reg_or_0_operand (from, mode))
|
|
|
-+ {
|
|
|
-+ if (no_new_pseudos)
|
|
|
-+ internal_error ("Trying to force_reg no_new_pseudos == 1");
|
|
|
-+ from = copy_to_mode_reg (mode, from);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ operands[0] = to;
|
|
|
-+ operands[1] = from;
|
|
|
-+ return 0;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Divide Support */
|
|
|
-+
|
|
|
-+/*
|
|
|
-+ If -O3 is used, we want to output a table lookup for
|
|
|
-+ divides between small numbers (both num and den >= 0
|
|
|
-+ and < 0x10). The overhead of this method in the worse
|
|
|
-+ case is 40 bytes in the text section (10 insns) and
|
|
|
-+ 256 bytes in the data section. Additional divides do
|
|
|
-+ not incur additional penalties in the data section.
|
|
|
-+
|
|
|
-+ Code speed is improved for small divides by about 5x
|
|
|
-+ when using this method in the worse case (~9 cycles
|
|
|
-+ vs ~45). And in the worse case divides not within the
|
|
|
-+ table are penalized by about 10% (~5 cycles vs ~45).
|
|
|
-+ However in the typical case the penalty is not as bad
|
|
|
-+ because doing the long divide in only 45 cycles is
|
|
|
-+ quite optimistic.
|
|
|
-+
|
|
|
-+ ??? It would be nice to have some benchmarks other
|
|
|
-+ than Dhrystone to back this up.
|
|
|
-+
|
|
|
-+ This bit of expansion is to create this instruction
|
|
|
-+ sequence as rtl.
|
|
|
-+ or $8, $4, $5
|
|
|
-+ slli $9, $4, 4
|
|
|
-+ cmpgeui $3, $8, 16
|
|
|
-+ beq $3, $0, .L3
|
|
|
-+ or $10, $9, $5
|
|
|
-+ add $12, $11, divide_table
|
|
|
-+ ldbu $2, 0($12)
|
|
|
-+ br .L1
|
|
|
-+.L3:
|
|
|
-+ call slow_div
|
|
|
-+.L1:
|
|
|
-+# continue here with result in $2
|
|
|
-+
|
|
|
-+ ??? Ideally I would like the emit libcall block to contain
|
|
|
-+ all of this code, but I don't know how to do that. What it
|
|
|
-+ means is that if the divide can be eliminated, it may not
|
|
|
-+ completely disappear.
|
|
|
-+
|
|
|
-+ ??? The __divsi3_table label should ideally be moved out
|
|
|
-+ of this block and into a global. If it is placed into the
|
|
|
-+ sdata section we can save even more cycles by doing things
|
|
|
-+ gp relative.
|
|
|
-+*/
|
|
|
-+int
|
|
|
-+nios2_emit_expensive_div (rtx *operands, enum machine_mode mode)
|
|
|
-+{
|
|
|
-+ rtx or_result, shift_left_result;
|
|
|
-+ rtx lookup_value;
|
|
|
-+ rtx lab1, lab3;
|
|
|
-+ rtx insns;
|
|
|
-+ rtx libfunc;
|
|
|
-+ rtx final_result;
|
|
|
-+ rtx tmp;
|
|
|
-+
|
|
|
-+ /* it may look a little generic, but only SImode
|
|
|
-+ is supported for now */
|
|
|
-+ if (mode != SImode)
|
|
|
-+ abort ();
|
|
|
-+
|
|
|
-+ libfunc = sdiv_optab->handlers[(int) SImode].libfunc;
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+ lab1 = gen_label_rtx ();
|
|
|
-+ lab3 = gen_label_rtx ();
|
|
|
-+
|
|
|
-+ or_result = expand_simple_binop (SImode, IOR,
|
|
|
-+ operands[1], operands[2],
|
|
|
-+ 0, 0, OPTAB_LIB_WIDEN);
|
|
|
-+
|
|
|
-+ emit_cmp_and_jump_insns (or_result, GEN_INT (15), GTU, 0,
|
|
|
-+ GET_MODE (or_result), 0, lab3);
|
|
|
-+ JUMP_LABEL (get_last_insn ()) = lab3;
|
|
|
-+
|
|
|
-+ shift_left_result = expand_simple_binop (SImode, ASHIFT,
|
|
|
-+ operands[1], GEN_INT (4),
|
|
|
-+ 0, 0, OPTAB_LIB_WIDEN);
|
|
|
-+
|
|
|
-+ lookup_value = expand_simple_binop (SImode, IOR,
|
|
|
-+ shift_left_result, operands[2],
|
|
|
-+ 0, 0, OPTAB_LIB_WIDEN);
|
|
|
-+
|
|
|
-+ convert_move (operands[0],
|
|
|
-+ gen_rtx (MEM, QImode,
|
|
|
-+ gen_rtx (PLUS, SImode,
|
|
|
-+ lookup_value,
|
|
|
-+ gen_rtx_SYMBOL_REF (SImode, "__divsi3_table"))),
|
|
|
-+ 1);
|
|
|
-+
|
|
|
-+
|
|
|
-+ tmp = emit_jump_insn (gen_jump (lab1));
|
|
|
-+ JUMP_LABEL (tmp) = lab1;
|
|
|
-+ emit_barrier ();
|
|
|
-+
|
|
|
-+ emit_label (lab3);
|
|
|
-+ LABEL_NUSES (lab3) = 1;
|
|
|
-+
|
|
|
-+ start_sequence ();
|
|
|
-+ final_result = emit_library_call_value (libfunc, NULL_RTX,
|
|
|
-+ LCT_CONST, SImode, 2,
|
|
|
-+ operands[1], SImode,
|
|
|
-+ operands[2], SImode);
|
|
|
-+
|
|
|
-+
|
|
|
-+ insns = get_insns ();
|
|
|
-+ end_sequence ();
|
|
|
-+ emit_libcall_block (insns, operands[0], final_result,
|
|
|
-+ gen_rtx (DIV, SImode, operands[1], operands[2]));
|
|
|
-+
|
|
|
-+ emit_label (lab1);
|
|
|
-+ LABEL_NUSES (lab1) = 1;
|
|
|
-+ return 1;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Branches/Compares */
|
|
|
-+
|
|
|
-+/* the way of handling branches/compares
|
|
|
-+ in gcc is heavily borrowed from MIPS */
|
|
|
-+
|
|
|
-+enum internal_test
|
|
|
-+{
|
|
|
-+ ITEST_EQ,
|
|
|
-+ ITEST_NE,
|
|
|
-+ ITEST_GT,
|
|
|
-+ ITEST_GE,
|
|
|
-+ ITEST_LT,
|
|
|
-+ ITEST_LE,
|
|
|
-+ ITEST_GTU,
|
|
|
-+ ITEST_GEU,
|
|
|
-+ ITEST_LTU,
|
|
|
-+ ITEST_LEU,
|
|
|
-+ ITEST_MAX
|
|
|
-+};
|
|
|
-+
|
|
|
-+static enum internal_test map_test_to_internal_test (enum rtx_code);
|
|
|
-+
|
|
|
-+/* Cached operands, and operator to compare for use in set/branch/trap
|
|
|
-+ on condition codes. */
|
|
|
-+rtx branch_cmp[2];
|
|
|
-+enum cmp_type branch_type;
|
|
|
-+
|
|
|
-+/* Make normal rtx_code into something we can index from an array */
|
|
|
-+
|
|
|
-+static enum internal_test
|
|
|
-+map_test_to_internal_test (enum rtx_code test_code)
|
|
|
-+{
|
|
|
-+ enum internal_test test = ITEST_MAX;
|
|
|
-+
|
|
|
-+ switch (test_code)
|
|
|
-+ {
|
|
|
-+ case EQ:
|
|
|
-+ test = ITEST_EQ;
|
|
|
-+ break;
|
|
|
-+ case NE:
|
|
|
-+ test = ITEST_NE;
|
|
|
-+ break;
|
|
|
-+ case GT:
|
|
|
-+ test = ITEST_GT;
|
|
|
-+ break;
|
|
|
-+ case GE:
|
|
|
-+ test = ITEST_GE;
|
|
|
-+ break;
|
|
|
-+ case LT:
|
|
|
-+ test = ITEST_LT;
|
|
|
-+ break;
|
|
|
-+ case LE:
|
|
|
-+ test = ITEST_LE;
|
|
|
-+ break;
|
|
|
-+ case GTU:
|
|
|
-+ test = ITEST_GTU;
|
|
|
-+ break;
|
|
|
-+ case GEU:
|
|
|
-+ test = ITEST_GEU;
|
|
|
-+ break;
|
|
|
-+ case LTU:
|
|
|
-+ test = ITEST_LTU;
|
|
|
-+ break;
|
|
|
-+ case LEU:
|
|
|
-+ test = ITEST_LEU;
|
|
|
-+ break;
|
|
|
-+ default:
|
|
|
-+ break;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return test;
|
|
|
-+}
|
|
|
-+
|
|
|
-+bool have_nios2_fpu_cmp_insn( enum rtx_code cond_t, enum cmp_type cmp_t );
|
|
|
-+enum rtx_code get_reverse_cond(enum rtx_code cond_t);
|
|
|
-+
|
|
|
-+bool
|
|
|
-+have_nios2_fpu_cmp_insn( enum rtx_code cond_t, enum cmp_type cmp_t )
|
|
|
-+{
|
|
|
-+ if (cmp_t == CMP_SF)
|
|
|
-+ {
|
|
|
-+ switch (cond_t) {
|
|
|
-+ case EQ:
|
|
|
-+ return (nios2_fpu_insns[nios2_fpu_nios2_seqsf].N >= 0);
|
|
|
-+ case NE:
|
|
|
-+ return (nios2_fpu_insns[nios2_fpu_nios2_snesf].N >= 0);
|
|
|
-+ case GT:
|
|
|
-+ return (nios2_fpu_insns[nios2_fpu_nios2_sgtsf].N >= 0);
|
|
|
-+ case GE:
|
|
|
-+ return (nios2_fpu_insns[nios2_fpu_nios2_sgesf].N >= 0);
|
|
|
-+ case LT:
|
|
|
-+ return (nios2_fpu_insns[nios2_fpu_nios2_sltsf].N >= 0);
|
|
|
-+ case LE:
|
|
|
-+ return (nios2_fpu_insns[nios2_fpu_nios2_slesf].N >= 0);
|
|
|
-+ default:
|
|
|
-+ break;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ else if (cmp_t == CMP_DF)
|
|
|
-+ {
|
|
|
-+ switch (cond_t) {
|
|
|
-+ case EQ:
|
|
|
-+ return (nios2_fpu_insns[nios2_fpu_nios2_seqdf].N >= 0);
|
|
|
-+ case NE:
|
|
|
-+ return (nios2_fpu_insns[nios2_fpu_nios2_snedf].N >= 0);
|
|
|
-+ case GT:
|
|
|
-+ return (nios2_fpu_insns[nios2_fpu_nios2_sgtdf].N >= 0);
|
|
|
-+ case GE:
|
|
|
-+ return (nios2_fpu_insns[nios2_fpu_nios2_sgedf].N >= 0);
|
|
|
-+ case LT:
|
|
|
-+ return (nios2_fpu_insns[nios2_fpu_nios2_sltdf].N >= 0);
|
|
|
-+ case LE:
|
|
|
-+ return (nios2_fpu_insns[nios2_fpu_nios2_sledf].N >= 0);
|
|
|
-+ default:
|
|
|
-+ break;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return false;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Note that get_reverse_cond() is not the same as get_inverse_cond()
|
|
|
-+ get_reverse_cond() means that if the operand order is reversed,
|
|
|
-+ what is the operand that is needed to generate the same condition?
|
|
|
-+*/
|
|
|
-+enum rtx_code
|
|
|
-+get_reverse_cond(enum rtx_code cond_t)
|
|
|
-+{
|
|
|
-+ switch (cond_t)
|
|
|
-+ {
|
|
|
-+ case GT: return LT;
|
|
|
-+ case GE: return LE;
|
|
|
-+ case LT: return GT;
|
|
|
-+ case LE: return GE;
|
|
|
-+ case GTU: return LTU;
|
|
|
-+ case GEU: return LEU;
|
|
|
-+ case LTU: return GTU;
|
|
|
-+ case LEU: return GEU;
|
|
|
-+ default: break;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return cond_t;
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+/* Generate the code to compare (and possibly branch) two integer values
|
|
|
-+ TEST_CODE is the comparison code we are trying to emulate
|
|
|
-+ (or implement directly)
|
|
|
-+ RESULT is where to store the result of the comparison,
|
|
|
-+ or null to emit a branch
|
|
|
-+ CMP0 CMP1 are the two comparison operands
|
|
|
-+ DESTINATION is the destination of the branch, or null to only compare
|
|
|
-+ */
|
|
|
-+
|
|
|
-+void
|
|
|
-+gen_int_relational (enum rtx_code test_code, /* relational test (EQ, etc) */
|
|
|
-+ rtx result, /* result to store comp. or 0 if branch */
|
|
|
-+ rtx cmp0, /* first operand to compare */
|
|
|
-+ rtx cmp1, /* second operand to compare */
|
|
|
-+ rtx destination) /* destination of the branch, or 0 if compare */
|
|
|
-+{
|
|
|
-+ struct cmp_info
|
|
|
-+ {
|
|
|
-+ /* for register (or 0) compares */
|
|
|
-+ enum rtx_code test_code_reg; /* code to use in instruction (LT vs. LTU) */
|
|
|
-+ int reverse_regs; /* reverse registers in test */
|
|
|
-+
|
|
|
-+ /* for immediate compares */
|
|
|
-+ enum rtx_code test_code_const;
|
|
|
-+ /* code to use in instruction (LT vs. LTU) */
|
|
|
-+ int const_low; /* low bound of constant we can accept */
|
|
|
-+ int const_high; /* high bound of constant we can accept */
|
|
|
-+ int const_add; /* constant to add */
|
|
|
-+
|
|
|
-+ /* generic info */
|
|
|
-+ int unsignedp; /* != 0 for unsigned comparisons. */
|
|
|
-+ };
|
|
|
-+
|
|
|
-+ static const struct cmp_info info[(int) ITEST_MAX] = {
|
|
|
-+
|
|
|
-+ {EQ, 0, EQ, -32768, 32767, 0, 0}, /* EQ */
|
|
|
-+ {NE, 0, NE, -32768, 32767, 0, 0}, /* NE */
|
|
|
-+
|
|
|
-+ {LT, 1, GE, -32769, 32766, 1, 0}, /* GT */
|
|
|
-+ {GE, 0, GE, -32768, 32767, 0, 0}, /* GE */
|
|
|
-+ {LT, 0, LT, -32768, 32767, 0, 0}, /* LT */
|
|
|
-+ {GE, 1, LT, -32769, 32766, 1, 0}, /* LE */
|
|
|
-+
|
|
|
-+ {LTU, 1, GEU, 0, 65534, 1, 0}, /* GTU */
|
|
|
-+ {GEU, 0, GEU, 0, 65535, 0, 0}, /* GEU */
|
|
|
-+ {LTU, 0, LTU, 0, 65535, 0, 0}, /* LTU */
|
|
|
-+ {GEU, 1, LTU, 0, 65534, 1, 0}, /* LEU */
|
|
|
-+ };
|
|
|
-+
|
|
|
-+ enum internal_test test;
|
|
|
-+ enum machine_mode mode;
|
|
|
-+ const struct cmp_info *p_info;
|
|
|
-+ int branch_p;
|
|
|
-+
|
|
|
-+
|
|
|
-+ test = map_test_to_internal_test (test_code);
|
|
|
-+ if (test == ITEST_MAX)
|
|
|
-+ abort ();
|
|
|
-+
|
|
|
-+ p_info = &info[(int) test];
|
|
|
-+
|
|
|
-+ mode = GET_MODE (cmp0);
|
|
|
-+ if (mode == VOIDmode)
|
|
|
-+ mode = GET_MODE (cmp1);
|
|
|
-+
|
|
|
-+ branch_p = (destination != 0);
|
|
|
-+
|
|
|
-+ /* Handle floating point comparison directly. */
|
|
|
-+ if (branch_type == CMP_SF || branch_type == CMP_DF)
|
|
|
-+ {
|
|
|
-+
|
|
|
-+ bool reverse_operands = false;
|
|
|
-+
|
|
|
-+ enum machine_mode float_mode = (branch_type == CMP_SF) ? SFmode : DFmode;
|
|
|
-+
|
|
|
-+ if (!register_operand (cmp0, float_mode)
|
|
|
-+ || !register_operand (cmp1, float_mode))
|
|
|
-+ {
|
|
|
-+ abort ();
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (branch_p)
|
|
|
-+ {
|
|
|
-+ test_code = p_info->test_code_reg;
|
|
|
-+ reverse_operands = (p_info->reverse_regs);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if ( !have_nios2_fpu_cmp_insn(test_code, branch_type) &&
|
|
|
-+ have_nios2_fpu_cmp_insn(get_reverse_cond(test_code), branch_type) )
|
|
|
-+ {
|
|
|
-+ test_code = get_reverse_cond(test_code);
|
|
|
-+ reverse_operands = !reverse_operands;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (reverse_operands)
|
|
|
-+ {
|
|
|
-+ rtx temp = cmp0;
|
|
|
-+ cmp0 = cmp1;
|
|
|
-+ cmp1 = temp;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (branch_p)
|
|
|
-+ {
|
|
|
-+ rtx cond = gen_rtx (test_code, SImode, cmp0, cmp1);
|
|
|
-+ rtx label = gen_rtx_LABEL_REF (VOIDmode, destination);
|
|
|
-+ rtx insn = gen_rtx_SET (VOIDmode, pc_rtx,
|
|
|
-+ gen_rtx_IF_THEN_ELSE (VOIDmode,
|
|
|
-+ cond, label, pc_rtx));
|
|
|
-+ emit_jump_insn (insn);
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ emit_move_insn (result, gen_rtx (test_code, SImode, cmp0, cmp1));
|
|
|
-+ }
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* We can't, under any circumstances, have const_ints in cmp0
|
|
|
-+ ??? Actually we could have const0 */
|
|
|
-+ if (GET_CODE (cmp0) == CONST_INT)
|
|
|
-+ cmp0 = force_reg (mode, cmp0);
|
|
|
-+
|
|
|
-+ /* if the comparison is against an int not in legal range
|
|
|
-+ move it into a register */
|
|
|
-+ if (GET_CODE (cmp1) == CONST_INT)
|
|
|
-+ {
|
|
|
-+ HOST_WIDE_INT value = INTVAL (cmp1);
|
|
|
-+
|
|
|
-+ if (value < p_info->const_low || value > p_info->const_high)
|
|
|
-+ cmp1 = force_reg (mode, cmp1);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* Comparison to constants, may involve adding 1 to change a GT into GE.
|
|
|
-+ Comparison between two registers, may involve switching operands. */
|
|
|
-+ if (GET_CODE (cmp1) == CONST_INT)
|
|
|
-+ {
|
|
|
-+ if (p_info->const_add != 0)
|
|
|
-+ {
|
|
|
-+ HOST_WIDE_INT new = INTVAL (cmp1) + p_info->const_add;
|
|
|
-+
|
|
|
-+ /* If modification of cmp1 caused overflow,
|
|
|
-+ we would get the wrong answer if we follow the usual path;
|
|
|
-+ thus, x > 0xffffffffU would turn into x > 0U. */
|
|
|
-+ if ((p_info->unsignedp
|
|
|
-+ ? (unsigned HOST_WIDE_INT) new >
|
|
|
-+ (unsigned HOST_WIDE_INT) INTVAL (cmp1)
|
|
|
-+ : new > INTVAL (cmp1)) != (p_info->const_add > 0))
|
|
|
-+ {
|
|
|
-+ /* ??? This case can never happen with the current numbers,
|
|
|
-+ but I am paranoid and would rather an abort than
|
|
|
-+ a bug I will never find */
|
|
|
-+ abort ();
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ cmp1 = GEN_INT (new);
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ else if (p_info->reverse_regs)
|
|
|
-+ {
|
|
|
-+ rtx temp = cmp0;
|
|
|
-+ cmp0 = cmp1;
|
|
|
-+ cmp1 = temp;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+ if (branch_p)
|
|
|
-+ {
|
|
|
-+ if (register_operand (cmp0, mode) && register_operand (cmp1, mode))
|
|
|
-+ {
|
|
|
-+ rtx insn;
|
|
|
-+ rtx cond = gen_rtx (p_info->test_code_reg, mode, cmp0, cmp1);
|
|
|
-+ rtx label = gen_rtx_LABEL_REF (VOIDmode, destination);
|
|
|
-+
|
|
|
-+ insn = gen_rtx_SET (VOIDmode, pc_rtx,
|
|
|
-+ gen_rtx_IF_THEN_ELSE (VOIDmode,
|
|
|
-+ cond, label, pc_rtx));
|
|
|
-+ emit_jump_insn (insn);
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ rtx cond, label;
|
|
|
-+
|
|
|
-+ result = gen_reg_rtx (mode);
|
|
|
-+
|
|
|
-+ emit_move_insn (result,
|
|
|
-+ gen_rtx (p_info->test_code_const, mode, cmp0,
|
|
|
-+ cmp1));
|
|
|
-+
|
|
|
-+ cond = gen_rtx (NE, mode, result, const0_rtx);
|
|
|
-+ label = gen_rtx_LABEL_REF (VOIDmode, destination);
|
|
|
-+
|
|
|
-+ emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx,
|
|
|
-+ gen_rtx_IF_THEN_ELSE (VOIDmode,
|
|
|
-+ cond,
|
|
|
-+ label, pc_rtx)));
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ if (register_operand (cmp0, mode) && register_operand (cmp1, mode))
|
|
|
-+ {
|
|
|
-+ emit_move_insn (result,
|
|
|
-+ gen_rtx (p_info->test_code_reg, mode, cmp0, cmp1));
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ emit_move_insn (result,
|
|
|
-+ gen_rtx (p_info->test_code_const, mode, cmp0,
|
|
|
-+ cmp1));
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+/* ??? For now conditional moves are only supported
|
|
|
-+ when the mode of the operands being compared are
|
|
|
-+ the same as the ones being moved */
|
|
|
-+
|
|
|
-+void
|
|
|
-+gen_conditional_move (rtx *operands, enum machine_mode mode)
|
|
|
-+{
|
|
|
-+ rtx insn, cond;
|
|
|
-+ rtx cmp_reg = gen_reg_rtx (mode);
|
|
|
-+ enum rtx_code cmp_code = GET_CODE (operands[1]);
|
|
|
-+ enum rtx_code move_code = EQ;
|
|
|
-+
|
|
|
-+ /* emit a comparison if it is not "simple".
|
|
|
-+ Simple comparisons are X eq 0 and X ne 0 */
|
|
|
-+ if ((cmp_code == EQ || cmp_code == NE) && branch_cmp[1] == const0_rtx)
|
|
|
-+ {
|
|
|
-+ cmp_reg = branch_cmp[0];
|
|
|
-+ move_code = cmp_code;
|
|
|
-+ }
|
|
|
-+ else if ((cmp_code == EQ || cmp_code == NE) && branch_cmp[0] == const0_rtx)
|
|
|
-+ {
|
|
|
-+ cmp_reg = branch_cmp[1];
|
|
|
-+ move_code = cmp_code == EQ ? NE : EQ;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ gen_int_relational (cmp_code, cmp_reg, branch_cmp[0], branch_cmp[1],
|
|
|
-+ NULL_RTX);
|
|
|
-+
|
|
|
-+ cond = gen_rtx (move_code, VOIDmode, cmp_reg, CONST0_RTX (mode));
|
|
|
-+ insn = gen_rtx_SET (mode, operands[0],
|
|
|
-+ gen_rtx_IF_THEN_ELSE (mode,
|
|
|
-+ cond, operands[2], operands[3]));
|
|
|
-+ emit_insn (insn);
|
|
|
-+}
|
|
|
-+
|
|
|
-+/*******************
|
|
|
-+ * Addressing Modes
|
|
|
-+ *******************/
|
|
|
-+
|
|
|
-+int
|
|
|
-+nios2_legitimate_address (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED,
|
|
|
-+ int strict)
|
|
|
-+{
|
|
|
-+ int ret_val = 0;
|
|
|
-+
|
|
|
-+ switch (GET_CODE (operand))
|
|
|
-+ {
|
|
|
-+ /* direct. */
|
|
|
-+ case SYMBOL_REF:
|
|
|
-+ if (SYMBOL_REF_IN_NIOS2_SMALL_DATA_P (operand))
|
|
|
-+ {
|
|
|
-+ ret_val = 1;
|
|
|
-+ break;
|
|
|
-+ }
|
|
|
-+ /* else, fall through */
|
|
|
-+ case LABEL_REF:
|
|
|
-+ case CONST_INT:
|
|
|
-+ case CONST:
|
|
|
-+ case CONST_DOUBLE:
|
|
|
-+ /* ??? In here I need to add gp addressing */
|
|
|
-+ ret_val = 0;
|
|
|
-+
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ /* Register indirect. */
|
|
|
-+ case REG:
|
|
|
-+ ret_val = REG_OK_FOR_BASE_P2 (operand, strict);
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ /* Register indirect with displacement */
|
|
|
-+ case PLUS:
|
|
|
-+ {
|
|
|
-+ rtx op0 = XEXP (operand, 0);
|
|
|
-+ rtx op1 = XEXP (operand, 1);
|
|
|
-+
|
|
|
-+ if (REG_P (op0) && REG_P (op1))
|
|
|
-+ ret_val = 0;
|
|
|
-+ else if (REG_P (op0) && GET_CODE (op1) == CONST_INT)
|
|
|
-+ ret_val = REG_OK_FOR_BASE_P2 (op0, strict)
|
|
|
-+ && SMALL_INT (INTVAL (op1));
|
|
|
-+ else if (REG_P (op1) && GET_CODE (op0) == CONST_INT)
|
|
|
-+ ret_val = REG_OK_FOR_BASE_P2 (op1, strict)
|
|
|
-+ && SMALL_INT (INTVAL (op0));
|
|
|
-+ else
|
|
|
-+ ret_val = 0;
|
|
|
-+ }
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ default:
|
|
|
-+ ret_val = 0;
|
|
|
-+ break;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return ret_val;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Return true if EXP should be placed in the small data section. */
|
|
|
-+
|
|
|
-+static bool
|
|
|
-+nios2_in_small_data_p (tree exp)
|
|
|
-+{
|
|
|
-+ /* We want to merge strings, so we never consider them small data. */
|
|
|
-+ if (TREE_CODE (exp) == STRING_CST)
|
|
|
-+ return false;
|
|
|
-+
|
|
|
-+ if (TREE_CODE (exp) == VAR_DECL && DECL_SECTION_NAME (exp))
|
|
|
-+ {
|
|
|
-+ const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (exp));
|
|
|
-+ /* ??? these string names need moving into
|
|
|
-+ an array in some header file */
|
|
|
-+ if (nios2_section_threshold > 0
|
|
|
-+ && (strcmp (section, ".sbss") == 0
|
|
|
-+ || strncmp (section, ".sbss.", 6) == 0
|
|
|
-+ || strcmp (section, ".sdata") == 0
|
|
|
-+ || strncmp (section, ".sdata.", 7) == 0))
|
|
|
-+ return true;
|
|
|
-+ }
|
|
|
-+ else if (TREE_CODE (exp) == VAR_DECL)
|
|
|
-+ {
|
|
|
-+ HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp));
|
|
|
-+
|
|
|
-+ /* If this is an incomplete type with size 0, then we can't put it
|
|
|
-+ in sdata because it might be too big when completed. */
|
|
|
-+ if (size > 0 && (unsigned HOST_WIDE_INT)size <= nios2_section_threshold)
|
|
|
-+ return true;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return false;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static void
|
|
|
-+nios2_encode_section_info (tree decl, rtx rtl, int first)
|
|
|
-+{
|
|
|
-+
|
|
|
-+ rtx symbol;
|
|
|
-+ int flags;
|
|
|
-+
|
|
|
-+ default_encode_section_info (decl, rtl, first);
|
|
|
-+
|
|
|
-+ /* Careful not to prod global register variables. */
|
|
|
-+ if (GET_CODE (rtl) != MEM)
|
|
|
-+ return;
|
|
|
-+ symbol = XEXP (rtl, 0);
|
|
|
-+ if (GET_CODE (symbol) != SYMBOL_REF)
|
|
|
-+ return;
|
|
|
-+
|
|
|
-+ flags = SYMBOL_REF_FLAGS (symbol);
|
|
|
-+
|
|
|
-+ /* We don't want weak variables to be addressed with gp in case they end up with
|
|
|
-+ value 0 which is not within 2^15 of $gp */
|
|
|
-+ if (DECL_P (decl) && DECL_WEAK (decl))
|
|
|
-+ flags |= SYMBOL_FLAG_WEAK_DECL;
|
|
|
-+
|
|
|
-+ SYMBOL_REF_FLAGS (symbol) = flags;
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+static unsigned int
|
|
|
-+nios2_section_type_flags (tree decl, const char *name, int reloc)
|
|
|
-+{
|
|
|
-+ unsigned int flags;
|
|
|
-+
|
|
|
-+ flags = default_section_type_flags (decl, name, reloc);
|
|
|
-+
|
|
|
-+ /* ??? these string names need moving into an array in some header file */
|
|
|
-+ if (strcmp (name, ".sbss") == 0
|
|
|
-+ || strncmp (name, ".sbss.", 6) == 0
|
|
|
-+ || strcmp (name, ".sdata") == 0
|
|
|
-+ || strncmp (name, ".sdata.", 7) == 0)
|
|
|
-+ flags |= SECTION_SMALL;
|
|
|
-+
|
|
|
-+ return flags;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Handle a #pragma reverse_bitfields */
|
|
|
-+static void
|
|
|
-+nios2_pragma_reverse_bitfields (struct cpp_reader *pfile ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ nios2_pragma_reverse_bitfields_flag = 1; /* Reverse */
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Handle a #pragma no_reverse_bitfields */
|
|
|
-+static void
|
|
|
-+nios2_pragma_no_reverse_bitfields (struct cpp_reader *pfile ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ nios2_pragma_reverse_bitfields_flag = -1; /* Forward */
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Handle the various #pragma custom_<switch>s */
|
|
|
-+static void
|
|
|
-+nios2_pragma_fpu (int *value, const char *opt, int *seen)
|
|
|
-+{
|
|
|
-+ tree t;
|
|
|
-+ if (c_lex (&t) != CPP_NUMBER)
|
|
|
-+ {
|
|
|
-+ error ("`#pragma custom_%s' value must be a number between 0 and 255",
|
|
|
-+ opt);
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (TREE_INT_CST_HIGH (t) == 0
|
|
|
-+ && TREE_INT_CST_LOW (t) <= 255)
|
|
|
-+ {
|
|
|
-+ *value = (int)TREE_INT_CST_LOW (t);
|
|
|
-+ *seen = 1;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ error ("`#pragma custom_%s' value must be between 0 and 255", opt);
|
|
|
-+ }
|
|
|
-+ nios2_custom_check_insns (1);
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Handle the various #pragma no_custom_<switch>s */
|
|
|
-+static void
|
|
|
-+nios2_pragma_no_fpu (int *value, const char *opt ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ *value = -1;
|
|
|
-+ nios2_custom_check_insns (1);
|
|
|
-+}
|
|
|
-+
|
|
|
-+#undef NIOS2_FPU_INSN
|
|
|
-+#define NIOS2_FPU_INSN(opt, insn, args) \
|
|
|
-+static void \
|
|
|
-+NIOS2_CONCAT (nios2_pragma_, insn) \
|
|
|
-+ (struct cpp_reader *pfile ATTRIBUTE_UNUSED) \
|
|
|
-+{ \
|
|
|
-+ nios2_fpu_info *inf = &(nios2_fpu_insns[NIOS2_CONCAT (nios2_fpu_, insn)]); \
|
|
|
-+ nios2_pragma_fpu (&(inf->N), inf->option, &(inf->pragma_seen)); \
|
|
|
-+} \
|
|
|
-+static void \
|
|
|
-+NIOS2_CONCAT (nios2_pragma_no_, insn) \
|
|
|
-+ (struct cpp_reader *pfile ATTRIBUTE_UNUSED) \
|
|
|
-+{ \
|
|
|
-+ nios2_fpu_info *inf = &(nios2_fpu_insns[NIOS2_CONCAT (nios2_fpu_, insn)]); \
|
|
|
-+ nios2_pragma_no_fpu (&(inf->N), inf->option); \
|
|
|
-+}
|
|
|
-+NIOS2_FOR_ALL_FPU_INSNS
|
|
|
-+
|
|
|
-+static void
|
|
|
-+nios2_pragma_handle_custom_fpu_cfg (struct cpp_reader *pfile ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ tree t;
|
|
|
-+ if (c_lex (&t) != CPP_STRING)
|
|
|
-+ {
|
|
|
-+ error ("`#pragma custom_fpu_cfg' value must be a string");
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (TREE_STRING_LENGTH (t) > 0)
|
|
|
-+ {
|
|
|
-+ nios2_handle_custom_fpu_cfg (TREE_STRING_POINTER (t), 1);
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+
|
|
|
-+void
|
|
|
-+nios2_register_target_pragmas ()
|
|
|
-+{
|
|
|
-+ int i;
|
|
|
-+
|
|
|
-+ c_register_pragma (0, "reverse_bitfields",
|
|
|
-+ nios2_pragma_reverse_bitfields);
|
|
|
-+ c_register_pragma (0, "no_reverse_bitfields",
|
|
|
-+ nios2_pragma_no_reverse_bitfields);
|
|
|
-+
|
|
|
-+ for (i = 0; i < nios2_fpu_max_insn; i++)
|
|
|
-+ {
|
|
|
-+ nios2_fpu_info *inf = &(nios2_fpu_insns[i]);
|
|
|
-+ c_register_pragma (0, inf->pname, inf->pragma);
|
|
|
-+ c_register_pragma (0, inf->nopname, inf->nopragma);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ c_register_pragma (0, "custom_fpu_cfg",
|
|
|
-+ nios2_pragma_handle_custom_fpu_cfg);
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Handle a "reverse_bitfields" or "no_reverse_bitfields" attribute.
|
|
|
-+ ??? What do these attributes mean on a union? */
|
|
|
-+static tree
|
|
|
-+nios2_handle_struct_attribute (tree *node, tree name,
|
|
|
-+ tree args ATTRIBUTE_UNUSED,
|
|
|
-+ int flags ATTRIBUTE_UNUSED,
|
|
|
-+ bool *no_add_attrs)
|
|
|
-+{
|
|
|
-+ tree *type = NULL;
|
|
|
-+ if (DECL_P (*node))
|
|
|
-+ {
|
|
|
-+ if (TREE_CODE (*node) == TYPE_DECL)
|
|
|
-+ {
|
|
|
-+ type = &TREE_TYPE (*node);
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ type = node;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (!(type && (TREE_CODE (*type) == RECORD_TYPE
|
|
|
-+ || TREE_CODE (*type) == UNION_TYPE)))
|
|
|
-+ {
|
|
|
-+ warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
|
|
|
-+ *no_add_attrs = true;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ else if ((is_attribute_p ("reverse_bitfields", name)
|
|
|
-+ && lookup_attribute ("no_reverse_bitfields",
|
|
|
-+ TYPE_ATTRIBUTES (*type)))
|
|
|
-+ || ((is_attribute_p ("no_reverse_bitfields", name)
|
|
|
-+ && lookup_attribute ("reverse_bitfields",
|
|
|
-+ TYPE_ATTRIBUTES (*type)))))
|
|
|
-+ {
|
|
|
-+ warning ("`%s' incompatible attribute ignored",
|
|
|
-+ IDENTIFIER_POINTER (name));
|
|
|
-+ *no_add_attrs = true;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return NULL_TREE;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/*
|
|
|
-+ Add __attribute__ ((pragma_reverse_bitfields)) when in the scope of a
|
|
|
-+ #pragma reverse_bitfields, or __attribute__
|
|
|
-+ ((pragma_no_reverse_bitfields)) when in the scope of a #pragma
|
|
|
-+ no_reverse_bitfields. This gets called before
|
|
|
-+ nios2_handle_struct_attribute above, so we can't just reuse the same
|
|
|
-+ attributes.
|
|
|
-+*/
|
|
|
-+static void
|
|
|
-+nios2_insert_attributes (tree node, tree *attr_ptr)
|
|
|
-+{
|
|
|
-+ tree type = NULL;
|
|
|
-+ if (DECL_P (node))
|
|
|
-+ {
|
|
|
-+ if (TREE_CODE (node) == TYPE_DECL)
|
|
|
-+ {
|
|
|
-+ type = TREE_TYPE (node);
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ type = node;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (!type
|
|
|
-+ || (TREE_CODE (type) != RECORD_TYPE
|
|
|
-+ && TREE_CODE (type) != UNION_TYPE))
|
|
|
-+ {
|
|
|
-+ /* We can ignore things other than structs & unions */
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (lookup_attribute ("reverse_bitfields", TYPE_ATTRIBUTES (type))
|
|
|
-+ || lookup_attribute ("no_reverse_bitfields", TYPE_ATTRIBUTES (type)))
|
|
|
-+ {
|
|
|
-+ /* If an attribute is already set, it silently overrides the
|
|
|
-+ current #pragma, if any */
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (nios2_pragma_reverse_bitfields_flag)
|
|
|
-+ {
|
|
|
-+ const char *id = (nios2_pragma_reverse_bitfields_flag == 1 ?
|
|
|
-+ "pragma_reverse_bitfields" :
|
|
|
-+ "pragma_no_reverse_bitfields");
|
|
|
-+ /* No attribute set, and we are in the scope of a #pragma */
|
|
|
-+ *attr_ptr = tree_cons (get_identifier (id), NULL, *attr_ptr);
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+/*
|
|
|
-+ * The attributes take precedence over the pragmas, which in turn take
|
|
|
-+ * precedence over the compile-time switches.
|
|
|
-+ */
|
|
|
-+static bool
|
|
|
-+nios2_reverse_bitfield_layout_p (tree record_type)
|
|
|
-+{
|
|
|
-+ return ((TARGET_REVERSE_BITFIELDS
|
|
|
-+ && !lookup_attribute ("pragma_no_reverse_bitfields",
|
|
|
-+ TYPE_ATTRIBUTES (record_type))
|
|
|
-+ && !lookup_attribute ("no_reverse_bitfields",
|
|
|
-+ TYPE_ATTRIBUTES (record_type)))
|
|
|
-+ || (lookup_attribute ("pragma_reverse_bitfields",
|
|
|
-+ TYPE_ATTRIBUTES (record_type))
|
|
|
-+ && !lookup_attribute ("no_reverse_bitfields",
|
|
|
-+ TYPE_ATTRIBUTES (record_type)))
|
|
|
-+ || lookup_attribute ("reverse_bitfields",
|
|
|
-+ TYPE_ATTRIBUTES (record_type)));
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+/*****************************************
|
|
|
-+ * Defining the Output Assembler Language
|
|
|
-+ *****************************************/
|
|
|
-+
|
|
|
-+/* -------------- *
|
|
|
-+ * Output of Data
|
|
|
-+ * -------------- */
|
|
|
-+
|
|
|
-+
|
|
|
-+/* -------------------------------- *
|
|
|
-+ * Output of Assembler Instructions
|
|
|
-+ * -------------------------------- */
|
|
|
-+
|
|
|
-+
|
|
|
-+/* print the operand OP to file stream
|
|
|
-+ FILE modified by LETTER. LETTER
|
|
|
-+ can be one of:
|
|
|
-+ i: print "i" if OP is an immediate, except 0
|
|
|
-+ o: print "io" if OP is volatile
|
|
|
-+
|
|
|
-+ z: for const0_rtx print $0 instead of 0
|
|
|
-+ H: for %hiadj
|
|
|
-+ L: for %lo
|
|
|
-+ U: for upper half of 32 bit value
|
|
|
-+ D: for the upper 32-bits of a 64-bit double value
|
|
|
-+ */
|
|
|
-+
|
|
|
-+void
|
|
|
-+nios2_print_operand (FILE *file, rtx op, int letter)
|
|
|
-+{
|
|
|
-+
|
|
|
-+ switch (letter)
|
|
|
-+ {
|
|
|
-+ case 'i':
|
|
|
-+ if (CONSTANT_P (op) && (op != const0_rtx))
|
|
|
-+ fprintf (file, "i");
|
|
|
-+ return;
|
|
|
-+
|
|
|
-+ case 'o':
|
|
|
-+ if (GET_CODE (op) == MEM
|
|
|
-+ && ((MEM_VOLATILE_P (op) && !TARGET_CACHE_VOLATILE)
|
|
|
-+ || TARGET_BYPASS_CACHE))
|
|
|
-+ fprintf (file, "io");
|
|
|
-+ return;
|
|
|
-+
|
|
|
-+ default:
|
|
|
-+ break;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (comparison_operator (op, VOIDmode))
|
|
|
-+ {
|
|
|
-+ if (letter == 0)
|
|
|
-+ {
|
|
|
-+ fprintf (file, "%s", GET_RTX_NAME (GET_CODE (op)));
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+
|
|
|
-+ switch (GET_CODE (op))
|
|
|
-+ {
|
|
|
-+ case REG:
|
|
|
-+ if (letter == 0 || letter == 'z')
|
|
|
-+ {
|
|
|
-+ fprintf (file, "%s", reg_names[REGNO (op)]);
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+ else if (letter == 'D')
|
|
|
-+ {
|
|
|
-+ fprintf (file, "%s", reg_names[REGNO (op)+1]);
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case CONST_INT:
|
|
|
-+ if (INTVAL (op) == 0 && letter == 'z')
|
|
|
-+ {
|
|
|
-+ fprintf (file, "zero");
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+ else if (letter == 'U')
|
|
|
-+ {
|
|
|
-+ HOST_WIDE_INT val = INTVAL (op);
|
|
|
-+ rtx new_op;
|
|
|
-+ val = (val / 65536) & 0xFFFF;
|
|
|
-+ new_op = GEN_INT (val);
|
|
|
-+ output_addr_const (file, new_op);
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* else, fall through */
|
|
|
-+ case CONST:
|
|
|
-+ case LABEL_REF:
|
|
|
-+ case SYMBOL_REF:
|
|
|
-+ case CONST_DOUBLE:
|
|
|
-+ if (letter == 0 || letter == 'z')
|
|
|
-+ {
|
|
|
-+ output_addr_const (file, op);
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+ else if (letter == 'H')
|
|
|
-+ {
|
|
|
-+ fprintf (file, "%%hiadj(");
|
|
|
-+ output_addr_const (file, op);
|
|
|
-+ fprintf (file, ")");
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+ else if (letter == 'L')
|
|
|
-+ {
|
|
|
-+ fprintf (file, "%%lo(");
|
|
|
-+ output_addr_const (file, op);
|
|
|
-+ fprintf (file, ")");
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+
|
|
|
-+ case SUBREG:
|
|
|
-+ case MEM:
|
|
|
-+ if (letter == 0)
|
|
|
-+ {
|
|
|
-+ output_address (op);
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case CODE_LABEL:
|
|
|
-+ if (letter == 0)
|
|
|
-+ {
|
|
|
-+ output_addr_const (file, op);
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ default:
|
|
|
-+ break;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ fprintf (stderr, "Missing way to print (%c) ", letter);
|
|
|
-+ debug_rtx (op);
|
|
|
-+ abort ();
|
|
|
-+}
|
|
|
-+
|
|
|
-+static int gprel_constant (rtx);
|
|
|
-+
|
|
|
-+static int
|
|
|
-+gprel_constant (rtx op)
|
|
|
-+{
|
|
|
-+ if (GET_CODE (op) == SYMBOL_REF
|
|
|
-+ && SYMBOL_REF_IN_NIOS2_SMALL_DATA_P (op))
|
|
|
-+ {
|
|
|
-+ return 1;
|
|
|
-+ }
|
|
|
-+ else if (GET_CODE (op) == CONST
|
|
|
-+ && GET_CODE (XEXP (op, 0)) == PLUS)
|
|
|
-+ {
|
|
|
-+ return gprel_constant (XEXP (XEXP (op, 0), 0));
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ return 0;
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+
|
|
|
-+void
|
|
|
-+nios2_print_operand_address (FILE *file, rtx op)
|
|
|
-+{
|
|
|
-+ switch (GET_CODE (op))
|
|
|
-+ {
|
|
|
-+ case CONST:
|
|
|
-+ case CONST_INT:
|
|
|
-+ case LABEL_REF:
|
|
|
-+ case CONST_DOUBLE:
|
|
|
-+ case SYMBOL_REF:
|
|
|
-+ if (gprel_constant (op))
|
|
|
-+ {
|
|
|
-+ fprintf (file, "%%gprel(");
|
|
|
-+ output_addr_const (file, op);
|
|
|
-+ fprintf (file, ")(%s)", reg_names[GP_REGNO]);
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case PLUS:
|
|
|
-+ {
|
|
|
-+ rtx op0 = XEXP (op, 0);
|
|
|
-+ rtx op1 = XEXP (op, 1);
|
|
|
-+
|
|
|
-+ if (REG_P (op0) && CONSTANT_P (op1))
|
|
|
-+ {
|
|
|
-+ output_addr_const (file, op1);
|
|
|
-+ fprintf (file, "(%s)", reg_names[REGNO (op0)]);
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+ else if (REG_P (op1) && CONSTANT_P (op0))
|
|
|
-+ {
|
|
|
-+ output_addr_const (file, op0);
|
|
|
-+ fprintf (file, "(%s)", reg_names[REGNO (op1)]);
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ break;
|
|
|
-+
|
|
|
-+ case REG:
|
|
|
-+ fprintf (file, "0(%s)", reg_names[REGNO (op)]);
|
|
|
-+ return;
|
|
|
-+
|
|
|
-+ case MEM:
|
|
|
-+ {
|
|
|
-+ rtx base = XEXP (op, 0);
|
|
|
-+ PRINT_OPERAND_ADDRESS (file, base);
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+ default:
|
|
|
-+ break;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ fprintf (stderr, "Missing way to print address\n");
|
|
|
-+ debug_rtx (op);
|
|
|
-+ abort ();
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+/****************************
|
|
|
-+ * Predicates
|
|
|
-+ ****************************/
|
|
|
-+
|
|
|
-+int
|
|
|
-+arith_operand (rtx op, enum machine_mode mode)
|
|
|
-+{
|
|
|
-+ if (GET_CODE (op) == CONST_INT && SMALL_INT (INTVAL (op)))
|
|
|
-+ return 1;
|
|
|
-+
|
|
|
-+ return register_operand (op, mode);
|
|
|
-+}
|
|
|
-+
|
|
|
-+int
|
|
|
-+uns_arith_operand (rtx op, enum machine_mode mode)
|
|
|
-+{
|
|
|
-+ if (GET_CODE (op) == CONST_INT && SMALL_INT_UNSIGNED (INTVAL (op)))
|
|
|
-+ return 1;
|
|
|
-+
|
|
|
-+ return register_operand (op, mode);
|
|
|
-+}
|
|
|
-+
|
|
|
-+int
|
|
|
-+logical_operand (rtx op, enum machine_mode mode)
|
|
|
-+{
|
|
|
-+ if (GET_CODE (op) == CONST_INT
|
|
|
-+ && (SMALL_INT_UNSIGNED (INTVAL (op)) || UPPER16_INT (INTVAL (op))))
|
|
|
-+ return 1;
|
|
|
-+
|
|
|
-+ return register_operand (op, mode);
|
|
|
-+}
|
|
|
-+
|
|
|
-+int
|
|
|
-+shift_operand (rtx op, enum machine_mode mode)
|
|
|
-+{
|
|
|
-+ if (GET_CODE (op) == CONST_INT && SHIFT_INT (INTVAL (op)))
|
|
|
-+ return 1;
|
|
|
-+
|
|
|
-+ return register_operand (op, mode);
|
|
|
-+}
|
|
|
-+
|
|
|
-+int
|
|
|
-+rdwrctl_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ return GET_CODE (op) == CONST_INT && RDWRCTL_INT (INTVAL (op));
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Return truth value of whether OP is a register or the constant 0. */
|
|
|
-+
|
|
|
-+int
|
|
|
-+reg_or_0_operand (rtx op, enum machine_mode mode)
|
|
|
-+{
|
|
|
-+ switch (GET_CODE (op))
|
|
|
-+ {
|
|
|
-+ case CONST_INT:
|
|
|
-+ return INTVAL (op) == 0;
|
|
|
-+
|
|
|
-+ case CONST_DOUBLE:
|
|
|
-+ return op == CONST0_RTX (mode);
|
|
|
-+
|
|
|
-+ default:
|
|
|
-+ break;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return register_operand (op, mode);
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+int
|
|
|
-+equality_op (rtx op, enum machine_mode mode)
|
|
|
-+{
|
|
|
-+ if (mode != GET_MODE (op))
|
|
|
-+ return 0;
|
|
|
-+
|
|
|
-+ return GET_CODE (op) == EQ || GET_CODE (op) == NE;
|
|
|
-+}
|
|
|
-+
|
|
|
-+int
|
|
|
-+custom_insn_opcode (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ return GET_CODE (op) == CONST_INT && CUSTOM_INSN_OPCODE (INTVAL (op));
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+/*****************************************************************************
|
|
|
-+**
|
|
|
-+** custom fpu instruction output
|
|
|
-+**
|
|
|
-+*****************************************************************************/
|
|
|
-+
|
|
|
-+static const char *nios2_custom_fpu_insn_zdz (rtx, int, const char *);
|
|
|
-+static const char *nios2_custom_fpu_insn_zsz (rtx, int, const char *);
|
|
|
-+static const char *nios2_custom_fpu_insn_szz (rtx, int, const char *);
|
|
|
-+static const char *nios2_custom_fpu_insn_sss (rtx, int, const char *);
|
|
|
-+static const char *nios2_custom_fpu_insn_ssz (rtx, int, const char *);
|
|
|
-+static const char *nios2_custom_fpu_insn_iss (rtx, int, const char *);
|
|
|
-+static const char *nios2_custom_fpu_insn_ddd (rtx, int, const char *);
|
|
|
-+static const char *nios2_custom_fpu_insn_ddz (rtx, int, const char *);
|
|
|
-+static const char *nios2_custom_fpu_insn_idd (rtx, int, const char *);
|
|
|
-+static const char *nios2_custom_fpu_insn_siz (rtx, int, const char *);
|
|
|
-+static const char *nios2_custom_fpu_insn_suz (rtx, int, const char *);
|
|
|
-+static const char *nios2_custom_fpu_insn_diz (rtx, int, const char *);
|
|
|
-+static const char *nios2_custom_fpu_insn_duz (rtx, int, const char *);
|
|
|
-+static const char *nios2_custom_fpu_insn_isz (rtx, int, const char *);
|
|
|
-+static const char *nios2_custom_fpu_insn_usz (rtx, int, const char *);
|
|
|
-+static const char *nios2_custom_fpu_insn_idz (rtx, int, const char *);
|
|
|
-+static const char *nios2_custom_fpu_insn_udz (rtx, int, const char *);
|
|
|
-+static const char *nios2_custom_fpu_insn_dsz (rtx, int, const char *);
|
|
|
-+static const char *nios2_custom_fpu_insn_sdz (rtx, int, const char *);
|
|
|
-+
|
|
|
-+static const char *
|
|
|
-+nios2_custom_fpu_insn_zdz (rtx insn, int N, const char *opt)
|
|
|
-+{
|
|
|
-+ static char buf[1024];
|
|
|
-+
|
|
|
-+ if (N < 0)
|
|
|
-+ {
|
|
|
-+ fatal_insn ("attempt to use disabled fpu instruction", insn);
|
|
|
-+ }
|
|
|
-+ if (snprintf (buf, sizeof (buf),
|
|
|
-+ "custom\t%d, zero, %%0, %%D0 # %s %%0",
|
|
|
-+ N, opt) >= (int)sizeof (buf))
|
|
|
-+ {
|
|
|
-+ fatal_insn ("buffer overflow", insn);
|
|
|
-+ }
|
|
|
-+ return buf;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static const char *
|
|
|
-+nios2_custom_fpu_insn_zsz (rtx insn, int N, const char *opt)
|
|
|
-+{
|
|
|
-+ static char buf[1024];
|
|
|
-+
|
|
|
-+ if (N < 0)
|
|
|
-+ {
|
|
|
-+ fatal_insn ("attempt to use disabled fpu instruction", insn);
|
|
|
-+ }
|
|
|
-+ if (snprintf (buf, sizeof (buf),
|
|
|
-+ "custom\t%d, zero, %%0, zero # %s %%0",
|
|
|
-+ N, opt) >= (int)sizeof (buf))
|
|
|
-+ {
|
|
|
-+ fatal_insn ("buffer overflow", insn);
|
|
|
-+ }
|
|
|
-+ return buf;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static const char *
|
|
|
-+nios2_custom_fpu_insn_szz (rtx insn, int N, const char *opt)
|
|
|
-+{
|
|
|
-+ static char buf[1024];
|
|
|
-+
|
|
|
-+ if (N < 0)
|
|
|
-+ {
|
|
|
-+ fatal_insn ("attempt to use disabled fpu instruction", insn);
|
|
|
-+ }
|
|
|
-+ if (snprintf (buf, sizeof (buf),
|
|
|
-+ "custom\t%d, %%0, zero, zero # %s %%0",
|
|
|
-+ N, opt) >= (int)sizeof (buf))
|
|
|
-+ {
|
|
|
-+ fatal_insn ("buffer overflow", insn);
|
|
|
-+ }
|
|
|
-+ return buf;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static const char *
|
|
|
-+nios2_custom_fpu_insn_sss (rtx insn, int N, const char *opt)
|
|
|
-+{
|
|
|
-+ static char buf[1024];
|
|
|
-+
|
|
|
-+ if (N < 0)
|
|
|
-+ {
|
|
|
-+ fatal_insn ("attempt to use disabled fpu instruction", insn);
|
|
|
-+ }
|
|
|
-+ if (snprintf (buf, sizeof (buf),
|
|
|
-+ "custom\t%d, %%0, %%1, %%2 # %s %%0, %%1, %%2",
|
|
|
-+ N, opt) >= (int)sizeof (buf))
|
|
|
-+ {
|
|
|
-+ fatal_insn ("buffer overflow", insn);
|
|
|
-+ }
|
|
|
-+ return buf;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static const char *
|
|
|
-+nios2_custom_fpu_insn_ssz (rtx insn, int N, const char *opt)
|
|
|
-+{
|
|
|
-+ static char buf[1024];
|
|
|
-+
|
|
|
-+ if (N < 0)
|
|
|
-+ {
|
|
|
-+ fatal_insn ("attempt to use disabled fpu instruction", insn);
|
|
|
-+ }
|
|
|
-+ if (snprintf (buf, sizeof (buf),
|
|
|
-+ "custom\t%d, %%0, %%1, zero # %s %%0, %%1",
|
|
|
-+ N, opt) >= (int)sizeof (buf))
|
|
|
-+ {
|
|
|
-+ fatal_insn ("buffer overflow", insn);
|
|
|
-+ }
|
|
|
-+ return buf;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static const char *
|
|
|
-+nios2_custom_fpu_insn_iss (rtx insn, int N, const char *opt)
|
|
|
-+{
|
|
|
-+ return nios2_custom_fpu_insn_sss (insn, N, opt);
|
|
|
-+}
|
|
|
-+
|
|
|
-+static const char *
|
|
|
-+nios2_custom_fpu_insn_ddd (rtx insn, int N, const char *opt)
|
|
|
-+{
|
|
|
-+ static char buf[1024];
|
|
|
-+
|
|
|
-+ if (N < 0
|
|
|
-+ || nios2_fpu_insns[nios2_fpu_nios2_frdy].N < 0
|
|
|
-+ || nios2_fpu_insns[nios2_fpu_nios2_fwrx].N < 0)
|
|
|
-+ {
|
|
|
-+ fatal_insn ("attempt to use disabled fpu instruction", insn);
|
|
|
-+ }
|
|
|
-+ if (snprintf (buf, sizeof (buf),
|
|
|
-+ "custom\t%d, zero, %%1, %%D1 # fwrx %%1\n\t"
|
|
|
-+ "custom\t%d, %%D0, %%2, %%D2 # %s %%0, %%1, %%2\n\t"
|
|
|
-+ "custom\t%d, %%0, zero, zero # frdy %%0",
|
|
|
-+ nios2_fpu_insns[nios2_fpu_nios2_fwrx].N,
|
|
|
-+ N, opt,
|
|
|
-+ nios2_fpu_insns[nios2_fpu_nios2_frdy].N) >= (int)sizeof (buf))
|
|
|
-+ {
|
|
|
-+ fatal_insn ("buffer overflow", insn);
|
|
|
-+ }
|
|
|
-+ return buf;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static const char *
|
|
|
-+nios2_custom_fpu_insn_ddz (rtx insn, int N, const char *opt)
|
|
|
-+{
|
|
|
-+ static char buf[1024];
|
|
|
-+
|
|
|
-+ if (N < 0 || nios2_fpu_insns[nios2_fpu_nios2_frdy].N < 0)
|
|
|
-+ {
|
|
|
-+ fatal_insn ("attempt to use disabled fpu instruction", insn);
|
|
|
-+ }
|
|
|
-+ if (snprintf (buf, sizeof (buf),
|
|
|
-+ "custom\t%d, %%D0, %%1, %%D1 # %s %%0, %%1\n\t"
|
|
|
-+ "custom\t%d, %%0, zero, zero # frdy %%0",
|
|
|
-+ N, opt,
|
|
|
-+ nios2_fpu_insns[nios2_fpu_nios2_frdy].N) >= (int)sizeof (buf))
|
|
|
-+ {
|
|
|
-+ fatal_insn ("buffer overflow", insn);
|
|
|
-+ }
|
|
|
-+ return buf;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static const char *
|
|
|
-+nios2_custom_fpu_insn_idd (rtx insn, int N, const char *opt)
|
|
|
-+{
|
|
|
-+ static char buf[1024];
|
|
|
-+
|
|
|
-+ if (N < 0 || nios2_fpu_insns[nios2_fpu_nios2_fwrx].N < 0)
|
|
|
-+ {
|
|
|
-+ fatal_insn ("attempt to use disabled fpu instruction", insn);
|
|
|
-+ }
|
|
|
-+ if (snprintf (buf, sizeof (buf),
|
|
|
-+ "custom\t%d, zero, %%1, %%D1 # fwrx %%1\n\t"
|
|
|
-+ "custom\t%d, %%0, %%2, %%D2 # %s %%0, %%1, %%2",
|
|
|
-+ nios2_fpu_insns[nios2_fpu_nios2_fwrx].N,
|
|
|
-+ N, opt) >= (int)sizeof (buf))
|
|
|
-+ {
|
|
|
-+ fatal_insn ("buffer overflow", insn);
|
|
|
-+ }
|
|
|
-+ return buf;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static const char *
|
|
|
-+nios2_custom_fpu_insn_siz (rtx insn, int N, const char *opt)
|
|
|
-+{
|
|
|
-+ return nios2_custom_fpu_insn_ssz (insn, N, opt);
|
|
|
-+}
|
|
|
-+
|
|
|
-+static const char *
|
|
|
-+nios2_custom_fpu_insn_suz (rtx insn, int N, const char *opt)
|
|
|
-+{
|
|
|
-+ return nios2_custom_fpu_insn_ssz (insn, N, opt);
|
|
|
-+}
|
|
|
-+
|
|
|
-+static const char *
|
|
|
-+nios2_custom_fpu_insn_diz (rtx insn, int N, const char *opt)
|
|
|
-+{
|
|
|
-+ return nios2_custom_fpu_insn_dsz (insn, N, opt);
|
|
|
-+}
|
|
|
-+
|
|
|
-+static const char *
|
|
|
-+nios2_custom_fpu_insn_duz (rtx insn, int N, const char *opt)
|
|
|
-+{
|
|
|
-+ return nios2_custom_fpu_insn_dsz (insn, N, opt);
|
|
|
-+}
|
|
|
-+
|
|
|
-+static const char *
|
|
|
-+nios2_custom_fpu_insn_isz (rtx insn, int N, const char *opt)
|
|
|
-+{
|
|
|
-+ return nios2_custom_fpu_insn_ssz (insn, N, opt);
|
|
|
-+}
|
|
|
-+
|
|
|
-+static const char *
|
|
|
-+nios2_custom_fpu_insn_usz (rtx insn, int N, const char *opt)
|
|
|
-+{
|
|
|
-+ return nios2_custom_fpu_insn_ssz (insn, N, opt);
|
|
|
-+}
|
|
|
-+
|
|
|
-+static const char *
|
|
|
-+nios2_custom_fpu_insn_idz (rtx insn, int N, const char *opt)
|
|
|
-+{
|
|
|
-+ return nios2_custom_fpu_insn_sdz (insn, N, opt);
|
|
|
-+}
|
|
|
-+
|
|
|
-+static const char *
|
|
|
-+nios2_custom_fpu_insn_udz (rtx insn, int N, const char *opt)
|
|
|
-+{
|
|
|
-+ return nios2_custom_fpu_insn_sdz (insn, N, opt);
|
|
|
-+}
|
|
|
-+
|
|
|
-+static const char *
|
|
|
-+nios2_custom_fpu_insn_dsz (rtx insn, int N, const char *opt)
|
|
|
-+{
|
|
|
-+ static char buf[1024];
|
|
|
-+
|
|
|
-+ if (N < 0 || nios2_fpu_insns[nios2_fpu_nios2_frdy].N < 0)
|
|
|
-+ {
|
|
|
-+ fatal_insn ("attempt to use disabled fpu instruction", insn);
|
|
|
-+ }
|
|
|
-+ if (snprintf (buf, sizeof (buf),
|
|
|
-+ "custom\t%d, %%D0, %%1, zero # %s %%0, %%1\n\t"
|
|
|
-+ "custom\t%d, %%0, zero, zero # frdy %%0",
|
|
|
-+ N, opt,
|
|
|
-+ nios2_fpu_insns[nios2_fpu_nios2_frdy].N) >= (int)sizeof (buf))
|
|
|
-+ {
|
|
|
-+ fatal_insn ("buffer overflow", insn);
|
|
|
-+ }
|
|
|
-+ return buf;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static const char *
|
|
|
-+nios2_custom_fpu_insn_sdz (rtx insn, int N, const char *opt)
|
|
|
-+{
|
|
|
-+ static char buf[1024];
|
|
|
-+
|
|
|
-+ if (N < 0)
|
|
|
-+ {
|
|
|
-+ fatal_insn ("attempt to use disabled fpu instruction", insn);
|
|
|
-+ }
|
|
|
-+ if (snprintf (buf, sizeof (buf),
|
|
|
-+ "custom\t%d, %%0, %%1, %%D1 # %s %%0, %%1",
|
|
|
-+ N, opt) >= (int)sizeof (buf))
|
|
|
-+ {
|
|
|
-+ fatal_insn ("buffer overflow", insn);
|
|
|
-+ }
|
|
|
-+ return buf;
|
|
|
-+}
|
|
|
-+
|
|
|
-+#undef NIOS2_FPU_INSN
|
|
|
-+#define NIOS2_FPU_INSN(opt, insn, args) \
|
|
|
-+static const char * \
|
|
|
-+NIOS2_CONCAT (nios2_output_fpu_insn_, insn) (rtx i) \
|
|
|
-+{ \
|
|
|
-+ return NIOS2_CONCAT (nios2_custom_fpu_insn_, args) \
|
|
|
-+ (i, \
|
|
|
-+ nios2_fpu_insns[NIOS2_CONCAT (nios2_fpu_, insn)].N, \
|
|
|
-+ nios2_fpu_insns[NIOS2_CONCAT (nios2_fpu_, insn)].option); \
|
|
|
-+}
|
|
|
-+NIOS2_FOR_ALL_FPU_INSNS
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+const char *
|
|
|
-+nios2_output_fpu_insn_cmps (rtx insn, enum rtx_code cond)
|
|
|
-+{
|
|
|
-+ static char buf[1024];
|
|
|
-+ int N;
|
|
|
-+ const char *opt;
|
|
|
-+
|
|
|
-+ int operandL = 2;
|
|
|
-+ int operandR = 3;
|
|
|
-+
|
|
|
-+ if ( !have_nios2_fpu_cmp_insn(cond, CMP_SF) &&
|
|
|
-+ have_nios2_fpu_cmp_insn(get_reverse_cond(cond), CMP_SF) ) {
|
|
|
-+
|
|
|
-+ int temp = operandL;
|
|
|
-+ operandL = operandR;
|
|
|
-+ operandR = temp;
|
|
|
-+
|
|
|
-+ cond = get_reverse_cond(cond);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ switch (cond)
|
|
|
-+ {
|
|
|
-+ case EQ:
|
|
|
-+ N = nios2_fpu_insns[nios2_fpu_nios2_seqsf].N;
|
|
|
-+ opt = "fcmpeqs";
|
|
|
-+ break;
|
|
|
-+ case NE:
|
|
|
-+ N = nios2_fpu_insns[nios2_fpu_nios2_snesf].N;
|
|
|
-+ opt = "fcmpnes";
|
|
|
-+ break;
|
|
|
-+ case GT:
|
|
|
-+ N = nios2_fpu_insns[nios2_fpu_nios2_sgtsf].N;
|
|
|
-+ opt = "fcmpgts";
|
|
|
-+ break;
|
|
|
-+ case GE:
|
|
|
-+ N = nios2_fpu_insns[nios2_fpu_nios2_sgesf].N;
|
|
|
-+ opt = "fcmpges";
|
|
|
-+ break;
|
|
|
-+ case LT:
|
|
|
-+ N = nios2_fpu_insns[nios2_fpu_nios2_sltsf].N;
|
|
|
-+ opt = "fcmplts";
|
|
|
-+ break;
|
|
|
-+ case LE:
|
|
|
-+ N = nios2_fpu_insns[nios2_fpu_nios2_slesf].N;
|
|
|
-+ opt = "fcmples"; break;
|
|
|
-+ default:
|
|
|
-+ fatal_insn ("bad single compare", insn);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (N < 0)
|
|
|
-+ {
|
|
|
-+ fatal_insn ("attempt to use disabled fpu instruction", insn);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /*
|
|
|
-+ * ??? This raises the whole vexing issue of how to handle
|
|
|
-+ * out-of-range branches. Punt for now, seeing as how nios2-elf-as
|
|
|
-+ * doesn't even _try_ to handle out-of-range branches yet!
|
|
|
-+ */
|
|
|
-+ if (snprintf (buf, sizeof (buf),
|
|
|
-+ ".set\tnoat\n\t"
|
|
|
-+ "custom\t%d, at, %%%d, %%%d # %s at, %%%d, %%%d\n\t"
|
|
|
-+ "bne\tat, zero, %%l1\n\t"
|
|
|
-+ ".set\tat",
|
|
|
-+ N, operandL, operandR, opt, operandL, operandR) >= (int)sizeof (buf))
|
|
|
-+ {
|
|
|
-+ fatal_insn ("buffer overflow", insn);
|
|
|
-+ }
|
|
|
-+ return buf;
|
|
|
-+}
|
|
|
-+
|
|
|
-+const char *
|
|
|
-+nios2_output_fpu_insn_cmpd (rtx insn, enum rtx_code cond)
|
|
|
-+{
|
|
|
-+ static char buf[1024];
|
|
|
-+ int N;
|
|
|
-+ const char *opt;
|
|
|
-+
|
|
|
-+ int operandL = 2;
|
|
|
-+ int operandR = 3;
|
|
|
-+
|
|
|
-+ if ( !have_nios2_fpu_cmp_insn(cond, CMP_DF) &&
|
|
|
-+ have_nios2_fpu_cmp_insn(get_reverse_cond(cond), CMP_DF) ) {
|
|
|
-+
|
|
|
-+ int temp = operandL;
|
|
|
-+ operandL = operandR;
|
|
|
-+ operandR = temp;
|
|
|
-+
|
|
|
-+ cond = get_reverse_cond(cond);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ switch (cond)
|
|
|
-+ {
|
|
|
-+ case EQ:
|
|
|
-+ N = nios2_fpu_insns[nios2_fpu_nios2_seqdf].N;
|
|
|
-+ opt = "fcmpeqd";
|
|
|
-+ break;
|
|
|
-+ case NE:
|
|
|
-+ N = nios2_fpu_insns[nios2_fpu_nios2_snedf].N;
|
|
|
-+ opt = "fcmpned";
|
|
|
-+ break;
|
|
|
-+ case GT:
|
|
|
-+ N = nios2_fpu_insns[nios2_fpu_nios2_sgtdf].N;
|
|
|
-+ opt = "fcmpgtd";
|
|
|
-+ break;
|
|
|
-+ case GE:
|
|
|
-+ N = nios2_fpu_insns[nios2_fpu_nios2_sgedf].N;
|
|
|
-+ opt = "fcmpged";
|
|
|
-+ break;
|
|
|
-+ case LT:
|
|
|
-+ N = nios2_fpu_insns[nios2_fpu_nios2_sltdf].N;
|
|
|
-+ opt = "fcmpltd";
|
|
|
-+ break;
|
|
|
-+ case LE:
|
|
|
-+ N = nios2_fpu_insns[nios2_fpu_nios2_sledf].N;
|
|
|
-+ opt = "fcmpled";
|
|
|
-+ break;
|
|
|
-+ default:
|
|
|
-+ fatal_insn ("bad double compare", insn);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (N < 0 || nios2_fpu_insns[nios2_fpu_nios2_fwrx].N < 0)
|
|
|
-+ {
|
|
|
-+ fatal_insn ("attempt to use disabled fpu instruction", insn);
|
|
|
-+ }
|
|
|
-+ if (snprintf (buf, sizeof (buf),
|
|
|
-+ ".set\tnoat\n\t"
|
|
|
-+ "custom\t%d, zero, %%%d, %%D%d # fwrx %%%d\n\t"
|
|
|
-+ "custom\t%d, at, %%%d, %%D%d # %s at, %%%d, %%%d\n\t"
|
|
|
-+ "bne\tat, zero, %%l1\n\t"
|
|
|
-+ ".set\tat",
|
|
|
-+ nios2_fpu_insns[nios2_fpu_nios2_fwrx].N, operandL, operandL, operandL,
|
|
|
-+ N, operandR, operandR, operandL, operandR, opt) >= (int)sizeof (buf))
|
|
|
-+ {
|
|
|
-+ fatal_insn ("buffer overflow", insn);
|
|
|
-+ }
|
|
|
-+ return buf;
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+/*****************************************************************************
|
|
|
-+**
|
|
|
-+** instruction scheduler
|
|
|
-+**
|
|
|
-+*****************************************************************************/
|
|
|
-+static int
|
|
|
-+nios2_use_dfa_pipeline_interface ()
|
|
|
-+{
|
|
|
-+ return 1;
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+static int
|
|
|
-+nios2_issue_rate ()
|
|
|
-+{
|
|
|
-+#ifdef MAX_DFA_ISSUE_RATE
|
|
|
-+ return MAX_DFA_ISSUE_RATE;
|
|
|
-+#else
|
|
|
-+ return 1;
|
|
|
-+#endif
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+const char *
|
|
|
-+asm_output_opcode (FILE *file ATTRIBUTE_UNUSED,
|
|
|
-+ const char *ptr ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ const char *p;
|
|
|
-+
|
|
|
-+ p = ptr;
|
|
|
-+ return ptr;
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+/*****************************************************************************
|
|
|
-+**
|
|
|
-+** function arguments
|
|
|
-+**
|
|
|
-+*****************************************************************************/
|
|
|
-+
|
|
|
-+void
|
|
|
-+init_cumulative_args (CUMULATIVE_ARGS *cum,
|
|
|
-+ tree fntype ATTRIBUTE_UNUSED,
|
|
|
-+ rtx libname ATTRIBUTE_UNUSED,
|
|
|
-+ tree fndecl ATTRIBUTE_UNUSED,
|
|
|
-+ int n_named_args ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ cum->regs_used = 0;
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+/* Define where to put the arguments to a function. Value is zero to
|
|
|
-+ push the argument on the stack, or a hard register in which to
|
|
|
-+ store the argument.
|
|
|
-+
|
|
|
-+ MODE is the argument's machine mode.
|
|
|
-+ TYPE is the data type of the argument (as a tree).
|
|
|
-+ This is null for libcalls where that information may
|
|
|
-+ not be available.
|
|
|
-+ CUM is a variable of type CUMULATIVE_ARGS which gives info about
|
|
|
-+ the preceding args and about the function being called.
|
|
|
-+ NAMED is nonzero if this argument is a named parameter
|
|
|
-+ (otherwise it is an extra parameter matching an ellipsis). */
|
|
|
-+rtx
|
|
|
-+function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
|
|
|
-+ tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ rtx return_rtx = NULL_RTX;
|
|
|
-+
|
|
|
-+ if (cum->regs_used < NUM_ARG_REGS)
|
|
|
-+ {
|
|
|
-+ return_rtx = gen_rtx_REG (mode, FIRST_ARG_REGNO + cum->regs_used);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return return_rtx;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/*
|
|
|
-+ * This is just default_must_pass_in_stack from calls.c sans the final
|
|
|
-+ * test for padding which isn't needed: we define BLOCK_REG_PADDING
|
|
|
-+ * instead.
|
|
|
-+ */
|
|
|
-+int
|
|
|
-+nios2_must_pass_in_stack (enum machine_mode mode, tree type)
|
|
|
-+{
|
|
|
-+ if (!type)
|
|
|
-+ return false;
|
|
|
-+
|
|
|
-+ /* If the type has variable size... */
|
|
|
-+ if (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
|
|
|
-+ return true;
|
|
|
-+
|
|
|
-+ /* If the type is marked as addressable (it is required
|
|
|
-+ to be constructed into the stack)... */
|
|
|
-+ if (TREE_ADDRESSABLE (type))
|
|
|
-+ return true;
|
|
|
-+
|
|
|
-+ return false;
|
|
|
-+}
|
|
|
-+
|
|
|
-+int
|
|
|
-+function_arg_partial_nregs (const CUMULATIVE_ARGS *cum,
|
|
|
-+ enum machine_mode mode, tree type,
|
|
|
-+ int named ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ HOST_WIDE_INT param_size;
|
|
|
-+
|
|
|
-+ if (mode == BLKmode)
|
|
|
-+ {
|
|
|
-+ param_size = int_size_in_bytes (type);
|
|
|
-+ if (param_size < 0)
|
|
|
-+ internal_error
|
|
|
-+ ("Do not know how to handle large structs or variable length types");
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ param_size = GET_MODE_SIZE (mode);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* convert to words (round up) */
|
|
|
-+ param_size = (3 + param_size) / 4;
|
|
|
-+
|
|
|
-+ if (cum->regs_used < NUM_ARG_REGS
|
|
|
-+ && cum->regs_used + param_size > NUM_ARG_REGS)
|
|
|
-+ {
|
|
|
-+ return NUM_ARG_REGS - cum->regs_used;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ return 0;
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+/* Update the data in CUM to advance over an argument
|
|
|
-+ of mode MODE and data type TYPE.
|
|
|
-+ (TYPE is null for libcalls where that information may not be available.) */
|
|
|
-+
|
|
|
-+void
|
|
|
-+function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
|
|
|
-+ tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ HOST_WIDE_INT param_size;
|
|
|
-+
|
|
|
-+ if (mode == BLKmode)
|
|
|
-+ {
|
|
|
-+ param_size = int_size_in_bytes (type);
|
|
|
-+ if (param_size < 0)
|
|
|
-+ internal_error
|
|
|
-+ ("Do not know how to handle large structs or variable length types");
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ param_size = GET_MODE_SIZE (mode);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* convert to words (round up) */
|
|
|
-+ param_size = (3 + param_size) / 4;
|
|
|
-+
|
|
|
-+ if (cum->regs_used + param_size > NUM_ARG_REGS)
|
|
|
-+ {
|
|
|
-+ cum->regs_used = NUM_ARG_REGS;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ cum->regs_used += param_size;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return;
|
|
|
-+}
|
|
|
-+
|
|
|
-+int
|
|
|
-+nios2_function_arg_padding_upward (enum machine_mode mode, tree type)
|
|
|
-+{
|
|
|
-+ /* On little-endian targets, the first byte of every stack argument
|
|
|
-+ is passed in the first byte of the stack slot. */
|
|
|
-+ if (!BYTES_BIG_ENDIAN)
|
|
|
-+ return 1;
|
|
|
-+
|
|
|
-+ /* Otherwise, integral types are padded downward: the last byte of a
|
|
|
-+ stack argument is passed in the last byte of the stack slot. */
|
|
|
-+ if (type != 0
|
|
|
-+ ? INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type)
|
|
|
-+ : GET_MODE_CLASS (mode) == MODE_INT)
|
|
|
-+ return 0;
|
|
|
-+
|
|
|
-+ /* Arguments smaller than a stack slot are padded downward. */
|
|
|
-+ if (mode != BLKmode)
|
|
|
-+ return (GET_MODE_BITSIZE (mode) >= PARM_BOUNDARY) ? 1 : 0;
|
|
|
-+ else
|
|
|
-+ return ((int_size_in_bytes (type) >= (PARM_BOUNDARY / BITS_PER_UNIT))
|
|
|
-+ ? 1 : 0);
|
|
|
-+}
|
|
|
-+
|
|
|
-+int
|
|
|
-+nios2_block_reg_padding_upward (enum machine_mode mode, tree type,
|
|
|
-+ int first ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ /* ??? Do we need to treat floating point specially, ala MIPS? */
|
|
|
-+ return nios2_function_arg_padding_upward (mode, type);
|
|
|
-+}
|
|
|
-+
|
|
|
-+int
|
|
|
-+nios2_return_in_memory (tree type)
|
|
|
-+{
|
|
|
-+ int res = ((int_size_in_bytes (type) > (2 * UNITS_PER_WORD))
|
|
|
-+ || (int_size_in_bytes (type) == -1));
|
|
|
-+
|
|
|
-+ return res;
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* ??? It may be possible to eliminate the copyback and implement
|
|
|
-+ my own va_arg type, but that is more work for now. */
|
|
|
-+int
|
|
|
-+nios2_setup_incoming_varargs (const CUMULATIVE_ARGS *cum,
|
|
|
-+ enum machine_mode mode, tree type,
|
|
|
-+ int no_rtl)
|
|
|
-+{
|
|
|
-+ CUMULATIVE_ARGS local_cum;
|
|
|
-+ int regs_to_push;
|
|
|
-+
|
|
|
-+ local_cum = *cum;
|
|
|
-+ FUNCTION_ARG_ADVANCE (local_cum, mode, type, 1);
|
|
|
-+
|
|
|
-+ regs_to_push = NUM_ARG_REGS - local_cum.regs_used;
|
|
|
-+
|
|
|
-+ if (!no_rtl)
|
|
|
-+ {
|
|
|
-+ if (regs_to_push > 0)
|
|
|
-+ {
|
|
|
-+ rtx ptr, mem;
|
|
|
-+
|
|
|
-+ ptr = virtual_incoming_args_rtx;
|
|
|
-+ mem = gen_rtx_MEM (BLKmode, ptr);
|
|
|
-+
|
|
|
-+ /* va_arg is an array access in this case, which causes
|
|
|
-+ it to get MEM_IN_STRUCT_P set. We must set it here
|
|
|
-+ so that the insn scheduler won't assume that these
|
|
|
-+ stores can't possibly overlap with the va_arg loads. */
|
|
|
-+ MEM_SET_IN_STRUCT_P (mem, 1);
|
|
|
-+
|
|
|
-+ emit_insn (gen_blockage ());
|
|
|
-+ move_block_from_reg (local_cum.regs_used + FIRST_ARG_REGNO, mem,
|
|
|
-+ regs_to_push);
|
|
|
-+ emit_insn (gen_blockage ());
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return regs_to_push * UNITS_PER_WORD;
|
|
|
-+
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+/*****************************************************************************
|
|
|
-+**
|
|
|
-+** builtins
|
|
|
-+**
|
|
|
-+** This method for handling builtins is from CSP where _many_ more types of
|
|
|
-+** expanders have already been written. Check there first before writing
|
|
|
-+** new ones.
|
|
|
-+**
|
|
|
-+*****************************************************************************/
|
|
|
-+
|
|
|
-+enum nios2_builtins
|
|
|
-+{
|
|
|
-+ NIOS2_BUILTIN_LDBIO,
|
|
|
-+ NIOS2_BUILTIN_LDBUIO,
|
|
|
-+ NIOS2_BUILTIN_LDHIO,
|
|
|
-+ NIOS2_BUILTIN_LDHUIO,
|
|
|
-+ NIOS2_BUILTIN_LDWIO,
|
|
|
-+ NIOS2_BUILTIN_STBIO,
|
|
|
-+ NIOS2_BUILTIN_STHIO,
|
|
|
-+ NIOS2_BUILTIN_STWIO,
|
|
|
-+ NIOS2_BUILTIN_SYNC,
|
|
|
-+ NIOS2_BUILTIN_RDCTL,
|
|
|
-+ NIOS2_BUILTIN_WRCTL,
|
|
|
-+
|
|
|
-+#undef NIOS2_DO_BUILTIN
|
|
|
-+#define NIOS2_DO_BUILTIN(upper, lower, handler) \
|
|
|
-+ NIOS2_CONCAT (NIOS2_BUILTIN_CUSTOM_, upper),
|
|
|
-+NIOS2_FOR_ALL_CUSTOM_BUILTINS
|
|
|
-+
|
|
|
-+ NIOS2_FIRST_FPU_INSN,
|
|
|
-+
|
|
|
-+#undef NIOS2_FPU_INSN
|
|
|
-+#define NIOS2_FPU_INSN(opt, insn, args) \
|
|
|
-+ NIOS2_CONCAT (NIOS2_BUILTIN_FPU_, opt),
|
|
|
-+NIOS2_FOR_ALL_FPU_INSNS
|
|
|
-+
|
|
|
-+ NIOS2_LAST_FPU_INSN,
|
|
|
-+
|
|
|
-+ LIM_NIOS2_BUILTINS
|
|
|
-+};
|
|
|
-+
|
|
|
-+struct builtin_description
|
|
|
-+{
|
|
|
-+ const enum insn_code icode;
|
|
|
-+ const char *const name;
|
|
|
-+ const enum nios2_builtins code;
|
|
|
-+ const tree *type;
|
|
|
-+ rtx (* expander) (const struct builtin_description *,
|
|
|
-+ tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+};
|
|
|
-+
|
|
|
-+static rtx nios2_expand_STXIO (const struct builtin_description *,
|
|
|
-+ tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+static rtx nios2_expand_LDXIO (const struct builtin_description *,
|
|
|
-+ tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+static rtx nios2_expand_sync (const struct builtin_description *,
|
|
|
-+ tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+static rtx nios2_expand_rdctl (const struct builtin_description *,
|
|
|
-+ tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+static rtx nios2_expand_wrctl (const struct builtin_description *,
|
|
|
-+ tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+
|
|
|
-+static rtx nios2_expand_custom_n (const struct builtin_description *,
|
|
|
-+ tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+static rtx nios2_expand_custom_Xn (const struct builtin_description *,
|
|
|
-+ tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+static rtx nios2_expand_custom_nX (const struct builtin_description *,
|
|
|
-+ tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+static rtx nios2_expand_custom_XnX (const struct builtin_description *,
|
|
|
-+ tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+static rtx nios2_expand_custom_nXX (const struct builtin_description *,
|
|
|
-+ tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+static rtx nios2_expand_custom_XnXX (const struct builtin_description *,
|
|
|
-+ tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+
|
|
|
-+static rtx nios2_expand_custom_zdz (const struct builtin_description *,
|
|
|
-+ tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+static rtx nios2_expand_custom_zsz (const struct builtin_description *,
|
|
|
-+ tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+static rtx nios2_expand_custom_szz (const struct builtin_description *,
|
|
|
-+ tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+static rtx nios2_expand_custom_sss (const struct builtin_description *,
|
|
|
-+ tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+static rtx nios2_expand_custom_ssz (const struct builtin_description *,
|
|
|
-+ tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+static rtx nios2_expand_custom_iss (const struct builtin_description *,
|
|
|
-+ tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+static rtx nios2_expand_custom_ddd (const struct builtin_description *,
|
|
|
-+ tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+static rtx nios2_expand_custom_ddz (const struct builtin_description *,
|
|
|
-+ tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+static rtx nios2_expand_custom_idd (const struct builtin_description *,
|
|
|
-+ tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+static rtx nios2_expand_custom_siz (const struct builtin_description *,
|
|
|
-+ tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+static rtx nios2_expand_custom_suz (const struct builtin_description *,
|
|
|
-+ tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+static rtx nios2_expand_custom_diz (const struct builtin_description *,
|
|
|
-+ tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+static rtx nios2_expand_custom_duz (const struct builtin_description *,
|
|
|
-+ tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+static rtx nios2_expand_custom_isz (const struct builtin_description *,
|
|
|
-+ tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+static rtx nios2_expand_custom_usz (const struct builtin_description *,
|
|
|
-+ tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+static rtx nios2_expand_custom_idz (const struct builtin_description *,
|
|
|
-+ tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+static rtx nios2_expand_custom_udz (const struct builtin_description *,
|
|
|
-+ tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+static rtx nios2_expand_custom_dsz (const struct builtin_description *,
|
|
|
-+ tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+static rtx nios2_expand_custom_sdz (const struct builtin_description *,
|
|
|
-+ tree, rtx, rtx, enum machine_mode, int);
|
|
|
-+
|
|
|
-+static tree endlink;
|
|
|
-+
|
|
|
-+/* int fn (volatile const void *)
|
|
|
-+ */
|
|
|
-+static tree int_ftype_volatile_const_void_p;
|
|
|
-+
|
|
|
-+/* int fn (int)
|
|
|
-+ */
|
|
|
-+static tree int_ftype_int;
|
|
|
-+
|
|
|
-+/* void fn (int, int)
|
|
|
-+ */
|
|
|
-+static tree void_ftype_int_int;
|
|
|
-+
|
|
|
-+/* void fn (volatile void *, int)
|
|
|
-+ */
|
|
|
-+static tree void_ftype_volatile_void_p_int;
|
|
|
-+
|
|
|
-+/* void fn (void)
|
|
|
-+ */
|
|
|
-+static tree void_ftype_void;
|
|
|
-+
|
|
|
-+#undef NIOS2_DO_BUILTIN
|
|
|
-+#define NIOS2_DO_BUILTIN(upper, lower, handler) \
|
|
|
-+ static tree NIOS2_CONCAT (custom_, lower);
|
|
|
-+NIOS2_FOR_ALL_CUSTOM_BUILTINS
|
|
|
-+
|
|
|
-+static tree custom_zdz;
|
|
|
-+static tree custom_zsz;
|
|
|
-+static tree custom_szz;
|
|
|
-+static tree custom_sss;
|
|
|
-+static tree custom_ssz;
|
|
|
-+static tree custom_iss;
|
|
|
-+static tree custom_ddd;
|
|
|
-+static tree custom_ddz;
|
|
|
-+static tree custom_idd;
|
|
|
-+static tree custom_siz;
|
|
|
-+static tree custom_suz;
|
|
|
-+static tree custom_diz;
|
|
|
-+static tree custom_duz;
|
|
|
-+static tree custom_isz;
|
|
|
-+static tree custom_usz;
|
|
|
-+static tree custom_idz;
|
|
|
-+static tree custom_udz;
|
|
|
-+static tree custom_dsz;
|
|
|
-+static tree custom_sdz;
|
|
|
-+
|
|
|
-+static const struct builtin_description bdesc[] = {
|
|
|
-+ {CODE_FOR_ldbio, "__builtin_ldbio", NIOS2_BUILTIN_LDBIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO},
|
|
|
-+ {CODE_FOR_ldbuio, "__builtin_ldbuio", NIOS2_BUILTIN_LDBUIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO},
|
|
|
-+ {CODE_FOR_ldhio, "__builtin_ldhio", NIOS2_BUILTIN_LDHIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO},
|
|
|
-+ {CODE_FOR_ldhuio, "__builtin_ldhuio", NIOS2_BUILTIN_LDHUIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO},
|
|
|
-+ {CODE_FOR_ldwio, "__builtin_ldwio", NIOS2_BUILTIN_LDWIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO},
|
|
|
-+
|
|
|
-+ {CODE_FOR_stbio, "__builtin_stbio", NIOS2_BUILTIN_STBIO, &void_ftype_volatile_void_p_int, nios2_expand_STXIO},
|
|
|
-+ {CODE_FOR_sthio, "__builtin_sthio", NIOS2_BUILTIN_STHIO, &void_ftype_volatile_void_p_int, nios2_expand_STXIO},
|
|
|
-+ {CODE_FOR_stwio, "__builtin_stwio", NIOS2_BUILTIN_STWIO, &void_ftype_volatile_void_p_int, nios2_expand_STXIO},
|
|
|
-+
|
|
|
-+ {CODE_FOR_sync, "__builtin_sync", NIOS2_BUILTIN_SYNC, &void_ftype_void, nios2_expand_sync},
|
|
|
-+ {CODE_FOR_rdctl, "__builtin_rdctl", NIOS2_BUILTIN_RDCTL, &int_ftype_int, nios2_expand_rdctl},
|
|
|
-+ {CODE_FOR_wrctl, "__builtin_wrctl", NIOS2_BUILTIN_WRCTL, &void_ftype_int_int, nios2_expand_wrctl},
|
|
|
-+
|
|
|
-+#undef NIOS2_DO_BUILTIN
|
|
|
-+#define NIOS2_DO_BUILTIN(upper, lower, handler) \
|
|
|
-+ {NIOS2_CONCAT (CODE_FOR_custom_, lower), \
|
|
|
-+ "__builtin_custom_" NIOS2_STRINGIFY (lower), \
|
|
|
-+ NIOS2_CONCAT (NIOS2_BUILTIN_CUSTOM_, upper), \
|
|
|
-+ &NIOS2_CONCAT (custom_, lower), \
|
|
|
-+ NIOS2_CONCAT (nios2_expand_custom_, handler)},
|
|
|
-+NIOS2_FOR_ALL_CUSTOM_BUILTINS
|
|
|
-+
|
|
|
-+#undef NIOS2_FPU_INSN
|
|
|
-+#define NIOS2_FPU_INSN(opt, insn, args) \
|
|
|
-+ {NIOS2_CONCAT (CODE_FOR_, insn), \
|
|
|
-+ "__builtin_custom_" NIOS2_STRINGIFY (opt), \
|
|
|
-+ NIOS2_CONCAT (NIOS2_BUILTIN_FPU_, opt), \
|
|
|
-+ &NIOS2_CONCAT (custom_, args), \
|
|
|
-+ NIOS2_CONCAT (nios2_expand_custom_, args)},
|
|
|
-+NIOS2_FOR_ALL_FPU_INSNS
|
|
|
-+
|
|
|
-+ {0, 0, 0, 0, 0},
|
|
|
-+};
|
|
|
-+
|
|
|
-+/* This does not have a closing bracket on purpose (see use) */
|
|
|
-+#define def_param(TYPE) \
|
|
|
-+ tree_cons (NULL_TREE, TYPE,
|
|
|
-+
|
|
|
-+static void
|
|
|
-+nios2_init_builtins ()
|
|
|
-+{
|
|
|
-+ const struct builtin_description *d;
|
|
|
-+
|
|
|
-+
|
|
|
-+ endlink = void_list_node;
|
|
|
-+
|
|
|
-+ /* Special indenting here because one of the brackets is in def_param */
|
|
|
-+ /* *INDENT-OFF* */
|
|
|
-+
|
|
|
-+ /* int fn (volatile const void *)
|
|
|
-+ */
|
|
|
-+ int_ftype_volatile_const_void_p
|
|
|
-+ = build_function_type (integer_type_node,
|
|
|
-+ def_param (build_qualified_type (ptr_type_node,
|
|
|
-+ TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE))
|
|
|
-+ endlink));
|
|
|
-+
|
|
|
-+
|
|
|
-+ /* void fn (volatile void *, int)
|
|
|
-+ */
|
|
|
-+ void_ftype_volatile_void_p_int
|
|
|
-+ = build_function_type (void_type_node,
|
|
|
-+ def_param (build_qualified_type (ptr_type_node,
|
|
|
-+ TYPE_QUAL_VOLATILE))
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ endlink)));
|
|
|
-+
|
|
|
-+ /* void fn (void)
|
|
|
-+ */
|
|
|
-+ void_ftype_void
|
|
|
-+ = build_function_type (void_type_node,
|
|
|
-+ endlink);
|
|
|
-+
|
|
|
-+ /* int fn (int)
|
|
|
-+ */
|
|
|
-+ int_ftype_int
|
|
|
-+ = build_function_type (integer_type_node,
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ endlink));
|
|
|
-+
|
|
|
-+ /* void fn (int, int)
|
|
|
-+ */
|
|
|
-+ void_ftype_int_int
|
|
|
-+ = build_function_type (void_type_node,
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ endlink)));
|
|
|
-+
|
|
|
-+
|
|
|
-+#define CUSTOM_NUM def_param (integer_type_node)
|
|
|
-+
|
|
|
-+ custom_n
|
|
|
-+ = build_function_type (void_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ endlink));
|
|
|
-+ custom_ni
|
|
|
-+ = build_function_type (void_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ endlink)));
|
|
|
-+ custom_nf
|
|
|
-+ = build_function_type (void_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ endlink)));
|
|
|
-+ custom_np
|
|
|
-+ = build_function_type (void_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (ptr_type_node)
|
|
|
-+ endlink)));
|
|
|
-+ custom_nii
|
|
|
-+ = build_function_type (void_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ endlink))));
|
|
|
-+ custom_nif
|
|
|
-+ = build_function_type (void_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ endlink))));
|
|
|
-+ custom_nip
|
|
|
-+ = build_function_type (void_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ def_param (ptr_type_node)
|
|
|
-+ endlink))));
|
|
|
-+ custom_nfi
|
|
|
-+ = build_function_type (void_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ endlink))));
|
|
|
-+ custom_nff
|
|
|
-+ = build_function_type (void_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ endlink))));
|
|
|
-+ custom_nfp
|
|
|
-+ = build_function_type (void_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ def_param (ptr_type_node)
|
|
|
-+ endlink))));
|
|
|
-+ custom_npi
|
|
|
-+ = build_function_type (void_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (ptr_type_node)
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ endlink))));
|
|
|
-+ custom_npf
|
|
|
-+ = build_function_type (void_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (ptr_type_node)
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ endlink))));
|
|
|
-+ custom_npp
|
|
|
-+ = build_function_type (void_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (ptr_type_node)
|
|
|
-+ def_param (ptr_type_node)
|
|
|
-+ endlink))));
|
|
|
-+
|
|
|
-+ custom_in
|
|
|
-+ = build_function_type (integer_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ endlink));
|
|
|
-+ custom_ini
|
|
|
-+ = build_function_type (integer_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ endlink)));
|
|
|
-+ custom_inf
|
|
|
-+ = build_function_type (integer_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ endlink)));
|
|
|
-+ custom_inp
|
|
|
-+ = build_function_type (integer_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (ptr_type_node)
|
|
|
-+ endlink)));
|
|
|
-+ custom_inii
|
|
|
-+ = build_function_type (integer_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ endlink))));
|
|
|
-+ custom_inif
|
|
|
-+ = build_function_type (integer_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ endlink))));
|
|
|
-+ custom_inip
|
|
|
-+ = build_function_type (integer_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ def_param (ptr_type_node)
|
|
|
-+ endlink))));
|
|
|
-+ custom_infi
|
|
|
-+ = build_function_type (integer_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ endlink))));
|
|
|
-+ custom_inff
|
|
|
-+ = build_function_type (integer_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ endlink))));
|
|
|
-+ custom_infp
|
|
|
-+ = build_function_type (integer_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ def_param (ptr_type_node)
|
|
|
-+ endlink))));
|
|
|
-+ custom_inpi
|
|
|
-+ = build_function_type (integer_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (ptr_type_node)
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ endlink))));
|
|
|
-+ custom_inpf
|
|
|
-+ = build_function_type (integer_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (ptr_type_node)
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ endlink))));
|
|
|
-+ custom_inpp
|
|
|
-+ = build_function_type (integer_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (ptr_type_node)
|
|
|
-+ def_param (ptr_type_node)
|
|
|
-+ endlink))));
|
|
|
-+
|
|
|
-+ custom_fn
|
|
|
-+ = build_function_type (float_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ endlink));
|
|
|
-+ custom_fni
|
|
|
-+ = build_function_type (float_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ endlink)));
|
|
|
-+ custom_fnf
|
|
|
-+ = build_function_type (float_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ endlink)));
|
|
|
-+ custom_fnp
|
|
|
-+ = build_function_type (float_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (ptr_type_node)
|
|
|
-+ endlink)));
|
|
|
-+ custom_fnii
|
|
|
-+ = build_function_type (float_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ endlink))));
|
|
|
-+ custom_fnif
|
|
|
-+ = build_function_type (float_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ endlink))));
|
|
|
-+ custom_fnip
|
|
|
-+ = build_function_type (float_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ def_param (ptr_type_node)
|
|
|
-+ endlink))));
|
|
|
-+ custom_fnfi
|
|
|
-+ = build_function_type (float_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ endlink))));
|
|
|
-+ custom_fnff
|
|
|
-+ = build_function_type (float_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ endlink))));
|
|
|
-+ custom_fnfp
|
|
|
-+ = build_function_type (float_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ def_param (ptr_type_node)
|
|
|
-+ endlink))));
|
|
|
-+ custom_fnpi
|
|
|
-+ = build_function_type (float_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (ptr_type_node)
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ endlink))));
|
|
|
-+ custom_fnpf
|
|
|
-+ = build_function_type (float_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (ptr_type_node)
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ endlink))));
|
|
|
-+ custom_fnpp
|
|
|
-+ = build_function_type (float_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (ptr_type_node)
|
|
|
-+ def_param (ptr_type_node)
|
|
|
-+ endlink))));
|
|
|
-+
|
|
|
-+
|
|
|
-+ custom_pn
|
|
|
-+ = build_function_type (ptr_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ endlink));
|
|
|
-+ custom_pni
|
|
|
-+ = build_function_type (ptr_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ endlink)));
|
|
|
-+ custom_pnf
|
|
|
-+ = build_function_type (ptr_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ endlink)));
|
|
|
-+ custom_pnp
|
|
|
-+ = build_function_type (ptr_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (ptr_type_node)
|
|
|
-+ endlink)));
|
|
|
-+ custom_pnii
|
|
|
-+ = build_function_type (ptr_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ endlink))));
|
|
|
-+ custom_pnif
|
|
|
-+ = build_function_type (ptr_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ endlink))));
|
|
|
-+ custom_pnip
|
|
|
-+ = build_function_type (ptr_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ def_param (ptr_type_node)
|
|
|
-+ endlink))));
|
|
|
-+ custom_pnfi
|
|
|
-+ = build_function_type (ptr_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ endlink))));
|
|
|
-+ custom_pnff
|
|
|
-+ = build_function_type (ptr_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ endlink))));
|
|
|
-+ custom_pnfp
|
|
|
-+ = build_function_type (ptr_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ def_param (ptr_type_node)
|
|
|
-+ endlink))));
|
|
|
-+ custom_pnpi
|
|
|
-+ = build_function_type (ptr_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (ptr_type_node)
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ endlink))));
|
|
|
-+ custom_pnpf
|
|
|
-+ = build_function_type (ptr_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (ptr_type_node)
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ endlink))));
|
|
|
-+ custom_pnpp
|
|
|
-+ = build_function_type (ptr_type_node,
|
|
|
-+ CUSTOM_NUM
|
|
|
-+ def_param (ptr_type_node)
|
|
|
-+ def_param (ptr_type_node)
|
|
|
-+ endlink))));
|
|
|
-+
|
|
|
-+ custom_zdz
|
|
|
-+ = build_function_type (void_type_node,
|
|
|
-+ def_param (double_type_node)
|
|
|
-+ endlink));
|
|
|
-+
|
|
|
-+ custom_zsz
|
|
|
-+ = build_function_type (void_type_node,
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ endlink));
|
|
|
-+
|
|
|
-+ custom_szz
|
|
|
-+ = build_function_type (float_type_node,
|
|
|
-+ def_param (void_type_node)
|
|
|
-+ endlink));
|
|
|
-+
|
|
|
-+ custom_sss
|
|
|
-+ = build_function_type (float_type_node,
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ endlink)));
|
|
|
-+
|
|
|
-+ custom_ssz
|
|
|
-+ = build_function_type (float_type_node,
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ endlink));
|
|
|
-+
|
|
|
-+ custom_iss
|
|
|
-+ = build_function_type (integer_type_node,
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ endlink)));
|
|
|
-+
|
|
|
-+ custom_ddd
|
|
|
-+ = build_function_type (double_type_node,
|
|
|
-+ def_param (double_type_node)
|
|
|
-+ def_param (double_type_node)
|
|
|
-+ endlink)));
|
|
|
-+
|
|
|
-+ custom_ddz
|
|
|
-+ = build_function_type (double_type_node,
|
|
|
-+ def_param (double_type_node)
|
|
|
-+ endlink));
|
|
|
-+
|
|
|
-+ custom_idd
|
|
|
-+ = build_function_type (integer_type_node,
|
|
|
-+ def_param (double_type_node)
|
|
|
-+ def_param (double_type_node)
|
|
|
-+ endlink)));
|
|
|
-+
|
|
|
-+ custom_siz
|
|
|
-+ = build_function_type (float_type_node,
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ endlink));
|
|
|
-+
|
|
|
-+ custom_suz
|
|
|
-+ = build_function_type (float_type_node,
|
|
|
-+ def_param (unsigned_type_node)
|
|
|
-+ endlink));
|
|
|
-+
|
|
|
-+ custom_diz
|
|
|
-+ = build_function_type (double_type_node,
|
|
|
-+ def_param (integer_type_node)
|
|
|
-+ endlink));
|
|
|
-+
|
|
|
-+ custom_duz
|
|
|
-+ = build_function_type (double_type_node,
|
|
|
-+ def_param (unsigned_type_node)
|
|
|
-+ endlink));
|
|
|
-+
|
|
|
-+ custom_isz
|
|
|
-+ = build_function_type (integer_type_node,
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ endlink));
|
|
|
-+
|
|
|
-+ custom_usz
|
|
|
-+ = build_function_type (unsigned_type_node,
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ endlink));
|
|
|
-+
|
|
|
-+ custom_idz
|
|
|
-+ = build_function_type (integer_type_node,
|
|
|
-+ def_param (double_type_node)
|
|
|
-+ endlink));
|
|
|
-+
|
|
|
-+ custom_udz
|
|
|
-+ = build_function_type (unsigned_type_node,
|
|
|
-+ def_param (double_type_node)
|
|
|
-+ endlink));
|
|
|
-+
|
|
|
-+ custom_dsz
|
|
|
-+ = build_function_type (double_type_node,
|
|
|
-+ def_param (float_type_node)
|
|
|
-+ endlink));
|
|
|
-+
|
|
|
-+ custom_sdz
|
|
|
-+ = build_function_type (float_type_node,
|
|
|
-+ def_param (double_type_node)
|
|
|
-+ endlink));
|
|
|
-+
|
|
|
-+ /* *INDENT-ON* */
|
|
|
-+
|
|
|
-+
|
|
|
-+ for (d = bdesc; d->name; d++)
|
|
|
-+ {
|
|
|
-+ builtin_function (d->name, *d->type, d->code,
|
|
|
-+ BUILT_IN_MD, NULL, NULL);
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* Expand an expression EXP that calls a built-in function,
|
|
|
-+ with result going to TARGET if that's convenient
|
|
|
-+ (and in mode MODE if that's convenient).
|
|
|
-+ SUBTARGET may be used as the target for computing one of EXP's operands.
|
|
|
-+ IGNORE is nonzero if the value is to be ignored. */
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_expand_builtin (tree exp, rtx target, rtx subtarget,
|
|
|
-+ enum machine_mode mode, int ignore)
|
|
|
-+{
|
|
|
-+ const struct builtin_description *d;
|
|
|
-+ tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
|
|
|
-+ unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
|
|
|
-+
|
|
|
-+ for (d = bdesc; d->name; d++)
|
|
|
-+ if (d->code == fcode)
|
|
|
-+ {
|
|
|
-+ if (d->code > NIOS2_FIRST_FPU_INSN && d->code < NIOS2_LAST_FPU_INSN)
|
|
|
-+ {
|
|
|
-+ nios2_fpu_info *inf = &nios2_fpu_insns[d->code - (NIOS2_FIRST_FPU_INSN + 1)];
|
|
|
-+ const struct insn_data *idata = &insn_data[d->icode];
|
|
|
-+ if (inf->N < 0)
|
|
|
-+ {
|
|
|
-+ fatal_error ("Cannot call `%s' without specifying switch `-mcustom-%s'",
|
|
|
-+ d->name,
|
|
|
-+ inf->option);
|
|
|
-+ }
|
|
|
-+ if (inf->args[0] != 'z'
|
|
|
-+ && (!target
|
|
|
-+ || !(idata->operand[0].predicate) (target,
|
|
|
-+ idata->operand[0].mode)))
|
|
|
-+ target = gen_reg_rtx (idata->operand[0].mode);
|
|
|
-+ }
|
|
|
-+ return (d->expander) (d, exp, target, subtarget, mode, ignore);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /* we should have seen one of the functins we registered */
|
|
|
-+ abort ();
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx nios2_create_target (const struct builtin_description *, rtx);
|
|
|
-+
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_create_target (const struct builtin_description *d, rtx target)
|
|
|
-+{
|
|
|
-+ if (!target
|
|
|
-+ || !(*insn_data[d->icode].operand[0].predicate) (target,
|
|
|
-+ insn_data[d->icode].operand[0].mode))
|
|
|
-+ {
|
|
|
-+ target = gen_reg_rtx (insn_data[d->icode].operand[0].mode);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return target;
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+static rtx nios2_extract_opcode (const struct builtin_description *, int, tree);
|
|
|
-+static rtx nios2_extract_operand (const struct builtin_description *, int, int, tree);
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_extract_opcode (const struct builtin_description *d, int op, tree arglist)
|
|
|
-+{
|
|
|
-+ enum machine_mode mode = insn_data[d->icode].operand[op].mode;
|
|
|
-+ tree arg = TREE_VALUE (arglist);
|
|
|
-+ rtx opcode = expand_expr (arg, NULL_RTX, mode, 0);
|
|
|
-+ opcode = protect_from_queue (opcode, 0);
|
|
|
-+
|
|
|
-+ if (!(*insn_data[d->icode].operand[op].predicate) (opcode, mode))
|
|
|
-+ error ("Custom instruction opcode must be compile time constant in the range 0-255 for %s", d->name);
|
|
|
-+
|
|
|
-+ builtin_custom_seen[INTVAL (opcode)] = d->name;
|
|
|
-+ nios2_custom_check_insns (0);
|
|
|
-+ return opcode;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_extract_operand (const struct builtin_description *d, int op, int argnum, tree arglist)
|
|
|
-+{
|
|
|
-+ enum machine_mode mode = insn_data[d->icode].operand[op].mode;
|
|
|
-+ tree arg = TREE_VALUE (arglist);
|
|
|
-+ rtx operand = expand_expr (arg, NULL_RTX, mode, 0);
|
|
|
-+ operand = protect_from_queue (operand, 0);
|
|
|
-+
|
|
|
-+ if (!(*insn_data[d->icode].operand[op].predicate) (operand, mode))
|
|
|
-+ operand = copy_to_mode_reg (mode, operand);
|
|
|
-+
|
|
|
-+ /* ??? Better errors would be nice */
|
|
|
-+ if (!(*insn_data[d->icode].operand[op].predicate) (operand, mode))
|
|
|
-+ error ("Invalid argument %d to %s", argnum, d->name);
|
|
|
-+
|
|
|
-+ return operand;
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_expand_custom_n (const struct builtin_description *d, tree exp,
|
|
|
-+ rtx target ATTRIBUTE_UNUSED, rtx subtarget ATTRIBUTE_UNUSED,
|
|
|
-+ enum machine_mode mode ATTRIBUTE_UNUSED, int ignore ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ tree arglist = TREE_OPERAND (exp, 1);
|
|
|
-+ rtx pat;
|
|
|
-+ rtx opcode;
|
|
|
-+
|
|
|
-+ /* custom_n should have exactly one operand */
|
|
|
-+ if (insn_data[d->icode].n_operands != 1)
|
|
|
-+ abort ();
|
|
|
-+
|
|
|
-+ opcode = nios2_extract_opcode (d, 0, arglist);
|
|
|
-+
|
|
|
-+ pat = GEN_FCN (d->icode) (opcode);
|
|
|
-+ if (!pat)
|
|
|
-+ return 0;
|
|
|
-+ emit_insn (pat);
|
|
|
-+ return 0;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_expand_custom_Xn (const struct builtin_description *d, tree exp,
|
|
|
-+ rtx target, rtx subtarget ATTRIBUTE_UNUSED,
|
|
|
-+ enum machine_mode mode ATTRIBUTE_UNUSED,
|
|
|
-+ int ignore ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ tree arglist = TREE_OPERAND (exp, 1);
|
|
|
-+ rtx pat;
|
|
|
-+ rtx opcode;
|
|
|
-+
|
|
|
-+ /* custom_Xn should have exactly two operands */
|
|
|
-+ if (insn_data[d->icode].n_operands != 2)
|
|
|
-+ abort ();
|
|
|
-+
|
|
|
-+ target = nios2_create_target (d, target);
|
|
|
-+ opcode = nios2_extract_opcode (d, 1, arglist);
|
|
|
-+
|
|
|
-+ pat = GEN_FCN (d->icode) (target, opcode);
|
|
|
-+ if (!pat)
|
|
|
-+ return 0;
|
|
|
-+ emit_insn (pat);
|
|
|
-+ return target;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_expand_custom_nX (const struct builtin_description *d, tree exp,
|
|
|
-+ rtx target ATTRIBUTE_UNUSED, rtx subtarget ATTRIBUTE_UNUSED,
|
|
|
-+ enum machine_mode mode ATTRIBUTE_UNUSED, int ignore ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ tree arglist = TREE_OPERAND (exp, 1);
|
|
|
-+ rtx pat;
|
|
|
-+ rtx opcode;
|
|
|
-+ rtx operands[1];
|
|
|
-+ int i;
|
|
|
-+
|
|
|
-+
|
|
|
-+ /* custom_nX should have exactly two operands */
|
|
|
-+ if (insn_data[d->icode].n_operands != 2)
|
|
|
-+ abort ();
|
|
|
-+
|
|
|
-+ opcode = nios2_extract_opcode (d, 0, arglist);
|
|
|
-+ for (i = 0; i < 1; i++)
|
|
|
-+ {
|
|
|
-+ arglist = TREE_CHAIN (arglist);
|
|
|
-+ operands[i] = nios2_extract_operand (d, i + 1, i + 1, arglist);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ pat = GEN_FCN (d->icode) (opcode, operands[0]);
|
|
|
-+ if (!pat)
|
|
|
-+ return 0;
|
|
|
-+ emit_insn (pat);
|
|
|
-+ return 0;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_expand_custom_XnX (const struct builtin_description *d, tree exp, rtx target,
|
|
|
-+ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED,
|
|
|
-+ int ignore ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ tree arglist = TREE_OPERAND (exp, 1);
|
|
|
-+ rtx pat;
|
|
|
-+ rtx opcode;
|
|
|
-+ rtx operands[1];
|
|
|
-+ int i;
|
|
|
-+
|
|
|
-+ /* custom_Xn should have exactly three operands */
|
|
|
-+ if (insn_data[d->icode].n_operands != 3)
|
|
|
-+ abort ();
|
|
|
-+
|
|
|
-+ target = nios2_create_target (d, target);
|
|
|
-+ opcode = nios2_extract_opcode (d, 1, arglist);
|
|
|
-+
|
|
|
-+ for (i = 0; i < 1; i++)
|
|
|
-+ {
|
|
|
-+ arglist = TREE_CHAIN (arglist);
|
|
|
-+ operands[i] = nios2_extract_operand (d, i + 2, i + 1, arglist);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ pat = GEN_FCN (d->icode) (target, opcode, operands[0]);
|
|
|
-+
|
|
|
-+ if (!pat)
|
|
|
-+ return 0;
|
|
|
-+ emit_insn (pat);
|
|
|
-+ return target;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_expand_custom_nXX (const struct builtin_description *d, tree exp, rtx target ATTRIBUTE_UNUSED,
|
|
|
-+ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED,
|
|
|
-+ int ignore ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ tree arglist = TREE_OPERAND (exp, 1);
|
|
|
-+ rtx pat;
|
|
|
-+ rtx opcode;
|
|
|
-+ rtx operands[2];
|
|
|
-+ int i;
|
|
|
-+
|
|
|
-+
|
|
|
-+ /* custom_nX should have exactly three operands */
|
|
|
-+ if (insn_data[d->icode].n_operands != 3)
|
|
|
-+ abort ();
|
|
|
-+
|
|
|
-+ opcode = nios2_extract_opcode (d, 0, arglist);
|
|
|
-+ for (i = 0; i < 2; i++)
|
|
|
-+ {
|
|
|
-+ arglist = TREE_CHAIN (arglist);
|
|
|
-+ operands[i] = nios2_extract_operand (d, i + 1, i + 1, arglist);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ pat = GEN_FCN (d->icode) (opcode, operands[0], operands[1]);
|
|
|
-+ if (!pat)
|
|
|
-+ return 0;
|
|
|
-+ emit_insn (pat);
|
|
|
-+ return 0;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_expand_custom_XnXX (const struct builtin_description *d, tree exp, rtx target,
|
|
|
-+ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED,
|
|
|
-+ int ignore ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ tree arglist = TREE_OPERAND (exp, 1);
|
|
|
-+ rtx pat;
|
|
|
-+ rtx opcode;
|
|
|
-+ rtx operands[2];
|
|
|
-+ int i;
|
|
|
-+
|
|
|
-+
|
|
|
-+ /* custom_XnX should have exactly four operands */
|
|
|
-+ if (insn_data[d->icode].n_operands != 4)
|
|
|
-+ abort ();
|
|
|
-+
|
|
|
-+ target = nios2_create_target (d, target);
|
|
|
-+ opcode = nios2_extract_opcode (d, 1, arglist);
|
|
|
-+ for (i = 0; i < 2; i++)
|
|
|
-+ {
|
|
|
-+ arglist = TREE_CHAIN (arglist);
|
|
|
-+ operands[i] = nios2_extract_operand (d, i + 2, i + 1, arglist);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ pat = GEN_FCN (d->icode) (target, opcode, operands[0], operands[1]);
|
|
|
-+
|
|
|
-+ if (!pat)
|
|
|
-+ return 0;
|
|
|
-+ emit_insn (pat);
|
|
|
-+ return target;
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_expand_STXIO (const struct builtin_description *d, tree exp, rtx target ATTRIBUTE_UNUSED,
|
|
|
-+ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED,
|
|
|
-+ int ignore ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ tree arglist = TREE_OPERAND (exp, 1);
|
|
|
-+ rtx pat;
|
|
|
-+ rtx store_dest, store_val;
|
|
|
-+ enum insn_code icode = d->icode;
|
|
|
-+
|
|
|
-+ /* stores should have exactly two operands */
|
|
|
-+ if (insn_data[icode].n_operands != 2)
|
|
|
-+ abort ();
|
|
|
-+
|
|
|
-+ /* process the destination of the store */
|
|
|
-+ {
|
|
|
-+ enum machine_mode mode = insn_data[icode].operand[0].mode;
|
|
|
-+ tree arg = TREE_VALUE (arglist);
|
|
|
-+ store_dest = expand_expr (arg, NULL_RTX, VOIDmode, 0);
|
|
|
-+ store_dest = protect_from_queue (store_dest, 0);
|
|
|
-+
|
|
|
-+ store_dest = gen_rtx_MEM (mode, copy_to_mode_reg (Pmode, store_dest));
|
|
|
-+
|
|
|
-+ /* ??? Better errors would be nice */
|
|
|
-+ if (!(*insn_data[icode].operand[0].predicate) (store_dest, mode))
|
|
|
-+ error ("Invalid argument 1 to %s", d->name);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+
|
|
|
-+ /* process the value to store */
|
|
|
-+ {
|
|
|
-+ enum machine_mode mode = insn_data[icode].operand[1].mode;
|
|
|
-+ tree arg = TREE_VALUE (TREE_CHAIN (arglist));
|
|
|
-+ store_val = expand_expr (arg, NULL_RTX, mode, 0);
|
|
|
-+ store_val = protect_from_queue (store_val, 0);
|
|
|
-+
|
|
|
-+ if (!(*insn_data[icode].operand[1].predicate) (store_val, mode))
|
|
|
-+ store_val = copy_to_mode_reg (mode, store_val);
|
|
|
-+
|
|
|
-+ /* ??? Better errors would be nice */
|
|
|
-+ if (!(*insn_data[icode].operand[1].predicate) (store_val, mode))
|
|
|
-+ error ("Invalid argument 2 to %s", d->name);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ pat = GEN_FCN (d->icode) (store_dest, store_val);
|
|
|
-+ if (!pat)
|
|
|
-+ return 0;
|
|
|
-+ emit_insn (pat);
|
|
|
-+ return 0;
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_expand_LDXIO (const struct builtin_description * d, tree exp, rtx target,
|
|
|
-+ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED,
|
|
|
-+ int ignore ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ tree arglist = TREE_OPERAND (exp, 1);
|
|
|
-+ rtx pat;
|
|
|
-+ rtx ld_src;
|
|
|
-+ enum insn_code icode = d->icode;
|
|
|
-+
|
|
|
-+ /* loads should have exactly two operands */
|
|
|
-+ if (insn_data[icode].n_operands != 2)
|
|
|
-+ abort ();
|
|
|
-+
|
|
|
-+ target = nios2_create_target (d, target);
|
|
|
-+
|
|
|
-+ {
|
|
|
-+ enum machine_mode mode = insn_data[icode].operand[1].mode;
|
|
|
-+ tree arg = TREE_VALUE (arglist);
|
|
|
-+ ld_src = expand_expr (arg, NULL_RTX, VOIDmode, 0);
|
|
|
-+ ld_src = protect_from_queue (ld_src, 0);
|
|
|
-+
|
|
|
-+ ld_src = gen_rtx_MEM (mode, copy_to_mode_reg (Pmode, ld_src));
|
|
|
-+
|
|
|
-+ /* ??? Better errors would be nice */
|
|
|
-+ if (!(*insn_data[icode].operand[1].predicate) (ld_src, mode))
|
|
|
-+ {
|
|
|
-+ error ("Invalid argument 1 to %s", d->name);
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ pat = GEN_FCN (d->icode) (target, ld_src);
|
|
|
-+ if (!pat)
|
|
|
-+ return 0;
|
|
|
-+ emit_insn (pat);
|
|
|
-+ return target;
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_expand_sync (const struct builtin_description * d ATTRIBUTE_UNUSED,
|
|
|
-+ tree exp ATTRIBUTE_UNUSED, rtx target ATTRIBUTE_UNUSED,
|
|
|
-+ rtx subtarget ATTRIBUTE_UNUSED,
|
|
|
-+ enum machine_mode mode ATTRIBUTE_UNUSED,
|
|
|
-+ int ignore ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ emit_insn (gen_sync ());
|
|
|
-+ return 0;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_expand_rdctl (const struct builtin_description * d ATTRIBUTE_UNUSED,
|
|
|
-+ tree exp ATTRIBUTE_UNUSED, rtx target ATTRIBUTE_UNUSED,
|
|
|
-+ rtx subtarget ATTRIBUTE_UNUSED,
|
|
|
-+ enum machine_mode mode ATTRIBUTE_UNUSED,
|
|
|
-+ int ignore ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ tree arglist = TREE_OPERAND (exp, 1);
|
|
|
-+ rtx pat;
|
|
|
-+ rtx rdctl_reg;
|
|
|
-+ enum insn_code icode = d->icode;
|
|
|
-+
|
|
|
-+ /* rdctl should have exactly two operands */
|
|
|
-+ if (insn_data[icode].n_operands != 2)
|
|
|
-+ abort ();
|
|
|
-+
|
|
|
-+ target = nios2_create_target (d, target);
|
|
|
-+
|
|
|
-+ {
|
|
|
-+ enum machine_mode mode = insn_data[icode].operand[1].mode;
|
|
|
-+ tree arg = TREE_VALUE (arglist);
|
|
|
-+ rdctl_reg = expand_expr (arg, NULL_RTX, VOIDmode, 0);
|
|
|
-+ rdctl_reg = protect_from_queue (rdctl_reg, 0);
|
|
|
-+
|
|
|
-+ if (!(*insn_data[icode].operand[1].predicate) (rdctl_reg, mode))
|
|
|
-+ {
|
|
|
-+ error ("Control register number must be in range 0-31 for %s", d->name);
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ pat = GEN_FCN (d->icode) (target, rdctl_reg);
|
|
|
-+ if (!pat)
|
|
|
-+ return 0;
|
|
|
-+ emit_insn (pat);
|
|
|
-+ return target;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_expand_wrctl (const struct builtin_description * d ATTRIBUTE_UNUSED,
|
|
|
-+ tree exp ATTRIBUTE_UNUSED, rtx target ATTRIBUTE_UNUSED,
|
|
|
-+ rtx subtarget ATTRIBUTE_UNUSED,
|
|
|
-+ enum machine_mode mode ATTRIBUTE_UNUSED,
|
|
|
-+ int ignore ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ tree arglist = TREE_OPERAND (exp, 1);
|
|
|
-+ rtx pat;
|
|
|
-+ rtx wrctl_reg, store_val;
|
|
|
-+ enum insn_code icode = d->icode;
|
|
|
-+
|
|
|
-+ /* stores should have exactly two operands */
|
|
|
-+ if (insn_data[icode].n_operands != 2)
|
|
|
-+ abort ();
|
|
|
-+
|
|
|
-+ /* process the destination of the store */
|
|
|
-+ {
|
|
|
-+ enum machine_mode mode = insn_data[icode].operand[0].mode;
|
|
|
-+ tree arg = TREE_VALUE (arglist);
|
|
|
-+ wrctl_reg = expand_expr (arg, NULL_RTX, VOIDmode, 0);
|
|
|
-+ wrctl_reg = protect_from_queue (wrctl_reg, 0);
|
|
|
-+
|
|
|
-+ if (!(*insn_data[icode].operand[0].predicate) (wrctl_reg, mode))
|
|
|
-+ error ("Control register number must be in range 0-31 for %s", d->name);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+
|
|
|
-+ /* process the value to store */
|
|
|
-+ {
|
|
|
-+ enum machine_mode mode = insn_data[icode].operand[1].mode;
|
|
|
-+ tree arg = TREE_VALUE (TREE_CHAIN (arglist));
|
|
|
-+ store_val = expand_expr (arg, NULL_RTX, mode, 0);
|
|
|
-+ store_val = protect_from_queue (store_val, 0);
|
|
|
-+
|
|
|
-+ if (!(*insn_data[icode].operand[1].predicate) (store_val, mode))
|
|
|
-+ store_val = copy_to_mode_reg (mode, store_val);
|
|
|
-+
|
|
|
-+ /* ??? Better errors would be nice */
|
|
|
-+ if (!(*insn_data[icode].operand[1].predicate) (store_val, mode))
|
|
|
-+ error ("Invalid argument 2 to %s", d->name);
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ pat = GEN_FCN (d->icode) (wrctl_reg, store_val);
|
|
|
-+ if (!pat)
|
|
|
-+ return 0;
|
|
|
-+ emit_insn (pat);
|
|
|
-+ return 0;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_extract_double (const struct insn_data *idata, tree arglist, int index)
|
|
|
-+{
|
|
|
-+ rtx arg;
|
|
|
-+
|
|
|
-+ while (index--)
|
|
|
-+ {
|
|
|
-+ arglist = TREE_CHAIN (arglist);
|
|
|
-+ }
|
|
|
-+ arg = expand_expr (TREE_VALUE (arglist), NULL_RTX, DFmode, 0);
|
|
|
-+ arg = protect_from_queue (arg, 0);
|
|
|
-+ if (!(*(idata->operand[index+1].predicate)) (arg, DFmode))
|
|
|
-+ {
|
|
|
-+ arg = copy_to_mode_reg (DFmode, arg);
|
|
|
-+ }
|
|
|
-+ return arg;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_extract_float (const struct insn_data *idata, tree arglist, int index)
|
|
|
-+{
|
|
|
-+ rtx arg;
|
|
|
-+
|
|
|
-+ while (index--)
|
|
|
-+ {
|
|
|
-+ arglist = TREE_CHAIN (arglist);
|
|
|
-+ }
|
|
|
-+ arg = expand_expr (TREE_VALUE (arglist), NULL_RTX, SFmode, 0);
|
|
|
-+ arg = protect_from_queue (arg, 0);
|
|
|
-+ if (!(*(idata->operand[index+1].predicate)) (arg, SFmode))
|
|
|
-+ {
|
|
|
-+ arg = copy_to_mode_reg (SFmode, arg);
|
|
|
-+ }
|
|
|
-+ return arg;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_extract_integer (const struct insn_data *idata, tree arglist, int index)
|
|
|
-+{
|
|
|
-+ rtx arg;
|
|
|
-+
|
|
|
-+ while (index--)
|
|
|
-+ {
|
|
|
-+ arglist = TREE_CHAIN (arglist);
|
|
|
-+ }
|
|
|
-+ arg = expand_expr (TREE_VALUE (arglist), NULL_RTX, SImode, 0);
|
|
|
-+ arg = protect_from_queue (arg, 0);
|
|
|
-+ if (!(*(idata->operand[index+1].predicate)) (arg, SImode))
|
|
|
-+ {
|
|
|
-+ arg = copy_to_mode_reg (SImode, arg);
|
|
|
-+ }
|
|
|
-+ return protect_from_queue (arg, 0);
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_expand_custom_zdz (const struct builtin_description *d,
|
|
|
-+ tree exp,
|
|
|
-+ rtx target ATTRIBUTE_UNUSED,
|
|
|
-+ rtx subtarget ATTRIBUTE_UNUSED,
|
|
|
-+ enum machine_mode mode ATTRIBUTE_UNUSED,
|
|
|
-+ int ignore ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ tree arglist = TREE_OPERAND (exp, 1);
|
|
|
-+ rtx pat = GEN_FCN (d->icode) (nios2_extract_double (&insn_data[d->icode],
|
|
|
-+ arglist, 0));
|
|
|
-+ if (pat)
|
|
|
-+ emit_insn (pat);
|
|
|
-+ return 0;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_expand_custom_zsz (const struct builtin_description *d,
|
|
|
-+ tree exp,
|
|
|
-+ rtx target ATTRIBUTE_UNUSED,
|
|
|
-+ rtx subtarget ATTRIBUTE_UNUSED,
|
|
|
-+ enum machine_mode mode ATTRIBUTE_UNUSED,
|
|
|
-+ int ignore ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ tree arglist = TREE_OPERAND (exp, 1);
|
|
|
-+ rtx pat = GEN_FCN (d->icode) (nios2_extract_float (&insn_data[d->icode],
|
|
|
-+ arglist, 0));
|
|
|
-+ if (pat)
|
|
|
-+ emit_insn (pat);
|
|
|
-+ return 0;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_expand_custom_szz (const struct builtin_description *d,
|
|
|
-+ tree exp ATTRIBUTE_UNUSED,
|
|
|
-+ rtx target,
|
|
|
-+ rtx subtarget ATTRIBUTE_UNUSED,
|
|
|
-+ enum machine_mode mode ATTRIBUTE_UNUSED,
|
|
|
-+ int ignore ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ rtx pat = GEN_FCN (d->icode) (target);
|
|
|
-+ if (pat)
|
|
|
-+ emit_insn (pat);
|
|
|
-+ return target;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_expand_custom_sss (const struct builtin_description *d,
|
|
|
-+ tree exp,
|
|
|
-+ rtx target,
|
|
|
-+ rtx subtarget ATTRIBUTE_UNUSED,
|
|
|
-+ enum machine_mode mode ATTRIBUTE_UNUSED,
|
|
|
-+ int ignore ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ tree arglist = TREE_OPERAND (exp, 1);
|
|
|
-+ rtx pat = GEN_FCN (d->icode) (target,
|
|
|
-+ nios2_extract_float (&insn_data[d->icode],
|
|
|
-+ arglist, 0),
|
|
|
-+ nios2_extract_float (&insn_data[d->icode],
|
|
|
-+ arglist, 1));
|
|
|
-+ if (pat)
|
|
|
-+ emit_insn (pat);
|
|
|
-+ return target;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_expand_custom_ssz (const struct builtin_description *d,
|
|
|
-+ tree exp,
|
|
|
-+ rtx target,
|
|
|
-+ rtx subtarget ATTRIBUTE_UNUSED,
|
|
|
-+ enum machine_mode mode ATTRIBUTE_UNUSED,
|
|
|
-+ int ignore ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ tree arglist = TREE_OPERAND (exp, 1);
|
|
|
-+ rtx pat = GEN_FCN (d->icode) (target,
|
|
|
-+ nios2_extract_float (&insn_data[d->icode],
|
|
|
-+ arglist, 0));
|
|
|
-+ if (pat)
|
|
|
-+ emit_insn (pat);
|
|
|
-+ return target;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_expand_custom_iss (const struct builtin_description *d,
|
|
|
-+ tree exp,
|
|
|
-+ rtx target,
|
|
|
-+ rtx subtarget ATTRIBUTE_UNUSED,
|
|
|
-+ enum machine_mode mode ATTRIBUTE_UNUSED,
|
|
|
-+ int ignore ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ tree arglist = TREE_OPERAND (exp, 1);
|
|
|
-+ rtx pat = GEN_FCN (d->icode) (target,
|
|
|
-+ nios2_extract_float (&insn_data[d->icode],
|
|
|
-+ arglist, 0),
|
|
|
-+ nios2_extract_float (&insn_data[d->icode],
|
|
|
-+ arglist, 1));
|
|
|
-+ if (pat)
|
|
|
-+ emit_insn (pat);
|
|
|
-+ return target;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_expand_custom_ddd (const struct builtin_description *d,
|
|
|
-+ tree exp,
|
|
|
-+ rtx target,
|
|
|
-+ rtx subtarget ATTRIBUTE_UNUSED,
|
|
|
-+ enum machine_mode mode ATTRIBUTE_UNUSED,
|
|
|
-+ int ignore ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ tree arglist = TREE_OPERAND (exp, 1);
|
|
|
-+ rtx pat = GEN_FCN (d->icode) (target,
|
|
|
-+ nios2_extract_double (&insn_data[d->icode],
|
|
|
-+ arglist, 0),
|
|
|
-+ nios2_extract_double (&insn_data[d->icode],
|
|
|
-+ arglist, 1));
|
|
|
-+ if (pat)
|
|
|
-+ emit_insn (pat);
|
|
|
-+ return target;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_expand_custom_ddz (const struct builtin_description *d,
|
|
|
-+ tree exp,
|
|
|
-+ rtx target,
|
|
|
-+ rtx subtarget ATTRIBUTE_UNUSED,
|
|
|
-+ enum machine_mode mode ATTRIBUTE_UNUSED,
|
|
|
-+ int ignore ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ tree arglist = TREE_OPERAND (exp, 1);
|
|
|
-+ rtx pat = GEN_FCN (d->icode) (target,
|
|
|
-+ nios2_extract_double (&insn_data[d->icode],
|
|
|
-+ arglist, 0));
|
|
|
-+ if (pat)
|
|
|
-+ emit_insn (pat);
|
|
|
-+ return target;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_expand_custom_idd (const struct builtin_description *d,
|
|
|
-+ tree exp,
|
|
|
-+ rtx target,
|
|
|
-+ rtx subtarget ATTRIBUTE_UNUSED,
|
|
|
-+ enum machine_mode mode ATTRIBUTE_UNUSED,
|
|
|
-+ int ignore ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ tree arglist = TREE_OPERAND (exp, 1);
|
|
|
-+ rtx pat = GEN_FCN (d->icode) (target,
|
|
|
-+ nios2_extract_double (&insn_data[d->icode],
|
|
|
-+ arglist, 0),
|
|
|
-+ nios2_extract_double (&insn_data[d->icode],
|
|
|
-+ arglist, 1));
|
|
|
-+ if (pat)
|
|
|
-+ emit_insn (pat);
|
|
|
-+ return target;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_expand_custom_siz (const struct builtin_description *d,
|
|
|
-+ tree exp,
|
|
|
-+ rtx target,
|
|
|
-+ rtx subtarget ATTRIBUTE_UNUSED,
|
|
|
-+ enum machine_mode mode ATTRIBUTE_UNUSED,
|
|
|
-+ int ignore ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ tree arglist = TREE_OPERAND (exp, 1);
|
|
|
-+ rtx pat = GEN_FCN (d->icode) (target,
|
|
|
-+ nios2_extract_integer (&insn_data[d->icode],
|
|
|
-+ arglist, 0));
|
|
|
-+ if (pat)
|
|
|
-+ emit_insn (pat);
|
|
|
-+ return target;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_expand_custom_suz (const struct builtin_description *d,
|
|
|
-+ tree exp,
|
|
|
-+ rtx target,
|
|
|
-+ rtx subtarget ATTRIBUTE_UNUSED,
|
|
|
-+ enum machine_mode mode ATTRIBUTE_UNUSED,
|
|
|
-+ int ignore ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ tree arglist = TREE_OPERAND (exp, 1);
|
|
|
-+ rtx pat = GEN_FCN (d->icode) (target,
|
|
|
-+ nios2_extract_integer (&insn_data[d->icode],
|
|
|
-+ arglist, 0));
|
|
|
-+ if (pat)
|
|
|
-+ emit_insn (pat);
|
|
|
-+ return target;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_expand_custom_diz (const struct builtin_description *d,
|
|
|
-+ tree exp,
|
|
|
-+ rtx target,
|
|
|
-+ rtx subtarget ATTRIBUTE_UNUSED,
|
|
|
-+ enum machine_mode mode ATTRIBUTE_UNUSED,
|
|
|
-+ int ignore ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ tree arglist = TREE_OPERAND (exp, 1);
|
|
|
-+ rtx pat = GEN_FCN (d->icode) (target,
|
|
|
-+ nios2_extract_integer (&insn_data[d->icode],
|
|
|
-+ arglist, 0));
|
|
|
-+ if (pat)
|
|
|
-+ emit_insn (pat);
|
|
|
-+ return target;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_expand_custom_duz (const struct builtin_description *d,
|
|
|
-+ tree exp,
|
|
|
-+ rtx target,
|
|
|
-+ rtx subtarget ATTRIBUTE_UNUSED,
|
|
|
-+ enum machine_mode mode ATTRIBUTE_UNUSED,
|
|
|
-+ int ignore ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ tree arglist = TREE_OPERAND (exp, 1);
|
|
|
-+ rtx pat = GEN_FCN (d->icode) (target,
|
|
|
-+ nios2_extract_integer (&insn_data[d->icode],
|
|
|
-+ arglist, 0));
|
|
|
-+ if (pat)
|
|
|
-+ emit_insn (pat);
|
|
|
-+ return target;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_expand_custom_isz (const struct builtin_description *d,
|
|
|
-+ tree exp,
|
|
|
-+ rtx target,
|
|
|
-+ rtx subtarget ATTRIBUTE_UNUSED,
|
|
|
-+ enum machine_mode mode ATTRIBUTE_UNUSED,
|
|
|
-+ int ignore ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ tree arglist = TREE_OPERAND (exp, 1);
|
|
|
-+ rtx pat = GEN_FCN (d->icode) (target,
|
|
|
-+ nios2_extract_float (&insn_data[d->icode],
|
|
|
-+ arglist, 0));
|
|
|
-+ if (pat)
|
|
|
-+ emit_insn (pat);
|
|
|
-+ return target;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_expand_custom_usz (const struct builtin_description *d,
|
|
|
-+ tree exp,
|
|
|
-+ rtx target,
|
|
|
-+ rtx subtarget ATTRIBUTE_UNUSED,
|
|
|
-+ enum machine_mode mode ATTRIBUTE_UNUSED,
|
|
|
-+ int ignore ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ tree arglist = TREE_OPERAND (exp, 1);
|
|
|
-+ rtx pat = GEN_FCN (d->icode) (target,
|
|
|
-+ nios2_extract_float (&insn_data[d->icode],
|
|
|
-+ arglist, 0));
|
|
|
-+ if (pat)
|
|
|
-+ emit_insn (pat);
|
|
|
-+ return target;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_expand_custom_idz (const struct builtin_description *d,
|
|
|
-+ tree exp,
|
|
|
-+ rtx target,
|
|
|
-+ rtx subtarget ATTRIBUTE_UNUSED,
|
|
|
-+ enum machine_mode mode ATTRIBUTE_UNUSED,
|
|
|
-+ int ignore ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ tree arglist = TREE_OPERAND (exp, 1);
|
|
|
-+ rtx pat = GEN_FCN (d->icode) (target,
|
|
|
-+ nios2_extract_double (&insn_data[d->icode],
|
|
|
-+ arglist, 0));
|
|
|
-+ if (pat)
|
|
|
-+ emit_insn (pat);
|
|
|
-+ return target;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_expand_custom_udz (const struct builtin_description *d,
|
|
|
-+ tree exp,
|
|
|
-+ rtx target,
|
|
|
-+ rtx subtarget ATTRIBUTE_UNUSED,
|
|
|
-+ enum machine_mode mode ATTRIBUTE_UNUSED,
|
|
|
-+ int ignore ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ tree arglist = TREE_OPERAND (exp, 1);
|
|
|
-+ rtx pat = GEN_FCN (d->icode) (target,
|
|
|
-+ nios2_extract_double (&insn_data[d->icode],
|
|
|
-+ arglist, 0));
|
|
|
-+ if (pat)
|
|
|
-+ emit_insn (pat);
|
|
|
-+ return target;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_expand_custom_dsz (const struct builtin_description *d,
|
|
|
-+ tree exp,
|
|
|
-+ rtx target,
|
|
|
-+ rtx subtarget ATTRIBUTE_UNUSED,
|
|
|
-+ enum machine_mode mode ATTRIBUTE_UNUSED,
|
|
|
-+ int ignore ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ tree arglist = TREE_OPERAND (exp, 1);
|
|
|
-+ rtx pat = GEN_FCN (d->icode) (target,
|
|
|
-+ nios2_extract_float (&insn_data[d->icode],
|
|
|
-+ arglist, 0));
|
|
|
-+ if (pat)
|
|
|
-+ emit_insn (pat);
|
|
|
-+ return target;
|
|
|
-+}
|
|
|
-+
|
|
|
-+static rtx
|
|
|
-+nios2_expand_custom_sdz (const struct builtin_description *d,
|
|
|
-+ tree exp,
|
|
|
-+ rtx target,
|
|
|
-+ rtx subtarget ATTRIBUTE_UNUSED,
|
|
|
-+ enum machine_mode mode ATTRIBUTE_UNUSED,
|
|
|
-+ int ignore ATTRIBUTE_UNUSED)
|
|
|
-+{
|
|
|
-+ tree arglist = TREE_OPERAND (exp, 1);
|
|
|
-+ rtx pat = GEN_FCN (d->icode) (target,
|
|
|
-+ nios2_extract_double (&insn_data[d->icode],
|
|
|
-+ arglist, 0));
|
|
|
-+ if (pat)
|
|
|
-+ emit_insn (pat);
|
|
|
-+ return target;
|
|
|
-+}
|
|
|
-+
|
|
|
-+#include "gt-nios2.h"
|
|
|
-+
|
|
|
-diff --git a/gcc/config/nios2/nios2.h b/gcc/config/nios2/nios2.h
|
|
|
-new file mode 100644
|
|
|
-index 0000000..500ccf0
|
|
|
---- /dev/null
|
|
|
-+++ b/gcc/config/nios2/nios2.h
|
|
|
-@@ -0,0 +1,1130 @@
|
|
|
-+/* Definitions of target machine for Altera NIOS 2G NIOS2 version.
|
|
|
-+ Copyright (C) 2005 Altera
|
|
|
-+ Contributed by Jonah Graham (jgraham@altera.com) and Will Reece (wreece@altera.com).
|
|
|
-+
|
|
|
-+This file is part of GNU CC.
|
|
|
-+
|
|
|
-+GNU CC is free software; you can redistribute it and/or modify
|
|
|
-+it under the terms of the GNU General Public License as published by
|
|
|
-+the Free Software Foundation; either version 2, or (at your option)
|
|
|
-+any later version.
|
|
|
-+
|
|
|
-+GNU CC is distributed in the hope that it will be useful,
|
|
|
-+but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
-+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
-+GNU General Public License for more details.
|
|
|
-+
|
|
|
-+You should have received a copy of the GNU General Public License
|
|
|
-+along with GNU CC; see the file COPYING. If not, write to
|
|
|
-+the Free Software Foundation, 59 Temple Place - Suite 330,
|
|
|
-+Boston, MA 02111-1307, USA. */
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+#define TARGET_CPU_CPP_BUILTINS() \
|
|
|
-+ do \
|
|
|
-+ { \
|
|
|
-+ builtin_define_std ("NIOS2"); \
|
|
|
-+ builtin_define_std ("nios2"); \
|
|
|
-+ if (TARGET_BIG_ENDIAN) \
|
|
|
-+ builtin_define_std ("nios2_big_endian"); \
|
|
|
-+ else \
|
|
|
-+ builtin_define_std ("nios2_little_endian"); \
|
|
|
-+ } \
|
|
|
-+ while (0)
|
|
|
-+#define TARGET_VERSION fprintf (stderr, " (Altera Nios II)")
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+/*********************************
|
|
|
-+ * Run-time Target Specification
|
|
|
-+ *********************************/
|
|
|
-+
|
|
|
-+#define HAS_DIV_FLAG 0x0001
|
|
|
-+#define HAS_MUL_FLAG 0x0002
|
|
|
-+#define HAS_MULX_FLAG 0x0004
|
|
|
-+#define FAST_SW_DIV_FLAG 0x0008
|
|
|
-+#define INLINE_MEMCPY_FLAG 0x00010
|
|
|
-+#define CACHE_VOLATILE_FLAG 0x0020
|
|
|
-+#define BYPASS_CACHE_FLAG 0x0040
|
|
|
-+#define STACK_CHECK_FLAG 0x0080
|
|
|
-+#define REVERSE_BITFIELDS_FLAG 0x0100
|
|
|
-+/* Reserve 0x0200 for REVERSE_ENDIAN_FLAG */
|
|
|
-+#define BIG_ENDIAN_FLAG 0x0400
|
|
|
-+
|
|
|
-+extern int target_flags;
|
|
|
-+#define TARGET_HAS_DIV (target_flags & HAS_DIV_FLAG)
|
|
|
-+#define TARGET_HAS_MUL (target_flags & HAS_MUL_FLAG)
|
|
|
-+#define TARGET_HAS_MULX (target_flags & HAS_MULX_FLAG)
|
|
|
-+#define TARGET_FAST_SW_DIV (target_flags & FAST_SW_DIV_FLAG)
|
|
|
-+#define TARGET_INLINE_MEMCPY (target_flags & INLINE_MEMCPY_FLAG)
|
|
|
-+#define TARGET_CACHE_VOLATILE (target_flags & CACHE_VOLATILE_FLAG)
|
|
|
-+#define TARGET_BYPASS_CACHE (target_flags & BYPASS_CACHE_FLAG)
|
|
|
-+#define TARGET_STACK_CHECK (target_flags & STACK_CHECK_FLAG)
|
|
|
-+#define TARGET_REVERSE_BITFIELDS (target_flags & REVERSE_BITFIELDS_FLAG)
|
|
|
-+#define TARGET_BIG_ENDIAN (target_flags & BIG_ENDIAN_FLAG)
|
|
|
-+
|
|
|
-+#define TARGET_SWITCHES \
|
|
|
-+{ \
|
|
|
-+ { "hw-div", HAS_DIV_FLAG, \
|
|
|
-+ N_("Enable DIV, DIVU") }, \
|
|
|
-+ { "no-hw-div", -HAS_DIV_FLAG, \
|
|
|
-+ N_("Disable DIV, DIVU (default)") }, \
|
|
|
-+ { "hw-mul", HAS_MUL_FLAG, \
|
|
|
-+ N_("Enable MUL instructions (default)") }, \
|
|
|
-+ { "hw-mulx", HAS_MULX_FLAG, \
|
|
|
-+ N_("Enable MULX instructions, assume fast shifter") }, \
|
|
|
-+ { "no-hw-mul", -HAS_MUL_FLAG, \
|
|
|
-+ N_("Disable MUL instructions") }, \
|
|
|
-+ { "no-hw-mulx", -HAS_MULX_FLAG, \
|
|
|
-+ N_("Disable MULX instructions, assume slow shifter (default and implied by -mno-hw-mul)") }, \
|
|
|
-+ { "fast-sw-div", FAST_SW_DIV_FLAG, \
|
|
|
-+ N_("Use table based fast divide (default at -O3)") }, \
|
|
|
-+ { "no-fast-sw-div", -FAST_SW_DIV_FLAG, \
|
|
|
-+ N_("Don't use table based fast divide ever") }, \
|
|
|
-+ { "inline-memcpy", INLINE_MEMCPY_FLAG, \
|
|
|
-+ N_("Inline small memcpy (default when optimizing)") }, \
|
|
|
-+ { "no-inline-memcpy", -INLINE_MEMCPY_FLAG, \
|
|
|
-+ N_("Don't Inline small memcpy") }, \
|
|
|
-+ { "cache-volatile", CACHE_VOLATILE_FLAG, \
|
|
|
-+ N_("Volatile accesses use non-io variants of instructions (default)") }, \
|
|
|
-+ { "no-cache-volatile", -CACHE_VOLATILE_FLAG, \
|
|
|
-+ N_("Volatile accesses use io variants of instructions") }, \
|
|
|
-+ { "bypass-cache", BYPASS_CACHE_FLAG, \
|
|
|
-+ N_("All ld/st instructins use io variants") }, \
|
|
|
-+ { "no-bypass-cache", -BYPASS_CACHE_FLAG, \
|
|
|
-+ N_("All ld/st instructins do not use io variants (default)") }, \
|
|
|
-+ { "smallc", 0, \
|
|
|
-+ N_("Link with a limited version of the C library") }, \
|
|
|
-+ { "ctors-in-init", 0, \
|
|
|
-+ "" /* undocumented: N_("Link with static constructors and destructors in init") */ }, \
|
|
|
-+ { "stack-check", STACK_CHECK_FLAG, \
|
|
|
-+ N_("Enable stack limit checking.") }, \
|
|
|
-+ { "no-stack-check", -STACK_CHECK_FLAG, \
|
|
|
-+ N_("Disable stack limit checking (default).") }, \
|
|
|
-+ { "reverse-bitfields", REVERSE_BITFIELDS_FLAG, \
|
|
|
-+ N_("Reverse the order of bitfields in a struct.") }, \
|
|
|
-+ { "no-reverse-bitfields", -REVERSE_BITFIELDS_FLAG, \
|
|
|
-+ N_("Use the normal order of bitfields in a struct (default).") }, \
|
|
|
-+ { "eb", BIG_ENDIAN_FLAG, \
|
|
|
-+ N_("Use big-endian byte order") }, \
|
|
|
-+ { "el", -BIG_ENDIAN_FLAG, \
|
|
|
-+ N_("Use little-endian byte order") }, \
|
|
|
-+ { "", TARGET_DEFAULT, 0 } \
|
|
|
-+}
|
|
|
-+
|
|
|
-+extern const char *nios2_sys_nosys_string; /* for -msys=nosys */
|
|
|
-+extern const char *nios2_sys_lib_string; /* for -msys-lib= */
|
|
|
-+extern const char *nios2_sys_crt0_string; /* for -msys-crt0= */
|
|
|
-+
|
|
|
-+/*
|
|
|
-+ * There's a lot of error-prone tedium with all the different
|
|
|
-+ * custom floating point instructions. Try to automate it a bit
|
|
|
-+ * to make it easier to deal with.
|
|
|
-+ */
|
|
|
-+#define NIOS2_STRINGIFY_INNER(x) #x
|
|
|
-+#define NIOS2_STRINGIFY(x) NIOS2_STRINGIFY_INNER(x)
|
|
|
-+#define NIOS2_CONCAT_INNER(x, y) x ## y
|
|
|
-+#define NIOS2_CONCAT(x, y) NIOS2_CONCAT_INNER (x, y)
|
|
|
-+
|
|
|
-+#define NIOS2_FOR_ALL_FPU_INSNS \
|
|
|
-+ NIOS2_FPU_INSN (fwrx, nios2_fwrx, zdz) \
|
|
|
-+ NIOS2_FPU_INSN (fwry, nios2_fwry, zsz) \
|
|
|
-+ NIOS2_FPU_INSN (frdxlo, nios2_frdxlo, szz) \
|
|
|
-+ NIOS2_FPU_INSN (frdxhi, nios2_frdxhi, szz) \
|
|
|
-+ NIOS2_FPU_INSN (frdy, nios2_frdy, szz) \
|
|
|
-+\
|
|
|
-+ NIOS2_FPU_INSN (fadds, addsf3, sss) \
|
|
|
-+ NIOS2_FPU_INSN (fsubs, subsf3, sss) \
|
|
|
-+ NIOS2_FPU_INSN (fmuls, mulsf3, sss) \
|
|
|
-+ NIOS2_FPU_INSN (fdivs, divsf3, sss) \
|
|
|
-+ NIOS2_FPU_INSN (fmins, minsf3, sss) \
|
|
|
-+ NIOS2_FPU_INSN (fmaxs, maxsf3, sss) \
|
|
|
-+ NIOS2_FPU_INSN (fnegs, negsf2, ssz) \
|
|
|
-+ NIOS2_FPU_INSN (fabss, abssf2, ssz) \
|
|
|
-+ NIOS2_FPU_INSN (fsqrts, sqrtsf2, ssz) \
|
|
|
-+ NIOS2_FPU_INSN (fcoss, cossf2, ssz) \
|
|
|
-+ NIOS2_FPU_INSN (fsins, sinsf2, ssz) \
|
|
|
-+ NIOS2_FPU_INSN (ftans, tansf2, ssz) \
|
|
|
-+ NIOS2_FPU_INSN (fatans, atansf2, ssz) \
|
|
|
-+ NIOS2_FPU_INSN (fexps, expsf2, ssz) \
|
|
|
-+ NIOS2_FPU_INSN (flogs, logsf2, ssz) \
|
|
|
-+ NIOS2_FPU_INSN (fcmplts, nios2_sltsf, iss) \
|
|
|
-+ NIOS2_FPU_INSN (fcmples, nios2_slesf, iss) \
|
|
|
-+ NIOS2_FPU_INSN (fcmpgts, nios2_sgtsf, iss) \
|
|
|
-+ NIOS2_FPU_INSN (fcmpges, nios2_sgesf, iss) \
|
|
|
-+ NIOS2_FPU_INSN (fcmpeqs, nios2_seqsf, iss) \
|
|
|
-+ NIOS2_FPU_INSN (fcmpnes, nios2_snesf, iss) \
|
|
|
-+\
|
|
|
-+ NIOS2_FPU_INSN (faddd, adddf3, ddd) \
|
|
|
-+ NIOS2_FPU_INSN (fsubd, subdf3, ddd) \
|
|
|
-+ NIOS2_FPU_INSN (fmuld, muldf3, ddd) \
|
|
|
-+ NIOS2_FPU_INSN (fdivd, divdf3, ddd) \
|
|
|
-+ NIOS2_FPU_INSN (fmind, mindf3, ddd) \
|
|
|
-+ NIOS2_FPU_INSN (fmaxd, maxdf3, ddd) \
|
|
|
-+ NIOS2_FPU_INSN (fnegd, negdf2, ddz) \
|
|
|
-+ NIOS2_FPU_INSN (fabsd, absdf2, ddz) \
|
|
|
-+ NIOS2_FPU_INSN (fsqrtd, sqrtdf2, ddz) \
|
|
|
-+ NIOS2_FPU_INSN (fcosd, cosdf2, ddz) \
|
|
|
-+ NIOS2_FPU_INSN (fsind, sindf2, ddz) \
|
|
|
-+ NIOS2_FPU_INSN (ftand, tandf2, ddz) \
|
|
|
-+ NIOS2_FPU_INSN (fatand, atandf2, ddz) \
|
|
|
-+ NIOS2_FPU_INSN (fexpd, expdf2, ddz) \
|
|
|
-+ NIOS2_FPU_INSN (flogd, logdf2, ddz) \
|
|
|
-+ NIOS2_FPU_INSN (fcmpltd, nios2_sltdf, idd) \
|
|
|
-+ NIOS2_FPU_INSN (fcmpled, nios2_sledf, idd) \
|
|
|
-+ NIOS2_FPU_INSN (fcmpgtd, nios2_sgtdf, idd) \
|
|
|
-+ NIOS2_FPU_INSN (fcmpged, nios2_sgedf, idd) \
|
|
|
-+ NIOS2_FPU_INSN (fcmpeqd, nios2_seqdf, idd) \
|
|
|
-+ NIOS2_FPU_INSN (fcmpned, nios2_snedf, idd) \
|
|
|
-+\
|
|
|
-+ NIOS2_FPU_INSN (floatis, floatsisf2, siz) \
|
|
|
-+ NIOS2_FPU_INSN (floatus, floatunssisf2, suz) \
|
|
|
-+ NIOS2_FPU_INSN (floatid, floatsidf2, diz) \
|
|
|
-+ NIOS2_FPU_INSN (floatud, floatunssidf2, duz) \
|
|
|
-+ NIOS2_FPU_INSN (fixsi, fixsfsi2, isz) \
|
|
|
-+ NIOS2_FPU_INSN (fixsu, fixunssfsi2, usz) \
|
|
|
-+ NIOS2_FPU_INSN (fixdi, fixdfsi2, idz) \
|
|
|
-+ NIOS2_FPU_INSN (fixdu, fixunsdfsi2, udz) \
|
|
|
-+ NIOS2_FPU_INSN (fextsd, extendsfdf2, dsz) \
|
|
|
-+ NIOS2_FPU_INSN (ftruncds, truncdfsf2, sdz)
|
|
|
-+
|
|
|
-+enum
|
|
|
-+{
|
|
|
-+#define NIOS2_FPU_INSN(opt, insn, args) \
|
|
|
-+ NIOS2_CONCAT (nios2_fpu_, insn),
|
|
|
-+NIOS2_FOR_ALL_FPU_INSNS
|
|
|
-+ nios2_fpu_max_insn
|
|
|
-+};
|
|
|
-+
|
|
|
-+struct cpp_reader;
|
|
|
-+typedef const char * (*nios2_outputfn) (rtx);
|
|
|
-+typedef void (*nios2_pragmafn) (struct cpp_reader *);
|
|
|
-+
|
|
|
-+typedef struct
|
|
|
-+{
|
|
|
-+ const char *option; /* name of switch, e.g. fadds */
|
|
|
-+ const char *insnnm; /* name of gcc insn, e.g. addsf3 */
|
|
|
-+ const char *args; /* args to gcc insn, e.g. sss */
|
|
|
-+ const char *value; /* value of switch as a string */
|
|
|
-+ int N; /* value of switch as an integer, -1 = not used */
|
|
|
-+ nios2_outputfn output; /* output function for use in .md file */
|
|
|
-+ const char *pname; /* name of corresponding #pragma custom- */
|
|
|
-+ nios2_pragmafn pragma; /* pragma function for register_target_pragmas */
|
|
|
-+ const char *nopname; /* name of corresponding #pragma no-custom- */
|
|
|
-+ nios2_pragmafn nopragma; /* pragma function for register_target_pragmas */
|
|
|
-+ int is_double; /* does this insn have any double operands */
|
|
|
-+ int needed_by_double; /* is this insn needed if doubles are used? */
|
|
|
-+ int needs_unsafe; /* does this insn require
|
|
|
-+ -funsafe-math-optimizations to work? */
|
|
|
-+ int needs_finite; /* does this insn require
|
|
|
-+ -ffinite-math-only to work? */
|
|
|
-+ int pragma_seen; /* have we seen the corresponding #pragma? */
|
|
|
-+} nios2_fpu_info;
|
|
|
-+
|
|
|
-+extern nios2_fpu_info nios2_fpu_insns[nios2_fpu_max_insn];
|
|
|
-+extern const char *nios2_custom_fpu_cfg_string;
|
|
|
-+
|
|
|
-+#undef NIOS2_FPU_INSN
|
|
|
-+#define NIOS2_FPU_INSN(opt, insn, args) \
|
|
|
-+ { \
|
|
|
-+ "custom-" NIOS2_STRINGIFY (opt) "=", \
|
|
|
-+ &(nios2_fpu_insns[NIOS2_CONCAT (nios2_fpu_, insn)].value), \
|
|
|
-+ N_("Integer id (N) of " NIOS2_STRINGIFY (opt) " custom instruction"), \
|
|
|
-+ 0 \
|
|
|
-+ }, \
|
|
|
-+ { \
|
|
|
-+ "no-custom-" NIOS2_STRINGIFY (opt), \
|
|
|
-+ &(nios2_fpu_insns[NIOS2_CONCAT (nios2_fpu_, insn)].value), \
|
|
|
-+ N_("Do not use the " NIOS2_STRINGIFY (opt) " custom instruction"), \
|
|
|
-+ "-1" \
|
|
|
-+ },
|
|
|
-+
|
|
|
-+#define TARGET_OPTIONS \
|
|
|
-+{ \
|
|
|
-+ { "sys=nosys", &nios2_sys_nosys_string, \
|
|
|
-+ N_("Use stub versions of OS library calls (default)"), 0}, \
|
|
|
-+ { "sys-lib=", &nios2_sys_lib_string, \
|
|
|
-+ N_("Name of System Library to link against. (Converted to a -l option)"), 0}, \
|
|
|
-+ { "sys-crt0=", &nios2_sys_crt0_string, \
|
|
|
-+ N_("Name of the startfile. (default is a crt0 for the ISS only)"), 0}, \
|
|
|
-+ NIOS2_FOR_ALL_FPU_INSNS \
|
|
|
-+ { "custom-fpu-cfg=", &nios2_custom_fpu_cfg_string, \
|
|
|
-+ N_("Floating point custom instruction configuration name"), 0 }, \
|
|
|
-+}
|
|
|
-+
|
|
|
-+/* We're little endian, unless otherwise specified by including big.h */
|
|
|
-+#ifndef TARGET_ENDIAN_DEFAULT
|
|
|
-+# define TARGET_ENDIAN_DEFAULT 0
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+/* Default target_flags if no switches specified. */
|
|
|
-+#ifndef TARGET_DEFAULT
|
|
|
-+# define TARGET_DEFAULT (HAS_MUL_FLAG | CACHE_VOLATILE_FLAG | TARGET_ENDIAN_DEFAULT)
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+/* Switch Recognition by gcc.c. Add -G xx support */
|
|
|
-+#undef SWITCH_TAKES_ARG
|
|
|
-+#define SWITCH_TAKES_ARG(CHAR) \
|
|
|
-+ (DEFAULT_SWITCH_TAKES_ARG (CHAR) || (CHAR) == 'G')
|
|
|
-+
|
|
|
-+#define OVERRIDE_OPTIONS override_options ()
|
|
|
-+#define OPTIMIZATION_OPTIONS(LEVEL, SIZE) optimization_options (LEVEL, SIZE)
|
|
|
-+#define CAN_DEBUG_WITHOUT_FP
|
|
|
-+
|
|
|
-+#define CC1_SPEC "\
|
|
|
-+%{G*} %{EB:-meb} %{EL:-mel} %{EB:%{EL:%emay not use both -EB and -EL}}"
|
|
|
-+
|
|
|
-+#if TARGET_ENDIAN_DEFAULT == 0
|
|
|
-+# define ASM_SPEC "\
|
|
|
-+%{!EB:%{!meb:-EL}} %{EB|meb:-EB}"
|
|
|
-+# define LINK_SPEC "\
|
|
|
-+%{!EB:%{!meb:-EL}} %{EB|meb:-EB}"
|
|
|
-+# define MULTILIB_DEFAULTS { "EL" }
|
|
|
-+#else
|
|
|
-+# define ASM_SPEC "\
|
|
|
-+%{!EL:%{!mel:-EB}} %{EL|mel:-EL}"
|
|
|
-+# define LINK_SPEC "\
|
|
|
-+%{!EL:%{!mel:-EB}} %{EL|mel:-EL}"
|
|
|
-+# define MULTILIB_DEFAULTS { "EB" }
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+#undef LIB_SPEC
|
|
|
-+#define LIB_SPEC \
|
|
|
-+"--start-group %{msmallc: -lsmallc} %{!msmallc: -lc} -lgcc \
|
|
|
-+ %{msys-lib=*: -l%*} \
|
|
|
-+ %{!msys-lib=*: -lnosys -lstack} \
|
|
|
-+ --end-group \
|
|
|
-+ %{msys-lib=: %eYou need a library name for -msys-lib=} \
|
|
|
-+"
|
|
|
-+
|
|
|
-+
|
|
|
-+#undef STARTFILE_SPEC
|
|
|
-+#define STARTFILE_SPEC \
|
|
|
-+"%{msys-crt0=*: %*} %{!msys-crt0=*: crt0%O%s} \
|
|
|
-+ %{msys-crt0=: %eYou need a C startup file for -msys-crt0=} \
|
|
|
-+ %{mctors-in-init: crti%O%s crtbegin%O%s} \
|
|
|
-+"
|
|
|
-+
|
|
|
-+#undef ENDFILE_SPEC
|
|
|
-+#define ENDFILE_SPEC \
|
|
|
-+ "%{mctors-in-init: crtend%O%s crtn%O%s}"
|
|
|
-+
|
|
|
-+
|
|
|
-+/***********************
|
|
|
-+ * Storage Layout
|
|
|
-+ ***********************/
|
|
|
-+
|
|
|
-+#define DEFAULT_SIGNED_CHAR 1
|
|
|
-+#define BITS_BIG_ENDIAN 0
|
|
|
-+#define BYTES_BIG_ENDIAN (TARGET_BIG_ENDIAN != 0)
|
|
|
-+#define WORDS_BIG_ENDIAN (TARGET_BIG_ENDIAN != 0)
|
|
|
-+#if defined(__nios2_big_endian__)
|
|
|
-+#define LIBGCC2_WORDS_BIG_ENDIAN 1
|
|
|
-+#else
|
|
|
-+#define LIBGCC2_WORDS_BIG_ENDIAN 0
|
|
|
-+#endif
|
|
|
-+#define BITS_PER_UNIT 8
|
|
|
-+#define BITS_PER_WORD 32
|
|
|
-+#define UNITS_PER_WORD 4
|
|
|
-+#define POINTER_SIZE 32
|
|
|
-+#define BIGGEST_ALIGNMENT 32
|
|
|
-+#define STRICT_ALIGNMENT 1
|
|
|
-+#define FUNCTION_BOUNDARY 32
|
|
|
-+#define PARM_BOUNDARY 32
|
|
|
-+#define STACK_BOUNDARY 32
|
|
|
-+#define PREFERRED_STACK_BOUNDARY 32
|
|
|
-+#define MAX_FIXED_MODE_SIZE 64
|
|
|
-+
|
|
|
-+#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
|
|
|
-+ ((TREE_CODE (EXP) == STRING_CST) \
|
|
|
-+ && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
|
|
|
-+
|
|
|
-+
|
|
|
-+/**********************
|
|
|
-+ * Layout of Source Language Data Types
|
|
|
-+ **********************/
|
|
|
-+
|
|
|
-+#define INT_TYPE_SIZE 32
|
|
|
-+#define SHORT_TYPE_SIZE 16
|
|
|
-+#define LONG_TYPE_SIZE 32
|
|
|
-+#define LONG_LONG_TYPE_SIZE 64
|
|
|
-+#define FLOAT_TYPE_SIZE 32
|
|
|
-+#define DOUBLE_TYPE_SIZE 64
|
|
|
-+#define LONG_DOUBLE_TYPE_SIZE DOUBLE_TYPE_SIZE
|
|
|
-+
|
|
|
-+
|
|
|
-+/*************************
|
|
|
-+ * Condition Code Status
|
|
|
-+ ************************/
|
|
|
-+
|
|
|
-+/* comparison type */
|
|
|
-+/* ??? Currently CMP_DI is unused. CMP_SF and CMP_DF are only used if
|
|
|
-+ the corresponding -mcustom-<opcode> switches are present. */
|
|
|
-+enum cmp_type {
|
|
|
-+ CMP_SI, /* compare four byte integers */
|
|
|
-+ CMP_DI, /* compare eight byte integers */
|
|
|
-+ CMP_SF, /* compare single precision floats */
|
|
|
-+ CMP_DF, /* compare double precision floats */
|
|
|
-+ CMP_MAX /* max comparison type */
|
|
|
-+};
|
|
|
-+
|
|
|
-+extern GTY(()) rtx branch_cmp[2]; /* operands for compare */
|
|
|
-+extern enum cmp_type branch_type; /* what type of branch to use */
|
|
|
-+
|
|
|
-+/**********************
|
|
|
-+ * Register Usage
|
|
|
-+ **********************/
|
|
|
-+
|
|
|
-+/* ---------------------------------- *
|
|
|
-+ * Basic Characteristics of Registers
|
|
|
-+ * ---------------------------------- */
|
|
|
-+
|
|
|
-+/*
|
|
|
-+Register Number
|
|
|
-+ Register Name
|
|
|
-+ Alternate Name
|
|
|
-+ Purpose
|
|
|
-+0 r0 zero always zero
|
|
|
-+1 r1 at Assembler Temporary
|
|
|
-+2-3 r2-r3 Return Location
|
|
|
-+4-7 r4-r7 Register Arguments
|
|
|
-+8-15 r8-r15 Caller Saved Registers
|
|
|
-+16-22 r16-r22 Callee Saved Registers
|
|
|
-+23 r23 sc Static Chain (Callee Saved)
|
|
|
-+ ??? Does $sc want to be caller or callee
|
|
|
-+ saved. If caller, 15, else 23.
|
|
|
-+24 r24 et Exception Temporary
|
|
|
-+25 r25 bt Breakpoint Temporary
|
|
|
-+26 r26 gp Global Pointer
|
|
|
-+27 r27 sp Stack Pointer
|
|
|
-+28 r28 fp Frame Pointer
|
|
|
-+29 r29 ea Exception Return Address
|
|
|
-+30 r30 ba Breakpoint Return Address
|
|
|
-+31 r31 ra Return Address
|
|
|
-+
|
|
|
-+32 ctl0 status
|
|
|
-+33 ctl1 estatus STATUS saved by exception ?
|
|
|
-+34 ctl2 bstatus STATUS saved by break ?
|
|
|
-+35 ctl3 ipri Interrupt Priority Mask ?
|
|
|
-+36 ctl4 ecause Exception Cause ?
|
|
|
-+
|
|
|
-+37 pc Not an actual register
|
|
|
-+
|
|
|
-+38 rap Return address pointer, this does not
|
|
|
-+ actually exist and will be eliminated
|
|
|
-+
|
|
|
-+39 fake_fp Fake Frame Pointer which will always be eliminated.
|
|
|
-+40 fake_ap Fake Argument Pointer which will always be eliminated.
|
|
|
-+
|
|
|
-+41 First Pseudo Register
|
|
|
-+
|
|
|
-+
|
|
|
-+The definitions for all the hard register numbers
|
|
|
-+are located in nios2.md.
|
|
|
-+*/
|
|
|
-+
|
|
|
-+#define FIRST_PSEUDO_REGISTER 41
|
|
|
-+#define NUM_ARG_REGS (LAST_ARG_REGNO - FIRST_ARG_REGNO + 1)
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+/* also see CONDITIONAL_REGISTER_USAGE */
|
|
|
-+#define FIXED_REGISTERS \
|
|
|
-+ { \
|
|
|
-+/* +0 1 2 3 4 5 6 7 8 9 */ \
|
|
|
-+/* 0 */ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, \
|
|
|
-+/* 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
|
|
|
-+/* 20 */ 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, \
|
|
|
-+/* 30 */ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, \
|
|
|
-+/* 40 */ 1 \
|
|
|
-+ }
|
|
|
-+
|
|
|
-+/* call used is the same as caller saved
|
|
|
-+ + fixed regs + args + ret vals */
|
|
|
-+#define CALL_USED_REGISTERS \
|
|
|
-+ { \
|
|
|
-+/* +0 1 2 3 4 5 6 7 8 9 */ \
|
|
|
-+/* 0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
|
|
|
-+/* 10 */ 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, \
|
|
|
-+/* 20 */ 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, \
|
|
|
-+/* 30 */ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, \
|
|
|
-+/* 40 */ 1 \
|
|
|
-+ }
|
|
|
-+
|
|
|
-+#define HARD_REGNO_NREGS(REGNO, MODE) \
|
|
|
-+ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \
|
|
|
-+ / UNITS_PER_WORD)
|
|
|
-+
|
|
|
-+/* --------------------------- *
|
|
|
-+ * How Values Fit in Registers
|
|
|
-+ * --------------------------- */
|
|
|
-+
|
|
|
-+#define HARD_REGNO_MODE_OK(REGNO, MODE) 1
|
|
|
-+
|
|
|
-+#define MODES_TIEABLE_P(MODE1, MODE2) 1
|
|
|
-+
|
|
|
-+
|
|
|
-+/*************************
|
|
|
-+ * Register Classes
|
|
|
-+ *************************/
|
|
|
-+
|
|
|
-+enum reg_class
|
|
|
-+{
|
|
|
-+ NO_REGS,
|
|
|
-+ D00_REG,
|
|
|
-+ D01_REG,
|
|
|
-+ D02_REG,
|
|
|
-+ D03_REG,
|
|
|
-+ D04_REG,
|
|
|
-+ D05_REG,
|
|
|
-+ D06_REG,
|
|
|
-+ D07_REG,
|
|
|
-+ D08_REG,
|
|
|
-+ D09_REG,
|
|
|
-+ D10_REG,
|
|
|
-+ D11_REG,
|
|
|
-+ D12_REG,
|
|
|
-+ D13_REG,
|
|
|
-+ D14_REG,
|
|
|
-+ D15_REG,
|
|
|
-+ D16_REG,
|
|
|
-+ D17_REG,
|
|
|
-+ D18_REG,
|
|
|
-+ D19_REG,
|
|
|
-+ D20_REG,
|
|
|
-+ D21_REG,
|
|
|
-+ D22_REG,
|
|
|
-+ D23_REG,
|
|
|
-+ D24_REG,
|
|
|
-+ D25_REG,
|
|
|
-+ D26_REG,
|
|
|
-+ D27_REG,
|
|
|
-+ D28_REG,
|
|
|
-+ D29_REG,
|
|
|
-+ D30_REG,
|
|
|
-+ D31_REG,
|
|
|
-+ GP_REGS,
|
|
|
-+ ALL_REGS,
|
|
|
-+ LIM_REG_CLASSES
|
|
|
-+};
|
|
|
-+
|
|
|
-+#define N_REG_CLASSES (int) LIM_REG_CLASSES
|
|
|
-+
|
|
|
-+#define REG_CLASS_NAMES \
|
|
|
-+ {"NO_REGS", \
|
|
|
-+ "D00_REG", \
|
|
|
-+ "D01_REG", \
|
|
|
-+ "D02_REG", \
|
|
|
-+ "D03_REG", \
|
|
|
-+ "D04_REG", \
|
|
|
-+ "D05_REG", \
|
|
|
-+ "D06_REG", \
|
|
|
-+ "D07_REG", \
|
|
|
-+ "D08_REG", \
|
|
|
-+ "D09_REG", \
|
|
|
-+ "D10_REG", \
|
|
|
-+ "D11_REG", \
|
|
|
-+ "D12_REG", \
|
|
|
-+ "D13_REG", \
|
|
|
-+ "D14_REG", \
|
|
|
-+ "D15_REG", \
|
|
|
-+ "D16_REG", \
|
|
|
-+ "D17_REG", \
|
|
|
-+ "D18_REG", \
|
|
|
-+ "D19_REG", \
|
|
|
-+ "D20_REG", \
|
|
|
-+ "D21_REG", \
|
|
|
-+ "D22_REG", \
|
|
|
-+ "D23_REG", \
|
|
|
-+ "D24_REG", \
|
|
|
-+ "D25_REG", \
|
|
|
-+ "D26_REG", \
|
|
|
-+ "D27_REG", \
|
|
|
-+ "D28_REG", \
|
|
|
-+ "D29_REG", \
|
|
|
-+ "D30_REG", \
|
|
|
-+ "D31_REG", \
|
|
|
-+ "GP_REGS", \
|
|
|
-+ "ALL_REGS"}
|
|
|
-+
|
|
|
-+#define GENERAL_REGS ALL_REGS
|
|
|
-+
|
|
|
-+#define REG_CLASS_CONTENTS \
|
|
|
-+/* NO_REGS */ {{ 0, 0}, \
|
|
|
-+/* D00_REG */ { 1 << 0, 0}, \
|
|
|
-+/* D01_REG */ { 1 << 1, 0}, \
|
|
|
-+/* D02_REG */ { 1 << 2, 0}, \
|
|
|
-+/* D03_REG */ { 1 << 3, 0}, \
|
|
|
-+/* D04_REG */ { 1 << 4, 0}, \
|
|
|
-+/* D05_REG */ { 1 << 5, 0}, \
|
|
|
-+/* D06_REG */ { 1 << 6, 0}, \
|
|
|
-+/* D07_REG */ { 1 << 7, 0}, \
|
|
|
-+/* D08_REG */ { 1 << 8, 0}, \
|
|
|
-+/* D09_REG */ { 1 << 9, 0}, \
|
|
|
-+/* D10_REG */ { 1 << 10, 0}, \
|
|
|
-+/* D11_REG */ { 1 << 11, 0}, \
|
|
|
-+/* D12_REG */ { 1 << 12, 0}, \
|
|
|
-+/* D13_REG */ { 1 << 13, 0}, \
|
|
|
-+/* D14_REG */ { 1 << 14, 0}, \
|
|
|
-+/* D15_REG */ { 1 << 15, 0}, \
|
|
|
-+/* D16_REG */ { 1 << 16, 0}, \
|
|
|
-+/* D17_REG */ { 1 << 17, 0}, \
|
|
|
-+/* D18_REG */ { 1 << 18, 0}, \
|
|
|
-+/* D19_REG */ { 1 << 19, 0}, \
|
|
|
-+/* D20_REG */ { 1 << 20, 0}, \
|
|
|
-+/* D21_REG */ { 1 << 21, 0}, \
|
|
|
-+/* D22_REG */ { 1 << 22, 0}, \
|
|
|
-+/* D23_REG */ { 1 << 23, 0}, \
|
|
|
-+/* D24_REG */ { 1 << 24, 0}, \
|
|
|
-+/* D25_REG */ { 1 << 25, 0}, \
|
|
|
-+/* D26_REG */ { 1 << 26, 0}, \
|
|
|
-+/* D27_REG */ { 1 << 27, 0}, \
|
|
|
-+/* D28_REG */ { 1 << 28, 0}, \
|
|
|
-+/* D29_REG */ { 1 << 29, 0}, \
|
|
|
-+/* D30_REG */ { 1 << 30, 0}, \
|
|
|
-+/* D31_REG */ { 1 << 31, 0}, \
|
|
|
-+/* GP_REGS */ {~0, 0}, \
|
|
|
-+/* ALL_REGS */ {~0,~0}} \
|
|
|
-+
|
|
|
-+#define REGNO_REG_CLASS(REGNO) ((REGNO) <= 31 ? GP_REGS : ALL_REGS)
|
|
|
-+
|
|
|
-+#define BASE_REG_CLASS ALL_REGS
|
|
|
-+#define INDEX_REG_CLASS ALL_REGS
|
|
|
-+
|
|
|
-+/* 'r', is handled automatically */
|
|
|
-+#define REG_CLASS_FROM_CONSTRAINT(CHAR, STR) \
|
|
|
-+ reg_class_from_constraint ((CHAR), (STR))
|
|
|
-+
|
|
|
-+
|
|
|
-+#define REGNO_OK_FOR_BASE_P2(REGNO, STRICT) \
|
|
|
-+ ((STRICT) \
|
|
|
-+ ? (REGNO) < FIRST_PSEUDO_REGISTER \
|
|
|
-+ : (REGNO) < FIRST_PSEUDO_REGISTER || (reg_renumber && reg_renumber[REGNO] < FIRST_PSEUDO_REGISTER))
|
|
|
-+
|
|
|
-+#define REGNO_OK_FOR_INDEX_P2(REGNO, STRICT) \
|
|
|
-+ (REGNO_OK_FOR_BASE_P2 (REGNO, STRICT))
|
|
|
-+
|
|
|
-+#define REGNO_OK_FOR_BASE_P(REGNO) \
|
|
|
-+ (REGNO_OK_FOR_BASE_P2 (REGNO, 1))
|
|
|
-+
|
|
|
-+#define REGNO_OK_FOR_INDEX_P(REGNO) \
|
|
|
-+ (REGNO_OK_FOR_INDEX_P2 (REGNO, 1))
|
|
|
-+
|
|
|
-+#define REG_OK_FOR_BASE_P2(X, STRICT) \
|
|
|
-+ (STRICT \
|
|
|
-+ ? REGNO_OK_FOR_BASE_P2 (REGNO (X), 1) \
|
|
|
-+ : REGNO_OK_FOR_BASE_P2 (REGNO (X), 1) || REGNO(X) >= FIRST_PSEUDO_REGISTER)
|
|
|
-+
|
|
|
-+#define REG_OK_FOR_INDEX_P2(X, STRICT) \
|
|
|
-+ (STRICT \
|
|
|
-+ ? REGNO_OK_FOR_INDEX_P2 (REGNO (X), 1) \
|
|
|
-+ : REGNO_OK_FOR_INDEX_P2 (REGNO (X), 1) || REGNO(X) >= FIRST_PSEUDO_REGISTER)
|
|
|
-+
|
|
|
-+#define CLASS_MAX_NREGS(CLASS, MODE) \
|
|
|
-+ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \
|
|
|
-+ / UNITS_PER_WORD)
|
|
|
-+
|
|
|
-+
|
|
|
-+#define SMALL_INT(X) ((unsigned HOST_WIDE_INT) ((X) + 0x8000) < 0x10000)
|
|
|
-+#define SMALL_INT_UNSIGNED(X) ((unsigned HOST_WIDE_INT) (X) < 0x10000)
|
|
|
-+#define UPPER16_INT(X) (((X) & 0xffff) == 0)
|
|
|
-+#define SHIFT_INT(X) ((X) >= 0 && (X) <= 31)
|
|
|
-+#define RDWRCTL_INT(X) ((X) >= 0 && (X) <= 31)
|
|
|
-+#define CUSTOM_INSN_OPCODE(X) ((X) >= 0 && (X) <= 255)
|
|
|
-+
|
|
|
-+#define CONST_OK_FOR_LETTER_P(VALUE, C) \
|
|
|
-+ ( \
|
|
|
-+ (C) == 'I' ? SMALL_INT (VALUE) : \
|
|
|
-+ (C) == 'J' ? SMALL_INT_UNSIGNED (VALUE) : \
|
|
|
-+ (C) == 'K' ? UPPER16_INT (VALUE) : \
|
|
|
-+ (C) == 'L' ? SHIFT_INT (VALUE) : \
|
|
|
-+ (C) == 'M' ? (VALUE) == 0 : \
|
|
|
-+ (C) == 'N' ? CUSTOM_INSN_OPCODE (VALUE) : \
|
|
|
-+ (C) == 'O' ? RDWRCTL_INT (VALUE) : \
|
|
|
-+ 0)
|
|
|
-+
|
|
|
-+#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) 0
|
|
|
-+
|
|
|
-+#define PREFERRED_RELOAD_CLASS(X, CLASS) \
|
|
|
-+ ((CLASS) == NO_REGS ? GENERAL_REGS : (CLASS))
|
|
|
-+
|
|
|
-+#define CONSTRAINT_LEN(C, STR) \
|
|
|
-+ ((C) == 'D' ? 3 : DEFAULT_CONSTRAINT_LEN ((C), (STR)))
|
|
|
-+
|
|
|
-+/* 'S' matches immediates which are in small data
|
|
|
-+ and therefore can be added to gp to create a
|
|
|
-+ 32-bit value. */
|
|
|
-+#define EXTRA_CONSTRAINT(VALUE, C) \
|
|
|
-+ ((C) == 'S' \
|
|
|
-+ && (GET_CODE (VALUE) == SYMBOL_REF) \
|
|
|
-+ && SYMBOL_REF_IN_NIOS2_SMALL_DATA_P (VALUE))
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+/* Say that the epilogue uses the return address register. Note that
|
|
|
-+ in the case of sibcalls, the values "used by the epilogue" are
|
|
|
-+ considered live at the start of the called function. */
|
|
|
-+#define EPILOGUE_USES(REGNO) ((REGNO) == RA_REGNO)
|
|
|
-+
|
|
|
-+
|
|
|
-+#define DEFAULT_MAIN_RETURN c_expand_return (integer_zero_node)
|
|
|
-+
|
|
|
-+/**********************************
|
|
|
-+ * Trampolines for Nested Functions
|
|
|
-+ ***********************************/
|
|
|
-+
|
|
|
-+#define TRAMPOLINE_TEMPLATE(FILE) \
|
|
|
-+ error ("trampolines not yet implemented")
|
|
|
-+#define TRAMPOLINE_SIZE 20
|
|
|
-+#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \
|
|
|
-+ error ("trampolines not yet implemented")
|
|
|
-+
|
|
|
-+/***************************
|
|
|
-+ * Stack Layout and Calling Conventions
|
|
|
-+ ***************************/
|
|
|
-+
|
|
|
-+/* ------------------ *
|
|
|
-+ * Basic Stack Layout
|
|
|
-+ * ------------------ */
|
|
|
-+
|
|
|
-+/* The downward variants are used by the compiler,
|
|
|
-+ the upward ones serve as documentation */
|
|
|
-+#define STACK_GROWS_DOWNWARD
|
|
|
-+#define FRAME_GROWS_UPWARD
|
|
|
-+#define ARGS_GROW_UPWARD
|
|
|
-+
|
|
|
-+#define STARTING_FRAME_OFFSET current_function_outgoing_args_size
|
|
|
-+#define FIRST_PARM_OFFSET(FUNDECL) 0
|
|
|
-+
|
|
|
-+/* Before the prologue, RA lives in r31. */
|
|
|
-+#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (VOIDmode, RA_REGNO)
|
|
|
-+
|
|
|
-+/* -------------------------------------- *
|
|
|
-+ * Registers That Address the Stack Frame
|
|
|
-+ * -------------------------------------- */
|
|
|
-+
|
|
|
-+#define STACK_POINTER_REGNUM SP_REGNO
|
|
|
-+#define STATIC_CHAIN_REGNUM SC_REGNO
|
|
|
-+#define PC_REGNUM PC_REGNO
|
|
|
-+#define DWARF_FRAME_RETURN_COLUMN RA_REGNO
|
|
|
-+
|
|
|
-+/* Base register for access to local variables of the function. We
|
|
|
-+ pretend that the frame pointer is a non-existent hard register, and
|
|
|
-+ then eliminate it to HARD_FRAME_POINTER_REGNUM. */
|
|
|
-+#define FRAME_POINTER_REGNUM FAKE_FP_REGNO
|
|
|
-+
|
|
|
-+#define HARD_FRAME_POINTER_REGNUM FP_REGNO
|
|
|
-+#define RETURN_ADDRESS_POINTER_REGNUM RAP_REGNO
|
|
|
-+/* the argumnet pointer needs to always be eliminated
|
|
|
-+ so it is set to a fake hard register. */
|
|
|
-+#define ARG_POINTER_REGNUM FAKE_AP_REGNO
|
|
|
-+
|
|
|
-+/* ----------------------------------------- *
|
|
|
-+ * Eliminating Frame Pointer and Arg Pointer
|
|
|
-+ * ----------------------------------------- */
|
|
|
-+
|
|
|
-+#define FRAME_POINTER_REQUIRED 0
|
|
|
-+
|
|
|
-+#define ELIMINABLE_REGS \
|
|
|
-+{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
|
|
|
-+ { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \
|
|
|
-+ { RETURN_ADDRESS_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
|
|
|
-+ { RETURN_ADDRESS_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \
|
|
|
-+ { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
|
|
|
-+ { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}}
|
|
|
-+
|
|
|
-+#define CAN_ELIMINATE(FROM, TO) 1
|
|
|
-+
|
|
|
-+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
|
|
|
-+ (OFFSET) = nios2_initial_elimination_offset ((FROM), (TO))
|
|
|
-+
|
|
|
-+#define MUST_SAVE_REGISTER(regno) \
|
|
|
-+ ((regs_ever_live[regno] && !call_used_regs[regno]) \
|
|
|
-+ || (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed) \
|
|
|
-+ || (regno == RA_REGNO && regs_ever_live[RA_REGNO]))
|
|
|
-+
|
|
|
-+/* Treat LOC as a byte offset from the stack pointer and round it up
|
|
|
-+ to the next fully-aligned offset. */
|
|
|
-+#define STACK_ALIGN(LOC) \
|
|
|
-+ (((LOC) + ((PREFERRED_STACK_BOUNDARY / 8) - 1)) & ~((PREFERRED_STACK_BOUNDARY / 8) - 1))
|
|
|
-+
|
|
|
-+
|
|
|
-+/* ------------------------------ *
|
|
|
-+ * Passing Arguments in Registers
|
|
|
-+ * ------------------------------ */
|
|
|
-+
|
|
|
-+/* see nios2.c */
|
|
|
-+#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
|
|
|
-+ (function_arg (&CUM, MODE, TYPE, NAMED))
|
|
|
-+
|
|
|
-+#define MUST_PASS_IN_STACK(MODE, TYPE) \
|
|
|
-+ nios2_must_pass_in_stack ((MODE), (TYPE))
|
|
|
-+
|
|
|
-+#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \
|
|
|
-+ (function_arg_partial_nregs (&CUM, MODE, TYPE, NAMED))
|
|
|
-+
|
|
|
-+#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) 0
|
|
|
-+
|
|
|
-+#define FUNCTION_ARG_CALLEE_COPIES(CUM, MODE, TYPE, NAMED) 0
|
|
|
-+
|
|
|
-+typedef struct nios2_args
|
|
|
-+{
|
|
|
-+ int regs_used;
|
|
|
-+} CUMULATIVE_ARGS;
|
|
|
-+
|
|
|
-+/* This is to initialize the above unused CUM data type */
|
|
|
-+#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS) \
|
|
|
-+ (init_cumulative_args (&CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS))
|
|
|
-+
|
|
|
-+#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \
|
|
|
-+ (function_arg_advance (&CUM, MODE, TYPE, NAMED))
|
|
|
-+
|
|
|
-+#define FUNCTION_ARG_PADDING(MODE, TYPE) \
|
|
|
-+ (nios2_function_arg_padding_upward ((MODE), (TYPE)) ? upward : downward)
|
|
|
-+
|
|
|
-+#define PAD_VARARGS_DOWN \
|
|
|
-+ (FUNCTION_ARG_PADDING (TYPE_MODE (type), type) == downward)
|
|
|
-+
|
|
|
-+#define BLOCK_REG_PADDING(MODE, TYPE, FIRST) \
|
|
|
-+ (nios2_block_reg_padding_upward ((MODE), (TYPE), (FIRST)) ? upward : downward)
|
|
|
-+
|
|
|
-+#define FUNCTION_ARG_REGNO_P(REGNO) \
|
|
|
-+ ((REGNO) >= FIRST_ARG_REGNO && (REGNO) <= LAST_ARG_REGNO)
|
|
|
-+
|
|
|
-+#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \
|
|
|
-+ { \
|
|
|
-+ int pret_size = nios2_setup_incoming_varargs (&(CUM), (MODE), \
|
|
|
-+ (TYPE), (NO_RTL)); \
|
|
|
-+ if (pret_size) \
|
|
|
-+ (PRETEND_SIZE) = pret_size; \
|
|
|
-+ }
|
|
|
-+
|
|
|
-+/* ----------------------------- *
|
|
|
-+ * Generating Code for Profiling
|
|
|
-+ * ----------------------------- */
|
|
|
-+
|
|
|
-+
|
|
|
-+#define PROFILE_BEFORE_PROLOGUE
|
|
|
-+#define NO_PROFILE_COUNTERS 1
|
|
|
-+#define FUNCTION_PROFILER(FILE, LABELNO) \
|
|
|
-+ function_profiler ((FILE), (LABELNO))
|
|
|
-+
|
|
|
-+/* --------------------------------------- *
|
|
|
-+ * Passing Function Arguments on the Stack
|
|
|
-+ * --------------------------------------- */
|
|
|
-+
|
|
|
-+#define PROMOTE_PROTOTYPES 1
|
|
|
-+
|
|
|
-+#define PUSH_ARGS 0
|
|
|
-+#define ACCUMULATE_OUTGOING_ARGS 1
|
|
|
-+
|
|
|
-+#define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, STACKSIZE) 0
|
|
|
-+
|
|
|
-+/* --------------------------------------- *
|
|
|
-+ * How Scalar Function Values Are Returned
|
|
|
-+ * --------------------------------------- */
|
|
|
-+
|
|
|
-+#define FUNCTION_VALUE(VALTYPE, FUNC) \
|
|
|
-+ gen_rtx(REG, TYPE_MODE(VALTYPE), FIRST_RETVAL_REGNO)
|
|
|
-+
|
|
|
-+#define LIBCALL_VALUE(MODE) \
|
|
|
-+ gen_rtx(REG, MODE, FIRST_RETVAL_REGNO)
|
|
|
-+
|
|
|
-+#define FUNCTION_VALUE_REGNO_P(REGNO) ((REGNO) == FIRST_RETVAL_REGNO)
|
|
|
-+
|
|
|
-+/* ----------------------------- *
|
|
|
-+ * How Large Values Are Returned
|
|
|
-+ * ----------------------------- */
|
|
|
-+
|
|
|
-+
|
|
|
-+#define RETURN_IN_MEMORY(TYPE) \
|
|
|
-+ nios2_return_in_memory (TYPE)
|
|
|
-+
|
|
|
-+
|
|
|
-+#define STRUCT_VALUE 0
|
|
|
-+
|
|
|
-+#define DEFAULT_PCC_STRUCT_RETURN 0
|
|
|
-+
|
|
|
-+/*******************
|
|
|
-+ * Addressing Modes
|
|
|
-+ *******************/
|
|
|
-+
|
|
|
-+
|
|
|
-+#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN)
|
|
|
-+
|
|
|
-+#define CONSTANT_ADDRESS_P(X) (CONSTANT_P (X))
|
|
|
-+
|
|
|
-+#define MAX_REGS_PER_ADDRESS 1
|
|
|
-+
|
|
|
-+/* Go to ADDR if X is a valid address. */
|
|
|
-+#ifndef REG_OK_STRICT
|
|
|
-+#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \
|
|
|
-+ { \
|
|
|
-+ if (nios2_legitimate_address ((X), (MODE), 0)) \
|
|
|
-+ goto ADDR; \
|
|
|
-+ }
|
|
|
-+#else
|
|
|
-+#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \
|
|
|
-+ { \
|
|
|
-+ if (nios2_legitimate_address ((X), (MODE), 1)) \
|
|
|
-+ goto ADDR; \
|
|
|
-+ }
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+#ifndef REG_OK_STRICT
|
|
|
-+#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P2 (REGNO (X), 0)
|
|
|
-+#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P2 (REGNO (X), 0)
|
|
|
-+#else
|
|
|
-+#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P2 (REGNO (X), 1)
|
|
|
-+#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P2 (REGNO (X), 1)
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+#define LEGITIMATE_CONSTANT_P(X) 1
|
|
|
-+
|
|
|
-+/* Nios II has no mode dependent addresses. */
|
|
|
-+#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL)
|
|
|
-+
|
|
|
-+/* Set if this has a weak declaration */
|
|
|
-+#define SYMBOL_FLAG_WEAK_DECL (1 << SYMBOL_FLAG_MACH_DEP_SHIFT)
|
|
|
-+#define SYMBOL_REF_WEAK_DECL_P(RTX) \
|
|
|
-+ ((SYMBOL_REF_FLAGS (RTX) & SYMBOL_FLAG_WEAK_DECL) != 0)
|
|
|
-+
|
|
|
-+
|
|
|
-+/* true if a symbol is both small and not weak. In this case, gp
|
|
|
-+ relative access can be used */
|
|
|
-+#define SYMBOL_REF_IN_NIOS2_SMALL_DATA_P(RTX) \
|
|
|
-+ (SYMBOL_REF_SMALL_P(RTX) && !SYMBOL_REF_WEAK_DECL_P(RTX))
|
|
|
-+
|
|
|
-+/*****************
|
|
|
-+ * Describing Relative Costs of Operations
|
|
|
-+ *****************/
|
|
|
-+
|
|
|
-+#define SLOW_BYTE_ACCESS 1
|
|
|
-+
|
|
|
-+/* It is as good to call a constant function address as to call an address
|
|
|
-+ kept in a register.
|
|
|
-+ ??? Not true anymore really. Now that call cannot address full range
|
|
|
-+ of memory callr may need to be used */
|
|
|
-+
|
|
|
-+#define NO_FUNCTION_CSE
|
|
|
-+#define NO_RECURSIVE_FUNCTION_CSE
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+/*****************************************
|
|
|
-+ * Defining the Output Assembler Language
|
|
|
-+ *****************************************/
|
|
|
-+
|
|
|
-+/* ------------------------------------------ *
|
|
|
-+ * The Overall Framework of an Assembler File
|
|
|
-+ * ------------------------------------------ */
|
|
|
-+
|
|
|
-+#define ASM_APP_ON "#APP\n"
|
|
|
-+#define ASM_APP_OFF "#NO_APP\n"
|
|
|
-+
|
|
|
-+#define ASM_COMMENT_START "# "
|
|
|
-+
|
|
|
-+/* ------------------------------- *
|
|
|
-+ * Output and Generation of Labels
|
|
|
-+ * ------------------------------- */
|
|
|
-+
|
|
|
-+#define GLOBAL_ASM_OP "\t.global\t"
|
|
|
-+
|
|
|
-+
|
|
|
-+/* -------------- *
|
|
|
-+ * Output of Data
|
|
|
-+ * -------------- */
|
|
|
-+
|
|
|
-+#define DWARF2_UNWIND_INFO 0
|
|
|
-+
|
|
|
-+
|
|
|
-+/* -------------------------------- *
|
|
|
-+ * Assembler Commands for Alignment
|
|
|
-+ * -------------------------------- */
|
|
|
-+
|
|
|
-+#define ASM_OUTPUT_ALIGN(FILE, LOG) \
|
|
|
-+ do { \
|
|
|
-+ fprintf ((FILE), "%s%d\n", ALIGN_ASM_OP, (LOG)); \
|
|
|
-+ } while (0)
|
|
|
-+
|
|
|
-+
|
|
|
-+/* -------------------------------- *
|
|
|
-+ * Output of Assembler Instructions
|
|
|
-+ * -------------------------------- */
|
|
|
-+
|
|
|
-+#define REGISTER_NAMES \
|
|
|
-+{ \
|
|
|
-+ "zero", \
|
|
|
-+ "at", \
|
|
|
-+ "r2", \
|
|
|
-+ "r3", \
|
|
|
-+ "r4", \
|
|
|
-+ "r5", \
|
|
|
-+ "r6", \
|
|
|
-+ "r7", \
|
|
|
-+ "r8", \
|
|
|
-+ "r9", \
|
|
|
-+ "r10", \
|
|
|
-+ "r11", \
|
|
|
-+ "r12", \
|
|
|
-+ "r13", \
|
|
|
-+ "r14", \
|
|
|
-+ "r15", \
|
|
|
-+ "r16", \
|
|
|
-+ "r17", \
|
|
|
-+ "r18", \
|
|
|
-+ "r19", \
|
|
|
-+ "r20", \
|
|
|
-+ "r21", \
|
|
|
-+ "r22", \
|
|
|
-+ "r23", \
|
|
|
-+ "et", \
|
|
|
-+ "bt", \
|
|
|
-+ "gp", \
|
|
|
-+ "sp", \
|
|
|
-+ "fp", \
|
|
|
-+ "ta", \
|
|
|
-+ "ba", \
|
|
|
-+ "ra", \
|
|
|
-+ "status", \
|
|
|
-+ "estatus", \
|
|
|
-+ "bstatus", \
|
|
|
-+ "ipri", \
|
|
|
-+ "ecause", \
|
|
|
-+ "pc", \
|
|
|
-+ "rap", \
|
|
|
-+ "fake_fp", \
|
|
|
-+ "fake_ap", \
|
|
|
-+}
|
|
|
-+
|
|
|
-+#define ADDITIONAL_REGISTER_NAMES \
|
|
|
-+{ \
|
|
|
-+ {"r0", 0}, \
|
|
|
-+ {"r1", 1}, \
|
|
|
-+ {"r24", 24}, \
|
|
|
-+ {"r25", 25}, \
|
|
|
-+ {"r26", 26}, \
|
|
|
-+ {"r27", 27}, \
|
|
|
-+ {"r28", 28}, \
|
|
|
-+ {"r29", 29}, \
|
|
|
-+ {"r30", 30}, \
|
|
|
-+ {"r31", 31} \
|
|
|
-+}
|
|
|
-+
|
|
|
-+
|
|
|
-+#define ASM_OUTPUT_OPCODE(STREAM, PTR)\
|
|
|
-+ (PTR) = asm_output_opcode (STREAM, PTR)
|
|
|
-+
|
|
|
-+#define PRINT_OPERAND(STREAM, X, CODE) \
|
|
|
-+ nios2_print_operand (STREAM, X, CODE)
|
|
|
-+
|
|
|
-+#define PRINT_OPERAND_ADDRESS(STREAM, X) \
|
|
|
-+ nios2_print_operand_address (STREAM, X)
|
|
|
-+
|
|
|
-+#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
|
|
|
-+do { fputs (integer_asm_op (POINTER_SIZE / BITS_PER_UNIT, TRUE), FILE); \
|
|
|
-+ fprintf (FILE, ".L%u\n", (unsigned) (VALUE)); \
|
|
|
-+ } while (0)
|
|
|
-+
|
|
|
-+
|
|
|
-+/* ------------ *
|
|
|
-+ * Label Output
|
|
|
-+ * ------------ */
|
|
|
-+
|
|
|
-+
|
|
|
-+/* ---------------------------------------------------- *
|
|
|
-+ * Dividing the Output into Sections (Texts, Data, ...)
|
|
|
-+ * ---------------------------------------------------- */
|
|
|
-+
|
|
|
-+/* Output before read-only data. */
|
|
|
-+#define TEXT_SECTION_ASM_OP ("\t.section\t.text")
|
|
|
-+
|
|
|
-+/* Output before writable data. */
|
|
|
-+#define DATA_SECTION_ASM_OP ("\t.section\t.data")
|
|
|
-+
|
|
|
-+
|
|
|
-+/* Default the definition of "small data" to 8 bytes. */
|
|
|
-+/* ??? How come I can't use HOST_WIDE_INT here? */
|
|
|
-+extern unsigned long nios2_section_threshold;
|
|
|
-+#define NIOS2_DEFAULT_GVALUE 8
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+/* This says how to output assembler code to declare an
|
|
|
-+ uninitialized external linkage data object. Under SVR4,
|
|
|
-+ the linker seems to want the alignment of data objects
|
|
|
-+ to depend on their types. We do exactly that here. */
|
|
|
-+
|
|
|
-+#undef COMMON_ASM_OP
|
|
|
-+#define COMMON_ASM_OP "\t.comm\t"
|
|
|
-+
|
|
|
-+#undef ASM_OUTPUT_ALIGNED_COMMON
|
|
|
-+#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \
|
|
|
-+do \
|
|
|
-+{ \
|
|
|
-+ if ((SIZE) <= nios2_section_threshold) \
|
|
|
-+ { \
|
|
|
-+ named_section (0, ".sbss", 0); \
|
|
|
-+ (*targetm.asm_out.globalize_label) (FILE, NAME); \
|
|
|
-+ ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object"); \
|
|
|
-+ if (!flag_inhibit_size_directive) \
|
|
|
-+ ASM_OUTPUT_SIZE_DIRECTIVE (FILE, NAME, SIZE); \
|
|
|
-+ ASM_OUTPUT_ALIGN ((FILE), exact_log2((ALIGN) / BITS_PER_UNIT)); \
|
|
|
-+ ASM_OUTPUT_LABEL(FILE, NAME); \
|
|
|
-+ ASM_OUTPUT_SKIP((FILE), (SIZE) ? (SIZE) : 1); \
|
|
|
-+ } \
|
|
|
-+ else \
|
|
|
-+ { \
|
|
|
-+ fprintf ((FILE), "%s", COMMON_ASM_OP); \
|
|
|
-+ assemble_name ((FILE), (NAME)); \
|
|
|
-+ fprintf ((FILE), ","HOST_WIDE_INT_PRINT_UNSIGNED",%u\n", (SIZE), (ALIGN) / BITS_PER_UNIT); \
|
|
|
-+ } \
|
|
|
-+} \
|
|
|
-+while (0)
|
|
|
-+
|
|
|
-+
|
|
|
-+/* This says how to output assembler code to declare an
|
|
|
-+ uninitialized internal linkage data object. Under SVR4,
|
|
|
-+ the linker seems to want the alignment of data objects
|
|
|
-+ to depend on their types. We do exactly that here. */
|
|
|
-+
|
|
|
-+#undef ASM_OUTPUT_ALIGNED_LOCAL
|
|
|
-+#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \
|
|
|
-+do { \
|
|
|
-+ if ((SIZE) <= nios2_section_threshold) \
|
|
|
-+ named_section (0, ".sbss", 0); \
|
|
|
-+ else \
|
|
|
-+ named_section (0, ".bss", 0); \
|
|
|
-+ ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object"); \
|
|
|
-+ if (!flag_inhibit_size_directive) \
|
|
|
-+ ASM_OUTPUT_SIZE_DIRECTIVE (FILE, NAME, SIZE); \
|
|
|
-+ ASM_OUTPUT_ALIGN ((FILE), exact_log2((ALIGN) / BITS_PER_UNIT)); \
|
|
|
-+ ASM_OUTPUT_LABEL(FILE, NAME); \
|
|
|
-+ ASM_OUTPUT_SKIP((FILE), (SIZE) ? (SIZE) : 1); \
|
|
|
-+} while (0)
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+/***************************
|
|
|
-+ * Miscellaneous Parameters
|
|
|
-+ ***************************/
|
|
|
-+
|
|
|
-+#define MOVE_MAX 4
|
|
|
-+
|
|
|
-+#define STORE_FLAG_VALUE 1
|
|
|
-+#define Pmode SImode
|
|
|
-+#define FUNCTION_MODE QImode
|
|
|
-+
|
|
|
-+#define REGISTER_TARGET_PRAGMAS() nios2_register_target_pragmas ();
|
|
|
-+
|
|
|
-+#define CASE_VECTOR_MODE Pmode
|
|
|
-+
|
|
|
-+#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
|
|
|
-+
|
|
|
-+#define LOAD_EXTEND_OP(MODE) (ZERO_EXTEND)
|
|
|
-+
|
|
|
-+#define WORD_REGISTER_OPERATIONS
|
|
|
-diff --git a/gcc/config/nios2/nios2.md b/gcc/config/nios2/nios2.md
|
|
|
-new file mode 100644
|
|
|
-index 0000000..6183247
|
|
|
---- /dev/null
|
|
|
-+++ b/gcc/config/nios2/nios2.md
|
|
|
-@@ -0,0 +1,2867 @@
|
|
|
-+;; Machine Description for Altera NIOS 2G NIOS2 version.
|
|
|
-+;; Copyright (C) 2005 Altera
|
|
|
-+;; Contributed by Jonah Graham (jgraham@altera.com) and Will Reece (wreece@altera.com).
|
|
|
-+;;
|
|
|
-+;; This file is part of GNU CC.
|
|
|
-+;;
|
|
|
-+;; GNU CC is free software; you can redistribute it and/or modify
|
|
|
-+;; it under the terms of the GNU General Public License as published by
|
|
|
-+;; the Free Software Foundation; either version 2, or (at your option)
|
|
|
-+;; any later version.
|
|
|
-+;;
|
|
|
-+;; GNU CC is distributed in the hope that it will be useful,
|
|
|
-+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
-+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
-+;; GNU General Public License for more details.
|
|
|
-+;;
|
|
|
-+;; You should have received a copy of the GNU General Public License
|
|
|
-+;; along with GNU CC; see the file COPYING. If not, write to
|
|
|
-+;; the Free Software Foundation, 59 Temple Place - Suite 330,
|
|
|
-+;; Boston, MA 02111-1307, USA. */
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+;*****************************************************************************
|
|
|
-+;*
|
|
|
-+;* constraint strings
|
|
|
-+;*
|
|
|
-+;*****************************************************************************
|
|
|
-+;
|
|
|
-+; We use the following constraint letters for constants
|
|
|
-+;
|
|
|
-+; I: -32768 to -32767
|
|
|
-+; J: 0 to 65535
|
|
|
-+; K: $nnnn0000 for some nnnn
|
|
|
-+; L: 0 to 31 (for shift counts)
|
|
|
-+; M: 0
|
|
|
-+; N: 0 to 255 (for custom instruction numbers)
|
|
|
-+; O: 0 to 31 (for control register numbers)
|
|
|
-+;
|
|
|
-+; We use the following built-in register classes:
|
|
|
-+;
|
|
|
-+; r: general purpose register (r0..r31)
|
|
|
-+; m: memory operand
|
|
|
-+;
|
|
|
-+; Plus, we define the following constraint strings:
|
|
|
-+;
|
|
|
-+; S: symbol that is in the "small data" area
|
|
|
-+; Dnn: Dnn_REG (just rnn)
|
|
|
-+;
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+;*****************************************************************************
|
|
|
-+;*
|
|
|
-+;* constants
|
|
|
-+;*
|
|
|
-+;*****************************************************************************
|
|
|
-+(define_constants [
|
|
|
-+ (ET_REGNO 24)
|
|
|
-+ (GP_REGNO 26)
|
|
|
-+ (SP_REGNO 27)
|
|
|
-+ (FP_REGNO 28)
|
|
|
-+ (RA_REGNO 31)
|
|
|
-+ (RAP_REGNO 38)
|
|
|
-+ (FIRST_RETVAL_REGNO 2)
|
|
|
-+ (LAST_RETVAL_REGNO 3)
|
|
|
-+ (FIRST_ARG_REGNO 4)
|
|
|
-+ (LAST_ARG_REGNO 7)
|
|
|
-+ (SC_REGNO 23)
|
|
|
-+ (PC_REGNO 37)
|
|
|
-+ (FAKE_FP_REGNO 39)
|
|
|
-+ (FAKE_AP_REGNO 40)
|
|
|
-+
|
|
|
-+
|
|
|
-+ (UNSPEC_BLOCKAGE 0)
|
|
|
-+ (UNSPEC_LDBIO 1)
|
|
|
-+ (UNSPEC_LDBUIO 2)
|
|
|
-+ (UNSPEC_LDHIO 3)
|
|
|
-+ (UNSPEC_LDHUIO 4)
|
|
|
-+ (UNSPEC_LDWIO 5)
|
|
|
-+ (UNSPEC_STBIO 6)
|
|
|
-+ (UNSPEC_STHIO 7)
|
|
|
-+ (UNSPEC_STWIO 8)
|
|
|
-+ (UNSPEC_SYNC 9)
|
|
|
-+ (UNSPEC_WRCTL 10)
|
|
|
-+ (UNSPEC_RDCTL 11)
|
|
|
-+ (UNSPEC_TRAP 12)
|
|
|
-+ (UNSPEC_STACK_OVERFLOW_DETECT_AND_TRAP 13)
|
|
|
-+ (UNSPEC_FCOSS 14)
|
|
|
-+ (UNSPEC_FCOSD 15)
|
|
|
-+ (UNSPEC_FSINS 16)
|
|
|
-+ (UNSPEC_FSIND 17)
|
|
|
-+ (UNSPEC_FTANS 18)
|
|
|
-+ (UNSPEC_FTAND 19)
|
|
|
-+ (UNSPEC_FATANS 20)
|
|
|
-+ (UNSPEC_FATAND 21)
|
|
|
-+ (UNSPEC_FEXPS 22)
|
|
|
-+ (UNSPEC_FEXPD 23)
|
|
|
-+ (UNSPEC_FLOGS 24)
|
|
|
-+ (UNSPEC_FLOGD 25)
|
|
|
-+ (UNSPEC_FWRX 26)
|
|
|
-+ (UNSPEC_FWRY 27)
|
|
|
-+ (UNSPEC_FRDXLO 28)
|
|
|
-+ (UNSPEC_FRDXHI 29)
|
|
|
-+ (UNSPEC_FRDY 30)
|
|
|
-+ ;; Note that values 100..151 are used by custom instructions, see below.
|
|
|
-+])
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+;*****************************************************************************
|
|
|
-+;*
|
|
|
-+;* instruction scheduler
|
|
|
-+;*
|
|
|
-+;*****************************************************************************
|
|
|
-+
|
|
|
-+; No schedule info is currently available, using an assumption that no
|
|
|
-+; instruction can use the results of the previous instruction without
|
|
|
-+; incuring a stall.
|
|
|
-+
|
|
|
-+; length of an instruction (in bytes)
|
|
|
-+(define_attr "length" "" (const_int 4))
|
|
|
-+(define_attr "type" "unknown,complex,control,alu,cond_alu,st,ld,shift,mul,div,custom" (const_string "complex"))
|
|
|
-+
|
|
|
-+(define_asm_attributes
|
|
|
-+ [(set_attr "length" "4")
|
|
|
-+ (set_attr "type" "complex")])
|
|
|
-+
|
|
|
-+(define_automaton "nios2")
|
|
|
-+(automata_option "v")
|
|
|
-+;(automata_option "no-minimization")
|
|
|
-+(automata_option "ndfa")
|
|
|
-+
|
|
|
-+; The nios2 pipeline is fairly straightforward for the fast model.
|
|
|
-+; Every alu operation is pipelined so that an instruction can
|
|
|
-+; be issued every cycle. However, there are still potential
|
|
|
-+; stalls which this description tries to deal with.
|
|
|
-+
|
|
|
-+(define_cpu_unit "cpu" "nios2")
|
|
|
-+
|
|
|
-+(define_insn_reservation "complex" 1
|
|
|
-+ (eq_attr "type" "complex")
|
|
|
-+ "cpu")
|
|
|
-+
|
|
|
-+(define_insn_reservation "control" 1
|
|
|
-+ (eq_attr "type" "control")
|
|
|
-+ "cpu")
|
|
|
-+
|
|
|
-+(define_insn_reservation "alu" 1
|
|
|
-+ (eq_attr "type" "alu")
|
|
|
-+ "cpu")
|
|
|
-+
|
|
|
-+(define_insn_reservation "cond_alu" 1
|
|
|
-+ (eq_attr "type" "cond_alu")
|
|
|
-+ "cpu")
|
|
|
-+
|
|
|
-+(define_insn_reservation "st" 1
|
|
|
-+ (eq_attr "type" "st")
|
|
|
-+ "cpu")
|
|
|
-+
|
|
|
-+(define_insn_reservation "custom" 1
|
|
|
-+ (eq_attr "type" "custom")
|
|
|
-+ "cpu")
|
|
|
-+
|
|
|
-+; shifts, muls and lds have three cycle latency
|
|
|
-+(define_insn_reservation "ld" 3
|
|
|
-+ (eq_attr "type" "ld")
|
|
|
-+ "cpu")
|
|
|
-+
|
|
|
-+(define_insn_reservation "shift" 3
|
|
|
-+ (eq_attr "type" "shift")
|
|
|
-+ "cpu")
|
|
|
-+
|
|
|
-+(define_insn_reservation "mul" 3
|
|
|
-+ (eq_attr "type" "mul")
|
|
|
-+ "cpu")
|
|
|
-+
|
|
|
-+(define_insn_reservation "div" 1
|
|
|
-+ (eq_attr "type" "div")
|
|
|
-+ "cpu")
|
|
|
-+
|
|
|
-+
|
|
|
-+;*****************************************************************************
|
|
|
-+;*
|
|
|
-+;* MOV Instructions
|
|
|
-+;*
|
|
|
-+;*****************************************************************************
|
|
|
-+
|
|
|
-+(define_expand "movqi"
|
|
|
-+ [(set (match_operand:QI 0 "nonimmediate_operand" "")
|
|
|
-+ (match_operand:QI 1 "general_operand" ""))]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+ if (nios2_emit_move_sequence (operands, QImode))
|
|
|
-+ DONE;
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_insn "movqi_internal"
|
|
|
-+ [(set (match_operand:QI 0 "nonimmediate_operand" "=m, r,r, r")
|
|
|
-+ (match_operand:QI 1 "general_operand" "rM,m,rM,I"))]
|
|
|
-+ "(register_operand (operands[0], QImode)
|
|
|
-+ || reg_or_0_operand (operands[1], QImode))"
|
|
|
-+ "@
|
|
|
-+ stb%o0\\t%z1, %0
|
|
|
-+ ldbu%o1\\t%0, %1
|
|
|
-+ mov\\t%0, %z1
|
|
|
-+ movi\\t%0, %1"
|
|
|
-+ [(set_attr "type" "st,ld,alu,alu")])
|
|
|
-+
|
|
|
-+(define_insn "ldbio"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDBIO))
|
|
|
-+ (use (match_operand:SI 1 "memory_operand" "m"))]
|
|
|
-+ ""
|
|
|
-+ "ldbio\\t%0, %1"
|
|
|
-+ [(set_attr "type" "ld")])
|
|
|
-+
|
|
|
-+(define_insn "ldbuio"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDBUIO))
|
|
|
-+ (use (match_operand:SI 1 "memory_operand" "m"))]
|
|
|
-+ ""
|
|
|
-+ "ldbuio\\t%0, %1"
|
|
|
-+ [(set_attr "type" "ld")])
|
|
|
-+
|
|
|
-+(define_insn "stbio"
|
|
|
-+ [(set (match_operand:SI 0 "memory_operand" "=m")
|
|
|
-+ (match_operand:SI 1 "reg_or_0_operand" "rM"))
|
|
|
-+ (unspec_volatile:SI [(const_int 0)] UNSPEC_STBIO)]
|
|
|
-+ ""
|
|
|
-+ "stbio\\t%z1, %0"
|
|
|
-+ [(set_attr "type" "st")])
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_expand "movhi"
|
|
|
-+ [(set (match_operand:HI 0 "nonimmediate_operand" "")
|
|
|
-+ (match_operand:HI 1 "general_operand" ""))]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+ if (nios2_emit_move_sequence (operands, HImode))
|
|
|
-+ DONE;
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_insn "movhi_internal"
|
|
|
-+ [(set (match_operand:HI 0 "nonimmediate_operand" "=m, r,r, r,r")
|
|
|
-+ (match_operand:HI 1 "general_operand" "rM,m,rM,I,J"))]
|
|
|
-+ "(register_operand (operands[0], HImode)
|
|
|
-+ || reg_or_0_operand (operands[1], HImode))"
|
|
|
-+ "@
|
|
|
-+ sth%o0\\t%z1, %0
|
|
|
-+ ldhu%o1\\t%0, %1
|
|
|
-+ mov\\t%0, %z1
|
|
|
-+ movi\\t%0, %1
|
|
|
-+ movui\\t%0, %1"
|
|
|
-+ [(set_attr "type" "st,ld,alu,alu,alu")])
|
|
|
-+
|
|
|
-+(define_insn "ldhio"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDHIO))
|
|
|
-+ (use (match_operand:SI 1 "memory_operand" "m"))]
|
|
|
-+ ""
|
|
|
-+ "ldhio\\t%0, %1"
|
|
|
-+ [(set_attr "type" "ld")])
|
|
|
-+
|
|
|
-+(define_insn "ldhuio"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDHUIO))
|
|
|
-+ (use (match_operand:SI 1 "memory_operand" "m"))]
|
|
|
-+ ""
|
|
|
-+ "ldhuio\\t%0, %1"
|
|
|
-+ [(set_attr "type" "ld")])
|
|
|
-+
|
|
|
-+(define_insn "sthio"
|
|
|
-+ [(set (match_operand:SI 0 "memory_operand" "=m")
|
|
|
-+ (match_operand:SI 1 "reg_or_0_operand" "rM"))
|
|
|
-+ (unspec_volatile:SI [(const_int 0)] UNSPEC_STHIO)]
|
|
|
-+ ""
|
|
|
-+ "sthio\\t%z1, %0"
|
|
|
-+ [(set_attr "type" "st")])
|
|
|
-+
|
|
|
-+(define_expand "movsi"
|
|
|
-+ [(set (match_operand:SI 0 "nonimmediate_operand" "")
|
|
|
-+ (match_operand:SI 1 "general_operand" ""))]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+ if (nios2_emit_move_sequence (operands, SImode))
|
|
|
-+ DONE;
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_insn "movsi_internal"
|
|
|
-+ [(set (match_operand:SI 0 "nonimmediate_operand" "=m, r,r, r,r,r,r")
|
|
|
-+ (match_operand:SI 1 "general_operand" "rM,m,rM,I,J,S,i"))]
|
|
|
-+ "(register_operand (operands[0], SImode)
|
|
|
-+ || reg_or_0_operand (operands[1], SImode))"
|
|
|
-+ "@
|
|
|
-+ stw%o0\\t%z1, %0
|
|
|
-+ ldw%o1\\t%0, %1
|
|
|
-+ mov\\t%0, %z1
|
|
|
-+ movi\\t%0, %1
|
|
|
-+ movui\\t%0, %1
|
|
|
-+ addi\\t%0, gp, %%gprel(%1)
|
|
|
-+ movhi\\t%0, %H1\;addi\\t%0, %0, %L1"
|
|
|
-+ [(set_attr "type" "st,ld,alu,alu,alu,alu,alu")])
|
|
|
-+
|
|
|
-+(define_insn "ldwio"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDWIO))
|
|
|
-+ (use (match_operand:SI 1 "memory_operand" "m"))]
|
|
|
-+ ""
|
|
|
-+ "ldwio\\t%0, %1"
|
|
|
-+ [(set_attr "type" "ld")])
|
|
|
-+
|
|
|
-+(define_insn "stwio"
|
|
|
-+ [(set (match_operand:SI 0 "memory_operand" "=m")
|
|
|
-+ (match_operand:SI 1 "reg_or_0_operand" "rM"))
|
|
|
-+ (unspec_volatile:SI [(const_int 0)] UNSPEC_STWIO)]
|
|
|
-+ ""
|
|
|
-+ "stwio\\t%z1, %0"
|
|
|
-+ [(set_attr "type" "st")])
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+;*****************************************************************************
|
|
|
-+;*
|
|
|
-+;* zero extension
|
|
|
-+;*
|
|
|
-+;*****************************************************************************
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "zero_extendhisi2"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r,r")
|
|
|
-+ (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))]
|
|
|
-+ ""
|
|
|
-+ "@
|
|
|
-+ andi\\t%0, %1, 0xffff
|
|
|
-+ ldhu%o1\\t%0, %1"
|
|
|
-+ [(set_attr "type" "alu,ld")])
|
|
|
-+
|
|
|
-+(define_insn "zero_extendqihi2"
|
|
|
-+ [(set (match_operand:HI 0 "register_operand" "=r,r")
|
|
|
-+ (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
|
|
|
-+ ""
|
|
|
-+ "@
|
|
|
-+ andi\\t%0, %1, 0xff
|
|
|
-+ ldbu%o1\\t%0, %1"
|
|
|
-+ [(set_attr "type" "alu,ld")])
|
|
|
-+
|
|
|
-+(define_insn "zero_extendqisi2"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r,r")
|
|
|
-+ (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
|
|
|
-+ ""
|
|
|
-+ "@
|
|
|
-+ andi\\t%0, %1, 0xff
|
|
|
-+ ldbu%o1\\t%0, %1"
|
|
|
-+ [(set_attr "type" "alu,ld")])
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+;*****************************************************************************
|
|
|
-+;*
|
|
|
-+;* sign extension
|
|
|
-+;*
|
|
|
-+;*****************************************************************************
|
|
|
-+(define_expand "extendhisi2"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "")
|
|
|
-+ (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_insn "*extendhisi2"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (sign_extend:SI (match_operand:HI 1 "register_operand" "r")))]
|
|
|
-+ ""
|
|
|
-+ "#")
|
|
|
-+
|
|
|
-+(define_split
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "")
|
|
|
-+ (sign_extend:SI (match_operand:HI 1 "register_operand" "")))]
|
|
|
-+ "reload_completed"
|
|
|
-+ [(set (match_dup 0)
|
|
|
-+ (and:SI (match_dup 1) (const_int 65535)))
|
|
|
-+ (set (match_dup 0)
|
|
|
-+ (xor:SI (match_dup 0) (const_int 32768)))
|
|
|
-+ (set (match_dup 0)
|
|
|
-+ (plus:SI (match_dup 0) (const_int -32768)))]
|
|
|
-+ "operands[1] = gen_lowpart (SImode, operands[1]);")
|
|
|
-+
|
|
|
-+(define_insn "extendhisi2_internal"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))]
|
|
|
-+ ""
|
|
|
-+ "ldh%o1\\t%0, %1"
|
|
|
-+ [(set_attr "type" "ld")])
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_expand "extendqihi2"
|
|
|
-+ [(set (match_operand:HI 0 "register_operand" "")
|
|
|
-+ (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_insn "*extendqihi2"
|
|
|
-+ [(set (match_operand:HI 0 "register_operand" "=r")
|
|
|
-+ (sign_extend:HI (match_operand:QI 1 "register_operand" "r")))]
|
|
|
-+ ""
|
|
|
-+ "#")
|
|
|
-+
|
|
|
-+(define_split
|
|
|
-+ [(set (match_operand:HI 0 "register_operand" "")
|
|
|
-+ (sign_extend:HI (match_operand:QI 1 "register_operand" "")))]
|
|
|
-+ "reload_completed"
|
|
|
-+ [(set (match_dup 0)
|
|
|
-+ (and:SI (match_dup 1) (const_int 255)))
|
|
|
-+ (set (match_dup 0)
|
|
|
-+ (xor:SI (match_dup 0) (const_int 128)))
|
|
|
-+ (set (match_dup 0)
|
|
|
-+ (plus:SI (match_dup 0) (const_int -128)))]
|
|
|
-+ "operands[0] = gen_lowpart (SImode, operands[0]);
|
|
|
-+ operands[1] = gen_lowpart (SImode, operands[1]);")
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "extendqihi2_internal"
|
|
|
-+ [(set (match_operand:HI 0 "register_operand" "=r")
|
|
|
-+ (sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))]
|
|
|
-+ ""
|
|
|
-+ "ldb%o1\\t%0, %1"
|
|
|
-+ [(set_attr "type" "ld")])
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_expand "extendqisi2"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "")
|
|
|
-+ (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_insn "*extendqisi2"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (sign_extend:SI (match_operand:QI 1 "register_operand" "r")))]
|
|
|
-+ ""
|
|
|
-+ "#")
|
|
|
-+
|
|
|
-+(define_split
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "")
|
|
|
-+ (sign_extend:SI (match_operand:QI 1 "register_operand" "")))]
|
|
|
-+ "reload_completed"
|
|
|
-+ [(set (match_dup 0)
|
|
|
-+ (and:SI (match_dup 1) (const_int 255)))
|
|
|
-+ (set (match_dup 0)
|
|
|
-+ (xor:SI (match_dup 0) (const_int 128)))
|
|
|
-+ (set (match_dup 0)
|
|
|
-+ (plus:SI (match_dup 0) (const_int -128)))]
|
|
|
-+ "operands[1] = gen_lowpart (SImode, operands[1]);")
|
|
|
-+
|
|
|
-+(define_insn "extendqisi2_insn"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))]
|
|
|
-+ ""
|
|
|
-+ "ldb%o1\\t%0, %1"
|
|
|
-+ [(set_attr "type" "ld")])
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+;*****************************************************************************
|
|
|
-+;*
|
|
|
-+;* Arithmetic Operations
|
|
|
-+;*
|
|
|
-+;*****************************************************************************
|
|
|
-+
|
|
|
-+(define_insn "addsi3"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r,r")
|
|
|
-+ (plus:SI (match_operand:SI 1 "register_operand" "%r,r")
|
|
|
-+ (match_operand:SI 2 "arith_operand" "r,I")))]
|
|
|
-+ ""
|
|
|
-+ "add%i2\\t%0, %1, %z2"
|
|
|
-+ [(set_attr "type" "alu")])
|
|
|
-+
|
|
|
-+(define_insn "addsf3"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (plus:SF (match_operand:SF 1 "register_operand" "%r")
|
|
|
-+ (match_operand:SF 2 "register_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_addsf3].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_addsf3].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "adddf3"
|
|
|
-+ [(set (match_operand:DF 0 "register_operand" "=r")
|
|
|
-+ (plus:DF (match_operand:DF 1 "register_operand" "%r")
|
|
|
-+ (match_operand:DF 2 "register_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_adddf3].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_adddf3].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "subsi3"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")))]
|
|
|
-+ ""
|
|
|
-+ "sub\\t%0, %z1, %2"
|
|
|
-+ [(set_attr "type" "alu")])
|
|
|
-+
|
|
|
-+(define_insn "subsf3"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (minus:SF (match_operand:SF 1 "register_operand" "r")
|
|
|
-+ (match_operand:SF 2 "register_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_subsf3].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_subsf3].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "subdf3"
|
|
|
-+ [(set (match_operand:DF 0 "register_operand" "=r")
|
|
|
-+ (minus:DF (match_operand:DF 1 "register_operand" "r")
|
|
|
-+ (match_operand:DF 2 "register_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_subdf3].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_subdf3].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "mulsi3"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r,r")
|
|
|
-+ (mult:SI (match_operand:SI 1 "register_operand" "r,r")
|
|
|
-+ (match_operand:SI 2 "arith_operand" "r,I")))]
|
|
|
-+ "TARGET_HAS_MUL"
|
|
|
-+ "mul%i2\\t%0, %1, %z2"
|
|
|
-+ [(set_attr "type" "mul")])
|
|
|
-+
|
|
|
-+(define_insn "mulsf3"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (mult:SF (match_operand:SF 1 "register_operand" "%r")
|
|
|
-+ (match_operand:SF 2 "register_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_mulsf3].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_mulsf3].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "muldf3"
|
|
|
-+ [(set (match_operand:DF 0 "register_operand" "=r")
|
|
|
-+ (mult:DF (match_operand:DF 1 "register_operand" "%r")
|
|
|
-+ (match_operand:DF 2 "register_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_muldf3].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_muldf3].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_expand "divsi3"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (div:SI (match_operand:SI 1 "register_operand" "r")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")))]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+ if (!TARGET_HAS_DIV)
|
|
|
-+ {
|
|
|
-+ if (!TARGET_FAST_SW_DIV)
|
|
|
-+ FAIL;
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ if (nios2_emit_expensive_div (operands, SImode))
|
|
|
-+ DONE;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_insn "divsi3_insn"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (div:SI (match_operand:SI 1 "register_operand" "r")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")))]
|
|
|
-+ "TARGET_HAS_DIV"
|
|
|
-+ "div\\t%0, %1, %2"
|
|
|
-+ [(set_attr "type" "div")])
|
|
|
-+
|
|
|
-+(define_insn "divsf3"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (div:SF (match_operand:SF 1 "register_operand" "r")
|
|
|
-+ (match_operand:SF 2 "register_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_divsf3].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_divsf3].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "divdf3"
|
|
|
-+ [(set (match_operand:DF 0 "register_operand" "=r")
|
|
|
-+ (div:DF (match_operand:DF 1 "register_operand" "r")
|
|
|
-+ (match_operand:DF 2 "register_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_divdf3].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_divdf3].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "udivsi3"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (udiv:SI (match_operand:SI 1 "register_operand" "r")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")))]
|
|
|
-+ "TARGET_HAS_DIV"
|
|
|
-+ "divu\\t%0, %1, %2"
|
|
|
-+ [(set_attr "type" "div")])
|
|
|
-+
|
|
|
-+(define_insn "smulsi3_highpart"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (truncate:SI
|
|
|
-+ (lshiftrt:DI
|
|
|
-+ (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r"))
|
|
|
-+ (sign_extend:DI (match_operand:SI 2 "register_operand" "r")))
|
|
|
-+ (const_int 32))))]
|
|
|
-+ "TARGET_HAS_MULX"
|
|
|
-+ "mulxss\\t%0, %1, %2"
|
|
|
-+ [(set_attr "type" "mul")])
|
|
|
-+
|
|
|
-+(define_insn "umulsi3_highpart"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (truncate:SI
|
|
|
-+ (lshiftrt:DI
|
|
|
-+ (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
|
|
|
-+ (zero_extend:DI (match_operand:SI 2 "register_operand" "r")))
|
|
|
-+ (const_int 32))))]
|
|
|
-+ "TARGET_HAS_MULX"
|
|
|
-+ "mulxuu\\t%0, %1, %2"
|
|
|
-+ [(set_attr "type" "mul")])
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_expand "mulsidi3_little_endian"
|
|
|
-+ [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 0)
|
|
|
-+ (mult:SI (match_operand:SI 1 "register_operand" "")
|
|
|
-+ (match_operand:SI 2 "register_operand" "")))
|
|
|
-+ (set (subreg:SI (match_dup 0) 4)
|
|
|
-+ (truncate:SI (lshiftrt:DI (mult:DI (sign_extend:DI (match_dup 1))
|
|
|
-+ (sign_extend:DI (match_dup 2)))
|
|
|
-+ (const_int 32))))]
|
|
|
-+ "TARGET_HAS_MULX && !WORDS_BIG_ENDIAN"
|
|
|
-+ "")
|
|
|
-+
|
|
|
-+(define_expand "mulsidi3_big_endian"
|
|
|
-+ [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 4)
|
|
|
-+ (mult:SI (match_operand:SI 1 "register_operand" "")
|
|
|
-+ (match_operand:SI 2 "register_operand" "")))
|
|
|
-+ (set (subreg:SI (match_dup 0) 0)
|
|
|
-+ (truncate:SI (lshiftrt:DI (mult:DI (sign_extend:DI (match_dup 1))
|
|
|
-+ (sign_extend:DI (match_dup 2)))
|
|
|
-+ (const_int 32))))]
|
|
|
-+ "TARGET_HAS_MULX && WORDS_BIG_ENDIAN"
|
|
|
-+ "")
|
|
|
-+
|
|
|
-+(define_expand "mulsidi3"
|
|
|
-+ [(match_operand:DI 0 "register_operand" "")
|
|
|
-+ (match_operand:SI 1 "register_operand" "")
|
|
|
-+ (match_operand:SI 2 "register_operand" "")]
|
|
|
-+ "TARGET_HAS_MULX"
|
|
|
-+ {
|
|
|
-+ if (WORDS_BIG_ENDIAN)
|
|
|
-+ {
|
|
|
-+ emit_insn (gen_mulsidi3_big_endian (operands[0],
|
|
|
-+ operands[1],
|
|
|
-+ operands[2]));
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ emit_insn (gen_mulsidi3_little_endian (operands[0],
|
|
|
-+ operands[1],
|
|
|
-+ operands[2]));
|
|
|
-+ }
|
|
|
-+ DONE;
|
|
|
-+ })
|
|
|
-+
|
|
|
-+(define_expand "umulsidi3_little_endian"
|
|
|
-+ [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 0)
|
|
|
-+ (mult:SI (match_operand:SI 1 "register_operand" "")
|
|
|
-+ (match_operand:SI 2 "register_operand" "")))
|
|
|
-+ (set (subreg:SI (match_dup 0) 4)
|
|
|
-+ (truncate:SI (lshiftrt:DI (mult:DI (zero_extend:DI (match_dup 1))
|
|
|
-+ (zero_extend:DI (match_dup 2)))
|
|
|
-+ (const_int 32))))]
|
|
|
-+ "TARGET_HAS_MULX && !WORDS_BIG_ENDIAN"
|
|
|
-+ "")
|
|
|
-+
|
|
|
-+(define_expand "umulsidi3_big_endian"
|
|
|
-+ [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 4)
|
|
|
-+ (mult:SI (match_operand:SI 1 "register_operand" "")
|
|
|
-+ (match_operand:SI 2 "register_operand" "")))
|
|
|
-+ (set (subreg:SI (match_dup 0) 0)
|
|
|
-+ (truncate:SI (lshiftrt:DI (mult:DI (zero_extend:DI (match_dup 1))
|
|
|
-+ (zero_extend:DI (match_dup 2)))
|
|
|
-+ (const_int 32))))]
|
|
|
-+ "TARGET_HAS_MULX && WORDS_BIG_ENDIAN"
|
|
|
-+ "")
|
|
|
-+
|
|
|
-+(define_expand "umulsidi3"
|
|
|
-+ [(match_operand:DI 0 "register_operand" "")
|
|
|
-+ (match_operand:SI 1 "register_operand" "")
|
|
|
-+ (match_operand:SI 2 "register_operand" "")]
|
|
|
-+ "TARGET_HAS_MULX"
|
|
|
-+ {
|
|
|
-+ if (WORDS_BIG_ENDIAN)
|
|
|
-+ {
|
|
|
-+ emit_insn (gen_umulsidi3_big_endian (operands[0],
|
|
|
-+ operands[1],
|
|
|
-+ operands[2]));
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ emit_insn (gen_umulsidi3_little_endian (operands[0],
|
|
|
-+ operands[1],
|
|
|
-+ operands[2]));
|
|
|
-+ }
|
|
|
-+ DONE;
|
|
|
-+ })
|
|
|
-+
|
|
|
-+
|
|
|
-+;*****************************************************************************
|
|
|
-+;*
|
|
|
-+;* Negate and ones complement
|
|
|
-+;*
|
|
|
-+;*****************************************************************************
|
|
|
-+
|
|
|
-+(define_insn "negsi2"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (neg:SI (match_operand:SI 1 "register_operand" "r")))]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+ operands[2] = const0_rtx;
|
|
|
-+ return "sub\\t%0, %z2, %1";
|
|
|
-+}
|
|
|
-+ [(set_attr "type" "alu")])
|
|
|
-+
|
|
|
-+(define_insn "negsf2"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (neg:SF (match_operand:SF 1 "register_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_negsf2].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_negsf2].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "negdf2"
|
|
|
-+ [(set (match_operand:DF 0 "register_operand" "=r")
|
|
|
-+ (neg:DF (match_operand:DF 1 "register_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_negdf2].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_negdf2].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "one_cmplsi2"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (not:SI (match_operand:SI 1 "register_operand" "r")))]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+ operands[2] = const0_rtx;
|
|
|
-+ return "nor\\t%0, %z2, %1";
|
|
|
-+}
|
|
|
-+ [(set_attr "type" "alu")])
|
|
|
-+
|
|
|
-+
|
|
|
-+;*****************************************************************************
|
|
|
-+;*
|
|
|
-+;* Miscellaneous floating point
|
|
|
-+;*
|
|
|
-+;*****************************************************************************
|
|
|
-+(define_insn "nios2_fwrx"
|
|
|
-+ [(unspec_volatile [(match_operand:DF 0 "register_operand" "r")] UNSPEC_FWRX)]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_nios2_fwrx].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_nios2_fwrx].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "nios2_fwry"
|
|
|
-+ [(unspec_volatile [(match_operand:SF 0 "register_operand" "r")] UNSPEC_FWRY)]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_nios2_fwry].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_nios2_fwry].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "nios2_frdxlo"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SF [(const_int 0)] UNSPEC_FRDXLO))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_nios2_frdxlo].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_nios2_frdxlo].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "nios2_frdxhi"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SF [(const_int 0)] UNSPEC_FRDXHI))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_nios2_frdxhi].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_nios2_frdxhi].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "nios2_frdy"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SF [(const_int 0)] UNSPEC_FRDY))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_nios2_frdy].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_nios2_frdy].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "minsf3"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (if_then_else:SF (lt:SF (match_operand:SF 1 "register_operand" "%r")
|
|
|
-+ (match_operand:SF 2 "register_operand" "r"))
|
|
|
-+ (match_dup 1)
|
|
|
-+ (match_dup 2)))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_minsf3].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_minsf3].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "mindf3"
|
|
|
-+ [(set (match_operand:DF 0 "register_operand" "=r")
|
|
|
-+ (if_then_else:DF (lt:DF (match_operand:DF 1 "register_operand" "%r")
|
|
|
-+ (match_operand:DF 2 "register_operand" "r"))
|
|
|
-+ (match_dup 1)
|
|
|
-+ (match_dup 2)))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_mindf3].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_mindf3].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "maxsf3"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (if_then_else:SF (lt:SF (match_operand:SF 1 "register_operand" "%r")
|
|
|
-+ (match_operand:SF 2 "register_operand" "r"))
|
|
|
-+ (match_dup 2)
|
|
|
-+ (match_dup 1)))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_maxsf3].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_maxsf3].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "maxdf3"
|
|
|
-+ [(set (match_operand:DF 0 "register_operand" "=r")
|
|
|
-+ (if_then_else:DF (lt:DF (match_operand:DF 1 "register_operand" "%r")
|
|
|
-+ (match_operand:DF 2 "register_operand" "r"))
|
|
|
-+ (match_dup 2)
|
|
|
-+ (match_dup 1)))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_maxdf3].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_maxdf3].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "abssf2"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (abs:SF (match_operand:SF 1 "register_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_abssf2].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_abssf2].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "absdf2"
|
|
|
-+ [(set (match_operand:DF 0 "register_operand" "=r")
|
|
|
-+ (abs:DF (match_operand:DF 1 "register_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_absdf2].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_absdf2].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "sqrtsf2"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (sqrt:SF (match_operand:SF 1 "register_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_sqrtsf2].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_sqrtsf2].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "sqrtdf2"
|
|
|
-+ [(set (match_operand:DF 0 "register_operand" "=r")
|
|
|
-+ (sqrt:DF (match_operand:DF 1 "register_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_sqrtdf2].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_sqrtdf2].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "cossf2"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (unspec:SF [(match_operand:SF 1 "register_operand" "r")] UNSPEC_FCOSS))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_cossf2].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_cossf2].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "cosdf2"
|
|
|
-+ [(set (match_operand:DF 0 "register_operand" "=r")
|
|
|
-+ (unspec:DF [(match_operand:DF 1 "register_operand" "r")] UNSPEC_FCOSD))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_cosdf2].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_cosdf2].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "sinsf2"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (unspec:SF [(match_operand:SF 1 "register_operand" "r")] UNSPEC_FSINS))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_sinsf2].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_sinsf2].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "sindf2"
|
|
|
-+ [(set (match_operand:DF 0 "register_operand" "=r")
|
|
|
-+ (unspec:DF [(match_operand:DF 1 "register_operand" "r")] UNSPEC_FSIND))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_sindf2].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_sindf2].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "tansf2"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (unspec:SF [(match_operand:SF 1 "register_operand" "r")] UNSPEC_FTANS))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_tansf2].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_tansf2].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "tandf2"
|
|
|
-+ [(set (match_operand:DF 0 "register_operand" "=r")
|
|
|
-+ (unspec:DF [(match_operand:DF 1 "register_operand" "r")] UNSPEC_FTAND))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_tandf2].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_tandf2].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "atansf2"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (unspec:SF [(match_operand:SF 1 "register_operand" "r")] UNSPEC_FATANS))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_atansf2].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_atansf2].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "atandf2"
|
|
|
-+ [(set (match_operand:DF 0 "register_operand" "=r")
|
|
|
-+ (unspec:DF [(match_operand:DF 1 "register_operand" "r")] UNSPEC_FATAND))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_atandf2].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_atandf2].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "expsf2"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (unspec:SF [(match_operand:SF 1 "register_operand" "r")] UNSPEC_FEXPS))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_expsf2].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_expsf2].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "expdf2"
|
|
|
-+ [(set (match_operand:DF 0 "register_operand" "=r")
|
|
|
-+ (unspec:DF [(match_operand:DF 1 "register_operand" "r")] UNSPEC_FEXPD))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_expdf2].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_expdf2].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "logsf2"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (unspec:SF [(match_operand:SF 1 "register_operand" "r")] UNSPEC_FLOGS))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_logsf2].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_logsf2].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "logdf2"
|
|
|
-+ [(set (match_operand:DF 0 "register_operand" "=r")
|
|
|
-+ (unspec:DF [(match_operand:DF 1 "register_operand" "r")] UNSPEC_FLOGD))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_logdf2].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_logdf2].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+
|
|
|
-+;*****************************************************************************
|
|
|
-+;*
|
|
|
-+;* Logical Operantions
|
|
|
-+;*
|
|
|
-+;*****************************************************************************
|
|
|
-+
|
|
|
-+(define_insn "andsi3"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r, r,r")
|
|
|
-+ (and:SI (match_operand:SI 1 "register_operand" "%r, r,r")
|
|
|
-+ (match_operand:SI 2 "logical_operand" "rM,J,K")))]
|
|
|
-+ ""
|
|
|
-+ "@
|
|
|
-+ and\\t%0, %1, %z2
|
|
|
-+ and%i2\\t%0, %1, %2
|
|
|
-+ andh%i2\\t%0, %1, %U2"
|
|
|
-+ [(set_attr "type" "alu")])
|
|
|
-+
|
|
|
-+(define_insn "iorsi3"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r, r,r")
|
|
|
-+ (ior:SI (match_operand:SI 1 "register_operand" "%r, r,r")
|
|
|
-+ (match_operand:SI 2 "logical_operand" "rM,J,K")))]
|
|
|
-+ ""
|
|
|
-+ "@
|
|
|
-+ or\\t%0, %1, %z2
|
|
|
-+ or%i2\\t%0, %1, %2
|
|
|
-+ orh%i2\\t%0, %1, %U2"
|
|
|
-+ [(set_attr "type" "alu")])
|
|
|
-+
|
|
|
-+(define_insn "*norsi3"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (and:SI (not:SI (match_operand:SI 1 "register_operand" "%r"))
|
|
|
-+ (not:SI (match_operand:SI 2 "reg_or_0_operand" "rM"))))]
|
|
|
-+ ""
|
|
|
-+ "nor\\t%0, %1, %z2"
|
|
|
-+ [(set_attr "type" "alu")])
|
|
|
-+
|
|
|
-+(define_insn "xorsi3"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r, r,r")
|
|
|
-+ (xor:SI (match_operand:SI 1 "register_operand" "%r, r,r")
|
|
|
-+ (match_operand:SI 2 "logical_operand" "rM,J,K")))]
|
|
|
-+ ""
|
|
|
-+ "@
|
|
|
-+ xor\\t%0, %1, %z2
|
|
|
-+ xor%i2\\t%0, %1, %2
|
|
|
-+ xorh%i2\\t%0, %1, %U2"
|
|
|
-+ [(set_attr "type" "alu")])
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+;*****************************************************************************
|
|
|
-+;*
|
|
|
-+;* Shifts
|
|
|
-+;*
|
|
|
-+;*****************************************************************************
|
|
|
-+
|
|
|
-+(define_insn "ashlsi3"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r,r")
|
|
|
-+ (ashift:SI (match_operand:SI 1 "register_operand" "r,r")
|
|
|
-+ (match_operand:SI 2 "shift_operand" "r,L")))]
|
|
|
-+ ""
|
|
|
-+
|
|
|
-+{
|
|
|
-+ if( GET_CODE ( operands[2] ) == CONST_INT && INTVAL( operands[2] ) == 1 )
|
|
|
-+ return "add\t%0,%1,%1";
|
|
|
-+ return "sll%i2\t%0,%1,%z2";
|
|
|
-+}
|
|
|
-+ [(set_attr "type" "shift")])
|
|
|
-+
|
|
|
-+(define_insn "ashrsi3"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r,r")
|
|
|
-+ (ashiftrt:SI (match_operand:SI 1 "register_operand" "r,r")
|
|
|
-+ (match_operand:SI 2 "shift_operand" "r,L")))]
|
|
|
-+ ""
|
|
|
-+ "sra%i2\\t%0, %1, %z2"
|
|
|
-+ [(set_attr "type" "shift")])
|
|
|
-+
|
|
|
-+(define_insn "lshrsi3"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r,r")
|
|
|
-+ (lshiftrt:SI (match_operand:SI 1 "register_operand" "r,r")
|
|
|
-+ (match_operand:SI 2 "shift_operand" "r,L")))]
|
|
|
-+ ""
|
|
|
-+ "srl%i2\\t%0, %1, %z2"
|
|
|
-+ [(set_attr "type" "shift")])
|
|
|
-+
|
|
|
-+(define_insn "rotlsi3"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r,r")
|
|
|
-+ (rotate:SI (match_operand:SI 1 "register_operand" "r,r")
|
|
|
-+ (match_operand:SI 2 "shift_operand" "r,L")))]
|
|
|
-+ ""
|
|
|
-+ "rol%i2\\t%0, %1, %z2"
|
|
|
-+ [(set_attr "type" "shift")])
|
|
|
-+
|
|
|
-+(define_insn "rotrsi3"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r,r")
|
|
|
-+ (rotatert:SI (match_operand:SI 1 "register_operand" "r,r")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r,r")))]
|
|
|
-+ ""
|
|
|
-+ "ror\\t%0, %1, %2"
|
|
|
-+ [(set_attr "type" "shift")])
|
|
|
-+
|
|
|
-+(define_insn "*shift_mul_constants"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (ashift:SI (mult:SI (match_operand:SI 1 "register_operand" "r")
|
|
|
-+ (match_operand:SI 2 "const_int_operand" "I"))
|
|
|
-+ (match_operand:SI 3 "const_int_operand" "I")))]
|
|
|
-+ "TARGET_HAS_MUL && SMALL_INT (INTVAL (operands[2]) << INTVAL (operands[3]))"
|
|
|
-+{
|
|
|
-+ HOST_WIDE_INT mul = INTVAL (operands[2]) << INTVAL (operands[3]);
|
|
|
-+ rtx ops[3];
|
|
|
-+
|
|
|
-+ ops[0] = operands[0];
|
|
|
-+ ops[1] = operands[1];
|
|
|
-+ ops[2] = GEN_INT (mul);
|
|
|
-+
|
|
|
-+ output_asm_insn ("muli\t%0, %1, %2", ops);
|
|
|
-+ return "";
|
|
|
-+}
|
|
|
-+ [(set_attr "type" "mul")])
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+;*****************************************************************************
|
|
|
-+;*
|
|
|
-+;* Converting between floating point and fixed point
|
|
|
-+;*
|
|
|
-+;*****************************************************************************
|
|
|
-+(define_insn "floatsisf2"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (float:SF (match_operand:SI 1 "register_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_floatsisf2].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_floatsisf2].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "floatsidf2"
|
|
|
-+ [(set (match_operand:DF 0 "register_operand" "=r")
|
|
|
-+ (float:DF (match_operand:SI 1 "register_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_floatsidf2].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_floatsidf2].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "floatunssisf2"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (unsigned_float:SF (match_operand:SI 1 "register_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_floatunssisf2].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_floatunssisf2].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "floatunssidf2"
|
|
|
-+ [(set (match_operand:DF 0 "register_operand" "=r")
|
|
|
-+ (unsigned_float:DF (match_operand:SI 1 "register_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_floatunssidf2].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_floatunssidf2].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "fixsfsi2"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (fix:SI (match_operand:SF 1 "general_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_fixsfsi2].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_fixsfsi2].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "fixdfsi2"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (fix:SI (match_operand:DF 1 "general_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_fixdfsi2].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_fixdfsi2].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "fixunssfsi2"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unsigned_fix:SI (match_operand:SF 1 "general_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_fixunssfsi2].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_fixunssfsi2].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "fixunsdfsi2"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unsigned_fix:SI (match_operand:DF 1 "general_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_fixunsdfsi2].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_fixunsdfsi2].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "extendsfdf2"
|
|
|
-+ [(set (match_operand:DF 0 "register_operand" "=r")
|
|
|
-+ (float_extend:DF (match_operand:SF 1 "general_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_extendsfdf2].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_extendsfdf2].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "truncdfsf2"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (float_truncate:SF (match_operand:DF 1 "general_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_truncdfsf2].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_truncdfsf2].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+;*****************************************************************************
|
|
|
-+;*
|
|
|
-+;* Prologue, Epilogue and Return
|
|
|
-+;*
|
|
|
-+;*****************************************************************************
|
|
|
-+
|
|
|
-+(define_expand "prologue"
|
|
|
-+ [(const_int 1)]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+ expand_prologue ();
|
|
|
-+ DONE;
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_expand "epilogue"
|
|
|
-+ [(return)]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+ expand_epilogue (false);
|
|
|
-+ DONE;
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_expand "sibcall_epilogue"
|
|
|
-+ [(return)]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+ expand_epilogue (true);
|
|
|
-+ DONE;
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_insn "return"
|
|
|
-+ [(return)]
|
|
|
-+ "reload_completed && nios2_can_use_return_insn ()"
|
|
|
-+ "ret\\t"
|
|
|
-+)
|
|
|
-+
|
|
|
-+(define_insn "return_from_epilogue"
|
|
|
-+ [(use (match_operand 0 "pmode_register_operand" ""))
|
|
|
-+ (return)]
|
|
|
-+ "reload_completed"
|
|
|
-+ "ret\\t"
|
|
|
-+)
|
|
|
-+
|
|
|
-+;; Block any insns from being moved before this point, since the
|
|
|
-+;; profiling call to mcount can use various registers that aren't
|
|
|
-+;; saved or used to pass arguments.
|
|
|
-+
|
|
|
-+(define_insn "blockage"
|
|
|
-+ [(unspec_volatile [(const_int 0)] UNSPEC_BLOCKAGE)]
|
|
|
-+ ""
|
|
|
-+ ""
|
|
|
-+ [(set_attr "type" "unknown")
|
|
|
-+ (set_attr "length" "0")])
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+;*****************************************************************************
|
|
|
-+;*
|
|
|
-+;* Jumps and Calls
|
|
|
-+;*
|
|
|
-+;*****************************************************************************
|
|
|
-+
|
|
|
-+(define_insn "indirect_jump"
|
|
|
-+ [(set (pc) (match_operand:SI 0 "register_operand" "r"))]
|
|
|
-+ ""
|
|
|
-+ "jmp\\t%0"
|
|
|
-+ [(set_attr "type" "control")])
|
|
|
-+
|
|
|
-+(define_insn "jump"
|
|
|
-+ [(set (pc)
|
|
|
-+ (label_ref (match_operand 0 "" "")))]
|
|
|
-+ ""
|
|
|
-+ "br\\t%0"
|
|
|
-+ [(set_attr "type" "control")])
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "indirect_call"
|
|
|
-+ [(call (mem:QI (match_operand:SI 0 "register_operand" "r"))
|
|
|
-+ (match_operand 1 "" ""))
|
|
|
-+ (clobber (reg:SI RA_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "callr\\t%0"
|
|
|
-+ [(set_attr "type" "control")])
|
|
|
-+
|
|
|
-+(define_insn "indirect_call_value"
|
|
|
-+ [(set (match_operand 0 "" "")
|
|
|
-+ (call (mem:QI (match_operand:SI 1 "register_operand" "r"))
|
|
|
-+ (match_operand 2 "" "")))
|
|
|
-+ (clobber (reg:SI RA_REGNO))]
|
|
|
-+ ""
|
|
|
-+ "callr\\t%1"
|
|
|
-+)
|
|
|
-+
|
|
|
-+(define_expand "call"
|
|
|
-+ [(parallel [(call (match_operand 0 "" "")
|
|
|
-+ (match_operand 1 "" ""))
|
|
|
-+ (clobber (reg:SI RA_REGNO))])]
|
|
|
-+ ""
|
|
|
-+ "")
|
|
|
-+
|
|
|
-+(define_expand "call_value"
|
|
|
-+ [(parallel [(set (match_operand 0 "" "")
|
|
|
-+ (call (match_operand 1 "" "")
|
|
|
-+ (match_operand 2 "" "")))
|
|
|
-+ (clobber (reg:SI RA_REGNO))])]
|
|
|
-+ ""
|
|
|
-+ "")
|
|
|
-+
|
|
|
-+(define_insn "*call"
|
|
|
-+ [(call (mem:QI (match_operand:SI 0 "immediate_operand" "i"))
|
|
|
-+ (match_operand 1 "" ""))
|
|
|
-+ (clobber (match_operand:SI 2 "register_operand" "=r"))]
|
|
|
-+ ""
|
|
|
-+ "call\\t%0"
|
|
|
-+ [(set_attr "type" "control")])
|
|
|
-+
|
|
|
-+(define_insn "*call_value"
|
|
|
-+ [(set (match_operand 0 "" "")
|
|
|
-+ (call (mem:QI (match_operand:SI 1 "immediate_operand" "i"))
|
|
|
-+ (match_operand 2 "" "")))
|
|
|
-+ (clobber (match_operand:SI 3 "register_operand" "=r"))]
|
|
|
-+ ""
|
|
|
-+ "call\\t%1"
|
|
|
-+ [(set_attr "type" "control")])
|
|
|
-+
|
|
|
-+(define_expand "sibcall"
|
|
|
-+ [(parallel [(call (match_operand 0 "" "")
|
|
|
-+ (match_operand 1 "" ""))
|
|
|
-+ (return)
|
|
|
-+ (use (match_operand 2 "" ""))])]
|
|
|
-+ ""
|
|
|
-+ {
|
|
|
-+ XEXP (operands[0], 0) = copy_to_mode_reg (SImode, XEXP (operands[0], 0));
|
|
|
-+
|
|
|
-+ if (operands[2] == NULL_RTX)
|
|
|
-+ operands[2] = const0_rtx;
|
|
|
-+ }
|
|
|
-+)
|
|
|
-+
|
|
|
-+(define_expand "sibcall_value"
|
|
|
-+ [(parallel [(set (match_operand 0 "" "")
|
|
|
-+ (call (match_operand 1 "" "")
|
|
|
-+ (match_operand 2 "" "")))
|
|
|
-+ (return)
|
|
|
-+ (use (match_operand 3 "" ""))])]
|
|
|
-+ ""
|
|
|
-+ {
|
|
|
-+ XEXP (operands[1], 0) = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
|
|
|
-+
|
|
|
-+ if (operands[3] == NULL_RTX)
|
|
|
-+ operands[3] = const0_rtx;
|
|
|
-+ }
|
|
|
-+)
|
|
|
-+
|
|
|
-+(define_insn "sibcall_insn"
|
|
|
-+ [(call (mem:QI (match_operand:SI 0 "register_operand" "D08"))
|
|
|
-+ (match_operand 1 "" ""))
|
|
|
-+ (return)
|
|
|
-+ (use (match_operand 2 "" ""))]
|
|
|
-+ ""
|
|
|
-+ "jmp\\t%0"
|
|
|
-+)
|
|
|
-+
|
|
|
-+(define_insn "sibcall_value_insn"
|
|
|
-+ [(set (match_operand 0 "register_operand" "")
|
|
|
-+ (call (mem:QI (match_operand:SI 1 "register_operand" "D08"))
|
|
|
-+ (match_operand 2 "" "")))
|
|
|
-+ (return)
|
|
|
-+ (use (match_operand 3 "" ""))]
|
|
|
-+ ""
|
|
|
-+ "jmp\\t%1"
|
|
|
-+)
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_expand "tablejump"
|
|
|
-+ [(parallel [(set (pc) (match_operand 0 "register_operand" "r"))
|
|
|
-+ (use (label_ref (match_operand 1 "" "")))])]
|
|
|
-+ ""
|
|
|
-+ ""
|
|
|
-+)
|
|
|
-+
|
|
|
-+(define_insn "*tablejump"
|
|
|
-+ [(set (pc)
|
|
|
-+ (match_operand:SI 0 "register_operand" "r"))
|
|
|
-+ (use (label_ref (match_operand 1 "" "")))]
|
|
|
-+ ""
|
|
|
-+ "jmp\\t%0"
|
|
|
-+ [(set_attr "type" "control")])
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+;*****************************************************************************
|
|
|
-+;*
|
|
|
-+;* Comparisons
|
|
|
-+;*
|
|
|
-+;*****************************************************************************
|
|
|
-+;; Flow here is rather complex (based on MIPS):
|
|
|
-+;;
|
|
|
-+;; 1) The cmp{si,di,sf,df} routine is called. It deposits the
|
|
|
-+;; arguments into the branch_cmp array, and the type into
|
|
|
-+;; branch_type. No RTL is generated.
|
|
|
-+;;
|
|
|
-+;; 2) The appropriate branch define_expand is called, which then
|
|
|
-+;; creates the appropriate RTL for the comparison and branch.
|
|
|
-+;; Different CC modes are used, based on what type of branch is
|
|
|
-+;; done, so that we can constrain things appropriately. There
|
|
|
-+;; are assumptions in the rest of GCC that break if we fold the
|
|
|
-+;; operands into the branchs for integer operations, and use cc0
|
|
|
-+;; for floating point, so we use the fp status register instead.
|
|
|
-+;; If needed, an appropriate temporary is created to hold the
|
|
|
-+;; of the integer compare.
|
|
|
-+
|
|
|
-+(define_expand "cmpsi"
|
|
|
-+ [(set (cc0)
|
|
|
-+ (compare:CC (match_operand:SI 0 "register_operand" "")
|
|
|
-+ (match_operand:SI 1 "arith_operand" "")))]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+ branch_cmp[0] = operands[0];
|
|
|
-+ branch_cmp[1] = operands[1];
|
|
|
-+ branch_type = CMP_SI;
|
|
|
-+ DONE;
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_expand "tstsi"
|
|
|
-+ [(set (cc0)
|
|
|
-+ (match_operand:SI 0 "register_operand" ""))]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+ branch_cmp[0] = operands[0];
|
|
|
-+ branch_cmp[1] = const0_rtx;
|
|
|
-+ branch_type = CMP_SI;
|
|
|
-+ DONE;
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_expand "cmpsf"
|
|
|
-+ [(set (cc0)
|
|
|
-+ (compare:CC (match_operand:SF 0 "register_operand" "")
|
|
|
-+ (match_operand:SF 1 "register_operand" "")))]
|
|
|
-+ "(nios2_fpu_insns[nios2_fpu_nios2_sltsf].N >= 0
|
|
|
-+ || nios2_fpu_insns[nios2_fpu_nios2_sgtsf].N >= 0)
|
|
|
-+ && (nios2_fpu_insns[nios2_fpu_nios2_sgesf].N >= 0
|
|
|
-+ || nios2_fpu_insns[nios2_fpu_nios2_slesf].N >= 0)
|
|
|
-+ && nios2_fpu_insns[nios2_fpu_nios2_seqsf].N >= 0
|
|
|
-+ && nios2_fpu_insns[nios2_fpu_nios2_snesf].N >= 0"
|
|
|
-+{
|
|
|
-+ branch_cmp[0] = operands[0];
|
|
|
-+ branch_cmp[1] = operands[1];
|
|
|
-+ branch_type = CMP_SF;
|
|
|
-+ DONE;
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_expand "cmpdf"
|
|
|
-+ [(set (cc0)
|
|
|
-+ (compare:CC (match_operand:DF 0 "register_operand" "")
|
|
|
-+ (match_operand:DF 1 "register_operand" "")))]
|
|
|
-+ "(nios2_fpu_insns[nios2_fpu_nios2_sltdf].N >= 0
|
|
|
-+ || nios2_fpu_insns[nios2_fpu_nios2_sgtdf].N >= 0)
|
|
|
-+ && (nios2_fpu_insns[nios2_fpu_nios2_sgedf].N >= 0
|
|
|
-+ || nios2_fpu_insns[nios2_fpu_nios2_sledf].N >= 0)
|
|
|
-+ && nios2_fpu_insns[nios2_fpu_nios2_seqdf].N >= 0
|
|
|
-+ && nios2_fpu_insns[nios2_fpu_nios2_snedf].N >= 0"
|
|
|
-+{
|
|
|
-+ branch_cmp[0] = operands[0];
|
|
|
-+ branch_cmp[1] = operands[1];
|
|
|
-+ branch_type = CMP_DF;
|
|
|
-+ DONE;
|
|
|
-+})
|
|
|
-+
|
|
|
-+
|
|
|
-+;*****************************************************************************
|
|
|
-+;*
|
|
|
-+;* setting a register from a comparison
|
|
|
-+;*
|
|
|
-+;*****************************************************************************
|
|
|
-+
|
|
|
-+(define_expand "seq"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (eq:SI (match_dup 1)
|
|
|
-+ (match_dup 2)))]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+ if (branch_type != CMP_SI && branch_type != CMP_SF && branch_type != CMP_DF)
|
|
|
-+ FAIL;
|
|
|
-+
|
|
|
-+ /* set up operands from compare. */
|
|
|
-+ operands[1] = branch_cmp[0];
|
|
|
-+ operands[2] = branch_cmp[1];
|
|
|
-+
|
|
|
-+ gen_int_relational (EQ, operands[0], operands[1], operands[2], NULL_RTX);
|
|
|
-+ DONE;
|
|
|
-+})
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "*seq"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (eq:SI (match_operand:SI 1 "reg_or_0_operand" "%rM")
|
|
|
-+ (match_operand:SI 2 "arith_operand" "rI")))]
|
|
|
-+ ""
|
|
|
-+ "cmpeq%i2\\t%0, %z1, %z2"
|
|
|
-+ [(set_attr "type" "alu")])
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "nios2_seqsf"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (eq:SI (match_operand:SF 1 "register_operand" "%r")
|
|
|
-+ (match_operand:SF 2 "register_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_nios2_seqsf].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_nios2_seqsf].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "nios2_seqdf"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (eq:SI (match_operand:DF 1 "register_operand" "%r")
|
|
|
-+ (match_operand:DF 2 "register_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_nios2_seqdf].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_nios2_seqdf].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_expand "sne"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (ne:SI (match_dup 1)
|
|
|
-+ (match_dup 2)))]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+ if (branch_type != CMP_SI && branch_type != CMP_SF && branch_type != CMP_DF)
|
|
|
-+ FAIL;
|
|
|
-+
|
|
|
-+ /* set up operands from compare. */
|
|
|
-+ operands[1] = branch_cmp[0];
|
|
|
-+ operands[2] = branch_cmp[1];
|
|
|
-+
|
|
|
-+ gen_int_relational (NE, operands[0], operands[1], operands[2], NULL_RTX);
|
|
|
-+ DONE;
|
|
|
-+})
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "*sne"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (ne:SI (match_operand:SI 1 "reg_or_0_operand" "%rM")
|
|
|
-+ (match_operand:SI 2 "arith_operand" "rI")))]
|
|
|
-+ ""
|
|
|
-+ "cmpne%i2\\t%0, %z1, %z2"
|
|
|
-+ [(set_attr "type" "alu")])
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "nios2_snesf"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (ne:SI (match_operand:SF 1 "register_operand" "%r")
|
|
|
-+ (match_operand:SF 2 "register_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_nios2_snesf].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_nios2_snesf].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "nios2_snedf"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (ne:SI (match_operand:DF 1 "register_operand" "%r")
|
|
|
-+ (match_operand:DF 2 "register_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_nios2_snedf].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_nios2_snedf].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_expand "sgt"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (gt:SI (match_dup 1)
|
|
|
-+ (match_dup 2)))]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+ if (branch_type != CMP_SI && branch_type != CMP_SF && branch_type != CMP_DF)
|
|
|
-+ FAIL;
|
|
|
-+
|
|
|
-+ /* set up operands from compare. */
|
|
|
-+ operands[1] = branch_cmp[0];
|
|
|
-+ operands[2] = branch_cmp[1];
|
|
|
-+
|
|
|
-+ gen_int_relational (GT, operands[0], operands[1], operands[2], NULL_RTX);
|
|
|
-+ DONE;
|
|
|
-+})
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "*sgt"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (gt:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
|
|
|
-+ (match_operand:SI 2 "reg_or_0_operand" "rM")))]
|
|
|
-+ ""
|
|
|
-+ "cmplt\\t%0, %z2, %z1"
|
|
|
-+ [(set_attr "type" "alu")])
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "nios2_sgtsf"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (gt:SI (match_operand:SF 1 "register_operand" "r")
|
|
|
-+ (match_operand:SF 2 "register_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_nios2_sgtsf].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_nios2_sgtsf].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "nios2_sgtdf"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (gt:SI (match_operand:DF 1 "register_operand" "r")
|
|
|
-+ (match_operand:DF 2 "register_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_nios2_sgtdf].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_nios2_sgtdf].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_expand "sge"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (ge:SI (match_dup 1)
|
|
|
-+ (match_dup 2)))]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+ if (branch_type != CMP_SI && branch_type != CMP_SF && branch_type != CMP_DF)
|
|
|
-+ FAIL;
|
|
|
-+
|
|
|
-+ /* set up operands from compare. */
|
|
|
-+ operands[1] = branch_cmp[0];
|
|
|
-+ operands[2] = branch_cmp[1];
|
|
|
-+
|
|
|
-+ gen_int_relational (GE, operands[0], operands[1], operands[2], NULL_RTX);
|
|
|
-+ DONE;
|
|
|
-+})
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "*sge"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (ge:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
|
|
|
-+ (match_operand:SI 2 "arith_operand" "rI")))]
|
|
|
-+ ""
|
|
|
-+ "cmpge%i2\\t%0, %z1, %z2"
|
|
|
-+ [(set_attr "type" "alu")])
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "nios2_sgesf"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (ge:SI (match_operand:SF 1 "register_operand" "r")
|
|
|
-+ (match_operand:SF 2 "register_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_nios2_sgesf].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_nios2_sgesf].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "nios2_sgedf"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (ge:SI (match_operand:DF 1 "register_operand" "r")
|
|
|
-+ (match_operand:DF 2 "register_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_nios2_sgedf].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_nios2_sgedf].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_expand "sle"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (le:SI (match_dup 1)
|
|
|
-+ (match_dup 2)))]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+ if (branch_type != CMP_SI && branch_type != CMP_SF && branch_type != CMP_DF)
|
|
|
-+ FAIL;
|
|
|
-+
|
|
|
-+ /* set up operands from compare. */
|
|
|
-+ operands[1] = branch_cmp[0];
|
|
|
-+ operands[2] = branch_cmp[1];
|
|
|
-+
|
|
|
-+ gen_int_relational (LE, operands[0], operands[1], operands[2], NULL_RTX);
|
|
|
-+ DONE;
|
|
|
-+})
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "*sle"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (le:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
|
|
|
-+ (match_operand:SI 2 "reg_or_0_operand" "rM")))]
|
|
|
-+ ""
|
|
|
-+ "cmpge\\t%0, %z2, %z1"
|
|
|
-+ [(set_attr "type" "alu")])
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "nios2_slesf"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (le:SI (match_operand:SF 1 "register_operand" "r")
|
|
|
-+ (match_operand:SF 2 "register_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_nios2_slesf].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_nios2_slesf].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "nios2_sledf"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (le:SI (match_operand:DF 1 "register_operand" "r")
|
|
|
-+ (match_operand:DF 2 "register_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_nios2_sledf].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_nios2_sledf].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_expand "slt"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (lt:SI (match_dup 1)
|
|
|
-+ (match_dup 2)))]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+ if (branch_type != CMP_SI && branch_type != CMP_SF && branch_type != CMP_DF)
|
|
|
-+ FAIL;
|
|
|
-+
|
|
|
-+ /* set up operands from compare. */
|
|
|
-+ operands[1] = branch_cmp[0];
|
|
|
-+ operands[2] = branch_cmp[1];
|
|
|
-+
|
|
|
-+ gen_int_relational (LT, operands[0], operands[1], operands[2], NULL_RTX);
|
|
|
-+ DONE;
|
|
|
-+})
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "*slt"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (lt:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
|
|
|
-+ (match_operand:SI 2 "arith_operand" "rI")))]
|
|
|
-+ ""
|
|
|
-+ "cmplt%i2\\t%0, %z1, %z2"
|
|
|
-+ [(set_attr "type" "alu")])
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "nios2_sltsf"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (lt:SI (match_operand:SF 1 "register_operand" "r")
|
|
|
-+ (match_operand:SF 2 "register_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_nios2_sltsf].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_nios2_sltsf].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "nios2_sltdf"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (lt:SI (match_operand:DF 1 "register_operand" "r")
|
|
|
-+ (match_operand:DF 2 "register_operand" "r")))]
|
|
|
-+ "nios2_fpu_insns[nios2_fpu_nios2_sltdf].N >= 0"
|
|
|
-+ {
|
|
|
-+ return (*nios2_fpu_insns[nios2_fpu_nios2_sltdf].output) (insn);
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_expand "sgtu"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (gtu:SI (match_dup 1)
|
|
|
-+ (match_dup 2)))]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+ if (branch_type != CMP_SI)
|
|
|
-+ FAIL;
|
|
|
-+
|
|
|
-+ /* set up operands from compare. */
|
|
|
-+ operands[1] = branch_cmp[0];
|
|
|
-+ operands[2] = branch_cmp[1];
|
|
|
-+
|
|
|
-+ gen_int_relational (GTU, operands[0], operands[1], operands[2], NULL_RTX);
|
|
|
-+ DONE;
|
|
|
-+})
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "*sgtu"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (gtu:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
|
|
|
-+ (match_operand:SI 2 "reg_or_0_operand" "rM")))]
|
|
|
-+ ""
|
|
|
-+ "cmpltu\\t%0, %z2, %z1"
|
|
|
-+ [(set_attr "type" "alu")])
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_expand "sgeu"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (geu:SI (match_dup 1)
|
|
|
-+ (match_dup 2)))]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+ if (branch_type != CMP_SI)
|
|
|
-+ FAIL;
|
|
|
-+
|
|
|
-+ /* set up operands from compare. */
|
|
|
-+ operands[1] = branch_cmp[0];
|
|
|
-+ operands[2] = branch_cmp[1];
|
|
|
-+
|
|
|
-+ gen_int_relational (GEU, operands[0], operands[1], operands[2], NULL_RTX);
|
|
|
-+ DONE;
|
|
|
-+})
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "*sgeu"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (geu:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
|
|
|
-+ (match_operand:SI 2 "uns_arith_operand" "rJ")))]
|
|
|
-+ ""
|
|
|
-+ "cmpgeu%i2\\t%0, %z1, %z2"
|
|
|
-+ [(set_attr "type" "alu")])
|
|
|
-+
|
|
|
-+(define_expand "sleu"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (leu:SI (match_dup 1)
|
|
|
-+ (match_dup 2)))]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+ if (branch_type != CMP_SI)
|
|
|
-+ FAIL;
|
|
|
-+
|
|
|
-+ /* set up operands from compare. */
|
|
|
-+ operands[1] = branch_cmp[0];
|
|
|
-+ operands[2] = branch_cmp[1];
|
|
|
-+
|
|
|
-+ gen_int_relational (LEU, operands[0], operands[1], operands[2], NULL_RTX);
|
|
|
-+ DONE;
|
|
|
-+})
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "*sleu"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (leu:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
|
|
|
-+ (match_operand:SI 2 "reg_or_0_operand" "rM")))]
|
|
|
-+ ""
|
|
|
-+ "cmpgeu\\t%0, %z2, %z1"
|
|
|
-+ [(set_attr "type" "alu")])
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_expand "sltu"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (ltu:SI (match_dup 1)
|
|
|
-+ (match_dup 2)))]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+ if (branch_type != CMP_SI)
|
|
|
-+ FAIL;
|
|
|
-+
|
|
|
-+ /* set up operands from compare. */
|
|
|
-+ operands[1] = branch_cmp[0];
|
|
|
-+ operands[2] = branch_cmp[1];
|
|
|
-+
|
|
|
-+ gen_int_relational (LTU, operands[0], operands[1], operands[2], NULL_RTX);
|
|
|
-+ DONE;
|
|
|
-+})
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "*sltu"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (ltu:SI (match_operand:SI 1 "reg_or_0_operand" "rM")
|
|
|
-+ (match_operand:SI 2 "uns_arith_operand" "rJ")))]
|
|
|
-+ ""
|
|
|
-+ "cmpltu%i2\\t%0, %z1, %z2"
|
|
|
-+ [(set_attr "type" "alu")])
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+;*****************************************************************************
|
|
|
-+;*
|
|
|
-+;* branches
|
|
|
-+;*
|
|
|
-+;*****************************************************************************
|
|
|
-+
|
|
|
-+(define_insn "*cbranch"
|
|
|
-+ [(set (pc)
|
|
|
-+ (if_then_else
|
|
|
-+ (match_operator:SI 0 "comparison_operator"
|
|
|
-+ [(match_operand:SI 2 "reg_or_0_operand" "rM")
|
|
|
-+ (match_operand:SI 3 "reg_or_0_operand" "rM")])
|
|
|
-+ (label_ref (match_operand 1 "" ""))
|
|
|
-+ (pc)))]
|
|
|
-+ ""
|
|
|
-+ "b%0\\t%z2, %z3, %l1"
|
|
|
-+ [(set_attr "type" "control")])
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "nios2_cbranch_sf"
|
|
|
-+ [(set (pc)
|
|
|
-+ (if_then_else
|
|
|
-+ (match_operator:SI 0 "comparison_operator"
|
|
|
-+ [(match_operand:SF 2 "register_operand" "r")
|
|
|
-+ (match_operand:SF 3 "register_operand" "r")])
|
|
|
-+ (label_ref (match_operand 1 "" ""))
|
|
|
-+ (pc)))]
|
|
|
-+ ""
|
|
|
-+ {
|
|
|
-+ return nios2_output_fpu_insn_cmps (insn, GET_CODE (operands[0]));
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "nios2_cbranch_df"
|
|
|
-+ [(set (pc)
|
|
|
-+ (if_then_else
|
|
|
-+ (match_operator:SI 0 "comparison_operator"
|
|
|
-+ [(match_operand:DF 2 "register_operand" "r")
|
|
|
-+ (match_operand:DF 3 "register_operand" "r")])
|
|
|
-+ (label_ref (match_operand 1 "" ""))
|
|
|
-+ (pc)))]
|
|
|
-+ ""
|
|
|
-+ {
|
|
|
-+ return nios2_output_fpu_insn_cmpd (insn, GET_CODE (operands[0]));
|
|
|
-+ }
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_expand "beq"
|
|
|
-+ [(set (pc)
|
|
|
-+ (if_then_else (eq:CC (cc0)
|
|
|
-+ (const_int 0))
|
|
|
-+ (label_ref (match_operand 0 "" ""))
|
|
|
-+ (pc)))]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+ gen_int_relational (EQ, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]);
|
|
|
-+ DONE;
|
|
|
-+})
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_expand "bne"
|
|
|
-+ [(set (pc)
|
|
|
-+ (if_then_else (ne:CC (cc0)
|
|
|
-+ (const_int 0))
|
|
|
-+ (label_ref (match_operand 0 "" ""))
|
|
|
-+ (pc)))]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+ gen_int_relational (NE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]);
|
|
|
-+ DONE;
|
|
|
-+})
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_expand "bgt"
|
|
|
-+ [(set (pc)
|
|
|
-+ (if_then_else (gt:CC (cc0)
|
|
|
-+ (const_int 0))
|
|
|
-+ (label_ref (match_operand 0 "" ""))
|
|
|
-+ (pc)))]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+ gen_int_relational (GT, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]);
|
|
|
-+ DONE;
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_expand "bge"
|
|
|
-+ [(set (pc)
|
|
|
-+ (if_then_else (ge:CC (cc0)
|
|
|
-+ (const_int 0))
|
|
|
-+ (label_ref (match_operand 0 "" ""))
|
|
|
-+ (pc)))]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+ gen_int_relational (GE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]);
|
|
|
-+ DONE;
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_expand "ble"
|
|
|
-+ [(set (pc)
|
|
|
-+ (if_then_else (le:CC (cc0)
|
|
|
-+ (const_int 0))
|
|
|
-+ (label_ref (match_operand 0 "" ""))
|
|
|
-+ (pc)))]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+ gen_int_relational (LE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]);
|
|
|
-+ DONE;
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_expand "blt"
|
|
|
-+ [(set (pc)
|
|
|
-+ (if_then_else (lt:CC (cc0)
|
|
|
-+ (const_int 0))
|
|
|
-+ (label_ref (match_operand 0 "" ""))
|
|
|
-+ (pc)))]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+ gen_int_relational (LT, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]);
|
|
|
-+ DONE;
|
|
|
-+})
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_expand "bgtu"
|
|
|
-+ [(set (pc)
|
|
|
-+ (if_then_else (gtu:CC (cc0)
|
|
|
-+ (const_int 0))
|
|
|
-+ (label_ref (match_operand 0 "" ""))
|
|
|
-+ (pc)))]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+ gen_int_relational (GTU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]);
|
|
|
-+ DONE;
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_expand "bgeu"
|
|
|
-+ [(set (pc)
|
|
|
-+ (if_then_else (geu:CC (cc0)
|
|
|
-+ (const_int 0))
|
|
|
-+ (label_ref (match_operand 0 "" ""))
|
|
|
-+ (pc)))]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+ gen_int_relational (GEU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]);
|
|
|
-+ DONE;
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_expand "bleu"
|
|
|
-+ [(set (pc)
|
|
|
-+ (if_then_else (leu:CC (cc0)
|
|
|
-+ (const_int 0))
|
|
|
-+ (label_ref (match_operand 0 "" ""))
|
|
|
-+ (pc)))]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+ gen_int_relational (LEU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]);
|
|
|
-+ DONE;
|
|
|
-+})
|
|
|
-+
|
|
|
-+(define_expand "bltu"
|
|
|
-+ [(set (pc)
|
|
|
-+ (if_then_else (ltu:CC (cc0)
|
|
|
-+ (const_int 0))
|
|
|
-+ (label_ref (match_operand 0 "" ""))
|
|
|
-+ (pc)))]
|
|
|
-+ ""
|
|
|
-+{
|
|
|
-+ gen_int_relational (LTU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]);
|
|
|
-+ DONE;
|
|
|
-+})
|
|
|
-+
|
|
|
-+
|
|
|
-+;*****************************************************************************
|
|
|
-+;*
|
|
|
-+;* String and Block Operations
|
|
|
-+;*
|
|
|
-+;*****************************************************************************
|
|
|
-+
|
|
|
-+; ??? This is all really a hack to get Dhrystone to work as fast as possible
|
|
|
-+; things to be fixed:
|
|
|
-+; * let the compiler core handle all of this, for that to work the extra
|
|
|
-+; aliasing needs to be addressed.
|
|
|
-+; * we use three temporary registers for loading and storing to ensure no
|
|
|
-+; ld use stalls, this is excessive, because after the first ld/st only
|
|
|
-+; two are needed. Only two would be needed all the way through if
|
|
|
-+; we could schedule with other code. Consider:
|
|
|
-+; 1 ld $1, 0($src)
|
|
|
-+; 2 ld $2, 4($src)
|
|
|
-+; 3 ld $3, 8($src)
|
|
|
-+; 4 st $1, 0($dest)
|
|
|
-+; 5 ld $1, 12($src)
|
|
|
-+; 6 st $2, 4($src)
|
|
|
-+; 7 etc.
|
|
|
-+; The first store has to wait until 4. If it does not there will be one
|
|
|
-+; cycle of stalling. However, if any other instruction could be placed
|
|
|
-+; between 1 and 4, $3 would not be needed.
|
|
|
-+; * In small we probably don't want to ever do this ourself because there
|
|
|
-+; is no ld use stall.
|
|
|
-+
|
|
|
-+(define_expand "movstrsi"
|
|
|
-+ [(parallel [(set (match_operand:BLK 0 "general_operand" "")
|
|
|
-+ (match_operand:BLK 1 "general_operand" ""))
|
|
|
-+ (use (match_operand:SI 2 "const_int_operand" ""))
|
|
|
-+ (use (match_operand:SI 3 "const_int_operand" ""))
|
|
|
-+ (clobber (match_scratch:SI 4 "=&r"))
|
|
|
-+ (clobber (match_scratch:SI 5 "=&r"))
|
|
|
-+ (clobber (match_scratch:SI 6 "=&r"))])]
|
|
|
-+ "TARGET_INLINE_MEMCPY"
|
|
|
-+{
|
|
|
-+ rtx ld_addr_reg, st_addr_reg;
|
|
|
-+
|
|
|
-+ /* If the predicate for op2 fails in expr.c:emit_block_move_via_movstr
|
|
|
-+ it trys to copy to a register, but does not re-try the predicate.
|
|
|
-+ ??? Intead of fixing expr.c, I fix it here. */
|
|
|
-+ if (!const_int_operand (operands[2], SImode))
|
|
|
-+ FAIL;
|
|
|
-+
|
|
|
-+ /* ??? there are some magic numbers which need to be sorted out here.
|
|
|
-+ the basis for them is not increasing code size hugely or going
|
|
|
-+ out of range of offset addressing */
|
|
|
-+ if (INTVAL (operands[3]) < 4)
|
|
|
-+ FAIL;
|
|
|
-+ if (!optimize
|
|
|
-+ || (optimize_size && INTVAL (operands[2]) > 12)
|
|
|
-+ || (optimize < 3 && INTVAL (operands[2]) > 100)
|
|
|
-+ || INTVAL (operands[2]) > 200)
|
|
|
-+ FAIL;
|
|
|
-+
|
|
|
-+ st_addr_reg
|
|
|
-+ = replace_equiv_address (operands[0],
|
|
|
-+ copy_to_mode_reg (Pmode, XEXP (operands[0], 0)));
|
|
|
-+ ld_addr_reg
|
|
|
-+ = replace_equiv_address (operands[1],
|
|
|
-+ copy_to_mode_reg (Pmode, XEXP (operands[1], 0)));
|
|
|
-+ emit_insn (gen_movstrsi_internal (st_addr_reg, ld_addr_reg,
|
|
|
-+ operands[2], operands[3]));
|
|
|
-+
|
|
|
-+ DONE;
|
|
|
-+})
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "movstrsi_internal"
|
|
|
-+ [(set (match_operand:BLK 0 "memory_operand" "=o")
|
|
|
-+ (match_operand:BLK 1 "memory_operand" "o"))
|
|
|
-+ (use (match_operand:SI 2 "const_int_operand" "i"))
|
|
|
-+ (use (match_operand:SI 3 "const_int_operand" "i"))
|
|
|
-+ (clobber (match_scratch:SI 4 "=&r"))
|
|
|
-+ (clobber (match_scratch:SI 5 "=&r"))
|
|
|
-+ (clobber (match_scratch:SI 6 "=&r"))]
|
|
|
-+ "TARGET_INLINE_MEMCPY"
|
|
|
-+{
|
|
|
-+ int ld_offset = INTVAL (operands[2]);
|
|
|
-+ int ld_len = INTVAL (operands[2]);
|
|
|
-+ int ld_reg = 0;
|
|
|
-+ rtx ld_addr_reg = XEXP (operands[1], 0);
|
|
|
-+ int st_offset = INTVAL (operands[2]);
|
|
|
-+ int st_len = INTVAL (operands[2]);
|
|
|
-+ int st_reg = 0;
|
|
|
-+ rtx st_addr_reg = XEXP (operands[0], 0);
|
|
|
-+ int delay_count = 0;
|
|
|
-+
|
|
|
-+ /* ops[0] is the address used by the insn
|
|
|
-+ ops[1] is the register being loaded or stored */
|
|
|
-+ rtx ops[2];
|
|
|
-+
|
|
|
-+ if (INTVAL (operands[3]) < 4)
|
|
|
-+ abort ();
|
|
|
-+
|
|
|
-+ while (ld_offset >= 4)
|
|
|
-+ {
|
|
|
-+ /* if the load use delay has been met, I can start
|
|
|
-+ storing */
|
|
|
-+ if (delay_count >= 3)
|
|
|
-+ {
|
|
|
-+ ops[0] = gen_rtx (MEM, SImode,
|
|
|
-+ plus_constant (st_addr_reg, st_len - st_offset));
|
|
|
-+ ops[1] = operands[st_reg + 4];
|
|
|
-+ output_asm_insn ("stw\t%1, %0", ops);
|
|
|
-+
|
|
|
-+ st_reg = (st_reg + 1) % 3;
|
|
|
-+ st_offset -= 4;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ ops[0] = gen_rtx (MEM, SImode,
|
|
|
-+ plus_constant (ld_addr_reg, ld_len - ld_offset));
|
|
|
-+ ops[1] = operands[ld_reg + 4];
|
|
|
-+ output_asm_insn ("ldw\t%1, %0", ops);
|
|
|
-+
|
|
|
-+ ld_reg = (ld_reg + 1) % 3;
|
|
|
-+ ld_offset -= 4;
|
|
|
-+ delay_count++;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (ld_offset >= 2)
|
|
|
-+ {
|
|
|
-+ /* if the load use delay has been met, I can start
|
|
|
-+ storing */
|
|
|
-+ if (delay_count >= 3)
|
|
|
-+ {
|
|
|
-+ ops[0] = gen_rtx (MEM, SImode,
|
|
|
-+ plus_constant (st_addr_reg, st_len - st_offset));
|
|
|
-+ ops[1] = operands[st_reg + 4];
|
|
|
-+ output_asm_insn ("stw\t%1, %0", ops);
|
|
|
-+
|
|
|
-+ st_reg = (st_reg + 1) % 3;
|
|
|
-+ st_offset -= 4;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ ops[0] = gen_rtx (MEM, HImode,
|
|
|
-+ plus_constant (ld_addr_reg, ld_len - ld_offset));
|
|
|
-+ ops[1] = operands[ld_reg + 4];
|
|
|
-+ output_asm_insn ("ldh\t%1, %0", ops);
|
|
|
-+
|
|
|
-+ ld_reg = (ld_reg + 1) % 3;
|
|
|
-+ ld_offset -= 2;
|
|
|
-+ delay_count++;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ if (ld_offset >= 1)
|
|
|
-+ {
|
|
|
-+ /* if the load use delay has been met, I can start
|
|
|
-+ storing */
|
|
|
-+ if (delay_count >= 3)
|
|
|
-+ {
|
|
|
-+ ops[0] = gen_rtx (MEM, SImode,
|
|
|
-+ plus_constant (st_addr_reg, st_len - st_offset));
|
|
|
-+ ops[1] = operands[st_reg + 4];
|
|
|
-+ output_asm_insn ("stw\t%1, %0", ops);
|
|
|
-+
|
|
|
-+ st_reg = (st_reg + 1) % 3;
|
|
|
-+ st_offset -= 4;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ ops[0] = gen_rtx (MEM, QImode,
|
|
|
-+ plus_constant (ld_addr_reg, ld_len - ld_offset));
|
|
|
-+ ops[1] = operands[ld_reg + 4];
|
|
|
-+ output_asm_insn ("ldb\t%1, %0", ops);
|
|
|
-+
|
|
|
-+ ld_reg = (ld_reg + 1) % 3;
|
|
|
-+ ld_offset -= 1;
|
|
|
-+ delay_count++;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ while (st_offset >= 4)
|
|
|
-+ {
|
|
|
-+ ops[0] = gen_rtx (MEM, SImode,
|
|
|
-+ plus_constant (st_addr_reg, st_len - st_offset));
|
|
|
-+ ops[1] = operands[st_reg + 4];
|
|
|
-+ output_asm_insn ("stw\t%1, %0", ops);
|
|
|
-+
|
|
|
-+ st_reg = (st_reg + 1) % 3;
|
|
|
-+ st_offset -= 4;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ while (st_offset >= 2)
|
|
|
-+ {
|
|
|
-+ ops[0] = gen_rtx (MEM, HImode,
|
|
|
-+ plus_constant (st_addr_reg, st_len - st_offset));
|
|
|
-+ ops[1] = operands[st_reg + 4];
|
|
|
-+ output_asm_insn ("sth\t%1, %0", ops);
|
|
|
-+
|
|
|
-+ st_reg = (st_reg + 1) % 3;
|
|
|
-+ st_offset -= 2;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ while (st_offset >= 1)
|
|
|
-+ {
|
|
|
-+ ops[0] = gen_rtx (MEM, QImode,
|
|
|
-+ plus_constant (st_addr_reg, st_len - st_offset));
|
|
|
-+ ops[1] = operands[st_reg + 4];
|
|
|
-+ output_asm_insn ("stb\t%1, %0", ops);
|
|
|
-+
|
|
|
-+ st_reg = (st_reg + 1) % 3;
|
|
|
-+ st_offset -= 1;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ return "";
|
|
|
-+}
|
|
|
-+; ??? lengths are not being used yet, but I will probably forget
|
|
|
-+; to update this once I am using lengths, so set it to something
|
|
|
-+; definetely big enough to cover it. 400 allows for 200 bytes
|
|
|
-+; of motion.
|
|
|
-+ [(set_attr "length" "400")])
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+;*****************************************************************************
|
|
|
-+;*
|
|
|
-+;* Custom instructions
|
|
|
-+;*
|
|
|
-+;*****************************************************************************
|
|
|
-+
|
|
|
-+(define_constants [
|
|
|
-+ (CUSTOM_N 100)
|
|
|
-+ (CUSTOM_NI 101)
|
|
|
-+ (CUSTOM_NF 102)
|
|
|
-+ (CUSTOM_NP 103)
|
|
|
-+ (CUSTOM_NII 104)
|
|
|
-+ (CUSTOM_NIF 105)
|
|
|
-+ (CUSTOM_NIP 106)
|
|
|
-+ (CUSTOM_NFI 107)
|
|
|
-+ (CUSTOM_NFF 108)
|
|
|
-+ (CUSTOM_NFP 109)
|
|
|
-+ (CUSTOM_NPI 110)
|
|
|
-+ (CUSTOM_NPF 111)
|
|
|
-+ (CUSTOM_NPP 112)
|
|
|
-+ (CUSTOM_IN 113)
|
|
|
-+ (CUSTOM_INI 114)
|
|
|
-+ (CUSTOM_INF 115)
|
|
|
-+ (CUSTOM_INP 116)
|
|
|
-+ (CUSTOM_INII 117)
|
|
|
-+ (CUSTOM_INIF 118)
|
|
|
-+ (CUSTOM_INIP 119)
|
|
|
-+ (CUSTOM_INFI 120)
|
|
|
-+ (CUSTOM_INFF 121)
|
|
|
-+ (CUSTOM_INFP 122)
|
|
|
-+ (CUSTOM_INPI 123)
|
|
|
-+ (CUSTOM_INPF 124)
|
|
|
-+ (CUSTOM_INPP 125)
|
|
|
-+ (CUSTOM_FN 126)
|
|
|
-+ (CUSTOM_FNI 127)
|
|
|
-+ (CUSTOM_FNF 128)
|
|
|
-+ (CUSTOM_FNP 129)
|
|
|
-+ (CUSTOM_FNII 130)
|
|
|
-+ (CUSTOM_FNIF 131)
|
|
|
-+ (CUSTOM_FNIP 132)
|
|
|
-+ (CUSTOM_FNFI 133)
|
|
|
-+ (CUSTOM_FNFF 134)
|
|
|
-+ (CUSTOM_FNFP 135)
|
|
|
-+ (CUSTOM_FNPI 136)
|
|
|
-+ (CUSTOM_FNPF 137)
|
|
|
-+ (CUSTOM_FNPP 138)
|
|
|
-+ (CUSTOM_PN 139)
|
|
|
-+ (CUSTOM_PNI 140)
|
|
|
-+ (CUSTOM_PNF 141)
|
|
|
-+ (CUSTOM_PNP 142)
|
|
|
-+ (CUSTOM_PNII 143)
|
|
|
-+ (CUSTOM_PNIF 144)
|
|
|
-+ (CUSTOM_PNIP 145)
|
|
|
-+ (CUSTOM_PNFI 146)
|
|
|
-+ (CUSTOM_PNFF 147)
|
|
|
-+ (CUSTOM_PNFP 148)
|
|
|
-+ (CUSTOM_PNPI 149)
|
|
|
-+ (CUSTOM_PNPF 150)
|
|
|
-+ (CUSTOM_PNPP 151)
|
|
|
-+])
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "custom_n"
|
|
|
-+ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")] CUSTOM_N)]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%0, zero, zero, zero"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_ni"
|
|
|
-+ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SI 1 "register_operand" "r")] CUSTOM_NI)]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%0, zero, %1, zero"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_nf"
|
|
|
-+ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SF 1 "register_operand" "r")] CUSTOM_NF)]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%0, zero, %1, zero"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_np"
|
|
|
-+ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SI 1 "register_operand" "r")] CUSTOM_NP)]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%0, zero, %1, zero"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_nii"
|
|
|
-+ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SI 1 "register_operand" "r")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NII)]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%0, zero, %1, %2"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_nif"
|
|
|
-+ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SI 1 "register_operand" "r")
|
|
|
-+ (match_operand:SF 2 "register_operand" "r")] CUSTOM_NIF)]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%0, zero, %1, %2"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_nip"
|
|
|
-+ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SI 1 "register_operand" "r")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NIP)]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%0, zero, %1, %2"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_nfi"
|
|
|
-+ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SF 1 "register_operand" "r")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NFI)]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%0, zero, %1, %2"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_nff"
|
|
|
-+ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SF 1 "register_operand" "r")
|
|
|
-+ (match_operand:SF 2 "register_operand" "r")] CUSTOM_NFF)]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%0, zero, %1, %2"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_nfp"
|
|
|
-+ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SF 1 "register_operand" "r")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NFP)]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%0, zero, %1, %2"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_npi"
|
|
|
-+ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SI 1 "register_operand" "r")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NPI)]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%0, zero, %1, %2"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_npf"
|
|
|
-+ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SI 1 "register_operand" "r")
|
|
|
-+ (match_operand:SF 2 "register_operand" "r")] CUSTOM_NPF)]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%0, zero, %1, %2"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_npp"
|
|
|
-+ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SI 1 "register_operand" "r")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NPP)]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%0, zero, %1, %2"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "custom_in"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")] CUSTOM_IN))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, zero, zero"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_ini"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")] CUSTOM_INI))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, zero"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_inf"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SF 2 "register_operand" "r")] CUSTOM_INF))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, zero"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_inp"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")] CUSTOM_INP))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, zero"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_inii"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")
|
|
|
-+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INII))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, %3"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_inif"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")
|
|
|
-+ (match_operand:SF 3 "register_operand" "r")] CUSTOM_INIF))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, %3"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_inip"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")
|
|
|
-+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INIP))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, %3"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_infi"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SF 2 "register_operand" "r")
|
|
|
-+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INFI))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, %3"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_inff"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SF 2 "register_operand" "r")
|
|
|
-+ (match_operand:SF 3 "register_operand" "r")] CUSTOM_INFF))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, %3"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_infp"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SF 2 "register_operand" "r")
|
|
|
-+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INFP))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, %3"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_inpi"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")
|
|
|
-+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INPI))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, %3"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_inpf"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")
|
|
|
-+ (match_operand:SF 3 "register_operand" "r")] CUSTOM_INPF))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, %3"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_inpp"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")
|
|
|
-+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INPP))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, %3"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "custom_fn"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")] CUSTOM_FN))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, zero, zero"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_fni"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")] CUSTOM_FNI))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, zero"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_fnf"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SF 2 "register_operand" "r")] CUSTOM_FNF))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, zero"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_fnp"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")] CUSTOM_FNP))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, zero"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_fnii"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")
|
|
|
-+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNII))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, %3"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_fnif"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")
|
|
|
-+ (match_operand:SF 3 "register_operand" "r")] CUSTOM_FNIF))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, %3"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_fnip"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")
|
|
|
-+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNIP))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, %3"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_fnfi"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SF 2 "register_operand" "r")
|
|
|
-+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNFI))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, %3"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_fnff"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SF 2 "register_operand" "r")
|
|
|
-+ (match_operand:SF 3 "register_operand" "r")] CUSTOM_FNFF))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, %3"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_fnfp"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SF 2 "register_operand" "r")
|
|
|
-+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNFP))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, %3"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_fnpi"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")
|
|
|
-+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNPI))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, %3"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_fnpf"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")
|
|
|
-+ (match_operand:SF 3 "register_operand" "r")] CUSTOM_FNPF))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, %3"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_fnpp"
|
|
|
-+ [(set (match_operand:SF 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")
|
|
|
-+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNPP))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, %3"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "custom_pn"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")] CUSTOM_PN))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, zero, zero"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_pni"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")] CUSTOM_PNI))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, zero"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_pnf"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SF 2 "register_operand" "r")] CUSTOM_PNF))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, zero"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_pnp"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")] CUSTOM_PNP))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, zero"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_pnii"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")
|
|
|
-+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNII))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, %3"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_pnif"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")
|
|
|
-+ (match_operand:SF 3 "register_operand" "r")] CUSTOM_PNIF))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, %3"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_pnip"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")
|
|
|
-+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNIP))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, %3"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_pnfi"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SF 2 "register_operand" "r")
|
|
|
-+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNFI))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, %3"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_pnff"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SF 2 "register_operand" "r")
|
|
|
-+ (match_operand:SF 3 "register_operand" "r")] CUSTOM_PNFF))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, %3"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_pnfp"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SF 2 "register_operand" "r")
|
|
|
-+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNFP))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, %3"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_pnpi"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")
|
|
|
-+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNPI))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, %3"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_pnpf"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")
|
|
|
-+ (match_operand:SF 3 "register_operand" "r")] CUSTOM_PNPF))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, %3"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+(define_insn "custom_pnpp"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")
|
|
|
-+ (match_operand:SI 2 "register_operand" "r")
|
|
|
-+ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNPP))]
|
|
|
-+ ""
|
|
|
-+ "custom\\t%1, %0, %2, %3"
|
|
|
-+ [(set_attr "type" "custom")])
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+
|
|
|
-+;*****************************************************************************
|
|
|
-+;*
|
|
|
-+;* Misc
|
|
|
-+;*
|
|
|
-+;*****************************************************************************
|
|
|
-+
|
|
|
-+(define_insn "nop"
|
|
|
-+ [(const_int 0)]
|
|
|
-+ ""
|
|
|
-+ "nop\\t"
|
|
|
-+ [(set_attr "type" "alu")])
|
|
|
-+
|
|
|
-+(define_insn "sync"
|
|
|
-+ [(unspec_volatile [(const_int 0)] UNSPEC_SYNC)]
|
|
|
-+ ""
|
|
|
-+ "sync\\t"
|
|
|
-+ [(set_attr "type" "control")])
|
|
|
-+
|
|
|
-+
|
|
|
-+(define_insn "rdctl"
|
|
|
-+ [(set (match_operand:SI 0 "register_operand" "=r")
|
|
|
-+ (unspec_volatile:SI [(match_operand:SI 1 "rdwrctl_operand" "O")] UNSPEC_RDCTL))]
|
|
|
-+ ""
|
|
|
-+ "rdctl\\t%0, ctl%1"
|
|
|
-+ [(set_attr "type" "control")])
|
|
|
-+
|
|
|
-+(define_insn "wrctl"
|
|
|
-+ [(unspec_volatile:SI [(match_operand:SI 0 "rdwrctl_operand" "O")
|
|
|
-+ (match_operand:SI 1 "reg_or_0_operand" "rM")] UNSPEC_WRCTL)]
|
|
|
-+ ""
|
|
|
-+ "wrctl\\tctl%0, %z1"
|
|
|
-+ [(set_attr "type" "control")])
|
|
|
-+
|
|
|
-+;Used to signal a stack overflow
|
|
|
-+(define_insn "trap"
|
|
|
-+ [(unspec_volatile [(const_int 0)] UNSPEC_TRAP)]
|
|
|
-+ ""
|
|
|
-+ "break\\t3"
|
|
|
-+ [(set_attr "type" "control")])
|
|
|
-+
|
|
|
-+(define_insn "stack_overflow_detect_and_trap"
|
|
|
-+ [(unspec_volatile [(const_int 0)] UNSPEC_STACK_OVERFLOW_DETECT_AND_TRAP)]
|
|
|
-+ ""
|
|
|
-+ "bgeu\\tsp, et, 1f\;break\\t3\;1:"
|
|
|
-+ [(set_attr "type" "control")])
|
|
|
-+
|
|
|
-+
|
|
|
-+;*****************************************************************************
|
|
|
-+;*
|
|
|
-+;* Peepholes
|
|
|
-+;*
|
|
|
-+;*****************************************************************************
|
|
|
-+
|
|
|
-+
|
|
|
-+;; Local Variables:
|
|
|
-+;; mode: lisp
|
|
|
-+;; End:
|
|
|
-diff --git a/gcc/config/nios2/t-nios2 b/gcc/config/nios2/t-nios2
|
|
|
-new file mode 100644
|
|
|
-index 0000000..b92f80a
|
|
|
---- /dev/null
|
|
|
-+++ b/gcc/config/nios2/t-nios2
|
|
|
-@@ -0,0 +1,175 @@
|
|
|
-+##
|
|
|
-+## Compiler flags to use when compiling libgcc2.c.
|
|
|
-+##
|
|
|
-+## LIB2FUNCS_EXTRA
|
|
|
-+## A list of source file names to be compiled or assembled and inserted into libgcc.a.
|
|
|
-+
|
|
|
-+LIB2FUNCS_EXTRA=$(srcdir)/config/nios2/lib2-divmod.c \
|
|
|
-+ $(srcdir)/config/nios2/lib2-divmod-hi.c \
|
|
|
-+ $(srcdir)/config/nios2/lib2-divtable.c \
|
|
|
-+ $(srcdir)/config/nios2/lib2-mul.c
|
|
|
-+
|
|
|
-+##
|
|
|
-+## Floating Point Emulation
|
|
|
-+## To have GCC include software floating point libraries in libgcc.a define FPBIT
|
|
|
-+## and DPBIT along with a few rules as follows:
|
|
|
-+##
|
|
|
-+## # We want fine grained libraries, so use the new code
|
|
|
-+## # to build the floating point emulation libraries.
|
|
|
-+FPBIT=$(srcdir)/config/nios2/nios2-fp-bit.c
|
|
|
-+DPBIT=$(srcdir)/config/nios2/nios2-dp-bit.c
|
|
|
-+
|
|
|
-+TARGET_LIBGCC2_CFLAGS = -O2
|
|
|
-+
|
|
|
-+# FLOAT_ONLY - no doubles
|
|
|
-+# SMALL_MACHINE - QI/HI is faster than SI
|
|
|
-+# Actually SMALL_MACHINE uses chars and shorts instead of ints
|
|
|
-+# since ints (16-bit ones as they are today) are at least as fast
|
|
|
-+# as chars and shorts, don't define SMALL_MACHINE
|
|
|
-+# CMPtype - type returned by FP compare, i.e. INT (hard coded in fp-bit - see code )
|
|
|
-+
|
|
|
-+$(FPBIT): $(srcdir)/config/fp-bit.c Makefile
|
|
|
-+ echo '#define FLOAT' > ${FPBIT}
|
|
|
-+ echo '#ifndef __nios2_big_endian__' >> ${FPBIT}
|
|
|
-+ echo '#define FLOAT_BIT_ORDER_MISMATCH' >> ${FPBIT}
|
|
|
-+ echo '#endif' >> ${FPBIT}
|
|
|
-+ cat $(srcdir)/config/fp-bit.c >> ${FPBIT}
|
|
|
-+
|
|
|
-+$(DPBIT): $(srcdir)/config/fp-bit.c Makefile
|
|
|
-+ echo '' > ${DPBIT}
|
|
|
-+ echo '#ifndef __nios2_big_endian__' >> ${DPBIT}
|
|
|
-+ echo '#define FLOAT_BIT_ORDER_MISMATCH' >> ${DPBIT}
|
|
|
-+ echo '#endif' >> ${DPBIT}
|
|
|
-+ cat $(srcdir)/config/fp-bit.c >> ${DPBIT}
|
|
|
-+
|
|
|
-+EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o crti.o crtn.o
|
|
|
-+
|
|
|
-+# Assemble startup files.
|
|
|
-+$(T)crti.o: $(srcdir)/config/nios2/crti.asm $(GCC_PASSES)
|
|
|
-+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \
|
|
|
-+ -c -o $(T)crti.o -x assembler-with-cpp $(srcdir)/config/nios2/crti.asm
|
|
|
-+
|
|
|
-+$(T)crtn.o: $(srcdir)/config/nios2/crtn.asm $(GCC_PASSES)
|
|
|
-+ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \
|
|
|
-+ -c -o $(T)crtn.o -x assembler-with-cpp $(srcdir)/config/nios2/crtn.asm
|
|
|
-+
|
|
|
-+
|
|
|
-+## You may need to provide additional #defines at the beginning of
|
|
|
-+## fp-bit.c and dp-bit.c to control target endianness and other options
|
|
|
-+##
|
|
|
-+## CRTSTUFF_T_CFLAGS
|
|
|
-+## Special flags used when compiling crtstuff.c. See Initialization.
|
|
|
-+##
|
|
|
-+## CRTSTUFF_T_CFLAGS_S
|
|
|
-+## Special flags used when compiling crtstuff.c for shared linking. Used
|
|
|
-+## if you use crtbeginS.o and crtendS.o in EXTRA-PARTS. See Initialization.
|
|
|
-+##
|
|
|
-+## MULTILIB_OPTIONS
|
|
|
-+## For some targets, invoking GCC in different ways produces objects that
|
|
|
-+## can not be linked together. For example, for some targets GCC produces
|
|
|
-+## both big and little endian code. For these targets, you must arrange
|
|
|
-+## for multiple versions of libgcc.a to be compiled, one for each set of
|
|
|
-+## incompatible options. When GCC invokes the linker, it arranges to link
|
|
|
-+## in the right version of libgcc.a, based on the command line options
|
|
|
-+## used.
|
|
|
-+## The MULTILIB_OPTIONS macro lists the set of options for which special
|
|
|
-+## versions of libgcc.a must be built. Write options that are mutually
|
|
|
-+## incompatible side by side, separated by a slash. Write options that may
|
|
|
-+## be used together separated by a space. The build procedure will build
|
|
|
-+## all combinations of compatible options.
|
|
|
-+##
|
|
|
-+## For example, if you set MULTILIB_OPTIONS to m68000/m68020 msoft-float,
|
|
|
-+## Makefile will build special versions of libgcc.a using the following
|
|
|
-+## sets of options: -m68000, -m68020, -msoft-float, -m68000 -msoft-float,
|
|
|
-+## and -m68020 -msoft-float.
|
|
|
-+
|
|
|
-+
|
|
|
-+## The BUILD_BE_MULTILIB and BUILD_PG_MULTILIB variables allow the
|
|
|
-+## makefile user to enable/disable the generation of the precompiled
|
|
|
-+## big endian and profiling libraries. By default, the big endian
|
|
|
-+## libraries are not created on a windows build and the profiling
|
|
|
-+## libraries are not created on a Solaris build. All other library
|
|
|
-+## combinations are created by default.
|
|
|
-+
|
|
|
-+# Uncomment to temporarily avoid building big endian and profiling libraries during a Windows build.
|
|
|
-+#ifeq ($(DEV_HOST_OS), win32)
|
|
|
-+#BUILD_BE_MULTILIB ?= 0
|
|
|
-+#BUILD_PG_MULTILIB ?= 0
|
|
|
-+#endif
|
|
|
-+
|
|
|
-+#By default, avoid building the profiling libraries during a Solaris build.
|
|
|
-+ifeq ($(DEV_HOST_OS), solaris)
|
|
|
-+BUILD_PG_MULTILIB ?= 0
|
|
|
-+endif
|
|
|
-+
|
|
|
-+BUILD_BE_MULTILIB ?= 1
|
|
|
-+BUILD_PG_MULTILIB ?= 1
|
|
|
-+BUILD_MULTILIB ?= 1
|
|
|
-+
|
|
|
-+ifeq ($(BUILD_MULTILIB), 1)
|
|
|
-+
|
|
|
-+MULTILIB_OPTIONS = mno-hw-mul mhw-mulx mstack-check mcustom-fpu-cfg=60-1 mcustom-fpu-cfg=60-2
|
|
|
-+
|
|
|
-+#Add the profiling flag to the multilib variable if required
|
|
|
-+ifeq ($(BUILD_PG_MULTILIB), 1)
|
|
|
-+MULTILIB_OPTIONS += pg
|
|
|
-+endif
|
|
|
-+
|
|
|
-+#Add the big endian flag to the multilib variable if required
|
|
|
-+ifeq ($(BUILD_BE_MULTILIB), 1)
|
|
|
-+MULTILIB_OPTIONS += EB/EL
|
|
|
-+endif
|
|
|
-+
|
|
|
-+endif
|
|
|
-+
|
|
|
-+## MULTILIB_DIRNAMES
|
|
|
-+## If MULTILIB_OPTIONS is used, this variable specifies the directory names
|
|
|
-+## that should be used to hold the various libraries. Write one element in
|
|
|
-+## MULTILIB_DIRNAMES for each element in MULTILIB_OPTIONS. If
|
|
|
-+## MULTILIB_DIRNAMES is not used, the default value will be
|
|
|
-+## MULTILIB_OPTIONS, with all slashes treated as spaces.
|
|
|
-+## For example, if MULTILIB_OPTIONS is set to m68000/m68020 msoft-float,
|
|
|
-+## then the default value of MULTILIB_DIRNAMES is m68000 m68020
|
|
|
-+## msoft-float. You may specify a different value if you desire a
|
|
|
-+## different set of directory names.
|
|
|
-+
|
|
|
-+# MULTILIB_DIRNAMES =
|
|
|
-+
|
|
|
-+## MULTILIB_MATCHES
|
|
|
-+## Sometimes the same option may be written in two different ways. If an
|
|
|
-+## option is listed in MULTILIB_OPTIONS, GCC needs to know about any
|
|
|
-+## synonyms. In that case, set MULTILIB_MATCHES to a list of items of the
|
|
|
-+## form option=option to describe all relevant synonyms. For example,
|
|
|
-+## m68000=mc68000 m68020=mc68020.
|
|
|
-+
|
|
|
-+ifeq ($(BUILD_MULTILIB), 1)
|
|
|
-+ifeq ($(BUILD_BE_MULTILIB), 1)
|
|
|
-+MULTILIB_MATCHES = EL=mel EB=meb
|
|
|
-+endif
|
|
|
-+endif
|
|
|
-+
|
|
|
-+##
|
|
|
-+## MULTILIB_EXCEPTIONS
|
|
|
-+## Sometimes when there are multiple sets of MULTILIB_OPTIONS being
|
|
|
-+## specified, there are combinations that should not be built. In that
|
|
|
-+## case, set MULTILIB_EXCEPTIONS to be all of the switch exceptions in
|
|
|
-+## shell case syntax that should not be built.
|
|
|
-+## For example, in the PowerPC embedded ABI support, it is not desirable to
|
|
|
-+## build libraries compiled with the -mcall-aix option and either of the
|
|
|
-+## -fleading-underscore or -mlittle options at the same time. Therefore
|
|
|
-+## MULTILIB_EXCEPTIONS is set to
|
|
|
-+##
|
|
|
-+## *mcall-aix/*fleading-underscore* *mlittle/*mcall-aix*
|
|
|
-+##
|
|
|
-+
|
|
|
-+ifeq ($(BUILD_MULTILIB), 1)
|
|
|
-+MULTILIB_EXCEPTIONS = *mno-hw-mul/*mhw-mulx* *mcustom-fpu-cfg=60-1/*mcustom-fpu-cfg=60-2*
|
|
|
-+endif
|
|
|
-+
|
|
|
-+##
|
|
|
-+## MULTILIB_EXTRA_OPTS Sometimes it is desirable that when building
|
|
|
-+## multiple versions of libgcc.a certain options should always be passed on
|
|
|
-+## to the compiler. In that case, set MULTILIB_EXTRA_OPTS to be the list
|
|
|
-+## of options to be used for all builds.
|
|
|
-+##
|
|
|
-+
|
|
|
-diff --git a/gcc/config/nios2/t-nios2-uclibc b/gcc/config/nios2/t-nios2-uclibc
|
|
|
-new file mode 100644
|
|
|
-index 0000000..9a303db
|
|
|
---- /dev/null
|
|
|
-+++ b/gcc/config/nios2/t-nios2-uclibc
|
|
|
-@@ -0,0 +1,152 @@
|
|
|
-+##
|
|
|
-+## Compiler flags to use when compiling libgcc2.c.
|
|
|
-+##
|
|
|
-+## LIB2FUNCS_EXTRA
|
|
|
-+## A list of source file names to be compiled or assembled and inserted into libgcc.a.
|
|
|
-+
|
|
|
-+LIB2FUNCS_EXTRA=$(srcdir)/config/nios2/lib2-divmod.c \
|
|
|
-+ $(srcdir)/config/nios2/lib2-divmod-hi.c \
|
|
|
-+ $(srcdir)/config/nios2/lib2-divtable.c \
|
|
|
-+ $(srcdir)/config/nios2/lib2-mul.c
|
|
|
-+
|
|
|
-+##
|
|
|
-+## Floating Point Emulation
|
|
|
-+## To have GCC include software floating point libraries in libgcc.a define FPBIT
|
|
|
-+## and DPBIT along with a few rules as follows:
|
|
|
-+##
|
|
|
-+## # We want fine grained libraries, so use the new code
|
|
|
-+## # to build the floating point emulation libraries.
|
|
|
-+FPBIT=$(srcdir)/config/nios2/nios2-fp-bit.c
|
|
|
-+DPBIT=$(srcdir)/config/nios2/nios2-dp-bit.c
|
|
|
-+
|
|
|
-+TARGET_LIBGCC2_CFLAGS = -O2
|
|
|
-+
|
|
|
-+# FLOAT_ONLY - no doubles
|
|
|
-+# SMALL_MACHINE - QI/HI is faster than SI
|
|
|
-+# Actually SMALL_MACHINE uses chars and shorts instead of ints
|
|
|
-+# since ints (16-bit ones as they are today) are at least as fast
|
|
|
-+# as chars and shorts, don't define SMALL_MACHINE
|
|
|
-+# CMPtype - type returned by FP compare, i.e. INT (hard coded in fp-bit - see code )
|
|
|
-+
|
|
|
-+$(FPBIT): $(srcdir)/config/fp-bit.c Makefile
|
|
|
-+ echo '#define FLOAT' > ${FPBIT}
|
|
|
-+ echo '#ifndef __nios2_big_endian__' >> ${FPBIT}
|
|
|
-+ echo '#define FLOAT_BIT_ORDER_MISMATCH' >> ${FPBIT}
|
|
|
-+ echo '#endif' >> ${FPBIT}
|
|
|
-+ cat $(srcdir)/config/fp-bit.c >> ${FPBIT}
|
|
|
-+
|
|
|
-+$(DPBIT): $(srcdir)/config/fp-bit.c Makefile
|
|
|
-+ echo '' > ${DPBIT}
|
|
|
-+ echo '#ifndef __nios2_big_endian__' >> ${DPBIT}
|
|
|
-+ echo '#define FLOAT_BIT_ORDER_MISMATCH' >> ${DPBIT}
|
|
|
-+ echo '#endif' >> ${DPBIT}
|
|
|
-+ cat $(srcdir)/config/fp-bit.c >> ${DPBIT}
|
|
|
-+
|
|
|
-+EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o
|
|
|
-+
|
|
|
-+## You may need to provide additional #defines at the beginning of
|
|
|
-+## fp-bit.c and dp-bit.c to control target endianness and other options
|
|
|
-+##
|
|
|
-+## CRTSTUFF_T_CFLAGS
|
|
|
-+## Special flags used when compiling crtstuff.c. See Initialization.
|
|
|
-+##
|
|
|
-+## CRTSTUFF_T_CFLAGS_S
|
|
|
-+## Special flags used when compiling crtstuff.c for shared linking. Used
|
|
|
-+## if you use crtbeginS.o and crtendS.o in EXTRA-PARTS. See Initialization.
|
|
|
-+##
|
|
|
-+## MULTILIB_OPTIONS
|
|
|
-+## For some targets, invoking GCC in different ways produces objects that
|
|
|
-+## can not be linked together. For example, for some targets GCC produces
|
|
|
-+## both big and little endian code. For these targets, you must arrange
|
|
|
-+## for multiple versions of libgcc.a to be compiled, one for each set of
|
|
|
-+## incompatible options. When GCC invokes the linker, it arranges to link
|
|
|
-+## in the right version of libgcc.a, based on the command line options
|
|
|
-+## used.
|
|
|
-+## The MULTILIB_OPTIONS macro lists the set of options for which special
|
|
|
-+## versions of libgcc.a must be built. Write options that are mutually
|
|
|
-+## incompatible side by side, separated by a slash. Write options that may
|
|
|
-+## be used together separated by a space. The build procedure will build
|
|
|
-+## all combinations of compatible options.
|
|
|
-+##
|
|
|
-+## For example, if you set MULTILIB_OPTIONS to m68000/m68020 msoft-float,
|
|
|
-+## Makefile will build special versions of libgcc.a using the following
|
|
|
-+## sets of options: -m68000, -m68020, -msoft-float, -m68000 -msoft-float,
|
|
|
-+## and -m68020 -msoft-float.
|
|
|
-+
|
|
|
-+
|
|
|
-+## The BUILD_BE_MULTILIB and BUILD_PG_MULTILIB variables allow the
|
|
|
-+## makefile user to enable/disable the generation of the precompiled
|
|
|
-+## big endian and profiling libraries.
|
|
|
-+
|
|
|
-+# By default, avoid building big endian and profiling libraries
|
|
|
-+BUILD_BE_MULTILIB ?= 0
|
|
|
-+BUILD_PG_MULTILIB ?= 0
|
|
|
-+BUILD_MULTILIB ?= 1
|
|
|
-+
|
|
|
-+ifeq ($(BUILD_MULTILIB), 1)
|
|
|
-+
|
|
|
-+MULTILIB_OPTIONS = mno-hw-mul mhw-mulx mstack-check mcustom-fpu-cfg=60-1 mcustom-fpu-cfg=60-2
|
|
|
-+
|
|
|
-+#Add the profiling flag to the multilib variable if required
|
|
|
-+ifeq ($(BUILD_PG_MULTILIB), 1)
|
|
|
-+MULTILIB_OPTIONS += pg
|
|
|
-+endif
|
|
|
-+
|
|
|
-+#Add the big endian flag to the multilib variable if required
|
|
|
-+ifeq ($(BUILD_BE_MULTILIB), 1)
|
|
|
-+MULTILIB_OPTIONS += EB/EL
|
|
|
-+endif
|
|
|
-+
|
|
|
-+endif
|
|
|
-+
|
|
|
-+## MULTILIB_DIRNAMES
|
|
|
-+## If MULTILIB_OPTIONS is used, this variable specifies the directory names
|
|
|
-+## that should be used to hold the various libraries. Write one element in
|
|
|
-+## MULTILIB_DIRNAMES for each element in MULTILIB_OPTIONS. If
|
|
|
-+## MULTILIB_DIRNAMES is not used, the default value will be
|
|
|
-+## MULTILIB_OPTIONS, with all slashes treated as spaces.
|
|
|
-+## For example, if MULTILIB_OPTIONS is set to m68000/m68020 msoft-float,
|
|
|
-+## then the default value of MULTILIB_DIRNAMES is m68000 m68020
|
|
|
-+## msoft-float. You may specify a different value if you desire a
|
|
|
-+## different set of directory names.
|
|
|
-+
|
|
|
-+# MULTILIB_DIRNAMES =
|
|
|
-+
|
|
|
-+## MULTILIB_MATCHES
|
|
|
-+## Sometimes the same option may be written in two different ways. If an
|
|
|
-+## option is listed in MULTILIB_OPTIONS, GCC needs to know about any
|
|
|
-+## synonyms. In that case, set MULTILIB_MATCHES to a list of items of the
|
|
|
-+## form option=option to describe all relevant synonyms. For example,
|
|
|
-+## m68000=mc68000 m68020=mc68020.
|
|
|
-+
|
|
|
-+ifeq ($(BUILD_MULTILIB), 1)
|
|
|
-+ifeq ($(BUILD_BE_MULTILIB), 1)
|
|
|
-+MULTILIB_MATCHES = EL=mel EB=meb
|
|
|
-+endif
|
|
|
-+endif
|
|
|
-+
|
|
|
-+##
|
|
|
-+## MULTILIB_EXCEPTIONS
|
|
|
-+## Sometimes when there are multiple sets of MULTILIB_OPTIONS being
|
|
|
-+## specified, there are combinations that should not be built. In that
|
|
|
-+## case, set MULTILIB_EXCEPTIONS to be all of the switch exceptions in
|
|
|
-+## shell case syntax that should not be built.
|
|
|
-+## For example, in the PowerPC embedded ABI support, it is not desirable to
|
|
|
-+## build libraries compiled with the -mcall-aix option and either of the
|
|
|
-+## -fleading-underscore or -mlittle options at the same time. Therefore
|
|
|
-+## MULTILIB_EXCEPTIONS is set to
|
|
|
-+##
|
|
|
-+## *mcall-aix/*fleading-underscore* *mlittle/*mcall-aix*
|
|
|
-+##
|
|
|
-+
|
|
|
-+ifeq ($(BUILD_MULTILIB), 1)
|
|
|
-+MULTILIB_EXCEPTIONS = *mno-hw-mul/*mhw-mulx* *mcustom-fpu-cfg=60-1/*mcustom-fpu-cfg=60-2*
|
|
|
-+endif
|
|
|
-+
|
|
|
-+##
|
|
|
-+## MULTILIB_EXTRA_OPTS Sometimes it is desirable that when building
|
|
|
-+## multiple versions of libgcc.a certain options should always be passed on
|
|
|
-+## to the compiler. In that case, set MULTILIB_EXTRA_OPTS to be the list
|
|
|
-+## of options to be used for all builds.
|
|
|
-+##
|
|
|
-+
|
|
|
-diff --git a/gcc/cse.c b/gcc/cse.c
|
|
|
-index 72af39a..b36310c 100644
|
|
|
---- a/gcc/cse.c
|
|
|
-+++ b/gcc/cse.c
|
|
|
-@@ -3134,6 +3134,10 @@ find_comparison_args (enum rtx_code code, rtx *parg1, rtx *parg2,
|
|
|
- #ifdef FLOAT_STORE_FLAG_VALUE
|
|
|
- REAL_VALUE_TYPE fsfv;
|
|
|
- #endif
|
|
|
-+#ifdef __nios2__
|
|
|
-+ if (p->is_const)
|
|
|
-+ break;
|
|
|
-+#endif
|
|
|
-
|
|
|
- /* If the entry isn't valid, skip it. */
|
|
|
- if (! exp_equiv_p (p->exp, p->exp, 1, 0))
|
|
|
-diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
|
|
|
-index 4638645..cdb248d 100644
|
|
|
---- a/gcc/doc/extend.texi
|
|
|
-+++ b/gcc/doc/extend.texi
|
|
|
-@@ -2488,6 +2488,33 @@ contents of that register. The @code{short_call} attribute always places
|
|
|
- the offset to the function from the call site into the @samp{BL}
|
|
|
- instruction directly.
|
|
|
-
|
|
|
-+@item reverse_bitfields/no_reverse_bitfields
|
|
|
-+@cindex reverse_bitfields on Altera Nios II
|
|
|
-+This attribute specifies the order of bitfield allocation within a
|
|
|
-+particular struct on Altera's Nios II processor. This overrides both
|
|
|
-+the @option{-mno-reverse-bitfields} and @option{-mreverse-bitfields}
|
|
|
-+switches, as well as any @code{#pragma} that might be present. It is
|
|
|
-+ignored except when present on a struct.
|
|
|
-+
|
|
|
-+@smallexample
|
|
|
-+struct inner
|
|
|
-+@{
|
|
|
-+ unsigned int a:1;
|
|
|
-+ unsigned int b:31;
|
|
|
-+@} __attribute__ ((reverse_bitfields));
|
|
|
-+
|
|
|
-+union outer
|
|
|
-+@{
|
|
|
-+ struct inner inner;
|
|
|
-+ unsigned int val;
|
|
|
-+@};
|
|
|
-+
|
|
|
-+@end smallexample
|
|
|
-+
|
|
|
-+will cause a to be allocated overlapping the most significant bit of
|
|
|
-+val, regardless of any @code{#pragma} or compiler switch. See the
|
|
|
-+@option{-mreverse-bitfields} switch for more examples.
|
|
|
-+
|
|
|
- @item function_vector
|
|
|
- @cindex calling functions through the function vector on the H8/300 processors
|
|
|
- Use this attribute on the H8/300, H8/300H, and H8S to indicate that the specified
|
|
|
-@@ -5638,12 +5665,118 @@ to those machines. Generally these generate calls to specific machine
|
|
|
- instructions, but allow the compiler to schedule those calls.
|
|
|
-
|
|
|
- @menu
|
|
|
-+* Altera Nios II Built-in Functions::
|
|
|
- * Alpha Built-in Functions::
|
|
|
- * ARM Built-in Functions::
|
|
|
- * X86 Built-in Functions::
|
|
|
- * PowerPC AltiVec Built-in Functions::
|
|
|
- @end menu
|
|
|
-
|
|
|
-+@node Altera Nios II Built-in Functions
|
|
|
-+@subsection Altera Nios II Built-in Functions
|
|
|
-+
|
|
|
-+These built-in functions are available for the Altera Nios II
|
|
|
-+family of processors.
|
|
|
-+
|
|
|
-+The following built-in functions are always available. They
|
|
|
-+all generate the machine instruction that is part of the name.
|
|
|
-+
|
|
|
-+@example
|
|
|
-+int __builtin_ldbio (volatile const void *)
|
|
|
-+int __builtin_ldbuio (volatile const void *)
|
|
|
-+int __builtin_ldhio (volatile const void *)
|
|
|
-+int __builtin_ldhuio (volatile const void *)
|
|
|
-+int __builtin_ldwio (volatile const void *)
|
|
|
-+void __builtin_stbio (volatile void *, int)
|
|
|
-+void __builtin_sthio (volatile void *, int)
|
|
|
-+void __builtin_stwio (volatile void *, int)
|
|
|
-+void __builtin_sync (void)
|
|
|
-+int __builtin_rdctl (int)
|
|
|
-+void __builtin_wrctl (int, int)
|
|
|
-+@end example
|
|
|
-+
|
|
|
-+The following built-in functions are always available. They
|
|
|
-+all generate a Nios II Custom Instruction. The name of the
|
|
|
-+function represents the types that the function takes and
|
|
|
-+returns. The letter before the @code{n} is the return type
|
|
|
-+or void if absent. The @code{n} represnts the first parameter
|
|
|
-+to all the custom instructions, the custom instruction number.
|
|
|
-+The two letters after the @code{n} represent the up to two
|
|
|
-+parameters to the function.
|
|
|
-+
|
|
|
-+The letters reprsent the following data types:
|
|
|
-+@table @code
|
|
|
-+@item <no letter>
|
|
|
-+@code{void} for return type and no parameter for parameter types.
|
|
|
-+
|
|
|
-+@item i
|
|
|
-+@code{int} for return type and parameter type
|
|
|
-+
|
|
|
-+@item f
|
|
|
-+@code{float} for return type and parameter type
|
|
|
-+
|
|
|
-+@item p
|
|
|
-+@code{void *} for return type and parameter type
|
|
|
-+
|
|
|
-+@end table
|
|
|
-+
|
|
|
-+And the function names are:
|
|
|
-+@example
|
|
|
-+void __builtin_custom_n (void)
|
|
|
-+void __builtin_custom_ni (int)
|
|
|
-+void __builtin_custom_nf (float)
|
|
|
-+void __builtin_custom_np (void *)
|
|
|
-+void __builtin_custom_nii (int, int)
|
|
|
-+void __builtin_custom_nif (int, float)
|
|
|
-+void __builtin_custom_nip (int, void *)
|
|
|
-+void __builtin_custom_nfi (float, int)
|
|
|
-+void __builtin_custom_nff (float, float)
|
|
|
-+void __builtin_custom_nfp (float, void *)
|
|
|
-+void __builtin_custom_npi (void *, int)
|
|
|
-+void __builtin_custom_npf (void *, float)
|
|
|
-+void __builtin_custom_npp (void *, void *)
|
|
|
-+int __builtin_custom_in (void)
|
|
|
-+int __builtin_custom_ini (int)
|
|
|
-+int __builtin_custom_inf (float)
|
|
|
-+int __builtin_custom_inp (void *)
|
|
|
-+int __builtin_custom_inii (int, int)
|
|
|
-+int __builtin_custom_inif (int, float)
|
|
|
-+int __builtin_custom_inip (int, void *)
|
|
|
-+int __builtin_custom_infi (float, int)
|
|
|
-+int __builtin_custom_inff (float, float)
|
|
|
-+int __builtin_custom_infp (float, void *)
|
|
|
-+int __builtin_custom_inpi (void *, int)
|
|
|
-+int __builtin_custom_inpf (void *, float)
|
|
|
-+int __builtin_custom_inpp (void *, void *)
|
|
|
-+float __builtin_custom_fn (void)
|
|
|
-+float __builtin_custom_fni (int)
|
|
|
-+float __builtin_custom_fnf (float)
|
|
|
-+float __builtin_custom_fnp (void *)
|
|
|
-+float __builtin_custom_fnii (int, int)
|
|
|
-+float __builtin_custom_fnif (int, float)
|
|
|
-+float __builtin_custom_fnip (int, void *)
|
|
|
-+float __builtin_custom_fnfi (float, int)
|
|
|
-+float __builtin_custom_fnff (float, float)
|
|
|
-+float __builtin_custom_fnfp (float, void *)
|
|
|
-+float __builtin_custom_fnpi (void *, int)
|
|
|
-+float __builtin_custom_fnpf (void *, float)
|
|
|
-+float __builtin_custom_fnpp (void *, void *)
|
|
|
-+void * __builtin_custom_pn (void)
|
|
|
-+void * __builtin_custom_pni (int)
|
|
|
-+void * __builtin_custom_pnf (float)
|
|
|
-+void * __builtin_custom_pnp (void *)
|
|
|
-+void * __builtin_custom_pnii (int, int)
|
|
|
-+void * __builtin_custom_pnif (int, float)
|
|
|
-+void * __builtin_custom_pnip (int, void *)
|
|
|
-+void * __builtin_custom_pnfi (float, int)
|
|
|
-+void * __builtin_custom_pnff (float, float)
|
|
|
-+void * __builtin_custom_pnfp (float, void *)
|
|
|
-+void * __builtin_custom_pnpi (void *, int)
|
|
|
-+void * __builtin_custom_pnpf (void *, float)
|
|
|
-+void * __builtin_custom_pnpp (void *, void *)
|
|
|
-+@end example
|
|
|
-+
|
|
|
-+
|
|
|
- @node Alpha Built-in Functions
|
|
|
- @subsection Alpha Built-in Functions
|
|
|
-
|
|
|
-@@ -8022,6 +8155,7 @@ we do not recommend the use of pragmas; @xref{Function Attributes},
|
|
|
- for further explanation.
|
|
|
-
|
|
|
- @menu
|
|
|
-+* Altera Nios II Pragmas::
|
|
|
- * ARM Pragmas::
|
|
|
- * RS/6000 and PowerPC Pragmas::
|
|
|
- * Darwin Pragmas::
|
|
|
-@@ -8029,6 +8163,29 @@ for further explanation.
|
|
|
- * Tru64 Pragmas::
|
|
|
- @end menu
|
|
|
-
|
|
|
-+@node Altera Nios II Pragmas
|
|
|
-+@subsection Altera Nios II Pragmas
|
|
|
-+
|
|
|
-+The Altera Nios II target defines two pragmas to control the placement
|
|
|
-+of bitfields within a struct.
|
|
|
-+
|
|
|
-+@table @code
|
|
|
-+@item reverse_bitfields
|
|
|
-+@cindex pragma, reverse_bitfields
|
|
|
-+Cause all subsequent structs to behave as though the -mreverse-bitfields
|
|
|
-+compiler switch had been given. Can be overridden by the
|
|
|
-+@code{no_reverse_bitfields} attribute or a subsequent
|
|
|
-+@code{#pragma no_reverse_bitfields}.
|
|
|
-+
|
|
|
-+@item no_reverse_bitfields
|
|
|
-+@cindex pragma, no_reverse_bitfields
|
|
|
-+Cause all subsequent structs to behave as though the -mno-reverse-bitfields
|
|
|
-+compiler switch had been given. Can be overridden by the
|
|
|
-+@code{reverse_bitfields} attribute or a subsequent
|
|
|
-+@code{#pragma reverse_bitfields}.
|
|
|
-+
|
|
|
-+@end table
|
|
|
-+
|
|
|
- @node ARM Pragmas
|
|
|
- @subsection ARM Pragmas
|
|
|
-
|
|
|
-diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
|
|
|
-index e683d0c..b34200f 100644
|
|
|
---- a/gcc/doc/invoke.texi
|
|
|
-+++ b/gcc/doc/invoke.texi
|
|
|
-@@ -337,6 +337,16 @@ in the following sections.
|
|
|
- @item Machine Dependent Options
|
|
|
- @xref{Submodel Options,,Hardware Models and Configurations}.
|
|
|
-
|
|
|
-+@emph{Altera Nios II Options}
|
|
|
-+@gccoptlist{-msmallc -mno-bypass-cache -mbypass-cache @gol
|
|
|
-+-mno-cache-volatile -mcache-volatile -mno-inline-memcpy @gol
|
|
|
-+-minline-memcpy -mno-fast-sw-div -mfast-sw-div @gol
|
|
|
-+-mhw-mul -mno-hw-mul -mhw-mulx -mno-hw-mulx @gol
|
|
|
-+-mno-hw-div -mhw-div @gol
|
|
|
-+-mno-stack-check -mstack-check @gol
|
|
|
-+-msys-crt0= -msys-lib= -msys=nosys @gol
|
|
|
-+-mreverse-bitfields -mno-reverse-bitfields}
|
|
|
-+
|
|
|
- @emph{M680x0 Options}
|
|
|
- @gccoptlist{-m68000 -m68020 -m68020-40 -m68020-60 -m68030 -m68040 @gol
|
|
|
- -m68060 -mcpu32 -m5200 -m68881 -mbitfield -mc68000 -mc68020 @gol
|
|
|
-@@ -5839,6 +5849,7 @@ machine description. The default for the options is also defined by
|
|
|
- that macro, which enables you to change the defaults.
|
|
|
-
|
|
|
- @menu
|
|
|
-+* Altera Nios II Options::
|
|
|
- * M680x0 Options::
|
|
|
- * M68hc1x Options::
|
|
|
- * VAX Options::
|
|
|
-@@ -5874,6 +5885,290 @@ that macro, which enables you to change the defaults.
|
|
|
- * FRV Options::
|
|
|
- @end menu
|
|
|
-
|
|
|
-+
|
|
|
-+@node Altera Nios II Options
|
|
|
-+@subsection Altera Nios II Options
|
|
|
-+@cindex Altera Nios II options
|
|
|
-+
|
|
|
-+These are the @samp{-m} options defined for the Altera Nios II
|
|
|
-+processor.
|
|
|
-+
|
|
|
-+@table @gcctabopt
|
|
|
-+
|
|
|
-+@item -msmallc
|
|
|
-+@opindex msmallc
|
|
|
-+Link with a limited version of the C library, -lsmallc. For more
|
|
|
-+information see the C Library Documentation.
|
|
|
-+
|
|
|
-+
|
|
|
-+@item -mbypass-cache
|
|
|
-+@itemx -mno-bypass-cache
|
|
|
-+@opindex mno-bypass-cache
|
|
|
-+@opindex mbypass-cache
|
|
|
-+Force all load and store instructions to always bypass cache by
|
|
|
-+using io variants of the instructions. The default is to not
|
|
|
-+bypass the cache.
|
|
|
-+
|
|
|
-+@item -mno-cache-volatile
|
|
|
-+@itemx -mcache-volatile
|
|
|
-+@opindex mcache-volatile
|
|
|
-+@opindex mno-cache-volatile
|
|
|
-+Volatile memory access bypass the cache using the io variants of
|
|
|
-+the ld and st instructions. The default is to cache volatile
|
|
|
-+accesses.
|
|
|
-+
|
|
|
-+-mno-cache-volatile is deprecated and will be deleted in a
|
|
|
-+future GCC release.
|
|
|
-+
|
|
|
-+
|
|
|
-+@item -mno-inline-memcpy
|
|
|
-+@itemx -minline-memcpy
|
|
|
-+@opindex mno-inline-memcpy
|
|
|
-+@opindex minline-memcpy
|
|
|
-+Do not inline memcpy. The default is to inline when -O is on.
|
|
|
-+
|
|
|
-+
|
|
|
-+@item -mno-fast-sw-div
|
|
|
-+@itemx -mfast-sw-div
|
|
|
-+@opindex mno-fast-sw-div
|
|
|
-+@opindex mfast-sw-div
|
|
|
-+Do no use table based fast divide for small numbers. The default
|
|
|
-+is to use the fast divide at -O3 and above.
|
|
|
-+
|
|
|
-+
|
|
|
-+@item -mno-hw-mul
|
|
|
-+@itemx -mhw-mul
|
|
|
-+@itemx -mno-hw-mulx
|
|
|
-+@itemx -mhw-mulx
|
|
|
-+@itemx -mno-hw-div
|
|
|
-+@itemx -mhw-div
|
|
|
-+@opindex mno-hw-mul
|
|
|
-+@opindex mhw-mul
|
|
|
-+@opindex mno-hw-mulx
|
|
|
-+@opindex mhw-mulx
|
|
|
-+@opindex mno-hw-div
|
|
|
-+@opindex mhw-div
|
|
|
-+Enable or disable emitting @code{mul}, @code{mulx} and @code{div} family of
|
|
|
-+instructions by the compiler. The default is to emit @code{mul}
|
|
|
-+and not emit @code{div} and @code{mulx}.
|
|
|
-+
|
|
|
-+The different combinations of @code{mul} and @code{mulx} instructions
|
|
|
-+generate a different multilib options.
|
|
|
-+
|
|
|
-+@item -mno-stack-check
|
|
|
-+@itemx -mstack-check
|
|
|
-+@opindex no-stack-check
|
|
|
-+@opindex stack-check
|
|
|
-+Enables or disables the checking for sufficient memory when
|
|
|
-+items are pushed onto the stack. A checked and non-checked
|
|
|
-+version of each of the multilibs is provided.
|
|
|
-+
|
|
|
-+@item -msys-crt0=@var{startfile}
|
|
|
-+@opindex msys-crt0
|
|
|
-+@var{startfile} is the file name of the startfile (crt0) to use
|
|
|
-+when linking. The default is crt0.o that comes with libgloss
|
|
|
-+and is only suitable for use with the instruction set
|
|
|
-+simulator.
|
|
|
-+
|
|
|
-+@item -msys-lib=@var{systemlib}
|
|
|
-+@itemx -msys-lib=nosys
|
|
|
-+@opindex msys-lib
|
|
|
-+@var{systemlib} is the library name of the library which provides
|
|
|
-+the system calls required by the C library, e.g. @code{read}, @code{write}
|
|
|
-+etc. The default is to use nosys, this library provides
|
|
|
-+stub implementations of the calls and is part of libgloss.
|
|
|
-+
|
|
|
-+@item -mno-reverse-bitfields
|
|
|
-+@itemx -mreverse-bitfields
|
|
|
-+@opindex mno-reverse-bitfields
|
|
|
-+@opindex mreverse-bitfields
|
|
|
-+When enabled, bitfields within a struct are allocated in reverse order.
|
|
|
-+This is useful with legacy code that depends on the (inherently
|
|
|
-+non-portable) ordering of bitfields via a union. Given:
|
|
|
-+
|
|
|
-+@smallexample
|
|
|
-+struct inner
|
|
|
-+@{
|
|
|
-+ unsigned int a:1;
|
|
|
-+ unsigned int b:31;
|
|
|
-+@};
|
|
|
-+
|
|
|
-+union outer
|
|
|
-+@{
|
|
|
-+ struct inner inner;
|
|
|
-+ unsigned int val;
|
|
|
-+@};
|
|
|
-+
|
|
|
-+unsigned int f()
|
|
|
-+@{
|
|
|
-+ union outer o;
|
|
|
-+ o.inner.a = 1;
|
|
|
-+ o.inner.b = 0;
|
|
|
-+ return o.val;
|
|
|
-+@}
|
|
|
-+@end smallexample
|
|
|
-+
|
|
|
-+a call to @code{f} will return 1 when compiled with
|
|
|
-+@option{-mno-reverse-bitfields} (the default), or 2147483648 when
|
|
|
-+compiled with @option{-mreverse-bitfields}.
|
|
|
-+
|
|
|
-+For structures that are a multiple of 32 bits wide, the reversal is
|
|
|
-+done 32 bits at a time. For structures that are an odd multiple of 16
|
|
|
-+bits wide, the reversal is done 16 bits at a time. For structures
|
|
|
-+that are an odd multiple of 8 bits wide, the reversal is done 8 bits
|
|
|
-+at a time. The size of a structure (as measured by the @code{sizeof}
|
|
|
-+operator) never changes between @option{-mno-reverse-bitfields} and
|
|
|
-+@option{-mreverse-bitfields}. Nonetheless, there can be some
|
|
|
-+confusing corner cases with structs where the compiler has to add
|
|
|
-+additional padding to meet alignment restrictions. Consider:
|
|
|
-+
|
|
|
-+@smallexample
|
|
|
-+struct inner
|
|
|
-+@{
|
|
|
-+ unsigned int a:1;
|
|
|
-+ unsigned int b:15;
|
|
|
-+@};
|
|
|
-+
|
|
|
-+union outer
|
|
|
-+@{
|
|
|
-+ struct inner inner;
|
|
|
-+ unsigned int val;
|
|
|
-+@};
|
|
|
-+
|
|
|
-+unsigned int f()
|
|
|
-+@{
|
|
|
-+ union outer o;
|
|
|
-+ o.val = 0;
|
|
|
-+ o.inner.b = 1;
|
|
|
-+ return o.val;
|
|
|
-+@}
|
|
|
-+@end smallexample
|
|
|
-+
|
|
|
-+a call to @code{f} will return 2 when compiled with
|
|
|
-+@option{-mno-reverse-bitfields} (the default), or 65536 when compiled
|
|
|
-+with @option{-mreverse-bitfields}. This is because @code{sizeof
|
|
|
-+(inner)} is 4 in both cases. In the @option{-mno-reverse-bitfields}
|
|
|
-+case, the compiler pads the struct at the end to be 4 bytes long,
|
|
|
-+effectively doing:
|
|
|
-+
|
|
|
-+@smallexample
|
|
|
-+struct inner
|
|
|
-+@{
|
|
|
-+ unsigned int a:1;
|
|
|
-+ unsigned int b:15;
|
|
|
-+ unsigned int padding:16;
|
|
|
-+@};
|
|
|
-+@end smallexample
|
|
|
-+
|
|
|
-+In the @option{-mreverse-bitfields} case, the hidden padding is
|
|
|
-+reversed along with everything else, yielding the equivalent of:
|
|
|
-+
|
|
|
-+@smallexample
|
|
|
-+struct inner
|
|
|
-+@{
|
|
|
-+ unsigned int padding:16;
|
|
|
-+ unsigned int b:15;
|
|
|
-+ unsigned int a:1;
|
|
|
-+@};
|
|
|
-+@end smallexample
|
|
|
-+
|
|
|
-+Of course, if we would rather that @code{sizeof (inner)} was 2, we could
|
|
|
-+write the struct as:
|
|
|
-+
|
|
|
-+@smallexample
|
|
|
-+struct inner
|
|
|
-+@{
|
|
|
-+ unsigned short a:1;
|
|
|
-+ unsigned short b:15;
|
|
|
-+@};
|
|
|
-+@end smallexample
|
|
|
-+
|
|
|
-+and the padding would go away.
|
|
|
-+
|
|
|
-+In some cases, especially when using the @code{__packed__} attribute,
|
|
|
-+there is no well-defined bit reversal that is possible: the compiler
|
|
|
-+will issue an error message in this case. Consider:
|
|
|
-+
|
|
|
-+@smallexample
|
|
|
-+struct invalid
|
|
|
-+@{
|
|
|
-+ unsigned int f1:1;
|
|
|
-+ unsigned int f2:15;
|
|
|
-+ unsigned int f3:4;
|
|
|
-+ unsigned int f4:4;
|
|
|
-+@} __attribute__ ((__packed__));
|
|
|
-+@end smallexample
|
|
|
-+
|
|
|
-+Since @code{sizeof (invalid)} is 3, we are forced to try reversing
|
|
|
-+individual bytes in the struct. But f2 is more than a byte wide, so
|
|
|
-+we can't reverse it and still have it be contiguous. Similar cases
|
|
|
-+occur when dealing with arrays or other large contiguous objects:
|
|
|
-+
|
|
|
-+@smallexample
|
|
|
-+struct invalid2
|
|
|
-+@{
|
|
|
-+ unsigned char f1[5];
|
|
|
-+ unsigned char f2[3];
|
|
|
-+@};
|
|
|
-+@end smallexample
|
|
|
-+
|
|
|
-+You'll have to rewrite the affected structs to say exactly what you
|
|
|
-+mean in odd cases like that.
|
|
|
-+
|
|
|
-+Finally, note that individual fields are sized as a whole. The structs
|
|
|
-+
|
|
|
-+@smallexample
|
|
|
-+struct array1
|
|
|
-+@{
|
|
|
-+ unsigned char f1[3];
|
|
|
-+ unsigned char f2;
|
|
|
-+@}
|
|
|
-+@end smallexample
|
|
|
-+
|
|
|
-+and:
|
|
|
-+
|
|
|
-+@smallexample
|
|
|
-+struct array2
|
|
|
-+@{
|
|
|
-+ unsigned char f1a;
|
|
|
-+ unsigned char f1b;
|
|
|
-+ unsigned char f1c;
|
|
|
-+ unsigned char f2;
|
|
|
-+@}
|
|
|
-+@end smallexample
|
|
|
-+
|
|
|
-+are not equivalent. When compiled with @option{-mreverse-bitfields},
|
|
|
-+they behave the same as:
|
|
|
-+
|
|
|
-+@smallexample
|
|
|
-+struct array1r
|
|
|
-+@{
|
|
|
-+ unsigned char f2;
|
|
|
-+ unsigned char f1[3];
|
|
|
-+@}
|
|
|
-+@end smallexample
|
|
|
-+
|
|
|
-+and:
|
|
|
-+
|
|
|
-+@smallexample
|
|
|
-+struct array2r
|
|
|
-+@{
|
|
|
-+ unsigned char f2;
|
|
|
-+ unsigned char f1c;
|
|
|
-+ unsigned char f1b;
|
|
|
-+ unsigned char f1a;
|
|
|
-+@}
|
|
|
-+@end smallexample
|
|
|
-+
|
|
|
-+would, respectively, when compiled with
|
|
|
-+@option{-mno-reverse-bitfields}. In particular, f1 is treated as a
|
|
|
-+single contiguous 24-bit object for purposes of reversal, while f1a,
|
|
|
-+f1b, and f1c are treated as individual 8-bit objects that need not
|
|
|
-+(and do not) remain contiguous. Use caution.
|
|
|
-+
|
|
|
-+@end table
|
|
|
-+
|
|
|
-+
|
|
|
- @node M680x0 Options
|
|
|
- @subsection M680x0 Options
|
|
|
- @cindex M680x0 options
|
|
|
-diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
|
|
|
-index b73f325..4a134b2 100644
|
|
|
---- a/gcc/doc/md.texi
|
|
|
-+++ b/gcc/doc/md.texi
|
|
|
-@@ -1337,6 +1337,58 @@ However, here is a summary of the machine-dependent constraints
|
|
|
- available on some particular machines.
|
|
|
-
|
|
|
- @table @emph
|
|
|
-+
|
|
|
-+@item Altera Nios II family---@file{nios2.h}
|
|
|
-+@table @code
|
|
|
-+
|
|
|
-+@item I
|
|
|
-+Integer that is valid as an immediate operand in an
|
|
|
-+instruction taking a signed 16-bit number. Range
|
|
|
-+@minus{}32768 to 32767.
|
|
|
-+
|
|
|
-+@item J
|
|
|
-+Integer that is valid as an immediate operand in an
|
|
|
-+instruction taking an unsigned 16-bit number. Range
|
|
|
-+0 to 65535.
|
|
|
-+
|
|
|
-+@item K
|
|
|
-+Integer that is valid as an immediate operand in an
|
|
|
-+instruction taking only the upper 16-bits of a
|
|
|
-+32-bit number. Range 32-bit numbers with the lower
|
|
|
-+16-bits being 0.
|
|
|
-+
|
|
|
-+@item L
|
|
|
-+Integer that is valid as an immediate operand for a
|
|
|
-+shift instruction. Range 0 to 31.
|
|
|
-+
|
|
|
-+
|
|
|
-+@item M
|
|
|
-+Integer that is valid as an immediate operand for
|
|
|
-+only the value 0. Can be used in conjunction with
|
|
|
-+the format modifier @code{z} to use @code{r0}
|
|
|
-+instead of @code{0} in the assembly output.
|
|
|
-+
|
|
|
-+@item N
|
|
|
-+Integer that is valid as an immediate operand for
|
|
|
-+a custom instruction opcode. Range 0 to 255.
|
|
|
-+
|
|
|
-+@item S
|
|
|
-+Matches immediates which are addresses in the small
|
|
|
-+data section and therefore can be added to @code{gp}
|
|
|
-+as a 16-bit immediate to re-create their 32-bit value.
|
|
|
-+
|
|
|
-+@item D@var{nn}
|
|
|
-+For a given two digit @var{nn} constrains the operand
|
|
|
-+to the corresponding register. Example: D02 forces the
|
|
|
-+operand into register r2. The side effect of using this
|
|
|
-+operand constraint is that reload may not be able to
|
|
|
-+meet the constraint. If reload fails, an error message
|
|
|
-+about failing to find any register to spill in the
|
|
|
-+D@var{nn}_REG register class will be emitted.
|
|
|
-+
|
|
|
-+@end table
|
|
|
-+
|
|
|
-+
|
|
|
- @item ARM family---@file{arm.h}
|
|
|
- @table @code
|
|
|
- @item f
|
|
|
-diff --git a/gcc/stor-layout.c b/gcc/stor-layout.c
|
|
|
-index 4527fe4..e7cc581 100644
|
|
|
---- a/gcc/stor-layout.c
|
|
|
-+++ b/gcc/stor-layout.c
|
|
|
-@@ -1435,6 +1435,355 @@ finalize_type_size (tree type)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-+static void
|
|
|
-+reverse_bitfield_layout (record_layout_info rli)
|
|
|
-+{
|
|
|
-+ tree field;
|
|
|
-+ tree rev_size;
|
|
|
-+ unsigned int rev_size_int;
|
|
|
-+
|
|
|
-+ /*
|
|
|
-+ * The size of the words we'll be reversing. Normally, we reverse
|
|
|
-+ * entire SImode words. However, if the entire struct's size isn't an
|
|
|
-+ * exact multiple of the size of SImode, we can reverse HImode or even
|
|
|
-+ * QImode pieces. In the examples below, assume SImode/int is 32
|
|
|
-+ * bits, HImode/short is 16 bits, and QImode/char is 8 bits.
|
|
|
-+ * Consider:
|
|
|
-+ *
|
|
|
-+ * struct s1
|
|
|
-+ * {
|
|
|
-+ * int f1:1;
|
|
|
-+ * int f2:31;
|
|
|
-+ * };
|
|
|
-+ *
|
|
|
-+ * struct s2
|
|
|
-+ * {
|
|
|
-+ * int f1:1;
|
|
|
-+ * int f2:15;
|
|
|
-+ * } __attribute__ ((__packed__));
|
|
|
-+ *
|
|
|
-+ * struct s3
|
|
|
-+ * {
|
|
|
-+ * short f1:1;
|
|
|
-+ * short f2:15;
|
|
|
-+ * };
|
|
|
-+ *
|
|
|
-+ * struct s4
|
|
|
-+ * {
|
|
|
-+ * int f1:1;
|
|
|
-+ * int f2:15;
|
|
|
-+ * };
|
|
|
-+ *
|
|
|
-+ * struct s5
|
|
|
-+ * {
|
|
|
-+ * int f1:8;
|
|
|
-+ * int f2:8;
|
|
|
-+ * int f3:4;
|
|
|
-+ * int f4:4;
|
|
|
-+ * } __attribute__ ((__packed__));
|
|
|
-+ *
|
|
|
-+ * struct s6
|
|
|
-+ * {
|
|
|
-+ * int f1:1;
|
|
|
-+ * int f2:15;
|
|
|
-+ * int f3:4;
|
|
|
-+ * int f4:4;
|
|
|
-+ * int f5:8;
|
|
|
-+ * };
|
|
|
-+ *
|
|
|
-+ * struct s7
|
|
|
-+ * {
|
|
|
-+ * int f1:1;
|
|
|
-+ * int f2:15;
|
|
|
-+ * int f3:4;
|
|
|
-+ * int f4:4;
|
|
|
-+ * } __attribute__ ((__packed__));
|
|
|
-+ *
|
|
|
-+ * struct s8
|
|
|
-+ * {
|
|
|
-+ * char f1;
|
|
|
-+ * short f2;
|
|
|
-+ * char f3;
|
|
|
-+ * };
|
|
|
-+ *
|
|
|
-+ * struct s9
|
|
|
-+ * {
|
|
|
-+ * char f1;
|
|
|
-+ * short f2;
|
|
|
-+ * char f3;
|
|
|
-+ * } __attribute__ ((__packed__));
|
|
|
-+ *
|
|
|
-+ * struct s10
|
|
|
-+ * {
|
|
|
-+ * char f1;
|
|
|
-+ * short f2;
|
|
|
-+ * char f3;
|
|
|
-+ * short f4;
|
|
|
-+ * };
|
|
|
-+ *
|
|
|
-+ * struct s11
|
|
|
-+ * {
|
|
|
-+ * char f1[5];
|
|
|
-+ * int f2;
|
|
|
-+ * };
|
|
|
-+ *
|
|
|
-+ * struct s12
|
|
|
-+ * {
|
|
|
-+ * char f1[5];
|
|
|
-+ * char f2[3];
|
|
|
-+ * int f3;
|
|
|
-+ * };
|
|
|
-+ *
|
|
|
-+ * struct s13
|
|
|
-+ * {
|
|
|
-+ * char f1[3];
|
|
|
-+ * int f2;
|
|
|
-+ * };
|
|
|
-+ *
|
|
|
-+ * struct s14
|
|
|
-+ * {
|
|
|
-+ * char f1a;
|
|
|
-+ * char f1b;
|
|
|
-+ * char f1c;
|
|
|
-+ * int f2;
|
|
|
-+ * };
|
|
|
-+ *
|
|
|
-+ * Then we have:
|
|
|
-+ *
|
|
|
-+ * sizeof (struct s1) == 4
|
|
|
-+ * sizeof (struct s2) == 2
|
|
|
-+ * sizeof (struct s3) == 2
|
|
|
-+ * sizeof (struct s4) == 4
|
|
|
-+ * sizeof (struct s5) == 3
|
|
|
-+ * sizeof (struct s6) == 4
|
|
|
-+ * sizeof (struct s7) == 3
|
|
|
-+ * sizeof (struct s8) == 6
|
|
|
-+ * sizeof (struct s9) == 4
|
|
|
-+ * sizeof (struct s10) == 8
|
|
|
-+ * sizeof (struct s11) == 12
|
|
|
-+ * sizeof (struct s12) == 12
|
|
|
-+ *
|
|
|
-+ * We want the equivalent reversed bitfield structs to be:
|
|
|
-+ *
|
|
|
-+ * struct s1r
|
|
|
-+ * {
|
|
|
-+ * int f2:31;
|
|
|
-+ * int f1:1;
|
|
|
-+ * };
|
|
|
-+ *
|
|
|
-+ * struct s2r
|
|
|
-+ * {
|
|
|
-+ * int f2:15;
|
|
|
-+ * int f1:1;
|
|
|
-+ * } __attribute__ ((__packed__));
|
|
|
-+ *
|
|
|
-+ * struct s3r
|
|
|
-+ * {
|
|
|
-+ * short f2:15;
|
|
|
-+ * short f1:1;
|
|
|
-+ * };
|
|
|
-+ *
|
|
|
-+ * struct s4r
|
|
|
-+ * {
|
|
|
-+ * int unnamed:16;
|
|
|
-+ * int f2:15;
|
|
|
-+ * int f1:1;
|
|
|
-+ * };
|
|
|
-+ *
|
|
|
-+ * struct s5r
|
|
|
-+ * {
|
|
|
-+ * int f1:8;
|
|
|
-+ * int f2:8;
|
|
|
-+ * int f4:4;
|
|
|
-+ * int f3:4;
|
|
|
-+ * } __attribute__ ((__packed__));
|
|
|
-+ *
|
|
|
-+ * struct s6r
|
|
|
-+ * {
|
|
|
-+ * int f5:8;
|
|
|
-+ * int f4:4;
|
|
|
-+ * int f3:4;
|
|
|
-+ * int f2:15;
|
|
|
-+ * int f1:1;
|
|
|
-+ * };
|
|
|
-+ *
|
|
|
-+ * struct s7r
|
|
|
-+ * {
|
|
|
-+ * #error cannot reverse bitfield
|
|
|
-+ * } __attribute__ ((__packed__));
|
|
|
-+ *
|
|
|
-+ * struct s8r
|
|
|
-+ * {
|
|
|
-+ * char unnamed1;
|
|
|
-+ * char f1;
|
|
|
-+ * short f2;
|
|
|
-+ * char unnamed2;
|
|
|
-+ * char f3;
|
|
|
-+ * };
|
|
|
-+ *
|
|
|
-+ * struct s9r
|
|
|
-+ * {
|
|
|
-+ * char f3;
|
|
|
-+ * short f2;
|
|
|
-+ * char f1;
|
|
|
-+ * } __attribute__ ((__packed__));
|
|
|
-+ *
|
|
|
-+ * struct s10r
|
|
|
-+ * {
|
|
|
-+ * short f2;
|
|
|
-+ * char unnamed1;
|
|
|
-+ * char f1;
|
|
|
-+ * short f4;
|
|
|
-+ * char unnamed2;
|
|
|
-+ * char f3;
|
|
|
-+ * };
|
|
|
-+ *
|
|
|
-+ * struct s11r
|
|
|
-+ * {
|
|
|
-+ * char f1[5];
|
|
|
-+ * int f2;
|
|
|
-+ * };
|
|
|
-+ *
|
|
|
-+ * struct s12r
|
|
|
-+ * {
|
|
|
-+ * #error cannot reverse bitfield
|
|
|
-+ * };
|
|
|
-+ *
|
|
|
-+ * struct s13r
|
|
|
-+ * {
|
|
|
-+ * char unnamed;
|
|
|
-+ * char f1[3];
|
|
|
-+ * int f2;
|
|
|
-+ * };
|
|
|
-+ *
|
|
|
-+ * struct s14r
|
|
|
-+ * {
|
|
|
-+ * char unnamed;
|
|
|
-+ * char f1c;
|
|
|
-+ * char f1b;
|
|
|
-+ * char f1a;
|
|
|
-+ * int f2;
|
|
|
-+ * };
|
|
|
-+ *
|
|
|
-+ * Note that the s4, s8, s10, s13, and s14 cases produce somewhat
|
|
|
-+ * suprising results: the normally hidden padding bytes the compiler
|
|
|
-+ * adds are also reversed. Further note that s13 and s14 are not
|
|
|
-+ * equivalent: the f1 field in s13 is 24-bits wide, and is reversed
|
|
|
-+ * accordingly, while the three fields f1a, f1b, and f1c in s14 are
|
|
|
-+ * reversed as individual bytes.
|
|
|
-+ *
|
|
|
-+ * The s7 and s12 cases produce an error: we can't reverse a bitfield
|
|
|
-+ * that is larger than word size we're reversing. The error is
|
|
|
-+ * suppressed in the s11 case since the field in question and the
|
|
|
-+ * field that follows are both word aligned.
|
|
|
-+ */
|
|
|
-+
|
|
|
-+ /*
|
|
|
-+ * First, figure out what size words to reverse. We look at the total
|
|
|
-+ * number of bits currently in use by the struct, rounded up to the
|
|
|
-+ * next multiple of rli->record_align, to decide.
|
|
|
-+ */
|
|
|
-+ {
|
|
|
-+ int bits_in_use = TREE_INT_CST_LOW (round_up (rli_size_so_far (rli),
|
|
|
-+ rli->record_align));
|
|
|
-+ unsigned int size;
|
|
|
-+ for (size = GET_MODE_BITSIZE (SImode);
|
|
|
-+ size >= GET_MODE_BITSIZE (QImode);
|
|
|
-+ size /= 2)
|
|
|
-+ {
|
|
|
-+ if (bits_in_use % size == 0)
|
|
|
-+ {
|
|
|
-+ break;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ if (size < GET_MODE_BITSIZE (QImode))
|
|
|
-+ {
|
|
|
-+ /*
|
|
|
-+ * rli->record_align should never be less than QImode, even
|
|
|
-+ * for packed structs.
|
|
|
-+ */
|
|
|
-+ abort ();
|
|
|
-+ }
|
|
|
-+ rev_size = size_int_type (size, bitsizetype);
|
|
|
-+ rev_size_int = size;
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /*
|
|
|
-+ * Then, iterate over the fields, reversing them as we go.
|
|
|
-+ */
|
|
|
-+ for (field = TYPE_FIELDS (rli->t); field; field = TREE_CHAIN (field))
|
|
|
-+ {
|
|
|
-+ tree type = TREE_TYPE (field);
|
|
|
-+ if (TREE_CODE (field) != FIELD_DECL)
|
|
|
-+ {
|
|
|
-+ continue;
|
|
|
-+ }
|
|
|
-+ if (TREE_CODE (field) == ERROR_MARK || TREE_CODE (type) == ERROR_MARK)
|
|
|
-+ {
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+ {
|
|
|
-+ tree offset = DECL_FIELD_OFFSET (field);
|
|
|
-+ tree offset_type = TREE_TYPE (offset);
|
|
|
-+ tree bit_offset = DECL_FIELD_BIT_OFFSET (field);
|
|
|
-+ tree bit_offset_type = TREE_TYPE (bit_offset);
|
|
|
-+ tree bit = bit_from_pos (offset, bit_offset);
|
|
|
-+ tree true_size = DECL_SIZE (field);
|
|
|
-+ pos_from_bit (&offset, &bit_offset, rev_size_int, bit);
|
|
|
-+ bit_offset = size_binop (MINUS_EXPR,
|
|
|
-+ size_binop (MINUS_EXPR, rev_size, true_size),
|
|
|
-+ bit_offset);
|
|
|
-+ if (TREE_INT_CST_HIGH (bit_offset) != 0)
|
|
|
-+ {
|
|
|
-+ /*
|
|
|
-+ * This happens when a field spans a rev_size boundary (see
|
|
|
-+ * example s7 above): rather than try to come up with some
|
|
|
-+ * well-defined, but non-intuitive definition for this case,
|
|
|
-+ * just issue an error. It can also happen for large fields,
|
|
|
-+ * e.g. arrays or other structs: if these large fields were
|
|
|
-+ * already aligned, leave them be; otherwise issue the error
|
|
|
-+ * in this case as well.
|
|
|
-+ */
|
|
|
-+ if ((TREE_INT_CST_HIGH (true_size) != 0
|
|
|
-+ || TREE_INT_CST_LOW (true_size) > rev_size_int)
|
|
|
-+ && TREE_INT_CST_HIGH (DECL_FIELD_BIT_OFFSET (field)) == 0
|
|
|
-+ && TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field)) == 0)
|
|
|
-+ {
|
|
|
-+ tree next_field = TREE_CHAIN (field);
|
|
|
-+ if (!next_field)
|
|
|
-+ {
|
|
|
-+ /* No following field, so we're ok. */
|
|
|
-+ continue;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ tree next_offset = DECL_FIELD_OFFSET (next_field);
|
|
|
-+ tree next_bit_offset = DECL_FIELD_BIT_OFFSET (next_field);
|
|
|
-+ tree next_bit = bit_from_pos (next_offset, next_bit_offset);
|
|
|
-+ pos_from_bit (&next_offset, &next_bit_offset, rev_size_int,
|
|
|
-+ next_bit);
|
|
|
-+ if (TREE_INT_CST_HIGH (next_bit_offset) == 0
|
|
|
-+ && TREE_INT_CST_LOW (next_bit_offset) == 0)
|
|
|
-+ {
|
|
|
-+ /* Following field is aligned wrt rev_size_int boundary,
|
|
|
-+ so we're ok. */
|
|
|
-+ continue;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+ error ("unable to reverse bitfields in structure");
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+ bit = bit_from_pos (offset, bit_offset);
|
|
|
-+ pos_from_bit (&offset, &bit_offset, rli->offset_align, bit);
|
|
|
-+ TREE_TYPE (offset) = offset_type;
|
|
|
-+ DECL_FIELD_OFFSET (field) = offset;
|
|
|
-+ TREE_TYPE (bit_offset) = bit_offset_type;
|
|
|
-+ DECL_FIELD_BIT_OFFSET (field) = bit_offset;
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+
|
|
|
- /* Do all of the work required to layout the type indicated by RLI,
|
|
|
- once the fields have been laid out. This function will call `free'
|
|
|
- for RLI, unless FREE_P is false. Passing a value other than false
|
|
|
-@@ -1444,6 +1793,12 @@ finalize_type_size (tree type)
|
|
|
- void
|
|
|
- finish_record_layout (record_layout_info rli, int free_p)
|
|
|
- {
|
|
|
-+ /* Optionally reverse the placement of bitfields within the record */
|
|
|
-+ if ((* targetm.reverse_bitfield_layout_p) (rli->t))
|
|
|
-+ {
|
|
|
-+ reverse_bitfield_layout (rli);
|
|
|
-+ }
|
|
|
-+
|
|
|
- /* Compute the final size. */
|
|
|
- finalize_record_size (rli);
|
|
|
-
|
|
|
-diff --git a/gcc/target-def.h b/gcc/target-def.h
|
|
|
-index 32d00ae..bdea4d4 100644
|
|
|
---- a/gcc/target-def.h
|
|
|
-+++ b/gcc/target-def.h
|
|
|
-@@ -300,6 +300,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
- #define TARGET_INSERT_ATTRIBUTES hook_void_tree_treeptr
|
|
|
- #define TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P hook_bool_tree_false
|
|
|
- #define TARGET_MS_BITFIELD_LAYOUT_P hook_bool_tree_false
|
|
|
-+#define TARGET_REVERSE_BITFIELD_LAYOUT_P hook_bool_tree_false
|
|
|
- #define TARGET_RTX_COSTS hook_bool_rtx_int_int_intp_false
|
|
|
- #define TARGET_MANGLE_FUNDAMENTAL_TYPE hook_constcharptr_tree_null
|
|
|
-
|
|
|
-@@ -368,6 +369,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
- TARGET_INSERT_ATTRIBUTES, \
|
|
|
- TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P, \
|
|
|
- TARGET_MS_BITFIELD_LAYOUT_P, \
|
|
|
-+ TARGET_REVERSE_BITFIELD_LAYOUT_P, \
|
|
|
- TARGET_INIT_BUILTINS, \
|
|
|
- TARGET_EXPAND_BUILTIN, \
|
|
|
- TARGET_MANGLE_FUNDAMENTAL_TYPE, \
|
|
|
-diff --git a/gcc/target.h b/gcc/target.h
|
|
|
-index 59788f9..97bde5f 100644
|
|
|
---- a/gcc/target.h
|
|
|
-+++ b/gcc/target.h
|
|
|
-@@ -295,6 +295,10 @@ struct gcc_target
|
|
|
- Microsoft Visual C++ bitfield layout rules. */
|
|
|
- bool (* ms_bitfield_layout_p) (tree record_type);
|
|
|
-
|
|
|
-+ /* Return true if bitfields in RECORD_TYPE should be allocated
|
|
|
-+ within their base type's bytes starting at the opposite end. */
|
|
|
-+ bool (* reverse_bitfield_layout_p) (tree record_type);
|
|
|
-+
|
|
|
- /* Set up target-specific built-in functions. */
|
|
|
- void (* init_builtins) (void);
|
|
|
-
|
|
|
-diff --git a/gcc/varasm.c b/gcc/varasm.c
|
|
|
-index 33307e5..d4ed0fc 100644
|
|
|
---- a/gcc/varasm.c
|
|
|
-+++ b/gcc/varasm.c
|
|
|
-@@ -3912,6 +3912,107 @@ array_size_for_constructor (tree val)
|
|
|
- return tree_low_cst (i, 1);
|
|
|
- }
|
|
|
-
|
|
|
-+struct reorder_bitfields_key
|
|
|
-+{
|
|
|
-+ tree field;
|
|
|
-+ tree value;
|
|
|
-+};
|
|
|
-+
|
|
|
-+static int
|
|
|
-+reorder_bitfields_compare (const void *x1, const void *x2)
|
|
|
-+{
|
|
|
-+ const struct reorder_bitfields_key *key1 = x1;
|
|
|
-+ const struct reorder_bitfields_key *key2 = x2;
|
|
|
-+ int pos1 = int_bit_position (key1->field);
|
|
|
-+ int pos2 = int_bit_position (key2->field);
|
|
|
-+
|
|
|
-+ if (pos1 < pos2)
|
|
|
-+ {
|
|
|
-+ return -1;
|
|
|
-+ }
|
|
|
-+ else if (pos1 > pos2)
|
|
|
-+ {
|
|
|
-+ return 1;
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ /*
|
|
|
-+ * No two fields should ever have the same bit_position, so
|
|
|
-+ * something is horribly wrong.
|
|
|
-+ */
|
|
|
-+ abort ();
|
|
|
-+ }
|
|
|
-+}
|
|
|
-+
|
|
|
-+static void
|
|
|
-+reorder_bitfields (tree *first_field, tree *first_value)
|
|
|
-+{
|
|
|
-+ struct reorder_bitfields_key *keys;
|
|
|
-+ size_t field_count;
|
|
|
-+ tree field;
|
|
|
-+ tree value;
|
|
|
-+ size_t i;
|
|
|
-+
|
|
|
-+ /*
|
|
|
-+ * Find out how many fields are in this record, and allocate an array
|
|
|
-+ * of keys to hold them all.
|
|
|
-+ */
|
|
|
-+ field_count = 0;
|
|
|
-+ for (field = *first_field; field; field = TREE_CHAIN (field))
|
|
|
-+ {
|
|
|
-+ field_count++;
|
|
|
-+ }
|
|
|
-+ if (field_count < 2)
|
|
|
-+ {
|
|
|
-+ return;
|
|
|
-+ }
|
|
|
-+ keys = xmalloc (sizeof (struct reorder_bitfields_key) * field_count);
|
|
|
-+
|
|
|
-+ /*
|
|
|
-+ * Make copies of the existing fields and values (using signed integer
|
|
|
-+ * zeros for missing values) in the array of keys.
|
|
|
-+ */
|
|
|
-+ field = *first_field;
|
|
|
-+ value = *first_value;
|
|
|
-+ for (i = 0; i < field_count; i++)
|
|
|
-+ {
|
|
|
-+ keys[i].field = copy_node (field);
|
|
|
-+ field = TREE_CHAIN (field);
|
|
|
-+ if (value)
|
|
|
-+ {
|
|
|
-+ keys[i].value = copy_node (value);
|
|
|
-+ TREE_PURPOSE (keys[i].value) = keys[i].field;
|
|
|
-+ value = TREE_CHAIN (value);
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ keys[i].value = tree_cons (keys[i].field, ssize_int (0), 0);
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-+
|
|
|
-+ /*
|
|
|
-+ * Sort the array based on position of the fields in the record.
|
|
|
-+ */
|
|
|
-+ qsort (keys, field_count, sizeof (struct reorder_bitfields_key),
|
|
|
-+ reorder_bitfields_compare);
|
|
|
-+
|
|
|
-+ /*
|
|
|
-+ * Build new lists out of the sorted array.
|
|
|
-+ */
|
|
|
-+ for (i = 0; i < field_count - 1; i++)
|
|
|
-+ {
|
|
|
-+ TREE_CHAIN (keys[i].field) = keys[i+1].field;
|
|
|
-+ TREE_CHAIN (keys[i].value) = keys[i+1].value;
|
|
|
-+ }
|
|
|
-+ *first_field = keys[0].field;
|
|
|
-+ *first_value = keys[0].value;
|
|
|
-+
|
|
|
-+ /*
|
|
|
-+ * Get rid of our array of keys and we're done.
|
|
|
-+ */
|
|
|
-+ free (keys);
|
|
|
-+}
|
|
|
-+
|
|
|
- /* Subroutine of output_constant, used for CONSTRUCTORs (aggregate constants).
|
|
|
- Generate at least SIZE bytes, padding if necessary. */
|
|
|
-
|
|
|
-@@ -3928,12 +4029,29 @@ output_constructor (tree exp, unsigned HOST_WIDE_INT size,
|
|
|
- /* Nonzero means BYTE contains part of a byte, to be output. */
|
|
|
- int byte_buffer_in_use = 0;
|
|
|
- int byte = 0;
|
|
|
-+ tree first_link = CONSTRUCTOR_ELTS (exp);
|
|
|
-
|
|
|
- if (HOST_BITS_PER_WIDE_INT < BITS_PER_UNIT)
|
|
|
- abort ();
|
|
|
-
|
|
|
- if (TREE_CODE (type) == RECORD_TYPE)
|
|
|
-+ {
|
|
|
-+ if ((*targetm.reverse_bitfield_layout_p) (type))
|
|
|
-+ {
|
|
|
-+ /*
|
|
|
-+ * If we're reversing bitfields, we have to reverse the order in
|
|
|
-+ * which constructors containing bitfields are output. The
|
|
|
-+ * easiest way to do that is to reorder the constructor elements
|
|
|
-+ * and fields to be in memory-order.
|
|
|
-+ */
|
|
|
- field = TYPE_FIELDS (type);
|
|
|
-+ reorder_bitfields (&field, &first_link);
|
|
|
-+ }
|
|
|
-+ else
|
|
|
-+ {
|
|
|
-+ field = TYPE_FIELDS (type);
|
|
|
-+ }
|
|
|
-+ }
|
|
|
-
|
|
|
- if (TREE_CODE (type) == ARRAY_TYPE
|
|
|
- && TYPE_DOMAIN (type) != 0)
|
|
|
-@@ -3948,7 +4066,7 @@ output_constructor (tree exp, unsigned HOST_WIDE_INT size,
|
|
|
- There is always a maximum of one element in the chain LINK for unions
|
|
|
- (even if the initializer in a source program incorrectly contains
|
|
|
- more one). */
|
|
|
-- for (link = CONSTRUCTOR_ELTS (exp);
|
|
|
-+ for (link = first_link;
|
|
|
- link;
|
|
|
- link = TREE_CHAIN (link),
|
|
|
- field = field ? TREE_CHAIN (field) : 0)
|