yann@1: --- gcc-3.4.3/gcc/Makefile.in yann@1: +++ gcc-3.4.3-nios2/gcc/Makefile.in yann@1: @@ -3085,7 +3085,7 @@ install-mkheaders: stmp-int-hdrs $(STMP_ yann@1: $(INSTALL_DATA) $(srcdir)/README-fixinc \ yann@1: $(DESTDIR)$(itoolsdatadir)/include/README ; \ yann@1: $(INSTALL_SCRIPT) fixinc.sh $(DESTDIR)$(itoolsdir)/fixinc.sh ; \ yann@1: - $(INSTALL_PROGRAM) fixinc/fixincl $(DESTDIR)$(itoolsdir)/fixincl ; \ yann@1: + $(INSTALL_PROGRAM) fixinc/fixincl$(build_exeext) $(DESTDIR)$(itoolsdir)/fixincl$(build_exeext) ; \ yann@1: $(INSTALL_DATA) $(srcdir)/gsyslimits.h \ yann@1: $(DESTDIR)$(itoolsdatadir)/gsyslimits.h ; \ yann@1: else :; fi yann@1: --- gcc-3.4.3/gcc/combine.c yann@1: +++ gcc-3.4.3-nios2/gcc/combine.c yann@1: @@ -4380,6 +4380,14 @@ combine_simplify_rtx (rtx x, enum machin yann@1: mode); yann@1: } yann@1: yann@1: +#ifndef __nios2__ yann@1: +/* This screws up Nios II in this test case: yann@1: + yann@1: +if (x & 1) yann@1: + return 2; yann@1: +else yann@1: + return 3; yann@1: +*/ yann@1: else if (STORE_FLAG_VALUE == 1 yann@1: && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT yann@1: && op1 == const0_rtx yann@1: @@ -4391,6 +4399,7 @@ combine_simplify_rtx (rtx x, enum machin yann@1: gen_lowpart_for_combine (mode, op0), yann@1: const1_rtx); yann@1: } yann@1: +#endif yann@1: yann@1: else if (STORE_FLAG_VALUE == 1 yann@1: && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT yann@1: --- gcc-3.4.3/gcc/config/nios2/crti.asm yann@1: +++ gcc-3.4.3-nios2/gcc/config/nios2/crti.asm yann@1: @@ -0,0 +1,88 @@ yann@1: +/* yann@1: + Copyright (C) 2003 yann@1: + by Jonah Graham (jgraham@altera.com) yann@1: + yann@1: +This file is free software; you can redistribute it and/or modify it yann@1: +under the terms of the GNU General Public License as published by the yann@1: +Free Software Foundation; either version 2, or (at your option) any yann@1: +later version. yann@1: + yann@1: +In addition to the permissions in the GNU General Public License, the yann@1: +Free Software Foundation gives you unlimited permission to link the yann@1: +compiled version of this file with other programs, and to distribute yann@1: +those programs without any restriction coming from the use of this yann@1: +file. (The General Public License restrictions do apply in other yann@1: +respects; for example, they cover modification of the file, and yann@1: +distribution when not linked into another program.) yann@1: + yann@1: +This file is distributed in the hope that it will be useful, but yann@1: +WITHOUT ANY WARRANTY; without even the implied warranty of yann@1: +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yann@1: +General Public License for more details. yann@1: + yann@1: +You should have received a copy of the GNU General Public License yann@1: +along with this program; see the file COPYING. If not, write to yann@1: +the Free Software Foundation, 59 Temple Place - Suite 330, yann@1: +Boston, MA 02111-1307, USA. yann@1: + yann@1: + As a special exception, if you link this library with files yann@1: + compiled with GCC to produce an executable, this does not cause yann@1: + the resulting executable to be covered by the GNU General Public License. yann@1: + This exception does not however invalidate any other reasons why yann@1: + the executable file might be covered by the GNU General Public License. yann@1: + yann@1: + yann@1: +This file just make a stack frame for the contents of the .fini and yann@1: +.init sections. Users may put any desired instructions in those yann@1: +sections. yann@1: + yann@1: + yann@1: +While technically any code can be put in the init and fini sections yann@1: +most stuff will not work other than stuff which obeys the call frame yann@1: +and ABI. All the call-preserved registers are saved, the call clobbered yann@1: +registers should have been saved by the code calling init and fini. yann@1: + yann@1: +See crtstuff.c for an example of code that inserts itself in the yann@1: +init and fini sections. yann@1: + yann@1: +See crt0.s for the code that calls init and fini. yann@1: +*/ yann@1: + yann@1: + .file "crti.asm" yann@1: + yann@1: + .section ".init" yann@1: + .align 2 yann@1: + .global _init yann@1: +_init: yann@1: + addi sp, sp, -48 yann@1: + stw ra, 44(sp) yann@1: + stw r23, 40(sp) yann@1: + stw r22, 36(sp) yann@1: + stw r21, 32(sp) yann@1: + stw r20, 28(sp) yann@1: + stw r19, 24(sp) yann@1: + stw r18, 20(sp) yann@1: + stw r17, 16(sp) yann@1: + stw r16, 12(sp) yann@1: + stw fp, 8(sp) yann@1: + mov fp, sp yann@1: + yann@1: + yann@1: + .section ".fini" yann@1: + .align 2 yann@1: + .global _fini yann@1: +_fini: yann@1: + addi sp, sp, -48 yann@1: + stw ra, 44(sp) yann@1: + stw r23, 40(sp) yann@1: + stw r22, 36(sp) yann@1: + stw r21, 32(sp) yann@1: + stw r20, 28(sp) yann@1: + stw r19, 24(sp) yann@1: + stw r18, 20(sp) yann@1: + stw r17, 16(sp) yann@1: + stw r16, 12(sp) yann@1: + stw fp, 8(sp) yann@1: + mov fp, sp yann@1: + yann@1: + yann@1: --- gcc-3.4.3/gcc/config/nios2/crtn.asm yann@1: +++ gcc-3.4.3-nios2/gcc/config/nios2/crtn.asm yann@1: @@ -0,0 +1,70 @@ yann@1: +/* yann@1: + Copyright (C) 2003 yann@1: + by Jonah Graham (jgraham@altera.com) yann@1: + yann@1: +This file is free software; you can redistribute it and/or modify it yann@1: +under the terms of the GNU General Public License as published by the yann@1: +Free Software Foundation; either version 2, or (at your option) any yann@1: +later version. yann@1: + yann@1: +In addition to the permissions in the GNU General Public License, the yann@1: +Free Software Foundation gives you unlimited permission to link the yann@1: +compiled version of this file with other programs, and to distribute yann@1: +those programs without any restriction coming from the use of this yann@1: +file. (The General Public License restrictions do apply in other yann@1: +respects; for example, they cover modification of the file, and yann@1: +distribution when not linked into another program.) yann@1: + yann@1: +This file is distributed in the hope that it will be useful, but yann@1: +WITHOUT ANY WARRANTY; without even the implied warranty of yann@1: +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yann@1: +General Public License for more details. yann@1: + yann@1: +You should have received a copy of the GNU General Public License yann@1: +along with this program; see the file COPYING. If not, write to yann@1: +the Free Software Foundation, 59 Temple Place - Suite 330, yann@1: +Boston, MA 02111-1307, USA. yann@1: + yann@1: + As a special exception, if you link this library with files yann@1: + compiled with GCC to produce an executable, this does not cause yann@1: + the resulting executable to be covered by the GNU General Public License. yann@1: + This exception does not however invalidate any other reasons why yann@1: + the executable file might be covered by the GNU General Public License. yann@1: + yann@1: + yann@1: +This file just makes sure that the .fini and .init sections do in yann@1: +fact return. Users may put any desired instructions in those sections. yann@1: +This file is the last thing linked into any executable. yann@1: +*/ yann@1: + .file "crtn.asm" yann@1: + yann@1: + yann@1: + yann@1: + .section ".init" yann@1: + ldw ra, 44(sp) yann@1: + ldw r23, 40(sp) yann@1: + ldw r22, 36(sp) yann@1: + ldw r21, 32(sp) yann@1: + ldw r20, 28(sp) yann@1: + ldw r19, 24(sp) yann@1: + ldw r18, 20(sp) yann@1: + ldw r17, 16(sp) yann@1: + ldw r16, 12(sp) yann@1: + ldw fp, 8(sp) yann@1: + addi sp, sp, -48 yann@1: + ret yann@1: + yann@1: + .section ".fini" yann@1: + ldw ra, 44(sp) yann@1: + ldw r23, 40(sp) yann@1: + ldw r22, 36(sp) yann@1: + ldw r21, 32(sp) yann@1: + ldw r20, 28(sp) yann@1: + ldw r19, 24(sp) yann@1: + ldw r18, 20(sp) yann@1: + ldw r17, 16(sp) yann@1: + ldw r16, 12(sp) yann@1: + ldw fp, 8(sp) yann@1: + addi sp, sp, -48 yann@1: + ret yann@1: + yann@1: --- gcc-3.4.3/gcc/config/nios2/lib2-divmod-hi.c yann@1: +++ gcc-3.4.3-nios2/gcc/config/nios2/lib2-divmod-hi.c yann@1: @@ -0,0 +1,123 @@ yann@1: + yann@1: +/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is yann@1: + supposedly valid even though this is a "target" file. */ yann@1: +#include "auto-host.h" yann@1: + yann@1: + yann@1: +#include "tconfig.h" yann@1: +#include "tsystem.h" yann@1: +#include "coretypes.h" yann@1: +#include "tm.h" yann@1: + yann@1: + yann@1: +/* Don't use `fancy_abort' here even if config.h says to use it. */ yann@1: +#ifdef abort yann@1: +#undef abort yann@1: +#endif yann@1: + yann@1: + yann@1: +#ifdef HAVE_GAS_HIDDEN yann@1: +#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) yann@1: +#else yann@1: +#define ATTRIBUTE_HIDDEN yann@1: +#endif yann@1: + yann@1: +#include "libgcc2.h" yann@1: + yann@1: +extern HItype __modhi3 (HItype, HItype); yann@1: +extern HItype __divhi3 (HItype, HItype); yann@1: +extern HItype __umodhi3 (HItype, HItype); yann@1: +extern HItype __udivhi3 (HItype, HItype); yann@1: + yann@1: +static UHItype udivmodhi4(UHItype, UHItype, word_type); yann@1: + yann@1: +static UHItype yann@1: +udivmodhi4(UHItype num, UHItype den, word_type modwanted) yann@1: +{ yann@1: + UHItype bit = 1; yann@1: + UHItype res = 0; yann@1: + yann@1: + while (den < num && bit && !(den & (1L<<15))) yann@1: + { yann@1: + den <<=1; yann@1: + bit <<=1; yann@1: + } yann@1: + while (bit) yann@1: + { yann@1: + if (num >= den) yann@1: + { yann@1: + num -= den; yann@1: + res |= bit; yann@1: + } yann@1: + bit >>=1; yann@1: + den >>=1; yann@1: + } yann@1: + if (modwanted) return num; yann@1: + return res; yann@1: +} yann@1: + yann@1: + yann@1: +HItype yann@1: +__divhi3 (HItype a, HItype b) yann@1: +{ yann@1: + word_type neg = 0; yann@1: + HItype res; yann@1: + yann@1: + if (a < 0) yann@1: + { yann@1: + a = -a; yann@1: + neg = !neg; yann@1: + } yann@1: + yann@1: + if (b < 0) yann@1: + { yann@1: + b = -b; yann@1: + neg = !neg; yann@1: + } yann@1: + yann@1: + res = udivmodhi4 (a, b, 0); yann@1: + yann@1: + if (neg) yann@1: + res = -res; yann@1: + yann@1: + return res; yann@1: +} yann@1: + yann@1: + yann@1: +HItype yann@1: +__modhi3 (HItype a, HItype b) yann@1: +{ yann@1: + word_type neg = 0; yann@1: + HItype res; yann@1: + yann@1: + if (a < 0) yann@1: + { yann@1: + a = -a; yann@1: + neg = 1; yann@1: + } yann@1: + yann@1: + if (b < 0) yann@1: + b = -b; yann@1: + yann@1: + res = udivmodhi4 (a, b, 1); yann@1: + yann@1: + if (neg) yann@1: + res = -res; yann@1: + yann@1: + return res; yann@1: +} yann@1: + yann@1: + yann@1: +HItype yann@1: +__udivhi3 (HItype a, HItype b) yann@1: +{ yann@1: + return udivmodhi4 (a, b, 0); yann@1: +} yann@1: + yann@1: + yann@1: +HItype yann@1: +__umodhi3 (HItype a, HItype b) yann@1: +{ yann@1: + return udivmodhi4 (a, b, 1); yann@1: +} yann@1: + yann@1: --- gcc-3.4.3/gcc/config/nios2/lib2-divmod.c yann@1: +++ gcc-3.4.3-nios2/gcc/config/nios2/lib2-divmod.c yann@1: @@ -0,0 +1,126 @@ yann@1: + yann@1: +/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is yann@1: + supposedly valid even though this is a "target" file. */ yann@1: +#include "auto-host.h" yann@1: + yann@1: + yann@1: +#include "tconfig.h" yann@1: +#include "tsystem.h" yann@1: +#include "coretypes.h" yann@1: +#include "tm.h" yann@1: + yann@1: + yann@1: +/* Don't use `fancy_abort' here even if config.h says to use it. */ yann@1: +#ifdef abort yann@1: +#undef abort yann@1: +#endif yann@1: + yann@1: + yann@1: +#ifdef HAVE_GAS_HIDDEN yann@1: +#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) yann@1: +#else yann@1: +#define ATTRIBUTE_HIDDEN yann@1: +#endif yann@1: + yann@1: +#include "libgcc2.h" yann@1: + yann@1: +extern SItype __modsi3 (SItype, SItype); yann@1: +extern SItype __divsi3 (SItype, SItype); yann@1: +extern SItype __umodsi3 (SItype, SItype); yann@1: +extern SItype __udivsi3 (SItype, SItype); yann@1: + yann@1: +static USItype udivmodsi4(USItype, USItype, word_type); yann@1: + yann@1: +/* 16-bit SI divide and modulo as used in NIOS */ yann@1: + yann@1: + yann@1: +static USItype yann@1: +udivmodsi4(USItype num, USItype den, word_type modwanted) yann@1: +{ yann@1: + USItype bit = 1; yann@1: + USItype res = 0; yann@1: + yann@1: + while (den < num && bit && !(den & (1L<<31))) yann@1: + { yann@1: + den <<=1; yann@1: + bit <<=1; yann@1: + } yann@1: + while (bit) yann@1: + { yann@1: + if (num >= den) yann@1: + { yann@1: + num -= den; yann@1: + res |= bit; yann@1: + } yann@1: + bit >>=1; yann@1: + den >>=1; yann@1: + } yann@1: + if (modwanted) return num; yann@1: + return res; yann@1: +} yann@1: + yann@1: + yann@1: +SItype yann@1: +__divsi3 (SItype a, SItype b) yann@1: +{ yann@1: + word_type neg = 0; yann@1: + SItype res; yann@1: + yann@1: + if (a < 0) yann@1: + { yann@1: + a = -a; yann@1: + neg = !neg; yann@1: + } yann@1: + yann@1: + if (b < 0) yann@1: + { yann@1: + b = -b; yann@1: + neg = !neg; yann@1: + } yann@1: + yann@1: + res = udivmodsi4 (a, b, 0); yann@1: + yann@1: + if (neg) yann@1: + res = -res; yann@1: + yann@1: + return res; yann@1: +} yann@1: + yann@1: + yann@1: +SItype yann@1: +__modsi3 (SItype a, SItype b) yann@1: +{ yann@1: + word_type neg = 0; yann@1: + SItype res; yann@1: + yann@1: + if (a < 0) yann@1: + { yann@1: + a = -a; yann@1: + neg = 1; yann@1: + } yann@1: + yann@1: + if (b < 0) yann@1: + b = -b; yann@1: + yann@1: + res = udivmodsi4 (a, b, 1); yann@1: + yann@1: + if (neg) yann@1: + res = -res; yann@1: + yann@1: + return res; yann@1: +} yann@1: + yann@1: + yann@1: +SItype yann@1: +__udivsi3 (SItype a, SItype b) yann@1: +{ yann@1: + return udivmodsi4 (a, b, 0); yann@1: +} yann@1: + yann@1: + yann@1: +SItype yann@1: +__umodsi3 (SItype a, SItype b) yann@1: +{ yann@1: + return udivmodsi4 (a, b, 1); yann@1: +} yann@1: + yann@1: --- gcc-3.4.3/gcc/config/nios2/lib2-divtable.c yann@1: +++ gcc-3.4.3-nios2/gcc/config/nios2/lib2-divtable.c yann@1: @@ -0,0 +1,46 @@ yann@1: + yann@1: +/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is yann@1: + supposedly valid even though this is a "target" file. */ yann@1: +#include "auto-host.h" yann@1: + yann@1: + yann@1: +#include "tconfig.h" yann@1: +#include "tsystem.h" yann@1: +#include "coretypes.h" yann@1: +#include "tm.h" yann@1: + yann@1: + yann@1: +/* Don't use `fancy_abort' here even if config.h says to use it. */ yann@1: +#ifdef abort yann@1: +#undef abort yann@1: +#endif yann@1: + yann@1: + yann@1: +#ifdef HAVE_GAS_HIDDEN yann@1: +#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) yann@1: +#else yann@1: +#define ATTRIBUTE_HIDDEN yann@1: +#endif yann@1: + yann@1: +#include "libgcc2.h" yann@1: + yann@1: +UQItype __divsi3_table[] = yann@1: +{ yann@1: + 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, yann@1: + 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, yann@1: + 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, yann@1: + 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, yann@1: + 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, yann@1: + 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, yann@1: + 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, yann@1: + 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, yann@1: + 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, yann@1: + 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, yann@1: + 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, yann@1: + 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, yann@1: + 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, yann@1: + 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, yann@1: + 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, yann@1: + 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, yann@1: +}; yann@1: + yann@1: --- gcc-3.4.3/gcc/config/nios2/lib2-mul.c yann@1: +++ gcc-3.4.3-nios2/gcc/config/nios2/lib2-mul.c yann@1: @@ -0,0 +1,103 @@ yann@1: +/* while we are debugging (ie compile outside of gcc build) yann@1: + disable gcc specific headers */ yann@1: +#ifndef DEBUG_MULSI3 yann@1: + yann@1: + yann@1: +/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is yann@1: + supposedly valid even though this is a "target" file. */ yann@1: +#include "auto-host.h" yann@1: + yann@1: + yann@1: +#include "tconfig.h" yann@1: +#include "tsystem.h" yann@1: +#include "coretypes.h" yann@1: +#include "tm.h" yann@1: + yann@1: + yann@1: +/* Don't use `fancy_abort' here even if config.h says to use it. */ yann@1: +#ifdef abort yann@1: +#undef abort yann@1: +#endif yann@1: + yann@1: + yann@1: +#ifdef HAVE_GAS_HIDDEN yann@1: +#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) yann@1: +#else yann@1: +#define ATTRIBUTE_HIDDEN yann@1: +#endif yann@1: + yann@1: +#include "libgcc2.h" yann@1: + yann@1: +#else yann@1: +#define SItype int yann@1: +#define USItype unsigned int yann@1: +#endif yann@1: + yann@1: + yann@1: +extern SItype __mulsi3 (SItype, SItype); yann@1: + yann@1: +SItype yann@1: +__mulsi3 (SItype a, SItype b) yann@1: +{ yann@1: + SItype res = 0; yann@1: + USItype cnt = a; yann@1: + yann@1: + while (cnt) yann@1: + { yann@1: + if (cnt & 1) yann@1: + { yann@1: + res += b; yann@1: + } yann@1: + b <<= 1; yann@1: + cnt >>= 1; yann@1: + } yann@1: + yann@1: + return res; yann@1: +} yann@1: +/* yann@1: +TODO: Choose best alternative implementation. yann@1: + yann@1: +SItype yann@1: +__divsi3 (SItype a, SItype b) yann@1: +{ yann@1: + SItype res = 0; yann@1: + USItype cnt = 0; yann@1: + yann@1: + while (cnt < 32) yann@1: + { yann@1: + if (a & (1L << cnt)) yann@1: + { yann@1: + res += b; yann@1: + } yann@1: + b <<= 1; yann@1: + cnt++; yann@1: + } yann@1: + yann@1: + return res; yann@1: +} yann@1: +*/ yann@1: + yann@1: + yann@1: +#ifdef DEBUG_MULSI3 yann@1: + yann@1: +int yann@1: +main () yann@1: +{ yann@1: + int i, j; yann@1: + int error = 0; yann@1: + yann@1: + for (i = -1000; i < 1000; i++) yann@1: + for (j = -1000; j < 1000; j++) yann@1: + { yann@1: + int expect = i * j; yann@1: + int actual = A__divsi3 (i, j); yann@1: + if (expect != actual) yann@1: + { yann@1: + printf ("error: %d * %d = %d not %d\n", i, j, expect, actual); yann@1: + error = 1; yann@1: + } yann@1: + } yann@1: + yann@1: + return error; yann@1: +} yann@1: +#endif yann@1: --- gcc-3.4.3/gcc/config/nios2/nios2-dp-bit.c yann@1: +++ gcc-3.4.3-nios2/gcc/config/nios2/nios2-dp-bit.c yann@1: @@ -0,0 +1,1652 @@ yann@1: + yann@1: +/* This is a software floating point library which can be used yann@1: + for targets without hardware floating point. yann@1: + Copyright (C) 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004 yann@1: + Free Software Foundation, Inc. yann@1: + yann@1: +This file is free software; you can redistribute it and/or modify it yann@1: +under the terms of the GNU General Public License as published by the yann@1: +Free Software Foundation; either version 2, or (at your option) any yann@1: +later version. yann@1: + yann@1: +In addition to the permissions in the GNU General Public License, the yann@1: +Free Software Foundation gives you unlimited permission to link the yann@1: +compiled version of this file with other programs, and to distribute yann@1: +those programs without any restriction coming from the use of this yann@1: +file. (The General Public License restrictions do apply in other yann@1: +respects; for example, they cover modification of the file, and yann@1: +distribution when not linked into another program.) yann@1: + yann@1: +This file is distributed in the hope that it will be useful, but yann@1: +WITHOUT ANY WARRANTY; without even the implied warranty of yann@1: +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yann@1: +General Public License for more details. yann@1: + yann@1: +You should have received a copy of the GNU General Public License yann@1: +along with this program; see the file COPYING. If not, write to yann@1: +the Free Software Foundation, 59 Temple Place - Suite 330, yann@1: +Boston, MA 02111-1307, USA. */ yann@1: + yann@1: +/* As a special exception, if you link this library with other files, yann@1: + some of which are compiled with GCC, to produce an executable, yann@1: + this library does not by itself cause the resulting executable yann@1: + to be covered by the GNU General Public License. yann@1: + This exception does not however invalidate any other reasons why yann@1: + the executable file might be covered by the GNU General Public License. */ yann@1: + yann@1: +/* This implements IEEE 754 format arithmetic, but does not provide a yann@1: + mechanism for setting the rounding mode, or for generating or handling yann@1: + exceptions. yann@1: + yann@1: + The original code by Steve Chamberlain, hacked by Mark Eichin and Jim yann@1: + Wilson, all of Cygnus Support. */ yann@1: + yann@1: +/* The intended way to use this file is to make two copies, add `#define FLOAT' yann@1: + to one copy, then compile both copies and add them to libgcc.a. */ yann@1: + yann@1: +#include "tconfig.h" yann@1: +#include "coretypes.h" yann@1: +#include "tm.h" yann@1: +#include "config/fp-bit.h" yann@1: + yann@1: +/* The following macros can be defined to change the behavior of this file: yann@1: + FLOAT: Implement a `float', aka SFmode, fp library. If this is not yann@1: + defined, then this file implements a `double', aka DFmode, fp library. yann@1: + FLOAT_ONLY: Used with FLOAT, to implement a `float' only library, i.e. yann@1: + don't include float->double conversion which requires the double library. yann@1: + This is useful only for machines which can't support doubles, e.g. some yann@1: + 8-bit processors. yann@1: + CMPtype: Specify the type that floating point compares should return. yann@1: + This defaults to SItype, aka int. yann@1: + US_SOFTWARE_GOFAST: This makes all entry points use the same names as the yann@1: + US Software goFast library. yann@1: + _DEBUG_BITFLOAT: This makes debugging the code a little easier, by adding yann@1: + two integers to the FLO_union_type. yann@1: + NO_DENORMALS: Disable handling of denormals. yann@1: + NO_NANS: Disable nan and infinity handling yann@1: + SMALL_MACHINE: Useful when operations on QIs and HIs are faster yann@1: + than on an SI */ yann@1: + yann@1: +/* We don't currently support extended floats (long doubles) on machines yann@1: + without hardware to deal with them. yann@1: + yann@1: + These stubs are just to keep the linker from complaining about unresolved yann@1: + references which can be pulled in from libio & libstdc++, even if the yann@1: + user isn't using long doubles. However, they may generate an unresolved yann@1: + external to abort if abort is not used by the function, and the stubs yann@1: + are referenced from within libc, since libgcc goes before and after the yann@1: + system library. */ yann@1: + yann@1: +#ifdef DECLARE_LIBRARY_RENAMES yann@1: + DECLARE_LIBRARY_RENAMES yann@1: +#endif yann@1: + yann@1: +#ifdef EXTENDED_FLOAT_STUBS yann@1: +extern void abort (void); yann@1: +void __extendsfxf2 (void) { abort(); } yann@1: +void __extenddfxf2 (void) { abort(); } yann@1: +void __truncxfdf2 (void) { abort(); } yann@1: +void __truncxfsf2 (void) { abort(); } yann@1: +void __fixxfsi (void) { abort(); } yann@1: +void __floatsixf (void) { abort(); } yann@1: +void __addxf3 (void) { abort(); } yann@1: +void __subxf3 (void) { abort(); } yann@1: +void __mulxf3 (void) { abort(); } yann@1: +void __divxf3 (void) { abort(); } yann@1: +void __negxf2 (void) { abort(); } yann@1: +void __eqxf2 (void) { abort(); } yann@1: +void __nexf2 (void) { abort(); } yann@1: +void __gtxf2 (void) { abort(); } yann@1: +void __gexf2 (void) { abort(); } yann@1: +void __lexf2 (void) { abort(); } yann@1: +void __ltxf2 (void) { abort(); } yann@1: + yann@1: +void __extendsftf2 (void) { abort(); } yann@1: +void __extenddftf2 (void) { abort(); } yann@1: +void __trunctfdf2 (void) { abort(); } yann@1: +void __trunctfsf2 (void) { abort(); } yann@1: +void __fixtfsi (void) { abort(); } yann@1: +void __floatsitf (void) { abort(); } yann@1: +void __addtf3 (void) { abort(); } yann@1: +void __subtf3 (void) { abort(); } yann@1: +void __multf3 (void) { abort(); } yann@1: +void __divtf3 (void) { abort(); } yann@1: +void __negtf2 (void) { abort(); } yann@1: +void __eqtf2 (void) { abort(); } yann@1: +void __netf2 (void) { abort(); } yann@1: +void __gttf2 (void) { abort(); } yann@1: +void __getf2 (void) { abort(); } yann@1: +void __letf2 (void) { abort(); } yann@1: +void __lttf2 (void) { abort(); } yann@1: +#else /* !EXTENDED_FLOAT_STUBS, rest of file */ yann@1: + yann@1: +/* IEEE "special" number predicates */ yann@1: + yann@1: +#ifdef NO_NANS yann@1: + yann@1: +#define nan() 0 yann@1: +#define isnan(x) 0 yann@1: +#define isinf(x) 0 yann@1: +#else yann@1: + yann@1: +#if defined L_thenan_sf yann@1: +const fp_number_type __thenan_sf = { CLASS_SNAN, 0, 0, {(fractype) 0} }; yann@1: +#elif defined L_thenan_df yann@1: +const fp_number_type __thenan_df = { CLASS_SNAN, 0, 0, {(fractype) 0} }; yann@1: +#elif defined L_thenan_tf yann@1: +const fp_number_type __thenan_tf = { CLASS_SNAN, 0, 0, {(fractype) 0} }; yann@1: +#elif defined TFLOAT yann@1: +extern const fp_number_type __thenan_tf; yann@1: +#elif defined FLOAT yann@1: +extern const fp_number_type __thenan_sf; yann@1: +#else yann@1: +extern const fp_number_type __thenan_df; yann@1: +#endif yann@1: + yann@1: +INLINE yann@1: +static fp_number_type * yann@1: +nan (void) yann@1: +{ yann@1: + /* Discard the const qualifier... */ yann@1: +#ifdef TFLOAT yann@1: + return (fp_number_type *) (& __thenan_tf); yann@1: +#elif defined FLOAT yann@1: + return (fp_number_type *) (& __thenan_sf); yann@1: +#else yann@1: + return (fp_number_type *) (& __thenan_df); yann@1: +#endif yann@1: +} yann@1: + yann@1: +INLINE yann@1: +static int yann@1: +isnan ( fp_number_type * x) yann@1: +{ yann@1: + return x->class == CLASS_SNAN || x->class == CLASS_QNAN; yann@1: +} yann@1: + yann@1: +INLINE yann@1: +static int yann@1: +isinf ( fp_number_type * x) yann@1: +{ yann@1: + return x->class == CLASS_INFINITY; yann@1: +} yann@1: + yann@1: +#endif /* NO_NANS */ yann@1: + yann@1: +INLINE yann@1: +static int yann@1: +iszero ( fp_number_type * x) yann@1: +{ yann@1: + return x->class == CLASS_ZERO; yann@1: +} yann@1: + yann@1: +INLINE yann@1: +static void yann@1: +flip_sign ( fp_number_type * x) yann@1: +{ yann@1: + x->sign = !x->sign; yann@1: +} yann@1: + yann@1: +extern FLO_type pack_d ( fp_number_type * ); yann@1: + yann@1: +#if defined(L_pack_df) || defined(L_pack_sf) || defined(L_pack_tf) yann@1: +FLO_type yann@1: +pack_d ( fp_number_type * src) yann@1: +{ yann@1: + FLO_union_type dst; yann@1: + fractype fraction = src->fraction.ll; /* wasn't unsigned before? */ yann@1: + int sign = src->sign; yann@1: + int exp = 0; yann@1: + yann@1: + if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && (isnan (src) || isinf (src))) yann@1: + { yann@1: + /* We can't represent these values accurately. By using the yann@1: + largest possible magnitude, we guarantee that the conversion yann@1: + of infinity is at least as big as any finite number. */ yann@1: + exp = EXPMAX; yann@1: + fraction = ((fractype) 1 << FRACBITS) - 1; yann@1: + } yann@1: + else if (isnan (src)) yann@1: + { yann@1: + exp = EXPMAX; yann@1: + if (src->class == CLASS_QNAN || 1) yann@1: + { yann@1: +#ifdef QUIET_NAN_NEGATED yann@1: + fraction |= QUIET_NAN - 1; yann@1: +#else yann@1: + fraction |= QUIET_NAN; yann@1: +#endif yann@1: + } yann@1: + } yann@1: + else if (isinf (src)) yann@1: + { yann@1: + exp = EXPMAX; yann@1: + fraction = 0; yann@1: + } yann@1: + else if (iszero (src)) yann@1: + { yann@1: + exp = 0; yann@1: + fraction = 0; yann@1: + } yann@1: + else if (fraction == 0) yann@1: + { yann@1: + exp = 0; yann@1: + } yann@1: + else yann@1: + { yann@1: + if (src->normal_exp < NORMAL_EXPMIN) yann@1: + { yann@1: +#ifdef NO_DENORMALS yann@1: + /* Go straight to a zero representation if denormals are not yann@1: + supported. The denormal handling would be harmless but yann@1: + isn't unnecessary. */ yann@1: + exp = 0; yann@1: + fraction = 0; yann@1: +#else /* NO_DENORMALS */ yann@1: + /* This number's exponent is too low to fit into the bits yann@1: + available in the number, so we'll store 0 in the exponent and yann@1: + shift the fraction to the right to make up for it. */ yann@1: + yann@1: + int shift = NORMAL_EXPMIN - src->normal_exp; yann@1: + yann@1: + exp = 0; yann@1: + yann@1: + if (shift > FRAC_NBITS - NGARDS) yann@1: + { yann@1: + /* No point shifting, since it's more that 64 out. */ yann@1: + fraction = 0; yann@1: + } yann@1: + else yann@1: + { yann@1: + int lowbit = (fraction & (((fractype)1 << shift) - 1)) ? 1 : 0; yann@1: + fraction = (fraction >> shift) | lowbit; yann@1: + } yann@1: + if ((fraction & GARDMASK) == GARDMSB) yann@1: + { yann@1: + if ((fraction & (1 << NGARDS))) yann@1: + fraction += GARDROUND + 1; yann@1: + } yann@1: + else yann@1: + { yann@1: + /* Add to the guards to round up. */ yann@1: + fraction += GARDROUND; yann@1: + } yann@1: + /* Perhaps the rounding means we now need to change the yann@1: + exponent, because the fraction is no longer denormal. */ yann@1: + if (fraction >= IMPLICIT_1) yann@1: + { yann@1: + exp += 1; yann@1: + } yann@1: + fraction >>= NGARDS; yann@1: +#endif /* NO_DENORMALS */ yann@1: + } yann@1: + else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) yann@1: + && src->normal_exp > EXPBIAS) yann@1: + { yann@1: + exp = EXPMAX; yann@1: + fraction = 0; yann@1: + } yann@1: + else yann@1: + { yann@1: + exp = src->normal_exp + EXPBIAS; yann@1: + if (!ROUND_TOWARDS_ZERO) yann@1: + { yann@1: + /* IF the gard bits are the all zero, but the first, then we're yann@1: + half way between two numbers, choose the one which makes the yann@1: + lsb of the answer 0. */ yann@1: + if ((fraction & GARDMASK) == GARDMSB) yann@1: + { yann@1: + if (fraction & (1 << NGARDS)) yann@1: + fraction += GARDROUND + 1; yann@1: + } yann@1: + else yann@1: + { yann@1: + /* Add a one to the guards to round up */ yann@1: + fraction += GARDROUND; yann@1: + } yann@1: + if (fraction >= IMPLICIT_2) yann@1: + { yann@1: + fraction >>= 1; yann@1: + exp += 1; yann@1: + } yann@1: + } yann@1: + fraction >>= NGARDS; yann@1: + yann@1: + if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp > EXPMAX) yann@1: + { yann@1: + /* Saturate on overflow. */ yann@1: + exp = EXPMAX; yann@1: + fraction = ((fractype) 1 << FRACBITS) - 1; yann@1: + } yann@1: + } yann@1: + } yann@1: + yann@1: + /* We previously used bitfields to store the number, but this doesn't yann@1: + handle little/big endian systems conveniently, so use shifts and yann@1: + masks */ yann@1: +#ifdef FLOAT_BIT_ORDER_MISMATCH yann@1: + dst.bits.fraction = fraction; yann@1: + dst.bits.exp = exp; yann@1: + dst.bits.sign = sign; yann@1: +#else yann@1: +# if defined TFLOAT && defined HALFFRACBITS yann@1: + { yann@1: + halffractype high, low, unity; yann@1: + int lowsign, lowexp; yann@1: + yann@1: + unity = (halffractype) 1 << HALFFRACBITS; yann@1: + yann@1: + /* Set HIGH to the high double's significand, masking out the implicit 1. yann@1: + Set LOW to the low double's full significand. */ yann@1: + high = (fraction >> (FRACBITS - HALFFRACBITS)) & (unity - 1); yann@1: + low = fraction & (unity * 2 - 1); yann@1: + yann@1: + /* Get the initial sign and exponent of the low double. */ yann@1: + lowexp = exp - HALFFRACBITS - 1; yann@1: + lowsign = sign; yann@1: + yann@1: + /* HIGH should be rounded like a normal double, making |LOW| <= yann@1: + 0.5 ULP of HIGH. Assume round-to-nearest. */ yann@1: + if (exp < EXPMAX) yann@1: + if (low > unity || (low == unity && (high & 1) == 1)) yann@1: + { yann@1: + /* Round HIGH up and adjust LOW to match. */ yann@1: + high++; yann@1: + if (high == unity) yann@1: + { yann@1: + /* May make it infinite, but that's OK. */ yann@1: + high = 0; yann@1: + exp++; yann@1: + } yann@1: + low = unity * 2 - low; yann@1: + lowsign ^= 1; yann@1: + } yann@1: + yann@1: + high |= (halffractype) exp << HALFFRACBITS; yann@1: + high |= (halffractype) sign << (HALFFRACBITS + EXPBITS); yann@1: + yann@1: + if (exp == EXPMAX || exp == 0 || low == 0) yann@1: + low = 0; yann@1: + else yann@1: + { yann@1: + while (lowexp > 0 && low < unity) yann@1: + { yann@1: + low <<= 1; yann@1: + lowexp--; yann@1: + } yann@1: + yann@1: + if (lowexp <= 0) yann@1: + { yann@1: + halffractype roundmsb, round; yann@1: + int shift; yann@1: + yann@1: + shift = 1 - lowexp; yann@1: + roundmsb = (1 << (shift - 1)); yann@1: + round = low & ((roundmsb << 1) - 1); yann@1: + yann@1: + low >>= shift; yann@1: + lowexp = 0; yann@1: + yann@1: + if (round > roundmsb || (round == roundmsb && (low & 1) == 1)) yann@1: + { yann@1: + low++; yann@1: + if (low == unity) yann@1: + /* LOW rounds up to the smallest normal number. */ yann@1: + lowexp++; yann@1: + } yann@1: + } yann@1: + yann@1: + low &= unity - 1; yann@1: + low |= (halffractype) lowexp << HALFFRACBITS; yann@1: + low |= (halffractype) lowsign << (HALFFRACBITS + EXPBITS); yann@1: + } yann@1: + dst.value_raw = ((fractype) high << HALFSHIFT) | low; yann@1: + } yann@1: +# else yann@1: + dst.value_raw = fraction & ((((fractype)1) << FRACBITS) - (fractype)1); yann@1: + dst.value_raw |= ((fractype) (exp & ((1 << EXPBITS) - 1))) << FRACBITS; yann@1: + dst.value_raw |= ((fractype) (sign & 1)) << (FRACBITS | EXPBITS); yann@1: +# endif yann@1: +#endif yann@1: + yann@1: +#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT) yann@1: +#ifdef TFLOAT yann@1: + { yann@1: + qrtrfractype tmp1 = dst.words[0]; yann@1: + qrtrfractype tmp2 = dst.words[1]; yann@1: + dst.words[0] = dst.words[3]; yann@1: + dst.words[1] = dst.words[2]; yann@1: + dst.words[2] = tmp2; yann@1: + dst.words[3] = tmp1; yann@1: + } yann@1: +#else yann@1: + { yann@1: + halffractype tmp = dst.words[0]; yann@1: + dst.words[0] = dst.words[1]; yann@1: + dst.words[1] = tmp; yann@1: + } yann@1: +#endif yann@1: +#endif yann@1: + yann@1: + return dst.value; yann@1: +} yann@1: +#endif yann@1: + yann@1: +#if defined(L_unpack_df) || defined(L_unpack_sf) || defined(L_unpack_tf) yann@1: +void yann@1: +unpack_d (FLO_union_type * src, fp_number_type * dst) yann@1: +{ yann@1: + /* We previously used bitfields to store the number, but this doesn't yann@1: + handle little/big endian systems conveniently, so use shifts and yann@1: + masks */ yann@1: + fractype fraction; yann@1: + int exp; yann@1: + int sign; yann@1: + yann@1: +#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT) yann@1: + FLO_union_type swapped; yann@1: + yann@1: +#ifdef TFLOAT yann@1: + swapped.words[0] = src->words[3]; yann@1: + swapped.words[1] = src->words[2]; yann@1: + swapped.words[2] = src->words[1]; yann@1: + swapped.words[3] = src->words[0]; yann@1: +#else yann@1: + swapped.words[0] = src->words[1]; yann@1: + swapped.words[1] = src->words[0]; yann@1: +#endif yann@1: + src = &swapped; yann@1: +#endif yann@1: + yann@1: +#ifdef FLOAT_BIT_ORDER_MISMATCH yann@1: + fraction = src->bits.fraction; yann@1: + exp = src->bits.exp; yann@1: + sign = src->bits.sign; yann@1: +#else yann@1: +# if defined TFLOAT && defined HALFFRACBITS yann@1: + { yann@1: + halffractype high, low; yann@1: + yann@1: + high = src->value_raw >> HALFSHIFT; yann@1: + low = src->value_raw & (((fractype)1 << HALFSHIFT) - 1); yann@1: + yann@1: + fraction = high & ((((fractype)1) << HALFFRACBITS) - 1); yann@1: + fraction <<= FRACBITS - HALFFRACBITS; yann@1: + exp = ((int)(high >> HALFFRACBITS)) & ((1 << EXPBITS) - 1); yann@1: + sign = ((int)(high >> (((HALFFRACBITS + EXPBITS))))) & 1; yann@1: + yann@1: + if (exp != EXPMAX && exp != 0 && low != 0) yann@1: + { yann@1: + int lowexp = ((int)(low >> HALFFRACBITS)) & ((1 << EXPBITS) - 1); yann@1: + int lowsign = ((int)(low >> (((HALFFRACBITS + EXPBITS))))) & 1; yann@1: + int shift; yann@1: + fractype xlow; yann@1: + yann@1: + xlow = low & ((((fractype)1) << HALFFRACBITS) - 1); yann@1: + if (lowexp) yann@1: + xlow |= (((halffractype)1) << HALFFRACBITS); yann@1: + else yann@1: + lowexp = 1; yann@1: + shift = (FRACBITS - HALFFRACBITS) - (exp - lowexp); yann@1: + if (shift > 0) yann@1: + xlow <<= shift; yann@1: + else if (shift < 0) yann@1: + xlow >>= -shift; yann@1: + if (sign == lowsign) yann@1: + fraction += xlow; yann@1: + else if (fraction >= xlow) yann@1: + fraction -= xlow; yann@1: + else yann@1: + { yann@1: + /* The high part is a power of two but the full number is lower. yann@1: + This code will leave the implicit 1 in FRACTION, but we'd yann@1: + have added that below anyway. */ yann@1: + fraction = (((fractype) 1 << FRACBITS) - xlow) << 1; yann@1: + exp--; yann@1: + } yann@1: + } yann@1: + } yann@1: +# else yann@1: + fraction = src->value_raw & ((((fractype)1) << FRACBITS) - 1); yann@1: + exp = ((int)(src->value_raw >> FRACBITS)) & ((1 << EXPBITS) - 1); yann@1: + sign = ((int)(src->value_raw >> (FRACBITS + EXPBITS))) & 1; yann@1: +# endif yann@1: +#endif yann@1: + yann@1: + dst->sign = sign; yann@1: + if (exp == 0) yann@1: + { yann@1: + /* Hmm. Looks like 0 */ yann@1: + if (fraction == 0 yann@1: +#ifdef NO_DENORMALS yann@1: + || 1 yann@1: +#endif yann@1: + ) yann@1: + { yann@1: + /* tastes like zero */ yann@1: + dst->class = CLASS_ZERO; yann@1: + } yann@1: + else yann@1: + { yann@1: + /* Zero exponent with nonzero fraction - it's denormalized, yann@1: + so there isn't a leading implicit one - we'll shift it so yann@1: + it gets one. */ yann@1: + dst->normal_exp = exp - EXPBIAS + 1; yann@1: + fraction <<= NGARDS; yann@1: + yann@1: + dst->class = CLASS_NUMBER; yann@1: +#if 1 yann@1: + while (fraction < IMPLICIT_1) yann@1: + { yann@1: + fraction <<= 1; yann@1: + dst->normal_exp--; yann@1: + } yann@1: +#endif yann@1: + dst->fraction.ll = fraction; yann@1: + } yann@1: + } yann@1: + else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp == EXPMAX) yann@1: + { yann@1: + /* Huge exponent*/ yann@1: + if (fraction == 0) yann@1: + { yann@1: + /* Attached to a zero fraction - means infinity */ yann@1: + dst->class = CLASS_INFINITY; yann@1: + } yann@1: + else yann@1: + { yann@1: + /* Nonzero fraction, means nan */ yann@1: +#ifdef QUIET_NAN_NEGATED yann@1: + if ((fraction & QUIET_NAN) == 0) yann@1: +#else yann@1: + if (fraction & QUIET_NAN) yann@1: +#endif yann@1: + { yann@1: + dst->class = CLASS_QNAN; yann@1: + } yann@1: + else yann@1: + { yann@1: + dst->class = CLASS_SNAN; yann@1: + } yann@1: + /* Keep the fraction part as the nan number */ yann@1: + dst->fraction.ll = fraction; yann@1: + } yann@1: + } yann@1: + else yann@1: + { yann@1: + /* Nothing strange about this number */ yann@1: + dst->normal_exp = exp - EXPBIAS; yann@1: + dst->class = CLASS_NUMBER; yann@1: + dst->fraction.ll = (fraction << NGARDS) | IMPLICIT_1; yann@1: + } yann@1: +} yann@1: +#endif /* L_unpack_df || L_unpack_sf */ yann@1: + yann@1: +#if defined(L_addsub_sf) || defined(L_addsub_df) || defined(L_addsub_tf) yann@1: +static fp_number_type * yann@1: +_fpadd_parts (fp_number_type * a, yann@1: + fp_number_type * b, yann@1: + fp_number_type * tmp) yann@1: +{ yann@1: + intfrac tfraction; yann@1: + yann@1: + /* Put commonly used fields in local variables. */ yann@1: + int a_normal_exp; yann@1: + int b_normal_exp; yann@1: + fractype a_fraction; yann@1: + fractype b_fraction; yann@1: + yann@1: + if (isnan (a)) yann@1: + { yann@1: + return a; yann@1: + } yann@1: + if (isnan (b)) yann@1: + { yann@1: + return b; yann@1: + } yann@1: + if (isinf (a)) yann@1: + { yann@1: + /* Adding infinities with opposite signs yields a NaN. */ yann@1: + if (isinf (b) && a->sign != b->sign) yann@1: + return nan (); yann@1: + return a; yann@1: + } yann@1: + if (isinf (b)) yann@1: + { yann@1: + return b; yann@1: + } yann@1: + if (iszero (b)) yann@1: + { yann@1: + if (iszero (a)) yann@1: + { yann@1: + *tmp = *a; yann@1: + tmp->sign = a->sign & b->sign; yann@1: + return tmp; yann@1: + } yann@1: + return a; yann@1: + } yann@1: + if (iszero (a)) yann@1: + { yann@1: + return b; yann@1: + } yann@1: + yann@1: + /* Got two numbers. shift the smaller and increment the exponent till yann@1: + they're the same */ yann@1: + { yann@1: + int diff; yann@1: + yann@1: + a_normal_exp = a->normal_exp; yann@1: + b_normal_exp = b->normal_exp; yann@1: + a_fraction = a->fraction.ll; yann@1: + b_fraction = b->fraction.ll; yann@1: + yann@1: + diff = a_normal_exp - b_normal_exp; yann@1: + yann@1: + if (diff < 0) yann@1: + diff = -diff; yann@1: + if (diff < FRAC_NBITS) yann@1: + { yann@1: + /* ??? This does shifts one bit at a time. Optimize. */ yann@1: + while (a_normal_exp > b_normal_exp) yann@1: + { yann@1: + b_normal_exp++; yann@1: + LSHIFT (b_fraction); yann@1: + } yann@1: + while (b_normal_exp > a_normal_exp) yann@1: + { yann@1: + a_normal_exp++; yann@1: + LSHIFT (a_fraction); yann@1: + } yann@1: + } yann@1: + else yann@1: + { yann@1: + /* Somethings's up.. choose the biggest */ yann@1: + if (a_normal_exp > b_normal_exp) yann@1: + { yann@1: + b_normal_exp = a_normal_exp; yann@1: + b_fraction = 0; yann@1: + } yann@1: + else yann@1: + { yann@1: + a_normal_exp = b_normal_exp; yann@1: + a_fraction = 0; yann@1: + } yann@1: + } yann@1: + } yann@1: + yann@1: + if (a->sign != b->sign) yann@1: + { yann@1: + if (a->sign) yann@1: + { yann@1: + tfraction = -a_fraction + b_fraction; yann@1: + } yann@1: + else yann@1: + { yann@1: + tfraction = a_fraction - b_fraction; yann@1: + } yann@1: + if (tfraction >= 0) yann@1: + { yann@1: + tmp->sign = 0; yann@1: + tmp->normal_exp = a_normal_exp; yann@1: + tmp->fraction.ll = tfraction; yann@1: + } yann@1: + else yann@1: + { yann@1: + tmp->sign = 1; yann@1: + tmp->normal_exp = a_normal_exp; yann@1: + tmp->fraction.ll = -tfraction; yann@1: + } yann@1: + /* and renormalize it */ yann@1: + yann@1: + while (tmp->fraction.ll < IMPLICIT_1 && tmp->fraction.ll) yann@1: + { yann@1: + tmp->fraction.ll <<= 1; yann@1: + tmp->normal_exp--; yann@1: + } yann@1: + } yann@1: + else yann@1: + { yann@1: + tmp->sign = a->sign; yann@1: + tmp->normal_exp = a_normal_exp; yann@1: + tmp->fraction.ll = a_fraction + b_fraction; yann@1: + } yann@1: + tmp->class = CLASS_NUMBER; yann@1: + /* Now the fraction is added, we have to shift down to renormalize the yann@1: + number */ yann@1: + yann@1: + if (tmp->fraction.ll >= IMPLICIT_2) yann@1: + { yann@1: + LSHIFT (tmp->fraction.ll); yann@1: + tmp->normal_exp++; yann@1: + } yann@1: + return tmp; yann@1: + yann@1: +} yann@1: + yann@1: +FLO_type yann@1: +add (FLO_type arg_a, FLO_type arg_b) yann@1: +{ yann@1: + fp_number_type a; yann@1: + fp_number_type b; yann@1: + fp_number_type tmp; yann@1: + fp_number_type *res; yann@1: + FLO_union_type au, bu; yann@1: + yann@1: + au.value = arg_a; yann@1: + bu.value = arg_b; yann@1: + yann@1: + unpack_d (&au, &a); yann@1: + unpack_d (&bu, &b); yann@1: + yann@1: + res = _fpadd_parts (&a, &b, &tmp); yann@1: + yann@1: + return pack_d (res); yann@1: +} yann@1: + yann@1: +FLO_type yann@1: +sub (FLO_type arg_a, FLO_type arg_b) yann@1: +{ yann@1: + fp_number_type a; yann@1: + fp_number_type b; yann@1: + fp_number_type tmp; yann@1: + fp_number_type *res; yann@1: + FLO_union_type au, bu; yann@1: + yann@1: + au.value = arg_a; yann@1: + bu.value = arg_b; yann@1: + yann@1: + unpack_d (&au, &a); yann@1: + unpack_d (&bu, &b); yann@1: + yann@1: + b.sign ^= 1; yann@1: + yann@1: + res = _fpadd_parts (&a, &b, &tmp); yann@1: + yann@1: + return pack_d (res); yann@1: +} yann@1: +#endif /* L_addsub_sf || L_addsub_df */ yann@1: + yann@1: +#if defined(L_mul_sf) || defined(L_mul_df) || defined(L_mul_tf) yann@1: +static inline __attribute__ ((__always_inline__)) fp_number_type * yann@1: +_fpmul_parts ( fp_number_type * a, yann@1: + fp_number_type * b, yann@1: + fp_number_type * tmp) yann@1: +{ yann@1: + fractype low = 0; yann@1: + fractype high = 0; yann@1: + yann@1: + if (isnan (a)) yann@1: + { yann@1: + a->sign = a->sign != b->sign; yann@1: + return a; yann@1: + } yann@1: + if (isnan (b)) yann@1: + { yann@1: + b->sign = a->sign != b->sign; yann@1: + return b; yann@1: + } yann@1: + if (isinf (a)) yann@1: + { yann@1: + if (iszero (b)) yann@1: + return nan (); yann@1: + a->sign = a->sign != b->sign; yann@1: + return a; yann@1: + } yann@1: + if (isinf (b)) yann@1: + { yann@1: + if (iszero (a)) yann@1: + { yann@1: + return nan (); yann@1: + } yann@1: + b->sign = a->sign != b->sign; yann@1: + return b; yann@1: + } yann@1: + if (iszero (a)) yann@1: + { yann@1: + a->sign = a->sign != b->sign; yann@1: + return a; yann@1: + } yann@1: + if (iszero (b)) yann@1: + { yann@1: + b->sign = a->sign != b->sign; yann@1: + return b; yann@1: + } yann@1: + yann@1: + /* Calculate the mantissa by multiplying both numbers to get a yann@1: + twice-as-wide number. */ yann@1: + { yann@1: +#if defined(NO_DI_MODE) || defined(TFLOAT) yann@1: + { yann@1: + fractype x = a->fraction.ll; yann@1: + fractype ylow = b->fraction.ll; yann@1: + fractype yhigh = 0; yann@1: + int bit; yann@1: + yann@1: + /* ??? This does multiplies one bit at a time. Optimize. */ yann@1: + for (bit = 0; bit < FRAC_NBITS; bit++) yann@1: + { yann@1: + int carry; yann@1: + yann@1: + if (x & 1) yann@1: + { yann@1: + carry = (low += ylow) < ylow; yann@1: + high += yhigh + carry; yann@1: + } yann@1: + yhigh <<= 1; yann@1: + if (ylow & FRACHIGH) yann@1: + { yann@1: + yhigh |= 1; yann@1: + } yann@1: + ylow <<= 1; yann@1: + x >>= 1; yann@1: + } yann@1: + } yann@1: +#elif defined(FLOAT) yann@1: + /* Multiplying two USIs to get a UDI, we're safe. */ yann@1: + { yann@1: + UDItype answer = (UDItype)a->fraction.ll * (UDItype)b->fraction.ll; yann@1: + yann@1: + high = answer >> BITS_PER_SI; yann@1: + low = answer; yann@1: + } yann@1: +#else yann@1: + /* fractype is DImode, but we need the result to be twice as wide. yann@1: + Assuming a widening multiply from DImode to TImode is not yann@1: + available, build one by hand. */ yann@1: + { yann@1: + USItype nl = a->fraction.ll; yann@1: + USItype nh = a->fraction.ll >> BITS_PER_SI; yann@1: + USItype ml = b->fraction.ll; yann@1: + USItype mh = b->fraction.ll >> BITS_PER_SI; yann@1: + UDItype pp_ll = (UDItype) ml * nl; yann@1: + UDItype pp_hl = (UDItype) mh * nl; yann@1: + UDItype pp_lh = (UDItype) ml * nh; yann@1: + UDItype pp_hh = (UDItype) mh * nh; yann@1: + UDItype res2 = 0; yann@1: + UDItype res0 = 0; yann@1: + UDItype ps_hh__ = pp_hl + pp_lh; yann@1: + if (ps_hh__ < pp_hl) yann@1: + res2 += (UDItype)1 << BITS_PER_SI; yann@1: + pp_hl = (UDItype)(USItype)ps_hh__ << BITS_PER_SI; yann@1: + res0 = pp_ll + pp_hl; yann@1: + if (res0 < pp_ll) yann@1: + res2++; yann@1: + res2 += (ps_hh__ >> BITS_PER_SI) + pp_hh; yann@1: + high = res2; yann@1: + low = res0; yann@1: + } yann@1: +#endif yann@1: + } yann@1: + yann@1: + tmp->normal_exp = a->normal_exp + b->normal_exp yann@1: + + FRAC_NBITS - (FRACBITS + NGARDS); yann@1: + tmp->sign = a->sign != b->sign; yann@1: + while (high >= IMPLICIT_2) yann@1: + { yann@1: + tmp->normal_exp++; yann@1: + if (high & 1) yann@1: + { yann@1: + low >>= 1; yann@1: + low |= FRACHIGH; yann@1: + } yann@1: + high >>= 1; yann@1: + } yann@1: + while (high < IMPLICIT_1) yann@1: + { yann@1: + tmp->normal_exp--; yann@1: + yann@1: + high <<= 1; yann@1: + if (low & FRACHIGH) yann@1: + high |= 1; yann@1: + low <<= 1; yann@1: + } yann@1: + /* rounding is tricky. if we only round if it won't make us round later. */ yann@1: +#if 0 yann@1: + if (low & FRACHIGH2) yann@1: + { yann@1: + if (((high & GARDMASK) != GARDMSB) yann@1: + && (((high + 1) & GARDMASK) == GARDMSB)) yann@1: + { yann@1: + /* don't round, it gets done again later. */ yann@1: + } yann@1: + else yann@1: + { yann@1: + high++; yann@1: + } yann@1: + } yann@1: +#endif yann@1: + if (!ROUND_TOWARDS_ZERO && (high & GARDMASK) == GARDMSB) yann@1: + { yann@1: + if (high & (1 << NGARDS)) yann@1: + { yann@1: + /* half way, so round to even */ yann@1: + high += GARDROUND + 1; yann@1: + } yann@1: + else if (low) yann@1: + { yann@1: + /* but we really weren't half way */ yann@1: + high += GARDROUND + 1; yann@1: + } yann@1: + } yann@1: + tmp->fraction.ll = high; yann@1: + tmp->class = CLASS_NUMBER; yann@1: + return tmp; yann@1: +} yann@1: + yann@1: +FLO_type yann@1: +multiply (FLO_type arg_a, FLO_type arg_b) yann@1: +{ yann@1: + fp_number_type a; yann@1: + fp_number_type b; yann@1: + fp_number_type tmp; yann@1: + fp_number_type *res; yann@1: + FLO_union_type au, bu; yann@1: + yann@1: + au.value = arg_a; yann@1: + bu.value = arg_b; yann@1: + yann@1: + unpack_d (&au, &a); yann@1: + unpack_d (&bu, &b); yann@1: + yann@1: + res = _fpmul_parts (&a, &b, &tmp); yann@1: + yann@1: + return pack_d (res); yann@1: +} yann@1: +#endif /* L_mul_sf || L_mul_df */ yann@1: + yann@1: +#if defined(L_div_sf) || defined(L_div_df) || defined(L_div_tf) yann@1: +static inline __attribute__ ((__always_inline__)) fp_number_type * yann@1: +_fpdiv_parts (fp_number_type * a, yann@1: + fp_number_type * b) yann@1: +{ yann@1: + fractype bit; yann@1: + fractype numerator; yann@1: + fractype denominator; yann@1: + fractype quotient; yann@1: + yann@1: + if (isnan (a)) yann@1: + { yann@1: + return a; yann@1: + } yann@1: + if (isnan (b)) yann@1: + { yann@1: + return b; yann@1: + } yann@1: + yann@1: + a->sign = a->sign ^ b->sign; yann@1: + yann@1: + if (isinf (a) || iszero (a)) yann@1: + { yann@1: + if (a->class == b->class) yann@1: + return nan (); yann@1: + return a; yann@1: + } yann@1: + yann@1: + if (isinf (b)) yann@1: + { yann@1: + a->fraction.ll = 0; yann@1: + a->normal_exp = 0; yann@1: + return a; yann@1: + } yann@1: + if (iszero (b)) yann@1: + { yann@1: + a->class = CLASS_INFINITY; yann@1: + return a; yann@1: + } yann@1: + yann@1: + /* Calculate the mantissa by multiplying both 64bit numbers to get a yann@1: + 128 bit number */ yann@1: + { yann@1: + /* quotient = yann@1: + ( numerator / denominator) * 2^(numerator exponent - denominator exponent) yann@1: + */ yann@1: + yann@1: + a->normal_exp = a->normal_exp - b->normal_exp; yann@1: + numerator = a->fraction.ll; yann@1: + denominator = b->fraction.ll; yann@1: + yann@1: + if (numerator < denominator) yann@1: + { yann@1: + /* Fraction will be less than 1.0 */ yann@1: + numerator *= 2; yann@1: + a->normal_exp--; yann@1: + } yann@1: + bit = IMPLICIT_1; yann@1: + quotient = 0; yann@1: + /* ??? Does divide one bit at a time. Optimize. */ yann@1: + while (bit) yann@1: + { yann@1: + if (numerator >= denominator) yann@1: + { yann@1: + quotient |= bit; yann@1: + numerator -= denominator; yann@1: + } yann@1: + bit >>= 1; yann@1: + numerator *= 2; yann@1: + } yann@1: + yann@1: + if (!ROUND_TOWARDS_ZERO && (quotient & GARDMASK) == GARDMSB) yann@1: + { yann@1: + if (quotient & (1 << NGARDS)) yann@1: + { yann@1: + /* half way, so round to even */ yann@1: + quotient += GARDROUND + 1; yann@1: + } yann@1: + else if (numerator) yann@1: + { yann@1: + /* but we really weren't half way, more bits exist */ yann@1: + quotient += GARDROUND + 1; yann@1: + } yann@1: + } yann@1: + yann@1: + a->fraction.ll = quotient; yann@1: + return (a); yann@1: + } yann@1: +} yann@1: + yann@1: +FLO_type yann@1: +divide (FLO_type arg_a, FLO_type arg_b) yann@1: +{ yann@1: + fp_number_type a; yann@1: + fp_number_type b; yann@1: + fp_number_type *res; yann@1: + FLO_union_type au, bu; yann@1: + yann@1: + au.value = arg_a; yann@1: + bu.value = arg_b; yann@1: + yann@1: + unpack_d (&au, &a); yann@1: + unpack_d (&bu, &b); yann@1: + yann@1: + res = _fpdiv_parts (&a, &b); yann@1: + yann@1: + return pack_d (res); yann@1: +} yann@1: +#endif /* L_div_sf || L_div_df */ yann@1: + yann@1: +#if defined(L_fpcmp_parts_sf) || defined(L_fpcmp_parts_df) \ yann@1: + || defined(L_fpcmp_parts_tf) yann@1: +/* according to the demo, fpcmp returns a comparison with 0... thus yann@1: + a -1 yann@1: + a==b -> 0 yann@1: + a>b -> +1 yann@1: + */ yann@1: + yann@1: +int yann@1: +__fpcmp_parts (fp_number_type * a, fp_number_type * b) yann@1: +{ yann@1: +#if 0 yann@1: + /* either nan -> unordered. Must be checked outside of this routine. */ yann@1: + if (isnan (a) && isnan (b)) yann@1: + { yann@1: + return 1; /* still unordered! */ yann@1: + } yann@1: +#endif yann@1: + yann@1: + if (isnan (a) || isnan (b)) yann@1: + { yann@1: + return 1; /* how to indicate unordered compare? */ yann@1: + } yann@1: + if (isinf (a) && isinf (b)) yann@1: + { yann@1: + /* +inf > -inf, but +inf != +inf */ yann@1: + /* b \a| +inf(0)| -inf(1) yann@1: + ______\+--------+-------- yann@1: + +inf(0)| a==b(0)| ab(1) | a==b(0) yann@1: + -------+--------+-------- yann@1: + So since unordered must be nonzero, just line up the columns... yann@1: + */ yann@1: + return b->sign - a->sign; yann@1: + } yann@1: + /* but not both... */ yann@1: + if (isinf (a)) yann@1: + { yann@1: + return a->sign ? -1 : 1; yann@1: + } yann@1: + if (isinf (b)) yann@1: + { yann@1: + return b->sign ? 1 : -1; yann@1: + } yann@1: + if (iszero (a) && iszero (b)) yann@1: + { yann@1: + return 0; yann@1: + } yann@1: + if (iszero (a)) yann@1: + { yann@1: + return b->sign ? 1 : -1; yann@1: + } yann@1: + if (iszero (b)) yann@1: + { yann@1: + return a->sign ? -1 : 1; yann@1: + } yann@1: + /* now both are "normal". */ yann@1: + if (a->sign != b->sign) yann@1: + { yann@1: + /* opposite signs */ yann@1: + return a->sign ? -1 : 1; yann@1: + } yann@1: + /* same sign; exponents? */ yann@1: + if (a->normal_exp > b->normal_exp) yann@1: + { yann@1: + return a->sign ? -1 : 1; yann@1: + } yann@1: + if (a->normal_exp < b->normal_exp) yann@1: + { yann@1: + return a->sign ? 1 : -1; yann@1: + } yann@1: + /* same exponents; check size. */ yann@1: + if (a->fraction.ll > b->fraction.ll) yann@1: + { yann@1: + return a->sign ? -1 : 1; yann@1: + } yann@1: + if (a->fraction.ll < b->fraction.ll) yann@1: + { yann@1: + return a->sign ? 1 : -1; yann@1: + } yann@1: + /* after all that, they're equal. */ yann@1: + return 0; yann@1: +} yann@1: +#endif yann@1: + yann@1: +#if defined(L_compare_sf) || defined(L_compare_df) || defined(L_compoare_tf) yann@1: +CMPtype yann@1: +compare (FLO_type arg_a, FLO_type arg_b) yann@1: +{ yann@1: + fp_number_type a; yann@1: + fp_number_type b; yann@1: + FLO_union_type au, bu; yann@1: + yann@1: + au.value = arg_a; yann@1: + bu.value = arg_b; yann@1: + yann@1: + unpack_d (&au, &a); yann@1: + unpack_d (&bu, &b); yann@1: + yann@1: + return __fpcmp_parts (&a, &b); yann@1: +} yann@1: +#endif /* L_compare_sf || L_compare_df */ yann@1: + yann@1: +#ifndef US_SOFTWARE_GOFAST yann@1: + yann@1: +/* These should be optimized for their specific tasks someday. */ yann@1: + yann@1: +#if defined(L_eq_sf) || defined(L_eq_df) || defined(L_eq_tf) yann@1: +CMPtype yann@1: +_eq_f2 (FLO_type arg_a, FLO_type arg_b) yann@1: +{ yann@1: + fp_number_type a; yann@1: + fp_number_type b; yann@1: + FLO_union_type au, bu; yann@1: + yann@1: + au.value = arg_a; yann@1: + bu.value = arg_b; yann@1: + yann@1: + unpack_d (&au, &a); yann@1: + unpack_d (&bu, &b); yann@1: + yann@1: + if (isnan (&a) || isnan (&b)) yann@1: + return 1; /* false, truth == 0 */ yann@1: + yann@1: + return __fpcmp_parts (&a, &b) ; yann@1: +} yann@1: +#endif /* L_eq_sf || L_eq_df */ yann@1: + yann@1: +#if defined(L_ne_sf) || defined(L_ne_df) || defined(L_ne_tf) yann@1: +CMPtype yann@1: +_ne_f2 (FLO_type arg_a, FLO_type arg_b) yann@1: +{ yann@1: + fp_number_type a; yann@1: + fp_number_type b; yann@1: + FLO_union_type au, bu; yann@1: + yann@1: + au.value = arg_a; yann@1: + bu.value = arg_b; yann@1: + yann@1: + unpack_d (&au, &a); yann@1: + unpack_d (&bu, &b); yann@1: + yann@1: + if (isnan (&a) || isnan (&b)) yann@1: + return 1; /* true, truth != 0 */ yann@1: + yann@1: + return __fpcmp_parts (&a, &b) ; yann@1: +} yann@1: +#endif /* L_ne_sf || L_ne_df */ yann@1: + yann@1: +#if defined(L_gt_sf) || defined(L_gt_df) || defined(L_gt_tf) yann@1: +CMPtype yann@1: +_gt_f2 (FLO_type arg_a, FLO_type arg_b) yann@1: +{ yann@1: + fp_number_type a; yann@1: + fp_number_type b; yann@1: + FLO_union_type au, bu; yann@1: + yann@1: + au.value = arg_a; yann@1: + bu.value = arg_b; yann@1: + yann@1: + unpack_d (&au, &a); yann@1: + unpack_d (&bu, &b); yann@1: + yann@1: + if (isnan (&a) || isnan (&b)) yann@1: + return -1; /* false, truth > 0 */ yann@1: + yann@1: + return __fpcmp_parts (&a, &b); yann@1: +} yann@1: +#endif /* L_gt_sf || L_gt_df */ yann@1: + yann@1: +#if defined(L_ge_sf) || defined(L_ge_df) || defined(L_ge_tf) yann@1: +CMPtype yann@1: +_ge_f2 (FLO_type arg_a, FLO_type arg_b) yann@1: +{ yann@1: + fp_number_type a; yann@1: + fp_number_type b; yann@1: + FLO_union_type au, bu; yann@1: + yann@1: + au.value = arg_a; yann@1: + bu.value = arg_b; yann@1: + yann@1: + unpack_d (&au, &a); yann@1: + unpack_d (&bu, &b); yann@1: + yann@1: + if (isnan (&a) || isnan (&b)) yann@1: + return -1; /* false, truth >= 0 */ yann@1: + return __fpcmp_parts (&a, &b) ; yann@1: +} yann@1: +#endif /* L_ge_sf || L_ge_df */ yann@1: + yann@1: +#if defined(L_lt_sf) || defined(L_lt_df) || defined(L_lt_tf) yann@1: +CMPtype yann@1: +_lt_f2 (FLO_type arg_a, FLO_type arg_b) yann@1: +{ yann@1: + fp_number_type a; yann@1: + fp_number_type b; yann@1: + FLO_union_type au, bu; yann@1: + yann@1: + au.value = arg_a; yann@1: + bu.value = arg_b; yann@1: + yann@1: + unpack_d (&au, &a); yann@1: + unpack_d (&bu, &b); yann@1: + yann@1: + if (isnan (&a) || isnan (&b)) yann@1: + return 1; /* false, truth < 0 */ yann@1: + yann@1: + return __fpcmp_parts (&a, &b); yann@1: +} yann@1: +#endif /* L_lt_sf || L_lt_df */ yann@1: + yann@1: +#if defined(L_le_sf) || defined(L_le_df) || defined(L_le_tf) yann@1: +CMPtype yann@1: +_le_f2 (FLO_type arg_a, FLO_type arg_b) yann@1: +{ yann@1: + fp_number_type a; yann@1: + fp_number_type b; yann@1: + FLO_union_type au, bu; yann@1: + yann@1: + au.value = arg_a; yann@1: + bu.value = arg_b; yann@1: + yann@1: + unpack_d (&au, &a); yann@1: + unpack_d (&bu, &b); yann@1: + yann@1: + if (isnan (&a) || isnan (&b)) yann@1: + return 1; /* false, truth <= 0 */ yann@1: + yann@1: + return __fpcmp_parts (&a, &b) ; yann@1: +} yann@1: +#endif /* L_le_sf || L_le_df */ yann@1: + yann@1: +#endif /* ! US_SOFTWARE_GOFAST */ yann@1: + yann@1: +#if defined(L_unord_sf) || defined(L_unord_df) || defined(L_unord_tf) yann@1: +CMPtype yann@1: +_unord_f2 (FLO_type arg_a, FLO_type arg_b) yann@1: +{ yann@1: + fp_number_type a; yann@1: + fp_number_type b; yann@1: + FLO_union_type au, bu; yann@1: + yann@1: + au.value = arg_a; yann@1: + bu.value = arg_b; yann@1: + yann@1: + unpack_d (&au, &a); yann@1: + unpack_d (&bu, &b); yann@1: + yann@1: + return (isnan (&a) || isnan (&b)); yann@1: +} yann@1: +#endif /* L_unord_sf || L_unord_df */ yann@1: + yann@1: +#if defined(L_si_to_sf) || defined(L_si_to_df) || defined(L_si_to_tf) yann@1: +FLO_type yann@1: +si_to_float (SItype arg_a) yann@1: +{ yann@1: + fp_number_type in; yann@1: + yann@1: + in.class = CLASS_NUMBER; yann@1: + in.sign = arg_a < 0; yann@1: + if (!arg_a) yann@1: + { yann@1: + in.class = CLASS_ZERO; yann@1: + } yann@1: + else yann@1: + { yann@1: + in.normal_exp = FRACBITS + NGARDS; yann@1: + if (in.sign) yann@1: + { yann@1: + /* Special case for minint, since there is no +ve integer yann@1: + representation for it */ yann@1: + if (arg_a == (- MAX_SI_INT - 1)) yann@1: + { yann@1: + return (FLO_type)(- MAX_SI_INT - 1); yann@1: + } yann@1: + in.fraction.ll = (-arg_a); yann@1: + } yann@1: + else yann@1: + in.fraction.ll = arg_a; yann@1: + yann@1: + while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS))) yann@1: + { yann@1: + in.fraction.ll <<= 1; yann@1: + in.normal_exp -= 1; yann@1: + } yann@1: + } yann@1: + return pack_d (&in); yann@1: +} yann@1: +#endif /* L_si_to_sf || L_si_to_df */ yann@1: + yann@1: +#if defined(L_usi_to_sf) || defined(L_usi_to_df) || defined(L_usi_to_tf) yann@1: +FLO_type yann@1: +usi_to_float (USItype arg_a) yann@1: +{ yann@1: + fp_number_type in; yann@1: + yann@1: + in.sign = 0; yann@1: + if (!arg_a) yann@1: + { yann@1: + in.class = CLASS_ZERO; yann@1: + } yann@1: + else yann@1: + { yann@1: + in.class = CLASS_NUMBER; yann@1: + in.normal_exp = FRACBITS + NGARDS; yann@1: + in.fraction.ll = arg_a; yann@1: + yann@1: + while (in.fraction.ll > ((fractype)1 << (FRACBITS + NGARDS))) yann@1: + { yann@1: + in.fraction.ll >>= 1; yann@1: + in.normal_exp += 1; yann@1: + } yann@1: + while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS))) yann@1: + { yann@1: + in.fraction.ll <<= 1; yann@1: + in.normal_exp -= 1; yann@1: + } yann@1: + } yann@1: + return pack_d (&in); yann@1: +} yann@1: +#endif yann@1: + yann@1: +#if defined(L_sf_to_si) || defined(L_df_to_si) || defined(L_tf_to_si) yann@1: +SItype yann@1: +float_to_si (FLO_type arg_a) yann@1: +{ yann@1: + fp_number_type a; yann@1: + SItype tmp; yann@1: + FLO_union_type au; yann@1: + yann@1: + au.value = arg_a; yann@1: + unpack_d (&au, &a); yann@1: + yann@1: + if (iszero (&a)) yann@1: + return 0; yann@1: + if (isnan (&a)) yann@1: + return 0; yann@1: + /* get reasonable MAX_SI_INT... */ yann@1: + if (isinf (&a)) yann@1: + return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT; yann@1: + /* it is a number, but a small one */ yann@1: + if (a.normal_exp < 0) yann@1: + return 0; yann@1: + if (a.normal_exp > BITS_PER_SI - 2) yann@1: + return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT; yann@1: + tmp = a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp); yann@1: + return a.sign ? (-tmp) : (tmp); yann@1: +} yann@1: +#endif /* L_sf_to_si || L_df_to_si */ yann@1: + yann@1: +#if defined(L_sf_to_usi) || defined(L_df_to_usi) || defined(L_tf_to_usi) yann@1: +#if defined US_SOFTWARE_GOFAST || defined(L_tf_to_usi) yann@1: +/* While libgcc2.c defines its own __fixunssfsi and __fixunsdfsi routines, yann@1: + we also define them for GOFAST because the ones in libgcc2.c have the yann@1: + wrong names and I'd rather define these here and keep GOFAST CYG-LOC's yann@1: + out of libgcc2.c. We can't define these here if not GOFAST because then yann@1: + there'd be duplicate copies. */ yann@1: + yann@1: +USItype yann@1: +float_to_usi (FLO_type arg_a) yann@1: +{ yann@1: + fp_number_type a; yann@1: + FLO_union_type au; yann@1: + yann@1: + au.value = arg_a; yann@1: + unpack_d (&au, &a); yann@1: + yann@1: + if (iszero (&a)) yann@1: + return 0; yann@1: + if (isnan (&a)) yann@1: + return 0; yann@1: + /* it is a negative number */ yann@1: + if (a.sign) yann@1: + return 0; yann@1: + /* get reasonable MAX_USI_INT... */ yann@1: + if (isinf (&a)) yann@1: + return MAX_USI_INT; yann@1: + /* it is a number, but a small one */ yann@1: + if (a.normal_exp < 0) yann@1: + return 0; yann@1: + if (a.normal_exp > BITS_PER_SI - 1) yann@1: + return MAX_USI_INT; yann@1: + else if (a.normal_exp > (FRACBITS + NGARDS)) yann@1: + return a.fraction.ll << (a.normal_exp - (FRACBITS + NGARDS)); yann@1: + else yann@1: + return a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp); yann@1: +} yann@1: +#endif /* US_SOFTWARE_GOFAST */ yann@1: +#endif /* L_sf_to_usi || L_df_to_usi */ yann@1: + yann@1: +#if defined(L_negate_sf) || defined(L_negate_df) || defined(L_negate_tf) yann@1: +FLO_type yann@1: +negate (FLO_type arg_a) yann@1: +{ yann@1: + fp_number_type a; yann@1: + FLO_union_type au; yann@1: + yann@1: + au.value = arg_a; yann@1: + unpack_d (&au, &a); yann@1: + yann@1: + flip_sign (&a); yann@1: + return pack_d (&a); yann@1: +} yann@1: +#endif /* L_negate_sf || L_negate_df */ yann@1: + yann@1: +#ifdef FLOAT yann@1: + yann@1: +#if defined(L_make_sf) yann@1: +SFtype yann@1: +__make_fp(fp_class_type class, yann@1: + unsigned int sign, yann@1: + int exp, yann@1: + USItype frac) yann@1: +{ yann@1: + fp_number_type in; yann@1: + yann@1: + in.class = class; yann@1: + in.sign = sign; yann@1: + in.normal_exp = exp; yann@1: + in.fraction.ll = frac; yann@1: + return pack_d (&in); yann@1: +} yann@1: +#endif /* L_make_sf */ yann@1: + yann@1: +#ifndef FLOAT_ONLY yann@1: + yann@1: +/* This enables one to build an fp library that supports float but not double. yann@1: + Otherwise, we would get an undefined reference to __make_dp. yann@1: + This is needed for some 8-bit ports that can't handle well values that yann@1: + are 8-bytes in size, so we just don't support double for them at all. */ yann@1: + yann@1: +#if defined(L_sf_to_df) yann@1: +DFtype yann@1: +sf_to_df (SFtype arg_a) yann@1: +{ yann@1: + fp_number_type in; yann@1: + FLO_union_type au; yann@1: + yann@1: + au.value = arg_a; yann@1: + unpack_d (&au, &in); yann@1: + yann@1: + return __make_dp (in.class, in.sign, in.normal_exp, yann@1: + ((UDItype) in.fraction.ll) << F_D_BITOFF); yann@1: +} yann@1: +#endif /* L_sf_to_df */ yann@1: + yann@1: +#if defined(L_sf_to_tf) && defined(TMODES) yann@1: +TFtype yann@1: +sf_to_tf (SFtype arg_a) yann@1: +{ yann@1: + fp_number_type in; yann@1: + FLO_union_type au; yann@1: + yann@1: + au.value = arg_a; yann@1: + unpack_d (&au, &in); yann@1: + yann@1: + return __make_tp (in.class, in.sign, in.normal_exp, yann@1: + ((UTItype) in.fraction.ll) << F_T_BITOFF); yann@1: +} yann@1: +#endif /* L_sf_to_df */ yann@1: + yann@1: +#endif /* ! FLOAT_ONLY */ yann@1: +#endif /* FLOAT */ yann@1: + yann@1: +#ifndef FLOAT yann@1: + yann@1: +extern SFtype __make_fp (fp_class_type, unsigned int, int, USItype); yann@1: + yann@1: +#if defined(L_make_df) yann@1: +DFtype yann@1: +__make_dp (fp_class_type class, unsigned int sign, int exp, UDItype frac) yann@1: +{ yann@1: + fp_number_type in; yann@1: + yann@1: + in.class = class; yann@1: + in.sign = sign; yann@1: + in.normal_exp = exp; yann@1: + in.fraction.ll = frac; yann@1: + return pack_d (&in); yann@1: +} yann@1: +#endif /* L_make_df */ yann@1: + yann@1: +#if defined(L_df_to_sf) yann@1: +SFtype yann@1: +df_to_sf (DFtype arg_a) yann@1: +{ yann@1: + fp_number_type in; yann@1: + USItype sffrac; yann@1: + FLO_union_type au; yann@1: + yann@1: + au.value = arg_a; yann@1: + unpack_d (&au, &in); yann@1: + yann@1: + sffrac = in.fraction.ll >> F_D_BITOFF; yann@1: + yann@1: + /* We set the lowest guard bit in SFFRAC if we discarded any non yann@1: + zero bits. */ yann@1: + if ((in.fraction.ll & (((USItype) 1 << F_D_BITOFF) - 1)) != 0) yann@1: + sffrac |= 1; yann@1: + yann@1: + return __make_fp (in.class, in.sign, in.normal_exp, sffrac); yann@1: +} yann@1: +#endif /* L_df_to_sf */ yann@1: + yann@1: +#if defined(L_df_to_tf) && defined(TMODES) \ yann@1: + && !defined(FLOAT) && !defined(TFLOAT) yann@1: +TFtype yann@1: +df_to_tf (DFtype arg_a) yann@1: +{ yann@1: + fp_number_type in; yann@1: + FLO_union_type au; yann@1: + yann@1: + au.value = arg_a; yann@1: + unpack_d (&au, &in); yann@1: + yann@1: + return __make_tp (in.class, in.sign, in.normal_exp, yann@1: + ((UTItype) in.fraction.ll) << D_T_BITOFF); yann@1: +} yann@1: +#endif /* L_sf_to_df */ yann@1: + yann@1: +#ifdef TFLOAT yann@1: +#if defined(L_make_tf) yann@1: +TFtype yann@1: +__make_tp(fp_class_type class, yann@1: + unsigned int sign, yann@1: + int exp, yann@1: + UTItype frac) yann@1: +{ yann@1: + fp_number_type in; yann@1: + yann@1: + in.class = class; yann@1: + in.sign = sign; yann@1: + in.normal_exp = exp; yann@1: + in.fraction.ll = frac; yann@1: + return pack_d (&in); yann@1: +} yann@1: +#endif /* L_make_tf */ yann@1: + yann@1: +#if defined(L_tf_to_df) yann@1: +DFtype yann@1: +tf_to_df (TFtype arg_a) yann@1: +{ yann@1: + fp_number_type in; yann@1: + UDItype sffrac; yann@1: + FLO_union_type au; yann@1: + yann@1: + au.value = arg_a; yann@1: + unpack_d (&au, &in); yann@1: + yann@1: + sffrac = in.fraction.ll >> D_T_BITOFF; yann@1: + yann@1: + /* We set the lowest guard bit in SFFRAC if we discarded any non yann@1: + zero bits. */ yann@1: + if ((in.fraction.ll & (((UTItype) 1 << D_T_BITOFF) - 1)) != 0) yann@1: + sffrac |= 1; yann@1: + yann@1: + return __make_dp (in.class, in.sign, in.normal_exp, sffrac); yann@1: +} yann@1: +#endif /* L_tf_to_df */ yann@1: + yann@1: +#if defined(L_tf_to_sf) yann@1: +SFtype yann@1: +tf_to_sf (TFtype arg_a) yann@1: +{ yann@1: + fp_number_type in; yann@1: + USItype sffrac; yann@1: + FLO_union_type au; yann@1: + yann@1: + au.value = arg_a; yann@1: + unpack_d (&au, &in); yann@1: + yann@1: + sffrac = in.fraction.ll >> F_T_BITOFF; yann@1: + yann@1: + /* We set the lowest guard bit in SFFRAC if we discarded any non yann@1: + zero bits. */ yann@1: + if ((in.fraction.ll & (((UTItype) 1 << F_T_BITOFF) - 1)) != 0) yann@1: + sffrac |= 1; yann@1: + yann@1: + return __make_fp (in.class, in.sign, in.normal_exp, sffrac); yann@1: +} yann@1: +#endif /* L_tf_to_sf */ yann@1: +#endif /* TFLOAT */ yann@1: + yann@1: +#endif /* ! FLOAT */ yann@1: +#endif /* !EXTENDED_FLOAT_STUBS */ yann@1: --- gcc-3.4.3/gcc/config/nios2/nios2-fp-bit.c yann@1: +++ gcc-3.4.3-nios2/gcc/config/nios2/nios2-fp-bit.c yann@1: @@ -0,0 +1,1652 @@ yann@1: +#define FLOAT yann@1: +/* This is a software floating point library which can be used yann@1: + for targets without hardware floating point. yann@1: + Copyright (C) 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004 yann@1: + Free Software Foundation, Inc. yann@1: + yann@1: +This file is free software; you can redistribute it and/or modify it yann@1: +under the terms of the GNU General Public License as published by the yann@1: +Free Software Foundation; either version 2, or (at your option) any yann@1: +later version. yann@1: + yann@1: +In addition to the permissions in the GNU General Public License, the yann@1: +Free Software Foundation gives you unlimited permission to link the yann@1: +compiled version of this file with other programs, and to distribute yann@1: +those programs without any restriction coming from the use of this yann@1: +file. (The General Public License restrictions do apply in other yann@1: +respects; for example, they cover modification of the file, and yann@1: +distribution when not linked into another program.) yann@1: + yann@1: +This file is distributed in the hope that it will be useful, but yann@1: +WITHOUT ANY WARRANTY; without even the implied warranty of yann@1: +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yann@1: +General Public License for more details. yann@1: + yann@1: +You should have received a copy of the GNU General Public License yann@1: +along with this program; see the file COPYING. If not, write to yann@1: +the Free Software Foundation, 59 Temple Place - Suite 330, yann@1: +Boston, MA 02111-1307, USA. */ yann@1: + yann@1: +/* As a special exception, if you link this library with other files, yann@1: + some of which are compiled with GCC, to produce an executable, yann@1: + this library does not by itself cause the resulting executable yann@1: + to be covered by the GNU General Public License. yann@1: + This exception does not however invalidate any other reasons why yann@1: + the executable file might be covered by the GNU General Public License. */ yann@1: + yann@1: +/* This implements IEEE 754 format arithmetic, but does not provide a yann@1: + mechanism for setting the rounding mode, or for generating or handling yann@1: + exceptions. yann@1: + yann@1: + The original code by Steve Chamberlain, hacked by Mark Eichin and Jim yann@1: + Wilson, all of Cygnus Support. */ yann@1: + yann@1: +/* The intended way to use this file is to make two copies, add `#define FLOAT' yann@1: + to one copy, then compile both copies and add them to libgcc.a. */ yann@1: + yann@1: +#include "tconfig.h" yann@1: +#include "coretypes.h" yann@1: +#include "tm.h" yann@1: +#include "config/fp-bit.h" yann@1: + yann@1: +/* The following macros can be defined to change the behavior of this file: yann@1: + FLOAT: Implement a `float', aka SFmode, fp library. If this is not yann@1: + defined, then this file implements a `double', aka DFmode, fp library. yann@1: + FLOAT_ONLY: Used with FLOAT, to implement a `float' only library, i.e. yann@1: + don't include float->double conversion which requires the double library. yann@1: + This is useful only for machines which can't support doubles, e.g. some yann@1: + 8-bit processors. yann@1: + CMPtype: Specify the type that floating point compares should return. yann@1: + This defaults to SItype, aka int. yann@1: + US_SOFTWARE_GOFAST: This makes all entry points use the same names as the yann@1: + US Software goFast library. yann@1: + _DEBUG_BITFLOAT: This makes debugging the code a little easier, by adding yann@1: + two integers to the FLO_union_type. yann@1: + NO_DENORMALS: Disable handling of denormals. yann@1: + NO_NANS: Disable nan and infinity handling yann@1: + SMALL_MACHINE: Useful when operations on QIs and HIs are faster yann@1: + than on an SI */ yann@1: + yann@1: +/* We don't currently support extended floats (long doubles) on machines yann@1: + without hardware to deal with them. yann@1: + yann@1: + These stubs are just to keep the linker from complaining about unresolved yann@1: + references which can be pulled in from libio & libstdc++, even if the yann@1: + user isn't using long doubles. However, they may generate an unresolved yann@1: + external to abort if abort is not used by the function, and the stubs yann@1: + are referenced from within libc, since libgcc goes before and after the yann@1: + system library. */ yann@1: + yann@1: +#ifdef DECLARE_LIBRARY_RENAMES yann@1: + DECLARE_LIBRARY_RENAMES yann@1: +#endif yann@1: + yann@1: +#ifdef EXTENDED_FLOAT_STUBS yann@1: +extern void abort (void); yann@1: +void __extendsfxf2 (void) { abort(); } yann@1: +void __extenddfxf2 (void) { abort(); } yann@1: +void __truncxfdf2 (void) { abort(); } yann@1: +void __truncxfsf2 (void) { abort(); } yann@1: +void __fixxfsi (void) { abort(); } yann@1: +void __floatsixf (void) { abort(); } yann@1: +void __addxf3 (void) { abort(); } yann@1: +void __subxf3 (void) { abort(); } yann@1: +void __mulxf3 (void) { abort(); } yann@1: +void __divxf3 (void) { abort(); } yann@1: +void __negxf2 (void) { abort(); } yann@1: +void __eqxf2 (void) { abort(); } yann@1: +void __nexf2 (void) { abort(); } yann@1: +void __gtxf2 (void) { abort(); } yann@1: +void __gexf2 (void) { abort(); } yann@1: +void __lexf2 (void) { abort(); } yann@1: +void __ltxf2 (void) { abort(); } yann@1: + yann@1: +void __extendsftf2 (void) { abort(); } yann@1: +void __extenddftf2 (void) { abort(); } yann@1: +void __trunctfdf2 (void) { abort(); } yann@1: +void __trunctfsf2 (void) { abort(); } yann@1: +void __fixtfsi (void) { abort(); } yann@1: +void __floatsitf (void) { abort(); } yann@1: +void __addtf3 (void) { abort(); } yann@1: +void __subtf3 (void) { abort(); } yann@1: +void __multf3 (void) { abort(); } yann@1: +void __divtf3 (void) { abort(); } yann@1: +void __negtf2 (void) { abort(); } yann@1: +void __eqtf2 (void) { abort(); } yann@1: +void __netf2 (void) { abort(); } yann@1: +void __gttf2 (void) { abort(); } yann@1: +void __getf2 (void) { abort(); } yann@1: +void __letf2 (void) { abort(); } yann@1: +void __lttf2 (void) { abort(); } yann@1: +#else /* !EXTENDED_FLOAT_STUBS, rest of file */ yann@1: + yann@1: +/* IEEE "special" number predicates */ yann@1: + yann@1: +#ifdef NO_NANS yann@1: + yann@1: +#define nan() 0 yann@1: +#define isnan(x) 0 yann@1: +#define isinf(x) 0 yann@1: +#else yann@1: + yann@1: +#if defined L_thenan_sf yann@1: +const fp_number_type __thenan_sf = { CLASS_SNAN, 0, 0, {(fractype) 0} }; yann@1: +#elif defined L_thenan_df yann@1: +const fp_number_type __thenan_df = { CLASS_SNAN, 0, 0, {(fractype) 0} }; yann@1: +#elif defined L_thenan_tf yann@1: +const fp_number_type __thenan_tf = { CLASS_SNAN, 0, 0, {(fractype) 0} }; yann@1: +#elif defined TFLOAT yann@1: +extern const fp_number_type __thenan_tf; yann@1: +#elif defined FLOAT yann@1: +extern const fp_number_type __thenan_sf; yann@1: +#else yann@1: +extern const fp_number_type __thenan_df; yann@1: +#endif yann@1: + yann@1: +INLINE yann@1: +static fp_number_type * yann@1: +nan (void) yann@1: +{ yann@1: + /* Discard the const qualifier... */ yann@1: +#ifdef TFLOAT yann@1: + return (fp_number_type *) (& __thenan_tf); yann@1: +#elif defined FLOAT yann@1: + return (fp_number_type *) (& __thenan_sf); yann@1: +#else yann@1: + return (fp_number_type *) (& __thenan_df); yann@1: +#endif yann@1: +} yann@1: + yann@1: +INLINE yann@1: +static int yann@1: +isnan ( fp_number_type * x) yann@1: +{ yann@1: + return x->class == CLASS_SNAN || x->class == CLASS_QNAN; yann@1: +} yann@1: + yann@1: +INLINE yann@1: +static int yann@1: +isinf ( fp_number_type * x) yann@1: +{ yann@1: + return x->class == CLASS_INFINITY; yann@1: +} yann@1: + yann@1: +#endif /* NO_NANS */ yann@1: + yann@1: +INLINE yann@1: +static int yann@1: +iszero ( fp_number_type * x) yann@1: +{ yann@1: + return x->class == CLASS_ZERO; yann@1: +} yann@1: + yann@1: +INLINE yann@1: +static void yann@1: +flip_sign ( fp_number_type * x) yann@1: +{ yann@1: + x->sign = !x->sign; yann@1: +} yann@1: + yann@1: +extern FLO_type pack_d ( fp_number_type * ); yann@1: + yann@1: +#if defined(L_pack_df) || defined(L_pack_sf) || defined(L_pack_tf) yann@1: +FLO_type yann@1: +pack_d ( fp_number_type * src) yann@1: +{ yann@1: + FLO_union_type dst; yann@1: + fractype fraction = src->fraction.ll; /* wasn't unsigned before? */ yann@1: + int sign = src->sign; yann@1: + int exp = 0; yann@1: + yann@1: + if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && (isnan (src) || isinf (src))) yann@1: + { yann@1: + /* We can't represent these values accurately. By using the yann@1: + largest possible magnitude, we guarantee that the conversion yann@1: + of infinity is at least as big as any finite number. */ yann@1: + exp = EXPMAX; yann@1: + fraction = ((fractype) 1 << FRACBITS) - 1; yann@1: + } yann@1: + else if (isnan (src)) yann@1: + { yann@1: + exp = EXPMAX; yann@1: + if (src->class == CLASS_QNAN || 1) yann@1: + { yann@1: +#ifdef QUIET_NAN_NEGATED yann@1: + fraction |= QUIET_NAN - 1; yann@1: +#else yann@1: + fraction |= QUIET_NAN; yann@1: +#endif yann@1: + } yann@1: + } yann@1: + else if (isinf (src)) yann@1: + { yann@1: + exp = EXPMAX; yann@1: + fraction = 0; yann@1: + } yann@1: + else if (iszero (src)) yann@1: + { yann@1: + exp = 0; yann@1: + fraction = 0; yann@1: + } yann@1: + else if (fraction == 0) yann@1: + { yann@1: + exp = 0; yann@1: + } yann@1: + else yann@1: + { yann@1: + if (src->normal_exp < NORMAL_EXPMIN) yann@1: + { yann@1: +#ifdef NO_DENORMALS yann@1: + /* Go straight to a zero representation if denormals are not yann@1: + supported. The denormal handling would be harmless but yann@1: + isn't unnecessary. */ yann@1: + exp = 0; yann@1: + fraction = 0; yann@1: +#else /* NO_DENORMALS */ yann@1: + /* This number's exponent is too low to fit into the bits yann@1: + available in the number, so we'll store 0 in the exponent and yann@1: + shift the fraction to the right to make up for it. */ yann@1: + yann@1: + int shift = NORMAL_EXPMIN - src->normal_exp; yann@1: + yann@1: + exp = 0; yann@1: + yann@1: + if (shift > FRAC_NBITS - NGARDS) yann@1: + { yann@1: + /* No point shifting, since it's more that 64 out. */ yann@1: + fraction = 0; yann@1: + } yann@1: + else yann@1: + { yann@1: + int lowbit = (fraction & (((fractype)1 << shift) - 1)) ? 1 : 0; yann@1: + fraction = (fraction >> shift) | lowbit; yann@1: + } yann@1: + if ((fraction & GARDMASK) == GARDMSB) yann@1: + { yann@1: + if ((fraction & (1 << NGARDS))) yann@1: + fraction += GARDROUND + 1; yann@1: + } yann@1: + else yann@1: + { yann@1: + /* Add to the guards to round up. */ yann@1: + fraction += GARDROUND; yann@1: + } yann@1: + /* Perhaps the rounding means we now need to change the yann@1: + exponent, because the fraction is no longer denormal. */ yann@1: + if (fraction >= IMPLICIT_1) yann@1: + { yann@1: + exp += 1; yann@1: + } yann@1: + fraction >>= NGARDS; yann@1: +#endif /* NO_DENORMALS */ yann@1: + } yann@1: + else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) yann@1: + && src->normal_exp > EXPBIAS) yann@1: + { yann@1: + exp = EXPMAX; yann@1: + fraction = 0; yann@1: + } yann@1: + else yann@1: + { yann@1: + exp = src->normal_exp + EXPBIAS; yann@1: + if (!ROUND_TOWARDS_ZERO) yann@1: + { yann@1: + /* IF the gard bits are the all zero, but the first, then we're yann@1: + half way between two numbers, choose the one which makes the yann@1: + lsb of the answer 0. */ yann@1: + if ((fraction & GARDMASK) == GARDMSB) yann@1: + { yann@1: + if (fraction & (1 << NGARDS)) yann@1: + fraction += GARDROUND + 1; yann@1: + } yann@1: + else yann@1: + { yann@1: + /* Add a one to the guards to round up */ yann@1: + fraction += GARDROUND; yann@1: + } yann@1: + if (fraction >= IMPLICIT_2) yann@1: + { yann@1: + fraction >>= 1; yann@1: + exp += 1; yann@1: + } yann@1: + } yann@1: + fraction >>= NGARDS; yann@1: + yann@1: + if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp > EXPMAX) yann@1: + { yann@1: + /* Saturate on overflow. */ yann@1: + exp = EXPMAX; yann@1: + fraction = ((fractype) 1 << FRACBITS) - 1; yann@1: + } yann@1: + } yann@1: + } yann@1: + yann@1: + /* We previously used bitfields to store the number, but this doesn't yann@1: + handle little/big endian systems conveniently, so use shifts and yann@1: + masks */ yann@1: +#ifdef FLOAT_BIT_ORDER_MISMATCH yann@1: + dst.bits.fraction = fraction; yann@1: + dst.bits.exp = exp; yann@1: + dst.bits.sign = sign; yann@1: +#else yann@1: +# if defined TFLOAT && defined HALFFRACBITS yann@1: + { yann@1: + halffractype high, low, unity; yann@1: + int lowsign, lowexp; yann@1: + yann@1: + unity = (halffractype) 1 << HALFFRACBITS; yann@1: + yann@1: + /* Set HIGH to the high double's significand, masking out the implicit 1. yann@1: + Set LOW to the low double's full significand. */ yann@1: + high = (fraction >> (FRACBITS - HALFFRACBITS)) & (unity - 1); yann@1: + low = fraction & (unity * 2 - 1); yann@1: + yann@1: + /* Get the initial sign and exponent of the low double. */ yann@1: + lowexp = exp - HALFFRACBITS - 1; yann@1: + lowsign = sign; yann@1: + yann@1: + /* HIGH should be rounded like a normal double, making |LOW| <= yann@1: + 0.5 ULP of HIGH. Assume round-to-nearest. */ yann@1: + if (exp < EXPMAX) yann@1: + if (low > unity || (low == unity && (high & 1) == 1)) yann@1: + { yann@1: + /* Round HIGH up and adjust LOW to match. */ yann@1: + high++; yann@1: + if (high == unity) yann@1: + { yann@1: + /* May make it infinite, but that's OK. */ yann@1: + high = 0; yann@1: + exp++; yann@1: + } yann@1: + low = unity * 2 - low; yann@1: + lowsign ^= 1; yann@1: + } yann@1: + yann@1: + high |= (halffractype) exp << HALFFRACBITS; yann@1: + high |= (halffractype) sign << (HALFFRACBITS + EXPBITS); yann@1: + yann@1: + if (exp == EXPMAX || exp == 0 || low == 0) yann@1: + low = 0; yann@1: + else yann@1: + { yann@1: + while (lowexp > 0 && low < unity) yann@1: + { yann@1: + low <<= 1; yann@1: + lowexp--; yann@1: + } yann@1: + yann@1: + if (lowexp <= 0) yann@1: + { yann@1: + halffractype roundmsb, round; yann@1: + int shift; yann@1: + yann@1: + shift = 1 - lowexp; yann@1: + roundmsb = (1 << (shift - 1)); yann@1: + round = low & ((roundmsb << 1) - 1); yann@1: + yann@1: + low >>= shift; yann@1: + lowexp = 0; yann@1: + yann@1: + if (round > roundmsb || (round == roundmsb && (low & 1) == 1)) yann@1: + { yann@1: + low++; yann@1: + if (low == unity) yann@1: + /* LOW rounds up to the smallest normal number. */ yann@1: + lowexp++; yann@1: + } yann@1: + } yann@1: + yann@1: + low &= unity - 1; yann@1: + low |= (halffractype) lowexp << HALFFRACBITS; yann@1: + low |= (halffractype) lowsign << (HALFFRACBITS + EXPBITS); yann@1: + } yann@1: + dst.value_raw = ((fractype) high << HALFSHIFT) | low; yann@1: + } yann@1: +# else yann@1: + dst.value_raw = fraction & ((((fractype)1) << FRACBITS) - (fractype)1); yann@1: + dst.value_raw |= ((fractype) (exp & ((1 << EXPBITS) - 1))) << FRACBITS; yann@1: + dst.value_raw |= ((fractype) (sign & 1)) << (FRACBITS | EXPBITS); yann@1: +# endif yann@1: +#endif yann@1: + yann@1: +#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT) yann@1: +#ifdef TFLOAT yann@1: + { yann@1: + qrtrfractype tmp1 = dst.words[0]; yann@1: + qrtrfractype tmp2 = dst.words[1]; yann@1: + dst.words[0] = dst.words[3]; yann@1: + dst.words[1] = dst.words[2]; yann@1: + dst.words[2] = tmp2; yann@1: + dst.words[3] = tmp1; yann@1: + } yann@1: +#else yann@1: + { yann@1: + halffractype tmp = dst.words[0]; yann@1: + dst.words[0] = dst.words[1]; yann@1: + dst.words[1] = tmp; yann@1: + } yann@1: +#endif yann@1: +#endif yann@1: + yann@1: + return dst.value; yann@1: +} yann@1: +#endif yann@1: + yann@1: +#if defined(L_unpack_df) || defined(L_unpack_sf) || defined(L_unpack_tf) yann@1: +void yann@1: +unpack_d (FLO_union_type * src, fp_number_type * dst) yann@1: +{ yann@1: + /* We previously used bitfields to store the number, but this doesn't yann@1: + handle little/big endian systems conveniently, so use shifts and yann@1: + masks */ yann@1: + fractype fraction; yann@1: + int exp; yann@1: + int sign; yann@1: + yann@1: +#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT) yann@1: + FLO_union_type swapped; yann@1: + yann@1: +#ifdef TFLOAT yann@1: + swapped.words[0] = src->words[3]; yann@1: + swapped.words[1] = src->words[2]; yann@1: + swapped.words[2] = src->words[1]; yann@1: + swapped.words[3] = src->words[0]; yann@1: +#else yann@1: + swapped.words[0] = src->words[1]; yann@1: + swapped.words[1] = src->words[0]; yann@1: +#endif yann@1: + src = &swapped; yann@1: +#endif yann@1: + yann@1: +#ifdef FLOAT_BIT_ORDER_MISMATCH yann@1: + fraction = src->bits.fraction; yann@1: + exp = src->bits.exp; yann@1: + sign = src->bits.sign; yann@1: +#else yann@1: +# if defined TFLOAT && defined HALFFRACBITS yann@1: + { yann@1: + halffractype high, low; yann@1: + yann@1: + high = src->value_raw >> HALFSHIFT; yann@1: + low = src->value_raw & (((fractype)1 << HALFSHIFT) - 1); yann@1: + yann@1: + fraction = high & ((((fractype)1) << HALFFRACBITS) - 1); yann@1: + fraction <<= FRACBITS - HALFFRACBITS; yann@1: + exp = ((int)(high >> HALFFRACBITS)) & ((1 << EXPBITS) - 1); yann@1: + sign = ((int)(high >> (((HALFFRACBITS + EXPBITS))))) & 1; yann@1: + yann@1: + if (exp != EXPMAX && exp != 0 && low != 0) yann@1: + { yann@1: + int lowexp = ((int)(low >> HALFFRACBITS)) & ((1 << EXPBITS) - 1); yann@1: + int lowsign = ((int)(low >> (((HALFFRACBITS + EXPBITS))))) & 1; yann@1: + int shift; yann@1: + fractype xlow; yann@1: + yann@1: + xlow = low & ((((fractype)1) << HALFFRACBITS) - 1); yann@1: + if (lowexp) yann@1: + xlow |= (((halffractype)1) << HALFFRACBITS); yann@1: + else yann@1: + lowexp = 1; yann@1: + shift = (FRACBITS - HALFFRACBITS) - (exp - lowexp); yann@1: + if (shift > 0) yann@1: + xlow <<= shift; yann@1: + else if (shift < 0) yann@1: + xlow >>= -shift; yann@1: + if (sign == lowsign) yann@1: + fraction += xlow; yann@1: + else if (fraction >= xlow) yann@1: + fraction -= xlow; yann@1: + else yann@1: + { yann@1: + /* The high part is a power of two but the full number is lower. yann@1: + This code will leave the implicit 1 in FRACTION, but we'd yann@1: + have added that below anyway. */ yann@1: + fraction = (((fractype) 1 << FRACBITS) - xlow) << 1; yann@1: + exp--; yann@1: + } yann@1: + } yann@1: + } yann@1: +# else yann@1: + fraction = src->value_raw & ((((fractype)1) << FRACBITS) - 1); yann@1: + exp = ((int)(src->value_raw >> FRACBITS)) & ((1 << EXPBITS) - 1); yann@1: + sign = ((int)(src->value_raw >> (FRACBITS + EXPBITS))) & 1; yann@1: +# endif yann@1: +#endif yann@1: + yann@1: + dst->sign = sign; yann@1: + if (exp == 0) yann@1: + { yann@1: + /* Hmm. Looks like 0 */ yann@1: + if (fraction == 0 yann@1: +#ifdef NO_DENORMALS yann@1: + || 1 yann@1: +#endif yann@1: + ) yann@1: + { yann@1: + /* tastes like zero */ yann@1: + dst->class = CLASS_ZERO; yann@1: + } yann@1: + else yann@1: + { yann@1: + /* Zero exponent with nonzero fraction - it's denormalized, yann@1: + so there isn't a leading implicit one - we'll shift it so yann@1: + it gets one. */ yann@1: + dst->normal_exp = exp - EXPBIAS + 1; yann@1: + fraction <<= NGARDS; yann@1: + yann@1: + dst->class = CLASS_NUMBER; yann@1: +#if 1 yann@1: + while (fraction < IMPLICIT_1) yann@1: + { yann@1: + fraction <<= 1; yann@1: + dst->normal_exp--; yann@1: + } yann@1: +#endif yann@1: + dst->fraction.ll = fraction; yann@1: + } yann@1: + } yann@1: + else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp == EXPMAX) yann@1: + { yann@1: + /* Huge exponent*/ yann@1: + if (fraction == 0) yann@1: + { yann@1: + /* Attached to a zero fraction - means infinity */ yann@1: + dst->class = CLASS_INFINITY; yann@1: + } yann@1: + else yann@1: + { yann@1: + /* Nonzero fraction, means nan */ yann@1: +#ifdef QUIET_NAN_NEGATED yann@1: + if ((fraction & QUIET_NAN) == 0) yann@1: +#else yann@1: + if (fraction & QUIET_NAN) yann@1: +#endif yann@1: + { yann@1: + dst->class = CLASS_QNAN; yann@1: + } yann@1: + else yann@1: + { yann@1: + dst->class = CLASS_SNAN; yann@1: + } yann@1: + /* Keep the fraction part as the nan number */ yann@1: + dst->fraction.ll = fraction; yann@1: + } yann@1: + } yann@1: + else yann@1: + { yann@1: + /* Nothing strange about this number */ yann@1: + dst->normal_exp = exp - EXPBIAS; yann@1: + dst->class = CLASS_NUMBER; yann@1: + dst->fraction.ll = (fraction << NGARDS) | IMPLICIT_1; yann@1: + } yann@1: +} yann@1: +#endif /* L_unpack_df || L_unpack_sf */ yann@1: + yann@1: +#if defined(L_addsub_sf) || defined(L_addsub_df) || defined(L_addsub_tf) yann@1: +static fp_number_type * yann@1: +_fpadd_parts (fp_number_type * a, yann@1: + fp_number_type * b, yann@1: + fp_number_type * tmp) yann@1: +{ yann@1: + intfrac tfraction; yann@1: + yann@1: + /* Put commonly used fields in local variables. */ yann@1: + int a_normal_exp; yann@1: + int b_normal_exp; yann@1: + fractype a_fraction; yann@1: + fractype b_fraction; yann@1: + yann@1: + if (isnan (a)) yann@1: + { yann@1: + return a; yann@1: + } yann@1: + if (isnan (b)) yann@1: + { yann@1: + return b; yann@1: + } yann@1: + if (isinf (a)) yann@1: + { yann@1: + /* Adding infinities with opposite signs yields a NaN. */ yann@1: + if (isinf (b) && a->sign != b->sign) yann@1: + return nan (); yann@1: + return a; yann@1: + } yann@1: + if (isinf (b)) yann@1: + { yann@1: + return b; yann@1: + } yann@1: + if (iszero (b)) yann@1: + { yann@1: + if (iszero (a)) yann@1: + { yann@1: + *tmp = *a; yann@1: + tmp->sign = a->sign & b->sign; yann@1: + return tmp; yann@1: + } yann@1: + return a; yann@1: + } yann@1: + if (iszero (a)) yann@1: + { yann@1: + return b; yann@1: + } yann@1: + yann@1: + /* Got two numbers. shift the smaller and increment the exponent till yann@1: + they're the same */ yann@1: + { yann@1: + int diff; yann@1: + yann@1: + a_normal_exp = a->normal_exp; yann@1: + b_normal_exp = b->normal_exp; yann@1: + a_fraction = a->fraction.ll; yann@1: + b_fraction = b->fraction.ll; yann@1: + yann@1: + diff = a_normal_exp - b_normal_exp; yann@1: + yann@1: + if (diff < 0) yann@1: + diff = -diff; yann@1: + if (diff < FRAC_NBITS) yann@1: + { yann@1: + /* ??? This does shifts one bit at a time. Optimize. */ yann@1: + while (a_normal_exp > b_normal_exp) yann@1: + { yann@1: + b_normal_exp++; yann@1: + LSHIFT (b_fraction); yann@1: + } yann@1: + while (b_normal_exp > a_normal_exp) yann@1: + { yann@1: + a_normal_exp++; yann@1: + LSHIFT (a_fraction); yann@1: + } yann@1: + } yann@1: + else yann@1: + { yann@1: + /* Somethings's up.. choose the biggest */ yann@1: + if (a_normal_exp > b_normal_exp) yann@1: + { yann@1: + b_normal_exp = a_normal_exp; yann@1: + b_fraction = 0; yann@1: + } yann@1: + else yann@1: + { yann@1: + a_normal_exp = b_normal_exp; yann@1: + a_fraction = 0; yann@1: + } yann@1: + } yann@1: + } yann@1: + yann@1: + if (a->sign != b->sign) yann@1: + { yann@1: + if (a->sign) yann@1: + { yann@1: + tfraction = -a_fraction + b_fraction; yann@1: + } yann@1: + else yann@1: + { yann@1: + tfraction = a_fraction - b_fraction; yann@1: + } yann@1: + if (tfraction >= 0) yann@1: + { yann@1: + tmp->sign = 0; yann@1: + tmp->normal_exp = a_normal_exp; yann@1: + tmp->fraction.ll = tfraction; yann@1: + } yann@1: + else yann@1: + { yann@1: + tmp->sign = 1; yann@1: + tmp->normal_exp = a_normal_exp; yann@1: + tmp->fraction.ll = -tfraction; yann@1: + } yann@1: + /* and renormalize it */ yann@1: + yann@1: + while (tmp->fraction.ll < IMPLICIT_1 && tmp->fraction.ll) yann@1: + { yann@1: + tmp->fraction.ll <<= 1; yann@1: + tmp->normal_exp--; yann@1: + } yann@1: + } yann@1: + else yann@1: + { yann@1: + tmp->sign = a->sign; yann@1: + tmp->normal_exp = a_normal_exp; yann@1: + tmp->fraction.ll = a_fraction + b_fraction; yann@1: + } yann@1: + tmp->class = CLASS_NUMBER; yann@1: + /* Now the fraction is added, we have to shift down to renormalize the yann@1: + number */ yann@1: + yann@1: + if (tmp->fraction.ll >= IMPLICIT_2) yann@1: + { yann@1: + LSHIFT (tmp->fraction.ll); yann@1: + tmp->normal_exp++; yann@1: + } yann@1: + return tmp; yann@1: + yann@1: +} yann@1: + yann@1: +FLO_type yann@1: +add (FLO_type arg_a, FLO_type arg_b) yann@1: +{ yann@1: + fp_number_type a; yann@1: + fp_number_type b; yann@1: + fp_number_type tmp; yann@1: + fp_number_type *res; yann@1: + FLO_union_type au, bu; yann@1: + yann@1: + au.value = arg_a; yann@1: + bu.value = arg_b; yann@1: + yann@1: + unpack_d (&au, &a); yann@1: + unpack_d (&bu, &b); yann@1: + yann@1: + res = _fpadd_parts (&a, &b, &tmp); yann@1: + yann@1: + return pack_d (res); yann@1: +} yann@1: + yann@1: +FLO_type yann@1: +sub (FLO_type arg_a, FLO_type arg_b) yann@1: +{ yann@1: + fp_number_type a; yann@1: + fp_number_type b; yann@1: + fp_number_type tmp; yann@1: + fp_number_type *res; yann@1: + FLO_union_type au, bu; yann@1: + yann@1: + au.value = arg_a; yann@1: + bu.value = arg_b; yann@1: + yann@1: + unpack_d (&au, &a); yann@1: + unpack_d (&bu, &b); yann@1: + yann@1: + b.sign ^= 1; yann@1: + yann@1: + res = _fpadd_parts (&a, &b, &tmp); yann@1: + yann@1: + return pack_d (res); yann@1: +} yann@1: +#endif /* L_addsub_sf || L_addsub_df */ yann@1: + yann@1: +#if defined(L_mul_sf) || defined(L_mul_df) || defined(L_mul_tf) yann@1: +static inline __attribute__ ((__always_inline__)) fp_number_type * yann@1: +_fpmul_parts ( fp_number_type * a, yann@1: + fp_number_type * b, yann@1: + fp_number_type * tmp) yann@1: +{ yann@1: + fractype low = 0; yann@1: + fractype high = 0; yann@1: + yann@1: + if (isnan (a)) yann@1: + { yann@1: + a->sign = a->sign != b->sign; yann@1: + return a; yann@1: + } yann@1: + if (isnan (b)) yann@1: + { yann@1: + b->sign = a->sign != b->sign; yann@1: + return b; yann@1: + } yann@1: + if (isinf (a)) yann@1: + { yann@1: + if (iszero (b)) yann@1: + return nan (); yann@1: + a->sign = a->sign != b->sign; yann@1: + return a; yann@1: + } yann@1: + if (isinf (b)) yann@1: + { yann@1: + if (iszero (a)) yann@1: + { yann@1: + return nan (); yann@1: + } yann@1: + b->sign = a->sign != b->sign; yann@1: + return b; yann@1: + } yann@1: + if (iszero (a)) yann@1: + { yann@1: + a->sign = a->sign != b->sign; yann@1: + return a; yann@1: + } yann@1: + if (iszero (b)) yann@1: + { yann@1: + b->sign = a->sign != b->sign; yann@1: + return b; yann@1: + } yann@1: + yann@1: + /* Calculate the mantissa by multiplying both numbers to get a yann@1: + twice-as-wide number. */ yann@1: + { yann@1: +#if defined(NO_DI_MODE) || defined(TFLOAT) yann@1: + { yann@1: + fractype x = a->fraction.ll; yann@1: + fractype ylow = b->fraction.ll; yann@1: + fractype yhigh = 0; yann@1: + int bit; yann@1: + yann@1: + /* ??? This does multiplies one bit at a time. Optimize. */ yann@1: + for (bit = 0; bit < FRAC_NBITS; bit++) yann@1: + { yann@1: + int carry; yann@1: + yann@1: + if (x & 1) yann@1: + { yann@1: + carry = (low += ylow) < ylow; yann@1: + high += yhigh + carry; yann@1: + } yann@1: + yhigh <<= 1; yann@1: + if (ylow & FRACHIGH) yann@1: + { yann@1: + yhigh |= 1; yann@1: + } yann@1: + ylow <<= 1; yann@1: + x >>= 1; yann@1: + } yann@1: + } yann@1: +#elif defined(FLOAT) yann@1: + /* Multiplying two USIs to get a UDI, we're safe. */ yann@1: + { yann@1: + UDItype answer = (UDItype)a->fraction.ll * (UDItype)b->fraction.ll; yann@1: + yann@1: + high = answer >> BITS_PER_SI; yann@1: + low = answer; yann@1: + } yann@1: +#else yann@1: + /* fractype is DImode, but we need the result to be twice as wide. yann@1: + Assuming a widening multiply from DImode to TImode is not yann@1: + available, build one by hand. */ yann@1: + { yann@1: + USItype nl = a->fraction.ll; yann@1: + USItype nh = a->fraction.ll >> BITS_PER_SI; yann@1: + USItype ml = b->fraction.ll; yann@1: + USItype mh = b->fraction.ll >> BITS_PER_SI; yann@1: + UDItype pp_ll = (UDItype) ml * nl; yann@1: + UDItype pp_hl = (UDItype) mh * nl; yann@1: + UDItype pp_lh = (UDItype) ml * nh; yann@1: + UDItype pp_hh = (UDItype) mh * nh; yann@1: + UDItype res2 = 0; yann@1: + UDItype res0 = 0; yann@1: + UDItype ps_hh__ = pp_hl + pp_lh; yann@1: + if (ps_hh__ < pp_hl) yann@1: + res2 += (UDItype)1 << BITS_PER_SI; yann@1: + pp_hl = (UDItype)(USItype)ps_hh__ << BITS_PER_SI; yann@1: + res0 = pp_ll + pp_hl; yann@1: + if (res0 < pp_ll) yann@1: + res2++; yann@1: + res2 += (ps_hh__ >> BITS_PER_SI) + pp_hh; yann@1: + high = res2; yann@1: + low = res0; yann@1: + } yann@1: +#endif yann@1: + } yann@1: + yann@1: + tmp->normal_exp = a->normal_exp + b->normal_exp yann@1: + + FRAC_NBITS - (FRACBITS + NGARDS); yann@1: + tmp->sign = a->sign != b->sign; yann@1: + while (high >= IMPLICIT_2) yann@1: + { yann@1: + tmp->normal_exp++; yann@1: + if (high & 1) yann@1: + { yann@1: + low >>= 1; yann@1: + low |= FRACHIGH; yann@1: + } yann@1: + high >>= 1; yann@1: + } yann@1: + while (high < IMPLICIT_1) yann@1: + { yann@1: + tmp->normal_exp--; yann@1: + yann@1: + high <<= 1; yann@1: + if (low & FRACHIGH) yann@1: + high |= 1; yann@1: + low <<= 1; yann@1: + } yann@1: + /* rounding is tricky. if we only round if it won't make us round later. */ yann@1: +#if 0 yann@1: + if (low & FRACHIGH2) yann@1: + { yann@1: + if (((high & GARDMASK) != GARDMSB) yann@1: + && (((high + 1) & GARDMASK) == GARDMSB)) yann@1: + { yann@1: + /* don't round, it gets done again later. */ yann@1: + } yann@1: + else yann@1: + { yann@1: + high++; yann@1: + } yann@1: + } yann@1: +#endif yann@1: + if (!ROUND_TOWARDS_ZERO && (high & GARDMASK) == GARDMSB) yann@1: + { yann@1: + if (high & (1 << NGARDS)) yann@1: + { yann@1: + /* half way, so round to even */ yann@1: + high += GARDROUND + 1; yann@1: + } yann@1: + else if (low) yann@1: + { yann@1: + /* but we really weren't half way */ yann@1: + high += GARDROUND + 1; yann@1: + } yann@1: + } yann@1: + tmp->fraction.ll = high; yann@1: + tmp->class = CLASS_NUMBER; yann@1: + return tmp; yann@1: +} yann@1: + yann@1: +FLO_type yann@1: +multiply (FLO_type arg_a, FLO_type arg_b) yann@1: +{ yann@1: + fp_number_type a; yann@1: + fp_number_type b; yann@1: + fp_number_type tmp; yann@1: + fp_number_type *res; yann@1: + FLO_union_type au, bu; yann@1: + yann@1: + au.value = arg_a; yann@1: + bu.value = arg_b; yann@1: + yann@1: + unpack_d (&au, &a); yann@1: + unpack_d (&bu, &b); yann@1: + yann@1: + res = _fpmul_parts (&a, &b, &tmp); yann@1: + yann@1: + return pack_d (res); yann@1: +} yann@1: +#endif /* L_mul_sf || L_mul_df */ yann@1: + yann@1: +#if defined(L_div_sf) || defined(L_div_df) || defined(L_div_tf) yann@1: +static inline __attribute__ ((__always_inline__)) fp_number_type * yann@1: +_fpdiv_parts (fp_number_type * a, yann@1: + fp_number_type * b) yann@1: +{ yann@1: + fractype bit; yann@1: + fractype numerator; yann@1: + fractype denominator; yann@1: + fractype quotient; yann@1: + yann@1: + if (isnan (a)) yann@1: + { yann@1: + return a; yann@1: + } yann@1: + if (isnan (b)) yann@1: + { yann@1: + return b; yann@1: + } yann@1: + yann@1: + a->sign = a->sign ^ b->sign; yann@1: + yann@1: + if (isinf (a) || iszero (a)) yann@1: + { yann@1: + if (a->class == b->class) yann@1: + return nan (); yann@1: + return a; yann@1: + } yann@1: + yann@1: + if (isinf (b)) yann@1: + { yann@1: + a->fraction.ll = 0; yann@1: + a->normal_exp = 0; yann@1: + return a; yann@1: + } yann@1: + if (iszero (b)) yann@1: + { yann@1: + a->class = CLASS_INFINITY; yann@1: + return a; yann@1: + } yann@1: + yann@1: + /* Calculate the mantissa by multiplying both 64bit numbers to get a yann@1: + 128 bit number */ yann@1: + { yann@1: + /* quotient = yann@1: + ( numerator / denominator) * 2^(numerator exponent - denominator exponent) yann@1: + */ yann@1: + yann@1: + a->normal_exp = a->normal_exp - b->normal_exp; yann@1: + numerator = a->fraction.ll; yann@1: + denominator = b->fraction.ll; yann@1: + yann@1: + if (numerator < denominator) yann@1: + { yann@1: + /* Fraction will be less than 1.0 */ yann@1: + numerator *= 2; yann@1: + a->normal_exp--; yann@1: + } yann@1: + bit = IMPLICIT_1; yann@1: + quotient = 0; yann@1: + /* ??? Does divide one bit at a time. Optimize. */ yann@1: + while (bit) yann@1: + { yann@1: + if (numerator >= denominator) yann@1: + { yann@1: + quotient |= bit; yann@1: + numerator -= denominator; yann@1: + } yann@1: + bit >>= 1; yann@1: + numerator *= 2; yann@1: + } yann@1: + yann@1: + if (!ROUND_TOWARDS_ZERO && (quotient & GARDMASK) == GARDMSB) yann@1: + { yann@1: + if (quotient & (1 << NGARDS)) yann@1: + { yann@1: + /* half way, so round to even */ yann@1: + quotient += GARDROUND + 1; yann@1: + } yann@1: + else if (numerator) yann@1: + { yann@1: + /* but we really weren't half way, more bits exist */ yann@1: + quotient += GARDROUND + 1; yann@1: + } yann@1: + } yann@1: + yann@1: + a->fraction.ll = quotient; yann@1: + return (a); yann@1: + } yann@1: +} yann@1: + yann@1: +FLO_type yann@1: +divide (FLO_type arg_a, FLO_type arg_b) yann@1: +{ yann@1: + fp_number_type a; yann@1: + fp_number_type b; yann@1: + fp_number_type *res; yann@1: + FLO_union_type au, bu; yann@1: + yann@1: + au.value = arg_a; yann@1: + bu.value = arg_b; yann@1: + yann@1: + unpack_d (&au, &a); yann@1: + unpack_d (&bu, &b); yann@1: + yann@1: + res = _fpdiv_parts (&a, &b); yann@1: + yann@1: + return pack_d (res); yann@1: +} yann@1: +#endif /* L_div_sf || L_div_df */ yann@1: + yann@1: +#if defined(L_fpcmp_parts_sf) || defined(L_fpcmp_parts_df) \ yann@1: + || defined(L_fpcmp_parts_tf) yann@1: +/* according to the demo, fpcmp returns a comparison with 0... thus yann@1: + a -1 yann@1: + a==b -> 0 yann@1: + a>b -> +1 yann@1: + */ yann@1: + yann@1: +int yann@1: +__fpcmp_parts (fp_number_type * a, fp_number_type * b) yann@1: +{ yann@1: +#if 0 yann@1: + /* either nan -> unordered. Must be checked outside of this routine. */ yann@1: + if (isnan (a) && isnan (b)) yann@1: + { yann@1: + return 1; /* still unordered! */ yann@1: + } yann@1: +#endif yann@1: + yann@1: + if (isnan (a) || isnan (b)) yann@1: + { yann@1: + return 1; /* how to indicate unordered compare? */ yann@1: + } yann@1: + if (isinf (a) && isinf (b)) yann@1: + { yann@1: + /* +inf > -inf, but +inf != +inf */ yann@1: + /* b \a| +inf(0)| -inf(1) yann@1: + ______\+--------+-------- yann@1: + +inf(0)| a==b(0)| ab(1) | a==b(0) yann@1: + -------+--------+-------- yann@1: + So since unordered must be nonzero, just line up the columns... yann@1: + */ yann@1: + return b->sign - a->sign; yann@1: + } yann@1: + /* but not both... */ yann@1: + if (isinf (a)) yann@1: + { yann@1: + return a->sign ? -1 : 1; yann@1: + } yann@1: + if (isinf (b)) yann@1: + { yann@1: + return b->sign ? 1 : -1; yann@1: + } yann@1: + if (iszero (a) && iszero (b)) yann@1: + { yann@1: + return 0; yann@1: + } yann@1: + if (iszero (a)) yann@1: + { yann@1: + return b->sign ? 1 : -1; yann@1: + } yann@1: + if (iszero (b)) yann@1: + { yann@1: + return a->sign ? -1 : 1; yann@1: + } yann@1: + /* now both are "normal". */ yann@1: + if (a->sign != b->sign) yann@1: + { yann@1: + /* opposite signs */ yann@1: + return a->sign ? -1 : 1; yann@1: + } yann@1: + /* same sign; exponents? */ yann@1: + if (a->normal_exp > b->normal_exp) yann@1: + { yann@1: + return a->sign ? -1 : 1; yann@1: + } yann@1: + if (a->normal_exp < b->normal_exp) yann@1: + { yann@1: + return a->sign ? 1 : -1; yann@1: + } yann@1: + /* same exponents; check size. */ yann@1: + if (a->fraction.ll > b->fraction.ll) yann@1: + { yann@1: + return a->sign ? -1 : 1; yann@1: + } yann@1: + if (a->fraction.ll < b->fraction.ll) yann@1: + { yann@1: + return a->sign ? 1 : -1; yann@1: + } yann@1: + /* after all that, they're equal. */ yann@1: + return 0; yann@1: +} yann@1: +#endif yann@1: + yann@1: +#if defined(L_compare_sf) || defined(L_compare_df) || defined(L_compoare_tf) yann@1: +CMPtype yann@1: +compare (FLO_type arg_a, FLO_type arg_b) yann@1: +{ yann@1: + fp_number_type a; yann@1: + fp_number_type b; yann@1: + FLO_union_type au, bu; yann@1: + yann@1: + au.value = arg_a; yann@1: + bu.value = arg_b; yann@1: + yann@1: + unpack_d (&au, &a); yann@1: + unpack_d (&bu, &b); yann@1: + yann@1: + return __fpcmp_parts (&a, &b); yann@1: +} yann@1: +#endif /* L_compare_sf || L_compare_df */ yann@1: + yann@1: +#ifndef US_SOFTWARE_GOFAST yann@1: + yann@1: +/* These should be optimized for their specific tasks someday. */ yann@1: + yann@1: +#if defined(L_eq_sf) || defined(L_eq_df) || defined(L_eq_tf) yann@1: +CMPtype yann@1: +_eq_f2 (FLO_type arg_a, FLO_type arg_b) yann@1: +{ yann@1: + fp_number_type a; yann@1: + fp_number_type b; yann@1: + FLO_union_type au, bu; yann@1: + yann@1: + au.value = arg_a; yann@1: + bu.value = arg_b; yann@1: + yann@1: + unpack_d (&au, &a); yann@1: + unpack_d (&bu, &b); yann@1: + yann@1: + if (isnan (&a) || isnan (&b)) yann@1: + return 1; /* false, truth == 0 */ yann@1: + yann@1: + return __fpcmp_parts (&a, &b) ; yann@1: +} yann@1: +#endif /* L_eq_sf || L_eq_df */ yann@1: + yann@1: +#if defined(L_ne_sf) || defined(L_ne_df) || defined(L_ne_tf) yann@1: +CMPtype yann@1: +_ne_f2 (FLO_type arg_a, FLO_type arg_b) yann@1: +{ yann@1: + fp_number_type a; yann@1: + fp_number_type b; yann@1: + FLO_union_type au, bu; yann@1: + yann@1: + au.value = arg_a; yann@1: + bu.value = arg_b; yann@1: + yann@1: + unpack_d (&au, &a); yann@1: + unpack_d (&bu, &b); yann@1: + yann@1: + if (isnan (&a) || isnan (&b)) yann@1: + return 1; /* true, truth != 0 */ yann@1: + yann@1: + return __fpcmp_parts (&a, &b) ; yann@1: +} yann@1: +#endif /* L_ne_sf || L_ne_df */ yann@1: + yann@1: +#if defined(L_gt_sf) || defined(L_gt_df) || defined(L_gt_tf) yann@1: +CMPtype yann@1: +_gt_f2 (FLO_type arg_a, FLO_type arg_b) yann@1: +{ yann@1: + fp_number_type a; yann@1: + fp_number_type b; yann@1: + FLO_union_type au, bu; yann@1: + yann@1: + au.value = arg_a; yann@1: + bu.value = arg_b; yann@1: + yann@1: + unpack_d (&au, &a); yann@1: + unpack_d (&bu, &b); yann@1: + yann@1: + if (isnan (&a) || isnan (&b)) yann@1: + return -1; /* false, truth > 0 */ yann@1: + yann@1: + return __fpcmp_parts (&a, &b); yann@1: +} yann@1: +#endif /* L_gt_sf || L_gt_df */ yann@1: + yann@1: +#if defined(L_ge_sf) || defined(L_ge_df) || defined(L_ge_tf) yann@1: +CMPtype yann@1: +_ge_f2 (FLO_type arg_a, FLO_type arg_b) yann@1: +{ yann@1: + fp_number_type a; yann@1: + fp_number_type b; yann@1: + FLO_union_type au, bu; yann@1: + yann@1: + au.value = arg_a; yann@1: + bu.value = arg_b; yann@1: + yann@1: + unpack_d (&au, &a); yann@1: + unpack_d (&bu, &b); yann@1: + yann@1: + if (isnan (&a) || isnan (&b)) yann@1: + return -1; /* false, truth >= 0 */ yann@1: + return __fpcmp_parts (&a, &b) ; yann@1: +} yann@1: +#endif /* L_ge_sf || L_ge_df */ yann@1: + yann@1: +#if defined(L_lt_sf) || defined(L_lt_df) || defined(L_lt_tf) yann@1: +CMPtype yann@1: +_lt_f2 (FLO_type arg_a, FLO_type arg_b) yann@1: +{ yann@1: + fp_number_type a; yann@1: + fp_number_type b; yann@1: + FLO_union_type au, bu; yann@1: + yann@1: + au.value = arg_a; yann@1: + bu.value = arg_b; yann@1: + yann@1: + unpack_d (&au, &a); yann@1: + unpack_d (&bu, &b); yann@1: + yann@1: + if (isnan (&a) || isnan (&b)) yann@1: + return 1; /* false, truth < 0 */ yann@1: + yann@1: + return __fpcmp_parts (&a, &b); yann@1: +} yann@1: +#endif /* L_lt_sf || L_lt_df */ yann@1: + yann@1: +#if defined(L_le_sf) || defined(L_le_df) || defined(L_le_tf) yann@1: +CMPtype yann@1: +_le_f2 (FLO_type arg_a, FLO_type arg_b) yann@1: +{ yann@1: + fp_number_type a; yann@1: + fp_number_type b; yann@1: + FLO_union_type au, bu; yann@1: + yann@1: + au.value = arg_a; yann@1: + bu.value = arg_b; yann@1: + yann@1: + unpack_d (&au, &a); yann@1: + unpack_d (&bu, &b); yann@1: + yann@1: + if (isnan (&a) || isnan (&b)) yann@1: + return 1; /* false, truth <= 0 */ yann@1: + yann@1: + return __fpcmp_parts (&a, &b) ; yann@1: +} yann@1: +#endif /* L_le_sf || L_le_df */ yann@1: + yann@1: +#endif /* ! US_SOFTWARE_GOFAST */ yann@1: + yann@1: +#if defined(L_unord_sf) || defined(L_unord_df) || defined(L_unord_tf) yann@1: +CMPtype yann@1: +_unord_f2 (FLO_type arg_a, FLO_type arg_b) yann@1: +{ yann@1: + fp_number_type a; yann@1: + fp_number_type b; yann@1: + FLO_union_type au, bu; yann@1: + yann@1: + au.value = arg_a; yann@1: + bu.value = arg_b; yann@1: + yann@1: + unpack_d (&au, &a); yann@1: + unpack_d (&bu, &b); yann@1: + yann@1: + return (isnan (&a) || isnan (&b)); yann@1: +} yann@1: +#endif /* L_unord_sf || L_unord_df */ yann@1: + yann@1: +#if defined(L_si_to_sf) || defined(L_si_to_df) || defined(L_si_to_tf) yann@1: +FLO_type yann@1: +si_to_float (SItype arg_a) yann@1: +{ yann@1: + fp_number_type in; yann@1: + yann@1: + in.class = CLASS_NUMBER; yann@1: + in.sign = arg_a < 0; yann@1: + if (!arg_a) yann@1: + { yann@1: + in.class = CLASS_ZERO; yann@1: + } yann@1: + else yann@1: + { yann@1: + in.normal_exp = FRACBITS + NGARDS; yann@1: + if (in.sign) yann@1: + { yann@1: + /* Special case for minint, since there is no +ve integer yann@1: + representation for it */ yann@1: + if (arg_a == (- MAX_SI_INT - 1)) yann@1: + { yann@1: + return (FLO_type)(- MAX_SI_INT - 1); yann@1: + } yann@1: + in.fraction.ll = (-arg_a); yann@1: + } yann@1: + else yann@1: + in.fraction.ll = arg_a; yann@1: + yann@1: + while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS))) yann@1: + { yann@1: + in.fraction.ll <<= 1; yann@1: + in.normal_exp -= 1; yann@1: + } yann@1: + } yann@1: + return pack_d (&in); yann@1: +} yann@1: +#endif /* L_si_to_sf || L_si_to_df */ yann@1: + yann@1: +#if defined(L_usi_to_sf) || defined(L_usi_to_df) || defined(L_usi_to_tf) yann@1: +FLO_type yann@1: +usi_to_float (USItype arg_a) yann@1: +{ yann@1: + fp_number_type in; yann@1: + yann@1: + in.sign = 0; yann@1: + if (!arg_a) yann@1: + { yann@1: + in.class = CLASS_ZERO; yann@1: + } yann@1: + else yann@1: + { yann@1: + in.class = CLASS_NUMBER; yann@1: + in.normal_exp = FRACBITS + NGARDS; yann@1: + in.fraction.ll = arg_a; yann@1: + yann@1: + while (in.fraction.ll > ((fractype)1 << (FRACBITS + NGARDS))) yann@1: + { yann@1: + in.fraction.ll >>= 1; yann@1: + in.normal_exp += 1; yann@1: + } yann@1: + while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS))) yann@1: + { yann@1: + in.fraction.ll <<= 1; yann@1: + in.normal_exp -= 1; yann@1: + } yann@1: + } yann@1: + return pack_d (&in); yann@1: +} yann@1: +#endif yann@1: + yann@1: +#if defined(L_sf_to_si) || defined(L_df_to_si) || defined(L_tf_to_si) yann@1: +SItype yann@1: +float_to_si (FLO_type arg_a) yann@1: +{ yann@1: + fp_number_type a; yann@1: + SItype tmp; yann@1: + FLO_union_type au; yann@1: + yann@1: + au.value = arg_a; yann@1: + unpack_d (&au, &a); yann@1: + yann@1: + if (iszero (&a)) yann@1: + return 0; yann@1: + if (isnan (&a)) yann@1: + return 0; yann@1: + /* get reasonable MAX_SI_INT... */ yann@1: + if (isinf (&a)) yann@1: + return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT; yann@1: + /* it is a number, but a small one */ yann@1: + if (a.normal_exp < 0) yann@1: + return 0; yann@1: + if (a.normal_exp > BITS_PER_SI - 2) yann@1: + return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT; yann@1: + tmp = a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp); yann@1: + return a.sign ? (-tmp) : (tmp); yann@1: +} yann@1: +#endif /* L_sf_to_si || L_df_to_si */ yann@1: + yann@1: +#if defined(L_sf_to_usi) || defined(L_df_to_usi) || defined(L_tf_to_usi) yann@1: +#if defined US_SOFTWARE_GOFAST || defined(L_tf_to_usi) yann@1: +/* While libgcc2.c defines its own __fixunssfsi and __fixunsdfsi routines, yann@1: + we also define them for GOFAST because the ones in libgcc2.c have the yann@1: + wrong names and I'd rather define these here and keep GOFAST CYG-LOC's yann@1: + out of libgcc2.c. We can't define these here if not GOFAST because then yann@1: + there'd be duplicate copies. */ yann@1: + yann@1: +USItype yann@1: +float_to_usi (FLO_type arg_a) yann@1: +{ yann@1: + fp_number_type a; yann@1: + FLO_union_type au; yann@1: + yann@1: + au.value = arg_a; yann@1: + unpack_d (&au, &a); yann@1: + yann@1: + if (iszero (&a)) yann@1: + return 0; yann@1: + if (isnan (&a)) yann@1: + return 0; yann@1: + /* it is a negative number */ yann@1: + if (a.sign) yann@1: + return 0; yann@1: + /* get reasonable MAX_USI_INT... */ yann@1: + if (isinf (&a)) yann@1: + return MAX_USI_INT; yann@1: + /* it is a number, but a small one */ yann@1: + if (a.normal_exp < 0) yann@1: + return 0; yann@1: + if (a.normal_exp > BITS_PER_SI - 1) yann@1: + return MAX_USI_INT; yann@1: + else if (a.normal_exp > (FRACBITS + NGARDS)) yann@1: + return a.fraction.ll << (a.normal_exp - (FRACBITS + NGARDS)); yann@1: + else yann@1: + return a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp); yann@1: +} yann@1: +#endif /* US_SOFTWARE_GOFAST */ yann@1: +#endif /* L_sf_to_usi || L_df_to_usi */ yann@1: + yann@1: +#if defined(L_negate_sf) || defined(L_negate_df) || defined(L_negate_tf) yann@1: +FLO_type yann@1: +negate (FLO_type arg_a) yann@1: +{ yann@1: + fp_number_type a; yann@1: + FLO_union_type au; yann@1: + yann@1: + au.value = arg_a; yann@1: + unpack_d (&au, &a); yann@1: + yann@1: + flip_sign (&a); yann@1: + return pack_d (&a); yann@1: +} yann@1: +#endif /* L_negate_sf || L_negate_df */ yann@1: + yann@1: +#ifdef FLOAT yann@1: + yann@1: +#if defined(L_make_sf) yann@1: +SFtype yann@1: +__make_fp(fp_class_type class, yann@1: + unsigned int sign, yann@1: + int exp, yann@1: + USItype frac) yann@1: +{ yann@1: + fp_number_type in; yann@1: + yann@1: + in.class = class; yann@1: + in.sign = sign; yann@1: + in.normal_exp = exp; yann@1: + in.fraction.ll = frac; yann@1: + return pack_d (&in); yann@1: +} yann@1: +#endif /* L_make_sf */ yann@1: + yann@1: +#ifndef FLOAT_ONLY yann@1: + yann@1: +/* This enables one to build an fp library that supports float but not double. yann@1: + Otherwise, we would get an undefined reference to __make_dp. yann@1: + This is needed for some 8-bit ports that can't handle well values that yann@1: + are 8-bytes in size, so we just don't support double for them at all. */ yann@1: + yann@1: +#if defined(L_sf_to_df) yann@1: +DFtype yann@1: +sf_to_df (SFtype arg_a) yann@1: +{ yann@1: + fp_number_type in; yann@1: + FLO_union_type au; yann@1: + yann@1: + au.value = arg_a; yann@1: + unpack_d (&au, &in); yann@1: + yann@1: + return __make_dp (in.class, in.sign, in.normal_exp, yann@1: + ((UDItype) in.fraction.ll) << F_D_BITOFF); yann@1: +} yann@1: +#endif /* L_sf_to_df */ yann@1: + yann@1: +#if defined(L_sf_to_tf) && defined(TMODES) yann@1: +TFtype yann@1: +sf_to_tf (SFtype arg_a) yann@1: +{ yann@1: + fp_number_type in; yann@1: + FLO_union_type au; yann@1: + yann@1: + au.value = arg_a; yann@1: + unpack_d (&au, &in); yann@1: + yann@1: + return __make_tp (in.class, in.sign, in.normal_exp, yann@1: + ((UTItype) in.fraction.ll) << F_T_BITOFF); yann@1: +} yann@1: +#endif /* L_sf_to_df */ yann@1: + yann@1: +#endif /* ! FLOAT_ONLY */ yann@1: +#endif /* FLOAT */ yann@1: + yann@1: +#ifndef FLOAT yann@1: + yann@1: +extern SFtype __make_fp (fp_class_type, unsigned int, int, USItype); yann@1: + yann@1: +#if defined(L_make_df) yann@1: +DFtype yann@1: +__make_dp (fp_class_type class, unsigned int sign, int exp, UDItype frac) yann@1: +{ yann@1: + fp_number_type in; yann@1: + yann@1: + in.class = class; yann@1: + in.sign = sign; yann@1: + in.normal_exp = exp; yann@1: + in.fraction.ll = frac; yann@1: + return pack_d (&in); yann@1: +} yann@1: +#endif /* L_make_df */ yann@1: + yann@1: +#if defined(L_df_to_sf) yann@1: +SFtype yann@1: +df_to_sf (DFtype arg_a) yann@1: +{ yann@1: + fp_number_type in; yann@1: + USItype sffrac; yann@1: + FLO_union_type au; yann@1: + yann@1: + au.value = arg_a; yann@1: + unpack_d (&au, &in); yann@1: + yann@1: + sffrac = in.fraction.ll >> F_D_BITOFF; yann@1: + yann@1: + /* We set the lowest guard bit in SFFRAC if we discarded any non yann@1: + zero bits. */ yann@1: + if ((in.fraction.ll & (((USItype) 1 << F_D_BITOFF) - 1)) != 0) yann@1: + sffrac |= 1; yann@1: + yann@1: + return __make_fp (in.class, in.sign, in.normal_exp, sffrac); yann@1: +} yann@1: +#endif /* L_df_to_sf */ yann@1: + yann@1: +#if defined(L_df_to_tf) && defined(TMODES) \ yann@1: + && !defined(FLOAT) && !defined(TFLOAT) yann@1: +TFtype yann@1: +df_to_tf (DFtype arg_a) yann@1: +{ yann@1: + fp_number_type in; yann@1: + FLO_union_type au; yann@1: + yann@1: + au.value = arg_a; yann@1: + unpack_d (&au, &in); yann@1: + yann@1: + return __make_tp (in.class, in.sign, in.normal_exp, yann@1: + ((UTItype) in.fraction.ll) << D_T_BITOFF); yann@1: +} yann@1: +#endif /* L_sf_to_df */ yann@1: + yann@1: +#ifdef TFLOAT yann@1: +#if defined(L_make_tf) yann@1: +TFtype yann@1: +__make_tp(fp_class_type class, yann@1: + unsigned int sign, yann@1: + int exp, yann@1: + UTItype frac) yann@1: +{ yann@1: + fp_number_type in; yann@1: + yann@1: + in.class = class; yann@1: + in.sign = sign; yann@1: + in.normal_exp = exp; yann@1: + in.fraction.ll = frac; yann@1: + return pack_d (&in); yann@1: +} yann@1: +#endif /* L_make_tf */ yann@1: + yann@1: +#if defined(L_tf_to_df) yann@1: +DFtype yann@1: +tf_to_df (TFtype arg_a) yann@1: +{ yann@1: + fp_number_type in; yann@1: + UDItype sffrac; yann@1: + FLO_union_type au; yann@1: + yann@1: + au.value = arg_a; yann@1: + unpack_d (&au, &in); yann@1: + yann@1: + sffrac = in.fraction.ll >> D_T_BITOFF; yann@1: + yann@1: + /* We set the lowest guard bit in SFFRAC if we discarded any non yann@1: + zero bits. */ yann@1: + if ((in.fraction.ll & (((UTItype) 1 << D_T_BITOFF) - 1)) != 0) yann@1: + sffrac |= 1; yann@1: + yann@1: + return __make_dp (in.class, in.sign, in.normal_exp, sffrac); yann@1: +} yann@1: +#endif /* L_tf_to_df */ yann@1: + yann@1: +#if defined(L_tf_to_sf) yann@1: +SFtype yann@1: +tf_to_sf (TFtype arg_a) yann@1: +{ yann@1: + fp_number_type in; yann@1: + USItype sffrac; yann@1: + FLO_union_type au; yann@1: + yann@1: + au.value = arg_a; yann@1: + unpack_d (&au, &in); yann@1: + yann@1: + sffrac = in.fraction.ll >> F_T_BITOFF; yann@1: + yann@1: + /* We set the lowest guard bit in SFFRAC if we discarded any non yann@1: + zero bits. */ yann@1: + if ((in.fraction.ll & (((UTItype) 1 << F_T_BITOFF) - 1)) != 0) yann@1: + sffrac |= 1; yann@1: + yann@1: + return __make_fp (in.class, in.sign, in.normal_exp, sffrac); yann@1: +} yann@1: +#endif /* L_tf_to_sf */ yann@1: +#endif /* TFLOAT */ yann@1: + yann@1: +#endif /* ! FLOAT */ yann@1: +#endif /* !EXTENDED_FLOAT_STUBS */ yann@1: --- gcc-3.4.3/gcc/config/nios2/nios2-protos.h yann@1: +++ gcc-3.4.3-nios2/gcc/config/nios2/nios2-protos.h yann@1: @@ -0,0 +1,70 @@ yann@1: +/* Subroutines for assembler code output for Altera NIOS 2G NIOS2 version. yann@1: + Copyright (C) 2003 Altera yann@1: + Contributed by Jonah Graham (jgraham@altera.com). yann@1: + yann@1: +This file is part of GNU CC. yann@1: + yann@1: +GNU CC is free software; you can redistribute it and/or modify yann@1: +it under the terms of the GNU General Public License as published by yann@1: +the Free Software Foundation; either version 2, or (at your option) yann@1: +any later version. yann@1: + yann@1: +GNU CC is distributed in the hope that it will be useful, yann@1: +but WITHOUT ANY WARRANTY; without even the implied warranty of yann@1: +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the yann@1: +GNU General Public License for more details. yann@1: + yann@1: +You should have received a copy of the GNU General Public License yann@1: +along with GNU CC; see the file COPYING. If not, write to yann@1: +the Free Software Foundation, 59 Temple Place - Suite 330, yann@1: +Boston, MA 02111-1307, USA. */ yann@1: + yann@1: +extern void dump_frame_size (FILE *); yann@1: +extern HOST_WIDE_INT compute_frame_size (void); yann@1: +extern int nios2_initial_elimination_offset (int, int); yann@1: +extern void override_options (void); yann@1: +extern void optimization_options (int, int); yann@1: +extern int nios2_can_use_return_insn (void); yann@1: +extern void expand_prologue (void); yann@1: +extern void expand_epilogue (bool); yann@1: +extern void function_profiler (FILE *, int); yann@1: + yann@1: + yann@1: +#ifdef RTX_CODE yann@1: +extern int nios2_legitimate_address (rtx, enum machine_mode, int); yann@1: +extern void nios2_print_operand (FILE *, rtx, int); yann@1: +extern void nios2_print_operand_address (FILE *, rtx); yann@1: + yann@1: +extern int nios2_emit_move_sequence (rtx *, enum machine_mode); yann@1: +extern int nios2_emit_expensive_div (rtx *, enum machine_mode); yann@1: + yann@1: +extern void gen_int_relational (enum rtx_code, rtx, rtx, rtx, rtx); yann@1: +extern void gen_conditional_move (rtx *, enum machine_mode); yann@1: +extern const char *asm_output_opcode (FILE *, const char *); yann@1: + yann@1: +/* predicates */ yann@1: +extern int arith_operand (rtx, enum machine_mode); yann@1: +extern int uns_arith_operand (rtx, enum machine_mode); yann@1: +extern int logical_operand (rtx, enum machine_mode); yann@1: +extern int shift_operand (rtx, enum machine_mode); yann@1: +extern int reg_or_0_operand (rtx, enum machine_mode); yann@1: +extern int equality_op (rtx, enum machine_mode); yann@1: +extern int custom_insn_opcode (rtx, enum machine_mode); yann@1: +extern int rdwrctl_operand (rtx, enum machine_mode); yann@1: + yann@1: +# ifdef HAVE_MACHINE_MODES yann@1: +# if defined TREE_CODE yann@1: +extern void function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode, tree, int); yann@1: +extern rtx function_arg (const CUMULATIVE_ARGS *, enum machine_mode, tree, int); yann@1: +extern int function_arg_partial_nregs (const CUMULATIVE_ARGS *, enum machine_mode, tree, int); yann@1: +extern void init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree, int); yann@1: +extern int nios2_setup_incoming_varargs (const CUMULATIVE_ARGS *, enum machine_mode, tree, int); yann@1: + yann@1: +# endif /* TREE_CODE */ yann@1: +# endif /* HAVE_MACHINE_MODES */ yann@1: +#endif yann@1: + yann@1: +#ifdef TREE_CODE yann@1: +extern int nios2_return_in_memory (tree); yann@1: + yann@1: +#endif /* TREE_CODE */ yann@1: --- gcc-3.4.3/gcc/config/nios2/nios2.c yann@1: +++ gcc-3.4.3-nios2/gcc/config/nios2/nios2.c yann@1: @@ -0,0 +1,2853 @@ yann@1: +/* Subroutines for assembler code output for Altera NIOS 2G NIOS2 version. yann@1: + Copyright (C) 2003 Altera yann@1: + Contributed by Jonah Graham (jgraham@altera.com). yann@1: + yann@1: +This file is part of GNU CC. yann@1: + yann@1: +GNU CC is free software; you can redistribute it and/or modify yann@1: +it under the terms of the GNU General Public License as published by yann@1: +the Free Software Foundation; either version 2, or (at your option) yann@1: +any later version. yann@1: + yann@1: +GNU CC is distributed in the hope that it will be useful, yann@1: +but WITHOUT ANY WARRANTY; without even the implied warranty of yann@1: +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the yann@1: +GNU General Public License for more details. yann@1: + yann@1: +You should have received a copy of the GNU General Public License yann@1: +along with GNU CC; see the file COPYING. If not, write to yann@1: +the Free Software Foundation, 59 Temple Place - Suite 330, yann@1: +Boston, MA 02111-1307, USA. */ yann@1: + yann@1: + yann@1: +#include yann@1: +#include "config.h" yann@1: +#include "system.h" yann@1: +#include "coretypes.h" yann@1: +#include "tm.h" yann@1: +#include "rtl.h" yann@1: +#include "tree.h" yann@1: +#include "tm_p.h" yann@1: +#include "regs.h" yann@1: +#include "hard-reg-set.h" yann@1: +#include "real.h" yann@1: +#include "insn-config.h" yann@1: +#include "conditions.h" yann@1: +#include "output.h" yann@1: +#include "insn-attr.h" yann@1: +#include "flags.h" yann@1: +#include "recog.h" yann@1: +#include "expr.h" yann@1: +#include "toplev.h" yann@1: +#include "basic-block.h" yann@1: +#include "function.h" yann@1: +#include "ggc.h" yann@1: +#include "reload.h" yann@1: +#include "debug.h" yann@1: +#include "optabs.h" yann@1: +#include "target.h" yann@1: +#include "target-def.h" yann@1: + yann@1: +/* local prototypes */ yann@1: +static bool nios2_rtx_costs (rtx, int, int, int *); yann@1: + yann@1: +static void nios2_asm_function_prologue (FILE *, HOST_WIDE_INT); yann@1: +static int nios2_use_dfa_pipeline_interface (void); yann@1: +static int nios2_issue_rate (void); yann@1: +static struct machine_function *nios2_init_machine_status (void); yann@1: +static bool nios2_in_small_data_p (tree); yann@1: +static rtx save_reg (int, HOST_WIDE_INT, rtx); yann@1: +static rtx restore_reg (int, HOST_WIDE_INT); yann@1: +static unsigned int nios2_section_type_flags (tree, const char *, int); yann@1: +static void nios2_init_builtins (void); yann@1: +static rtx nios2_expand_builtin (tree, rtx, rtx, enum machine_mode, int); yann@1: +static bool nios2_function_ok_for_sibcall (tree, tree); yann@1: +static void nios2_encode_section_info (tree, rtx, int); yann@1: + yann@1: +/* Initialize the GCC target structure. */ yann@1: +#undef TARGET_ASM_FUNCTION_PROLOGUE yann@1: +#define TARGET_ASM_FUNCTION_PROLOGUE nios2_asm_function_prologue yann@1: + yann@1: +#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE yann@1: +#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE \ yann@1: + nios2_use_dfa_pipeline_interface yann@1: +#undef TARGET_SCHED_ISSUE_RATE yann@1: +#define TARGET_SCHED_ISSUE_RATE nios2_issue_rate yann@1: +#undef TARGET_IN_SMALL_DATA_P yann@1: +#define TARGET_IN_SMALL_DATA_P nios2_in_small_data_p yann@1: +#undef TARGET_ENCODE_SECTION_INFO yann@1: +#define TARGET_ENCODE_SECTION_INFO nios2_encode_section_info yann@1: +#undef TARGET_SECTION_TYPE_FLAGS yann@1: +#define TARGET_SECTION_TYPE_FLAGS nios2_section_type_flags yann@1: + yann@1: +#undef TARGET_INIT_BUILTINS yann@1: +#define TARGET_INIT_BUILTINS nios2_init_builtins yann@1: +#undef TARGET_EXPAND_BUILTIN yann@1: +#define TARGET_EXPAND_BUILTIN nios2_expand_builtin yann@1: + yann@1: +#undef TARGET_FUNCTION_OK_FOR_SIBCALL yann@1: +#define TARGET_FUNCTION_OK_FOR_SIBCALL nios2_function_ok_for_sibcall yann@1: + yann@1: +#undef TARGET_RTX_COSTS yann@1: +#define TARGET_RTX_COSTS nios2_rtx_costs yann@1: + yann@1: + yann@1: +struct gcc_target targetm = TARGET_INITIALIZER; yann@1: + yann@1: + yann@1: + yann@1: +/* Threshold for data being put into the small data/bss area, instead yann@1: + of the normal data area (references to the small data/bss area take yann@1: + 1 instruction, and use the global pointer, references to the normal yann@1: + data area takes 2 instructions). */ yann@1: +unsigned HOST_WIDE_INT nios2_section_threshold = NIOS2_DEFAULT_GVALUE; yann@1: + yann@1: + yann@1: +/* Structure to be filled in by compute_frame_size with register yann@1: + save masks, and offsets for the current function. */ yann@1: + yann@1: +struct nios2_frame_info yann@1: +GTY (()) yann@1: +{ yann@1: + long total_size; /* # bytes that the entire frame takes up */ yann@1: + long var_size; /* # bytes that variables take up */ yann@1: + long args_size; /* # bytes that outgoing arguments take up */ yann@1: + int save_reg_size; /* # bytes needed to store gp regs */ yann@1: + int save_reg_rounded; /* # bytes needed to store gp regs */ yann@1: + long save_regs_offset; /* offset from new sp to store gp registers */ yann@1: + int initialized; /* != 0 if frame size already calculated */ yann@1: + int num_regs; /* number of gp registers saved */ yann@1: +}; yann@1: + yann@1: +struct machine_function yann@1: +GTY (()) yann@1: +{ yann@1: + yann@1: + /* Current frame information, calculated by compute_frame_size. */ yann@1: + struct nios2_frame_info frame; yann@1: +}; yann@1: + yann@1: + yann@1: +/*************************************** yann@1: + * Section encodings yann@1: + ***************************************/ yann@1: + yann@1: + yann@1: + yann@1: + yann@1: + yann@1: +/*************************************** yann@1: + * Stack Layout and Calling Conventions yann@1: + ***************************************/ yann@1: + yann@1: + yann@1: +#define TOO_BIG_OFFSET(X) ((X) > ((1 << 15) - 1)) yann@1: +#define TEMP_REG_NUM 8 yann@1: + yann@1: +static void yann@1: +nios2_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED) yann@1: +{ yann@1: + if (flag_verbose_asm || flag_debug_asm) yann@1: + { yann@1: + compute_frame_size (); yann@1: + dump_frame_size (file); yann@1: + } yann@1: +} yann@1: + yann@1: +static rtx yann@1: +save_reg (int regno, HOST_WIDE_INT offset, rtx cfa_store_reg) yann@1: +{ yann@1: + rtx insn, stack_slot; yann@1: + yann@1: + stack_slot = gen_rtx_PLUS (SImode, yann@1: + cfa_store_reg, yann@1: + GEN_INT (offset)); yann@1: + yann@1: + insn = emit_insn (gen_rtx_SET (SImode, yann@1: + gen_rtx_MEM (SImode, stack_slot), yann@1: + gen_rtx_REG (SImode, regno))); yann@1: + yann@1: + RTX_FRAME_RELATED_P (insn) = 1; yann@1: + yann@1: + return insn; yann@1: +} yann@1: + yann@1: +static rtx yann@1: +restore_reg (int regno, HOST_WIDE_INT offset) yann@1: +{ yann@1: + rtx insn, stack_slot; yann@1: + yann@1: + if (TOO_BIG_OFFSET (offset)) yann@1: + { yann@1: + stack_slot = gen_rtx_REG (SImode, TEMP_REG_NUM); yann@1: + insn = emit_insn (gen_rtx_SET (SImode, yann@1: + stack_slot, yann@1: + GEN_INT (offset))); yann@1: + yann@1: + insn = emit_insn (gen_rtx_SET (SImode, yann@1: + stack_slot, yann@1: + gen_rtx_PLUS (SImode, yann@1: + stack_slot, yann@1: + stack_pointer_rtx))); yann@1: + } yann@1: + else yann@1: + { yann@1: + stack_slot = gen_rtx_PLUS (SImode, yann@1: + stack_pointer_rtx, yann@1: + GEN_INT (offset)); yann@1: + } yann@1: + yann@1: + stack_slot = gen_rtx_MEM (SImode, stack_slot); yann@1: + yann@1: + insn = emit_move_insn (gen_rtx_REG (SImode, regno), stack_slot); yann@1: + yann@1: + return insn; yann@1: +} yann@1: + yann@1: + yann@1: +/* There are two possible paths for prologue expansion, yann@1: +- the first is if the total frame size is < 2^15-1. In that yann@1: +case all the immediates will fit into the 16-bit immediate yann@1: +fields. yann@1: +- the second is when the frame size is too big, in that yann@1: +case an additional temporary register is used, first yann@1: +as a cfa_temp to offset the sp, second as the cfa_store yann@1: +register. yann@1: + yann@1: +See the comment above dwarf2out_frame_debug_expr in yann@1: +dwarf2out.c for more explanation of the "rules." yann@1: + yann@1: + yann@1: +Case 1: yann@1: +Rule # Example Insn Effect yann@1: +2 addi sp, sp, -total_frame_size cfa.reg=sp, cfa.offset=total_frame_size yann@1: + cfa_store.reg=sp, cfa_store.offset=total_frame_size yann@1: +12 stw ra, offset(sp) yann@1: +12 stw r16, offset(sp) yann@1: +1 mov fp, sp yann@1: + yann@1: +Case 2: yann@1: +Rule # Example Insn Effect yann@1: +6 movi r8, total_frame_size cfa_temp.reg=r8, cfa_temp.offset=total_frame_size yann@1: +2 sub sp, sp, r8 cfa.reg=sp, cfa.offset=total_frame_size yann@1: + cfa_store.reg=sp, cfa_store.offset=total_frame_size yann@1: +5 add r8, r8, sp cfa_store.reg=r8, cfa_store.offset=0 yann@1: +12 stw ra, offset(r8) yann@1: +12 stw r16, offset(r8) yann@1: +1 mov fp, sp yann@1: + yann@1: +*/ yann@1: + yann@1: +void yann@1: +expand_prologue () yann@1: +{ yann@1: + int i; yann@1: + HOST_WIDE_INT total_frame_size; yann@1: + int cfa_store_offset; yann@1: + rtx insn; yann@1: + rtx cfa_store_reg = 0; yann@1: + yann@1: + total_frame_size = compute_frame_size (); yann@1: + yann@1: + if (total_frame_size) yann@1: + { yann@1: + yann@1: + if (TOO_BIG_OFFSET (total_frame_size)) yann@1: + { yann@1: + /* cfa_temp and cfa_store_reg are the same register, yann@1: + cfa_store_reg overwrites cfa_temp */ yann@1: + cfa_store_reg = gen_rtx_REG (SImode, TEMP_REG_NUM); yann@1: + insn = emit_insn (gen_rtx_SET (SImode, yann@1: + cfa_store_reg, yann@1: + GEN_INT (total_frame_size))); yann@1: + yann@1: + RTX_FRAME_RELATED_P (insn) = 1; yann@1: + yann@1: + yann@1: + insn = gen_rtx_SET (SImode, yann@1: + stack_pointer_rtx, yann@1: + gen_rtx_MINUS (SImode, yann@1: + stack_pointer_rtx, yann@1: + cfa_store_reg)); yann@1: + yann@1: + insn = emit_insn (insn); yann@1: + RTX_FRAME_RELATED_P (insn) = 1; yann@1: + yann@1: + yann@1: + /* if there are no registers to save, I don't need to yann@1: + create a cfa_store */ yann@1: + if (cfun->machine->frame.save_reg_size) yann@1: + { yann@1: + insn = gen_rtx_SET (SImode, yann@1: + cfa_store_reg, yann@1: + gen_rtx_PLUS (SImode, yann@1: + cfa_store_reg, yann@1: + stack_pointer_rtx)); yann@1: + yann@1: + insn = emit_insn (insn); yann@1: + RTX_FRAME_RELATED_P (insn) = 1; yann@1: + } yann@1: + yann@1: + cfa_store_offset yann@1: + = total_frame_size yann@1: + - (cfun->machine->frame.save_regs_offset yann@1: + + cfun->machine->frame.save_reg_rounded); yann@1: + } yann@1: + else yann@1: + { yann@1: + insn = gen_rtx_SET (SImode, yann@1: + stack_pointer_rtx, yann@1: + gen_rtx_PLUS (SImode, yann@1: + stack_pointer_rtx, yann@1: + GEN_INT (-total_frame_size))); yann@1: + insn = emit_insn (insn); yann@1: + RTX_FRAME_RELATED_P (insn) = 1; yann@1: + yann@1: + cfa_store_reg = stack_pointer_rtx; yann@1: + cfa_store_offset yann@1: + = cfun->machine->frame.save_regs_offset yann@1: + + cfun->machine->frame.save_reg_rounded; yann@1: + } yann@1: + } yann@1: + yann@1: + if (MUST_SAVE_REGISTER (RA_REGNO)) yann@1: + { yann@1: + cfa_store_offset -= 4; yann@1: + save_reg (RA_REGNO, cfa_store_offset, cfa_store_reg); yann@1: + } yann@1: + if (MUST_SAVE_REGISTER (FP_REGNO)) yann@1: + { yann@1: + cfa_store_offset -= 4; yann@1: + save_reg (FP_REGNO, cfa_store_offset, cfa_store_reg); yann@1: + } yann@1: + yann@1: + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) yann@1: + { yann@1: + if (MUST_SAVE_REGISTER (i) && i != FP_REGNO && i != RA_REGNO) yann@1: + { yann@1: + cfa_store_offset -= 4; yann@1: + save_reg (i, cfa_store_offset, cfa_store_reg); yann@1: + } yann@1: + } yann@1: + yann@1: + if (frame_pointer_needed) yann@1: + { yann@1: + insn = emit_insn (gen_rtx_SET (SImode, yann@1: + gen_rtx_REG (SImode, FP_REGNO), yann@1: + gen_rtx_REG (SImode, SP_REGNO))); yann@1: + yann@1: + RTX_FRAME_RELATED_P (insn) = 1; yann@1: + } yann@1: + yann@1: + /* If we are profiling, make sure no instructions are scheduled before yann@1: + the call to mcount. */ yann@1: + if (current_function_profile) yann@1: + emit_insn (gen_blockage ()); yann@1: +} yann@1: + yann@1: +void yann@1: +expand_epilogue (bool sibcall_p) yann@1: +{ yann@1: + rtx insn; yann@1: + int i; yann@1: + HOST_WIDE_INT total_frame_size; yann@1: + int register_store_offset; yann@1: + yann@1: + total_frame_size = compute_frame_size (); yann@1: + yann@1: + if (!sibcall_p && nios2_can_use_return_insn ()) yann@1: + { yann@1: + insn = emit_jump_insn (gen_return ()); yann@1: + return; yann@1: + } yann@1: + yann@1: + emit_insn (gen_blockage ()); yann@1: + yann@1: + register_store_offset = yann@1: + cfun->machine->frame.save_regs_offset + yann@1: + cfun->machine->frame.save_reg_rounded; yann@1: + yann@1: + if (MUST_SAVE_REGISTER (RA_REGNO)) yann@1: + { yann@1: + register_store_offset -= 4; yann@1: + restore_reg (RA_REGNO, register_store_offset); yann@1: + } yann@1: + yann@1: + if (MUST_SAVE_REGISTER (FP_REGNO)) yann@1: + { yann@1: + register_store_offset -= 4; yann@1: + restore_reg (FP_REGNO, register_store_offset); yann@1: + } yann@1: + yann@1: + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) yann@1: + { yann@1: + if (MUST_SAVE_REGISTER (i) && i != FP_REGNO && i != RA_REGNO) yann@1: + { yann@1: + register_store_offset -= 4; yann@1: + restore_reg (i, register_store_offset); yann@1: + } yann@1: + } yann@1: + yann@1: + if (total_frame_size) yann@1: + { yann@1: + rtx sp_adjust; yann@1: + yann@1: + if (TOO_BIG_OFFSET (total_frame_size)) yann@1: + { yann@1: + sp_adjust = gen_rtx_REG (SImode, TEMP_REG_NUM); yann@1: + insn = emit_insn (gen_rtx_SET (SImode, yann@1: + sp_adjust, yann@1: + GEN_INT (total_frame_size))); yann@1: + yann@1: + } yann@1: + else yann@1: + { yann@1: + sp_adjust = GEN_INT (total_frame_size); yann@1: + } yann@1: + yann@1: + insn = gen_rtx_SET (SImode, yann@1: + stack_pointer_rtx, yann@1: + gen_rtx_PLUS (SImode, yann@1: + stack_pointer_rtx, yann@1: + sp_adjust)); yann@1: + insn = emit_insn (insn); yann@1: + } yann@1: + yann@1: + yann@1: + if (!sibcall_p) yann@1: + { yann@1: + insn = emit_jump_insn (gen_return_from_epilogue (gen_rtx (REG, Pmode, yann@1: + RA_REGNO))); yann@1: + } yann@1: +} yann@1: + yann@1: + yann@1: +bool yann@1: +nios2_function_ok_for_sibcall (tree a ATTRIBUTE_UNUSED, tree b ATTRIBUTE_UNUSED) yann@1: +{ yann@1: + return true; yann@1: +} yann@1: + yann@1: + yann@1: + yann@1: + yann@1: + yann@1: +/* ----------------------- * yann@1: + * Profiling yann@1: + * ----------------------- */ yann@1: + yann@1: +void yann@1: +function_profiler (FILE *file, int labelno) yann@1: +{ yann@1: + fprintf (file, "\t%s mcount begin, label: .LP%d\n", yann@1: + ASM_COMMENT_START, labelno); yann@1: + fprintf (file, "\tnextpc\tr8\n"); yann@1: + fprintf (file, "\tmov\tr9, ra\n"); yann@1: + fprintf (file, "\tmovhi\tr10, %%hiadj(.LP%d)\n", labelno); yann@1: + fprintf (file, "\taddi\tr10, r10, %%lo(.LP%d)\n", labelno); yann@1: + fprintf (file, "\tcall\tmcount\n"); yann@1: + fprintf (file, "\tmov\tra, r9\n"); yann@1: + fprintf (file, "\t%s mcount end\n", ASM_COMMENT_START); yann@1: +} yann@1: + yann@1: + yann@1: +/*************************************** yann@1: + * Stack Layout yann@1: + ***************************************/ yann@1: + yann@1: + yann@1: +void yann@1: +dump_frame_size (FILE *file) yann@1: +{ yann@1: + fprintf (file, "\t%s Current Frame Info\n", ASM_COMMENT_START); yann@1: + yann@1: + fprintf (file, "\t%s total_size = %ld\n", ASM_COMMENT_START, yann@1: + cfun->machine->frame.total_size); yann@1: + fprintf (file, "\t%s var_size = %ld\n", ASM_COMMENT_START, yann@1: + cfun->machine->frame.var_size); yann@1: + fprintf (file, "\t%s args_size = %ld\n", ASM_COMMENT_START, yann@1: + cfun->machine->frame.args_size); yann@1: + fprintf (file, "\t%s save_reg_size = %d\n", ASM_COMMENT_START, yann@1: + cfun->machine->frame.save_reg_size); yann@1: + fprintf (file, "\t%s save_reg_rounded = %d\n", ASM_COMMENT_START, yann@1: + cfun->machine->frame.save_reg_rounded); yann@1: + fprintf (file, "\t%s initialized = %d\n", ASM_COMMENT_START, yann@1: + cfun->machine->frame.initialized); yann@1: + fprintf (file, "\t%s num_regs = %d\n", ASM_COMMENT_START, yann@1: + cfun->machine->frame.num_regs); yann@1: + fprintf (file, "\t%s save_regs_offset = %ld\n", ASM_COMMENT_START, yann@1: + cfun->machine->frame.save_regs_offset); yann@1: + fprintf (file, "\t%s current_function_is_leaf = %d\n", ASM_COMMENT_START, yann@1: + current_function_is_leaf); yann@1: + fprintf (file, "\t%s frame_pointer_needed = %d\n", ASM_COMMENT_START, yann@1: + frame_pointer_needed); yann@1: + fprintf (file, "\t%s pretend_args_size = %d\n", ASM_COMMENT_START, yann@1: + current_function_pretend_args_size); yann@1: + yann@1: +} yann@1: + yann@1: + yann@1: +/* Return the bytes needed to compute the frame pointer from the current yann@1: + stack pointer. yann@1: +*/ yann@1: + yann@1: +HOST_WIDE_INT yann@1: +compute_frame_size () yann@1: +{ yann@1: + unsigned int regno; yann@1: + HOST_WIDE_INT var_size; /* # of var. bytes allocated */ yann@1: + HOST_WIDE_INT total_size; /* # bytes that the entire frame takes up */ yann@1: + HOST_WIDE_INT save_reg_size; /* # bytes needed to store callee save regs */ yann@1: + HOST_WIDE_INT save_reg_rounded; yann@1: + /* # bytes needed to store callee save regs (rounded) */ yann@1: + HOST_WIDE_INT out_args_size; /* # bytes needed for outgoing args */ yann@1: + yann@1: + save_reg_size = 0; yann@1: + var_size = STACK_ALIGN (get_frame_size ()); yann@1: + out_args_size = STACK_ALIGN (current_function_outgoing_args_size); yann@1: + yann@1: + total_size = var_size + out_args_size; yann@1: + yann@1: + /* Calculate space needed for gp registers. */ yann@1: + for (regno = 0; regno <= FIRST_PSEUDO_REGISTER; regno++) yann@1: + { yann@1: + if (MUST_SAVE_REGISTER (regno)) yann@1: + { yann@1: + save_reg_size += 4; yann@1: + } yann@1: + } yann@1: + yann@1: + save_reg_rounded = STACK_ALIGN (save_reg_size); yann@1: + total_size += save_reg_rounded; yann@1: + yann@1: + total_size += STACK_ALIGN (current_function_pretend_args_size); yann@1: + yann@1: + /* Save other computed information. */ yann@1: + cfun->machine->frame.total_size = total_size; yann@1: + cfun->machine->frame.var_size = var_size; yann@1: + cfun->machine->frame.args_size = current_function_outgoing_args_size; yann@1: + cfun->machine->frame.save_reg_size = save_reg_size; yann@1: + cfun->machine->frame.save_reg_rounded = save_reg_rounded; yann@1: + cfun->machine->frame.initialized = reload_completed; yann@1: + cfun->machine->frame.num_regs = save_reg_size / UNITS_PER_WORD; yann@1: + yann@1: + cfun->machine->frame.save_regs_offset yann@1: + = save_reg_rounded ? current_function_outgoing_args_size + var_size : 0; yann@1: + yann@1: + return total_size; yann@1: +} yann@1: + yann@1: + yann@1: +int yann@1: +nios2_initial_elimination_offset (int from, int to ATTRIBUTE_UNUSED) yann@1: +{ yann@1: + int offset; yann@1: + yann@1: + /* Set OFFSET to the offset from the stack pointer. */ yann@1: + switch (from) yann@1: + { yann@1: + case FRAME_POINTER_REGNUM: yann@1: + offset = 0; yann@1: + break; yann@1: + yann@1: + case ARG_POINTER_REGNUM: yann@1: + compute_frame_size (); yann@1: + offset = cfun->machine->frame.total_size; yann@1: + offset -= current_function_pretend_args_size; yann@1: + break; yann@1: + yann@1: + case RETURN_ADDRESS_POINTER_REGNUM: yann@1: + compute_frame_size (); yann@1: + /* since the return address is always the first of the yann@1: + saved registers, return the offset to the beginning yann@1: + of the saved registers block */ yann@1: + offset = cfun->machine->frame.save_regs_offset; yann@1: + break; yann@1: + yann@1: + default: yann@1: + abort (); yann@1: + } yann@1: + yann@1: + return offset; yann@1: +} yann@1: + yann@1: +/* Return nonzero if this function is known to have a null epilogue. yann@1: + This allows the optimizer to omit jumps to jumps if no stack yann@1: + was created. */ yann@1: +int yann@1: +nios2_can_use_return_insn () yann@1: +{ yann@1: + if (!reload_completed) yann@1: + return 0; yann@1: + yann@1: + if (regs_ever_live[RA_REGNO] || current_function_profile) yann@1: + return 0; yann@1: + yann@1: + if (cfun->machine->frame.initialized) yann@1: + return cfun->machine->frame.total_size == 0; yann@1: + yann@1: + return compute_frame_size () == 0; yann@1: +} yann@1: + yann@1: + yann@1: + yann@1: + yann@1: + yann@1: +/*************************************** yann@1: + * yann@1: + ***************************************/ yann@1: + yann@1: +const char *nios2_sys_nosys_string; /* for -msys=nosys */ yann@1: +const char *nios2_sys_lib_string; /* for -msys-lib= */ yann@1: +const char *nios2_sys_crt0_string; /* for -msys-crt0= */ yann@1: + yann@1: +void yann@1: +override_options () yann@1: +{ yann@1: + /* Function to allocate machine-dependent function status. */ yann@1: + init_machine_status = &nios2_init_machine_status; yann@1: + yann@1: + nios2_section_threshold yann@1: + = g_switch_set ? g_switch_value : NIOS2_DEFAULT_GVALUE; yann@1: + yann@1: + if (nios2_sys_nosys_string && *nios2_sys_nosys_string) yann@1: + { yann@1: + error ("invalid option '-msys=nosys%s'", nios2_sys_nosys_string); yann@1: + } yann@1: + yann@1: + /* If we don't have mul, we don't have mulx either! */ yann@1: + if (!TARGET_HAS_MUL && TARGET_HAS_MULX) yann@1: + { yann@1: + target_flags &= ~HAS_MULX_FLAG; yann@1: + } yann@1: + yann@1: +} yann@1: + yann@1: +void yann@1: +optimization_options (int level, int size) yann@1: +{ yann@1: + if (level || size) yann@1: + { yann@1: + target_flags |= INLINE_MEMCPY_FLAG; yann@1: + } yann@1: + yann@1: + if (level >= 3 && !size) yann@1: + { yann@1: + target_flags |= FAST_SW_DIV_FLAG; yann@1: + } yann@1: +} yann@1: + yann@1: +/* Allocate a chunk of memory for per-function machine-dependent data. */ yann@1: +static struct machine_function * yann@1: +nios2_init_machine_status () yann@1: +{ yann@1: + return ((struct machine_function *) yann@1: + ggc_alloc_cleared (sizeof (struct machine_function))); yann@1: +} yann@1: + yann@1: + yann@1: + yann@1: +/***************** yann@1: + * Describing Relative Costs of Operations yann@1: + *****************/ yann@1: + yann@1: +/* Compute a (partial) cost for rtx X. Return true if the complete yann@1: + cost has been computed, and false if subexpressions should be yann@1: + scanned. In either case, *TOTAL contains the cost result. */ yann@1: + yann@1: + yann@1: + yann@1: +static bool yann@1: +nios2_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total) yann@1: +{ yann@1: + switch (code) yann@1: + { yann@1: + case CONST_INT: yann@1: + if (INTVAL (x) == 0) yann@1: + { yann@1: + *total = COSTS_N_INSNS (0); yann@1: + return true; yann@1: + } yann@1: + else if (SMALL_INT (INTVAL (x)) yann@1: + || SMALL_INT_UNSIGNED (INTVAL (x)) yann@1: + || UPPER16_INT (INTVAL (x))) yann@1: + { yann@1: + *total = COSTS_N_INSNS (2); yann@1: + return true; yann@1: + } yann@1: + else yann@1: + { yann@1: + *total = COSTS_N_INSNS (4); yann@1: + return true; yann@1: + } yann@1: + yann@1: + case LABEL_REF: yann@1: + case SYMBOL_REF: yann@1: + /* ??? gp relative stuff will fit in here */ yann@1: + /* fall through */ yann@1: + case CONST: yann@1: + case CONST_DOUBLE: yann@1: + { yann@1: + *total = COSTS_N_INSNS (4); yann@1: + return true; yann@1: + } yann@1: + yann@1: + case MULT: yann@1: + { yann@1: + *total = COSTS_N_INSNS (1); yann@1: + return false; yann@1: + } yann@1: + case SIGN_EXTEND: yann@1: + { yann@1: + *total = COSTS_N_INSNS (3); yann@1: + return false; yann@1: + } yann@1: + case ZERO_EXTEND: yann@1: + { yann@1: + *total = COSTS_N_INSNS (1); yann@1: + return false; yann@1: + } yann@1: + yann@1: + default: yann@1: + return false; yann@1: + } yann@1: +} yann@1: + yann@1: + yann@1: +/*************************************** yann@1: + * INSTRUCTION SUPPORT yann@1: + * yann@1: + * These functions are used within the Machine Description to yann@1: + * handle common or complicated output and expansions from yann@1: + * instructions. yann@1: + ***************************************/ yann@1: + yann@1: +int yann@1: +nios2_emit_move_sequence (rtx *operands, enum machine_mode mode) yann@1: +{ yann@1: + rtx to = operands[0]; yann@1: + rtx from = operands[1]; yann@1: + yann@1: + if (!register_operand (to, mode) && !reg_or_0_operand (from, mode)) yann@1: + { yann@1: + if (no_new_pseudos) yann@1: + internal_error ("Trying to force_reg no_new_pseudos == 1"); yann@1: + from = copy_to_mode_reg (mode, from); yann@1: + } yann@1: + yann@1: + operands[0] = to; yann@1: + operands[1] = from; yann@1: + return 0; yann@1: +} yann@1: + yann@1: +/* Divide Support */ yann@1: + yann@1: +/* yann@1: + If -O3 is used, we want to output a table lookup for yann@1: + divides between small numbers (both num and den >= 0 yann@1: + and < 0x10). The overhead of this method in the worse yann@1: + case is 40 bytes in the text section (10 insns) and yann@1: + 256 bytes in the data section. Additional divides do yann@1: + not incur additional penalties in the data section. yann@1: + yann@1: + Code speed is improved for small divides by about 5x yann@1: + when using this method in the worse case (~9 cycles yann@1: + vs ~45). And in the worse case divides not within the yann@1: + table are penalized by about 10% (~5 cycles vs ~45). yann@1: + However in the typical case the penalty is not as bad yann@1: + because doing the long divide in only 45 cycles is yann@1: + quite optimistic. yann@1: + yann@1: + ??? It would be nice to have some benchmarks other yann@1: + than Dhrystone to back this up. yann@1: + yann@1: + This bit of expansion is to create this instruction yann@1: + sequence as rtl. yann@1: + or $8, $4, $5 yann@1: + slli $9, $4, 4 yann@1: + cmpgeui $3, $8, 16 yann@1: + beq $3, $0, .L3 yann@1: + or $10, $9, $5 yann@1: + add $12, $11, divide_table yann@1: + ldbu $2, 0($12) yann@1: + br .L1 yann@1: +.L3: yann@1: + call slow_div yann@1: +.L1: yann@1: +# continue here with result in $2 yann@1: + yann@1: + ??? Ideally I would like the emit libcall block to contain yann@1: + all of this code, but I don't know how to do that. What it yann@1: + means is that if the divide can be eliminated, it may not yann@1: + completely disappear. yann@1: + yann@1: + ??? The __divsi3_table label should ideally be moved out yann@1: + of this block and into a global. If it is placed into the yann@1: + sdata section we can save even more cycles by doing things yann@1: + gp relative. yann@1: +*/ yann@1: +int yann@1: +nios2_emit_expensive_div (rtx *operands, enum machine_mode mode) yann@1: +{ yann@1: + rtx or_result, shift_left_result; yann@1: + rtx lookup_value; yann@1: + rtx lab1, lab3; yann@1: + rtx insns; yann@1: + rtx libfunc; yann@1: + rtx final_result; yann@1: + rtx tmp; yann@1: + yann@1: + /* it may look a little generic, but only SImode yann@1: + is supported for now */ yann@1: + if (mode != SImode) yann@1: + abort (); yann@1: + yann@1: + libfunc = sdiv_optab->handlers[(int) SImode].libfunc; yann@1: + yann@1: + yann@1: + yann@1: + lab1 = gen_label_rtx (); yann@1: + lab3 = gen_label_rtx (); yann@1: + yann@1: + or_result = expand_simple_binop (SImode, IOR, yann@1: + operands[1], operands[2], yann@1: + 0, 0, OPTAB_LIB_WIDEN); yann@1: + yann@1: + emit_cmp_and_jump_insns (or_result, GEN_INT (15), GTU, 0, yann@1: + GET_MODE (or_result), 0, lab3); yann@1: + JUMP_LABEL (get_last_insn ()) = lab3; yann@1: + yann@1: + shift_left_result = expand_simple_binop (SImode, ASHIFT, yann@1: + operands[1], GEN_INT (4), yann@1: + 0, 0, OPTAB_LIB_WIDEN); yann@1: + yann@1: + lookup_value = expand_simple_binop (SImode, IOR, yann@1: + shift_left_result, operands[2], yann@1: + 0, 0, OPTAB_LIB_WIDEN); yann@1: + yann@1: + convert_move (operands[0], yann@1: + gen_rtx (MEM, QImode, yann@1: + gen_rtx (PLUS, SImode, yann@1: + lookup_value, yann@1: + gen_rtx_SYMBOL_REF (SImode, "__divsi3_table"))), yann@1: + 1); yann@1: + yann@1: + yann@1: + tmp = emit_jump_insn (gen_jump (lab1)); yann@1: + JUMP_LABEL (tmp) = lab1; yann@1: + emit_barrier (); yann@1: + yann@1: + emit_label (lab3); yann@1: + LABEL_NUSES (lab3) = 1; yann@1: + yann@1: + start_sequence (); yann@1: + final_result = emit_library_call_value (libfunc, NULL_RTX, yann@1: + LCT_CONST, SImode, 2, yann@1: + operands[1], SImode, yann@1: + operands[2], SImode); yann@1: + yann@1: + yann@1: + insns = get_insns (); yann@1: + end_sequence (); yann@1: + emit_libcall_block (insns, operands[0], final_result, yann@1: + gen_rtx (DIV, SImode, operands[1], operands[2])); yann@1: + yann@1: + emit_label (lab1); yann@1: + LABEL_NUSES (lab1) = 1; yann@1: + return 1; yann@1: +} yann@1: + yann@1: +/* Branches/Compares */ yann@1: + yann@1: +/* the way of handling branches/compares yann@1: + in gcc is heavily borrowed from MIPS */ yann@1: + yann@1: +enum internal_test yann@1: +{ yann@1: + ITEST_EQ, yann@1: + ITEST_NE, yann@1: + ITEST_GT, yann@1: + ITEST_GE, yann@1: + ITEST_LT, yann@1: + ITEST_LE, yann@1: + ITEST_GTU, yann@1: + ITEST_GEU, yann@1: + ITEST_LTU, yann@1: + ITEST_LEU, yann@1: + ITEST_MAX yann@1: +}; yann@1: + yann@1: +static enum internal_test map_test_to_internal_test (enum rtx_code); yann@1: + yann@1: +/* Cached operands, and operator to compare for use in set/branch/trap yann@1: + on condition codes. */ yann@1: +rtx branch_cmp[2]; yann@1: +enum cmp_type branch_type; yann@1: + yann@1: +/* Make normal rtx_code into something we can index from an array */ yann@1: + yann@1: +static enum internal_test yann@1: +map_test_to_internal_test (enum rtx_code test_code) yann@1: +{ yann@1: + enum internal_test test = ITEST_MAX; yann@1: + yann@1: + switch (test_code) yann@1: + { yann@1: + case EQ: yann@1: + test = ITEST_EQ; yann@1: + break; yann@1: + case NE: yann@1: + test = ITEST_NE; yann@1: + break; yann@1: + case GT: yann@1: + test = ITEST_GT; yann@1: + break; yann@1: + case GE: yann@1: + test = ITEST_GE; yann@1: + break; yann@1: + case LT: yann@1: + test = ITEST_LT; yann@1: + break; yann@1: + case LE: yann@1: + test = ITEST_LE; yann@1: + break; yann@1: + case GTU: yann@1: + test = ITEST_GTU; yann@1: + break; yann@1: + case GEU: yann@1: + test = ITEST_GEU; yann@1: + break; yann@1: + case LTU: yann@1: + test = ITEST_LTU; yann@1: + break; yann@1: + case LEU: yann@1: + test = ITEST_LEU; yann@1: + break; yann@1: + default: yann@1: + break; yann@1: + } yann@1: + yann@1: + return test; yann@1: +} yann@1: + yann@1: +/* Generate the code to compare (and possibly branch) two integer values yann@1: + TEST_CODE is the comparison code we are trying to emulate yann@1: + (or implement directly) yann@1: + RESULT is where to store the result of the comparison, yann@1: + or null to emit a branch yann@1: + CMP0 CMP1 are the two comparison operands yann@1: + DESTINATION is the destination of the branch, or null to only compare yann@1: + */ yann@1: + yann@1: +void yann@1: +gen_int_relational (enum rtx_code test_code, /* relational test (EQ, etc) */ yann@1: + rtx result, /* result to store comp. or 0 if branch */ yann@1: + rtx cmp0, /* first operand to compare */ yann@1: + rtx cmp1, /* second operand to compare */ yann@1: + rtx destination) /* destination of the branch, or 0 if compare */ yann@1: +{ yann@1: + struct cmp_info yann@1: + { yann@1: + /* for register (or 0) compares */ yann@1: + enum rtx_code test_code_reg; /* code to use in instruction (LT vs. LTU) */ yann@1: + int reverse_regs; /* reverse registers in test */ yann@1: + yann@1: + /* for immediate compares */ yann@1: + enum rtx_code test_code_const; yann@1: + /* code to use in instruction (LT vs. LTU) */ yann@1: + int const_low; /* low bound of constant we can accept */ yann@1: + int const_high; /* high bound of constant we can accept */ yann@1: + int const_add; /* constant to add */ yann@1: + yann@1: + /* generic info */ yann@1: + int unsignedp; /* != 0 for unsigned comparisons. */ yann@1: + }; yann@1: + yann@1: + static const struct cmp_info info[(int) ITEST_MAX] = { yann@1: + yann@1: + {EQ, 0, EQ, -32768, 32767, 0, 0}, /* EQ */ yann@1: + {NE, 0, NE, -32768, 32767, 0, 0}, /* NE */ yann@1: + yann@1: + {LT, 1, GE, -32769, 32766, 1, 0}, /* GT */ yann@1: + {GE, 0, GE, -32768, 32767, 0, 0}, /* GE */ yann@1: + {LT, 0, LT, -32768, 32767, 0, 0}, /* LT */ yann@1: + {GE, 1, LT, -32769, 32766, 1, 0}, /* LE */ yann@1: + yann@1: + {LTU, 1, GEU, 0, 65534, 1, 0}, /* GTU */ yann@1: + {GEU, 0, GEU, 0, 65535, 0, 0}, /* GEU */ yann@1: + {LTU, 0, LTU, 0, 65535, 0, 0}, /* LTU */ yann@1: + {GEU, 1, LTU, 0, 65534, 1, 0}, /* LEU */ yann@1: + }; yann@1: + yann@1: + enum internal_test test; yann@1: + enum machine_mode mode; yann@1: + const struct cmp_info *p_info; yann@1: + int branch_p; yann@1: + yann@1: + yann@1: + yann@1: + yann@1: + test = map_test_to_internal_test (test_code); yann@1: + if (test == ITEST_MAX) yann@1: + abort (); yann@1: + yann@1: + p_info = &info[(int) test]; yann@1: + yann@1: + mode = GET_MODE (cmp0); yann@1: + if (mode == VOIDmode) yann@1: + mode = GET_MODE (cmp1); yann@1: + yann@1: + branch_p = (destination != 0); yann@1: + yann@1: + /* We can't, under any circumstances, have const_ints in cmp0 yann@1: + ??? Actually we could have const0 */ yann@1: + if (GET_CODE (cmp0) == CONST_INT) yann@1: + cmp0 = force_reg (mode, cmp0); yann@1: + yann@1: + /* if the comparison is against an int not in legal range yann@1: + move it into a register */ yann@1: + if (GET_CODE (cmp1) == CONST_INT) yann@1: + { yann@1: + HOST_WIDE_INT value = INTVAL (cmp1); yann@1: + yann@1: + if (value < p_info->const_low || value > p_info->const_high) yann@1: + cmp1 = force_reg (mode, cmp1); yann@1: + } yann@1: + yann@1: + /* Comparison to constants, may involve adding 1 to change a GT into GE. yann@1: + Comparison between two registers, may involve switching operands. */ yann@1: + if (GET_CODE (cmp1) == CONST_INT) yann@1: + { yann@1: + if (p_info->const_add != 0) yann@1: + { yann@1: + HOST_WIDE_INT new = INTVAL (cmp1) + p_info->const_add; yann@1: + yann@1: + /* If modification of cmp1 caused overflow, yann@1: + we would get the wrong answer if we follow the usual path; yann@1: + thus, x > 0xffffffffU would turn into x > 0U. */ yann@1: + if ((p_info->unsignedp yann@1: + ? (unsigned HOST_WIDE_INT) new > yann@1: + (unsigned HOST_WIDE_INT) INTVAL (cmp1) yann@1: + : new > INTVAL (cmp1)) != (p_info->const_add > 0)) yann@1: + { yann@1: + /* ??? This case can never happen with the current numbers, yann@1: + but I am paranoid and would rather an abort than yann@1: + a bug I will never find */ yann@1: + abort (); yann@1: + } yann@1: + else yann@1: + cmp1 = GEN_INT (new); yann@1: + } yann@1: + } yann@1: + yann@1: + else if (p_info->reverse_regs) yann@1: + { yann@1: + rtx temp = cmp0; yann@1: + cmp0 = cmp1; yann@1: + cmp1 = temp; yann@1: + } yann@1: + yann@1: + yann@1: + yann@1: + if (branch_p) yann@1: + { yann@1: + if (register_operand (cmp0, mode) && register_operand (cmp1, mode)) yann@1: + { yann@1: + rtx insn; yann@1: + rtx cond = gen_rtx (p_info->test_code_reg, mode, cmp0, cmp1); yann@1: + rtx label = gen_rtx_LABEL_REF (VOIDmode, destination); yann@1: + yann@1: + insn = gen_rtx_SET (VOIDmode, pc_rtx, yann@1: + gen_rtx_IF_THEN_ELSE (VOIDmode, yann@1: + cond, label, pc_rtx)); yann@1: + emit_jump_insn (insn); yann@1: + } yann@1: + else yann@1: + { yann@1: + rtx cond, label; yann@1: + yann@1: + result = gen_reg_rtx (mode); yann@1: + yann@1: + emit_move_insn (result, yann@1: + gen_rtx (p_info->test_code_const, mode, cmp0, yann@1: + cmp1)); yann@1: + yann@1: + cond = gen_rtx (NE, mode, result, const0_rtx); yann@1: + label = gen_rtx_LABEL_REF (VOIDmode, destination); yann@1: + yann@1: + emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, yann@1: + gen_rtx_IF_THEN_ELSE (VOIDmode, yann@1: + cond, yann@1: + label, pc_rtx))); yann@1: + } yann@1: + } yann@1: + else yann@1: + { yann@1: + if (register_operand (cmp0, mode) && register_operand (cmp1, mode)) yann@1: + { yann@1: + emit_move_insn (result, yann@1: + gen_rtx (p_info->test_code_reg, mode, cmp0, cmp1)); yann@1: + } yann@1: + else yann@1: + { yann@1: + emit_move_insn (result, yann@1: + gen_rtx (p_info->test_code_const, mode, cmp0, yann@1: + cmp1)); yann@1: + } yann@1: + } yann@1: + yann@1: +} yann@1: + yann@1: + yann@1: +/* ??? For now conditional moves are only supported yann@1: + when the mode of the operands being compared are yann@1: + the same as the ones being moved */ yann@1: + yann@1: +void yann@1: +gen_conditional_move (rtx *operands, enum machine_mode mode) yann@1: +{ yann@1: + rtx insn, cond; yann@1: + rtx cmp_reg = gen_reg_rtx (mode); yann@1: + enum rtx_code cmp_code = GET_CODE (operands[1]); yann@1: + enum rtx_code move_code = EQ; yann@1: + yann@1: + /* emit a comparison if it is not "simple". yann@1: + Simple comparisons are X eq 0 and X ne 0 */ yann@1: + if ((cmp_code == EQ || cmp_code == NE) && branch_cmp[1] == const0_rtx) yann@1: + { yann@1: + cmp_reg = branch_cmp[0]; yann@1: + move_code = cmp_code; yann@1: + } yann@1: + else if ((cmp_code == EQ || cmp_code == NE) && branch_cmp[0] == const0_rtx) yann@1: + { yann@1: + cmp_reg = branch_cmp[1]; yann@1: + move_code = cmp_code == EQ ? NE : EQ; yann@1: + } yann@1: + else yann@1: + gen_int_relational (cmp_code, cmp_reg, branch_cmp[0], branch_cmp[1], yann@1: + NULL_RTX); yann@1: + yann@1: + cond = gen_rtx (move_code, VOIDmode, cmp_reg, CONST0_RTX (mode)); yann@1: + insn = gen_rtx_SET (mode, operands[0], yann@1: + gen_rtx_IF_THEN_ELSE (mode, yann@1: + cond, operands[2], operands[3])); yann@1: + emit_insn (insn); yann@1: +} yann@1: + yann@1: +/******************* yann@1: + * Addressing Modes yann@1: + *******************/ yann@1: + yann@1: +int yann@1: +nios2_legitimate_address (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED, yann@1: + int strict) yann@1: +{ yann@1: + int ret_val = 0; yann@1: + yann@1: + switch (GET_CODE (operand)) yann@1: + { yann@1: + /* direct. */ yann@1: + case SYMBOL_REF: yann@1: + if (SYMBOL_REF_IN_NIOS2_SMALL_DATA_P (operand)) yann@1: + { yann@1: + ret_val = 1; yann@1: + break; yann@1: + } yann@1: + /* else, fall through */ yann@1: + case LABEL_REF: yann@1: + case CONST_INT: yann@1: + case CONST: yann@1: + case CONST_DOUBLE: yann@1: + /* ??? In here I need to add gp addressing */ yann@1: + ret_val = 0; yann@1: + yann@1: + break; yann@1: + yann@1: + /* Register indirect. */ yann@1: + case REG: yann@1: + ret_val = REG_OK_FOR_BASE_P2 (operand, strict); yann@1: + break; yann@1: + yann@1: + /* Register indirect with displacement */ yann@1: + case PLUS: yann@1: + { yann@1: + rtx op0 = XEXP (operand, 0); yann@1: + rtx op1 = XEXP (operand, 1); yann@1: + yann@1: + if (REG_P (op0) && REG_P (op1)) yann@1: + ret_val = 0; yann@1: + else if (REG_P (op0) && CONSTANT_P (op1)) yann@1: + ret_val = REG_OK_FOR_BASE_P2 (op0, strict) yann@1: + && SMALL_INT (INTVAL (op1)); yann@1: + else if (REG_P (op1) && CONSTANT_P (op0)) yann@1: + ret_val = REG_OK_FOR_BASE_P2 (op1, strict) yann@1: + && SMALL_INT (INTVAL (op0)); yann@1: + else yann@1: + ret_val = 0; yann@1: + } yann@1: + break; yann@1: + yann@1: + default: yann@1: + ret_val = 0; yann@1: + break; yann@1: + } yann@1: + yann@1: + return ret_val; yann@1: +} yann@1: + yann@1: +/* Return true if EXP should be placed in the small data section. */ yann@1: + yann@1: +static bool yann@1: +nios2_in_small_data_p (tree exp) yann@1: +{ yann@1: + /* We want to merge strings, so we never consider them small data. */ yann@1: + if (TREE_CODE (exp) == STRING_CST) yann@1: + return false; yann@1: + yann@1: + if (TREE_CODE (exp) == VAR_DECL && DECL_SECTION_NAME (exp)) yann@1: + { yann@1: + const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (exp)); yann@1: + /* ??? these string names need moving into yann@1: + an array in some header file */ yann@1: + if (nios2_section_threshold > 0 yann@1: + && (strcmp (section, ".sbss") == 0 yann@1: + || strncmp (section, ".sbss.", 6) == 0 yann@1: + || strcmp (section, ".sdata") == 0 yann@1: + || strncmp (section, ".sdata.", 7) == 0)) yann@1: + return true; yann@1: + } yann@1: + else if (TREE_CODE (exp) == VAR_DECL) yann@1: + { yann@1: + HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp)); yann@1: + yann@1: + /* If this is an incomplete type with size 0, then we can't put it yann@1: + in sdata because it might be too big when completed. */ yann@1: + if (size > 0 && size <= nios2_section_threshold) yann@1: + return true; yann@1: + } yann@1: + yann@1: + return false; yann@1: +} yann@1: + yann@1: +static void yann@1: +nios2_encode_section_info (tree decl, rtx rtl, int first) yann@1: +{ yann@1: + yann@1: + rtx symbol; yann@1: + int flags; yann@1: + yann@1: + default_encode_section_info (decl, rtl, first); yann@1: + yann@1: + /* Careful not to prod global register variables. */ yann@1: + if (GET_CODE (rtl) != MEM) yann@1: + return; yann@1: + symbol = XEXP (rtl, 0); yann@1: + if (GET_CODE (symbol) != SYMBOL_REF) yann@1: + return; yann@1: + yann@1: + flags = SYMBOL_REF_FLAGS (symbol); yann@1: + yann@1: + /* We don't want weak variables to be addressed with gp in case they end up with yann@1: + value 0 which is not within 2^15 of $gp */ yann@1: + if (DECL_P (decl) && DECL_WEAK (decl)) yann@1: + flags |= SYMBOL_FLAG_WEAK_DECL; yann@1: + yann@1: + SYMBOL_REF_FLAGS (symbol) = flags; yann@1: +} yann@1: + yann@1: + yann@1: +static unsigned int yann@1: +nios2_section_type_flags (tree decl, const char *name, int reloc) yann@1: +{ yann@1: + unsigned int flags; yann@1: + yann@1: + flags = default_section_type_flags (decl, name, reloc); yann@1: + yann@1: + /* ??? these string names need moving into an array in some header file */ yann@1: + if (strcmp (name, ".sbss") == 0 yann@1: + || strncmp (name, ".sbss.", 6) == 0 yann@1: + || strcmp (name, ".sdata") == 0 yann@1: + || strncmp (name, ".sdata.", 7) == 0) yann@1: + flags |= SECTION_SMALL; yann@1: + yann@1: + return flags; yann@1: +} yann@1: + yann@1: + yann@1: + yann@1: + yann@1: +/***************************************** yann@1: + * Defining the Output Assembler Language yann@1: + *****************************************/ yann@1: + yann@1: +/* -------------- * yann@1: + * Output of Data yann@1: + * -------------- */ yann@1: + yann@1: + yann@1: +/* -------------------------------- * yann@1: + * Output of Assembler Instructions yann@1: + * -------------------------------- */ yann@1: + yann@1: + yann@1: +/* print the operand OP to file stream yann@1: + FILE modified by LETTER. LETTER yann@1: + can be one of: yann@1: + i: print "i" if OP is an immediate, except 0 yann@1: + o: print "io" if OP is volatile yann@1: + yann@1: + z: for const0_rtx print $0 instead of 0 yann@1: + H: for %hiadj yann@1: + L: for %lo yann@1: + U: for upper half of 32 bit value yann@1: + */ yann@1: + yann@1: +void yann@1: +nios2_print_operand (FILE *file, rtx op, int letter) yann@1: +{ yann@1: + yann@1: + switch (letter) yann@1: + { yann@1: + case 'i': yann@1: + if (CONSTANT_P (op) && (op != const0_rtx)) yann@1: + fprintf (file, "i"); yann@1: + return; yann@1: + yann@1: + case 'o': yann@1: + if (GET_CODE (op) == MEM yann@1: + && ((MEM_VOLATILE_P (op) && !TARGET_CACHE_VOLATILE) yann@1: + || TARGET_BYPASS_CACHE)) yann@1: + fprintf (file, "io"); yann@1: + return; yann@1: + yann@1: + default: yann@1: + break; yann@1: + } yann@1: + yann@1: + if (comparison_operator (op, VOIDmode)) yann@1: + { yann@1: + if (letter == 0) yann@1: + { yann@1: + fprintf (file, "%s", GET_RTX_NAME (GET_CODE (op))); yann@1: + return; yann@1: + } yann@1: + } yann@1: + yann@1: + yann@1: + switch (GET_CODE (op)) yann@1: + { yann@1: + case REG: yann@1: + if (letter == 0 || letter == 'z') yann@1: + { yann@1: + fprintf (file, "%s", reg_names[REGNO (op)]); yann@1: + return; yann@1: + } yann@1: + yann@1: + case CONST_INT: yann@1: + if (INTVAL (op) == 0 && letter == 'z') yann@1: + { yann@1: + fprintf (file, "zero"); yann@1: + return; yann@1: + } yann@1: + else if (letter == 'U') yann@1: + { yann@1: + HOST_WIDE_INT val = INTVAL (op); yann@1: + rtx new_op; yann@1: + val = (val / 65536) & 0xFFFF; yann@1: + new_op = GEN_INT (val); yann@1: + output_addr_const (file, new_op); yann@1: + return; yann@1: + } yann@1: + yann@1: + /* else, fall through */ yann@1: + case CONST: yann@1: + case LABEL_REF: yann@1: + case SYMBOL_REF: yann@1: + case CONST_DOUBLE: yann@1: + if (letter == 0 || letter == 'z') yann@1: + { yann@1: + output_addr_const (file, op); yann@1: + return; yann@1: + } yann@1: + else if (letter == 'H') yann@1: + { yann@1: + fprintf (file, "%%hiadj("); yann@1: + output_addr_const (file, op); yann@1: + fprintf (file, ")"); yann@1: + return; yann@1: + } yann@1: + else if (letter == 'L') yann@1: + { yann@1: + fprintf (file, "%%lo("); yann@1: + output_addr_const (file, op); yann@1: + fprintf (file, ")"); yann@1: + return; yann@1: + } yann@1: + yann@1: + yann@1: + case SUBREG: yann@1: + case MEM: yann@1: + if (letter == 0) yann@1: + { yann@1: + output_address (op); yann@1: + return; yann@1: + } yann@1: + yann@1: + case CODE_LABEL: yann@1: + if (letter == 0) yann@1: + { yann@1: + output_addr_const (file, op); yann@1: + return; yann@1: + } yann@1: + yann@1: + default: yann@1: + break; yann@1: + } yann@1: + yann@1: + fprintf (stderr, "Missing way to print (%c) ", letter); yann@1: + debug_rtx (op); yann@1: + abort (); yann@1: +} yann@1: + yann@1: +static int gprel_constant (rtx); yann@1: + yann@1: +static int yann@1: +gprel_constant (rtx op) yann@1: +{ yann@1: + if (GET_CODE (op) == SYMBOL_REF yann@1: + && SYMBOL_REF_IN_NIOS2_SMALL_DATA_P (op)) yann@1: + { yann@1: + return 1; yann@1: + } yann@1: + else if (GET_CODE (op) == CONST yann@1: + && GET_CODE (XEXP (op, 0)) == PLUS) yann@1: + { yann@1: + return gprel_constant (XEXP (XEXP (op, 0), 0)); yann@1: + } yann@1: + else yann@1: + { yann@1: + return 0; yann@1: + } yann@1: +} yann@1: + yann@1: +void yann@1: +nios2_print_operand_address (FILE *file, rtx op) yann@1: +{ yann@1: + switch (GET_CODE (op)) yann@1: + { yann@1: + case CONST: yann@1: + case CONST_INT: yann@1: + case LABEL_REF: yann@1: + case CONST_DOUBLE: yann@1: + case SYMBOL_REF: yann@1: + if (gprel_constant (op)) yann@1: + { yann@1: + fprintf (file, "%%gprel("); yann@1: + output_addr_const (file, op); yann@1: + fprintf (file, ")(%s)", reg_names[GP_REGNO]); yann@1: + return; yann@1: + } yann@1: + yann@1: + break; yann@1: + yann@1: + case PLUS: yann@1: + { yann@1: + rtx op0 = XEXP (op, 0); yann@1: + rtx op1 = XEXP (op, 1); yann@1: + yann@1: + if (REG_P (op0) && CONSTANT_P (op1)) yann@1: + { yann@1: + output_addr_const (file, op1); yann@1: + fprintf (file, "(%s)", reg_names[REGNO (op0)]); yann@1: + return; yann@1: + } yann@1: + else if (REG_P (op1) && CONSTANT_P (op0)) yann@1: + { yann@1: + output_addr_const (file, op0); yann@1: + fprintf (file, "(%s)", reg_names[REGNO (op1)]); yann@1: + return; yann@1: + } yann@1: + } yann@1: + break; yann@1: + yann@1: + case REG: yann@1: + fprintf (file, "0(%s)", reg_names[REGNO (op)]); yann@1: + return; yann@1: + yann@1: + case MEM: yann@1: + { yann@1: + rtx base = XEXP (op, 0); yann@1: + PRINT_OPERAND_ADDRESS (file, base); yann@1: + return; yann@1: + } yann@1: + default: yann@1: + break; yann@1: + } yann@1: + yann@1: + fprintf (stderr, "Missing way to print address\n"); yann@1: + debug_rtx (op); yann@1: + abort (); yann@1: +} yann@1: + yann@1: + yann@1: + yann@1: + yann@1: + yann@1: +/**************************** yann@1: + * Predicates yann@1: + ****************************/ yann@1: + yann@1: +int yann@1: +arith_operand (rtx op, enum machine_mode mode) yann@1: +{ yann@1: + if (GET_CODE (op) == CONST_INT && SMALL_INT (INTVAL (op))) yann@1: + return 1; yann@1: + yann@1: + return register_operand (op, mode); yann@1: +} yann@1: + yann@1: +int yann@1: +uns_arith_operand (rtx op, enum machine_mode mode) yann@1: +{ yann@1: + if (GET_CODE (op) == CONST_INT && SMALL_INT_UNSIGNED (INTVAL (op))) yann@1: + return 1; yann@1: + yann@1: + return register_operand (op, mode); yann@1: +} yann@1: + yann@1: +int yann@1: +logical_operand (rtx op, enum machine_mode mode) yann@1: +{ yann@1: + if (GET_CODE (op) == CONST_INT yann@1: + && (SMALL_INT_UNSIGNED (INTVAL (op)) || UPPER16_INT (INTVAL (op)))) yann@1: + return 1; yann@1: + yann@1: + return register_operand (op, mode); yann@1: +} yann@1: + yann@1: +int yann@1: +shift_operand (rtx op, enum machine_mode mode) yann@1: +{ yann@1: + if (GET_CODE (op) == CONST_INT && SHIFT_INT (INTVAL (op))) yann@1: + return 1; yann@1: + yann@1: + return register_operand (op, mode); yann@1: +} yann@1: + yann@1: +int yann@1: +rdwrctl_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) yann@1: +{ yann@1: + return GET_CODE (op) == CONST_INT && RDWRCTL_INT (INTVAL (op)); yann@1: +} yann@1: + yann@1: +/* Return truth value of whether OP is a register or the constant 0. */ yann@1: + yann@1: +int yann@1: +reg_or_0_operand (rtx op, enum machine_mode mode) yann@1: +{ yann@1: + switch (GET_CODE (op)) yann@1: + { yann@1: + case CONST_INT: yann@1: + return INTVAL (op) == 0; yann@1: + yann@1: + case CONST_DOUBLE: yann@1: + return op == CONST0_RTX (mode); yann@1: + yann@1: + default: yann@1: + break; yann@1: + } yann@1: + yann@1: + return register_operand (op, mode); yann@1: +} yann@1: + yann@1: + yann@1: +int yann@1: +equality_op (rtx op, enum machine_mode mode) yann@1: +{ yann@1: + if (mode != GET_MODE (op)) yann@1: + return 0; yann@1: + yann@1: + return GET_CODE (op) == EQ || GET_CODE (op) == NE; yann@1: +} yann@1: + yann@1: +int yann@1: +custom_insn_opcode (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) yann@1: +{ yann@1: + return GET_CODE (op) == CONST_INT && CUSTOM_INSN_OPCODE (INTVAL (op)); yann@1: +} yann@1: + yann@1: + yann@1: + yann@1: + yann@1: + yann@1: + yann@1: + yann@1: +/***************************************************************************** yann@1: +** yann@1: +** instruction scheduler yann@1: +** yann@1: +*****************************************************************************/ yann@1: +static int yann@1: +nios2_use_dfa_pipeline_interface () yann@1: +{ yann@1: + return 1; yann@1: +} yann@1: + yann@1: + yann@1: +static int yann@1: +nios2_issue_rate () yann@1: +{ yann@1: +#ifdef MAX_DFA_ISSUE_RATE yann@1: + return MAX_DFA_ISSUE_RATE; yann@1: +#else yann@1: + return 1; yann@1: +#endif yann@1: +} yann@1: + yann@1: + yann@1: +const char * yann@1: +asm_output_opcode (FILE *file ATTRIBUTE_UNUSED, yann@1: + const char *ptr ATTRIBUTE_UNUSED) yann@1: +{ yann@1: + const char *p; yann@1: + yann@1: + p = ptr; yann@1: + return ptr; yann@1: +} yann@1: + yann@1: + yann@1: + yann@1: +/***************************************************************************** yann@1: +** yann@1: +** function arguments yann@1: +** yann@1: +*****************************************************************************/ yann@1: + yann@1: +void yann@1: +init_cumulative_args (CUMULATIVE_ARGS *cum, yann@1: + tree fntype ATTRIBUTE_UNUSED, yann@1: + rtx libname ATTRIBUTE_UNUSED, yann@1: + tree fndecl ATTRIBUTE_UNUSED, yann@1: + int n_named_args ATTRIBUTE_UNUSED) yann@1: +{ yann@1: + cum->regs_used = 0; yann@1: +} yann@1: + yann@1: + yann@1: +/* Update the data in CUM to advance over an argument yann@1: + of mode MODE and data type TYPE. yann@1: + (TYPE is null for libcalls where that information may not be available.) */ yann@1: + yann@1: +void yann@1: +function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, yann@1: + tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED) yann@1: +{ yann@1: + HOST_WIDE_INT param_size; yann@1: + yann@1: + if (mode == BLKmode) yann@1: + { yann@1: + param_size = int_size_in_bytes (type); yann@1: + if (param_size < 0) yann@1: + internal_error yann@1: + ("Do not know how to handle large structs or variable length types"); yann@1: + } yann@1: + else yann@1: + { yann@1: + param_size = GET_MODE_SIZE (mode); yann@1: + } yann@1: + yann@1: + /* convert to words (round up) */ yann@1: + param_size = (3 + param_size) / 4; yann@1: + yann@1: + if (cum->regs_used + param_size > NUM_ARG_REGS) yann@1: + { yann@1: + cum->regs_used = NUM_ARG_REGS; yann@1: + } yann@1: + else yann@1: + { yann@1: + cum->regs_used += param_size; yann@1: + } yann@1: + yann@1: + return; yann@1: +} yann@1: + yann@1: +/* Define where to put the arguments to a function. Value is zero to yann@1: + push the argument on the stack, or a hard register in which to yann@1: + store the argument. yann@1: + yann@1: + MODE is the argument's machine mode. yann@1: + TYPE is the data type of the argument (as a tree). yann@1: + This is null for libcalls where that information may yann@1: + not be available. yann@1: + CUM is a variable of type CUMULATIVE_ARGS which gives info about yann@1: + the preceding args and about the function being called. yann@1: + NAMED is nonzero if this argument is a named parameter yann@1: + (otherwise it is an extra parameter matching an ellipsis). */ yann@1: +rtx yann@1: +function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode, yann@1: + tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED) yann@1: +{ yann@1: + rtx return_rtx = NULL_RTX; yann@1: + yann@1: + if (cum->regs_used < NUM_ARG_REGS) yann@1: + { yann@1: + return_rtx = gen_rtx_REG (mode, FIRST_ARG_REGNO + cum->regs_used); yann@1: + } yann@1: + yann@1: + return return_rtx; yann@1: +} yann@1: + yann@1: +int yann@1: +function_arg_partial_nregs (const CUMULATIVE_ARGS *cum, yann@1: + enum machine_mode mode, tree type, yann@1: + int named ATTRIBUTE_UNUSED) yann@1: +{ yann@1: + HOST_WIDE_INT param_size; yann@1: + yann@1: + if (mode == BLKmode) yann@1: + { yann@1: + param_size = int_size_in_bytes (type); yann@1: + if (param_size < 0) yann@1: + internal_error yann@1: + ("Do not know how to handle large structs or variable length types"); yann@1: + } yann@1: + else yann@1: + { yann@1: + param_size = GET_MODE_SIZE (mode); yann@1: + } yann@1: + yann@1: + /* convert to words (round up) */ yann@1: + param_size = (3 + param_size) / 4; yann@1: + yann@1: + if (cum->regs_used < NUM_ARG_REGS yann@1: + && cum->regs_used + param_size > NUM_ARG_REGS) yann@1: + { yann@1: + return NUM_ARG_REGS - cum->regs_used; yann@1: + } yann@1: + else yann@1: + { yann@1: + return 0; yann@1: + } yann@1: +} yann@1: + yann@1: + yann@1: +int yann@1: +nios2_return_in_memory (tree type) yann@1: +{ yann@1: + int res = ((int_size_in_bytes (type) > (2 * UNITS_PER_WORD)) yann@1: + || (int_size_in_bytes (type) == -1)); yann@1: + yann@1: + return res; yann@1: +} yann@1: + yann@1: +/* ??? It may be possible to eliminate the copyback and implement yann@1: + my own va_arg type, but that is more work for now. */ yann@1: +int yann@1: +nios2_setup_incoming_varargs (const CUMULATIVE_ARGS *cum, yann@1: + enum machine_mode mode, tree type, yann@1: + int no_rtl) yann@1: +{ yann@1: + CUMULATIVE_ARGS local_cum; yann@1: + int regs_to_push; yann@1: + yann@1: + local_cum = *cum; yann@1: + FUNCTION_ARG_ADVANCE (local_cum, mode, type, 1); yann@1: + yann@1: + regs_to_push = NUM_ARG_REGS - local_cum.regs_used; yann@1: + yann@1: + if (!no_rtl) yann@1: + { yann@1: + if (regs_to_push > 0) yann@1: + { yann@1: + rtx ptr, mem; yann@1: + yann@1: + ptr = virtual_incoming_args_rtx; yann@1: + mem = gen_rtx_MEM (BLKmode, ptr); yann@1: + yann@1: + /* va_arg is an array access in this case, which causes yann@1: + it to get MEM_IN_STRUCT_P set. We must set it here yann@1: + so that the insn scheduler won't assume that these yann@1: + stores can't possibly overlap with the va_arg loads. */ yann@1: + MEM_SET_IN_STRUCT_P (mem, 1); yann@1: + yann@1: + emit_insn (gen_blockage ()); yann@1: + move_block_from_reg (local_cum.regs_used + FIRST_ARG_REGNO, mem, yann@1: + regs_to_push); yann@1: + emit_insn (gen_blockage ()); yann@1: + } yann@1: + } yann@1: + yann@1: + return regs_to_push * UNITS_PER_WORD; yann@1: + yann@1: +} yann@1: + yann@1: + yann@1: + yann@1: +/***************************************************************************** yann@1: +** yann@1: +** builtins yann@1: +** yann@1: +** This method for handling builtins is from CSP where _many_ more types of yann@1: +** expanders have already been written. Check there first before writing yann@1: +** new ones. yann@1: +** yann@1: +*****************************************************************************/ yann@1: + yann@1: +enum nios2_builtins yann@1: +{ yann@1: + NIOS2_BUILTIN_LDBIO, yann@1: + NIOS2_BUILTIN_LDBUIO, yann@1: + NIOS2_BUILTIN_LDHIO, yann@1: + NIOS2_BUILTIN_LDHUIO, yann@1: + NIOS2_BUILTIN_LDWIO, yann@1: + NIOS2_BUILTIN_STBIO, yann@1: + NIOS2_BUILTIN_STHIO, yann@1: + NIOS2_BUILTIN_STWIO, yann@1: + NIOS2_BUILTIN_SYNC, yann@1: + NIOS2_BUILTIN_RDCTL, yann@1: + NIOS2_BUILTIN_WRCTL, yann@1: + yann@1: + NIOS2_BUILTIN_CUSTOM_N, yann@1: + NIOS2_BUILTIN_CUSTOM_NI, yann@1: + NIOS2_BUILTIN_CUSTOM_NF, yann@1: + NIOS2_BUILTIN_CUSTOM_NP, yann@1: + NIOS2_BUILTIN_CUSTOM_NII, yann@1: + NIOS2_BUILTIN_CUSTOM_NIF, yann@1: + NIOS2_BUILTIN_CUSTOM_NIP, yann@1: + NIOS2_BUILTIN_CUSTOM_NFI, yann@1: + NIOS2_BUILTIN_CUSTOM_NFF, yann@1: + NIOS2_BUILTIN_CUSTOM_NFP, yann@1: + NIOS2_BUILTIN_CUSTOM_NPI, yann@1: + NIOS2_BUILTIN_CUSTOM_NPF, yann@1: + NIOS2_BUILTIN_CUSTOM_NPP, yann@1: + NIOS2_BUILTIN_CUSTOM_IN, yann@1: + NIOS2_BUILTIN_CUSTOM_INI, yann@1: + NIOS2_BUILTIN_CUSTOM_INF, yann@1: + NIOS2_BUILTIN_CUSTOM_INP, yann@1: + NIOS2_BUILTIN_CUSTOM_INII, yann@1: + NIOS2_BUILTIN_CUSTOM_INIF, yann@1: + NIOS2_BUILTIN_CUSTOM_INIP, yann@1: + NIOS2_BUILTIN_CUSTOM_INFI, yann@1: + NIOS2_BUILTIN_CUSTOM_INFF, yann@1: + NIOS2_BUILTIN_CUSTOM_INFP, yann@1: + NIOS2_BUILTIN_CUSTOM_INPI, yann@1: + NIOS2_BUILTIN_CUSTOM_INPF, yann@1: + NIOS2_BUILTIN_CUSTOM_INPP, yann@1: + NIOS2_BUILTIN_CUSTOM_FN, yann@1: + NIOS2_BUILTIN_CUSTOM_FNI, yann@1: + NIOS2_BUILTIN_CUSTOM_FNF, yann@1: + NIOS2_BUILTIN_CUSTOM_FNP, yann@1: + NIOS2_BUILTIN_CUSTOM_FNII, yann@1: + NIOS2_BUILTIN_CUSTOM_FNIF, yann@1: + NIOS2_BUILTIN_CUSTOM_FNIP, yann@1: + NIOS2_BUILTIN_CUSTOM_FNFI, yann@1: + NIOS2_BUILTIN_CUSTOM_FNFF, yann@1: + NIOS2_BUILTIN_CUSTOM_FNFP, yann@1: + NIOS2_BUILTIN_CUSTOM_FNPI, yann@1: + NIOS2_BUILTIN_CUSTOM_FNPF, yann@1: + NIOS2_BUILTIN_CUSTOM_FNPP, yann@1: + NIOS2_BUILTIN_CUSTOM_PN, yann@1: + NIOS2_BUILTIN_CUSTOM_PNI, yann@1: + NIOS2_BUILTIN_CUSTOM_PNF, yann@1: + NIOS2_BUILTIN_CUSTOM_PNP, yann@1: + NIOS2_BUILTIN_CUSTOM_PNII, yann@1: + NIOS2_BUILTIN_CUSTOM_PNIF, yann@1: + NIOS2_BUILTIN_CUSTOM_PNIP, yann@1: + NIOS2_BUILTIN_CUSTOM_PNFI, yann@1: + NIOS2_BUILTIN_CUSTOM_PNFF, yann@1: + NIOS2_BUILTIN_CUSTOM_PNFP, yann@1: + NIOS2_BUILTIN_CUSTOM_PNPI, yann@1: + NIOS2_BUILTIN_CUSTOM_PNPF, yann@1: + NIOS2_BUILTIN_CUSTOM_PNPP, yann@1: + yann@1: + yann@1: + LIM_NIOS2_BUILTINS yann@1: +}; yann@1: + yann@1: +struct builtin_description yann@1: +{ yann@1: + const enum insn_code icode; yann@1: + const char *const name; yann@1: + const enum nios2_builtins code; yann@1: + const tree *type; yann@1: + rtx (* expander) PARAMS ((const struct builtin_description *, yann@1: + tree, rtx, rtx, enum machine_mode, int)); yann@1: +}; yann@1: + yann@1: +static rtx nios2_expand_STXIO (const struct builtin_description *, yann@1: + tree, rtx, rtx, enum machine_mode, int); yann@1: +static rtx nios2_expand_LDXIO (const struct builtin_description *, yann@1: + tree, rtx, rtx, enum machine_mode, int); yann@1: +static rtx nios2_expand_sync (const struct builtin_description *, yann@1: + tree, rtx, rtx, enum machine_mode, int); yann@1: +static rtx nios2_expand_rdctl (const struct builtin_description *, yann@1: + tree, rtx, rtx, enum machine_mode, int); yann@1: +static rtx nios2_expand_wrctl (const struct builtin_description *, yann@1: + tree, rtx, rtx, enum machine_mode, int); yann@1: + yann@1: +static rtx nios2_expand_custom_n (const struct builtin_description *, yann@1: + tree, rtx, rtx, enum machine_mode, int); yann@1: +static rtx nios2_expand_custom_Xn (const struct builtin_description *, yann@1: + tree, rtx, rtx, enum machine_mode, int); yann@1: +static rtx nios2_expand_custom_nX (const struct builtin_description *, yann@1: + tree, rtx, rtx, enum machine_mode, int); yann@1: +static rtx nios2_expand_custom_XnX (const struct builtin_description *, yann@1: + tree, rtx, rtx, enum machine_mode, int); yann@1: +static rtx nios2_expand_custom_nXX (const struct builtin_description *, yann@1: + tree, rtx, rtx, enum machine_mode, int); yann@1: +static rtx nios2_expand_custom_XnXX (const struct builtin_description *, yann@1: + tree, rtx, rtx, enum machine_mode, int); yann@1: + yann@1: +static tree endlink; yann@1: + yann@1: +/* int fn (volatile const void *) yann@1: + */ yann@1: +static tree int_ftype_volatile_const_void_p; yann@1: + yann@1: +/* int fn (int) yann@1: + */ yann@1: +static tree int_ftype_int; yann@1: + yann@1: +/* void fn (int, int) yann@1: + */ yann@1: +static tree void_ftype_int_int; yann@1: + yann@1: +/* void fn (volatile void *, int) yann@1: + */ yann@1: +static tree void_ftype_volatile_void_p_int; yann@1: + yann@1: +/* void fn (void) yann@1: + */ yann@1: +static tree void_ftype_void; yann@1: + yann@1: +static tree custom_n; yann@1: +static tree custom_ni; yann@1: +static tree custom_nf; yann@1: +static tree custom_np; yann@1: +static tree custom_nii; yann@1: +static tree custom_nif; yann@1: +static tree custom_nip; yann@1: +static tree custom_nfi; yann@1: +static tree custom_nff; yann@1: +static tree custom_nfp; yann@1: +static tree custom_npi; yann@1: +static tree custom_npf; yann@1: +static tree custom_npp; yann@1: +static tree custom_in; yann@1: +static tree custom_ini; yann@1: +static tree custom_inf; yann@1: +static tree custom_inp; yann@1: +static tree custom_inii; yann@1: +static tree custom_inif; yann@1: +static tree custom_inip; yann@1: +static tree custom_infi; yann@1: +static tree custom_inff; yann@1: +static tree custom_infp; yann@1: +static tree custom_inpi; yann@1: +static tree custom_inpf; yann@1: +static tree custom_inpp; yann@1: +static tree custom_fn; yann@1: +static tree custom_fni; yann@1: +static tree custom_fnf; yann@1: +static tree custom_fnp; yann@1: +static tree custom_fnii; yann@1: +static tree custom_fnif; yann@1: +static tree custom_fnip; yann@1: +static tree custom_fnfi; yann@1: +static tree custom_fnff; yann@1: +static tree custom_fnfp; yann@1: +static tree custom_fnpi; yann@1: +static tree custom_fnpf; yann@1: +static tree custom_fnpp; yann@1: +static tree custom_pn; yann@1: +static tree custom_pni; yann@1: +static tree custom_pnf; yann@1: +static tree custom_pnp; yann@1: +static tree custom_pnii; yann@1: +static tree custom_pnif; yann@1: +static tree custom_pnip; yann@1: +static tree custom_pnfi; yann@1: +static tree custom_pnff; yann@1: +static tree custom_pnfp; yann@1: +static tree custom_pnpi; yann@1: +static tree custom_pnpf; yann@1: +static tree custom_pnpp; yann@1: + yann@1: + yann@1: +static const struct builtin_description bdesc[] = { yann@1: + {CODE_FOR_ldbio, "__builtin_ldbio", NIOS2_BUILTIN_LDBIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, yann@1: + {CODE_FOR_ldbuio, "__builtin_ldbuio", NIOS2_BUILTIN_LDBUIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, yann@1: + {CODE_FOR_ldhio, "__builtin_ldhio", NIOS2_BUILTIN_LDHIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, yann@1: + {CODE_FOR_ldhuio, "__builtin_ldhuio", NIOS2_BUILTIN_LDHUIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, yann@1: + {CODE_FOR_ldwio, "__builtin_ldwio", NIOS2_BUILTIN_LDWIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, yann@1: + yann@1: + {CODE_FOR_stbio, "__builtin_stbio", NIOS2_BUILTIN_STBIO, &void_ftype_volatile_void_p_int, nios2_expand_STXIO}, yann@1: + {CODE_FOR_sthio, "__builtin_sthio", NIOS2_BUILTIN_STHIO, &void_ftype_volatile_void_p_int, nios2_expand_STXIO}, yann@1: + {CODE_FOR_stwio, "__builtin_stwio", NIOS2_BUILTIN_STWIO, &void_ftype_volatile_void_p_int, nios2_expand_STXIO}, yann@1: + yann@1: + {CODE_FOR_sync, "__builtin_sync", NIOS2_BUILTIN_SYNC, &void_ftype_void, nios2_expand_sync}, yann@1: + {CODE_FOR_rdctl, "__builtin_rdctl", NIOS2_BUILTIN_RDCTL, &int_ftype_int, nios2_expand_rdctl}, yann@1: + {CODE_FOR_wrctl, "__builtin_wrctl", NIOS2_BUILTIN_WRCTL, &void_ftype_int_int, nios2_expand_wrctl}, yann@1: + yann@1: + {CODE_FOR_custom_n, "__builtin_custom_n", NIOS2_BUILTIN_CUSTOM_N, &custom_n, nios2_expand_custom_n}, yann@1: + {CODE_FOR_custom_ni, "__builtin_custom_ni", NIOS2_BUILTIN_CUSTOM_NI, &custom_ni, nios2_expand_custom_nX}, yann@1: + {CODE_FOR_custom_nf, "__builtin_custom_nf", NIOS2_BUILTIN_CUSTOM_NF, &custom_nf, nios2_expand_custom_nX}, yann@1: + {CODE_FOR_custom_np, "__builtin_custom_np", NIOS2_BUILTIN_CUSTOM_NP, &custom_np, nios2_expand_custom_nX}, yann@1: + {CODE_FOR_custom_nii, "__builtin_custom_nii", NIOS2_BUILTIN_CUSTOM_NII, &custom_nii, nios2_expand_custom_nXX}, yann@1: + {CODE_FOR_custom_nif, "__builtin_custom_nif", NIOS2_BUILTIN_CUSTOM_NIF, &custom_nif, nios2_expand_custom_nXX}, yann@1: + {CODE_FOR_custom_nip, "__builtin_custom_nip", NIOS2_BUILTIN_CUSTOM_NIP, &custom_nip, nios2_expand_custom_nXX}, yann@1: + {CODE_FOR_custom_nfi, "__builtin_custom_nfi", NIOS2_BUILTIN_CUSTOM_NFI, &custom_nfi, nios2_expand_custom_nXX}, yann@1: + {CODE_FOR_custom_nff, "__builtin_custom_nff", NIOS2_BUILTIN_CUSTOM_NFF, &custom_nff, nios2_expand_custom_nXX}, yann@1: + {CODE_FOR_custom_nfp, "__builtin_custom_nfp", NIOS2_BUILTIN_CUSTOM_NFP, &custom_nfp, nios2_expand_custom_nXX}, yann@1: + {CODE_FOR_custom_npi, "__builtin_custom_npi", NIOS2_BUILTIN_CUSTOM_NPI, &custom_npi, nios2_expand_custom_nXX}, yann@1: + {CODE_FOR_custom_npf, "__builtin_custom_npf", NIOS2_BUILTIN_CUSTOM_NPF, &custom_npf, nios2_expand_custom_nXX}, yann@1: + {CODE_FOR_custom_npp, "__builtin_custom_npp", NIOS2_BUILTIN_CUSTOM_NPP, &custom_npp, nios2_expand_custom_nXX}, yann@1: + {CODE_FOR_custom_in, "__builtin_custom_in", NIOS2_BUILTIN_CUSTOM_IN, &custom_in, nios2_expand_custom_Xn}, yann@1: + {CODE_FOR_custom_ini, "__builtin_custom_ini", NIOS2_BUILTIN_CUSTOM_INI, &custom_ini, nios2_expand_custom_XnX}, yann@1: + {CODE_FOR_custom_inf, "__builtin_custom_inf", NIOS2_BUILTIN_CUSTOM_INF, &custom_inf, nios2_expand_custom_XnX}, yann@1: + {CODE_FOR_custom_inp, "__builtin_custom_inp", NIOS2_BUILTIN_CUSTOM_INP, &custom_inp, nios2_expand_custom_XnX}, yann@1: + {CODE_FOR_custom_inii, "__builtin_custom_inii", NIOS2_BUILTIN_CUSTOM_INII, &custom_inii, nios2_expand_custom_XnXX}, yann@1: + {CODE_FOR_custom_inif, "__builtin_custom_inif", NIOS2_BUILTIN_CUSTOM_INIF, &custom_inif, nios2_expand_custom_XnXX}, yann@1: + {CODE_FOR_custom_inip, "__builtin_custom_inip", NIOS2_BUILTIN_CUSTOM_INIP, &custom_inip, nios2_expand_custom_XnXX}, yann@1: + {CODE_FOR_custom_infi, "__builtin_custom_infi", NIOS2_BUILTIN_CUSTOM_INFI, &custom_infi, nios2_expand_custom_XnXX}, yann@1: + {CODE_FOR_custom_inff, "__builtin_custom_inff", NIOS2_BUILTIN_CUSTOM_INFF, &custom_inff, nios2_expand_custom_XnXX}, yann@1: + {CODE_FOR_custom_infp, "__builtin_custom_infp", NIOS2_BUILTIN_CUSTOM_INFP, &custom_infp, nios2_expand_custom_XnXX}, yann@1: + {CODE_FOR_custom_inpi, "__builtin_custom_inpi", NIOS2_BUILTIN_CUSTOM_INPI, &custom_inpi, nios2_expand_custom_XnXX}, yann@1: + {CODE_FOR_custom_inpf, "__builtin_custom_inpf", NIOS2_BUILTIN_CUSTOM_INPF, &custom_inpf, nios2_expand_custom_XnXX}, yann@1: + {CODE_FOR_custom_inpp, "__builtin_custom_inpp", NIOS2_BUILTIN_CUSTOM_INPP, &custom_inpp, nios2_expand_custom_XnXX}, yann@1: + {CODE_FOR_custom_fn, "__builtin_custom_fn", NIOS2_BUILTIN_CUSTOM_FN, &custom_fn, nios2_expand_custom_Xn}, yann@1: + {CODE_FOR_custom_fni, "__builtin_custom_fni", NIOS2_BUILTIN_CUSTOM_FNI, &custom_fni, nios2_expand_custom_XnX}, yann@1: + {CODE_FOR_custom_fnf, "__builtin_custom_fnf", NIOS2_BUILTIN_CUSTOM_FNF, &custom_fnf, nios2_expand_custom_XnX}, yann@1: + {CODE_FOR_custom_fnp, "__builtin_custom_fnp", NIOS2_BUILTIN_CUSTOM_FNP, &custom_fnp, nios2_expand_custom_XnX}, yann@1: + {CODE_FOR_custom_fnii, "__builtin_custom_fnii", NIOS2_BUILTIN_CUSTOM_FNII, &custom_fnii, nios2_expand_custom_XnXX}, yann@1: + {CODE_FOR_custom_fnif, "__builtin_custom_fnif", NIOS2_BUILTIN_CUSTOM_FNIF, &custom_fnif, nios2_expand_custom_XnXX}, yann@1: + {CODE_FOR_custom_fnip, "__builtin_custom_fnip", NIOS2_BUILTIN_CUSTOM_FNIP, &custom_fnip, nios2_expand_custom_XnXX}, yann@1: + {CODE_FOR_custom_fnfi, "__builtin_custom_fnfi", NIOS2_BUILTIN_CUSTOM_FNFI, &custom_fnfi, nios2_expand_custom_XnXX}, yann@1: + {CODE_FOR_custom_fnff, "__builtin_custom_fnff", NIOS2_BUILTIN_CUSTOM_FNFF, &custom_fnff, nios2_expand_custom_XnXX}, yann@1: + {CODE_FOR_custom_fnfp, "__builtin_custom_fnfp", NIOS2_BUILTIN_CUSTOM_FNFP, &custom_fnfp, nios2_expand_custom_XnXX}, yann@1: + {CODE_FOR_custom_fnpi, "__builtin_custom_fnpi", NIOS2_BUILTIN_CUSTOM_FNPI, &custom_fnpi, nios2_expand_custom_XnXX}, yann@1: + {CODE_FOR_custom_fnpf, "__builtin_custom_fnpf", NIOS2_BUILTIN_CUSTOM_FNPF, &custom_fnpf, nios2_expand_custom_XnXX}, yann@1: + {CODE_FOR_custom_fnpp, "__builtin_custom_fnpp", NIOS2_BUILTIN_CUSTOM_FNPP, &custom_fnpp, nios2_expand_custom_XnXX}, yann@1: + {CODE_FOR_custom_pn, "__builtin_custom_pn", NIOS2_BUILTIN_CUSTOM_PN, &custom_pn, nios2_expand_custom_Xn}, yann@1: + {CODE_FOR_custom_pni, "__builtin_custom_pni", NIOS2_BUILTIN_CUSTOM_PNI, &custom_pni, nios2_expand_custom_XnX}, yann@1: + {CODE_FOR_custom_pnf, "__builtin_custom_pnf", NIOS2_BUILTIN_CUSTOM_PNF, &custom_pnf, nios2_expand_custom_XnX}, yann@1: + {CODE_FOR_custom_pnp, "__builtin_custom_pnp", NIOS2_BUILTIN_CUSTOM_PNP, &custom_pnp, nios2_expand_custom_XnX}, yann@1: + {CODE_FOR_custom_pnii, "__builtin_custom_pnii", NIOS2_BUILTIN_CUSTOM_PNII, &custom_pnii, nios2_expand_custom_XnXX}, yann@1: + {CODE_FOR_custom_pnif, "__builtin_custom_pnif", NIOS2_BUILTIN_CUSTOM_PNIF, &custom_pnif, nios2_expand_custom_XnXX}, yann@1: + {CODE_FOR_custom_pnip, "__builtin_custom_pnip", NIOS2_BUILTIN_CUSTOM_PNIP, &custom_pnip, nios2_expand_custom_XnXX}, yann@1: + {CODE_FOR_custom_pnfi, "__builtin_custom_pnfi", NIOS2_BUILTIN_CUSTOM_PNFI, &custom_pnfi, nios2_expand_custom_XnXX}, yann@1: + {CODE_FOR_custom_pnff, "__builtin_custom_pnff", NIOS2_BUILTIN_CUSTOM_PNFF, &custom_pnff, nios2_expand_custom_XnXX}, yann@1: + {CODE_FOR_custom_pnfp, "__builtin_custom_pnfp", NIOS2_BUILTIN_CUSTOM_PNFP, &custom_pnfp, nios2_expand_custom_XnXX}, yann@1: + {CODE_FOR_custom_pnpi, "__builtin_custom_pnpi", NIOS2_BUILTIN_CUSTOM_PNPI, &custom_pnpi, nios2_expand_custom_XnXX}, yann@1: + {CODE_FOR_custom_pnpf, "__builtin_custom_pnpf", NIOS2_BUILTIN_CUSTOM_PNPF, &custom_pnpf, nios2_expand_custom_XnXX}, yann@1: + {CODE_FOR_custom_pnpp, "__builtin_custom_pnpp", NIOS2_BUILTIN_CUSTOM_PNPP, &custom_pnpp, nios2_expand_custom_XnXX}, yann@1: + yann@1: + yann@1: + {0, 0, 0, 0, 0}, yann@1: +}; yann@1: + yann@1: +/* This does not have a closing bracket on purpose (see use) */ yann@1: +#define def_param(TYPE) \ yann@1: + tree_cons (NULL_TREE, TYPE, yann@1: + yann@1: +static void yann@1: +nios2_init_builtins () yann@1: +{ yann@1: + const struct builtin_description *d; yann@1: + yann@1: + yann@1: + endlink = void_list_node; yann@1: + yann@1: + /* Special indenting here because one of the brackets is in def_param */ yann@1: + /* *INDENT-OFF* */ yann@1: + yann@1: + /* int fn (volatile const void *) yann@1: + */ yann@1: + int_ftype_volatile_const_void_p yann@1: + = build_function_type (integer_type_node, yann@1: + def_param (build_qualified_type (ptr_type_node, yann@1: + TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE)) yann@1: + endlink)); yann@1: + yann@1: + yann@1: + /* void fn (volatile void *, int) yann@1: + */ yann@1: + void_ftype_volatile_void_p_int yann@1: + = build_function_type (void_type_node, yann@1: + def_param (build_qualified_type (ptr_type_node, yann@1: + TYPE_QUAL_VOLATILE)) yann@1: + def_param (integer_type_node) yann@1: + endlink))); yann@1: + yann@1: + /* void fn (void) yann@1: + */ yann@1: + void_ftype_void yann@1: + = build_function_type (void_type_node, yann@1: + endlink); yann@1: + yann@1: + /* int fn (int) yann@1: + */ yann@1: + int_ftype_int yann@1: + = build_function_type (integer_type_node, yann@1: + def_param (integer_type_node) yann@1: + endlink)); yann@1: + yann@1: + /* void fn (int, int) yann@1: + */ yann@1: + void_ftype_int_int yann@1: + = build_function_type (void_type_node, yann@1: + def_param (integer_type_node) yann@1: + def_param (integer_type_node) yann@1: + endlink))); yann@1: + yann@1: + yann@1: +#define CUSTOM_NUM def_param (integer_type_node) yann@1: + yann@1: + custom_n yann@1: + = build_function_type (void_type_node, yann@1: + CUSTOM_NUM yann@1: + endlink)); yann@1: + custom_ni yann@1: + = build_function_type (void_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (integer_type_node) yann@1: + endlink))); yann@1: + custom_nf yann@1: + = build_function_type (void_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (float_type_node) yann@1: + endlink))); yann@1: + custom_np yann@1: + = build_function_type (void_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (ptr_type_node) yann@1: + endlink))); yann@1: + custom_nii yann@1: + = build_function_type (void_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (integer_type_node) yann@1: + def_param (integer_type_node) yann@1: + endlink)))); yann@1: + custom_nif yann@1: + = build_function_type (void_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (integer_type_node) yann@1: + def_param (float_type_node) yann@1: + endlink)))); yann@1: + custom_nip yann@1: + = build_function_type (void_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (integer_type_node) yann@1: + def_param (ptr_type_node) yann@1: + endlink)))); yann@1: + custom_nfi yann@1: + = build_function_type (void_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (float_type_node) yann@1: + def_param (integer_type_node) yann@1: + endlink)))); yann@1: + custom_nff yann@1: + = build_function_type (void_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (float_type_node) yann@1: + def_param (float_type_node) yann@1: + endlink)))); yann@1: + custom_nfp yann@1: + = build_function_type (void_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (float_type_node) yann@1: + def_param (ptr_type_node) yann@1: + endlink)))); yann@1: + custom_npi yann@1: + = build_function_type (void_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (ptr_type_node) yann@1: + def_param (integer_type_node) yann@1: + endlink)))); yann@1: + custom_npf yann@1: + = build_function_type (void_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (ptr_type_node) yann@1: + def_param (float_type_node) yann@1: + endlink)))); yann@1: + custom_npp yann@1: + = build_function_type (void_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (ptr_type_node) yann@1: + def_param (ptr_type_node) yann@1: + endlink)))); yann@1: + yann@1: + custom_in yann@1: + = build_function_type (integer_type_node, yann@1: + CUSTOM_NUM yann@1: + endlink)); yann@1: + custom_ini yann@1: + = build_function_type (integer_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (integer_type_node) yann@1: + endlink))); yann@1: + custom_inf yann@1: + = build_function_type (integer_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (float_type_node) yann@1: + endlink))); yann@1: + custom_inp yann@1: + = build_function_type (integer_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (ptr_type_node) yann@1: + endlink))); yann@1: + custom_inii yann@1: + = build_function_type (integer_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (integer_type_node) yann@1: + def_param (integer_type_node) yann@1: + endlink)))); yann@1: + custom_inif yann@1: + = build_function_type (integer_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (integer_type_node) yann@1: + def_param (float_type_node) yann@1: + endlink)))); yann@1: + custom_inip yann@1: + = build_function_type (integer_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (integer_type_node) yann@1: + def_param (ptr_type_node) yann@1: + endlink)))); yann@1: + custom_infi yann@1: + = build_function_type (integer_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (float_type_node) yann@1: + def_param (integer_type_node) yann@1: + endlink)))); yann@1: + custom_inff yann@1: + = build_function_type (integer_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (float_type_node) yann@1: + def_param (float_type_node) yann@1: + endlink)))); yann@1: + custom_infp yann@1: + = build_function_type (integer_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (float_type_node) yann@1: + def_param (ptr_type_node) yann@1: + endlink)))); yann@1: + custom_inpi yann@1: + = build_function_type (integer_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (ptr_type_node) yann@1: + def_param (integer_type_node) yann@1: + endlink)))); yann@1: + custom_inpf yann@1: + = build_function_type (integer_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (ptr_type_node) yann@1: + def_param (float_type_node) yann@1: + endlink)))); yann@1: + custom_inpp yann@1: + = build_function_type (integer_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (ptr_type_node) yann@1: + def_param (ptr_type_node) yann@1: + endlink)))); yann@1: + yann@1: + custom_fn yann@1: + = build_function_type (float_type_node, yann@1: + CUSTOM_NUM yann@1: + endlink)); yann@1: + custom_fni yann@1: + = build_function_type (float_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (integer_type_node) yann@1: + endlink))); yann@1: + custom_fnf yann@1: + = build_function_type (float_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (float_type_node) yann@1: + endlink))); yann@1: + custom_fnp yann@1: + = build_function_type (float_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (ptr_type_node) yann@1: + endlink))); yann@1: + custom_fnii yann@1: + = build_function_type (float_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (integer_type_node) yann@1: + def_param (integer_type_node) yann@1: + endlink)))); yann@1: + custom_fnif yann@1: + = build_function_type (float_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (integer_type_node) yann@1: + def_param (float_type_node) yann@1: + endlink)))); yann@1: + custom_fnip yann@1: + = build_function_type (float_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (integer_type_node) yann@1: + def_param (ptr_type_node) yann@1: + endlink)))); yann@1: + custom_fnfi yann@1: + = build_function_type (float_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (float_type_node) yann@1: + def_param (integer_type_node) yann@1: + endlink)))); yann@1: + custom_fnff yann@1: + = build_function_type (float_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (float_type_node) yann@1: + def_param (float_type_node) yann@1: + endlink)))); yann@1: + custom_fnfp yann@1: + = build_function_type (float_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (float_type_node) yann@1: + def_param (ptr_type_node) yann@1: + endlink)))); yann@1: + custom_fnpi yann@1: + = build_function_type (float_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (ptr_type_node) yann@1: + def_param (integer_type_node) yann@1: + endlink)))); yann@1: + custom_fnpf yann@1: + = build_function_type (float_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (ptr_type_node) yann@1: + def_param (float_type_node) yann@1: + endlink)))); yann@1: + custom_fnpp yann@1: + = build_function_type (float_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (ptr_type_node) yann@1: + def_param (ptr_type_node) yann@1: + endlink)))); yann@1: + yann@1: + yann@1: + custom_pn yann@1: + = build_function_type (ptr_type_node, yann@1: + CUSTOM_NUM yann@1: + endlink)); yann@1: + custom_pni yann@1: + = build_function_type (ptr_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (integer_type_node) yann@1: + endlink))); yann@1: + custom_pnf yann@1: + = build_function_type (ptr_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (float_type_node) yann@1: + endlink))); yann@1: + custom_pnp yann@1: + = build_function_type (ptr_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (ptr_type_node) yann@1: + endlink))); yann@1: + custom_pnii yann@1: + = build_function_type (ptr_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (integer_type_node) yann@1: + def_param (integer_type_node) yann@1: + endlink)))); yann@1: + custom_pnif yann@1: + = build_function_type (ptr_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (integer_type_node) yann@1: + def_param (float_type_node) yann@1: + endlink)))); yann@1: + custom_pnip yann@1: + = build_function_type (ptr_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (integer_type_node) yann@1: + def_param (ptr_type_node) yann@1: + endlink)))); yann@1: + custom_pnfi yann@1: + = build_function_type (ptr_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (float_type_node) yann@1: + def_param (integer_type_node) yann@1: + endlink)))); yann@1: + custom_pnff yann@1: + = build_function_type (ptr_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (float_type_node) yann@1: + def_param (float_type_node) yann@1: + endlink)))); yann@1: + custom_pnfp yann@1: + = build_function_type (ptr_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (float_type_node) yann@1: + def_param (ptr_type_node) yann@1: + endlink)))); yann@1: + custom_pnpi yann@1: + = build_function_type (ptr_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (ptr_type_node) yann@1: + def_param (integer_type_node) yann@1: + endlink)))); yann@1: + custom_pnpf yann@1: + = build_function_type (ptr_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (ptr_type_node) yann@1: + def_param (float_type_node) yann@1: + endlink)))); yann@1: + custom_pnpp yann@1: + = build_function_type (ptr_type_node, yann@1: + CUSTOM_NUM yann@1: + def_param (ptr_type_node) yann@1: + def_param (ptr_type_node) yann@1: + endlink)))); yann@1: + yann@1: + yann@1: + yann@1: + /* *INDENT-ON* */ yann@1: + yann@1: + yann@1: + for (d = bdesc; d->name; d++) yann@1: + { yann@1: + builtin_function (d->name, *d->type, d->code, yann@1: + BUILT_IN_MD, NULL, NULL); yann@1: + } yann@1: +} yann@1: + yann@1: +/* Expand an expression EXP that calls a built-in function, yann@1: + with result going to TARGET if that's convenient yann@1: + (and in mode MODE if that's convenient). yann@1: + SUBTARGET may be used as the target for computing one of EXP's operands. yann@1: + IGNORE is nonzero if the value is to be ignored. */ yann@1: + yann@1: +static rtx yann@1: +nios2_expand_builtin (tree exp, rtx target, rtx subtarget, yann@1: + enum machine_mode mode, int ignore) yann@1: +{ yann@1: + const struct builtin_description *d; yann@1: + tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); yann@1: + unsigned int fcode = DECL_FUNCTION_CODE (fndecl); yann@1: + yann@1: + for (d = bdesc; d->name; d++) yann@1: + if (d->code == fcode) yann@1: + return (d->expander) (d, exp, target, subtarget, mode, ignore); yann@1: + yann@1: + /* we should have seen one of the functins we registered */ yann@1: + abort (); yann@1: +} yann@1: + yann@1: +static rtx nios2_create_target (const struct builtin_description *, rtx); yann@1: + yann@1: + yann@1: +static rtx yann@1: +nios2_create_target (const struct builtin_description *d, rtx target) yann@1: +{ yann@1: + if (!target yann@1: + || !(*insn_data[d->icode].operand[0].predicate) (target, yann@1: + insn_data[d->icode].operand[0].mode)) yann@1: + { yann@1: + target = gen_reg_rtx (insn_data[d->icode].operand[0].mode); yann@1: + } yann@1: + yann@1: + return target; yann@1: +} yann@1: + yann@1: + yann@1: +static rtx nios2_extract_opcode (const struct builtin_description *, int, tree); yann@1: +static rtx nios2_extract_operand (const struct builtin_description *, int, int, tree); yann@1: + yann@1: +static rtx yann@1: +nios2_extract_opcode (const struct builtin_description *d, int op, tree arglist) yann@1: +{ yann@1: + enum machine_mode mode = insn_data[d->icode].operand[op].mode; yann@1: + tree arg = TREE_VALUE (arglist); yann@1: + rtx opcode = expand_expr (arg, NULL_RTX, mode, 0); yann@1: + opcode = protect_from_queue (opcode, 0); yann@1: + yann@1: + if (!(*insn_data[d->icode].operand[op].predicate) (opcode, mode)) yann@1: + error ("Custom instruction opcode must be compile time constant in the range 0-255 for %s", d->name); yann@1: + yann@1: + return opcode; yann@1: +} yann@1: + yann@1: +static rtx yann@1: +nios2_extract_operand (const struct builtin_description *d, int op, int argnum, tree arglist) yann@1: +{ yann@1: + enum machine_mode mode = insn_data[d->icode].operand[op].mode; yann@1: + tree arg = TREE_VALUE (arglist); yann@1: + rtx operand = expand_expr (arg, NULL_RTX, mode, 0); yann@1: + operand = protect_from_queue (operand, 0); yann@1: + yann@1: + if (!(*insn_data[d->icode].operand[op].predicate) (operand, mode)) yann@1: + operand = copy_to_mode_reg (mode, operand); yann@1: + yann@1: + /* ??? Better errors would be nice */ yann@1: + if (!(*insn_data[d->icode].operand[op].predicate) (operand, mode)) yann@1: + error ("Invalid argument %d to %s", argnum, d->name); yann@1: + yann@1: + return operand; yann@1: +} yann@1: + yann@1: + yann@1: +static rtx yann@1: +nios2_expand_custom_n (const struct builtin_description *d, tree exp, yann@1: + rtx target ATTRIBUTE_UNUSED, rtx subtarget ATTRIBUTE_UNUSED, yann@1: + enum machine_mode mode ATTRIBUTE_UNUSED, int ignore ATTRIBUTE_UNUSED) yann@1: +{ yann@1: + tree arglist = TREE_OPERAND (exp, 1); yann@1: + rtx pat; yann@1: + rtx opcode; yann@1: + yann@1: + /* custom_n should have exactly one operand */ yann@1: + if (insn_data[d->icode].n_operands != 1) yann@1: + abort (); yann@1: + yann@1: + opcode = nios2_extract_opcode (d, 0, arglist); yann@1: + yann@1: + pat = GEN_FCN (d->icode) (opcode); yann@1: + if (!pat) yann@1: + return 0; yann@1: + emit_insn (pat); yann@1: + return 0; yann@1: +} yann@1: + yann@1: +static rtx yann@1: +nios2_expand_custom_Xn (const struct builtin_description *d, tree exp, yann@1: + rtx target, rtx subtarget ATTRIBUTE_UNUSED, yann@1: + enum machine_mode mode ATTRIBUTE_UNUSED, yann@1: + int ignore ATTRIBUTE_UNUSED) yann@1: +{ yann@1: + tree arglist = TREE_OPERAND (exp, 1); yann@1: + rtx pat; yann@1: + rtx opcode; yann@1: + yann@1: + /* custom_Xn should have exactly two operands */ yann@1: + if (insn_data[d->icode].n_operands != 2) yann@1: + abort (); yann@1: + yann@1: + target = nios2_create_target (d, target); yann@1: + opcode = nios2_extract_opcode (d, 1, arglist); yann@1: + yann@1: + pat = GEN_FCN (d->icode) (target, opcode); yann@1: + if (!pat) yann@1: + return 0; yann@1: + emit_insn (pat); yann@1: + return target; yann@1: +} yann@1: + yann@1: +static rtx yann@1: +nios2_expand_custom_nX (const struct builtin_description *d, tree exp, yann@1: + rtx target ATTRIBUTE_UNUSED, rtx subtarget ATTRIBUTE_UNUSED, yann@1: + enum machine_mode mode ATTRIBUTE_UNUSED, int ignore ATTRIBUTE_UNUSED) yann@1: +{ yann@1: + tree arglist = TREE_OPERAND (exp, 1); yann@1: + rtx pat; yann@1: + rtx opcode; yann@1: + rtx operands[1]; yann@1: + int i; yann@1: + yann@1: + yann@1: + /* custom_nX should have exactly two operands */ yann@1: + if (insn_data[d->icode].n_operands != 2) yann@1: + abort (); yann@1: + yann@1: + opcode = nios2_extract_opcode (d, 0, arglist); yann@1: + for (i = 0; i < 1; i++) yann@1: + { yann@1: + arglist = TREE_CHAIN (arglist); yann@1: + operands[i] = nios2_extract_operand (d, i + 1, i + 1, arglist); yann@1: + } yann@1: + yann@1: + pat = GEN_FCN (d->icode) (opcode, operands[0]); yann@1: + if (!pat) yann@1: + return 0; yann@1: + emit_insn (pat); yann@1: + return 0; yann@1: +} yann@1: + yann@1: +static rtx yann@1: +nios2_expand_custom_XnX (const struct builtin_description *d, tree exp, rtx target, yann@1: + rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, yann@1: + int ignore ATTRIBUTE_UNUSED) yann@1: +{ yann@1: + tree arglist = TREE_OPERAND (exp, 1); yann@1: + rtx pat; yann@1: + rtx opcode; yann@1: + rtx operands[1]; yann@1: + int i; yann@1: + yann@1: + /* custom_Xn should have exactly three operands */ yann@1: + if (insn_data[d->icode].n_operands != 3) yann@1: + abort (); yann@1: + yann@1: + target = nios2_create_target (d, target); yann@1: + opcode = nios2_extract_opcode (d, 1, arglist); yann@1: + yann@1: + for (i = 0; i < 1; i++) yann@1: + { yann@1: + arglist = TREE_CHAIN (arglist); yann@1: + operands[i] = nios2_extract_operand (d, i + 2, i + 1, arglist); yann@1: + } yann@1: + yann@1: + pat = GEN_FCN (d->icode) (target, opcode, operands[0]); yann@1: + yann@1: + if (!pat) yann@1: + return 0; yann@1: + emit_insn (pat); yann@1: + return target; yann@1: +} yann@1: + yann@1: +static rtx yann@1: +nios2_expand_custom_nXX (const struct builtin_description *d, tree exp, rtx target ATTRIBUTE_UNUSED, yann@1: + rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, yann@1: + int ignore ATTRIBUTE_UNUSED) yann@1: +{ yann@1: + tree arglist = TREE_OPERAND (exp, 1); yann@1: + rtx pat; yann@1: + rtx opcode; yann@1: + rtx operands[2]; yann@1: + int i; yann@1: + yann@1: + yann@1: + /* custom_nX should have exactly three operands */ yann@1: + if (insn_data[d->icode].n_operands != 3) yann@1: + abort (); yann@1: + yann@1: + opcode = nios2_extract_opcode (d, 0, arglist); yann@1: + for (i = 0; i < 2; i++) yann@1: + { yann@1: + arglist = TREE_CHAIN (arglist); yann@1: + operands[i] = nios2_extract_operand (d, i + 1, i + 1, arglist); yann@1: + } yann@1: + yann@1: + pat = GEN_FCN (d->icode) (opcode, operands[0], operands[1]); yann@1: + if (!pat) yann@1: + return 0; yann@1: + emit_insn (pat); yann@1: + return 0; yann@1: +} yann@1: + yann@1: +static rtx yann@1: +nios2_expand_custom_XnXX (const struct builtin_description *d, tree exp, rtx target, yann@1: + rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, yann@1: + int ignore ATTRIBUTE_UNUSED) yann@1: +{ yann@1: + tree arglist = TREE_OPERAND (exp, 1); yann@1: + rtx pat; yann@1: + rtx opcode; yann@1: + rtx operands[2]; yann@1: + int i; yann@1: + yann@1: + yann@1: + /* custom_XnX should have exactly four operands */ yann@1: + if (insn_data[d->icode].n_operands != 4) yann@1: + abort (); yann@1: + yann@1: + target = nios2_create_target (d, target); yann@1: + opcode = nios2_extract_opcode (d, 1, arglist); yann@1: + for (i = 0; i < 2; i++) yann@1: + { yann@1: + arglist = TREE_CHAIN (arglist); yann@1: + operands[i] = nios2_extract_operand (d, i + 2, i + 1, arglist); yann@1: + } yann@1: + yann@1: + pat = GEN_FCN (d->icode) (target, opcode, operands[0], operands[1]); yann@1: + yann@1: + if (!pat) yann@1: + return 0; yann@1: + emit_insn (pat); yann@1: + return target; yann@1: +} yann@1: + yann@1: + yann@1: + yann@1: +static rtx yann@1: +nios2_expand_STXIO (const struct builtin_description *d, tree exp, rtx target ATTRIBUTE_UNUSED, yann@1: + rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, yann@1: + int ignore ATTRIBUTE_UNUSED) yann@1: +{ yann@1: + tree arglist = TREE_OPERAND (exp, 1); yann@1: + rtx pat; yann@1: + rtx store_dest, store_val; yann@1: + enum insn_code icode = d->icode; yann@1: + yann@1: + /* stores should have exactly two operands */ yann@1: + if (insn_data[icode].n_operands != 2) yann@1: + abort (); yann@1: + yann@1: + /* process the destination of the store */ yann@1: + { yann@1: + enum machine_mode mode = insn_data[icode].operand[0].mode; yann@1: + tree arg = TREE_VALUE (arglist); yann@1: + store_dest = expand_expr (arg, NULL_RTX, VOIDmode, 0); yann@1: + store_dest = protect_from_queue (store_dest, 0); yann@1: + yann@1: + store_dest = gen_rtx_MEM (mode, copy_to_mode_reg (Pmode, store_dest)); yann@1: + yann@1: + /* ??? Better errors would be nice */ yann@1: + if (!(*insn_data[icode].operand[0].predicate) (store_dest, mode)) yann@1: + error ("Invalid argument 1 to %s", d->name); yann@1: + } yann@1: + yann@1: + yann@1: + /* process the value to store */ yann@1: + { yann@1: + enum machine_mode mode = insn_data[icode].operand[1].mode; yann@1: + tree arg = TREE_VALUE (TREE_CHAIN (arglist)); yann@1: + store_val = expand_expr (arg, NULL_RTX, mode, 0); yann@1: + store_val = protect_from_queue (store_val, 0); yann@1: + yann@1: + if (!(*insn_data[icode].operand[1].predicate) (store_val, mode)) yann@1: + store_val = copy_to_mode_reg (mode, store_val); yann@1: + yann@1: + /* ??? Better errors would be nice */ yann@1: + if (!(*insn_data[icode].operand[1].predicate) (store_val, mode)) yann@1: + error ("Invalid argument 2 to %s", d->name); yann@1: + } yann@1: + yann@1: + pat = GEN_FCN (d->icode) (store_dest, store_val); yann@1: + if (!pat) yann@1: + return 0; yann@1: + emit_insn (pat); yann@1: + return 0; yann@1: +} yann@1: + yann@1: + yann@1: +static rtx yann@1: +nios2_expand_LDXIO (const struct builtin_description * d, tree exp, rtx target, yann@1: + rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, yann@1: + int ignore ATTRIBUTE_UNUSED) yann@1: +{ yann@1: + tree arglist = TREE_OPERAND (exp, 1); yann@1: + rtx pat; yann@1: + rtx ld_src; yann@1: + enum insn_code icode = d->icode; yann@1: + yann@1: + /* loads should have exactly two operands */ yann@1: + if (insn_data[icode].n_operands != 2) yann@1: + abort (); yann@1: + yann@1: + target = nios2_create_target (d, target); yann@1: + yann@1: + { yann@1: + enum machine_mode mode = insn_data[icode].operand[1].mode; yann@1: + tree arg = TREE_VALUE (arglist); yann@1: + ld_src = expand_expr (arg, NULL_RTX, VOIDmode, 0); yann@1: + ld_src = protect_from_queue (ld_src, 0); yann@1: + yann@1: + ld_src = gen_rtx_MEM (mode, copy_to_mode_reg (Pmode, ld_src)); yann@1: + yann@1: + /* ??? Better errors would be nice */ yann@1: + if (!(*insn_data[icode].operand[1].predicate) (ld_src, mode)) yann@1: + { yann@1: + error ("Invalid argument 1 to %s", d->name); yann@1: + } yann@1: + } yann@1: + yann@1: + pat = GEN_FCN (d->icode) (target, ld_src); yann@1: + if (!pat) yann@1: + return 0; yann@1: + emit_insn (pat); yann@1: + return target; yann@1: +} yann@1: + yann@1: + yann@1: +static rtx yann@1: +nios2_expand_sync (const struct builtin_description * d ATTRIBUTE_UNUSED, yann@1: + tree exp ATTRIBUTE_UNUSED, rtx target ATTRIBUTE_UNUSED, yann@1: + rtx subtarget ATTRIBUTE_UNUSED, yann@1: + enum machine_mode mode ATTRIBUTE_UNUSED, yann@1: + int ignore ATTRIBUTE_UNUSED) yann@1: +{ yann@1: + emit_insn (gen_sync ()); yann@1: + return 0; yann@1: +} yann@1: + yann@1: +static rtx yann@1: +nios2_expand_rdctl (const struct builtin_description * d ATTRIBUTE_UNUSED, yann@1: + tree exp ATTRIBUTE_UNUSED, rtx target ATTRIBUTE_UNUSED, yann@1: + rtx subtarget ATTRIBUTE_UNUSED, yann@1: + enum machine_mode mode ATTRIBUTE_UNUSED, yann@1: + int ignore ATTRIBUTE_UNUSED) yann@1: +{ yann@1: + tree arglist = TREE_OPERAND (exp, 1); yann@1: + rtx pat; yann@1: + rtx rdctl_reg; yann@1: + enum insn_code icode = d->icode; yann@1: + yann@1: + /* rdctl should have exactly two operands */ yann@1: + if (insn_data[icode].n_operands != 2) yann@1: + abort (); yann@1: + yann@1: + target = nios2_create_target (d, target); yann@1: + yann@1: + { yann@1: + enum machine_mode mode = insn_data[icode].operand[1].mode; yann@1: + tree arg = TREE_VALUE (arglist); yann@1: + rdctl_reg = expand_expr (arg, NULL_RTX, VOIDmode, 0); yann@1: + rdctl_reg = protect_from_queue (rdctl_reg, 0); yann@1: + yann@1: + if (!(*insn_data[icode].operand[1].predicate) (rdctl_reg, mode)) yann@1: + { yann@1: + error ("Control register number must be in range 0-31 for %s", d->name); yann@1: + } yann@1: + } yann@1: + yann@1: + pat = GEN_FCN (d->icode) (target, rdctl_reg); yann@1: + if (!pat) yann@1: + return 0; yann@1: + emit_insn (pat); yann@1: + return target; yann@1: +} yann@1: + yann@1: +static rtx yann@1: +nios2_expand_wrctl (const struct builtin_description * d ATTRIBUTE_UNUSED, yann@1: + tree exp ATTRIBUTE_UNUSED, rtx target ATTRIBUTE_UNUSED, yann@1: + rtx subtarget ATTRIBUTE_UNUSED, yann@1: + enum machine_mode mode ATTRIBUTE_UNUSED, yann@1: + int ignore ATTRIBUTE_UNUSED) yann@1: +{ yann@1: + tree arglist = TREE_OPERAND (exp, 1); yann@1: + rtx pat; yann@1: + rtx wrctl_reg, store_val; yann@1: + enum insn_code icode = d->icode; yann@1: + yann@1: + /* stores should have exactly two operands */ yann@1: + if (insn_data[icode].n_operands != 2) yann@1: + abort (); yann@1: + yann@1: + /* process the destination of the store */ yann@1: + { yann@1: + enum machine_mode mode = insn_data[icode].operand[0].mode; yann@1: + tree arg = TREE_VALUE (arglist); yann@1: + wrctl_reg = expand_expr (arg, NULL_RTX, VOIDmode, 0); yann@1: + wrctl_reg = protect_from_queue (wrctl_reg, 0); yann@1: + yann@1: + if (!(*insn_data[icode].operand[0].predicate) (wrctl_reg, mode)) yann@1: + error ("Control register number must be in range 0-31 for %s", d->name); yann@1: + } yann@1: + yann@1: + yann@1: + /* process the value to store */ yann@1: + { yann@1: + enum machine_mode mode = insn_data[icode].operand[1].mode; yann@1: + tree arg = TREE_VALUE (TREE_CHAIN (arglist)); yann@1: + store_val = expand_expr (arg, NULL_RTX, mode, 0); yann@1: + store_val = protect_from_queue (store_val, 0); yann@1: + yann@1: + if (!(*insn_data[icode].operand[1].predicate) (store_val, mode)) yann@1: + store_val = copy_to_mode_reg (mode, store_val); yann@1: + yann@1: + /* ??? Better errors would be nice */ yann@1: + if (!(*insn_data[icode].operand[1].predicate) (store_val, mode)) yann@1: + error ("Invalid argument 2 to %s", d->name); yann@1: + } yann@1: + yann@1: + pat = GEN_FCN (d->icode) (wrctl_reg, store_val); yann@1: + if (!pat) yann@1: + return 0; yann@1: + emit_insn (pat); yann@1: + return 0; yann@1: +} yann@1: + yann@1: + yann@1: +#include "gt-nios2.h" yann@1: + yann@1: --- gcc-3.4.3/gcc/config/nios2/nios2.h yann@1: +++ gcc-3.4.3-nios2/gcc/config/nios2/nios2.h yann@1: @@ -0,0 +1,824 @@ yann@1: +/* Definitions of target machine for Altera NIOS 2G NIOS2 version. yann@1: + Copyright (C) 2003 Altera yann@1: + Contributed by Jonah Graham (jgraham@altera.com). yann@1: + yann@1: +This file is part of GNU CC. yann@1: + yann@1: +GNU CC is free software; you can redistribute it and/or modify yann@1: +it under the terms of the GNU General Public License as published by yann@1: +the Free Software Foundation; either version 2, or (at your option) yann@1: +any later version. yann@1: + yann@1: +GNU CC is distributed in the hope that it will be useful, yann@1: +but WITHOUT ANY WARRANTY; without even the implied warranty of yann@1: +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the yann@1: +GNU General Public License for more details. yann@1: + yann@1: +You should have received a copy of the GNU General Public License yann@1: +along with GNU CC; see the file COPYING. If not, write to yann@1: +the Free Software Foundation, 59 Temple Place - Suite 330, yann@1: +Boston, MA 02111-1307, USA. */ yann@1: + yann@1: + yann@1: + yann@1: +#define TARGET_CPU_CPP_BUILTINS() \ yann@1: + do \ yann@1: + { \ yann@1: + builtin_define_std ("NIOS2"); \ yann@1: + builtin_define_std ("nios2"); \ yann@1: + builtin_define ("_GNU_SOURCE"); \ yann@1: + } \ yann@1: + while (0) yann@1: +#define TARGET_VERSION fprintf (stderr, " (Altera Nios II)") yann@1: + yann@1: + yann@1: + yann@1: + yann@1: + yann@1: +/********************************* yann@1: + * Run-time Target Specification yann@1: + *********************************/ yann@1: + yann@1: +#define HAS_DIV_FLAG 0x0001 yann@1: +#define HAS_MUL_FLAG 0x0002 yann@1: +#define HAS_MULX_FLAG 0x0004 yann@1: +#define FAST_SW_DIV_FLAG 0x0008 yann@1: +#define INLINE_MEMCPY_FLAG 0x00010 yann@1: +#define CACHE_VOLATILE_FLAG 0x0020 yann@1: +#define BYPASS_CACHE_FLAG 0x0040 yann@1: + yann@1: +extern int target_flags; yann@1: +#define TARGET_HAS_DIV (target_flags & HAS_DIV_FLAG) yann@1: +#define TARGET_HAS_MUL (target_flags & HAS_MUL_FLAG) yann@1: +#define TARGET_HAS_MULX (target_flags & HAS_MULX_FLAG) yann@1: +#define TARGET_FAST_SW_DIV (target_flags & FAST_SW_DIV_FLAG) yann@1: +#define TARGET_INLINE_MEMCPY (target_flags & INLINE_MEMCPY_FLAG) yann@1: +#define TARGET_CACHE_VOLATILE (target_flags & CACHE_VOLATILE_FLAG) yann@1: +#define TARGET_BYPASS_CACHE (target_flags & BYPASS_CACHE_FLAG) yann@1: + yann@1: +#define TARGET_SWITCHES \ yann@1: +{ \ yann@1: + { "hw-div", HAS_DIV_FLAG, \ yann@1: + N_("Enable DIV, DIVU") }, \ yann@1: + { "no-hw-div", -HAS_DIV_FLAG, \ yann@1: + N_("Disable DIV, DIVU (default)") }, \ yann@1: + { "hw-mul", HAS_MUL_FLAG, \ yann@1: + N_("Enable MUL instructions (default)") }, \ yann@1: + { "hw-mulx", HAS_MULX_FLAG, \ yann@1: + N_("Enable MULX instructions, assume fast shifter") }, \ yann@1: + { "no-hw-mul", -HAS_MUL_FLAG, \ yann@1: + N_("Disable MUL instructions") }, \ yann@1: + { "no-hw-mulx", -HAS_MULX_FLAG, \ yann@1: + N_("Disable MULX instructions, assume slow shifter (default and implied by -mno-hw-mul)") }, \ yann@1: + { "fast-sw-div", FAST_SW_DIV_FLAG, \ yann@1: + N_("Use table based fast divide (default at -O3)") }, \ yann@1: + { "no-fast-sw-div", -FAST_SW_DIV_FLAG, \ yann@1: + N_("Don't use table based fast divide ever") }, \ yann@1: + { "inline-memcpy", INLINE_MEMCPY_FLAG, \ yann@1: + N_("Inline small memcpy (default when optimizing)") }, \ yann@1: + { "no-inline-memcpy", -INLINE_MEMCPY_FLAG, \ yann@1: + N_("Don't Inline small memcpy") }, \ yann@1: + { "cache-volatile", CACHE_VOLATILE_FLAG, \ yann@1: + N_("Volatile accesses use non-io variants of instructions (default)") }, \ yann@1: + { "no-cache-volatile", -CACHE_VOLATILE_FLAG, \ yann@1: + N_("Volatile accesses use io variants of instructions") }, \ yann@1: + { "bypass-cache", BYPASS_CACHE_FLAG, \ yann@1: + N_("All ld/st instructins use io variants") }, \ yann@1: + { "no-bypass-cache", -BYPASS_CACHE_FLAG, \ yann@1: + N_("All ld/st instructins do not use io variants (default)") }, \ yann@1: + { "smallc", 0, \ yann@1: + N_("Link with a limited version of the C library") }, \ yann@1: + { "ctors-in-init", 0, \ yann@1: + "" /* undocumented: N_("Link with static constructors and destructors in init") */ }, \ yann@1: + { "", TARGET_DEFAULT, 0 } \ yann@1: +} yann@1: + yann@1: + yann@1: +extern const char *nios2_sys_nosys_string; /* for -msys=nosys */ yann@1: +extern const char *nios2_sys_lib_string; /* for -msys-lib= */ yann@1: +extern const char *nios2_sys_crt0_string; /* for -msys-crt0= */ yann@1: + yann@1: +#define TARGET_OPTIONS \ yann@1: +{ \ yann@1: + { "sys=nosys", &nios2_sys_nosys_string, \ yann@1: + N_("Use stub versions of OS library calls (default)"), 0}, \ yann@1: + { "sys-lib=", &nios2_sys_lib_string, \ yann@1: + N_("Name of System Library to link against. (Converted to a -l option)"), 0}, \ yann@1: + { "sys-crt0=", &nios2_sys_crt0_string, \ yann@1: + N_("Name of the startfile. (default is a crt0 for the ISS only)"), 0}, \ yann@1: +} yann@1: + yann@1: + yann@1: +/* Default target_flags if no switches specified. */ yann@1: +#ifndef TARGET_DEFAULT yann@1: +# define TARGET_DEFAULT (HAS_MUL_FLAG | CACHE_VOLATILE_FLAG) yann@1: +#endif yann@1: + yann@1: +/* Switch Recognition by gcc.c. Add -G xx support */ yann@1: +#undef SWITCH_TAKES_ARG yann@1: +#define SWITCH_TAKES_ARG(CHAR) \ yann@1: + (DEFAULT_SWITCH_TAKES_ARG (CHAR) || (CHAR) == 'G') yann@1: + yann@1: +#define OVERRIDE_OPTIONS override_options () yann@1: +#define OPTIMIZATION_OPTIONS(LEVEL, SIZE) optimization_options (LEVEL, SIZE) yann@1: +#define CAN_DEBUG_WITHOUT_FP yann@1: + yann@1: +#define CC1_SPEC "\ yann@1: +%{G*}" yann@1: + yann@1: +#undef LIB_SPEC yann@1: +#define LIB_SPEC \ yann@1: +"--start-group %{msmallc: -lsmallc} %{!msmallc: -lc} -lgcc \ yann@1: + %{msys-lib=*: -l%*} \ yann@1: + %{!msys-lib=*: -lc } \ yann@1: + --end-group \ yann@1: + %{msys-lib=: %eYou need a library name for -msys-lib=} \ yann@1: +" yann@1: + yann@1: + yann@1: +#undef STARTFILE_SPEC yann@1: +#define STARTFILE_SPEC \ yann@1: +"%{msys-crt0=*: %*} %{!msys-crt0=*: crt1%O%s} \ yann@1: + %{msys-crt0=: %eYou need a C startup file for -msys-crt0=} \ yann@1: + %{mctors-in-init: crti%O%s crtbegin%O%s} \ yann@1: +" yann@1: + yann@1: +#undef ENDFILE_SPEC yann@1: +#define ENDFILE_SPEC \ yann@1: + "%{mctors-in-init: crtend%O%s crtn%O%s}" yann@1: + yann@1: + yann@1: +/*********************** yann@1: + * Storage Layout yann@1: + ***********************/ yann@1: + yann@1: +#define DEFAULT_SIGNED_CHAR 1 yann@1: +#define BITS_BIG_ENDIAN 0 yann@1: +#define BYTES_BIG_ENDIAN 0 yann@1: +#define WORDS_BIG_ENDIAN 0 yann@1: +#define BITS_PER_UNIT 8 yann@1: +#define BITS_PER_WORD 32 yann@1: +#define UNITS_PER_WORD 4 yann@1: +#define POINTER_SIZE 32 yann@1: +#define BIGGEST_ALIGNMENT 32 yann@1: +#define STRICT_ALIGNMENT 1 yann@1: +#define FUNCTION_BOUNDARY 32 yann@1: +#define PARM_BOUNDARY 32 yann@1: +#define STACK_BOUNDARY 32 yann@1: +#define PREFERRED_STACK_BOUNDARY 32 yann@1: +#define MAX_FIXED_MODE_SIZE 64 yann@1: + yann@1: +#define CONSTANT_ALIGNMENT(EXP, ALIGN) \ yann@1: + ((TREE_CODE (EXP) == STRING_CST) \ yann@1: + && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN)) yann@1: + yann@1: + yann@1: +/********************** yann@1: + * Layout of Source Language Data Types yann@1: + **********************/ yann@1: + yann@1: +#define INT_TYPE_SIZE 32 yann@1: +#define SHORT_TYPE_SIZE 16 yann@1: +#define LONG_TYPE_SIZE 32 yann@1: +#define LONG_LONG_TYPE_SIZE 64 yann@1: +#define FLOAT_TYPE_SIZE 32 yann@1: +#define DOUBLE_TYPE_SIZE 64 yann@1: +#define LONG_DOUBLE_TYPE_SIZE DOUBLE_TYPE_SIZE yann@1: + yann@1: + yann@1: +/************************* yann@1: + * Condition Code Status yann@1: + ************************/ yann@1: + yann@1: +/* comparison type */ yann@1: +/* ??? currently only CMP_SI is used */ yann@1: +enum cmp_type { yann@1: + CMP_SI, /* compare four byte integers */ yann@1: + CMP_DI, /* compare eight byte integers */ yann@1: + CMP_SF, /* compare single precision floats */ yann@1: + CMP_DF, /* compare double precision floats */ yann@1: + CMP_MAX /* max comparison type */ yann@1: +}; yann@1: + yann@1: +extern GTY(()) rtx branch_cmp[2]; /* operands for compare */ yann@1: +extern enum cmp_type branch_type; /* what type of branch to use */ yann@1: + yann@1: +/********************** yann@1: + * Register Usage yann@1: + **********************/ yann@1: + yann@1: +/* ---------------------------------- * yann@1: + * Basic Characteristics of Registers yann@1: + * ---------------------------------- */ yann@1: + yann@1: +/* yann@1: +Register Number yann@1: + Register Name yann@1: + Alternate Name yann@1: + Purpose yann@1: +0 r0 zero always zero yann@1: +1 r1 at Assembler Temporary yann@1: +2-3 r2-r3 Return Location yann@1: +4-7 r4-r7 Register Arguments yann@1: +8-15 r8-r15 Caller Saved Registers yann@1: +16-22 r16-r22 Callee Saved Registers yann@1: +23 r23 sc Static Chain (Callee Saved) yann@1: + ??? Does $sc want to be caller or callee yann@1: + saved. If caller, 15, else 23. yann@1: +24 r24 Exception Temporary yann@1: +25 r25 Breakpoint Temporary yann@1: +26 r26 gp Global Pointer yann@1: +27 r27 sp Stack Pointer yann@1: +28 r28 fp Frame Pointer yann@1: +29 r29 ea Exception Return Address yann@1: +30 r30 ba Breakpoint Return Address yann@1: +31 r31 ra Return Address yann@1: + yann@1: +32 ctl0 status yann@1: +33 ctl1 estatus STATUS saved by exception ? yann@1: +34 ctl2 bstatus STATUS saved by break ? yann@1: +35 ctl3 ipri Interrupt Priority Mask ? yann@1: +36 ctl4 ecause Exception Cause ? yann@1: + yann@1: +37 pc Not an actual register yann@1: + yann@1: +38 rap Return address pointer, this does not yann@1: + actually exist and will be eliminated yann@1: + yann@1: +39 fake_fp Fake Frame Pointer which will always be eliminated. yann@1: +40 fake_ap Fake Argument Pointer which will always be eliminated. yann@1: + yann@1: +41 First Pseudo Register yann@1: + yann@1: + yann@1: +The definitions for all the hard register numbers yann@1: +are located in nios2.md. yann@1: +*/ yann@1: + yann@1: +#define FIRST_PSEUDO_REGISTER 41 yann@1: +#define NUM_ARG_REGS (LAST_ARG_REGNO - FIRST_ARG_REGNO + 1) yann@1: + yann@1: + yann@1: + yann@1: +/* also see CONDITIONAL_REGISTER_USAGE */ yann@1: +#define FIXED_REGISTERS \ yann@1: + { \ yann@1: +/* +0 1 2 3 4 5 6 7 8 9 */ \ yann@1: +/* 0 */ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, \ yann@1: +/* 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ yann@1: +/* 20 */ 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, \ yann@1: +/* 30 */ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, \ yann@1: +/* 40 */ 1, \ yann@1: + } yann@1: + yann@1: +/* call used is the same as caller saved yann@1: + + fixed regs + args + ret vals */ yann@1: +#define CALL_USED_REGISTERS \ yann@1: + { \ yann@1: +/* +0 1 2 3 4 5 6 7 8 9 */ \ yann@1: +/* 0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ yann@1: +/* 10 */ 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, \ yann@1: +/* 20 */ 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, \ yann@1: +/* 30 */ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, \ yann@1: +/* 40 */ 1, \ yann@1: + } yann@1: + yann@1: +#define HARD_REGNO_NREGS(REGNO, MODE) \ yann@1: + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \ yann@1: + / UNITS_PER_WORD) yann@1: + yann@1: +/* --------------------------- * yann@1: + * How Values Fit in Registers yann@1: + * --------------------------- */ yann@1: + yann@1: +#define HARD_REGNO_MODE_OK(REGNO, MODE) 1 yann@1: + yann@1: +#define MODES_TIEABLE_P(MODE1, MODE2) 1 yann@1: + yann@1: + yann@1: +/************************* yann@1: + * Register Classes yann@1: + *************************/ yann@1: + yann@1: +enum reg_class yann@1: +{ yann@1: + NO_REGS, yann@1: + ALL_REGS, yann@1: + LIM_REG_CLASSES yann@1: +}; yann@1: + yann@1: +#define N_REG_CLASSES (int) LIM_REG_CLASSES yann@1: + yann@1: +#define REG_CLASS_NAMES \ yann@1: + {"NO_REGS", \ yann@1: + "ALL_REGS"} yann@1: + yann@1: +#define GENERAL_REGS ALL_REGS yann@1: + yann@1: +#define REG_CLASS_CONTENTS \ yann@1: +/* NO_REGS */ {{ 0, 0}, \ yann@1: +/* ALL_REGS */ {~0,~0}} \ yann@1: + yann@1: +#define REGNO_REG_CLASS(REGNO) ALL_REGS yann@1: + yann@1: +#define BASE_REG_CLASS ALL_REGS yann@1: +#define INDEX_REG_CLASS ALL_REGS yann@1: + yann@1: +/* only one reg class, 'r', is handled automatically */ yann@1: +#define REG_CLASS_FROM_LETTER(CHAR) NO_REGS yann@1: + yann@1: +#define REGNO_OK_FOR_BASE_P2(REGNO, STRICT) \ yann@1: + ((STRICT) \ yann@1: + ? (REGNO) < FIRST_PSEUDO_REGISTER \ yann@1: + : (REGNO) < FIRST_PSEUDO_REGISTER || (reg_renumber && reg_renumber[REGNO] < FIRST_PSEUDO_REGISTER)) yann@1: + yann@1: +#define REGNO_OK_FOR_INDEX_P2(REGNO, STRICT) \ yann@1: + (REGNO_OK_FOR_BASE_P2 (REGNO, STRICT)) yann@1: + yann@1: +#define REGNO_OK_FOR_BASE_P(REGNO) \ yann@1: + (REGNO_OK_FOR_BASE_P2 (REGNO, 1)) yann@1: + yann@1: +#define REGNO_OK_FOR_INDEX_P(REGNO) \ yann@1: + (REGNO_OK_FOR_INDEX_P2 (REGNO, 1)) yann@1: + yann@1: +#define REG_OK_FOR_BASE_P2(X, STRICT) \ yann@1: + (STRICT \ yann@1: + ? REGNO_OK_FOR_BASE_P2 (REGNO (X), 1) \ yann@1: + : REGNO_OK_FOR_BASE_P2 (REGNO (X), 1) || REGNO(X) >= FIRST_PSEUDO_REGISTER) yann@1: + yann@1: +#define REG_OK_FOR_INDEX_P2(X, STRICT) \ yann@1: + (STRICT \ yann@1: + ? REGNO_OK_FOR_INDEX_P2 (REGNO (X), 1) \ yann@1: + : REGNO_OK_FOR_INDEX_P2 (REGNO (X), 1) || REGNO(X) >= FIRST_PSEUDO_REGISTER) yann@1: + yann@1: +#define CLASS_MAX_NREGS(CLASS, MODE) \ yann@1: + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \ yann@1: + / UNITS_PER_WORD) yann@1: + yann@1: + yann@1: +#define SMALL_INT(X) ((unsigned HOST_WIDE_INT) ((X) + 0x8000) < 0x10000) yann@1: +#define SMALL_INT_UNSIGNED(X) ((unsigned HOST_WIDE_INT) (X) < 0x10000) yann@1: +#define UPPER16_INT(X) (((X) & 0xffff) == 0) yann@1: +#define SHIFT_INT(X) ((X) >= 0 && (X) <= 31) yann@1: +#define RDWRCTL_INT(X) ((X) >= 0 && (X) <= 31) yann@1: +#define CUSTOM_INSN_OPCODE(X) ((X) >= 0 && (X) <= 255) yann@1: + yann@1: +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ yann@1: + ( \ yann@1: + (C) == 'I' ? SMALL_INT (VALUE) : \ yann@1: + (C) == 'J' ? SMALL_INT_UNSIGNED (VALUE) : \ yann@1: + (C) == 'K' ? UPPER16_INT (VALUE) : \ yann@1: + (C) == 'L' ? SHIFT_INT (VALUE) : \ yann@1: + (C) == 'M' ? (VALUE) == 0 : \ yann@1: + (C) == 'N' ? CUSTOM_INSN_OPCODE (VALUE) : \ yann@1: + (C) == 'O' ? RDWRCTL_INT (VALUE) : \ yann@1: + 0) yann@1: + yann@1: +#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) 0 yann@1: + yann@1: +#define PREFERRED_RELOAD_CLASS(X, CLASS) \ yann@1: + ((CLASS) == NO_REGS ? GENERAL_REGS : (CLASS)) yann@1: + yann@1: +/* 'S' matches immediates which are in small data yann@1: + and therefore can be added to gp to create a yann@1: + 32-bit value. */ yann@1: +#define EXTRA_CONSTRAINT(VALUE, C) \ yann@1: + ((C) == 'S' \ yann@1: + && (GET_CODE (VALUE) == SYMBOL_REF) \ yann@1: + && SYMBOL_REF_IN_NIOS2_SMALL_DATA_P (VALUE)) yann@1: + yann@1: + yann@1: + yann@1: + yann@1: +/* Say that the epilogue uses the return address register. Note that yann@1: + in the case of sibcalls, the values "used by the epilogue" are yann@1: + considered live at the start of the called function. */ yann@1: +#define EPILOGUE_USES(REGNO) ((REGNO) == RA_REGNO) yann@1: + yann@1: + yann@1: +#define DEFAULT_MAIN_RETURN c_expand_return (integer_zero_node) yann@1: + yann@1: +/********************************** yann@1: + * Trampolines for Nested Functions yann@1: + ***********************************/ yann@1: + yann@1: +#define TRAMPOLINE_TEMPLATE(FILE) \ yann@1: + error ("trampolines not yet implemented") yann@1: +#define TRAMPOLINE_SIZE 20 yann@1: +#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \ yann@1: + error ("trampolines not yet implemented") yann@1: + yann@1: +/*************************** yann@1: + * Stack Layout and Calling Conventions yann@1: + ***************************/ yann@1: + yann@1: +/* ------------------ * yann@1: + * Basic Stack Layout yann@1: + * ------------------ */ yann@1: + yann@1: +/* The downward variants are used by the compiler, yann@1: + the upward ones serve as documentation */ yann@1: +#define STACK_GROWS_DOWNWARD yann@1: +#define FRAME_GROWS_UPWARD yann@1: +#define ARGS_GROW_UPWARD yann@1: + yann@1: +#define STARTING_FRAME_OFFSET current_function_outgoing_args_size yann@1: +#define FIRST_PARM_OFFSET(FUNDECL) 0 yann@1: + yann@1: +/* Before the prologue, RA lives in r31. */ yann@1: +#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (VOIDmode, RA_REGNO) yann@1: + yann@1: +/* -------------------------------------- * yann@1: + * Registers That Address the Stack Frame yann@1: + * -------------------------------------- */ yann@1: + yann@1: +#define STACK_POINTER_REGNUM SP_REGNO yann@1: +#define STATIC_CHAIN_REGNUM SC_REGNO yann@1: +#define PC_REGNUM PC_REGNO yann@1: +#define DWARF_FRAME_RETURN_COLUMN RA_REGNO yann@1: + yann@1: +/* Base register for access to local variables of the function. We yann@1: + pretend that the frame pointer is a non-existent hard register, and yann@1: + then eliminate it to HARD_FRAME_POINTER_REGNUM. */ yann@1: +#define FRAME_POINTER_REGNUM FAKE_FP_REGNO yann@1: + yann@1: +#define HARD_FRAME_POINTER_REGNUM FP_REGNO yann@1: +#define RETURN_ADDRESS_POINTER_REGNUM RAP_REGNO yann@1: +/* the argumnet pointer needs to always be eliminated yann@1: + so it is set to a fake hard register. */ yann@1: +#define ARG_POINTER_REGNUM FAKE_AP_REGNO yann@1: + yann@1: +/* ----------------------------------------- * yann@1: + * Eliminating Frame Pointer and Arg Pointer yann@1: + * ----------------------------------------- */ yann@1: + yann@1: +#define FRAME_POINTER_REQUIRED 0 yann@1: + yann@1: +#define ELIMINABLE_REGS \ yann@1: +{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ yann@1: + { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \ yann@1: + { RETURN_ADDRESS_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ yann@1: + { RETURN_ADDRESS_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \ yann@1: + { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ yann@1: + { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}} yann@1: + yann@1: +#define CAN_ELIMINATE(FROM, TO) 1 yann@1: + yann@1: +#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ yann@1: + (OFFSET) = nios2_initial_elimination_offset ((FROM), (TO)) yann@1: + yann@1: +#define MUST_SAVE_REGISTER(regno) \ yann@1: + ((regs_ever_live[regno] && !call_used_regs[regno]) \ yann@1: + || (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed) \ yann@1: + || (regno == RA_REGNO && regs_ever_live[RA_REGNO])) yann@1: + yann@1: +/* Treat LOC as a byte offset from the stack pointer and round it up yann@1: + to the next fully-aligned offset. */ yann@1: +#define STACK_ALIGN(LOC) \ yann@1: + (((LOC) + ((PREFERRED_STACK_BOUNDARY / 8) - 1)) & ~((PREFERRED_STACK_BOUNDARY / 8) - 1)) yann@1: + yann@1: + yann@1: +/* ------------------------------ * yann@1: + * Passing Arguments in Registers yann@1: + * ------------------------------ */ yann@1: + yann@1: +/* see nios2.c */ yann@1: +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ yann@1: + (function_arg (&CUM, MODE, TYPE, NAMED)) yann@1: + yann@1: +#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \ yann@1: + (function_arg_partial_nregs (&CUM, MODE, TYPE, NAMED)) yann@1: + yann@1: +#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) 0 yann@1: + yann@1: +#define FUNCTION_ARG_CALLEE_COPIES(CUM, MODE, TYPE, NAMED) 0 yann@1: + yann@1: +typedef struct nios2_args yann@1: +{ yann@1: + int regs_used; yann@1: +} CUMULATIVE_ARGS; yann@1: + yann@1: +/* This is to initialize the above unused CUM data type */ yann@1: +#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS) \ yann@1: + (init_cumulative_args (&CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS)) yann@1: + yann@1: +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ yann@1: + (function_arg_advance (&CUM, MODE, TYPE, NAMED)) yann@1: + yann@1: +#define FUNCTION_ARG_REGNO_P(REGNO) \ yann@1: + ((REGNO) >= FIRST_ARG_REGNO && (REGNO) <= LAST_ARG_REGNO) yann@1: + yann@1: +#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \ yann@1: + { \ yann@1: + int pret_size = nios2_setup_incoming_varargs (&(CUM), (MODE), \ yann@1: + (TYPE), (NO_RTL)); \ yann@1: + if (pret_size) \ yann@1: + (PRETEND_SIZE) = pret_size; \ yann@1: + } yann@1: + yann@1: +/* ----------------------------- * yann@1: + * Generating Code for Profiling yann@1: + * ----------------------------- */ yann@1: + yann@1: +#define PROFILE_BEFORE_PROLOGUE yann@1: + yann@1: +#define FUNCTION_PROFILER(FILE, LABELNO) \ yann@1: + function_profiler ((FILE), (LABELNO)) yann@1: + yann@1: +/* --------------------------------------- * yann@1: + * Passing Function Arguments on the Stack yann@1: + * --------------------------------------- */ yann@1: + yann@1: +#define PROMOTE_PROTOTYPES 1 yann@1: + yann@1: +#define PUSH_ARGS 0 yann@1: +#define ACCUMULATE_OUTGOING_ARGS 1 yann@1: + yann@1: +#define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, STACKSIZE) 0 yann@1: + yann@1: +/* --------------------------------------- * yann@1: + * How Scalar Function Values Are Returned yann@1: + * --------------------------------------- */ yann@1: + yann@1: +#define FUNCTION_VALUE(VALTYPE, FUNC) \ yann@1: + gen_rtx(REG, TYPE_MODE(VALTYPE), FIRST_RETVAL_REGNO) yann@1: + yann@1: +#define LIBCALL_VALUE(MODE) \ yann@1: + gen_rtx(REG, MODE, FIRST_RETVAL_REGNO) yann@1: + yann@1: +#define FUNCTION_VALUE_REGNO_P(REGNO) ((REGNO) == FIRST_RETVAL_REGNO) yann@1: + yann@1: +/* ----------------------------- * yann@1: + * How Large Values Are Returned yann@1: + * ----------------------------- */ yann@1: + yann@1: + yann@1: +#define RETURN_IN_MEMORY(TYPE) \ yann@1: + nios2_return_in_memory (TYPE) yann@1: + yann@1: + yann@1: +#define STRUCT_VALUE 0 yann@1: + yann@1: +#define DEFAULT_PCC_STRUCT_RETURN 0 yann@1: + yann@1: +/******************* yann@1: + * Addressing Modes yann@1: + *******************/ yann@1: + yann@1: + yann@1: +#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) yann@1: + yann@1: +#define CONSTANT_ADDRESS_P(X) (CONSTANT_P (X)) yann@1: + yann@1: +#define MAX_REGS_PER_ADDRESS 1 yann@1: + yann@1: +/* Go to ADDR if X is a valid address. */ yann@1: +#ifndef REG_OK_STRICT yann@1: +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ yann@1: + { \ yann@1: + if (nios2_legitimate_address ((X), (MODE), 0)) \ yann@1: + goto ADDR; \ yann@1: + } yann@1: +#else yann@1: +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ yann@1: + { \ yann@1: + if (nios2_legitimate_address ((X), (MODE), 1)) \ yann@1: + goto ADDR; \ yann@1: + } yann@1: +#endif yann@1: + yann@1: +#ifndef REG_OK_STRICT yann@1: +#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P2 (REGNO (X), 0) yann@1: +#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P2 (REGNO (X), 0) yann@1: +#else yann@1: +#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P2 (REGNO (X), 1) yann@1: +#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P2 (REGNO (X), 1) yann@1: +#endif yann@1: + yann@1: +#define LEGITIMATE_CONSTANT_P(X) 1 yann@1: + yann@1: +/* Nios II has no mode dependent addresses. */ yann@1: +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) yann@1: + yann@1: +/* Set if this has a weak declaration */ yann@1: +#define SYMBOL_FLAG_WEAK_DECL (1 << SYMBOL_FLAG_MACH_DEP_SHIFT) yann@1: +#define SYMBOL_REF_WEAK_DECL_P(RTX) \ yann@1: + ((SYMBOL_REF_FLAGS (RTX) & SYMBOL_FLAG_WEAK_DECL) != 0) yann@1: + yann@1: + yann@1: +/* true if a symbol is both small and not weak. In this case, gp yann@1: + relative access can be used */ yann@1: +#define SYMBOL_REF_IN_NIOS2_SMALL_DATA_P(RTX) \ yann@1: + (SYMBOL_REF_SMALL_P(RTX) && !SYMBOL_REF_WEAK_DECL_P(RTX)) yann@1: + yann@1: +/***************** yann@1: + * Describing Relative Costs of Operations yann@1: + *****************/ yann@1: + yann@1: +#define SLOW_BYTE_ACCESS 1 yann@1: + yann@1: +/* It is as good to call a constant function address as to call an address yann@1: + kept in a register. yann@1: + ??? Not true anymore really. Now that call cannot address full range yann@1: + of memory callr may need to be used */ yann@1: + yann@1: +#define NO_FUNCTION_CSE yann@1: +#define NO_RECURSIVE_FUNCTION_CSE yann@1: + yann@1: + yann@1: + yann@1: +/***************************************** yann@1: + * Defining the Output Assembler Language yann@1: + *****************************************/ yann@1: + yann@1: +/* ------------------------------------------ * yann@1: + * The Overall Framework of an Assembler File yann@1: + * ------------------------------------------ */ yann@1: + yann@1: +#define ASM_APP_ON "#APP\n" yann@1: +#define ASM_APP_OFF "#NO_APP\n" yann@1: + yann@1: +#define ASM_COMMENT_START "# " yann@1: + yann@1: +/* ------------------------------- * yann@1: + * Output and Generation of Labels yann@1: + * ------------------------------- */ yann@1: + yann@1: +#define GLOBAL_ASM_OP "\t.global\t" yann@1: + yann@1: + yann@1: +/* -------------- * yann@1: + * Output of Data yann@1: + * -------------- */ yann@1: + yann@1: +#define DWARF2_UNWIND_INFO 0 yann@1: + yann@1: + yann@1: +/* -------------------------------- * yann@1: + * Assembler Commands for Alignment yann@1: + * -------------------------------- */ yann@1: + yann@1: +#define ASM_OUTPUT_ALIGN(FILE, LOG) \ yann@1: + do { \ yann@1: + fprintf ((FILE), "%s%d\n", ALIGN_ASM_OP, (LOG)); \ yann@1: + } while (0) yann@1: + yann@1: + yann@1: +/* -------------------------------- * yann@1: + * Output of Assembler Instructions yann@1: + * -------------------------------- */ yann@1: + yann@1: +#define REGISTER_NAMES \ yann@1: +{ \ yann@1: + "zero", \ yann@1: + "at", \ yann@1: + "r2", \ yann@1: + "r3", \ yann@1: + "r4", \ yann@1: + "r5", \ yann@1: + "r6", \ yann@1: + "r7", \ yann@1: + "r8", \ yann@1: + "r9", \ yann@1: + "r10", \ yann@1: + "r11", \ yann@1: + "r12", \ yann@1: + "r13", \ yann@1: + "r14", \ yann@1: + "r15", \ yann@1: + "r16", \ yann@1: + "r17", \ yann@1: + "r18", \ yann@1: + "r19", \ yann@1: + "r20", \ yann@1: + "r21", \ yann@1: + "r22", \ yann@1: + "r23", \ yann@1: + "r24", \ yann@1: + "r25", \ yann@1: + "gp", \ yann@1: + "sp", \ yann@1: + "fp", \ yann@1: + "ta", \ yann@1: + "ba", \ yann@1: + "ra", \ yann@1: + "status", \ yann@1: + "estatus", \ yann@1: + "bstatus", \ yann@1: + "ipri", \ yann@1: + "ecause", \ yann@1: + "pc", \ yann@1: + "rap", \ yann@1: + "fake_fp", \ yann@1: + "fake_ap", \ yann@1: +} yann@1: + yann@1: +#define ASM_OUTPUT_OPCODE(STREAM, PTR)\ yann@1: + (PTR) = asm_output_opcode (STREAM, PTR) yann@1: + yann@1: +#define PRINT_OPERAND(STREAM, X, CODE) \ yann@1: + nios2_print_operand (STREAM, X, CODE) yann@1: + yann@1: +#define PRINT_OPERAND_ADDRESS(STREAM, X) \ yann@1: + nios2_print_operand_address (STREAM, X) yann@1: + yann@1: +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ yann@1: +do { fputs (integer_asm_op (POINTER_SIZE / BITS_PER_UNIT, TRUE), FILE); \ yann@1: + fprintf (FILE, ".L%u\n", (unsigned) (VALUE)); \ yann@1: + } while (0) yann@1: + yann@1: + yann@1: +/* ------------ * yann@1: + * Label Output yann@1: + * ------------ */ yann@1: + yann@1: + yann@1: +/* ---------------------------------------------------- * yann@1: + * Dividing the Output into Sections (Texts, Data, ...) yann@1: + * ---------------------------------------------------- */ yann@1: + yann@1: +/* Output before read-only data. */ yann@1: +#define TEXT_SECTION_ASM_OP ("\t.section\t.text") yann@1: + yann@1: +/* Output before writable data. */ yann@1: +#define DATA_SECTION_ASM_OP ("\t.section\t.data") yann@1: + yann@1: + yann@1: +/* Default the definition of "small data" to 8 bytes. */ yann@1: +/* ??? How come I can't use HOST_WIDE_INT here? */ yann@1: +extern unsigned long nios2_section_threshold; yann@1: +#define NIOS2_DEFAULT_GVALUE 8 yann@1: + yann@1: + yann@1: + yann@1: +/* This says how to output assembler code to declare an yann@1: + uninitialized external linkage data object. Under SVR4, yann@1: + the linker seems to want the alignment of data objects yann@1: + to depend on their types. We do exactly that here. */ yann@1: + yann@1: +#undef COMMON_ASM_OP yann@1: +#define COMMON_ASM_OP "\t.comm\t" yann@1: + yann@1: +#undef ASM_OUTPUT_ALIGNED_COMMON yann@1: +#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \ yann@1: +do \ yann@1: +{ \ yann@1: + if ((SIZE) <= nios2_section_threshold) \ yann@1: + { \ yann@1: + named_section (0, ".sbss", 0); \ yann@1: + (*targetm.asm_out.globalize_label) (FILE, NAME); \ yann@1: + ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object"); \ yann@1: + if (!flag_inhibit_size_directive) \ yann@1: + ASM_OUTPUT_SIZE_DIRECTIVE (FILE, NAME, SIZE); \ yann@1: + ASM_OUTPUT_ALIGN ((FILE), exact_log2((ALIGN) / BITS_PER_UNIT)); \ yann@1: + ASM_OUTPUT_LABEL(FILE, NAME); \ yann@1: + ASM_OUTPUT_SKIP((FILE), (SIZE) ? (SIZE) : 1); \ yann@1: + } \ yann@1: + else \ yann@1: + { \ yann@1: + fprintf ((FILE), "%s", COMMON_ASM_OP); \ yann@1: + assemble_name ((FILE), (NAME)); \ yann@1: + fprintf ((FILE), ","HOST_WIDE_INT_PRINT_UNSIGNED",%u\n", (SIZE), (ALIGN) / BITS_PER_UNIT); \ yann@1: + } \ yann@1: +} \ yann@1: +while (0) yann@1: + yann@1: + yann@1: +/* This says how to output assembler code to declare an yann@1: + uninitialized internal linkage data object. Under SVR4, yann@1: + the linker seems to want the alignment of data objects yann@1: + to depend on their types. We do exactly that here. */ yann@1: + yann@1: +#undef ASM_OUTPUT_ALIGNED_LOCAL yann@1: +#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \ yann@1: +do { \ yann@1: + if ((SIZE) <= nios2_section_threshold) \ yann@1: + named_section (0, ".sbss", 0); \ yann@1: + else \ yann@1: + named_section (0, ".bss", 0); \ yann@1: + ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object"); \ yann@1: + if (!flag_inhibit_size_directive) \ yann@1: + ASM_OUTPUT_SIZE_DIRECTIVE (FILE, NAME, SIZE); \ yann@1: + ASM_OUTPUT_ALIGN ((FILE), exact_log2((ALIGN) / BITS_PER_UNIT)); \ yann@1: + ASM_OUTPUT_LABEL(FILE, NAME); \ yann@1: + ASM_OUTPUT_SKIP((FILE), (SIZE) ? (SIZE) : 1); \ yann@1: +} while (0) yann@1: + yann@1: + yann@1: + yann@1: +/*************************** yann@1: + * Miscellaneous Parameters yann@1: + ***************************/ yann@1: + yann@1: +#define MOVE_MAX 4 yann@1: + yann@1: +#define Pmode SImode yann@1: +#define FUNCTION_MODE QImode yann@1: + yann@1: +#define CASE_VECTOR_MODE Pmode yann@1: + yann@1: +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 yann@1: + yann@1: +#define LOAD_EXTEND_OP(MODE) (ZERO_EXTEND) yann@1: + yann@1: +#define WORD_REGISTER_OPERATIONS yann@1: --- gcc-3.4.3/gcc/config/nios2/nios2.md yann@1: +++ gcc-3.4.3-nios2/gcc/config/nios2/nios2.md yann@1: @@ -0,0 +1,2078 @@ yann@1: +;; Machine Description for Altera NIOS 2G NIOS2 version. yann@1: +;; Copyright (C) 2003 Altera yann@1: +;; Contributed by Jonah Graham (jgraham@altera.com). yann@1: +;; yann@1: +;; This file is part of GNU CC. yann@1: +;; yann@1: +;; GNU CC is free software; you can redistribute it and/or modify yann@1: +;; it under the terms of the GNU General Public License as published by yann@1: +;; the Free Software Foundation; either version 2, or (at your option) yann@1: +;; any later version. yann@1: +;; yann@1: +;; GNU CC is distributed in the hope that it will be useful, yann@1: +;; but WITHOUT ANY WARRANTY; without even the implied warranty of yann@1: +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the yann@1: +;; GNU General Public License for more details. yann@1: +;; yann@1: +;; You should have received a copy of the GNU General Public License yann@1: +;; along with GNU CC; see the file COPYING. If not, write to yann@1: +;; the Free Software Foundation, 59 Temple Place - Suite 330, yann@1: +;; Boston, MA 02111-1307, USA. */ yann@1: + yann@1: + yann@1: + yann@1: +;***************************************************************************** yann@1: +;* yann@1: +;* constants yann@1: +;* yann@1: +;***************************************************************************** yann@1: +(define_constants [ yann@1: + (GP_REGNO 26) yann@1: + (SP_REGNO 27) yann@1: + (FP_REGNO 28) yann@1: + (RA_REGNO 31) yann@1: + (RAP_REGNO 38) yann@1: + (FIRST_RETVAL_REGNO 2) yann@1: + (LAST_RETVAL_REGNO 3) yann@1: + (FIRST_ARG_REGNO 4) yann@1: + (LAST_ARG_REGNO 7) yann@1: + (SC_REGNO 23) yann@1: + (PC_REGNO 37) yann@1: + (FAKE_FP_REGNO 39) yann@1: + (FAKE_AP_REGNO 40) yann@1: + yann@1: + yann@1: + (UNSPEC_BLOCKAGE 0) yann@1: + (UNSPEC_LDBIO 1) yann@1: + (UNSPEC_LDBUIO 2) yann@1: + (UNSPEC_LDHIO 3) yann@1: + (UNSPEC_LDHUIO 4) yann@1: + (UNSPEC_LDWIO 5) yann@1: + (UNSPEC_STBIO 6) yann@1: + (UNSPEC_STHIO 7) yann@1: + (UNSPEC_STWIO 8) yann@1: + (UNSPEC_SYNC 9) yann@1: + (UNSPEC_WRCTL 10) yann@1: + (UNSPEC_RDCTL 11) yann@1: + yann@1: +]) yann@1: + yann@1: + yann@1: + yann@1: +;***************************************************************************** yann@1: +;* yann@1: +;* instruction scheduler yann@1: +;* yann@1: +;***************************************************************************** yann@1: + yann@1: +; No schedule info is currently available, using an assumption that no yann@1: +; instruction can use the results of the previous instruction without yann@1: +; incuring a stall. yann@1: + yann@1: +; length of an instruction (in bytes) yann@1: +(define_attr "length" "" (const_int 4)) yann@1: +(define_attr "type" "unknown,complex,control,alu,cond_alu,st,ld,shift,mul,div,custom" (const_string "complex")) yann@1: + yann@1: +(define_asm_attributes yann@1: + [(set_attr "length" "4") yann@1: + (set_attr "type" "complex")]) yann@1: + yann@1: +(define_automaton "nios2") yann@1: +(automata_option "v") yann@1: +;(automata_option "no-minimization") yann@1: +(automata_option "ndfa") yann@1: + yann@1: +; The nios2 pipeline is fairly straightforward for the fast model. yann@1: +; Every alu operation is pipelined so that an instruction can yann@1: +; be issued every cycle. However, there are still potential yann@1: +; stalls which this description tries to deal with. yann@1: + yann@1: +(define_cpu_unit "cpu" "nios2") yann@1: + yann@1: +(define_insn_reservation "complex" 1 yann@1: + (eq_attr "type" "complex") yann@1: + "cpu") yann@1: + yann@1: +(define_insn_reservation "control" 1 yann@1: + (eq_attr "type" "control") yann@1: + "cpu") yann@1: + yann@1: +(define_insn_reservation "alu" 1 yann@1: + (eq_attr "type" "alu") yann@1: + "cpu") yann@1: + yann@1: +(define_insn_reservation "cond_alu" 1 yann@1: + (eq_attr "type" "cond_alu") yann@1: + "cpu") yann@1: + yann@1: +(define_insn_reservation "st" 1 yann@1: + (eq_attr "type" "st") yann@1: + "cpu") yann@1: + yann@1: +(define_insn_reservation "custom" 1 yann@1: + (eq_attr "type" "custom") yann@1: + "cpu") yann@1: + yann@1: +; shifts, muls and lds have three cycle latency yann@1: +(define_insn_reservation "ld" 3 yann@1: + (eq_attr "type" "ld") yann@1: + "cpu") yann@1: + yann@1: +(define_insn_reservation "shift" 3 yann@1: + (eq_attr "type" "shift") yann@1: + "cpu") yann@1: + yann@1: +(define_insn_reservation "mul" 3 yann@1: + (eq_attr "type" "mul") yann@1: + "cpu") yann@1: + yann@1: +(define_insn_reservation "div" 1 yann@1: + (eq_attr "type" "div") yann@1: + "cpu") yann@1: + yann@1: + yann@1: +;***************************************************************************** yann@1: +;* yann@1: +;* MOV Instructions yann@1: +;* yann@1: +;***************************************************************************** yann@1: + yann@1: +(define_expand "movqi" yann@1: + [(set (match_operand:QI 0 "nonimmediate_operand" "") yann@1: + (match_operand:QI 1 "general_operand" ""))] yann@1: + "" yann@1: +{ yann@1: + if (nios2_emit_move_sequence (operands, QImode)) yann@1: + DONE; yann@1: +}) yann@1: + yann@1: +(define_insn "movqi_internal" yann@1: + [(set (match_operand:QI 0 "nonimmediate_operand" "=m, r,r, r") yann@1: + (match_operand:QI 1 "general_operand" "rM,m,rM,I"))] yann@1: + "(register_operand (operands[0], QImode) yann@1: + || register_operand (operands[1], QImode) yann@1: + || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))" yann@1: + "@ yann@1: + stb%o0\\t%z1, %0 yann@1: + ldbu%o1\\t%0, %1 yann@1: + mov\\t%0, %z1 yann@1: + movi\\t%0, %1" yann@1: + [(set_attr "type" "st,ld,alu,alu")]) yann@1: + yann@1: +(define_insn "ldbio" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (unspec_volatile:SI [(const_int 0)] UNSPEC_LDBIO)) yann@1: + (use (match_operand:SI 1 "memory_operand" "m"))] yann@1: + "" yann@1: + "ldbio\\t%0, %1" yann@1: + [(set_attr "type" "ld")]) yann@1: + yann@1: +(define_insn "ldbuio" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (unspec_volatile:SI [(const_int 0)] UNSPEC_LDBUIO)) yann@1: + (use (match_operand:SI 1 "memory_operand" "m"))] yann@1: + "" yann@1: + "ldbuio\\t%0, %1" yann@1: + [(set_attr "type" "ld")]) yann@1: + yann@1: +(define_insn "stbio" yann@1: + [(set (match_operand:SI 0 "memory_operand" "=m") yann@1: + (match_operand:SI 1 "register_operand" "r")) yann@1: + (unspec_volatile:SI [(const_int 0)] UNSPEC_STBIO)] yann@1: + "" yann@1: + "stbio\\t%z1, %0" yann@1: + [(set_attr "type" "st")]) yann@1: + yann@1: + yann@1: +(define_expand "movhi" yann@1: + [(set (match_operand:HI 0 "nonimmediate_operand" "") yann@1: + (match_operand:HI 1 "general_operand" ""))] yann@1: + "" yann@1: +{ yann@1: + if (nios2_emit_move_sequence (operands, HImode)) yann@1: + DONE; yann@1: +}) yann@1: + yann@1: +(define_insn "movhi_internal" yann@1: + [(set (match_operand:HI 0 "nonimmediate_operand" "=m, r,r, r,r") yann@1: + (match_operand:HI 1 "general_operand" "rM,m,rM,I,J"))] yann@1: + "(register_operand (operands[0], HImode) yann@1: + || register_operand (operands[1], HImode) yann@1: + || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))" yann@1: + "@ yann@1: + sth%o0\\t%z1, %0 yann@1: + ldhu%o1\\t%0, %1 yann@1: + mov\\t%0, %z1 yann@1: + movi\\t%0, %1 yann@1: + movui\\t%0, %1" yann@1: + [(set_attr "type" "st,ld,alu,alu,alu")]) yann@1: + yann@1: +(define_insn "ldhio" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (unspec_volatile:SI [(const_int 0)] UNSPEC_LDHIO)) yann@1: + (use (match_operand:SI 1 "memory_operand" "m"))] yann@1: + "" yann@1: + "ldhio\\t%0, %1" yann@1: + [(set_attr "type" "ld")]) yann@1: + yann@1: +(define_insn "ldhuio" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (unspec_volatile:SI [(const_int 0)] UNSPEC_LDHUIO)) yann@1: + (use (match_operand:SI 1 "memory_operand" "m"))] yann@1: + "" yann@1: + "ldhuio\\t%0, %1" yann@1: + [(set_attr "type" "ld")]) yann@1: + yann@1: +(define_insn "sthio" yann@1: + [(set (match_operand:SI 0 "memory_operand" "=m") yann@1: + (match_operand:SI 1 "register_operand" "r")) yann@1: + (unspec_volatile:SI [(const_int 0)] UNSPEC_STHIO)] yann@1: + "" yann@1: + "sthio\\t%z1, %0" yann@1: + [(set_attr "type" "st")]) yann@1: + yann@1: +(define_expand "movsi" yann@1: + [(set (match_operand:SI 0 "nonimmediate_operand" "") yann@1: + (match_operand:SI 1 "general_operand" ""))] yann@1: + "" yann@1: +{ yann@1: + if (nios2_emit_move_sequence (operands, SImode)) yann@1: + DONE; yann@1: +}) yann@1: + yann@1: +(define_insn "movsi_internal" yann@1: + [(set (match_operand:SI 0 "nonimmediate_operand" "=m, r,r, r,r,r,r") yann@1: + (match_operand:SI 1 "general_operand" "rM,m,rM,I,J,S,i"))] yann@1: + "(register_operand (operands[0], SImode) yann@1: + || register_operand (operands[1], SImode) yann@1: + || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))" yann@1: + "@ yann@1: + stw%o0\\t%z1, %0 yann@1: + ldw%o1\\t%0, %1 yann@1: + mov\\t%0, %z1 yann@1: + movi\\t%0, %1 yann@1: + movui\\t%0, %1 yann@1: + addi\\t%0, gp, %%gprel(%1) yann@1: + movhi\\t%0, %H1\;addi\\t%0, %0, %L1" yann@1: + [(set_attr "type" "st,ld,alu,alu,alu,alu,alu")]) yann@1: + yann@1: +(define_insn "ldwio" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (unspec_volatile:SI [(const_int 0)] UNSPEC_LDWIO)) yann@1: + (use (match_operand:SI 1 "memory_operand" "m"))] yann@1: + "" yann@1: + "ldwio\\t%0, %1" yann@1: + [(set_attr "type" "ld")]) yann@1: + yann@1: +(define_insn "stwio" yann@1: + [(set (match_operand:SI 0 "memory_operand" "=m") yann@1: + (match_operand:SI 1 "register_operand" "r")) yann@1: + (unspec_volatile:SI [(const_int 0)] UNSPEC_STWIO)] yann@1: + "" yann@1: + "stwio\\t%z1, %0" yann@1: + [(set_attr "type" "st")]) yann@1: + yann@1: + yann@1: + yann@1: +;***************************************************************************** yann@1: +;* yann@1: +;* zero extension yann@1: +;* yann@1: +;***************************************************************************** yann@1: + yann@1: + yann@1: +(define_insn "zero_extendhisi2" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r,r") yann@1: + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))] yann@1: + "" yann@1: + "@ yann@1: + andi\\t%0, %1, 0xffff yann@1: + ldhu%o1\\t%0, %1" yann@1: + [(set_attr "type" "alu,ld")]) yann@1: + yann@1: +(define_insn "zero_extendqihi2" yann@1: + [(set (match_operand:HI 0 "register_operand" "=r,r") yann@1: + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "r,m")))] yann@1: + "" yann@1: + "@ yann@1: + andi\\t%0, %1, 0xff yann@1: + ldbu%o1\\t%0, %1" yann@1: + [(set_attr "type" "alu,ld")]) yann@1: + yann@1: +(define_insn "zero_extendqisi2" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r,r") yann@1: + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,m")))] yann@1: + "" yann@1: + "@ yann@1: + andi\\t%0, %1, 0xff yann@1: + ldbu%o1\\t%0, %1" yann@1: + [(set_attr "type" "alu,ld")]) yann@1: + yann@1: + yann@1: + yann@1: +;***************************************************************************** yann@1: +;* yann@1: +;* sign extension yann@1: +;* yann@1: +;***************************************************************************** yann@1: + yann@1: +(define_expand "extendhisi2" yann@1: + [(set (match_operand:SI 0 "register_operand" "") yann@1: + (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] yann@1: + "" yann@1: +{ yann@1: + if (optimize && GET_CODE (operands[1]) == MEM) yann@1: + operands[1] = force_not_mem (operands[1]); yann@1: + yann@1: + if (GET_CODE (operands[1]) != MEM) yann@1: + { yann@1: + rtx op1 = gen_lowpart (SImode, operands[1]); yann@1: + rtx temp = gen_reg_rtx (SImode); yann@1: + rtx shift = GEN_INT (16); yann@1: + yann@1: + emit_insn (gen_ashlsi3 (temp, op1, shift)); yann@1: + emit_insn (gen_ashrsi3 (operands[0], temp, shift)); yann@1: + DONE; yann@1: + } yann@1: +}) yann@1: + yann@1: +(define_insn "extendhisi2_internal" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))] yann@1: + "" yann@1: + "ldh%o1\\t%0, %1" yann@1: + [(set_attr "type" "ld")]) yann@1: + yann@1: +(define_expand "extendqihi2" yann@1: + [(set (match_operand:HI 0 "register_operand" "") yann@1: + (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))] yann@1: + "" yann@1: +{ yann@1: + if (optimize && GET_CODE (operands[1]) == MEM) yann@1: + operands[1] = force_not_mem (operands[1]); yann@1: + yann@1: + if (GET_CODE (operands[1]) != MEM) yann@1: + { yann@1: + rtx op0 = gen_lowpart (SImode, operands[0]); yann@1: + rtx op1 = gen_lowpart (SImode, operands[1]); yann@1: + rtx temp = gen_reg_rtx (SImode); yann@1: + rtx shift = GEN_INT (24); yann@1: + yann@1: + emit_insn (gen_ashlsi3 (temp, op1, shift)); yann@1: + emit_insn (gen_ashrsi3 (op0, temp, shift)); yann@1: + DONE; yann@1: + } yann@1: +}) yann@1: + yann@1: +(define_insn "extendqihi2_internal" yann@1: + [(set (match_operand:HI 0 "register_operand" "=r") yann@1: + (sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))] yann@1: + "" yann@1: + "ldb%o1\\t%0, %1" yann@1: + [(set_attr "type" "ld")]) yann@1: + yann@1: + yann@1: +(define_expand "extendqisi2" yann@1: + [(set (match_operand:SI 0 "register_operand" "") yann@1: + (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] yann@1: + "" yann@1: +{ yann@1: + if (optimize && GET_CODE (operands[1]) == MEM) yann@1: + operands[1] = force_not_mem (operands[1]); yann@1: + yann@1: + if (GET_CODE (operands[1]) != MEM) yann@1: + { yann@1: + rtx op1 = gen_lowpart (SImode, operands[1]); yann@1: + rtx temp = gen_reg_rtx (SImode); yann@1: + rtx shift = GEN_INT (24); yann@1: + yann@1: + emit_insn (gen_ashlsi3 (temp, op1, shift)); yann@1: + emit_insn (gen_ashrsi3 (operands[0], temp, shift)); yann@1: + DONE; yann@1: + } yann@1: +}) yann@1: + yann@1: +(define_insn "extendqisi2_insn" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))] yann@1: + "" yann@1: + "ldb%o1\\t%0, %1" yann@1: + [(set_attr "type" "ld")]) yann@1: + yann@1: + yann@1: + yann@1: +;***************************************************************************** yann@1: +;* yann@1: +;* Arithmetic Operations yann@1: +;* yann@1: +;***************************************************************************** yann@1: + yann@1: +(define_insn "addsi3" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r,r") yann@1: + (plus:SI (match_operand:SI 1 "register_operand" "%r,r") yann@1: + (match_operand:SI 2 "arith_operand" "r,I")))] yann@1: + "" yann@1: + "add%i2\\t%0, %1, %z2" yann@1: + [(set_attr "type" "alu")]) yann@1: + yann@1: +(define_insn "subsi3" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rM") yann@1: + (match_operand:SI 2 "register_operand" "r")))] yann@1: + "" yann@1: + "sub\\t%0, %z1, %2" yann@1: + [(set_attr "type" "alu")]) yann@1: + yann@1: +(define_insn "mulsi3" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r,r") yann@1: + (mult:SI (match_operand:SI 1 "register_operand" "r,r") yann@1: + (match_operand:SI 2 "arith_operand" "r,I")))] yann@1: + "TARGET_HAS_MUL" yann@1: + "mul%i2\\t%0, %1, %z2" yann@1: + [(set_attr "type" "mul")]) yann@1: + yann@1: +(define_expand "divsi3" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (div:SI (match_operand:SI 1 "register_operand" "r") yann@1: + (match_operand:SI 2 "register_operand" "r")))] yann@1: + "" yann@1: +{ yann@1: + if (!TARGET_HAS_DIV) yann@1: + { yann@1: + if (!TARGET_FAST_SW_DIV) yann@1: + FAIL; yann@1: + else yann@1: + { yann@1: + if (nios2_emit_expensive_div (operands, SImode)) yann@1: + DONE; yann@1: + } yann@1: + } yann@1: +}) yann@1: + yann@1: +(define_insn "divsi3_insn" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (div:SI (match_operand:SI 1 "register_operand" "r") yann@1: + (match_operand:SI 2 "register_operand" "r")))] yann@1: + "TARGET_HAS_DIV" yann@1: + "div\\t%0, %1, %2" yann@1: + [(set_attr "type" "div")]) yann@1: + yann@1: +(define_insn "udivsi3" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (udiv:SI (match_operand:SI 1 "register_operand" "r") yann@1: + (match_operand:SI 2 "register_operand" "r")))] yann@1: + "TARGET_HAS_DIV" yann@1: + "divu\\t%0, %1, %2" yann@1: + [(set_attr "type" "div")]) yann@1: + yann@1: +(define_insn "smulsi3_highpart" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (truncate:SI yann@1: + (lshiftrt:DI yann@1: + (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r")) yann@1: + (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))) yann@1: + (const_int 32))))] yann@1: + "TARGET_HAS_MULX" yann@1: + "mulxss\\t%0, %1, %2" yann@1: + [(set_attr "type" "mul")]) yann@1: + yann@1: +(define_insn "umulsi3_highpart" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (truncate:SI yann@1: + (lshiftrt:DI yann@1: + (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r")) yann@1: + (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))) yann@1: + (const_int 32))))] yann@1: + "TARGET_HAS_MULX" yann@1: + "mulxuu\\t%0, %1, %2" yann@1: + [(set_attr "type" "mul")]) yann@1: + yann@1: + yann@1: +(define_expand "mulsidi3" yann@1: + [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 0) yann@1: + (mult:SI (match_operand:SI 1 "register_operand" "") yann@1: + (match_operand:SI 2 "register_operand" ""))) yann@1: + (set (subreg:SI (match_dup 0) 4) yann@1: + (truncate:SI (lshiftrt:DI (mult:DI (sign_extend:DI (match_dup 1)) yann@1: + (sign_extend:DI (match_dup 2))) yann@1: + (const_int 32))))] yann@1: + "TARGET_HAS_MULX" yann@1: + "") yann@1: + yann@1: +(define_expand "umulsidi3" yann@1: + [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 0) yann@1: + (mult:SI (match_operand:SI 1 "register_operand" "") yann@1: + (match_operand:SI 2 "register_operand" ""))) yann@1: + (set (subreg:SI (match_dup 0) 4) yann@1: + (truncate:SI (lshiftrt:DI (mult:DI (zero_extend:DI (match_dup 1)) yann@1: + (zero_extend:DI (match_dup 2))) yann@1: + (const_int 32))))] yann@1: + "TARGET_HAS_MULX" yann@1: + "") yann@1: + yann@1: + yann@1: + yann@1: +;***************************************************************************** yann@1: +;* yann@1: +;* Negate and ones complement yann@1: +;* yann@1: +;***************************************************************************** yann@1: + yann@1: +(define_insn "negsi2" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (neg:SI (match_operand:SI 1 "register_operand" "r")))] yann@1: + "" yann@1: +{ yann@1: + operands[2] = const0_rtx; yann@1: + return "sub\\t%0, %z2, %1"; yann@1: +} yann@1: + [(set_attr "type" "alu")]) yann@1: + yann@1: +(define_insn "one_cmplsi2" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (not:SI (match_operand:SI 1 "register_operand" "r")))] yann@1: + "" yann@1: +{ yann@1: + operands[2] = const0_rtx; yann@1: + return "nor\\t%0, %z2, %1"; yann@1: +} yann@1: + [(set_attr "type" "alu")]) yann@1: + yann@1: + yann@1: + yann@1: +; Logical Operantions yann@1: + yann@1: +(define_insn "andsi3" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r, r,r") yann@1: + (and:SI (match_operand:SI 1 "register_operand" "%r, r,r") yann@1: + (match_operand:SI 2 "logical_operand" "rM,J,K")))] yann@1: + "" yann@1: + "@ yann@1: + and\\t%0, %1, %z2 yann@1: + and%i2\\t%0, %1, %2 yann@1: + andh%i2\\t%0, %1, %U2" yann@1: + [(set_attr "type" "alu")]) yann@1: + yann@1: +(define_insn "iorsi3" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r, r,r") yann@1: + (ior:SI (match_operand:SI 1 "register_operand" "%r, r,r") yann@1: + (match_operand:SI 2 "logical_operand" "rM,J,K")))] yann@1: + "" yann@1: + "@ yann@1: + or\\t%0, %1, %z2 yann@1: + or%i2\\t%0, %1, %2 yann@1: + orh%i2\\t%0, %1, %U2" yann@1: + [(set_attr "type" "alu")]) yann@1: + yann@1: +(define_insn "*norsi3" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (and:SI (not:SI (match_operand:SI 1 "register_operand" "%r")) yann@1: + (not:SI (match_operand:SI 2 "reg_or_0_operand" "rM"))))] yann@1: + "" yann@1: + "nor\\t%0, %1, %z2" yann@1: + [(set_attr "type" "alu")]) yann@1: + yann@1: +(define_insn "xorsi3" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r, r,r") yann@1: + (xor:SI (match_operand:SI 1 "register_operand" "%r, r,r") yann@1: + (match_operand:SI 2 "logical_operand" "rM,J,K")))] yann@1: + "" yann@1: + "@ yann@1: + xor\\t%0, %1, %z2 yann@1: + xor%i2\\t%0, %1, %2 yann@1: + xorh%i2\\t%0, %1, %U2" yann@1: + [(set_attr "type" "alu")]) yann@1: + yann@1: + yann@1: + yann@1: +;***************************************************************************** yann@1: +;* yann@1: +;* Shifts yann@1: +;* yann@1: +;***************************************************************************** yann@1: + yann@1: +(define_insn "ashlsi3" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r,r") yann@1: + (ashift:SI (match_operand:SI 1 "register_operand" "r,r") yann@1: + (match_operand:SI 2 "shift_operand" "r,L")))] yann@1: + "" yann@1: + "sll%i2\\t%0, %1, %z2" yann@1: + [(set_attr "type" "shift")]) yann@1: + yann@1: +(define_insn "ashrsi3" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r,r") yann@1: + (ashiftrt:SI (match_operand:SI 1 "register_operand" "r,r") yann@1: + (match_operand:SI 2 "shift_operand" "r,L")))] yann@1: + "" yann@1: + "sra%i2\\t%0, %1, %z2" yann@1: + [(set_attr "type" "shift")]) yann@1: + yann@1: +(define_insn "lshrsi3" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r,r") yann@1: + (lshiftrt:SI (match_operand:SI 1 "register_operand" "r,r") yann@1: + (match_operand:SI 2 "shift_operand" "r,L")))] yann@1: + "" yann@1: + "srl%i2\\t%0, %1, %z2" yann@1: + [(set_attr "type" "shift")]) yann@1: + yann@1: +(define_insn "rotlsi3" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r,r") yann@1: + (rotate:SI (match_operand:SI 1 "register_operand" "r,r") yann@1: + (match_operand:SI 2 "shift_operand" "r,L")))] yann@1: + "" yann@1: + "rol%i2\\t%0, %1, %z2" yann@1: + [(set_attr "type" "shift")]) yann@1: + yann@1: +(define_insn "rotrsi3" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r,r") yann@1: + (rotatert:SI (match_operand:SI 1 "register_operand" "r,r") yann@1: + (match_operand:SI 2 "register_operand" "r,r")))] yann@1: + "" yann@1: + "ror\\t%0, %1, %2" yann@1: + [(set_attr "type" "shift")]) yann@1: + yann@1: +(define_insn "*shift_mul_constants" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (ashift:SI (mult:SI (match_operand:SI 1 "register_operand" "r") yann@1: + (match_operand:SI 2 "const_int_operand" "I")) yann@1: + (match_operand:SI 3 "const_int_operand" "I")))] yann@1: + "TARGET_HAS_MUL && SMALL_INT (INTVAL (operands[2]) << INTVAL (operands[3]))" yann@1: +{ yann@1: + HOST_WIDE_INT mul = INTVAL (operands[2]) << INTVAL (operands[3]); yann@1: + rtx ops[3]; yann@1: + yann@1: + ops[0] = operands[0]; yann@1: + ops[1] = operands[1]; yann@1: + ops[2] = GEN_INT (mul); yann@1: + yann@1: + output_asm_insn ("muli\t%0, %1, %2", ops); yann@1: + return ""; yann@1: +} yann@1: + [(set_attr "type" "mul")]) yann@1: + yann@1: + yann@1: + yann@1: + yann@1: +;***************************************************************************** yann@1: +;* yann@1: +;* Prologue, Epilogue and Return yann@1: +;* yann@1: +;***************************************************************************** yann@1: + yann@1: +(define_expand "prologue" yann@1: + [(const_int 1)] yann@1: + "" yann@1: +{ yann@1: + expand_prologue (); yann@1: + DONE; yann@1: +}) yann@1: + yann@1: +(define_expand "epilogue" yann@1: + [(return)] yann@1: + "" yann@1: +{ yann@1: + expand_epilogue (false); yann@1: + DONE; yann@1: +}) yann@1: + yann@1: +(define_expand "sibcall_epilogue" yann@1: + [(return)] yann@1: + "" yann@1: +{ yann@1: + expand_epilogue (true); yann@1: + DONE; yann@1: +}) yann@1: + yann@1: +(define_insn "return" yann@1: + [(return)] yann@1: + "reload_completed && nios2_can_use_return_insn ()" yann@1: + "ret\\t" yann@1: +) yann@1: + yann@1: +(define_insn "return_from_epilogue" yann@1: + [(use (match_operand 0 "pmode_register_operand" "")) yann@1: + (return)] yann@1: + "reload_completed" yann@1: + "ret\\t" yann@1: +) yann@1: + yann@1: +;; Block any insns from being moved before this point, since the yann@1: +;; profiling call to mcount can use various registers that aren't yann@1: +;; saved or used to pass arguments. yann@1: + yann@1: +(define_insn "blockage" yann@1: + [(unspec_volatile [(const_int 0)] UNSPEC_BLOCKAGE)] yann@1: + "" yann@1: + "" yann@1: + [(set_attr "type" "unknown") yann@1: + (set_attr "length" "0")]) yann@1: + yann@1: + yann@1: + yann@1: +;***************************************************************************** yann@1: +;* yann@1: +;* Jumps and Calls yann@1: +;* yann@1: +;***************************************************************************** yann@1: + yann@1: +(define_insn "indirect_jump" yann@1: + [(set (pc) (match_operand:SI 0 "register_operand" "r"))] yann@1: + "" yann@1: + "jmp\\t%0" yann@1: + [(set_attr "type" "control")]) yann@1: + yann@1: +(define_insn "jump" yann@1: + [(set (pc) yann@1: + (label_ref (match_operand 0 "" "")))] yann@1: + "" yann@1: + "br\\t%0" yann@1: + [(set_attr "type" "control")]) yann@1: + yann@1: + yann@1: +(define_insn "indirect_call" yann@1: + [(call (mem:QI (match_operand:SI 0 "register_operand" "r")) yann@1: + (match_operand 1 "" "")) yann@1: + (clobber (reg:SI RA_REGNO))] yann@1: + "" yann@1: + "callr\\t%0" yann@1: + [(set_attr "type" "control")]) yann@1: + yann@1: +(define_insn "indirect_call_value" yann@1: + [(set (match_operand 0 "" "") yann@1: + (call (mem:QI (match_operand:SI 1 "register_operand" "r")) yann@1: + (match_operand 2 "" ""))) yann@1: + (clobber (reg:SI RA_REGNO))] yann@1: + "" yann@1: + "callr\\t%1" yann@1: +) yann@1: + yann@1: +(define_expand "call" yann@1: + [(parallel [(call (match_operand 0 "" "") yann@1: + (match_operand 1 "" "")) yann@1: + (clobber (reg:SI RA_REGNO))])] yann@1: + "" yann@1: + "") yann@1: + yann@1: +(define_expand "call_value" yann@1: + [(parallel [(set (match_operand 0 "" "") yann@1: + (call (match_operand 1 "" "") yann@1: + (match_operand 2 "" ""))) yann@1: + (clobber (reg:SI RA_REGNO))])] yann@1: + "" yann@1: + "") yann@1: + yann@1: +(define_insn "*call" yann@1: + [(call (mem:QI (match_operand:SI 0 "immediate_operand" "i")) yann@1: + (match_operand 1 "" "")) yann@1: + (clobber (match_operand:SI 2 "register_operand" "=r"))] yann@1: + "" yann@1: + "call\\t%0" yann@1: + [(set_attr "type" "control")]) yann@1: + yann@1: +(define_insn "*call_value" yann@1: + [(set (match_operand 0 "" "") yann@1: + (call (mem:QI (match_operand:SI 1 "immediate_operand" "i")) yann@1: + (match_operand 2 "" ""))) yann@1: + (clobber (match_operand:SI 3 "register_operand" "=r"))] yann@1: + "" yann@1: + "call\\t%1" yann@1: + [(set_attr "type" "control")]) yann@1: + yann@1: +(define_expand "sibcall" yann@1: + [(parallel [(call (match_operand 0 "" "") yann@1: + (match_operand 1 "" "")) yann@1: + (return) yann@1: + (use (match_operand 2 "" ""))])] yann@1: + "" yann@1: + { yann@1: + XEXP (operands[0], 0) = copy_to_mode_reg (SImode, XEXP (operands[0], 0)); yann@1: + yann@1: + if (operands[2] == NULL_RTX) yann@1: + operands[2] = const0_rtx; yann@1: + } yann@1: +) yann@1: + yann@1: +(define_expand "sibcall_value" yann@1: + [(parallel [(set (match_operand 0 "" "") yann@1: + (call (match_operand 1 "" "") yann@1: + (match_operand 2 "" ""))) yann@1: + (return) yann@1: + (use (match_operand 3 "" ""))])] yann@1: + "" yann@1: + { yann@1: + XEXP (operands[1], 0) = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); yann@1: + yann@1: + if (operands[3] == NULL_RTX) yann@1: + operands[3] = const0_rtx; yann@1: + } yann@1: +) yann@1: + yann@1: +(define_insn "sibcall_insn" yann@1: + [(call (mem:QI (match_operand:SI 0 "register_operand" "r")) yann@1: + (match_operand 1 "" "")) yann@1: + (return) yann@1: + (use (match_operand 2 "" ""))] yann@1: + "" yann@1: + "jmp\\t%0" yann@1: +) yann@1: + yann@1: +(define_insn "sibcall_value_insn" yann@1: + [(set (match_operand 0 "register_operand" "") yann@1: + (call (mem:QI (match_operand:SI 1 "register_operand" "r")) yann@1: + (match_operand 2 "" ""))) yann@1: + (return) yann@1: + (use (match_operand 3 "" ""))] yann@1: + "" yann@1: + "jmp\\t%1" yann@1: +) yann@1: + yann@1: + yann@1: + yann@1: + yann@1: +(define_expand "tablejump" yann@1: + [(parallel [(set (pc) (match_operand 0 "register_operand" "r")) yann@1: + (use (label_ref (match_operand 1 "" "")))])] yann@1: + "" yann@1: + "" yann@1: +) yann@1: + yann@1: +(define_insn "*tablejump" yann@1: + [(set (pc) yann@1: + (match_operand:SI 0 "register_operand" "r")) yann@1: + (use (label_ref (match_operand 1 "" "")))] yann@1: + "" yann@1: + "jmp\\t%0" yann@1: + [(set_attr "type" "control")]) yann@1: + yann@1: + yann@1: + yann@1: +;***************************************************************************** yann@1: +;* yann@1: +;* Comparisons yann@1: +;* yann@1: +;***************************************************************************** yann@1: +;; Flow here is rather complex (based on MIPS): yann@1: +;; yann@1: +;; 1) The cmp{si,di,sf,df} routine is called. It deposits the yann@1: +;; arguments into the branch_cmp array, and the type into yann@1: +;; branch_type. No RTL is generated. yann@1: +;; yann@1: +;; 2) The appropriate branch define_expand is called, which then yann@1: +;; creates the appropriate RTL for the comparison and branch. yann@1: +;; Different CC modes are used, based on what type of branch is yann@1: +;; done, so that we can constrain things appropriately. There yann@1: +;; are assumptions in the rest of GCC that break if we fold the yann@1: +;; operands into the branchs for integer operations, and use cc0 yann@1: +;; for floating point, so we use the fp status register instead. yann@1: +;; If needed, an appropriate temporary is created to hold the yann@1: +;; of the integer compare. yann@1: + yann@1: +(define_expand "cmpsi" yann@1: + [(set (cc0) yann@1: + (compare:CC (match_operand:SI 0 "register_operand" "") yann@1: + (match_operand:SI 1 "arith_operand" "")))] yann@1: + "" yann@1: +{ yann@1: + branch_cmp[0] = operands[0]; yann@1: + branch_cmp[1] = operands[1]; yann@1: + branch_type = CMP_SI; yann@1: + DONE; yann@1: +}) yann@1: + yann@1: +(define_expand "tstsi" yann@1: + [(set (cc0) yann@1: + (match_operand:SI 0 "register_operand" ""))] yann@1: + "" yann@1: +{ yann@1: + branch_cmp[0] = operands[0]; yann@1: + branch_cmp[1] = const0_rtx; yann@1: + branch_type = CMP_SI; yann@1: + DONE; yann@1: +}) yann@1: + yann@1: + yann@1: +;***************************************************************************** yann@1: +;* yann@1: +;* setting a register from a comparison yann@1: +;* yann@1: +;***************************************************************************** yann@1: + yann@1: +(define_expand "seq" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (eq:SI (match_dup 1) yann@1: + (match_dup 2)))] yann@1: + "" yann@1: +{ yann@1: + if (branch_type != CMP_SI) yann@1: + FAIL; yann@1: + yann@1: + /* set up operands from compare. */ yann@1: + operands[1] = branch_cmp[0]; yann@1: + operands[2] = branch_cmp[1]; yann@1: + yann@1: + gen_int_relational (EQ, operands[0], operands[1], operands[2], NULL_RTX); yann@1: + DONE; yann@1: +}) yann@1: + yann@1: + yann@1: +(define_insn "*seq" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (eq:SI (match_operand:SI 1 "reg_or_0_operand" "%rM") yann@1: + (match_operand:SI 2 "arith_operand" "rI")))] yann@1: + "" yann@1: + "cmpeq%i2\\t%0, %z1, %z2" yann@1: + [(set_attr "type" "alu")]) yann@1: + yann@1: + yann@1: +(define_expand "sne" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (ne:SI (match_dup 1) yann@1: + (match_dup 2)))] yann@1: + "" yann@1: +{ yann@1: + if (branch_type != CMP_SI) yann@1: + FAIL; yann@1: + yann@1: + /* set up operands from compare. */ yann@1: + operands[1] = branch_cmp[0]; yann@1: + operands[2] = branch_cmp[1]; yann@1: + yann@1: + gen_int_relational (NE, operands[0], operands[1], operands[2], NULL_RTX); yann@1: + DONE; yann@1: +}) yann@1: + yann@1: + yann@1: +(define_insn "*sne" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (ne:SI (match_operand:SI 1 "reg_or_0_operand" "%rM") yann@1: + (match_operand:SI 2 "arith_operand" "rI")))] yann@1: + "" yann@1: + "cmpne%i2\\t%0, %z1, %z2" yann@1: + [(set_attr "type" "alu")]) yann@1: + yann@1: + yann@1: +(define_expand "sgt" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (gt:SI (match_dup 1) yann@1: + (match_dup 2)))] yann@1: + "" yann@1: +{ yann@1: + if (branch_type != CMP_SI) yann@1: + FAIL; yann@1: + yann@1: + /* set up operands from compare. */ yann@1: + operands[1] = branch_cmp[0]; yann@1: + operands[2] = branch_cmp[1]; yann@1: + yann@1: + gen_int_relational (GT, operands[0], operands[1], operands[2], NULL_RTX); yann@1: + DONE; yann@1: +}) yann@1: + yann@1: + yann@1: +(define_insn "*sgt" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (gt:SI (match_operand:SI 1 "reg_or_0_operand" "rM") yann@1: + (match_operand:SI 2 "reg_or_0_operand" "rM")))] yann@1: + "" yann@1: + "cmplt\\t%0, %z2, %z1" yann@1: + [(set_attr "type" "alu")]) yann@1: + yann@1: + yann@1: +(define_expand "sge" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (ge:SI (match_dup 1) yann@1: + (match_dup 2)))] yann@1: + "" yann@1: +{ yann@1: + if (branch_type != CMP_SI) yann@1: + FAIL; yann@1: + yann@1: + /* set up operands from compare. */ yann@1: + operands[1] = branch_cmp[0]; yann@1: + operands[2] = branch_cmp[1]; yann@1: + yann@1: + gen_int_relational (GE, operands[0], operands[1], operands[2], NULL_RTX); yann@1: + DONE; yann@1: +}) yann@1: + yann@1: + yann@1: +(define_insn "*sge" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (ge:SI (match_operand:SI 1 "reg_or_0_operand" "rM") yann@1: + (match_operand:SI 2 "arith_operand" "rI")))] yann@1: + "" yann@1: + "cmpge%i2\\t%0, %z1, %z2" yann@1: + [(set_attr "type" "alu")]) yann@1: + yann@1: +(define_expand "sle" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (le:SI (match_dup 1) yann@1: + (match_dup 2)))] yann@1: + "" yann@1: +{ yann@1: + if (branch_type != CMP_SI) yann@1: + FAIL; yann@1: + yann@1: + /* set up operands from compare. */ yann@1: + operands[1] = branch_cmp[0]; yann@1: + operands[2] = branch_cmp[1]; yann@1: + yann@1: + gen_int_relational (LE, operands[0], operands[1], operands[2], NULL_RTX); yann@1: + DONE; yann@1: +}) yann@1: + yann@1: + yann@1: +(define_insn "*sle" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (le:SI (match_operand:SI 1 "reg_or_0_operand" "rM") yann@1: + (match_operand:SI 2 "reg_or_0_operand" "rM")))] yann@1: + "" yann@1: + "cmpge\\t%0, %z2, %z1" yann@1: + [(set_attr "type" "alu")]) yann@1: + yann@1: + yann@1: +(define_expand "slt" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (lt:SI (match_dup 1) yann@1: + (match_dup 2)))] yann@1: + "" yann@1: +{ yann@1: + if (branch_type != CMP_SI) yann@1: + FAIL; yann@1: + yann@1: + /* set up operands from compare. */ yann@1: + operands[1] = branch_cmp[0]; yann@1: + operands[2] = branch_cmp[1]; yann@1: + yann@1: + gen_int_relational (LT, operands[0], operands[1], operands[2], NULL_RTX); yann@1: + DONE; yann@1: +}) yann@1: + yann@1: + yann@1: +(define_insn "*slt" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (lt:SI (match_operand:SI 1 "reg_or_0_operand" "rM") yann@1: + (match_operand:SI 2 "arith_operand" "rI")))] yann@1: + "" yann@1: + "cmplt%i2\\t%0, %z1, %z2" yann@1: + [(set_attr "type" "alu")]) yann@1: + yann@1: + yann@1: +(define_expand "sgtu" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (gtu:SI (match_dup 1) yann@1: + (match_dup 2)))] yann@1: + "" yann@1: +{ yann@1: + if (branch_type != CMP_SI) yann@1: + FAIL; yann@1: + yann@1: + /* set up operands from compare. */ yann@1: + operands[1] = branch_cmp[0]; yann@1: + operands[2] = branch_cmp[1]; yann@1: + yann@1: + gen_int_relational (GTU, operands[0], operands[1], operands[2], NULL_RTX); yann@1: + DONE; yann@1: +}) yann@1: + yann@1: + yann@1: +(define_insn "*sgtu" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (gtu:SI (match_operand:SI 1 "reg_or_0_operand" "rM") yann@1: + (match_operand:SI 2 "reg_or_0_operand" "rM")))] yann@1: + "" yann@1: + "cmpltu\\t%0, %z2, %z1" yann@1: + [(set_attr "type" "alu")]) yann@1: + yann@1: + yann@1: +(define_expand "sgeu" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (geu:SI (match_dup 1) yann@1: + (match_dup 2)))] yann@1: + "" yann@1: +{ yann@1: + if (branch_type != CMP_SI) yann@1: + FAIL; yann@1: + yann@1: + /* set up operands from compare. */ yann@1: + operands[1] = branch_cmp[0]; yann@1: + operands[2] = branch_cmp[1]; yann@1: + yann@1: + gen_int_relational (GEU, operands[0], operands[1], operands[2], NULL_RTX); yann@1: + DONE; yann@1: +}) yann@1: + yann@1: + yann@1: +(define_insn "*sgeu" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (geu:SI (match_operand:SI 1 "reg_or_0_operand" "rM") yann@1: + (match_operand:SI 2 "uns_arith_operand" "rJ")))] yann@1: + "" yann@1: + "cmpgeu%i2\\t%0, %z1, %z2" yann@1: + [(set_attr "type" "alu")]) yann@1: + yann@1: +(define_expand "sleu" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (leu:SI (match_dup 1) yann@1: + (match_dup 2)))] yann@1: + "" yann@1: +{ yann@1: + if (branch_type != CMP_SI) yann@1: + FAIL; yann@1: + yann@1: + /* set up operands from compare. */ yann@1: + operands[1] = branch_cmp[0]; yann@1: + operands[2] = branch_cmp[1]; yann@1: + yann@1: + gen_int_relational (LEU, operands[0], operands[1], operands[2], NULL_RTX); yann@1: + DONE; yann@1: +}) yann@1: + yann@1: + yann@1: +(define_insn "*sleu" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (leu:SI (match_operand:SI 1 "reg_or_0_operand" "rM") yann@1: + (match_operand:SI 2 "reg_or_0_operand" "rM")))] yann@1: + "" yann@1: + "cmpgeu\\t%0, %z2, %z1" yann@1: + [(set_attr "type" "alu")]) yann@1: + yann@1: + yann@1: +(define_expand "sltu" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (ltu:SI (match_dup 1) yann@1: + (match_dup 2)))] yann@1: + "" yann@1: +{ yann@1: + if (branch_type != CMP_SI) yann@1: + FAIL; yann@1: + yann@1: + /* set up operands from compare. */ yann@1: + operands[1] = branch_cmp[0]; yann@1: + operands[2] = branch_cmp[1]; yann@1: + yann@1: + gen_int_relational (LTU, operands[0], operands[1], operands[2], NULL_RTX); yann@1: + DONE; yann@1: +}) yann@1: + yann@1: + yann@1: +(define_insn "*sltu" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (ltu:SI (match_operand:SI 1 "reg_or_0_operand" "rM") yann@1: + (match_operand:SI 2 "uns_arith_operand" "rJ")))] yann@1: + "" yann@1: + "cmpltu%i2\\t%0, %z1, %z2" yann@1: + [(set_attr "type" "alu")]) yann@1: + yann@1: + yann@1: + yann@1: + yann@1: +;***************************************************************************** yann@1: +;* yann@1: +;* branches yann@1: +;* yann@1: +;***************************************************************************** yann@1: + yann@1: +(define_insn "*cbranch" yann@1: + [(set (pc) yann@1: + (if_then_else yann@1: + (match_operator:SI 0 "comparison_operator" yann@1: + [(match_operand:SI 2 "reg_or_0_operand" "rM") yann@1: + (match_operand:SI 3 "reg_or_0_operand" "rM")]) yann@1: + (label_ref (match_operand 1 "" "")) yann@1: + (pc)))] yann@1: + "" yann@1: + "b%0\\t%z2, %z3, %l1" yann@1: + [(set_attr "type" "control")]) yann@1: + yann@1: + yann@1: +(define_expand "beq" yann@1: + [(set (pc) yann@1: + (if_then_else (eq:CC (cc0) yann@1: + (const_int 0)) yann@1: + (label_ref (match_operand 0 "" "")) yann@1: + (pc)))] yann@1: + "" yann@1: +{ yann@1: + gen_int_relational (EQ, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); yann@1: + DONE; yann@1: +}) yann@1: + yann@1: + yann@1: +(define_expand "bne" yann@1: + [(set (pc) yann@1: + (if_then_else (ne:CC (cc0) yann@1: + (const_int 0)) yann@1: + (label_ref (match_operand 0 "" "")) yann@1: + (pc)))] yann@1: + "" yann@1: +{ yann@1: + gen_int_relational (NE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); yann@1: + DONE; yann@1: +}) yann@1: + yann@1: + yann@1: +(define_expand "bgt" yann@1: + [(set (pc) yann@1: + (if_then_else (gt:CC (cc0) yann@1: + (const_int 0)) yann@1: + (label_ref (match_operand 0 "" "")) yann@1: + (pc)))] yann@1: + "" yann@1: +{ yann@1: + gen_int_relational (GT, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); yann@1: + DONE; yann@1: +}) yann@1: + yann@1: +(define_expand "bge" yann@1: + [(set (pc) yann@1: + (if_then_else (ge:CC (cc0) yann@1: + (const_int 0)) yann@1: + (label_ref (match_operand 0 "" "")) yann@1: + (pc)))] yann@1: + "" yann@1: +{ yann@1: + gen_int_relational (GE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); yann@1: + DONE; yann@1: +}) yann@1: + yann@1: +(define_expand "ble" yann@1: + [(set (pc) yann@1: + (if_then_else (le:CC (cc0) yann@1: + (const_int 0)) yann@1: + (label_ref (match_operand 0 "" "")) yann@1: + (pc)))] yann@1: + "" yann@1: +{ yann@1: + gen_int_relational (LE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); yann@1: + DONE; yann@1: +}) yann@1: + yann@1: +(define_expand "blt" yann@1: + [(set (pc) yann@1: + (if_then_else (lt:CC (cc0) yann@1: + (const_int 0)) yann@1: + (label_ref (match_operand 0 "" "")) yann@1: + (pc)))] yann@1: + "" yann@1: +{ yann@1: + gen_int_relational (LT, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); yann@1: + DONE; yann@1: +}) yann@1: + yann@1: + yann@1: +(define_expand "bgtu" yann@1: + [(set (pc) yann@1: + (if_then_else (gtu:CC (cc0) yann@1: + (const_int 0)) yann@1: + (label_ref (match_operand 0 "" "")) yann@1: + (pc)))] yann@1: + "" yann@1: +{ yann@1: + gen_int_relational (GTU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); yann@1: + DONE; yann@1: +}) yann@1: + yann@1: +(define_expand "bgeu" yann@1: + [(set (pc) yann@1: + (if_then_else (geu:CC (cc0) yann@1: + (const_int 0)) yann@1: + (label_ref (match_operand 0 "" "")) yann@1: + (pc)))] yann@1: + "" yann@1: +{ yann@1: + gen_int_relational (GEU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); yann@1: + DONE; yann@1: +}) yann@1: + yann@1: +(define_expand "bleu" yann@1: + [(set (pc) yann@1: + (if_then_else (leu:CC (cc0) yann@1: + (const_int 0)) yann@1: + (label_ref (match_operand 0 "" "")) yann@1: + (pc)))] yann@1: + "" yann@1: +{ yann@1: + gen_int_relational (LEU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); yann@1: + DONE; yann@1: +}) yann@1: + yann@1: +(define_expand "bltu" yann@1: + [(set (pc) yann@1: + (if_then_else (ltu:CC (cc0) yann@1: + (const_int 0)) yann@1: + (label_ref (match_operand 0 "" "")) yann@1: + (pc)))] yann@1: + "" yann@1: +{ yann@1: + gen_int_relational (LTU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); yann@1: + DONE; yann@1: +}) yann@1: + yann@1: + yann@1: +;***************************************************************************** yann@1: +;* yann@1: +;* String and Block Operations yann@1: +;* yann@1: +;***************************************************************************** yann@1: + yann@1: +; ??? This is all really a hack to get Dhrystone to work as fast as possible yann@1: +; things to be fixed: yann@1: +; * let the compiler core handle all of this, for that to work the extra yann@1: +; aliasing needs to be addressed. yann@1: +; * we use three temporary registers for loading and storing to ensure no yann@1: +; ld use stalls, this is excessive, because after the first ld/st only yann@1: +; two are needed. Only two would be needed all the way through if yann@1: +; we could schedule with other code. Consider: yann@1: +; 1 ld $1, 0($src) yann@1: +; 2 ld $2, 4($src) yann@1: +; 3 ld $3, 8($src) yann@1: +; 4 st $1, 0($dest) yann@1: +; 5 ld $1, 12($src) yann@1: +; 6 st $2, 4($src) yann@1: +; 7 etc. yann@1: +; The first store has to wait until 4. If it does not there will be one yann@1: +; cycle of stalling. However, if any other instruction could be placed yann@1: +; between 1 and 4, $3 would not be needed. yann@1: +; * In small we probably don't want to ever do this ourself because there yann@1: +; is no ld use stall. yann@1: + yann@1: +(define_expand "movstrsi" yann@1: + [(parallel [(set (match_operand:BLK 0 "general_operand" "") yann@1: + (match_operand:BLK 1 "general_operand" "")) yann@1: + (use (match_operand:SI 2 "const_int_operand" "")) yann@1: + (use (match_operand:SI 3 "const_int_operand" "")) yann@1: + (clobber (match_scratch:SI 4 "=&r")) yann@1: + (clobber (match_scratch:SI 5 "=&r")) yann@1: + (clobber (match_scratch:SI 6 "=&r"))])] yann@1: + "TARGET_INLINE_MEMCPY" yann@1: +{ yann@1: + rtx ld_addr_reg, st_addr_reg; yann@1: + yann@1: + /* If the predicate for op2 fails in expr.c:emit_block_move_via_movstr yann@1: + it trys to copy to a register, but does not re-try the predicate. yann@1: + ??? Intead of fixing expr.c, I fix it here. */ yann@1: + if (!const_int_operand (operands[2], SImode)) yann@1: + FAIL; yann@1: + yann@1: + /* ??? there are some magic numbers which need to be sorted out here. yann@1: + the basis for them is not increasing code size hugely or going yann@1: + out of range of offset addressing */ yann@1: + if (INTVAL (operands[3]) < 4) yann@1: + FAIL; yann@1: + if (!optimize yann@1: + || (optimize_size && INTVAL (operands[2]) > 12) yann@1: + || (optimize < 3 && INTVAL (operands[2]) > 100) yann@1: + || INTVAL (operands[2]) > 200) yann@1: + FAIL; yann@1: + yann@1: + st_addr_reg yann@1: + = replace_equiv_address (operands[0], yann@1: + copy_to_mode_reg (Pmode, XEXP (operands[0], 0))); yann@1: + ld_addr_reg yann@1: + = replace_equiv_address (operands[1], yann@1: + copy_to_mode_reg (Pmode, XEXP (operands[1], 0))); yann@1: + emit_insn (gen_movstrsi_internal (st_addr_reg, ld_addr_reg, yann@1: + operands[2], operands[3])); yann@1: + yann@1: + DONE; yann@1: +}) yann@1: + yann@1: + yann@1: +(define_insn "movstrsi_internal" yann@1: + [(set (match_operand:BLK 0 "memory_operand" "=o") yann@1: + (match_operand:BLK 1 "memory_operand" "o")) yann@1: + (use (match_operand:SI 2 "const_int_operand" "i")) yann@1: + (use (match_operand:SI 3 "const_int_operand" "i")) yann@1: + (clobber (match_scratch:SI 4 "=&r")) yann@1: + (clobber (match_scratch:SI 5 "=&r")) yann@1: + (clobber (match_scratch:SI 6 "=&r"))] yann@1: + "TARGET_INLINE_MEMCPY" yann@1: +{ yann@1: + int ld_offset = INTVAL (operands[2]); yann@1: + int ld_len = INTVAL (operands[2]); yann@1: + int ld_reg = 0; yann@1: + rtx ld_addr_reg = XEXP (operands[1], 0); yann@1: + int st_offset = INTVAL (operands[2]); yann@1: + int st_len = INTVAL (operands[2]); yann@1: + int st_reg = 0; yann@1: + rtx st_addr_reg = XEXP (operands[0], 0); yann@1: + int delay_count = 0; yann@1: + yann@1: + /* ops[0] is the address used by the insn yann@1: + ops[1] is the register being loaded or stored */ yann@1: + rtx ops[2]; yann@1: + yann@1: + if (INTVAL (operands[3]) < 4) yann@1: + abort (); yann@1: + yann@1: + while (ld_offset >= 4) yann@1: + { yann@1: + /* if the load use delay has been met, I can start yann@1: + storing */ yann@1: + if (delay_count >= 3) yann@1: + { yann@1: + ops[0] = gen_rtx (MEM, SImode, yann@1: + plus_constant (st_addr_reg, st_len - st_offset)); yann@1: + ops[1] = operands[st_reg + 4]; yann@1: + output_asm_insn ("stw\t%1, %0", ops); yann@1: + yann@1: + st_reg = (st_reg + 1) % 3; yann@1: + st_offset -= 4; yann@1: + } yann@1: + yann@1: + ops[0] = gen_rtx (MEM, SImode, yann@1: + plus_constant (ld_addr_reg, ld_len - ld_offset)); yann@1: + ops[1] = operands[ld_reg + 4]; yann@1: + output_asm_insn ("ldw\t%1, %0", ops); yann@1: + yann@1: + ld_reg = (ld_reg + 1) % 3; yann@1: + ld_offset -= 4; yann@1: + delay_count++; yann@1: + } yann@1: + yann@1: + if (ld_offset >= 2) yann@1: + { yann@1: + /* if the load use delay has been met, I can start yann@1: + storing */ yann@1: + if (delay_count >= 3) yann@1: + { yann@1: + ops[0] = gen_rtx (MEM, SImode, yann@1: + plus_constant (st_addr_reg, st_len - st_offset)); yann@1: + ops[1] = operands[st_reg + 4]; yann@1: + output_asm_insn ("stw\t%1, %0", ops); yann@1: + yann@1: + st_reg = (st_reg + 1) % 3; yann@1: + st_offset -= 4; yann@1: + } yann@1: + yann@1: + ops[0] = gen_rtx (MEM, HImode, yann@1: + plus_constant (ld_addr_reg, ld_len - ld_offset)); yann@1: + ops[1] = operands[ld_reg + 4]; yann@1: + output_asm_insn ("ldh\t%1, %0", ops); yann@1: + yann@1: + ld_reg = (ld_reg + 1) % 3; yann@1: + ld_offset -= 2; yann@1: + delay_count++; yann@1: + } yann@1: + yann@1: + if (ld_offset >= 1) yann@1: + { yann@1: + /* if the load use delay has been met, I can start yann@1: + storing */ yann@1: + if (delay_count >= 3) yann@1: + { yann@1: + ops[0] = gen_rtx (MEM, SImode, yann@1: + plus_constant (st_addr_reg, st_len - st_offset)); yann@1: + ops[1] = operands[st_reg + 4]; yann@1: + output_asm_insn ("stw\t%1, %0", ops); yann@1: + yann@1: + st_reg = (st_reg + 1) % 3; yann@1: + st_offset -= 4; yann@1: + } yann@1: + yann@1: + ops[0] = gen_rtx (MEM, QImode, yann@1: + plus_constant (ld_addr_reg, ld_len - ld_offset)); yann@1: + ops[1] = operands[ld_reg + 4]; yann@1: + output_asm_insn ("ldb\t%1, %0", ops); yann@1: + yann@1: + ld_reg = (ld_reg + 1) % 3; yann@1: + ld_offset -= 1; yann@1: + delay_count++; yann@1: + } yann@1: + yann@1: + while (st_offset >= 4) yann@1: + { yann@1: + ops[0] = gen_rtx (MEM, SImode, yann@1: + plus_constant (st_addr_reg, st_len - st_offset)); yann@1: + ops[1] = operands[st_reg + 4]; yann@1: + output_asm_insn ("stw\t%1, %0", ops); yann@1: + yann@1: + st_reg = (st_reg + 1) % 3; yann@1: + st_offset -= 4; yann@1: + } yann@1: + yann@1: + while (st_offset >= 2) yann@1: + { yann@1: + ops[0] = gen_rtx (MEM, HImode, yann@1: + plus_constant (st_addr_reg, st_len - st_offset)); yann@1: + ops[1] = operands[st_reg + 4]; yann@1: + output_asm_insn ("sth\t%1, %0", ops); yann@1: + yann@1: + st_reg = (st_reg + 1) % 3; yann@1: + st_offset -= 2; yann@1: + } yann@1: + yann@1: + while (st_offset >= 1) yann@1: + { yann@1: + ops[0] = gen_rtx (MEM, QImode, yann@1: + plus_constant (st_addr_reg, st_len - st_offset)); yann@1: + ops[1] = operands[st_reg + 4]; yann@1: + output_asm_insn ("stb\t%1, %0", ops); yann@1: + yann@1: + st_reg = (st_reg + 1) % 3; yann@1: + st_offset -= 1; yann@1: + } yann@1: + yann@1: + return ""; yann@1: +} yann@1: +; ??? lengths are not being used yet, but I will probably forget yann@1: +; to update this once I am using lengths, so set it to something yann@1: +; definetely big enough to cover it. 400 allows for 200 bytes yann@1: +; of motion. yann@1: + [(set_attr "length" "400")]) yann@1: + yann@1: + yann@1: + yann@1: +;***************************************************************************** yann@1: +;* yann@1: +;* Custom instructions yann@1: +;* yann@1: +;***************************************************************************** yann@1: + yann@1: +(define_constants [ yann@1: + (CUSTOM_N 100) yann@1: + (CUSTOM_NI 101) yann@1: + (CUSTOM_NF 102) yann@1: + (CUSTOM_NP 103) yann@1: + (CUSTOM_NII 104) yann@1: + (CUSTOM_NIF 105) yann@1: + (CUSTOM_NIP 106) yann@1: + (CUSTOM_NFI 107) yann@1: + (CUSTOM_NFF 108) yann@1: + (CUSTOM_NFP 109) yann@1: + (CUSTOM_NPI 110) yann@1: + (CUSTOM_NPF 111) yann@1: + (CUSTOM_NPP 112) yann@1: + (CUSTOM_IN 113) yann@1: + (CUSTOM_INI 114) yann@1: + (CUSTOM_INF 115) yann@1: + (CUSTOM_INP 116) yann@1: + (CUSTOM_INII 117) yann@1: + (CUSTOM_INIF 118) yann@1: + (CUSTOM_INIP 119) yann@1: + (CUSTOM_INFI 120) yann@1: + (CUSTOM_INFF 121) yann@1: + (CUSTOM_INFP 122) yann@1: + (CUSTOM_INPI 123) yann@1: + (CUSTOM_INPF 124) yann@1: + (CUSTOM_INPP 125) yann@1: + (CUSTOM_FN 126) yann@1: + (CUSTOM_FNI 127) yann@1: + (CUSTOM_FNF 128) yann@1: + (CUSTOM_FNP 129) yann@1: + (CUSTOM_FNII 130) yann@1: + (CUSTOM_FNIF 131) yann@1: + (CUSTOM_FNIP 132) yann@1: + (CUSTOM_FNFI 133) yann@1: + (CUSTOM_FNFF 134) yann@1: + (CUSTOM_FNFP 135) yann@1: + (CUSTOM_FNPI 136) yann@1: + (CUSTOM_FNPF 137) yann@1: + (CUSTOM_FNPP 138) yann@1: + (CUSTOM_PN 139) yann@1: + (CUSTOM_PNI 140) yann@1: + (CUSTOM_PNF 141) yann@1: + (CUSTOM_PNP 142) yann@1: + (CUSTOM_PNII 143) yann@1: + (CUSTOM_PNIF 144) yann@1: + (CUSTOM_PNIP 145) yann@1: + (CUSTOM_PNFI 146) yann@1: + (CUSTOM_PNFF 147) yann@1: + (CUSTOM_PNFP 148) yann@1: + (CUSTOM_PNPI 149) yann@1: + (CUSTOM_PNPF 150) yann@1: + (CUSTOM_PNPP 151) yann@1: +]) yann@1: + yann@1: + yann@1: +(define_insn "custom_n" yann@1: + [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")] CUSTOM_N)] yann@1: + "" yann@1: + "custom\\t%0, zero, zero, zero" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_ni" yann@1: + [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") yann@1: + (match_operand:SI 1 "register_operand" "r")] CUSTOM_NI)] yann@1: + "" yann@1: + "custom\\t%0, zero, %1, zero" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_nf" yann@1: + [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") yann@1: + (match_operand:SF 1 "register_operand" "r")] CUSTOM_NF)] yann@1: + "" yann@1: + "custom\\t%0, zero, %1, zero" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_np" yann@1: + [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") yann@1: + (match_operand:SI 1 "register_operand" "r")] CUSTOM_NP)] yann@1: + "" yann@1: + "custom\\t%0, zero, %1, zero" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_nii" yann@1: + [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") yann@1: + (match_operand:SI 1 "register_operand" "r") yann@1: + (match_operand:SI 2 "register_operand" "r")] CUSTOM_NII)] yann@1: + "" yann@1: + "custom\\t%0, zero, %1, %2" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_nif" yann@1: + [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") yann@1: + (match_operand:SI 1 "register_operand" "r") yann@1: + (match_operand:SF 2 "register_operand" "r")] CUSTOM_NIF)] yann@1: + "" yann@1: + "custom\\t%0, zero, %1, %2" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_nip" yann@1: + [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") yann@1: + (match_operand:SI 1 "register_operand" "r") yann@1: + (match_operand:SI 2 "register_operand" "r")] CUSTOM_NIP)] yann@1: + "" yann@1: + "custom\\t%0, zero, %1, %2" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_nfi" yann@1: + [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") yann@1: + (match_operand:SF 1 "register_operand" "r") yann@1: + (match_operand:SI 2 "register_operand" "r")] CUSTOM_NFI)] yann@1: + "" yann@1: + "custom\\t%0, zero, %1, %2" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_nff" yann@1: + [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") yann@1: + (match_operand:SF 1 "register_operand" "r") yann@1: + (match_operand:SF 2 "register_operand" "r")] CUSTOM_NFF)] yann@1: + "" yann@1: + "custom\\t%0, zero, %1, %2" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_nfp" yann@1: + [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") yann@1: + (match_operand:SF 1 "register_operand" "r") yann@1: + (match_operand:SI 2 "register_operand" "r")] CUSTOM_NFP)] yann@1: + "" yann@1: + "custom\\t%0, zero, %1, %2" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_npi" yann@1: + [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") yann@1: + (match_operand:SI 1 "register_operand" "r") yann@1: + (match_operand:SI 2 "register_operand" "r")] CUSTOM_NPI)] yann@1: + "" yann@1: + "custom\\t%0, zero, %1, %2" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_npf" yann@1: + [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") yann@1: + (match_operand:SI 1 "register_operand" "r") yann@1: + (match_operand:SF 2 "register_operand" "r")] CUSTOM_NPF)] yann@1: + "" yann@1: + "custom\\t%0, zero, %1, %2" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_npp" yann@1: + [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") yann@1: + (match_operand:SI 1 "register_operand" "r") yann@1: + (match_operand:SI 2 "register_operand" "r")] CUSTOM_NPP)] yann@1: + "" yann@1: + "custom\\t%0, zero, %1, %2" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: + yann@1: + yann@1: +(define_insn "custom_in" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")] CUSTOM_IN))] yann@1: + "" yann@1: + "custom\\t%1, %0, zero, zero" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_ini" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SI 2 "register_operand" "r")] CUSTOM_INI))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, zero" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_inf" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SF 2 "register_operand" "r")] CUSTOM_INF))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, zero" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_inp" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SI 2 "register_operand" "r")] CUSTOM_INP))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, zero" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_inii" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SI 2 "register_operand" "r") yann@1: + (match_operand:SI 3 "register_operand" "r")] CUSTOM_INII))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, %3" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_inif" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SI 2 "register_operand" "r") yann@1: + (match_operand:SF 3 "register_operand" "r")] CUSTOM_INIF))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, %3" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_inip" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SI 2 "register_operand" "r") yann@1: + (match_operand:SI 3 "register_operand" "r")] CUSTOM_INIP))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, %3" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_infi" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SF 2 "register_operand" "r") yann@1: + (match_operand:SI 3 "register_operand" "r")] CUSTOM_INFI))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, %3" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_inff" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SF 2 "register_operand" "r") yann@1: + (match_operand:SF 3 "register_operand" "r")] CUSTOM_INFF))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, %3" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_infp" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SF 2 "register_operand" "r") yann@1: + (match_operand:SI 3 "register_operand" "r")] CUSTOM_INFP))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, %3" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_inpi" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SI 2 "register_operand" "r") yann@1: + (match_operand:SI 3 "register_operand" "r")] CUSTOM_INPI))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, %3" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_inpf" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SI 2 "register_operand" "r") yann@1: + (match_operand:SF 3 "register_operand" "r")] CUSTOM_INPF))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, %3" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_inpp" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SI 2 "register_operand" "r") yann@1: + (match_operand:SI 3 "register_operand" "r")] CUSTOM_INPP))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, %3" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: + yann@1: + yann@1: + yann@1: + yann@1: +(define_insn "custom_fn" yann@1: + [(set (match_operand:SF 0 "register_operand" "=r") yann@1: + (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")] CUSTOM_FN))] yann@1: + "" yann@1: + "custom\\t%1, %0, zero, zero" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_fni" yann@1: + [(set (match_operand:SF 0 "register_operand" "=r") yann@1: + (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SI 2 "register_operand" "r")] CUSTOM_FNI))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, zero" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_fnf" yann@1: + [(set (match_operand:SF 0 "register_operand" "=r") yann@1: + (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SF 2 "register_operand" "r")] CUSTOM_FNF))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, zero" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_fnp" yann@1: + [(set (match_operand:SF 0 "register_operand" "=r") yann@1: + (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SI 2 "register_operand" "r")] CUSTOM_FNP))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, zero" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_fnii" yann@1: + [(set (match_operand:SF 0 "register_operand" "=r") yann@1: + (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SI 2 "register_operand" "r") yann@1: + (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNII))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, %3" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_fnif" yann@1: + [(set (match_operand:SF 0 "register_operand" "=r") yann@1: + (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SI 2 "register_operand" "r") yann@1: + (match_operand:SF 3 "register_operand" "r")] CUSTOM_FNIF))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, %3" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_fnip" yann@1: + [(set (match_operand:SF 0 "register_operand" "=r") yann@1: + (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SI 2 "register_operand" "r") yann@1: + (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNIP))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, %3" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_fnfi" yann@1: + [(set (match_operand:SF 0 "register_operand" "=r") yann@1: + (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SF 2 "register_operand" "r") yann@1: + (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNFI))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, %3" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_fnff" yann@1: + [(set (match_operand:SF 0 "register_operand" "=r") yann@1: + (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SF 2 "register_operand" "r") yann@1: + (match_operand:SF 3 "register_operand" "r")] CUSTOM_FNFF))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, %3" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_fnfp" yann@1: + [(set (match_operand:SF 0 "register_operand" "=r") yann@1: + (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SF 2 "register_operand" "r") yann@1: + (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNFP))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, %3" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_fnpi" yann@1: + [(set (match_operand:SF 0 "register_operand" "=r") yann@1: + (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SI 2 "register_operand" "r") yann@1: + (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNPI))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, %3" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_fnpf" yann@1: + [(set (match_operand:SF 0 "register_operand" "=r") yann@1: + (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SI 2 "register_operand" "r") yann@1: + (match_operand:SF 3 "register_operand" "r")] CUSTOM_FNPF))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, %3" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_fnpp" yann@1: + [(set (match_operand:SF 0 "register_operand" "=r") yann@1: + (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SI 2 "register_operand" "r") yann@1: + (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNPP))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, %3" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: + yann@1: + yann@1: +(define_insn "custom_pn" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")] CUSTOM_PN))] yann@1: + "" yann@1: + "custom\\t%1, %0, zero, zero" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_pni" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SI 2 "register_operand" "r")] CUSTOM_PNI))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, zero" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_pnf" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SF 2 "register_operand" "r")] CUSTOM_PNF))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, zero" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_pnp" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SI 2 "register_operand" "r")] CUSTOM_PNP))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, zero" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_pnii" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SI 2 "register_operand" "r") yann@1: + (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNII))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, %3" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_pnif" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SI 2 "register_operand" "r") yann@1: + (match_operand:SF 3 "register_operand" "r")] CUSTOM_PNIF))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, %3" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_pnip" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SI 2 "register_operand" "r") yann@1: + (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNIP))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, %3" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_pnfi" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SF 2 "register_operand" "r") yann@1: + (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNFI))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, %3" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_pnff" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SF 2 "register_operand" "r") yann@1: + (match_operand:SF 3 "register_operand" "r")] CUSTOM_PNFF))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, %3" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_pnfp" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SF 2 "register_operand" "r") yann@1: + (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNFP))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, %3" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_pnpi" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SI 2 "register_operand" "r") yann@1: + (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNPI))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, %3" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_pnpf" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SI 2 "register_operand" "r") yann@1: + (match_operand:SF 3 "register_operand" "r")] CUSTOM_PNPF))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, %3" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: +(define_insn "custom_pnpp" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") yann@1: + (match_operand:SI 2 "register_operand" "r") yann@1: + (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNPP))] yann@1: + "" yann@1: + "custom\\t%1, %0, %2, %3" yann@1: + [(set_attr "type" "custom")]) yann@1: + yann@1: + yann@1: + yann@1: + yann@1: + yann@1: + yann@1: +;***************************************************************************** yann@1: +;* yann@1: +;* Misc yann@1: +;* yann@1: +;***************************************************************************** yann@1: + yann@1: +(define_insn "nop" yann@1: + [(const_int 0)] yann@1: + "" yann@1: + "nop\\t" yann@1: + [(set_attr "type" "alu")]) yann@1: + yann@1: +(define_insn "sync" yann@1: + [(unspec_volatile [(const_int 0)] UNSPEC_SYNC)] yann@1: + "" yann@1: + "sync\\t" yann@1: + [(set_attr "type" "control")]) yann@1: + yann@1: + yann@1: +(define_insn "rdctl" yann@1: + [(set (match_operand:SI 0 "register_operand" "=r") yann@1: + (unspec_volatile:SI [(match_operand:SI 1 "rdwrctl_operand" "O")] UNSPEC_RDCTL))] yann@1: + "" yann@1: + "rdctl\\t%0, ctl%1" yann@1: + [(set_attr "type" "control")]) yann@1: + yann@1: +(define_insn "wrctl" yann@1: + [(unspec_volatile:SI [(match_operand:SI 0 "rdwrctl_operand" "O") yann@1: + (match_operand:SI 1 "register_operand" "r")] UNSPEC_WRCTL)] yann@1: + "" yann@1: + "wrctl\\tctl%0, %1" yann@1: + [(set_attr "type" "control")]) yann@1: + yann@1: + yann@1: + yann@1: +;***************************************************************************** yann@1: +;* yann@1: +;* Peepholes yann@1: +;* yann@1: +;***************************************************************************** yann@1: + yann@1: + yann@1: --- gcc-3.4.3/gcc/config/nios2/t-nios2 yann@1: +++ gcc-3.4.3-nios2/gcc/config/nios2/t-nios2 yann@1: @@ -0,0 +1,123 @@ yann@1: +## yann@1: +## Compiler flags to use when compiling libgcc2.c. yann@1: +## yann@1: +## LIB2FUNCS_EXTRA yann@1: +## A list of source file names to be compiled or assembled and inserted into libgcc.a. yann@1: + yann@1: +LIB2FUNCS_EXTRA=$(srcdir)/config/nios2/lib2-divmod.c \ yann@1: + $(srcdir)/config/nios2/lib2-divmod-hi.c \ yann@1: + $(srcdir)/config/nios2/lib2-divtable.c \ yann@1: + $(srcdir)/config/nios2/lib2-mul.c yann@1: + yann@1: +## yann@1: +## Floating Point Emulation yann@1: +## To have GCC include software floating point libraries in libgcc.a define FPBIT yann@1: +## and DPBIT along with a few rules as follows: yann@1: +## yann@1: +## # We want fine grained libraries, so use the new code yann@1: +## # to build the floating point emulation libraries. yann@1: +FPBIT=$(srcdir)/config/nios2/nios2-fp-bit.c yann@1: +DPBIT=$(srcdir)/config/nios2/nios2-dp-bit.c yann@1: + yann@1: +TARGET_LIBGCC2_CFLAGS = -O2 yann@1: + yann@1: +# FLOAT_ONLY - no doubles yann@1: +# SMALL_MACHINE - QI/HI is faster than SI yann@1: +# Actually SMALL_MACHINE uses chars and shorts instead of ints yann@1: +# since ints (16-bit ones as they are today) are at least as fast yann@1: +# as chars and shorts, don't define SMALL_MACHINE yann@1: +# CMPtype - type returned by FP compare, i.e. INT (hard coded in fp-bit - see code ) yann@1: + yann@1: +$(FPBIT): $(srcdir)/config/fp-bit.c Makefile yann@1: + echo '#define FLOAT' > ${FPBIT} yann@1: + cat $(srcdir)/config/fp-bit.c >> ${FPBIT} yann@1: + yann@1: +$(DPBIT): $(srcdir)/config/fp-bit.c Makefile yann@1: + echo '' > ${DPBIT} yann@1: + cat $(srcdir)/config/fp-bit.c >> ${DPBIT} yann@1: + yann@1: +EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o crti.o crtn.o yann@1: + yann@1: +# Assemble startup files. yann@1: +$(T)crti.o: $(srcdir)/config/nios2/crti.asm $(GCC_PASSES) yann@1: + $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \ yann@1: + -c -o $(T)crti.o -x assembler-with-cpp $(srcdir)/config/nios2/crti.asm yann@1: + yann@1: +$(T)crtn.o: $(srcdir)/config/nios2/crtn.asm $(GCC_PASSES) yann@1: + $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \ yann@1: + -c -o $(T)crtn.o -x assembler-with-cpp $(srcdir)/config/nios2/crtn.asm yann@1: + yann@1: + yann@1: +## You may need to provide additional #defines at the beginning of yann@1: +## fp-bit.c and dp-bit.c to control target endianness and other options yann@1: +## yann@1: +## CRTSTUFF_T_CFLAGS yann@1: +## Special flags used when compiling crtstuff.c. See Initialization. yann@1: +## yann@1: +## CRTSTUFF_T_CFLAGS_S yann@1: +## Special flags used when compiling crtstuff.c for shared linking. Used yann@1: +## if you use crtbeginS.o and crtendS.o in EXTRA-PARTS. See Initialization. yann@1: +## yann@1: +## MULTILIB_OPTIONS yann@1: +## For some targets, invoking GCC in different ways produces objects that yann@1: +## can not be linked together. For example, for some targets GCC produces yann@1: +## both big and little endian code. For these targets, you must arrange yann@1: +## for multiple versions of libgcc.a to be compiled, one for each set of yann@1: +## incompatible options. When GCC invokes the linker, it arranges to link yann@1: +## in the right version of libgcc.a, based on the command line options yann@1: +## used. yann@1: +## The MULTILIB_OPTIONS macro lists the set of options for which special yann@1: +## versions of libgcc.a must be built. Write options that are mutually yann@1: +## incompatible side by side, separated by a slash. Write options that may yann@1: +## be used together separated by a space. The build procedure will build yann@1: +## all combinations of compatible options. yann@1: +## yann@1: +## For example, if you set MULTILIB_OPTIONS to m68000/m68020 msoft-float, yann@1: +## Makefile will build special versions of libgcc.a using the following yann@1: +## sets of options: -m68000, -m68020, -msoft-float, -m68000 -msoft-float, yann@1: +## and -m68020 -msoft-float. yann@1: + yann@1: +MULTILIB_OPTIONS = mno-hw-mul mhw-mulx yann@1: + yann@1: +## MULTILIB_DIRNAMES yann@1: +## If MULTILIB_OPTIONS is used, this variable specifies the directory names yann@1: +## that should be used to hold the various libraries. Write one element in yann@1: +## MULTILIB_DIRNAMES for each element in MULTILIB_OPTIONS. If yann@1: +## MULTILIB_DIRNAMES is not used, the default value will be yann@1: +## MULTILIB_OPTIONS, with all slashes treated as spaces. yann@1: +## For example, if MULTILIB_OPTIONS is set to m68000/m68020 msoft-float, yann@1: +## then the default value of MULTILIB_DIRNAMES is m68000 m68020 yann@1: +## msoft-float. You may specify a different value if you desire a yann@1: +## different set of directory names. yann@1: + yann@1: +# MULTILIB_DIRNAMES = yann@1: + yann@1: +## MULTILIB_MATCHES yann@1: +## Sometimes the same option may be written in two different ways. If an yann@1: +## option is listed in MULTILIB_OPTIONS, GCC needs to know about any yann@1: +## synonyms. In that case, set MULTILIB_MATCHES to a list of items of the yann@1: +## form option=option to describe all relevant synonyms. For example, yann@1: +## m68000=mc68000 m68020=mc68020. yann@1: +## yann@1: +## MULTILIB_EXCEPTIONS yann@1: +## Sometimes when there are multiple sets of MULTILIB_OPTIONS being yann@1: +## specified, there are combinations that should not be built. In that yann@1: +## case, set MULTILIB_EXCEPTIONS to be all of the switch exceptions in yann@1: +## shell case syntax that should not be built. yann@1: +## For example, in the PowerPC embedded ABI support, it is not desirable to yann@1: +## build libraries compiled with the -mcall-aix option and either of the yann@1: +## -fleading-underscore or -mlittle options at the same time. Therefore yann@1: +## MULTILIB_EXCEPTIONS is set to yann@1: +## yann@1: +## *mcall-aix/*fleading-underscore* *mlittle/*mcall-aix* yann@1: +## yann@1: + yann@1: +MULTILIB_EXCEPTIONS = *mno-hw-mul/*mhw-mulx* yann@1: + yann@1: +## yann@1: +## MULTILIB_EXTRA_OPTS Sometimes it is desirable that when building yann@1: +## multiple versions of libgcc.a certain options should always be passed on yann@1: +## to the compiler. In that case, set MULTILIB_EXTRA_OPTS to be the list yann@1: +## of options to be used for all builds. yann@1: +## yann@1: + yann@1: --- gcc-3.4.3/gcc/config.gcc yann@1: +++ gcc-3.4.3-nios2/gcc/config.gcc yann@1: @@ -1321,6 +1321,10 @@ m32rle-*-linux*) yann@1: thread_file='posix' yann@1: fi yann@1: ;; yann@1: +# JBG yann@1: +nios2-*-* | nios2-*-*) yann@1: + tm_file="elfos.h ${tm_file}" yann@1: + ;; yann@1: # m68hc11 and m68hc12 share the same machine description. yann@1: m68hc11-*-*|m6811-*-*) yann@1: tm_file="dbxelf.h elfos.h m68hc11/m68hc11.h" yann@1: --- gcc-3.4.3/gcc/cse.c yann@1: +++ gcc-3.4.3-nios2/gcc/cse.c yann@1: @@ -3134,6 +3134,10 @@ find_comparison_args (enum rtx_code code yann@1: #ifdef FLOAT_STORE_FLAG_VALUE yann@1: REAL_VALUE_TYPE fsfv; yann@1: #endif yann@1: +#ifdef __nios2__ yann@1: + if (p->is_const) yann@1: + break; yann@1: +#endif yann@1: yann@1: /* If the entry isn't valid, skip it. */ yann@1: if (! exp_equiv_p (p->exp, p->exp, 1, 0)) yann@1: --- gcc-3.4.3/gcc/doc/extend.texi yann@1: +++ gcc-3.4.3-nios2/gcc/doc/extend.texi yann@1: @@ -5636,12 +5636,118 @@ to those machines. Generally these gene yann@1: instructions, but allow the compiler to schedule those calls. yann@1: yann@1: @menu yann@1: +* Altera Nios II Built-in Functions:: yann@1: * Alpha Built-in Functions:: yann@1: * ARM Built-in Functions:: yann@1: * X86 Built-in Functions:: yann@1: * PowerPC AltiVec Built-in Functions:: yann@1: @end menu yann@1: yann@1: +@node Altera Nios II Built-in Functions yann@1: +@subsection Altera Nios II Built-in Functions yann@1: + yann@1: +These built-in functions are available for the Altera Nios II yann@1: +family of processors. yann@1: + yann@1: +The following built-in functions are always available. They yann@1: +all generate the machine instruction that is part of the name. yann@1: + yann@1: +@example yann@1: +int __builtin_ldbio (volatile const void *) yann@1: +int __builtin_ldbuio (volatile const void *) yann@1: +int __builtin_ldhio (volatile const void *) yann@1: +int __builtin_ldhuio (volatile const void *) yann@1: +int __builtin_ldwio (volatile const void *) yann@1: +void __builtin_stbio (volatile void *, int) yann@1: +void __builtin_sthio (volatile void *, int) yann@1: +void __builtin_stwio (volatile void *, int) yann@1: +void __builtin_sync (void) yann@1: +int __builtin_rdctl (int) yann@1: +void __builtin_wrctl (int, int) yann@1: +@end example yann@1: + yann@1: +The following built-in functions are always available. They yann@1: +all generate a Nios II Custom Instruction. The name of the yann@1: +function represents the types that the function takes and yann@1: +returns. The letter before the @code{n} is the return type yann@1: +or void if absent. The @code{n} represnts the first parameter yann@1: +to all the custom instructions, the custom instruction number. yann@1: +The two letters after the @code{n} represent the up to two yann@1: +parameters to the function. yann@1: + yann@1: +The letters reprsent the following data types: yann@1: +@table @code yann@1: +@item yann@1: +@code{void} for return type and no parameter for parameter types. yann@1: + yann@1: +@item i yann@1: +@code{int} for return type and parameter type yann@1: + yann@1: +@item f yann@1: +@code{float} for return type and parameter type yann@1: + yann@1: +@item p yann@1: +@code{void *} for return type and parameter type yann@1: + yann@1: +@end table yann@1: + yann@1: +And the function names are: yann@1: +@example yann@1: +void __builtin_custom_n (void) yann@1: +void __builtin_custom_ni (int) yann@1: +void __builtin_custom_nf (float) yann@1: +void __builtin_custom_np (void *) yann@1: +void __builtin_custom_nii (int, int) yann@1: +void __builtin_custom_nif (int, float) yann@1: +void __builtin_custom_nip (int, void *) yann@1: +void __builtin_custom_nfi (float, int) yann@1: +void __builtin_custom_nff (float, float) yann@1: +void __builtin_custom_nfp (float, void *) yann@1: +void __builtin_custom_npi (void *, int) yann@1: +void __builtin_custom_npf (void *, float) yann@1: +void __builtin_custom_npp (void *, void *) yann@1: +int __builtin_custom_in (void) yann@1: +int __builtin_custom_ini (int) yann@1: +int __builtin_custom_inf (float) yann@1: +int __builtin_custom_inp (void *) yann@1: +int __builtin_custom_inii (int, int) yann@1: +int __builtin_custom_inif (int, float) yann@1: +int __builtin_custom_inip (int, void *) yann@1: +int __builtin_custom_infi (float, int) yann@1: +int __builtin_custom_inff (float, float) yann@1: +int __builtin_custom_infp (float, void *) yann@1: +int __builtin_custom_inpi (void *, int) yann@1: +int __builtin_custom_inpf (void *, float) yann@1: +int __builtin_custom_inpp (void *, void *) yann@1: +float __builtin_custom_fn (void) yann@1: +float __builtin_custom_fni (int) yann@1: +float __builtin_custom_fnf (float) yann@1: +float __builtin_custom_fnp (void *) yann@1: +float __builtin_custom_fnii (int, int) yann@1: +float __builtin_custom_fnif (int, float) yann@1: +float __builtin_custom_fnip (int, void *) yann@1: +float __builtin_custom_fnfi (float, int) yann@1: +float __builtin_custom_fnff (float, float) yann@1: +float __builtin_custom_fnfp (float, void *) yann@1: +float __builtin_custom_fnpi (void *, int) yann@1: +float __builtin_custom_fnpf (void *, float) yann@1: +float __builtin_custom_fnpp (void *, void *) yann@1: +void * __builtin_custom_pn (void) yann@1: +void * __builtin_custom_pni (int) yann@1: +void * __builtin_custom_pnf (float) yann@1: +void * __builtin_custom_pnp (void *) yann@1: +void * __builtin_custom_pnii (int, int) yann@1: +void * __builtin_custom_pnif (int, float) yann@1: +void * __builtin_custom_pnip (int, void *) yann@1: +void * __builtin_custom_pnfi (float, int) yann@1: +void * __builtin_custom_pnff (float, float) yann@1: +void * __builtin_custom_pnfp (float, void *) yann@1: +void * __builtin_custom_pnpi (void *, int) yann@1: +void * __builtin_custom_pnpf (void *, float) yann@1: +void * __builtin_custom_pnpp (void *, void *) yann@1: +@end example yann@1: + yann@1: + yann@1: @node Alpha Built-in Functions yann@1: @subsection Alpha Built-in Functions yann@1: yann@1: --- gcc-3.4.3/gcc/doc/invoke.texi yann@1: +++ gcc-3.4.3-nios2/gcc/doc/invoke.texi yann@1: @@ -337,6 +337,14 @@ in the following sections. yann@1: @item Machine Dependent Options yann@1: @xref{Submodel Options,,Hardware Models and Configurations}. yann@1: yann@1: +@emph{Altera Nios II Options} yann@1: +@gccoptlist{-msmallc -mno-bypass-cache -mbypass-cache @gol yann@1: +-mno-cache-volatile -mcache-volatile -mno-inline-memcpy @gol yann@1: +-minline-memcpy -mno-fast-sw-div -mfast-sw-div @gol yann@1: +-mhw-mul -mno-hw-mul -mhw-mulx -mno-hw-mulx @gol yann@1: +-mno-hw-div -mhw-div @gol yann@1: +-msys-crt0= -msys-lib= -msys=nosys } yann@1: + yann@1: @emph{M680x0 Options} yann@1: @gccoptlist{-m68000 -m68020 -m68020-40 -m68020-60 -m68030 -m68040 @gol yann@1: -m68060 -mcpu32 -m5200 -m68881 -mbitfield -mc68000 -mc68020 @gol yann@1: @@ -5836,6 +5844,7 @@ machine description. The default for th yann@1: that macro, which enables you to change the defaults. yann@1: yann@1: @menu yann@1: +* Altera Nios II Options:: yann@1: * M680x0 Options:: yann@1: * M68hc1x Options:: yann@1: * VAX Options:: yann@1: @@ -5871,6 +5880,103 @@ that macro, which enables you to change yann@1: * FRV Options:: yann@1: @end menu yann@1: yann@1: + yann@1: +@node Altera Nios II Options yann@1: +@subsection Altera Nios II Options yann@1: +@cindex Altera Nios II options yann@1: + yann@1: +These are the @samp{-m} options defined for the Altera Nios II yann@1: +processor. yann@1: + yann@1: +@table @gcctabopt yann@1: + yann@1: +@item -msmallc yann@1: +@opindex msmallc yann@1: + yann@1: +Link with a limited version of the C library, -lsmallc. For more yann@1: +information see the C Library Documentation. yann@1: + yann@1: + yann@1: +@item -mbypass-cache yann@1: +@itemx -mno-bypass-cache yann@1: +@opindex mno-bypass-cache yann@1: +@opindex mbypass-cache yann@1: + yann@1: +Force all load and store instructions to always bypass cache by yann@1: +using io variants of the instructions. The default is to not yann@1: +bypass the cache. yann@1: + yann@1: +@item -mno-cache-volatile yann@1: +@itemx -mcache-volatile yann@1: +@opindex mcache-volatile yann@1: +@opindex mno-cache-volatile yann@1: + yann@1: +Volatile memory access bypass the cache using the io variants of yann@1: +the ld and st instructions. The default is to cache volatile yann@1: +accesses. yann@1: + yann@1: +-mno-cache-volatile is deprecated and will be deleted in a yann@1: +future GCC release. yann@1: + yann@1: + yann@1: +@item -mno-inline-memcpy yann@1: +@itemx -minline-memcpy yann@1: +@opindex mno-inline-memcpy yann@1: +@opindex minline-memcpy yann@1: + yann@1: +Do not inline memcpy. The default is to inline when -O is on. yann@1: + yann@1: + yann@1: +@item -mno-fast-sw-div yann@1: +@itemx -mfast-sw-div yann@1: +@opindex mno-fast-sw-div yann@1: +@opindex mfast-sw-div yann@1: + yann@1: +Do no use table based fast divide for small numbers. The default yann@1: +is to use the fast divide at -O3 and above. yann@1: + yann@1: + yann@1: +@item -mno-hw-mul yann@1: +@itemx -mhw-mul yann@1: +@itemx -mno-hw-mulx yann@1: +@itemx -mhw-mulx yann@1: +@itemx -mno-hw-div yann@1: +@itemx -mhw-div yann@1: +@opindex mno-hw-mul yann@1: +@opindex mhw-mul yann@1: +@opindex mno-hw-mulx yann@1: +@opindex mhw-mulx yann@1: +@opindex mno-hw-div yann@1: +@opindex mhw-div yann@1: + yann@1: +Enable or disable emitting @code{mul}, @code{mulx} and @code{div} family of yann@1: +instructions by the compiler. The default is to emit @code{mul} yann@1: +and not emit @code{div} and @code{mulx}. yann@1: + yann@1: +The different combinations of @code{mul} and @code{mulx} instructions yann@1: +generate a different multilib options. yann@1: + yann@1: + yann@1: +@item -msys-crt0=@var{startfile} yann@1: +@opindex msys-crt0 yann@1: + yann@1: +@var{startfile} is the file name of the startfile (crt0) to use yann@1: +when linking. The default is crt0.o that comes with libgloss yann@1: +and is only suitable for use with the instruction set yann@1: +simulator. yann@1: + yann@1: +@item -msys-lib=@var{systemlib} yann@1: +@itemx -msys-lib=nosys yann@1: +@opindex msys-lib yann@1: + yann@1: +@var{systemlib} is the library name of the library which provides yann@1: +the system calls required by the C library, e.g. @code{read}, @code{write} yann@1: +etc. The default is to use nosys, this library provides yann@1: +stub implementations of the calls and is part of libgloss. yann@1: + yann@1: +@end table yann@1: + yann@1: + yann@1: @node M680x0 Options yann@1: @subsection M680x0 Options yann@1: @cindex M680x0 options yann@1: --- gcc-3.4.3/gcc/doc/md.texi yann@1: +++ gcc-3.4.3-nios2/gcc/doc/md.texi yann@1: @@ -1335,6 +1335,49 @@ However, here is a summary of the machin yann@1: available on some particular machines. yann@1: yann@1: @table @emph yann@1: + yann@1: +@item Altera Nios II family---@file{nios2.h} yann@1: +@table @code yann@1: + yann@1: +@item I yann@1: +Integer that is valid as an immediate operand in an yann@1: +instruction taking a signed 16-bit number. Range yann@1: +@minus{}32768 to 32767. yann@1: + yann@1: +@item J yann@1: +Integer that is valid as an immediate operand in an yann@1: +instruction taking an unsigned 16-bit number. Range yann@1: +0 to 65535. yann@1: + yann@1: +@item K yann@1: +Integer that is valid as an immediate operand in an yann@1: +instruction taking only the upper 16-bits of a yann@1: +32-bit number. Range 32-bit numbers with the lower yann@1: +16-bits being 0. yann@1: + yann@1: +@item L yann@1: +Integer that is valid as an immediate operand for a yann@1: +shift instruction. Range 0 to 31. yann@1: + yann@1: + yann@1: +@item M yann@1: +Integer that is valid as an immediate operand for yann@1: +only the value 0. Can be used in conjunction with yann@1: +the format modifier @code{z} to use @code{r0} yann@1: +instead of @code{0} in the assembly output. yann@1: + yann@1: +@item N yann@1: +Integer that is valid as an immediate operand for yann@1: +a custom instruction opcode. Range 0 to 255. yann@1: + yann@1: +@item S yann@1: +Matches immediates which are addresses in the small yann@1: +data section and therefore can be added to @code{gp} yann@1: +as a 16-bit immediate to re-create their 32-bit value. yann@1: + yann@1: +@end table yann@1: + yann@1: + yann@1: @item ARM family---@file{arm.h} yann@1: @table @code yann@1: @item f