Index: gcc-4.1.2/gcc/config/nios2/crti.asm =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gcc-4.1.2/gcc/config/nios2/crti.asm 2010-06-30 08:50:26.000000000 +0200 @@ -0,0 +1,97 @@ +/* NOT ASSIGNED TO FSF. COPYRIGHT ALTERA. */ +/* + Copyright (C) 2003 + by Jonah Graham (jgraham@altera.com) + +This file is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file with other programs, and to distribute +those programs without any restriction coming from the use of this +file. (The General Public License restrictions do apply in other +respects; for example, they cover modification of the file, and +distribution when not linked into another program.) + +This file is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. + + As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. + + +This file just make a stack frame for the contents of the .fini and +.init sections. Users may put any desired instructions in those +sections. + + +While technically any code can be put in the init and fini sections +most stuff will not work other than stuff which obeys the call frame +and ABI. All the call-preserved registers are saved, the call clobbered +registers should have been saved by the code calling init and fini. + +See crtstuff.c for an example of code that inserts itself in the +init and fini sections. + +See crt0.s for the code that calls init and fini. +*/ + + .file "crti.asm" + + .section ".init" + .align 2 + .global _init +_init: + addi sp, sp, -48 + stw ra, 44(sp) + stw r23, 40(sp) + stw r22, 36(sp) + stw r21, 32(sp) + stw r20, 28(sp) + stw r19, 24(sp) + stw r18, 20(sp) + stw r17, 16(sp) + stw r16, 12(sp) + stw fp, 8(sp) + addi fp, sp, 8 + nextpc r22 +1: movhi r2, %hiadj(_GLOBAL_OFFSET_TABLE_ - 1b) + addi r2, r2, %lo(_GLOBAL_OFFSET_TABLE_ - 1b) + add r22, r22, r2 + + + .section ".fini" + .align 2 + .global _fini +_fini: + addi sp, sp, -48 + stw ra, 44(sp) + stw r23, 40(sp) + stw r22, 36(sp) + stw r21, 32(sp) + stw r20, 28(sp) + stw r19, 24(sp) + stw r18, 20(sp) + stw r17, 16(sp) + stw r16, 12(sp) + stw fp, 8(sp) + addi fp, sp, 8 + nextpc r22 +1: movhi r2, %hiadj(_GLOBAL_OFFSET_TABLE_ - 1b) + addi r2, r2, %lo(_GLOBAL_OFFSET_TABLE_ - 1b) + add r22, r22, r2 + + Index: gcc-4.1.2/gcc/config/nios2/crtn.asm =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gcc-4.1.2/gcc/config/nios2/crtn.asm 2010-06-30 08:50:26.000000000 +0200 @@ -0,0 +1,71 @@ +/* NOT ASSIGNED TO FSF. COPYRIGHT ALTERA. */ +/* + Copyright (C) 2003 + by Jonah Graham (jgraham@altera.com) + +This file is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file with other programs, and to distribute +those programs without any restriction coming from the use of this +file. (The General Public License restrictions do apply in other +respects; for example, they cover modification of the file, and +distribution when not linked into another program.) + +This file is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. + + As a special exception, if you link this library with files + compiled with GCC to produce an executable, this does not cause + the resulting executable to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. + + +This file just makes sure that the .fini and .init sections do in +fact return. Users may put any desired instructions in those sections. +This file is the last thing linked into any executable. +*/ + .file "crtn.asm" + + + + .section ".init" + ldw ra, 44(sp) + ldw r23, 40(sp) + ldw r22, 36(sp) + ldw r21, 32(sp) + ldw r20, 28(sp) + ldw r19, 24(sp) + ldw r18, 20(sp) + ldw r17, 16(sp) + ldw r16, 12(sp) + ldw fp, 8(sp) + addi sp, sp, 48 + ret + + .section ".fini" + ldw ra, 44(sp) + ldw r23, 40(sp) + ldw r22, 36(sp) + ldw r21, 32(sp) + ldw r20, 28(sp) + ldw r19, 24(sp) + ldw r18, 20(sp) + ldw r17, 16(sp) + ldw r16, 12(sp) + ldw fp, 8(sp) + addi sp, sp, 48 + ret + Index: gcc-4.1.2/gcc/config/nios2/lib2-divmod-hi.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gcc-4.1.2/gcc/config/nios2/lib2-divmod-hi.c 2010-06-30 08:50:26.000000000 +0200 @@ -0,0 +1,133 @@ + +/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is + supposedly valid even though this is a "target" file. */ +#include "auto-host.h" +#undef gid_t +#undef pid_t +#undef rlim_t +#undef ssize_t +#undef uid_t +#undef vfork + + +#include "tconfig.h" +#include "tsystem.h" +#include "coretypes.h" +#include "tm.h" + + +/* Don't use `fancy_abort' here even if config.h says to use it. */ +#ifdef abort +#undef abort +#endif + + +#ifdef HAVE_GAS_HIDDEN +#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) +#else +#define ATTRIBUTE_HIDDEN +#endif + +#ifndef MIN_UNITS_PER_WORD +#define MIN_UNITS_PER_WORD UNITS_PER_WORD +#endif + +#include "libgcc2.h" + +extern HItype __modhi3 (HItype, HItype); +extern HItype __divhi3 (HItype, HItype); +extern UHItype __umodhi3 (UHItype, UHItype); +extern UHItype __udivhi3 (UHItype, UHItype); + +static UHItype udivmodhi4(UHItype, UHItype, word_type); + +static UHItype +udivmodhi4(UHItype num, UHItype den, word_type modwanted) +{ + UHItype bit = 1; + UHItype res = 0; + + while (den < num && bit && !(den & (1L<<15))) + { + den <<=1; + bit <<=1; + } + while (bit) + { + if (num >= den) + { + num -= den; + res |= bit; + } + bit >>=1; + den >>=1; + } + if (modwanted) return num; + return res; +} + + +HItype +__divhi3 (HItype a, HItype b) +{ + word_type neg = 0; + HItype res; + + if (a < 0) + { + a = -a; + neg = !neg; + } + + if (b < 0) + { + b = -b; + neg = !neg; + } + + res = udivmodhi4 (a, b, 0); + + if (neg) + res = -res; + + return res; +} + + +HItype +__modhi3 (HItype a, HItype b) +{ + word_type neg = 0; + HItype res; + + if (a < 0) + { + a = -a; + neg = 1; + } + + if (b < 0) + b = -b; + + res = udivmodhi4 (a, b, 1); + + if (neg) + res = -res; + + return res; +} + + +UHItype +__udivhi3 (UHItype a, UHItype b) +{ + return udivmodhi4 (a, b, 0); +} + + +UHItype +__umodhi3 (UHItype a, UHItype b) +{ + return udivmodhi4 (a, b, 1); +} + Index: gcc-4.1.2/gcc/config/nios2/lib2-divmod.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gcc-4.1.2/gcc/config/nios2/lib2-divmod.c 2010-06-30 08:50:26.000000000 +0200 @@ -0,0 +1,136 @@ + +/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is + supposedly valid even though this is a "target" file. */ +#include "auto-host.h" +#undef gid_t +#undef pid_t +#undef rlim_t +#undef ssize_t +#undef uid_t +#undef vfork + + +#include "tconfig.h" +#include "tsystem.h" +#include "coretypes.h" +#include "tm.h" + + +/* Don't use `fancy_abort' here even if config.h says to use it. */ +#ifdef abort +#undef abort +#endif + + +#ifdef HAVE_GAS_HIDDEN +#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) +#else +#define ATTRIBUTE_HIDDEN +#endif + +#ifndef MIN_UNITS_PER_WORD +#define MIN_UNITS_PER_WORD UNITS_PER_WORD +#endif + +#include "libgcc2.h" + +extern SItype __modsi3 (SItype, SItype); +extern SItype __divsi3 (SItype, SItype); +extern SItype __umodsi3 (SItype, SItype); +extern SItype __udivsi3 (SItype, SItype); + +static USItype udivmodsi4(USItype, USItype, word_type); + +/* 16-bit SI divide and modulo as used in NIOS */ + + +static USItype +udivmodsi4(USItype num, USItype den, word_type modwanted) +{ + USItype bit = 1; + USItype res = 0; + + while (den < num && bit && !(den & (1L<<31))) + { + den <<=1; + bit <<=1; + } + while (bit) + { + if (num >= den) + { + num -= den; + res |= bit; + } + bit >>=1; + den >>=1; + } + if (modwanted) return num; + return res; +} + + +SItype +__divsi3 (SItype a, SItype b) +{ + word_type neg = 0; + SItype res; + + if (a < 0) + { + a = -a; + neg = !neg; + } + + if (b < 0) + { + b = -b; + neg = !neg; + } + + res = udivmodsi4 (a, b, 0); + + if (neg) + res = -res; + + return res; +} + + +SItype +__modsi3 (SItype a, SItype b) +{ + word_type neg = 0; + SItype res; + + if (a < 0) + { + a = -a; + neg = 1; + } + + if (b < 0) + b = -b; + + res = udivmodsi4 (a, b, 1); + + if (neg) + res = -res; + + return res; +} + + +SItype +__udivsi3 (SItype a, SItype b) +{ + return udivmodsi4 (a, b, 0); +} + + +SItype +__umodsi3 (SItype a, SItype b) +{ + return udivmodsi4 (a, b, 1); +} + Index: gcc-4.1.2/gcc/config/nios2/lib2-divtable.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gcc-4.1.2/gcc/config/nios2/lib2-divtable.c 2010-06-30 08:50:26.000000000 +0200 @@ -0,0 +1,52 @@ + +/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is + supposedly valid even though this is a "target" file. */ +#include "auto-host.h" +#undef gid_t +#undef pid_t +#undef rlim_t +#undef ssize_t +#undef uid_t +#undef vfork + + +#include "tconfig.h" +#include "tsystem.h" +#include "coretypes.h" +#include "tm.h" + + +/* Don't use `fancy_abort' here even if config.h says to use it. */ +#ifdef abort +#undef abort +#endif + + +#ifdef HAVE_GAS_HIDDEN +#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) +#else +#define ATTRIBUTE_HIDDEN +#endif + +#include "libgcc2.h" + +UQItype __divsi3_table[] = +{ + 0, 0/1, 0/2, 0/3, 0/4, 0/5, 0/6, 0/7, 0/8, 0/9, 0/10, 0/11, 0/12, 0/13, 0/14, 0/15, + 0, 1/1, 1/2, 1/3, 1/4, 1/5, 1/6, 1/7, 1/8, 1/9, 1/10, 1/11, 1/12, 1/13, 1/14, 1/15, + 0, 2/1, 2/2, 2/3, 2/4, 2/5, 2/6, 2/7, 2/8, 2/9, 2/10, 2/11, 2/12, 2/13, 2/14, 2/15, + 0, 3/1, 3/2, 3/3, 3/4, 3/5, 3/6, 3/7, 3/8, 3/9, 3/10, 3/11, 3/12, 3/13, 3/14, 3/15, + 0, 4/1, 4/2, 4/3, 4/4, 4/5, 4/6, 4/7, 4/8, 4/9, 4/10, 4/11, 4/12, 4/13, 4/14, 4/15, + 0, 5/1, 5/2, 5/3, 5/4, 5/5, 5/6, 5/7, 5/8, 5/9, 5/10, 5/11, 5/12, 5/13, 5/14, 5/15, + 0, 6/1, 6/2, 6/3, 6/4, 6/5, 6/6, 6/7, 6/8, 6/9, 6/10, 6/11, 6/12, 6/13, 6/14, 6/15, + 0, 7/1, 7/2, 7/3, 7/4, 7/5, 7/6, 7/7, 7/8, 7/9, 7/10, 7/11, 7/12, 7/13, 7/14, 7/15, + 0, 8/1, 8/2, 8/3, 8/4, 8/5, 8/6, 8/7, 8/8, 8/9, 8/10, 8/11, 8/12, 8/13, 8/14, 8/15, + 0, 9/1, 9/2, 9/3, 9/4, 9/5, 9/6, 9/7, 9/8, 9/9, 9/10, 9/11, 9/12, 9/13, 9/14, 9/15, + 0, 10/1, 10/2, 10/3, 10/4, 10/5, 10/6, 10/7, 10/8, 10/9, 10/10, 10/11, 10/12, 10/13, 10/14, 10/15, + 0, 11/1, 11/2, 11/3, 11/4, 11/5, 11/6, 11/7, 11/8, 11/9, 11/10, 11/11, 11/12, 11/13, 11/14, 11/15, + 0, 12/1, 12/2, 12/3, 12/4, 12/5, 12/6, 12/7, 12/8, 12/9, 12/10, 12/11, 12/12, 12/13, 12/14, 12/15, + 0, 13/1, 13/2, 13/3, 13/4, 13/5, 13/6, 13/7, 13/8, 13/9, 13/10, 13/11, 13/12, 13/13, 13/14, 13/15, + 0, 14/1, 14/2, 14/3, 14/4, 14/5, 14/6, 14/7, 14/8, 14/9, 14/10, 14/11, 14/12, 14/13, 14/14, 14/15, + 0, 15/1, 15/2, 15/3, 15/4, 15/5, 15/6, 15/7, 15/8, 15/9, 15/10, 15/11, 15/12, 15/13, 15/14, 15/15, +}; + Index: gcc-4.1.2/gcc/config/nios2/lib2-mul.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gcc-4.1.2/gcc/config/nios2/lib2-mul.c 2010-06-30 08:50:26.000000000 +0200 @@ -0,0 +1,113 @@ +/* while we are debugging (ie compile outside of gcc build) + disable gcc specific headers */ +#ifndef DEBUG_MULSI3 + + +/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is + supposedly valid even though this is a "target" file. */ +#include "auto-host.h" +#undef gid_t +#undef pid_t +#undef rlim_t +#undef ssize_t +#undef uid_t +#undef vfork + + +#include "tconfig.h" +#include "tsystem.h" +#include "coretypes.h" +#include "tm.h" + + +/* Don't use `fancy_abort' here even if config.h says to use it. */ +#ifdef abort +#undef abort +#endif + + +#ifdef HAVE_GAS_HIDDEN +#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) +#else +#define ATTRIBUTE_HIDDEN +#endif + +#ifndef MIN_UNITS_PER_WORD +#define MIN_UNITS_PER_WORD UNITS_PER_WORD +#endif + +#include "libgcc2.h" + +#else +#define SItype int +#define USItype unsigned int +#endif + + +extern SItype __mulsi3 (SItype, SItype); + +SItype +__mulsi3 (SItype a, SItype b) +{ + SItype res = 0; + USItype cnt = a; + + while (cnt) + { + if (cnt & 1) + { + res += b; + } + b <<= 1; + cnt >>= 1; + } + + return res; +} +/* +TODO: Choose best alternative implementation. + +SItype +__divsi3 (SItype a, SItype b) +{ + SItype res = 0; + USItype cnt = 0; + + while (cnt < 32) + { + if (a & (1L << cnt)) + { + res += b; + } + b <<= 1; + cnt++; + } + + return res; +} +*/ + + +#ifdef DEBUG_MULSI3 + +int +main () +{ + int i, j; + int error = 0; + + for (i = -1000; i < 1000; i++) + for (j = -1000; j < 1000; j++) + { + int expect = i * j; + int actual = A__divsi3 (i, j); + if (expect != actual) + { + printf ("error: %d * %d = %d not %d\n", i, j, expect, actual); + error = 1; + } + } + + return error; +} +#endif Index: gcc-4.1.2/gcc/config/nios2/linux-atomic.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gcc-4.1.2/gcc/config/nios2/linux-atomic.c 2010-06-30 08:50:26.000000000 +0200 @@ -0,0 +1,302 @@ +/* Linux-specific atomic operations for Nios II Linux. + Copyright (C) 2008 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file into combinations with other programs, +and to distribute those combinations without any restriction coming +from the use of this file. (The General Public License restrictions +do apply in other respects; for example, they cover modification of +the file, and distribution when not linked into a combine +executable.) + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to the Free +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ + +#include +#define EFAULT 14 +#define EBUSY 16 +#define ENOSYS 38 + +/* We implement byte, short and int versions of each atomic operation + using the kernel helper defined below. There is no support for + 64-bit operations yet. */ + +/* Crash a userspace program with SIGSEV. */ +#define ABORT_INSTRUCTION asm ("stw zero, 0(zero)") + +/* Kernel helper for compare-and-exchange a 32-bit value. */ +static inline long +__kernel_cmpxchg (int oldval, int newval, int *mem) +{ + register int r2 asm ("r2") = __NR_nios2cmpxchg; + register unsigned long lws_mem asm("r4") = (unsigned long) (mem); + register int lws_old asm("r5") = oldval; + register int lws_new asm("r6") = newval; + register int err asm ("r7"); + asm volatile ("trap" + : "=r" (r2), "=r" (err) + : "r" (r2), "r" (lws_mem), "r" (lws_old), "r" (lws_new) + : "r1", "r3", "r8", "r9", "r10", "r11", "r12", "r13", "r14", + "r15", "r29", "memory"); + + /* If the kernel LWS call succeeded (err == 0), r2 contains the old value + from memory. If this value is equal to OLDVAL, the new value was written + to memory. If not, return EBUSY. */ + if (__builtin_expect (err, 0)) + { + if(__builtin_expect (r2 == EFAULT || r2 == ENOSYS,0)) + ABORT_INSTRUCTION; + } + else + { + if (__builtin_expect (r2 != oldval, 0)) + r2 = EBUSY; + else + r2 = 0; + } + + return r2; +} + +#define HIDDEN __attribute__ ((visibility ("hidden"))) + +/* Big endian masks */ +#define INVERT_MASK_1 24 +#define INVERT_MASK_2 16 + +#define MASK_1 0xffu +#define MASK_2 0xffffu + +#define FETCH_AND_OP_WORD(OP, PFX_OP, INF_OP) \ + int HIDDEN \ + __sync_fetch_and_##OP##_4 (int *ptr, int val) \ + { \ + int failure, tmp; \ + \ + do { \ + tmp = *ptr; \ + failure = __kernel_cmpxchg (tmp, PFX_OP tmp INF_OP val, ptr); \ + } while (failure != 0); \ + \ + return tmp; \ + } + +FETCH_AND_OP_WORD (add, , +) +FETCH_AND_OP_WORD (sub, , -) +FETCH_AND_OP_WORD (or, , |) +FETCH_AND_OP_WORD (and, , &) +FETCH_AND_OP_WORD (xor, , ^) +FETCH_AND_OP_WORD (nand, ~, &) + +#define NAME_oldval(OP, WIDTH) __sync_fetch_and_##OP##_##WIDTH +#define NAME_newval(OP, WIDTH) __sync_##OP##_and_fetch_##WIDTH + +/* Implement both __sync__and_fetch and __sync_fetch_and_ for + subword-sized quantities. */ + +#define SUBWORD_SYNC_OP(OP, PFX_OP, INF_OP, TYPE, WIDTH, RETURN) \ + TYPE HIDDEN \ + NAME##_##RETURN (OP, WIDTH) (TYPE *ptr, TYPE val) \ + { \ + int *wordptr = (int *) ((unsigned long) ptr & ~3); \ + unsigned int mask, shift, oldval, newval; \ + int failure; \ + \ + shift = (((unsigned long) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \ + mask = MASK_##WIDTH << shift; \ + \ + do { \ + oldval = *wordptr; \ + newval = ((PFX_OP ((oldval & mask) >> shift) \ + INF_OP (unsigned int) val) << shift) & mask; \ + newval |= oldval & ~mask; \ + failure = __kernel_cmpxchg (oldval, newval, wordptr); \ + } while (failure != 0); \ + \ + return (RETURN & mask) >> shift; \ + } + +SUBWORD_SYNC_OP (add, , +, short, 2, oldval) +SUBWORD_SYNC_OP (sub, , -, short, 2, oldval) +SUBWORD_SYNC_OP (or, , |, short, 2, oldval) +SUBWORD_SYNC_OP (and, , &, short, 2, oldval) +SUBWORD_SYNC_OP (xor, , ^, short, 2, oldval) +SUBWORD_SYNC_OP (nand, ~, &, short, 2, oldval) + +SUBWORD_SYNC_OP (add, , +, char, 1, oldval) +SUBWORD_SYNC_OP (sub, , -, char, 1, oldval) +SUBWORD_SYNC_OP (or, , |, char, 1, oldval) +SUBWORD_SYNC_OP (and, , &, char, 1, oldval) +SUBWORD_SYNC_OP (xor, , ^, char, 1, oldval) +SUBWORD_SYNC_OP (nand, ~, &, char, 1, oldval) + +#define OP_AND_FETCH_WORD(OP, PFX_OP, INF_OP) \ + int HIDDEN \ + __sync_##OP##_and_fetch_4 (int *ptr, int val) \ + { \ + int tmp, failure; \ + \ + do { \ + tmp = *ptr; \ + failure = __kernel_cmpxchg (tmp, PFX_OP tmp INF_OP val, ptr); \ + } while (failure != 0); \ + \ + return PFX_OP tmp INF_OP val; \ + } + +OP_AND_FETCH_WORD (add, , +) +OP_AND_FETCH_WORD (sub, , -) +OP_AND_FETCH_WORD (or, , |) +OP_AND_FETCH_WORD (and, , &) +OP_AND_FETCH_WORD (xor, , ^) +OP_AND_FETCH_WORD (nand, ~, &) + +SUBWORD_SYNC_OP (add, , +, short, 2, newval) +SUBWORD_SYNC_OP (sub, , -, short, 2, newval) +SUBWORD_SYNC_OP (or, , |, short, 2, newval) +SUBWORD_SYNC_OP (and, , &, short, 2, newval) +SUBWORD_SYNC_OP (xor, , ^, short, 2, newval) +SUBWORD_SYNC_OP (nand, ~, &, short, 2, newval) + +SUBWORD_SYNC_OP (add, , +, char, 1, newval) +SUBWORD_SYNC_OP (sub, , -, char, 1, newval) +SUBWORD_SYNC_OP (or, , |, char, 1, newval) +SUBWORD_SYNC_OP (and, , &, char, 1, newval) +SUBWORD_SYNC_OP (xor, , ^, char, 1, newval) +SUBWORD_SYNC_OP (nand, ~, &, char, 1, newval) + +int HIDDEN +__sync_val_compare_and_swap_4 (int *ptr, int oldval, int newval) +{ + int actual_oldval, fail; + + while (1) + { + actual_oldval = *ptr; + + if (oldval != actual_oldval) + return actual_oldval; + + fail = __kernel_cmpxchg (actual_oldval, newval, ptr); + + if (!fail) + return oldval; + } +} + +#define SUBWORD_VAL_CAS(TYPE, WIDTH) \ + TYPE HIDDEN \ + __sync_val_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval, \ + TYPE newval) \ + { \ + int *wordptr = (int *)((unsigned long) ptr & ~3), fail; \ + unsigned int mask, shift, actual_oldval, actual_newval; \ + \ + shift = (((unsigned long) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \ + mask = MASK_##WIDTH << shift; \ + \ + while (1) \ + { \ + actual_oldval = *wordptr; \ + \ + if (((actual_oldval & mask) >> shift) != (unsigned int) oldval) \ + return (actual_oldval & mask) >> shift; \ + \ + actual_newval = (actual_oldval & ~mask) \ + | (((unsigned int) newval << shift) & mask); \ + \ + fail = __kernel_cmpxchg (actual_oldval, actual_newval, \ + wordptr); \ + \ + if (!fail) \ + return oldval; \ + } \ + } + +SUBWORD_VAL_CAS (short, 2) +SUBWORD_VAL_CAS (char, 1) + +typedef unsigned char bool; + +bool HIDDEN +__sync_bool_compare_and_swap_4 (int *ptr, int oldval, int newval) +{ + int failure = __kernel_cmpxchg (oldval, newval, ptr); + return (failure == 0); +} + +#define SUBWORD_BOOL_CAS(TYPE, WIDTH) \ + bool HIDDEN \ + __sync_bool_compare_and_swap_##WIDTH (TYPE *ptr, TYPE oldval, \ + TYPE newval) \ + { \ + TYPE actual_oldval \ + = __sync_val_compare_and_swap_##WIDTH (ptr, oldval, newval); \ + return (oldval == actual_oldval); \ + } + +SUBWORD_BOOL_CAS (short, 2) +SUBWORD_BOOL_CAS (char, 1) + +int HIDDEN +__sync_lock_test_and_set_4 (int *ptr, int val) +{ + int failure, oldval; + + do { + oldval = *ptr; + failure = __kernel_cmpxchg (oldval, val, ptr); + } while (failure != 0); + + return oldval; +} + +#define SUBWORD_TEST_AND_SET(TYPE, WIDTH) \ + TYPE HIDDEN \ + __sync_lock_test_and_set_##WIDTH (TYPE *ptr, TYPE val) \ + { \ + int failure; \ + unsigned int oldval, newval, shift, mask; \ + int *wordptr = (int *) ((unsigned long) ptr & ~3); \ + \ + shift = (((unsigned long) ptr & 3) << 3) ^ INVERT_MASK_##WIDTH; \ + mask = MASK_##WIDTH << shift; \ + \ + do { \ + oldval = *wordptr; \ + newval = (oldval & ~mask) \ + | (((unsigned int) val << shift) & mask); \ + failure = __kernel_cmpxchg (oldval, newval, wordptr); \ + } while (failure != 0); \ + \ + return (oldval & mask) >> shift; \ + } + +SUBWORD_TEST_AND_SET (short, 2) +SUBWORD_TEST_AND_SET (char, 1) + +#define SYNC_LOCK_RELEASE(TYPE, WIDTH) \ + void HIDDEN \ + __sync_lock_release_##WIDTH (TYPE *ptr) \ + { \ + *ptr = 0; \ + } + +SYNC_LOCK_RELEASE (int, 4) +SYNC_LOCK_RELEASE (short, 2) +SYNC_LOCK_RELEASE (char, 1) Index: gcc-4.1.2/gcc/config/nios2/linux-unwind.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gcc-4.1.2/gcc/config/nios2/linux-unwind.h 2010-06-30 08:50:26.000000000 +0200 @@ -0,0 +1,166 @@ +/* DWARF2 EH unwinding support for NIOS2 Linux. + Copyright (C) 2008 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file with other programs, and to distribute +those programs without any restriction coming from the use of this +file. (The General Public License restrictions do apply in other +respects; for example, they cover modification of the file, and +distribution when not linked into another program.) + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#ifndef inhibit_libc + +/* Do code reading to identify a signal frame, and set the frame + state data appropriately. See unwind-dw2.c for the structs. */ + +#include +#include + +/* Unfortunately the kernel headers define the wrong shape of the + register file, so we define our own version here. This problem has + been reported. */ + +struct nios2_mcontext +{ + int version; /* 2 */ + unsigned seq_regs[23]; /* regs 1..23 */ + unsigned ra; /* Return address, r31 */ + unsigned fp; /* Frame pointer, r28 */ + unsigned gp; /* Global pointer, r26 */ + unsigned pad1; + unsigned ea; /* Exception return address (pc) */ + unsigned sp; /* Stack pointer, r27 */ + unsigned pad2; + /* Note r24, r25, r29, r30 are reserved registers */ +}; + +/* The kernel's definition of this structure also doesn't match + reality. Again, this has been reported. */ + +struct nios2_ucontext { + unsigned long uc_flags; + unsigned pad1; + void *uc_link; + stack_t uc_stack; + struct siginfo info; + struct nios2_mcontext uc_mcontext; +}; + +#define MD_FALLBACK_FRAME_STATE_FOR nios2_fallback_frame_state + +static _Unwind_Reason_Code +nios2_fallback_frame_state (struct _Unwind_Context *context, + _Unwind_FrameState *fs) +{ + u_int32_t *pc = (u_int32_t *) context->ra; + _Unwind_Ptr new_cfa; + int i; + + /* movi r2,(sigreturn/rt_sigreturn) + trap */ + if (pc[1] != 0x003b683a) /* trap */ + return _URC_END_OF_STACK; + +#define NIOS2_REG(NUM,NAME) \ + (fs->regs.reg[NUM].how = REG_SAVED_OFFSET, \ + fs->regs.reg[NUM].loc.offset = (_Unwind_Ptr)®s->NAME - new_cfa) + + if (pc[0] == (0x00800004 | (__NR_sigreturn << 6))) + { + struct sigframe { + u_int32_t trampoline[2]; + u_int32_t pad1; + u_int32_t pad2; + struct sigcontext ctx; + } *rt_ = context->ra; + struct pt_regs *regs = &rt_->ctx.regs; + + /* The CFA is the user's incoming stack pointer value. */ + new_cfa = (_Unwind_Ptr)regs->sp; + fs->cfa_how = CFA_REG_OFFSET; + fs->cfa_reg = STACK_POINTER_REGNUM; + fs->cfa_offset = new_cfa - (_Unwind_Ptr) context->cfa; + + /* Regs 1..15 */ + NIOS2_REG (1, r1); + NIOS2_REG (2, r2); + NIOS2_REG (3, r3); + NIOS2_REG (4, r4); + NIOS2_REG (5, r5); + NIOS2_REG (6, r6); + NIOS2_REG (7, r7); + NIOS2_REG (8, r8); + NIOS2_REG (9, r9); + NIOS2_REG (10, r10); + NIOS2_REG (11, r11); + NIOS2_REG (12, r12); + NIOS2_REG (13, r13); + NIOS2_REG (14, r14); + NIOS2_REG (15, r15); + + /* Regs 16..23 are not saved here. They are callee saved or + special. */ + + /* The random registers. */ + NIOS2_REG (RA_REGNO, ra); + NIOS2_REG (FP_REGNO, fp); + NIOS2_REG (GP_REGNO, gp); + NIOS2_REG (SIGNAL_UNWIND_RETURN_COLUMN, ea); + + fs->retaddr_column = SIGNAL_UNWIND_RETURN_COLUMN; + + return _URC_NO_REASON; + } + else if (pc[0] == (0x00800004 | (__NR_rt_sigreturn << 6))) + { + struct sigframe { + u_int32_t trampoline[2]; + struct nios2_ucontext sigctx; + } *rt_ = context->ra; + struct nios2_mcontext *regs = &rt_->sigctx.uc_mcontext; + + if (regs->version != 2) + return _URC_END_OF_STACK; + + /* The CFA is the user's incoming stack pointer value. */ + new_cfa = (_Unwind_Ptr)regs->sp; + fs->cfa_how = CFA_REG_OFFSET; + fs->cfa_reg = STACK_POINTER_REGNUM; + fs->cfa_offset = new_cfa - (_Unwind_Ptr) context->cfa; + + /* The sequential registers. */ + for (i = 1; i != 24; i++) + NIOS2_REG (i, seq_regs[i-1]); + + /* The random registers. */ + NIOS2_REG (RA_REGNO, ra); + NIOS2_REG (FP_REGNO, fp); + NIOS2_REG (GP_REGNO, gp); + NIOS2_REG (SIGNAL_UNWIND_RETURN_COLUMN, ea); + + fs->retaddr_column = SIGNAL_UNWIND_RETURN_COLUMN; + + return _URC_NO_REASON; + } +#undef NIOS2_REG + return _URC_END_OF_STACK; +} +#endif Index: gcc-4.1.2/gcc/config/nios2/linux.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gcc-4.1.2/gcc/config/nios2/linux.h 2010-06-30 08:50:26.000000000 +0200 @@ -0,0 +1,58 @@ +/* Definitions for Nios II running Linux-based GNU systems with + ELF format. + Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2008 + Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#undef LIB_SPEC +#define LIB_SPEC "-lc \ + %{pthread:-lpthread}" + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC \ +"%{!shared: crt1.o%s} \ + crti.o%s %{static:crtbeginT.o%s;shared|pie:crtbeginS.o%s;:crtbegin.o%s}" + +#undef ENDFILE_SPEC +#define ENDFILE_SPEC \ +"%{shared|pie:crtendS.o%s;:crtend.o%s} crtn.o%s" + +#define TARGET_OS_CPP_BUILTINS() \ + do \ + { \ + LINUX_TARGET_OS_CPP_BUILTINS(); \ + if (flag_pic) \ + { \ + builtin_define ("__PIC__"); \ + builtin_define ("__pic__"); \ + } \ + } \ + while (0) + +#undef SYSROOT_SUFFIX_SPEC +#define SYSROOT_SUFFIX_SPEC \ + "%{EB:/EB}" + +#undef LINK_SPEC +#define LINK_SPEC LINK_SPEC_ENDIAN \ + " %{shared:-shared} \ + %{static:-Bstatic} \ + %{rdynamic:-export-dynamic}" + +#define MD_UNWIND_SUPPORT "config/nios2/linux-unwind.h" Index: gcc-4.1.2/gcc/config/nios2/nios2-protos.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gcc-4.1.2/gcc/config/nios2/nios2-protos.h 2010-06-30 08:50:26.000000000 +0200 @@ -0,0 +1,92 @@ +/* NOT ASSIGNED TO FSF. COPYRIGHT ALTERA. */ +/* Subroutines for assembler code output for Altera NIOS 2G NIOS2 version. + Copyright (C) 2003 Altera + Contributed by Jonah Graham (jgraham@altera.com). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +extern void dump_frame_size (FILE *); +extern HOST_WIDE_INT compute_frame_size (void); +extern int nios2_initial_elimination_offset (int, int); +extern void override_options (void); +extern void optimization_options (int, int); +extern int nios2_can_use_return_insn (void); +extern void expand_prologue (void); +extern void expand_epilogue (bool); +extern void function_profiler (FILE *, int); +extern enum reg_class reg_class_from_constraint (char, const char *); +extern void nios2_register_target_pragmas (void); + +#ifdef RTX_CODE +extern int nios2_legitimate_address (rtx, enum machine_mode, int); +extern int nios2_legitimate_constant (rtx); +extern void nios2_print_operand (FILE *, rtx, int); +extern void nios2_print_operand_address (FILE *, rtx); +extern rtx nios2_legitimize_address (rtx, rtx, enum machine_mode); +extern bool nios2_legitimate_pic_operand_p (rtx); + +extern int nios2_emit_move_sequence (rtx *, enum machine_mode); +extern int nios2_emit_expensive_div (rtx *, enum machine_mode); +extern void nios2_adjust_call_address (rtx *); + +extern rtx nios2_get_return_address (int); +extern void nios2_set_return_address (rtx, rtx); + +extern void gen_int_relational (enum rtx_code, rtx, rtx, rtx, rtx); +extern void gen_conditional_move (rtx *, enum machine_mode); +extern const char *asm_output_opcode (FILE *, const char *); + +/* predicates */ +extern int call_operand (rtx, enum machine_mode); +extern int arith_operand (rtx, enum machine_mode); +extern int uns_arith_operand (rtx, enum machine_mode); +extern int logical_operand (rtx, enum machine_mode); +extern int shift_operand (rtx, enum machine_mode); +extern int reg_or_0_operand (rtx, enum machine_mode); +extern int equality_op (rtx, enum machine_mode); +extern int custom_insn_opcode (rtx, enum machine_mode); +extern int rdwrctl_operand (rtx, enum machine_mode); + +/* custom fpu instruction output */ +extern const char *nios2_output_fpu_insn_cmps (rtx, enum rtx_code); +extern const char *nios2_output_fpu_insn_cmpd (rtx, enum rtx_code); + +# ifdef HAVE_MACHINE_MODES +# if defined TREE_CODE +extern rtx function_arg (const CUMULATIVE_ARGS *, enum machine_mode, tree, int); +extern bool nios2_must_pass_in_stack (enum machine_mode, tree); +extern int function_arg_partial_nregs (const CUMULATIVE_ARGS *, + enum machine_mode, tree, int); +extern void function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode, tree, + int); +extern int nios2_function_arg_padding (enum machine_mode, tree); +extern int nios2_function_arg_padding_upward (enum machine_mode, tree); +extern int nios2_block_reg_padding (enum machine_mode, tree, int); +extern int nios2_block_reg_padding_upward (enum machine_mode, tree, int); +extern void init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree, int); +extern void nios2_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode, + tree, int *, int); + +# endif /* TREE_CODE */ +# endif /* HAVE_MACHINE_MODES */ +#endif + +#ifdef TREE_CODE +extern int nios2_return_in_memory (tree); + +#endif /* TREE_CODE */ Index: gcc-4.1.2/gcc/config/nios2/nios2.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gcc-4.1.2/gcc/config/nios2/nios2.c 2010-06-30 08:52:12.000000000 +0200 @@ -0,0 +1,4937 @@ +/* NOT ASSIGNED TO FSF. COPYRIGHT ALTERA. */ +/* Subroutines for assembler code output for Altera NIOS 2G NIOS2 version. + Copyright (C) 2005 Altera + Contributed by Jonah Graham (jgraham@altera.com), Will Reece (wreece@altera.com), + and Jeff DaSilva (jdasilva@altera.com). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + +#include +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "rtl.h" +#include "tree.h" +#include "tm_p.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "real.h" +#include "insn-config.h" +#include "conditions.h" +#include "output.h" +#include "insn-attr.h" +#include "flags.h" +#include "recog.h" +#include "expr.h" +#include "toplev.h" +#include "basic-block.h" +#include "function.h" +#include "integrate.h" +#include "ggc.h" +#include "reload.h" +#include "debug.h" +#include "optabs.h" +#include "target.h" +#include "target-def.h" +#include "c-pragma.h" /* For c_register_pragma. */ +#include "cpplib.h" /* For CPP_NUMBER. */ +#include "c-tree.h" /* For builtin_function. */ + +/* Local prototypes. */ +static bool nios2_rtx_costs (rtx, int, int, int *); + +static void nios2_asm_function_prologue (FILE *, HOST_WIDE_INT); +static int nios2_issue_rate (void); +static struct machine_function *nios2_init_machine_status (void); +static bool nios2_in_small_data_p (tree); +static void save_reg (int, HOST_WIDE_INT); +static void restore_reg (int, HOST_WIDE_INT); +static unsigned int nios2_section_type_flags (tree, const char *, int); + +/* 0 --> no #pragma seen + 1 --> in scope of #pragma reverse_bitfields + -1 --> in scope of #pragma no_reverse_bitfields. */ +static int nios2_pragma_reverse_bitfields_flag = 0; +static void nios2_pragma_reverse_bitfields (struct cpp_reader *); +static void nios2_pragma_no_reverse_bitfields (struct cpp_reader *); +static tree nios2_handle_struct_attribute (tree *, tree, tree, int, bool *); +static void nios2_insert_attributes (tree, tree *); +static void nios2_load_pic_register (void); +static bool nios2_cannot_force_const_mem (rtx); +bool nios2_legitimate_pic_operand_p (rtx x); +static rtx nios2_legitimize_pic_address (rtx orig, enum machine_mode mode, + rtx reg); +rtx nios2_legitimize_address (rtx x, rtx orig_x, enum machine_mode mode); +static void nios2_init_builtins (void); +static rtx nios2_expand_builtin (tree, rtx, rtx, enum machine_mode, int); +static bool nios2_function_ok_for_sibcall (tree, tree); +static int nios2_arg_partial_bytes (CUMULATIVE_ARGS *cum, + enum machine_mode mode, tree type, + bool named ATTRIBUTE_UNUSED); +static bool nios2_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + tree type, bool named ATTRIBUTE_UNUSED); +static void nios2_encode_section_info (tree, rtx, int); +int nios2_function_arg_padding_upward (enum machine_mode mode, tree type); +int nios2_block_reg_padding_upward (enum machine_mode mode, tree type, + int first ATTRIBUTE_UNUSED); +static void nios2_output_dwarf_dtprel (FILE *fuke, int size, rtx x); + +/* Initialize the GCC target structure. */ +#undef TARGET_ASM_FUNCTION_PROLOGUE +#define TARGET_ASM_FUNCTION_PROLOGUE nios2_asm_function_prologue + +#undef TARGET_DEFAULT_TARGET_FLAGS +#define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT + +#undef TARGET_SCHED_ISSUE_RATE +#define TARGET_SCHED_ISSUE_RATE nios2_issue_rate +#undef TARGET_IN_SMALL_DATA_P +#define TARGET_IN_SMALL_DATA_P nios2_in_small_data_p +#undef TARGET_ENCODE_SECTION_INFO +#define TARGET_ENCODE_SECTION_INFO nios2_encode_section_info +#undef TARGET_SECTION_TYPE_FLAGS +#define TARGET_SECTION_TYPE_FLAGS nios2_section_type_flags + +#undef TARGET_INIT_BUILTINS +#define TARGET_INIT_BUILTINS nios2_init_builtins +#undef TARGET_EXPAND_BUILTIN +#define TARGET_EXPAND_BUILTIN nios2_expand_builtin + +#undef TARGET_FUNCTION_OK_FOR_SIBCALL +#define TARGET_FUNCTION_OK_FOR_SIBCALL nios2_function_ok_for_sibcall + +#undef TARGET_PASS_BY_REFERENCE +#define TARGET_PASS_BY_REFERENCE nios2_pass_by_reference + +#undef TARGET_ARG_PARTIAL_BYTES +#define TARGET_ARG_PARTIAL_BYTES nios2_arg_partial_bytes + +#undef TARGET_PROMOTE_PROTOTYPES +#define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true + +#undef TARGET_SETUP_INCOMING_VARARGS +#define TARGET_SETUP_INCOMING_VARARGS nios2_setup_incoming_varargs + +#undef TARGET_MUST_PASS_IN_STACK +#define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size + +#undef TARGET_RTX_COSTS +#define TARGET_RTX_COSTS nios2_rtx_costs + +#undef TARGET_HAVE_TLS +#define TARGET_HAVE_TLS true + +#undef TARGET_CANNOT_FORCE_CONST_MEM +#define TARGET_CANNOT_FORCE_CONST_MEM nios2_cannot_force_const_mem + +#undef TARGET_ASM_OUTPUT_DWARF_DTPREL +#define TARGET_ASM_OUTPUT_DWARF_DTPREL nios2_output_dwarf_dtprel + +const struct attribute_spec nios2_attribute_table[] = +{ + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ + { "reverse_bitfields", 0, 0, false, false, false, + nios2_handle_struct_attribute }, + { "no_reverse_bitfields", 0, 0, false, false, false, + nios2_handle_struct_attribute }, + { NULL, 0, 0, false, false, false, NULL } +}; + +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE nios2_attribute_table + +#undef TARGET_INSERT_ATTRIBUTES +#define TARGET_INSERT_ATTRIBUTES nios2_insert_attributes + +/* ??? Might want to redefine TARGET_RETURN_IN_MSB here to handle + big-endian case; depends on what ABI we choose. */ + +struct gcc_target targetm = TARGET_INITIALIZER; + + + +/* Threshold for data being put into the small data/bss area, instead + of the normal data area (references to the small data/bss area take + 1 instruction, and use the global pointer, references to the normal + data area takes 2 instructions). */ +unsigned HOST_WIDE_INT nios2_section_threshold = NIOS2_DEFAULT_GVALUE; + +/* Structure to be filled in by compute_frame_size with register + save masks, and offsets for the current function. */ + +struct nios2_frame_info +GTY (()) +{ + unsigned HOST_WIDE_INT save_mask; /* Mask of registers to save */ + long total_size; /* # bytes that the entire frame takes up. */ + long var_size; /* # bytes that variables take up. */ + long args_size; /* # bytes that outgoing arguments take up. */ + int save_reg_size; /* # bytes needed to store gp regs. */ + long save_regs_offset; /* Offset from new sp to store gp registers. */ + int initialized; /* != 0 if frame size already calculated. */ +}; + +struct machine_function +GTY (()) +{ + + /* Current frame information, calculated by compute_frame_size. */ + struct nios2_frame_info frame; +}; + +/* Supported TLS relocations. */ + +enum tls_reloc { + TLS_GD16, + TLS_LDM16, + TLS_LDO16, + TLS_IE16, + TLS_LE16 +}; + +#define IS_UNSPEC_TLS(x) ((x)>=UNSPEC_TLS && (x)<=UNSPEC_ADD_TLS_LDO) + + + +/*************************************** + * Register Classes + ***************************************/ + +enum reg_class +reg_class_from_constraint (char chr, const char *str) +{ + if (chr == 'D' && ISDIGIT (str[1]) && ISDIGIT (str[2])) + { + int regno; + int ones = str[2] - '0'; + int tens = str[1] - '0'; + + regno = ones + (10 * tens); + if (regno < 0 || regno > 31) + return NO_REGS; + + return D00_REG + regno; + } + + return NO_REGS; +} + + +/*************************************** + * Stack Layout and Calling Conventions + ***************************************/ + + +#define TOO_BIG_OFFSET(X) ((X) > ((1 << 15) - 1)) +#define TEMP_REG_NUM 8 + +static void +nios2_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED) +{ + if (flag_verbose_asm || flag_debug_asm) + { + compute_frame_size (); + dump_frame_size (file); + } +} + +static void +save_reg (int regno, HOST_WIDE_INT offset) +{ + rtx reg = gen_rtx_REG (SImode, regno); + rtx addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offset)); + + rtx pattern = gen_rtx_SET (SImode, gen_frame_mem (Pmode, addr), reg); + rtx insn = emit_insn (pattern); + RTX_FRAME_RELATED_P (insn) = 1; +} + +static void +restore_reg (int regno, HOST_WIDE_INT offset) +{ + rtx reg = gen_rtx_REG (SImode, regno); + rtx addr = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offset)); + + rtx pattern = gen_rtx_SET (SImode, reg, gen_frame_mem (Pmode, addr)); + emit_insn (pattern); +} + + +void +expand_prologue (void) +{ + int ix; + HOST_WIDE_INT total_frame_size = compute_frame_size (); + HOST_WIDE_INT sp_offset; /* offset from base_reg to final stack value */ + HOST_WIDE_INT fp_offset; /* offset from base_reg to final fp value */ + HOST_WIDE_INT save_offset; + rtx insn; + unsigned HOST_WIDE_INT save_mask; + + total_frame_size = compute_frame_size (); + + /* Decrement the stack pointer */ + if (TOO_BIG_OFFSET (total_frame_size)) + { + /* We need an intermediary point, this will point at the spill + block */ + insn = emit_insn + (gen_add3_insn (stack_pointer_rtx, + stack_pointer_rtx, + GEN_INT (cfun->machine->frame.save_regs_offset + - total_frame_size))); + RTX_FRAME_RELATED_P (insn) = 1; + + fp_offset = 0; + sp_offset = -cfun->machine->frame.save_regs_offset; + } + else if (total_frame_size) + { + insn = emit_insn (gen_add3_insn (stack_pointer_rtx, + stack_pointer_rtx, + GEN_INT (-total_frame_size))); + RTX_FRAME_RELATED_P (insn) = 1; + fp_offset = cfun->machine->frame.save_regs_offset; + sp_offset = 0; + } + else + fp_offset = sp_offset = 0; + + if (current_function_limit_stack) + emit_insn (gen_stack_overflow_detect_and_trap ()); + + save_offset = fp_offset + cfun->machine->frame.save_reg_size; + save_mask = cfun->machine->frame.save_mask; + + for (ix = 32; ix--;) + if (save_mask & ((unsigned HOST_WIDE_INT)1 << ix)) + { + save_offset -= 4; + save_reg (ix, save_offset); + } + + if (frame_pointer_needed) + { + insn = emit_insn (gen_add3_insn (hard_frame_pointer_rtx, + stack_pointer_rtx, + GEN_INT (fp_offset))); + + RTX_FRAME_RELATED_P (insn) = 1; + } + + if (sp_offset) + { + rtx tmp = gen_rtx_REG (Pmode, TEMP_REG_NUM); + emit_insn (gen_rtx_SET (Pmode, tmp, GEN_INT (sp_offset))); + + insn = emit_insn (gen_add3_insn (stack_pointer_rtx, stack_pointer_rtx, + tmp)); + if (!frame_pointer_needed) + { + /* Attache a note indicating what just happened */ + rtx note = gen_rtx_SET (Pmode, stack_pointer_rtx, + gen_rtx_PLUS (Pmode, stack_pointer_rtx, + GEN_INT (sp_offset))); + REG_NOTES (insn) = alloc_EXPR_LIST (REG_FRAME_RELATED_EXPR, + note, REG_NOTES (insn)); + RTX_FRAME_RELATED_P (insn) = 1; + } + if (current_function_limit_stack) + emit_insn (gen_stack_overflow_detect_and_trap ()); + } + + /* Load the PIC register if needed. */ + if (current_function_uses_pic_offset_table) + nios2_load_pic_register (); + + /* If we are profiling, make sure no instructions are scheduled before + the call to mcount. */ + if (current_function_profile) + emit_insn (gen_blockage ()); +} + +void +expand_epilogue (bool sibcall_p) +{ + rtx insn; + int ix; + HOST_WIDE_INT total_frame_size = compute_frame_size (); + unsigned HOST_WIDE_INT save_mask; + HOST_WIDE_INT sp_adjust; + HOST_WIDE_INT save_offset; + + if (!sibcall_p && nios2_can_use_return_insn ()) + { + insn = emit_jump_insn (gen_return ()); + return; + } + + emit_insn (gen_blockage ()); + + if (frame_pointer_needed) + { + /* Recover the stack pointer. */ + emit_insn (gen_rtx_SET (Pmode, stack_pointer_rtx, + hard_frame_pointer_rtx)); + save_offset = 0; + sp_adjust = total_frame_size - cfun->machine->frame.save_regs_offset; + } + else if (TOO_BIG_OFFSET (total_frame_size)) + { + rtx tmp = gen_rtx_REG (Pmode, TEMP_REG_NUM); + + emit_insn + (gen_rtx_SET + (Pmode, tmp, GEN_INT (cfun->machine->frame.save_regs_offset))); + emit_insn (gen_add3_insn (stack_pointer_rtx, stack_pointer_rtx, tmp)); + save_offset = 0; + sp_adjust = total_frame_size - cfun->machine->frame.save_regs_offset; + } + else + { + save_offset = cfun->machine->frame.save_regs_offset; + sp_adjust = total_frame_size; + } + + save_mask = cfun->machine->frame.save_mask; + save_offset += cfun->machine->frame.save_reg_size; + + for (ix = 32; ix--;) + if (save_mask & ((unsigned HOST_WIDE_INT)1 << ix)) + { + save_offset -= 4; + restore_reg (ix, save_offset); + } + + if (sp_adjust) + emit_insn (gen_add3_insn (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (sp_adjust))); + + /* Add in the __builtin_eh_return stack adjustment. */ + if (current_function_calls_eh_return) + emit_insn (gen_add3_insn (stack_pointer_rtx, + stack_pointer_rtx, + EH_RETURN_STACKADJ_RTX)); + + if (!sibcall_p) + insn = emit_jump_insn + (gen_return_from_epilogue (gen_rtx_REG (Pmode, RA_REGNO))); +} + +/* Implement RETURN_ADDR_RTX. Note, we do not support moving + back to a previous frame. */ +rtx +nios2_get_return_address (int count) +{ + if (count != 0) + return const0_rtx; + + return get_hard_reg_initial_val (Pmode, RA_REGNO); +} + +/* Emit code to change the current function's return address to + ADDRESS. SCRATCH is available as a scratch register, if needed. + ADDRESS and SCRATCH are both word-mode GPRs. */ + +void +nios2_set_return_address (rtx address, rtx scratch) +{ + compute_frame_size (); + if ((cfun->machine->frame.save_mask >> RA_REGNO) & 1) + { + HOST_WIDE_INT offset = cfun->machine->frame.save_reg_size - 4; + rtx base; + + if (frame_pointer_needed) + base = hard_frame_pointer_rtx; + else + { + base = stack_pointer_rtx; + offset += cfun->machine->frame.save_regs_offset; + + if (TOO_BIG_OFFSET (offset)) + { + emit_insn (gen_rtx_SET (Pmode, scratch, GEN_INT (offset))); + emit_insn (gen_add3_insn (scratch, scratch, base)); + base = scratch; + offset = 0; + } + } + if (offset) + base = gen_rtx_PLUS (Pmode, base, GEN_INT (offset)); + emit_insn (gen_rtx_SET (Pmode, gen_rtx_MEM (Pmode, base), address)); + } + else + emit_insn (gen_rtx_SET (Pmode, gen_rtx_REG (Pmode, RA_REGNO), address)); +} + +bool +nios2_function_ok_for_sibcall (tree a ATTRIBUTE_UNUSED, tree b ATTRIBUTE_UNUSED) +{ + return true; +} + + + + + +/* ----------------------- * + * Profiling + * ----------------------- */ + +void +function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED) +{ + fprintf (file, "\tmov\tr8, ra\n"); + if (flag_pic) + { + fprintf (file, "\tnextpc\tr2\n"); + fprintf (file, "\t1: movhi\tr3, %%hiadj(_GLOBAL_OFFSET_TABLE_ - 1b)\n"); + fprintf (file, "\taddi\tr3, r3, %%lo(_GLOBAL_OFFSET_TABLE_ - 1b)\n"); + fprintf (file, "\tadd\tr2, r2, r3\n"); + fprintf (file, "\tldw\tr2, %%call(_mcount)(r2)\n"); + fprintf (file, "\tcallr\tr2\n"); + } + else + fprintf (file, "\tcall\t_mcount\n"); + fprintf (file, "\tmov\tra, r8\n"); +} + + +/*************************************** + * Stack Layout + ***************************************/ + + +void +dump_frame_size (FILE *file) +{ + fprintf (file, "\t%s Current Frame Info\n", ASM_COMMENT_START); + + fprintf (file, "\t%s total_size = %ld\n", ASM_COMMENT_START, + cfun->machine->frame.total_size); + fprintf (file, "\t%s var_size = %ld\n", ASM_COMMENT_START, + cfun->machine->frame.var_size); + fprintf (file, "\t%s args_size = %ld\n", ASM_COMMENT_START, + cfun->machine->frame.args_size); + fprintf (file, "\t%s save_reg_size = %d\n", ASM_COMMENT_START, + cfun->machine->frame.save_reg_size); + fprintf (file, "\t%s initialized = %d\n", ASM_COMMENT_START, + cfun->machine->frame.initialized); + fprintf (file, "\t%s save_regs_offset = %ld\n", ASM_COMMENT_START, + cfun->machine->frame.save_regs_offset); + fprintf (file, "\t%s current_function_is_leaf = %d\n", ASM_COMMENT_START, + current_function_is_leaf); + fprintf (file, "\t%s frame_pointer_needed = %d\n", ASM_COMMENT_START, + frame_pointer_needed); + fprintf (file, "\t%s pretend_args_size = %d\n", ASM_COMMENT_START, + current_function_pretend_args_size); + +} + +/* Return true if RENOG should be saved in a prologue. */ + +static bool +save_reg_p (unsigned regno) +{ + gcc_assert (GP_REGNO_P (regno)); + + if (regs_ever_live[regno] && !call_used_regs[regno]) + return true; + + if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed) + return true; + + if (regno == PIC_OFFSET_TABLE_REGNUM + && current_function_uses_pic_offset_table) + return true; + + if (regno == RA_REGNO && regs_ever_live[RA_REGNO]) + return true; + + return false; +} + +/* Return the bytes needed to compute the frame pointer from the current + stack pointer. */ + +HOST_WIDE_INT +compute_frame_size (void) +{ + unsigned int regno; + HOST_WIDE_INT var_size; /* # of var. bytes allocated */ + HOST_WIDE_INT total_size; /* # bytes that the entire frame takes up. */ + HOST_WIDE_INT save_reg_size; /* # bytes needed to store callee save regs. */ + HOST_WIDE_INT out_args_size; /* # bytes needed for outgoing args. */ + unsigned HOST_WIDE_INT save_mask = 0; + + if (cfun->machine->frame.initialized) + return cfun->machine->frame.total_size; + + save_reg_size = 0; + var_size = STACK_ALIGN (get_frame_size ()); + out_args_size = STACK_ALIGN (current_function_outgoing_args_size); + + total_size = var_size + out_args_size; + + /* Calculate space needed for gp registers. */ + for (regno = 0; GP_REGNO_P (regno); regno++) + if (save_reg_p (regno)) + { + save_mask |= (unsigned HOST_WIDE_INT)1 << regno; + save_reg_size += 4; + } + + /* If we call eh_return, we need to save the EH data registers. */ + if (current_function_calls_eh_return) + { + unsigned i; + unsigned r; + + for (i = 0; (r = EH_RETURN_DATA_REGNO (i)) != INVALID_REGNUM; i++) + if (!(save_mask & (1 << r))) + { + save_mask |= 1 << r; + save_reg_size += 4; + } + } + + save_reg_size = STACK_ALIGN (save_reg_size); + total_size += save_reg_size; + + total_size += STACK_ALIGN (current_function_pretend_args_size); + + /* Save other computed information. */ + cfun->machine->frame.save_mask = save_mask; + cfun->machine->frame.total_size = total_size; + cfun->machine->frame.var_size = var_size; + cfun->machine->frame.args_size = out_args_size; + cfun->machine->frame.save_reg_size = save_reg_size; + cfun->machine->frame.initialized = reload_completed; + + cfun->machine->frame.save_regs_offset = out_args_size + var_size; + + return total_size; +} + + +int +nios2_initial_elimination_offset (int from, int to) +{ + int offset; + + compute_frame_size (); + + /* Set OFFSET to the offset from the stack pointer. */ + switch (from) + { + case FRAME_POINTER_REGNUM: + offset = cfun->machine->frame.args_size; + break; + + case ARG_POINTER_REGNUM: + offset = cfun->machine->frame.total_size; + offset -= current_function_pretend_args_size; + break; + + default: + gcc_unreachable (); + } + + /* If we are asked for the frame pointer offset, then adjust OFFSET + by the offset from the frame pointer to the stack pointer. */ + if (to == HARD_FRAME_POINTER_REGNUM) + offset -= cfun->machine->frame.save_regs_offset; + + return offset; +} + +/* Return nonzero if this function is known to have a null epilogue. + This allows the optimizer to omit jumps to jumps if no stack + was created. */ +int +nios2_can_use_return_insn (void) +{ + if (!reload_completed) + return 0; + + if (regs_ever_live[RA_REGNO] || current_function_profile) + return 0; + + if (cfun->machine->frame.initialized) + return cfun->machine->frame.total_size == 0; + + return compute_frame_size () == 0; +} + + + + + +/* Try to take a bit of tedium out of the __builtin_custom_ + builtin functions, too. */ + +#define NIOS2_FOR_ALL_CUSTOM_BUILTINS \ + NIOS2_DO_BUILTIN (N, n, n ) \ + NIOS2_DO_BUILTIN (NI, ni, nX ) \ + NIOS2_DO_BUILTIN (NF, nf, nX ) \ + NIOS2_DO_BUILTIN (NP, np, nX ) \ + NIOS2_DO_BUILTIN (NII, nii, nXX ) \ + NIOS2_DO_BUILTIN (NIF, nif, nXX ) \ + NIOS2_DO_BUILTIN (NIP, nip, nXX ) \ + NIOS2_DO_BUILTIN (NFI, nfi, nXX ) \ + NIOS2_DO_BUILTIN (NFF, nff, nXX ) \ + NIOS2_DO_BUILTIN (NFP, nfp, nXX ) \ + NIOS2_DO_BUILTIN (NPI, npi, nXX ) \ + NIOS2_DO_BUILTIN (NPF, npf, nXX ) \ + NIOS2_DO_BUILTIN (NPP, npp, nXX ) \ + NIOS2_DO_BUILTIN (IN, in, Xn ) \ + NIOS2_DO_BUILTIN (INI, ini, XnX ) \ + NIOS2_DO_BUILTIN (INF, inf, XnX ) \ + NIOS2_DO_BUILTIN (INP, inp, XnX ) \ + NIOS2_DO_BUILTIN (INII, inii, XnXX ) \ + NIOS2_DO_BUILTIN (INIF, inif, XnXX ) \ + NIOS2_DO_BUILTIN (INIP, inip, XnXX ) \ + NIOS2_DO_BUILTIN (INFI, infi, XnXX ) \ + NIOS2_DO_BUILTIN (INFF, inff, XnXX ) \ + NIOS2_DO_BUILTIN (INFP, infp, XnXX ) \ + NIOS2_DO_BUILTIN (INPI, inpi, XnXX ) \ + NIOS2_DO_BUILTIN (INPF, inpf, XnXX ) \ + NIOS2_DO_BUILTIN (INPP, inpp, XnXX ) \ + NIOS2_DO_BUILTIN (FN, fn, Xn ) \ + NIOS2_DO_BUILTIN (FNI, fni, XnX ) \ + NIOS2_DO_BUILTIN (FNF, fnf, XnX ) \ + NIOS2_DO_BUILTIN (FNP, fnp, XnX ) \ + NIOS2_DO_BUILTIN (FNII, fnii, XnXX ) \ + NIOS2_DO_BUILTIN (FNIF, fnif, XnXX ) \ + NIOS2_DO_BUILTIN (FNIP, fnip, XnXX ) \ + NIOS2_DO_BUILTIN (FNFI, fnfi, XnXX ) \ + NIOS2_DO_BUILTIN (FNFF, fnff, XnXX ) \ + NIOS2_DO_BUILTIN (FNFP, fnfp, XnXX ) \ + NIOS2_DO_BUILTIN (FNPI, fnpi, XnXX ) \ + NIOS2_DO_BUILTIN (FNPF, fnpf, XnXX ) \ + NIOS2_DO_BUILTIN (FNPP, fnpp, XnXX ) \ + NIOS2_DO_BUILTIN (PN, pn, Xn ) \ + NIOS2_DO_BUILTIN (PNI, pni, XnX ) \ + NIOS2_DO_BUILTIN (PNF, pnf, XnX ) \ + NIOS2_DO_BUILTIN (PNP, pnp, XnX ) \ + NIOS2_DO_BUILTIN (PNII, pnii, XnXX ) \ + NIOS2_DO_BUILTIN (PNIF, pnif, XnXX ) \ + NIOS2_DO_BUILTIN (PNIP, pnip, XnXX ) \ + NIOS2_DO_BUILTIN (PNFI, pnfi, XnXX ) \ + NIOS2_DO_BUILTIN (PNFF, pnff, XnXX ) \ + NIOS2_DO_BUILTIN (PNFP, pnfp, XnXX ) \ + NIOS2_DO_BUILTIN (PNPI, pnpi, XnXX ) \ + NIOS2_DO_BUILTIN (PNPF, pnpf, XnXX ) \ + NIOS2_DO_BUILTIN (PNPP, pnpp, XnXX ) + +#undef NIOS2_FPU_INSN +#define NIOS2_FPU_INSN(opt, insn, args) \ +static const char *NIOS2_CONCAT (nios2_output_fpu_insn_, insn) (rtx); \ +static void NIOS2_CONCAT (nios2_pragma_, insn) (struct cpp_reader *); \ +static void NIOS2_CONCAT (nios2_pragma_no_, insn) (struct cpp_reader *); \ +int NIOS2_CONCAT (nios2_custom_, opt) = -1; +NIOS2_FOR_ALL_FPU_INSNS + +nios2_fpu_info nios2_fpu_insns[nios2_fpu_max_insn] = { +#undef NIOS2_FPU_INSN +#define NIOS2_FPU_INSN(opt, insn, args) \ + { NIOS2_STRINGIFY (opt), \ + NIOS2_STRINGIFY (insn), \ + NIOS2_STRINGIFY (args), \ + -1, \ + NIOS2_CONCAT (nios2_output_fpu_insn_, insn), \ + "custom_" NIOS2_STRINGIFY (opt), \ + NIOS2_CONCAT (nios2_pragma_, insn), \ + "no_custom_" NIOS2_STRINGIFY (opt), \ + NIOS2_CONCAT (nios2_pragma_no_, insn), \ + 0, \ + 0, \ + 0, \ + 0, \ + 0, \ + &NIOS2_CONCAT (nios2_custom_, opt) }, + NIOS2_FOR_ALL_FPU_INSNS +}; + +const char *nios2_custom_fpu_cfg_string; + +static const char *builtin_custom_seen[256]; + +static void +nios2_custom_switch (int parameter, int *value, const char *opt) +{ + /* We only document values from 0-255, but we secretly allow -1 so + * that the -mno-custom- switches work. */ + if (parameter != -1) + { + if (parameter < -1 || parameter > 255) + error ("switch `-mcustom-%s' value %ld must be between 0 and 255", + opt, parameter); + *value = (int)parameter; + } +} + +static void +nios2_custom_check_insns (int is_pragma) +{ + int i; + int has_double = 0; + int errors = 0; + const char *ns[256]; + int ps[256]; + + for (i = 0; i < nios2_fpu_max_insn; i++) + if (nios2_fpu_insns[i].is_double && nios2_fpu_insns[i].N >= 0) + has_double = 1; + + if (has_double) + { + for (i = 0; i < nios2_fpu_max_insn; i++) + { + if (nios2_fpu_insns[i].needed_by_double + && nios2_fpu_insns[i].N < 0) + { + if (is_pragma) + error ("either switch `-mcustom-%s' or `#pragma custom_%s' is " + "required for double precision floating point", + nios2_fpu_insns[i].option, + nios2_fpu_insns[i].option); + else + error ("switch `-mcustom-%s' is required for double precision " + "floating point", + nios2_fpu_insns[i].option); + errors = 1; + } + } + } + + /* Warn if the user has certain exotic operations that won't get used + without -funsafe-math-optimizations, See expand_builtin () in + bulitins.c. */ + if (!flag_unsafe_math_optimizations) + { + for (i = 0; i < nios2_fpu_max_insn; i++) + { + if (nios2_fpu_insns[i].needs_unsafe && nios2_fpu_insns[i].N >= 0) + { + warning (0, "%s%s' has no effect unless " + "-funsafe-math-optimizations is specified", + is_pragma ? "`#pragma custom_" : "switch `-mcustom-", + nios2_fpu_insns[i].option); + /* Just one warning per function per compilation unit, please. */ + nios2_fpu_insns[i].needs_unsafe = 0; + } + } + } + + /* Warn if the user is trying to use -mcustom-fmins et. al, that won't + get used without -ffinite-math-only. See fold in fold () in + fold-const.c. */ + if (!flag_finite_math_only) + { + for (i = 0; i < nios2_fpu_max_insn; i++) + { + if (nios2_fpu_insns[i].needs_finite && nios2_fpu_insns[i].N >= 0) + { + warning (0, "%s%s' has no effect unless -ffinite-math-only " + "is specified", + is_pragma ? "`#pragma custom_" : "switch `-mcustom-", + nios2_fpu_insns[i].option); + /* Just one warning per function per compilation unit, please. */ + nios2_fpu_insns[i].needs_finite = 0; + } + } + } + + /* Warn the user about double precision divide braindamage until we + can fix it properly. See the RDIV_EXPR case of expand_expr_real in + expr.c. */ + { + static int warned = 0; + if (flag_unsafe_math_optimizations + && !optimize_size + && nios2_fpu_insns[nios2_fpu_divdf3].N >= 0 + && !warned) + { + warning (0, "%s%s' behaves poorly without -Os", + is_pragma ? "`#pragma custom_" : "switch `-mcustom-", + nios2_fpu_insns[nios2_fpu_divdf3].option); + warned = 1; + } + } + + /* The following bit of voodoo is lifted from the generated file + insn-opinit.c: to allow #pragmas to work properly, we have to tweak + the optab_table manually -- it only gets initialized once after the + switches are handled and before any #pragmas are seen. */ + if (is_pragma) + { + /* Only do this if the optabs have already been defined, not + when we're handling command line switches. */ + addv_optab->handlers[SFmode].insn_code = + add_optab->handlers[SFmode].insn_code = CODE_FOR_nothing; + addv_optab->handlers[DFmode].insn_code = + add_optab->handlers[DFmode].insn_code = CODE_FOR_nothing; + subv_optab->handlers[SFmode].insn_code = + sub_optab->handlers[SFmode].insn_code = CODE_FOR_nothing; + subv_optab->handlers[DFmode].insn_code = + sub_optab->handlers[DFmode].insn_code = CODE_FOR_nothing; + smulv_optab->handlers[SFmode].insn_code = + smul_optab->handlers[SFmode].insn_code = CODE_FOR_nothing; + smulv_optab->handlers[DFmode].insn_code = + smul_optab->handlers[DFmode].insn_code = CODE_FOR_nothing; + sdiv_optab->handlers[SFmode].insn_code = CODE_FOR_nothing; + sdiv_optab->handlers[DFmode].insn_code = CODE_FOR_nothing; + negv_optab->handlers[SFmode].insn_code = + neg_optab->handlers[SFmode].insn_code = CODE_FOR_nothing; + negv_optab->handlers[DFmode].insn_code = + neg_optab->handlers[DFmode].insn_code = CODE_FOR_nothing; + smin_optab->handlers[SFmode].insn_code = CODE_FOR_nothing; + smin_optab->handlers[DFmode].insn_code = CODE_FOR_nothing; + smax_optab->handlers[SFmode].insn_code = CODE_FOR_nothing; + smax_optab->handlers[DFmode].insn_code = CODE_FOR_nothing; + absv_optab->handlers[SFmode].insn_code = + abs_optab->handlers[SFmode].insn_code = CODE_FOR_nothing; + absv_optab->handlers[DFmode].insn_code = + abs_optab->handlers[DFmode].insn_code = CODE_FOR_nothing; + sqrt_optab->handlers[SFmode].insn_code = CODE_FOR_nothing; + sqrt_optab->handlers[DFmode].insn_code = CODE_FOR_nothing; + cos_optab->handlers[SFmode].insn_code = CODE_FOR_nothing; + cos_optab->handlers[DFmode].insn_code = CODE_FOR_nothing; + sin_optab->handlers[SFmode].insn_code = CODE_FOR_nothing; + sin_optab->handlers[DFmode].insn_code = CODE_FOR_nothing; + tan_optab->handlers[SFmode].insn_code = CODE_FOR_nothing; + tan_optab->handlers[DFmode].insn_code = CODE_FOR_nothing; + atan_optab->handlers[SFmode].insn_code = CODE_FOR_nothing; + atan_optab->handlers[DFmode].insn_code = CODE_FOR_nothing; + exp_optab->handlers[SFmode].insn_code = CODE_FOR_nothing; + exp_optab->handlers[DFmode].insn_code = CODE_FOR_nothing; + log_optab->handlers[SFmode].insn_code = CODE_FOR_nothing; + log_optab->handlers[DFmode].insn_code = CODE_FOR_nothing; + sfloat_optab->handlers[SFmode][SImode].insn_code = CODE_FOR_nothing; + sfloat_optab->handlers[DFmode][SImode].insn_code = CODE_FOR_nothing; + ufloat_optab->handlers[SFmode][SImode].insn_code = CODE_FOR_nothing; + ufloat_optab->handlers[DFmode][SImode].insn_code = CODE_FOR_nothing; + sfix_optab->handlers[SImode][SFmode].insn_code = CODE_FOR_nothing; + sfix_optab->handlers[SImode][DFmode].insn_code = CODE_FOR_nothing; + ufix_optab->handlers[SImode][SFmode].insn_code = CODE_FOR_nothing; + ufix_optab->handlers[SImode][DFmode].insn_code = CODE_FOR_nothing; + sext_optab->handlers[DFmode][SFmode].insn_code = CODE_FOR_nothing; + trunc_optab->handlers[SFmode][DFmode].insn_code = CODE_FOR_nothing; + cmp_optab->handlers[SFmode].insn_code = CODE_FOR_nothing; + cmp_optab->handlers[DFmode].insn_code = CODE_FOR_nothing; + + if (HAVE_addsf3) + addv_optab->handlers[SFmode].insn_code = + add_optab->handlers[SFmode].insn_code = CODE_FOR_addsf3; + if (HAVE_adddf3) + addv_optab->handlers[DFmode].insn_code = + add_optab->handlers[DFmode].insn_code = CODE_FOR_adddf3; + if (HAVE_subsf3) + subv_optab->handlers[SFmode].insn_code = + sub_optab->handlers[SFmode].insn_code = CODE_FOR_subsf3; + if (HAVE_subdf3) + subv_optab->handlers[DFmode].insn_code = + sub_optab->handlers[DFmode].insn_code = CODE_FOR_subdf3; + if (HAVE_mulsf3) + smulv_optab->handlers[SFmode].insn_code = + smul_optab->handlers[SFmode].insn_code = CODE_FOR_mulsf3; + if (HAVE_muldf3) + smulv_optab->handlers[DFmode].insn_code = + smul_optab->handlers[DFmode].insn_code = CODE_FOR_muldf3; + if (HAVE_divsf3) + sdiv_optab->handlers[SFmode].insn_code = CODE_FOR_divsf3; + if (HAVE_divdf3) + sdiv_optab->handlers[DFmode].insn_code = CODE_FOR_divdf3; + if (HAVE_negsf2) + negv_optab->handlers[SFmode].insn_code = + neg_optab->handlers[SFmode].insn_code = CODE_FOR_negsf2; + if (HAVE_negdf2) + negv_optab->handlers[DFmode].insn_code = + neg_optab->handlers[DFmode].insn_code = CODE_FOR_negdf2; + if (HAVE_minsf3) + smin_optab->handlers[SFmode].insn_code = CODE_FOR_minsf3; + if (HAVE_mindf3) + smin_optab->handlers[DFmode].insn_code = CODE_FOR_mindf3; + if (HAVE_maxsf3) + smax_optab->handlers[SFmode].insn_code = CODE_FOR_maxsf3; + if (HAVE_maxdf3) + smax_optab->handlers[DFmode].insn_code = CODE_FOR_maxdf3; + if (HAVE_abssf2) + absv_optab->handlers[SFmode].insn_code = + abs_optab->handlers[SFmode].insn_code = CODE_FOR_abssf2; + if (HAVE_absdf2) + absv_optab->handlers[DFmode].insn_code = + abs_optab->handlers[DFmode].insn_code = CODE_FOR_absdf2; + if (HAVE_sqrtsf2) + sqrt_optab->handlers[SFmode].insn_code = CODE_FOR_sqrtsf2; + if (HAVE_sqrtdf2) + sqrt_optab->handlers[DFmode].insn_code = CODE_FOR_sqrtdf2; + if (HAVE_cossf2) + cos_optab->handlers[SFmode].insn_code = CODE_FOR_cossf2; + if (HAVE_cosdf2) + cos_optab->handlers[DFmode].insn_code = CODE_FOR_cosdf2; + if (HAVE_sinsf2) + sin_optab->handlers[SFmode].insn_code = CODE_FOR_sinsf2; + if (HAVE_sindf2) + sin_optab->handlers[DFmode].insn_code = CODE_FOR_sindf2; + if (HAVE_tansf2) + tan_optab->handlers[SFmode].insn_code = CODE_FOR_tansf2; + if (HAVE_tandf2) + tan_optab->handlers[DFmode].insn_code = CODE_FOR_tandf2; + if (HAVE_atansf2) + atan_optab->handlers[SFmode].insn_code = CODE_FOR_atansf2; + if (HAVE_atandf2) + atan_optab->handlers[DFmode].insn_code = CODE_FOR_atandf2; + if (HAVE_expsf2) + exp_optab->handlers[SFmode].insn_code = CODE_FOR_expsf2; + if (HAVE_expdf2) + exp_optab->handlers[DFmode].insn_code = CODE_FOR_expdf2; + if (HAVE_logsf2) + log_optab->handlers[SFmode].insn_code = CODE_FOR_logsf2; + if (HAVE_logdf2) + log_optab->handlers[DFmode].insn_code = CODE_FOR_logdf2; + if (HAVE_floatsisf2) + sfloat_optab->handlers[SFmode][SImode].insn_code = CODE_FOR_floatsisf2; + if (HAVE_floatsidf2) + sfloat_optab->handlers[DFmode][SImode].insn_code = CODE_FOR_floatsidf2; + if (HAVE_floatunssisf2) + ufloat_optab->handlers[SFmode][SImode].insn_code = CODE_FOR_floatunssisf2; + if (HAVE_floatunssidf2) + ufloat_optab->handlers[DFmode][SImode].insn_code = CODE_FOR_floatunssidf2; + if (HAVE_fixsfsi2) + sfix_optab->handlers[SImode][SFmode].insn_code = CODE_FOR_fixsfsi2; + if (HAVE_fixdfsi2) + sfix_optab->handlers[SImode][DFmode].insn_code = CODE_FOR_fixdfsi2; + if (HAVE_fixunssfsi2) + ufix_optab->handlers[SImode][SFmode].insn_code = CODE_FOR_fixunssfsi2; + if (HAVE_fixunsdfsi2) + ufix_optab->handlers[SImode][DFmode].insn_code = CODE_FOR_fixunsdfsi2; + if (HAVE_extendsfdf2) + sext_optab->handlers[DFmode][SFmode].insn_code = CODE_FOR_extendsfdf2; + if (HAVE_truncdfsf2) + trunc_optab->handlers[SFmode][DFmode].insn_code = CODE_FOR_truncdfsf2; + if (HAVE_cmpsf) + cmp_optab->handlers[SFmode].insn_code = CODE_FOR_cmpsf; + if (HAVE_cmpdf) + cmp_optab->handlers[DFmode].insn_code = CODE_FOR_cmpdf; + } + + /* Check for duplicate values of N. */ + for (i = 0; i < 256; i++) + { + ns[i] = 0; + ps[i] = 0; + } + + for (i = 0; i < nios2_fpu_max_insn; i++) + { + int N = nios2_fpu_insns[i].N; + if (N >= 0) + { + if (ns[N]) + { + error ("%s%s' conflicts with %s%s'", + is_pragma ? "`#pragma custom_" : "switch `-mcustom-", + nios2_fpu_insns[i].option, + ps[N] ? "`#pragma custom_" : "switch `-mcustom-", + ns[N]); + errors = 1; + } + else if (builtin_custom_seen[N]) + { + error ("call to `%s' conflicts with %s%s'", + builtin_custom_seen[N], + (nios2_fpu_insns[i].pragma_seen + ? "`#pragma custom_" : "switch `-mcustom-"), + nios2_fpu_insns[i].option); + errors = 1; + } + else + { + ns[N] = nios2_fpu_insns[i].option; + ps[N] = nios2_fpu_insns[i].pragma_seen; + } + } + } + + if (errors) + fatal_error ("conflicting use of -mcustom switches, #pragmas, and/or " + "__builtin_custom_ functions"); +} + +static void +nios2_handle_custom_fpu_cfg (const char *cfg, int is_pragma) +{ +#undef NIOS2_FPU_INSN +#define NIOS2_FPU_INSN(opt, insn, args) \ + int opt = nios2_fpu_insns[NIOS2_CONCAT (nios2_fpu_, insn)].N; +NIOS2_FOR_ALL_FPU_INSNS + + /* + * ??? These are just some sample possibilities. We'll change these + * at the last minute to match the capabilities of the actual fpu. + */ + if (!strcasecmp (cfg, "60-1")) + { + fmuls = 252; + fadds = 253; + fsubs = 254; + flag_single_precision_constant = 1; + } + else if (!strcasecmp (cfg, "60-2")) + { + fmuls = 252; + fadds = 253; + fsubs = 254; + fdivs = 255; + flag_single_precision_constant = 1; + } + else if (!strcasecmp (cfg, "72-3")) + { + floatus = 243; + fixsi = 244; + floatis = 245; + fcmpgts = 246; + fcmples = 249; + fcmpeqs = 250; + fcmpnes = 251; + fmuls = 252; + fadds = 253; + fsubs = 254; + fdivs = 255; + flag_single_precision_constant = 1; + } + else + warning (0, "ignoring unrecognized %sfpu-cfg' value `%s'", + is_pragma ? "`#pragma custom_" : "switch -mcustom-", cfg); + +#undef NIOS2_FPU_INSN +#define NIOS2_FPU_INSN(opt, insn, args) \ + nios2_fpu_insns[NIOS2_CONCAT (nios2_fpu_, insn)].N = opt; +NIOS2_FOR_ALL_FPU_INSNS + + /* Guard against errors in the standard configurations. */ + nios2_custom_check_insns (is_pragma); +} + +void +override_options (void) +{ + int i; + + /* Function to allocate machine-dependent function status. */ + init_machine_status = &nios2_init_machine_status; + + nios2_section_threshold + = g_switch_set ? g_switch_value : NIOS2_DEFAULT_GVALUE; + + /* If we don't have mul, we don't have mulx either! */ + if (!TARGET_HAS_MUL && TARGET_HAS_MULX) + target_flags &= ~MASK_HAS_MULX; + + /* Set up for stack limit checking. */ + if (TARGET_STACK_CHECK) + stack_limit_rtx = gen_rtx_REG(SImode, ET_REGNO); + + for (i = 0; i < nios2_fpu_max_insn; i++) + { + nios2_fpu_insns[i].is_double = (nios2_fpu_insns[i].args[0] == 'd' + || nios2_fpu_insns[i].args[0] == 'd' + || nios2_fpu_insns[i].args[0] == 'd'); + nios2_fpu_insns[i].needed_by_double = (i == nios2_fpu_nios2_fwrx + || i == nios2_fpu_nios2_fwry + || i == nios2_fpu_nios2_frdxlo + || i == nios2_fpu_nios2_frdxhi + || i == nios2_fpu_nios2_frdy); + nios2_fpu_insns[i].needs_unsafe = (i == nios2_fpu_cossf2 + || i == nios2_fpu_cosdf2 + || i == nios2_fpu_sinsf2 + || i == nios2_fpu_sindf2 + || i == nios2_fpu_tansf2 + || i == nios2_fpu_tandf2 + || i == nios2_fpu_atansf2 + || i == nios2_fpu_atandf2 + || i == nios2_fpu_expsf2 + || i == nios2_fpu_expdf2 + || i == nios2_fpu_logsf2 + || i == nios2_fpu_logdf2); + nios2_fpu_insns[i].needs_finite = (i == nios2_fpu_minsf3 + || i == nios2_fpu_maxsf3 + || i == nios2_fpu_mindf3 + || i == nios2_fpu_maxdf3); + } + + /* We haven't seen any __builtin_custom functions yet. */ + for (i = 0; i < 256; i++) + builtin_custom_seen[i] = 0; + + /* Set up default handling for floating point custom instructions. + + Putting things in this order means that the -mcustom-fpu-cfg= + switch will always be overridden by individual -mcustom-fadds= + switches, regardless of the order in which they were specified + on the command line. ??? Remember to document this. */ + if (nios2_custom_fpu_cfg_string && *nios2_custom_fpu_cfg_string) + nios2_handle_custom_fpu_cfg (nios2_custom_fpu_cfg_string, 0); + + for (i = 0; i < nios2_fpu_max_insn; i++) + nios2_custom_switch (*nios2_fpu_insns[i].pN, + &nios2_fpu_insns[i].N, + nios2_fpu_insns[i].option); + + nios2_custom_check_insns (0); +} + +void +optimization_options (int level, int size) +{ + if (level || size) + target_flags |= MASK_INLINE_MEMCPY; + + if (level >= 3 && !size) + target_flags |= MASK_FAST_SW_DIV; +} + +/* Allocate a chunk of memory for per-function machine-dependent data. */ +static struct machine_function * +nios2_init_machine_status (void) +{ + return ((struct machine_function *) + ggc_alloc_cleared (sizeof (struct machine_function))); +} + + + +/***************** + * Describing Relative Costs of Operations + *****************/ + +/* Compute a (partial) cost for rtx X. Return true if the complete + cost has been computed, and false if subexpressions should be + scanned. In either case, *TOTAL contains the cost result. */ + + + +static bool +nios2_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total) +{ + switch (code) + { + case CONST_INT: + if (INTVAL (x) == 0) + { + *total = COSTS_N_INSNS (0); + return true; + } + else if (SMALL_INT (INTVAL (x)) + || SMALL_INT_UNSIGNED (INTVAL (x)) + || UPPER16_INT (INTVAL (x))) + { + *total = COSTS_N_INSNS (2); + return true; + } + else + { + *total = COSTS_N_INSNS (4); + return true; + } + + case LABEL_REF: + case SYMBOL_REF: + /* ??? gp relative stuff will fit in here. */ + /* fall through */ + case CONST: + case CONST_DOUBLE: + { + *total = COSTS_N_INSNS (4); + return true; + } + + case MULT: + { + *total = COSTS_N_INSNS (1); + return false; + } + case SIGN_EXTEND: + { + *total = COSTS_N_INSNS (3); + return false; + } + case ZERO_EXTEND: + { + *total = COSTS_N_INSNS (1); + return false; + } + + default: + return false; + } +} + + +/*************************************** + * INSTRUCTION SUPPORT + * + * These functions are used within the Machine Description to + * handle common or complicated output and expansions from + * instructions. + ***************************************/ + +/* Return TRUE if X references a SYMBOL_REF. */ +static int +symbol_mentioned_p (rtx x) +{ + const char * fmt; + int i; + + if (GET_CODE (x) == SYMBOL_REF) + return 1; + + /* UNSPEC_TLS entries for a symbol include the SYMBOL_REF, but they + are constant offsets, not symbols. */ + if (GET_CODE (x) == UNSPEC && IS_UNSPEC_TLS (XINT (x, 1))) + return 0; + + fmt = GET_RTX_FORMAT (GET_CODE (x)); + + for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) + { + if (fmt[i] == 'E') + { + int j; + + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + if (symbol_mentioned_p (XVECEXP (x, i, j))) + return 1; + } + else if (fmt[i] == 'e' && symbol_mentioned_p (XEXP (x, i))) + return 1; + } + + return 0; +} + +/* Return TRUE if X references a LABEL_REF. */ +static int +label_mentioned_p (rtx x) +{ + const char * fmt; + int i; + + if (GET_CODE (x) == LABEL_REF) + return 1; + + /* UNSPEC_TLS entries for a symbol include a LABEL_REF for the referencing + instruction, but they are constant offsets, not symbols. */ + if (GET_CODE (x) == UNSPEC && IS_UNSPEC_TLS (XINT (x, 1))) + return 0; + + fmt = GET_RTX_FORMAT (GET_CODE (x)); + for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) + { + if (fmt[i] == 'E') + { + int j; + + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + if (label_mentioned_p (XVECEXP (x, i, j))) + return 1; + } + else if (fmt[i] == 'e' && label_mentioned_p (XEXP (x, i))) + return 1; + } + + return 0; +} + +static int +tls_mentioned_p (rtx x) +{ + switch (GET_CODE (x)) + { + case CONST: + return tls_mentioned_p (XEXP (x, 0)); + + case UNSPEC: + if (IS_UNSPEC_TLS (XINT (x, 1))) + return 1; + + default: + return 0; + } +} + +/* Helper for nios2_tls_referenced_p. */ + +static int +nios2_tls_operand_p_1 (rtx *x, void *data ATTRIBUTE_UNUSED) +{ + if (GET_CODE (*x) == SYMBOL_REF) + return SYMBOL_REF_TLS_MODEL (*x) != 0; + + /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are + TLS offsets, not real symbol references. */ + if (GET_CODE (*x) == UNSPEC + && IS_UNSPEC_TLS (XINT (*x, 1))) + return -1; + + return 0; +} + +/* Return TRUE if X contains any TLS symbol references. */ + +static bool +nios2_tls_referenced_p (rtx x) +{ + if (! TARGET_HAVE_TLS) + return false; + + return for_each_rtx (&x, nios2_tls_operand_p_1, NULL); +} + +static bool +nios2_cannot_force_const_mem (rtx x) +{ + return nios2_tls_referenced_p (x); +} + +/* Emit a call to __tls_get_addr. TI is the argument to this function. RET is + an RTX for the return value location. The entire insn sequence is + returned. */ + +static GTY(()) rtx nios2_tls_symbol; + +static rtx +nios2_call_tls_get_addr (rtx ti) +{ + rtx arg = gen_rtx_REG (Pmode, FIRST_ARG_REGNO); + rtx ret = gen_rtx_REG (Pmode, FIRST_RETVAL_REGNO); + rtx fn, insn; + + if (!nios2_tls_symbol) + nios2_tls_symbol = init_one_libfunc ("__tls_get_addr"); + + emit_insn (gen_rtx_SET (Pmode, arg, ti)); + fn = gen_rtx_MEM (QImode, nios2_tls_symbol); + insn = emit_call_insn (gen_call_value (ret, fn, const0_rtx)); + CONST_OR_PURE_CALL_P (insn) = 1; + use_reg (&CALL_INSN_FUNCTION_USAGE (insn), ret); + use_reg (&CALL_INSN_FUNCTION_USAGE (insn), arg); + + return ret; +} + +/* Generate the code to access LOC, a thread local SYMBOL_REF. The + return value will be a valid address and move_operand (either a REG + or a LO_SUM). */ + +static rtx +nios2_legitimize_tls_address (rtx loc) +{ + rtx dest = gen_reg_rtx (Pmode); + rtx ret, tmp1; + enum tls_model model = SYMBOL_REF_TLS_MODEL (loc); + + switch (model) + { + case TLS_MODEL_GLOBAL_DYNAMIC: + tmp1 = gen_reg_rtx (Pmode); + emit_insn (gen_add_tls_gd (tmp1, pic_offset_table_rtx, loc)); + current_function_uses_pic_offset_table = 1; + ret = nios2_call_tls_get_addr (tmp1); + emit_insn (gen_rtx_SET (Pmode, dest, ret)); + break; + + case TLS_MODEL_LOCAL_DYNAMIC: + tmp1 = gen_reg_rtx (Pmode); + emit_insn (gen_add_tls_ldm (tmp1, pic_offset_table_rtx, loc)); + current_function_uses_pic_offset_table = 1; + ret = nios2_call_tls_get_addr (tmp1); + + emit_insn (gen_add_tls_ldo (dest, ret, loc)); + + break; + + case TLS_MODEL_INITIAL_EXEC: + tmp1 = gen_reg_rtx (Pmode); + emit_insn (gen_load_tls_ie (tmp1, pic_offset_table_rtx, loc)); + current_function_uses_pic_offset_table = 1; + emit_insn (gen_add3_insn (dest, + gen_rtx_REG (Pmode, THREAD_POINTER_REGNUM), + tmp1)); + break; + + case TLS_MODEL_LOCAL_EXEC: + emit_insn (gen_add_tls_le (dest, + gen_rtx_REG (Pmode, THREAD_POINTER_REGNUM), + loc)); + break; + + default: + gcc_unreachable (); + } + + return dest; +} + +int +nios2_emit_move_sequence (rtx *operands, enum machine_mode mode) +{ + rtx to = operands[0]; + rtx from = operands[1]; + + if (!register_operand (to, mode) && !reg_or_0_operand (from, mode)) + { + if (no_new_pseudos) + internal_error ("Trying to force_reg no_new_pseudos == 1"); + from = copy_to_mode_reg (mode, from); + } + + /* Recognize the case where from is a reference to thread-local + data and load its address to a register. */ + if (nios2_tls_referenced_p (from)) + { + rtx tmp = from; + rtx addend = NULL; + + if (GET_CODE (tmp) == CONST && GET_CODE (XEXP (tmp, 0)) == PLUS) + { + addend = XEXP (XEXP (tmp, 0), 1); + tmp = XEXP (XEXP (tmp, 0), 0); + } + + gcc_assert (GET_CODE (tmp) == SYMBOL_REF); + gcc_assert (SYMBOL_REF_TLS_MODEL (tmp) != 0); + + tmp = nios2_legitimize_tls_address (tmp); + if (addend) + { + tmp = gen_rtx_PLUS (SImode, tmp, addend); + tmp = force_operand (tmp, to); + } + from = tmp; + } + else if (flag_pic && (CONSTANT_P (from) || symbol_mentioned_p (from) || + label_mentioned_p (from))) + from = nios2_legitimize_pic_address (from, SImode, + (no_new_pseudos ? to : 0)); + + operands[0] = to; + operands[1] = from; + return 0; +} + +/* Divide Support */ + +/* + If -O3 is used, we want to output a table lookup for + divides between small numbers (both num and den >= 0 + and < 0x10). The overhead of this method in the worse + case is 40 bytes in the text section (10 insns) and + 256 bytes in the data section. Additional divides do + not incur additional penalties in the data section. + + Code speed is improved for small divides by about 5x + when using this method in the worse case (~9 cycles + vs ~45). And in the worse case divides not within the + table are penalized by about 10% (~5 cycles vs ~45). + However in the typical case the penalty is not as bad + because doing the long divide in only 45 cycles is + quite optimistic. + + ??? It would be nice to have some benchmarks other + than Dhrystone to back this up. + + This bit of expansion is to create this instruction + sequence as rtl. + or $8, $4, $5 + slli $9, $4, 4 + cmpgeui $3, $8, 16 + beq $3, $0, .L3 + or $10, $9, $5 + add $12, $11, divide_table + ldbu $2, 0($12) + br .L1 +.L3: + call slow_div +.L1: +# continue here with result in $2 + + ??? Ideally I would like the emit libcall block to contain + all of this code, but I don't know how to do that. What it + means is that if the divide can be eliminated, it may not + completely disappear. + + ??? The __divsi3_table label should ideally be moved out + of this block and into a global. If it is placed into the + sdata section we can save even more cycles by doing things + gp relative. +*/ +int +nios2_emit_expensive_div (rtx *operands, enum machine_mode mode) +{ + rtx or_result, shift_left_result; + rtx lookup_value; + rtx lab1, lab3; + rtx insns; + rtx libfunc; + rtx final_result; + rtx tmp; + + /* It may look a little generic, but only SImode + is supported for now. */ + gcc_assert (mode == SImode); + + libfunc = sdiv_optab->handlers[(int) SImode].libfunc; + + + + lab1 = gen_label_rtx (); + lab3 = gen_label_rtx (); + + or_result = expand_simple_binop (SImode, IOR, + operands[1], operands[2], + 0, 0, OPTAB_LIB_WIDEN); + + emit_cmp_and_jump_insns (or_result, GEN_INT (15), GTU, 0, + GET_MODE (or_result), 0, lab3); + JUMP_LABEL (get_last_insn ()) = lab3; + + shift_left_result = expand_simple_binop (SImode, ASHIFT, + operands[1], GEN_INT (4), + 0, 0, OPTAB_LIB_WIDEN); + + lookup_value = expand_simple_binop (SImode, IOR, + shift_left_result, operands[2], + 0, 0, OPTAB_LIB_WIDEN); + + convert_move (operands[0], + gen_rtx_MEM (QImode, + gen_rtx_PLUS (SImode, + lookup_value, + gen_rtx_SYMBOL_REF (SImode, "__divsi3_table"))), + 1); + + + tmp = emit_jump_insn (gen_jump (lab1)); + JUMP_LABEL (tmp) = lab1; + emit_barrier (); + + emit_label (lab3); + LABEL_NUSES (lab3) = 1; + + start_sequence (); + final_result = emit_library_call_value (libfunc, NULL_RTX, + LCT_CONST, SImode, 2, + operands[1], SImode, + operands[2], SImode); + + + insns = get_insns (); + end_sequence (); + emit_libcall_block (insns, operands[0], final_result, + gen_rtx_DIV (SImode, operands[1], operands[2])); + + emit_label (lab1); + LABEL_NUSES (lab1) = 1; + return 1; +} + +/* The function with address *ADDR is being called. If the address + needs to be loaded from the GOT, emit the instruction to do so and + update *ADDR to point to the rtx for the loaded value. */ + +void +nios2_adjust_call_address (rtx *addr) +{ + if (flag_pic + && (GET_CODE (*addr) == SYMBOL_REF || GET_CODE (*addr) == LABEL_REF)) + { + rtx addr_orig; + current_function_uses_pic_offset_table = 1; + addr_orig = *addr; + *addr = gen_reg_rtx (GET_MODE (addr_orig)); + emit_insn (gen_pic_load_call_addr (*addr, + pic_offset_table_rtx, addr_orig)); + } +} + +/* Branches/Compares. */ + +/* The way of handling branches/compares + in gcc is heavily borrowed from MIPS. */ + +enum internal_test +{ + ITEST_EQ, + ITEST_NE, + ITEST_GT, + ITEST_GE, + ITEST_LT, + ITEST_LE, + ITEST_GTU, + ITEST_GEU, + ITEST_LTU, + ITEST_LEU, + ITEST_MAX +}; + +static enum internal_test map_test_to_internal_test (enum rtx_code); + +/* Cached operands, and operator to compare for use in set/branch/trap + on condition codes. */ +rtx branch_cmp[2]; +enum cmp_type branch_type; + +/* Make normal rtx_code into something we can index from an array. */ + +static enum internal_test +map_test_to_internal_test (enum rtx_code test_code) +{ + enum internal_test test = ITEST_MAX; + + switch (test_code) + { + case EQ: + test = ITEST_EQ; + break; + case NE: + test = ITEST_NE; + break; + case GT: + test = ITEST_GT; + break; + case GE: + test = ITEST_GE; + break; + case LT: + test = ITEST_LT; + break; + case LE: + test = ITEST_LE; + break; + case GTU: + test = ITEST_GTU; + break; + case GEU: + test = ITEST_GEU; + break; + case LTU: + test = ITEST_LTU; + break; + case LEU: + test = ITEST_LEU; + break; + default: + break; + } + + return test; +} + +bool have_nios2_fpu_cmp_insn( enum rtx_code cond_t, enum cmp_type cmp_t ); +enum rtx_code get_reverse_cond(enum rtx_code cond_t); + +bool +have_nios2_fpu_cmp_insn( enum rtx_code cond_t, enum cmp_type cmp_t ) +{ + if (cmp_t == CMP_SF) + { + switch (cond_t) + { + case EQ: + return (nios2_fpu_insns[nios2_fpu_nios2_seqsf].N >= 0); + case NE: + return (nios2_fpu_insns[nios2_fpu_nios2_snesf].N >= 0); + case GT: + return (nios2_fpu_insns[nios2_fpu_nios2_sgtsf].N >= 0); + case GE: + return (nios2_fpu_insns[nios2_fpu_nios2_sgesf].N >= 0); + case LT: + return (nios2_fpu_insns[nios2_fpu_nios2_sltsf].N >= 0); + case LE: + return (nios2_fpu_insns[nios2_fpu_nios2_slesf].N >= 0); + default: + break; + } + } + else if (cmp_t == CMP_DF) + { + switch (cond_t) + { + case EQ: + return (nios2_fpu_insns[nios2_fpu_nios2_seqdf].N >= 0); + case NE: + return (nios2_fpu_insns[nios2_fpu_nios2_snedf].N >= 0); + case GT: + return (nios2_fpu_insns[nios2_fpu_nios2_sgtdf].N >= 0); + case GE: + return (nios2_fpu_insns[nios2_fpu_nios2_sgedf].N >= 0); + case LT: + return (nios2_fpu_insns[nios2_fpu_nios2_sltdf].N >= 0); + case LE: + return (nios2_fpu_insns[nios2_fpu_nios2_sledf].N >= 0); + default: + break; + } + } + + return false; +} + +/* Note that get_reverse_cond() is not the same as get_inverse_cond() + get_reverse_cond() means that if the operand order is reversed, + what is the operand that is needed to generate the same condition? */ +enum rtx_code +get_reverse_cond(enum rtx_code cond_t) +{ + switch (cond_t) + { + case GT: return LT; + case GE: return LE; + case LT: return GT; + case LE: return GE; + case GTU: return LTU; + case GEU: return LEU; + case LTU: return GTU; + case LEU: return GEU; + default: break; + } + + return cond_t; +} + + +/* Generate the code to compare (and possibly branch) two integer values + TEST_CODE is the comparison code we are trying to emulate + (or implement directly) + RESULT is where to store the result of the comparison, + or null to emit a branch + CMP0 CMP1 are the two comparison operands + DESTINATION is the destination of the branch, or null to only compare. */ + +void +gen_int_relational (enum rtx_code test_code, /* Relational test (EQ, etc). */ + rtx result, /* Result to store comp. or 0 if branch. */ + rtx cmp0, /* First operand to compare. */ + rtx cmp1, /* Second operand to compare. */ + rtx destination) /* Destination of the branch, + or 0 if compare. */ +{ + struct cmp_info + { + /* For register (or 0) compares. */ + enum rtx_code test_code_reg; /* Code to use in instruction (LT vs. LTU). */ + int reverse_regs; /* Reverse registers in test. */ + + /* for immediate compares */ + enum rtx_code test_code_const; /* Code to use in instruction (LT vs. LTU). */ + int const_low; /* Low bound of constant we can accept. */ + int const_high; /* High bound of constant we can accept. */ + int const_add; /* Constant to add. */ + + /* generic info */ + int unsignedp; /* != 0 for unsigned comparisons. */ + }; + + static const struct cmp_info info[(int) ITEST_MAX] = { + + {EQ, 0, EQ, -32768, 32767, 0, 0}, /* EQ */ + {NE, 0, NE, -32768, 32767, 0, 0}, /* NE */ + + {LT, 1, GE, -32769, 32766, 1, 0}, /* GT */ + {GE, 0, GE, -32768, 32767, 0, 0}, /* GE */ + {LT, 0, LT, -32768, 32767, 0, 0}, /* LT */ + {GE, 1, LT, -32769, 32766, 1, 0}, /* LE */ + + {LTU, 1, GEU, 0, 65534, 1, 0}, /* GTU */ + {GEU, 0, GEU, 0, 65535, 0, 0}, /* GEU */ + {LTU, 0, LTU, 0, 65535, 0, 0}, /* LTU */ + {GEU, 1, LTU, 0, 65534, 1, 0}, /* LEU */ + }; + + enum internal_test test; + enum machine_mode mode; + const struct cmp_info *p_info; + int branch_p; + + + test = map_test_to_internal_test (test_code); + gcc_assert (test != ITEST_MAX); + + p_info = &info[(int) test]; + + mode = GET_MODE (cmp0); + if (mode == VOIDmode) + mode = GET_MODE (cmp1); + + branch_p = (destination != 0); + + /* Handle floating point comparison directly. */ + if (branch_type == CMP_SF || branch_type == CMP_DF) + { + + bool reverse_operands = false; + + enum machine_mode float_mode = (branch_type == CMP_SF) ? SFmode : DFmode; + + gcc_assert (register_operand (cmp0, float_mode) && + register_operand (cmp1, float_mode)); + + if (branch_p) + { + test_code = p_info->test_code_reg; + reverse_operands = (p_info->reverse_regs); + } + + if (!have_nios2_fpu_cmp_insn(test_code, branch_type) && + have_nios2_fpu_cmp_insn(get_reverse_cond(test_code), branch_type) ) + { + test_code = get_reverse_cond(test_code); + reverse_operands = !reverse_operands; + } + + if (reverse_operands) + { + rtx temp = cmp0; + cmp0 = cmp1; + cmp1 = temp; + } + + if (branch_p) + { + rtx cond = gen_rtx_fmt_ee (test_code, SImode, cmp0, cmp1); + rtx label = gen_rtx_LABEL_REF (VOIDmode, destination); + rtx insn = gen_rtx_SET (VOIDmode, pc_rtx, + gen_rtx_IF_THEN_ELSE (VOIDmode, + cond, label, pc_rtx)); + emit_jump_insn (insn); + } + else + emit_move_insn (result, gen_rtx_fmt_ee (test_code, SImode, cmp0, + cmp1)); + return; + } + + /* We can't, under any circumstances, have const_ints in cmp0 + ??? Actually we could have const0. */ + if (GET_CODE (cmp0) == CONST_INT) + cmp0 = force_reg (mode, cmp0); + + /* If the comparison is against an int not in legal range + move it into a register. */ + if (GET_CODE (cmp1) == CONST_INT) + { + HOST_WIDE_INT value = INTVAL (cmp1); + + if (value < p_info->const_low || value > p_info->const_high) + cmp1 = force_reg (mode, cmp1); + } + + /* Comparison to constants, may involve adding 1 to change a GT into GE. + Comparison between two registers, may involve switching operands. */ + if (GET_CODE (cmp1) == CONST_INT) + { + if (p_info->const_add != 0) + { + HOST_WIDE_INT new = INTVAL (cmp1) + p_info->const_add; + + /* If modification of cmp1 caused overflow, + we would get the wrong answer if we follow the usual path; + thus, x > 0xffffffffU would turn into x > 0U. */ + gcc_assert ((p_info->unsignedp + ? (unsigned HOST_WIDE_INT) new > + (unsigned HOST_WIDE_INT) INTVAL (cmp1) + : new > INTVAL (cmp1)) == (p_info->const_add > 0)); + + cmp1 = GEN_INT (new); + } + } + + else if (p_info->reverse_regs) + { + rtx temp = cmp0; + cmp0 = cmp1; + cmp1 = temp; + } + + + + if (branch_p) + { + if (register_operand (cmp0, mode) && register_operand (cmp1, mode)) + { + rtx insn; + rtx cond = gen_rtx_fmt_ee (p_info->test_code_reg, mode, cmp0, cmp1); + rtx label = gen_rtx_LABEL_REF (VOIDmode, destination); + + insn = gen_rtx_SET (VOIDmode, pc_rtx, + gen_rtx_IF_THEN_ELSE (VOIDmode, + cond, label, pc_rtx)); + emit_jump_insn (insn); + } + else + { + rtx cond, label; + + result = gen_reg_rtx (mode); + + emit_move_insn (result, + gen_rtx_fmt_ee (p_info->test_code_const, mode, cmp0, + cmp1)); + + cond = gen_rtx_NE (mode, result, const0_rtx); + label = gen_rtx_LABEL_REF (VOIDmode, destination); + + emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, + gen_rtx_IF_THEN_ELSE (VOIDmode, + cond, + label, pc_rtx))); + } + } + else + { + if (register_operand (cmp0, mode) && register_operand (cmp1, mode)) + emit_move_insn (result, + gen_rtx_fmt_ee (p_info->test_code_reg, mode, cmp0, cmp1)); + else + emit_move_insn (result, + gen_rtx_fmt_ee (p_info->test_code_const, mode, cmp0, + cmp1)); + } + +} + + +/* ??? For now conditional moves are only supported + when the mode of the operands being compared are + the same as the ones being moved. */ + +void +gen_conditional_move (rtx *operands, enum machine_mode mode) +{ + rtx insn, cond; + rtx cmp_reg = gen_reg_rtx (mode); + enum rtx_code cmp_code = GET_CODE (operands[1]); + enum rtx_code move_code = EQ; + + /* Emit a comparison if it is not "simple". + Simple comparisons are X eq 0 and X ne 0. */ + if ((cmp_code == EQ || cmp_code == NE) && branch_cmp[1] == const0_rtx) + { + cmp_reg = branch_cmp[0]; + move_code = cmp_code; + } + else if ((cmp_code == EQ || cmp_code == NE) && branch_cmp[0] == const0_rtx) + { + cmp_reg = branch_cmp[1]; + move_code = cmp_code == EQ ? NE : EQ; + } + else + gen_int_relational (cmp_code, cmp_reg, branch_cmp[0], branch_cmp[1], + NULL_RTX); + + cond = gen_rtx_fmt_ee (move_code, VOIDmode, cmp_reg, CONST0_RTX (mode)); + insn = gen_rtx_SET (mode, operands[0], + gen_rtx_IF_THEN_ELSE (mode, + cond, operands[2], operands[3])); + emit_insn (insn); +} + +/******************* + * Addressing Modes + *******************/ + +int +nios2_legitimate_constant (rtx x) +{ + switch (GET_CODE (x)) + { + case SYMBOL_REF: + return !SYMBOL_REF_TLS_MODEL (x); + case CONST: + { + rtx op = XEXP (x, 0); + if (GET_CODE (op) != PLUS) + return false; + return nios2_legitimate_constant (XEXP (op, 0)) + && nios2_legitimate_constant (XEXP (op, 1)); + } + default: + return true; + } +} + +int +nios2_legitimate_address (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED, + int strict) +{ + int ret_val = 0; + + switch (GET_CODE (operand)) + { + /* direct. */ + case SYMBOL_REF: + if (SYMBOL_REF_TLS_MODEL (operand)) + break; + + if (SYMBOL_REF_IN_NIOS2_SMALL_DATA_P (operand)) + { + ret_val = 1; + break; + } + /* else, fall through */ + case LABEL_REF: + case CONST_INT: + case CONST: + case CONST_DOUBLE: + /* ??? In here I need to add gp addressing */ + ret_val = 0; + + break; + + /* Register indirect. */ + case REG: + ret_val = REG_OK_FOR_BASE_P2 (operand, strict); + break; + + /* Register indirect with displacement. */ + case PLUS: + { + rtx op0 = XEXP (operand, 0); + rtx op1 = XEXP (operand, 1); + + if (REG_P (op0) && REG_P (op1)) + ret_val = 0; + else if (REG_P (op0) && GET_CODE (op1) == CONST_INT) + ret_val = REG_OK_FOR_BASE_P2 (op0, strict) + && SMALL_INT (INTVAL (op1)); + else if (REG_P (op1) && GET_CODE (op0) == CONST_INT) + ret_val = REG_OK_FOR_BASE_P2 (op1, strict) + && SMALL_INT (INTVAL (op0)); + else + ret_val = 0; + } + break; + + default: + ret_val = 0; + break; + } + + return ret_val; +} + +/* Return true if EXP should be placed in the small data section. */ + +static bool +nios2_in_small_data_p (tree exp) +{ + /* We want to merge strings, so we never consider them small data. */ + if (TREE_CODE (exp) == STRING_CST) + return false; + + if (TREE_CODE (exp) == VAR_DECL && DECL_SECTION_NAME (exp)) + { + const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (exp)); + /* ??? these string names need moving into + an array in some header file */ + if (nios2_section_threshold > 0 + && (strcmp (section, ".sbss") == 0 + || strncmp (section, ".sbss.", 6) == 0 + || strcmp (section, ".sdata") == 0 + || strncmp (section, ".sdata.", 7) == 0)) + return true; + } + else if (TREE_CODE (exp) == VAR_DECL) + { + HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp)); + + /* If this is an incomplete type with size 0, then we can't put it + in sdata because it might be too big when completed. */ + if (size > 0 && (unsigned HOST_WIDE_INT)size <= nios2_section_threshold) + return true; + } + + return false; +} + +static void +nios2_encode_section_info (tree decl, rtx rtl, int first) +{ + + rtx symbol; + int flags; + + default_encode_section_info (decl, rtl, first); + + /* Careful not to prod global register variables. */ + if (GET_CODE (rtl) != MEM) + return; + symbol = XEXP (rtl, 0); + if (GET_CODE (symbol) != SYMBOL_REF) + return; + + flags = SYMBOL_REF_FLAGS (symbol); + + /* We don't want weak variables to be addressed with gp in case they end up + with value 0 which is not within 2^15 of $gp. */ + if (DECL_P (decl) && DECL_WEAK (decl)) + flags |= SYMBOL_FLAG_WEAK_DECL; + + SYMBOL_REF_FLAGS (symbol) = flags; +} + + +static unsigned int +nios2_section_type_flags (tree decl, const char *name, int reloc) +{ + unsigned int flags; + + flags = default_section_type_flags (decl, name, reloc); + + if (strcmp (name, ".sbss") == 0 + || strncmp (name, ".sbss.", 6) == 0 + || strcmp (name, ".sdata") == 0 + || strncmp (name, ".sdata.", 7) == 0) + flags |= SECTION_SMALL; + + return flags; +} + +/* Handle a #pragma reverse_bitfields. */ +static void +nios2_pragma_reverse_bitfields (struct cpp_reader *pfile ATTRIBUTE_UNUSED) +{ + nios2_pragma_reverse_bitfields_flag = 1; /* Reverse */ +} + +/* Handle a #pragma no_reverse_bitfields. */ +static void +nios2_pragma_no_reverse_bitfields (struct cpp_reader *pfile ATTRIBUTE_UNUSED) +{ + nios2_pragma_reverse_bitfields_flag = -1; /* Forward */ +} + +/* Handle the various #pragma custom_s. */ +static void +nios2_pragma_fpu (int *value, const char *opt, int *seen) +{ + tree t; + if (c_lex (&t) != CPP_NUMBER) + { + error ("`#pragma custom_%s' value must be a number between 0 and 255", + opt); + return; + } + + if (TREE_INT_CST_HIGH (t) == 0 + && TREE_INT_CST_LOW (t) <= 255) + { + *value = (int)TREE_INT_CST_LOW (t); + *seen = 1; + } + else + error ("`#pragma custom_%s' value must be between 0 and 255", opt); + nios2_custom_check_insns (1); +} + +/* Handle the various #pragma no_custom_s. */ +static void +nios2_pragma_no_fpu (int *value, const char *opt ATTRIBUTE_UNUSED) +{ + *value = -1; + nios2_custom_check_insns (1); +} + +#undef NIOS2_FPU_INSN +#define NIOS2_FPU_INSN(opt, insn, args) \ +static void \ +NIOS2_CONCAT (nios2_pragma_, insn) \ + (struct cpp_reader *pfile ATTRIBUTE_UNUSED) \ +{ \ + nios2_fpu_info *inf = &(nios2_fpu_insns[NIOS2_CONCAT (nios2_fpu_, insn)]); \ + nios2_pragma_fpu (&(inf->N), inf->option, &(inf->pragma_seen)); \ +} \ +static void \ +NIOS2_CONCAT (nios2_pragma_no_, insn) \ + (struct cpp_reader *pfile ATTRIBUTE_UNUSED) \ +{ \ + nios2_fpu_info *inf = &(nios2_fpu_insns[NIOS2_CONCAT (nios2_fpu_, insn)]); \ + nios2_pragma_no_fpu (&(inf->N), inf->option); \ +} +NIOS2_FOR_ALL_FPU_INSNS + +static void +nios2_pragma_handle_custom_fpu_cfg (struct cpp_reader *pfile ATTRIBUTE_UNUSED) +{ + tree t; + if (c_lex (&t) != CPP_STRING) + { + error ("`#pragma custom_fpu_cfg' value must be a string"); + return; + } + + if (TREE_STRING_LENGTH (t) > 0) + nios2_handle_custom_fpu_cfg (TREE_STRING_POINTER (t), 1); +} + +void +nios2_register_target_pragmas (void) +{ + int i; + + c_register_pragma (0, "reverse_bitfields", + nios2_pragma_reverse_bitfields); + c_register_pragma (0, "no_reverse_bitfields", + nios2_pragma_no_reverse_bitfields); + + for (i = 0; i < nios2_fpu_max_insn; i++) + { + nios2_fpu_info *inf = &(nios2_fpu_insns[i]); + c_register_pragma (0, inf->pname, inf->pragma); + c_register_pragma (0, inf->nopname, inf->nopragma); + } + + c_register_pragma (0, "custom_fpu_cfg", + nios2_pragma_handle_custom_fpu_cfg); +} + +/* Handle a "reverse_bitfields" or "no_reverse_bitfields" attribute. + ??? What do these attributes mean on a union? */ +static tree +nios2_handle_struct_attribute (tree *node, tree name, + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, + bool *no_add_attrs) +{ + tree *type = NULL; + if (DECL_P (*node)) + { + if (TREE_CODE (*node) == TYPE_DECL) + type = &TREE_TYPE (*node); + } + else + type = node; + + if (!(type && (TREE_CODE (*type) == RECORD_TYPE + || TREE_CODE (*type) == UNION_TYPE))) + { + warning (0, "`%s' attribute ignored", IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + + else if ((is_attribute_p ("reverse_bitfields", name) + && lookup_attribute ("no_reverse_bitfields", + TYPE_ATTRIBUTES (*type))) + || ((is_attribute_p ("no_reverse_bitfields", name) + && lookup_attribute ("reverse_bitfields", + TYPE_ATTRIBUTES (*type))))) + { + warning (0, "`%s' incompatible attribute ignored", + IDENTIFIER_POINTER (name)); + *no_add_attrs = true; + } + + return NULL_TREE; +} + +/* Add __attribute__ ((pragma_reverse_bitfields)) when in the scope of a + #pragma reverse_bitfields, or __attribute__ + ((pragma_no_reverse_bitfields)) when in the scope of a #pragma + no_reverse_bitfields. This gets called before + nios2_handle_struct_attribute above, so we can't just reuse the same + attributes. */ +static void +nios2_insert_attributes (tree node, tree *attr_ptr) +{ + tree type = NULL; + if (DECL_P (node)) + { + if (TREE_CODE (node) == TYPE_DECL) + type = TREE_TYPE (node); + } + else + type = node; + + if (!type + || (TREE_CODE (type) != RECORD_TYPE + && TREE_CODE (type) != UNION_TYPE)) + { + /* We can ignore things other than structs & unions. */ + return; + } + + if (lookup_attribute ("reverse_bitfields", TYPE_ATTRIBUTES (type)) + || lookup_attribute ("no_reverse_bitfields", TYPE_ATTRIBUTES (type))) + { + /* If an attribute is already set, it silently overrides the + current #pragma, if any. */ + return; + } + + if (nios2_pragma_reverse_bitfields_flag) + { + const char *id = (nios2_pragma_reverse_bitfields_flag == 1 ? + "pragma_reverse_bitfields" : + "pragma_no_reverse_bitfields"); + /* No attribute set, and we are in the scope of a #pragma. */ + *attr_ptr = tree_cons (get_identifier (id), NULL, *attr_ptr); + } +} + +/***************************************** + * Position Independent Code + *****************************************/ + +/* Emit code to load the PIC register. */ + +static void +nios2_load_pic_register (void) +{ + rtx tmp = gen_rtx_REG (Pmode, TEMP_REG_NUM); + + emit_insn (gen_load_got_register (pic_offset_table_rtx, tmp)); + emit_insn (gen_add3_insn (pic_offset_table_rtx, pic_offset_table_rtx, tmp)); +} + +/* Nonzero if the constant value X is a legitimate general operand + when generating PIC code. It is given that flag_pic is on and + that X satisfies CONSTANT_P or is a CONST_DOUBLE. */ + +bool +nios2_legitimate_pic_operand_p (rtx x) +{ + rtx inner; + + /* UNSPEC_TLS is always PIC. */ + if (tls_mentioned_p (x)) + return true; + + if (GET_CODE (x) == SYMBOL_REF) + return false; + if (GET_CODE (x) == LABEL_REF) + return false; + if (GET_CODE (x) == CONST) + { + inner = XEXP (x, 0); + if (GET_CODE (inner) == PLUS && + GET_CODE (XEXP (inner, 0)) == SYMBOL_REF && + GET_CODE (XEXP (inner, 1)) == CONST) + return false; + } + return true; +} + +rtx +nios2_legitimize_pic_address (rtx orig, + enum machine_mode mode ATTRIBUTE_UNUSED, rtx reg) +{ + if (GET_CODE (orig) == SYMBOL_REF + || GET_CODE (orig) == LABEL_REF) + { + if (reg == 0) + { + gcc_assert (!no_new_pseudos); + reg = gen_reg_rtx (Pmode); + } + + emit_insn (gen_pic_load_addr (reg, pic_offset_table_rtx, orig)); + + current_function_uses_pic_offset_table = 1; + + return reg; + } + else if (GET_CODE (orig) == CONST) + { + rtx base, offset; + + if (GET_CODE (XEXP (orig, 0)) == PLUS + && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx) + return orig; + + if (GET_CODE (XEXP (orig, 0)) == UNSPEC + && IS_UNSPEC_TLS (XINT (XEXP (orig, 0), 1))) + return orig; + + if (reg == 0) + { + gcc_assert (!no_new_pseudos); + reg = gen_reg_rtx (Pmode); + } + + gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS); + + base = nios2_legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, + reg); + offset = nios2_legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode, + base == reg ? 0 : reg); + + if (GET_CODE (offset) == CONST_INT) + return plus_constant (base, INTVAL (offset)); + + return gen_rtx_PLUS (Pmode, base, offset); + } + + return orig; +} + +/* Test for various thread-local symbols. */ + +/* Return TRUE if X is a thread-local symbol. */ + +static bool +nios2_tls_symbol_p (rtx x) +{ + if (! TARGET_HAVE_TLS) + return false; + + if (GET_CODE (x) != SYMBOL_REF) + return false; + + return SYMBOL_REF_TLS_MODEL (x) != 0; +} + +rtx +nios2_legitimize_address (rtx x, rtx orig_x, enum machine_mode mode) +{ + if (nios2_tls_symbol_p (x)) + return nios2_legitimize_tls_address (x); + + if (flag_pic) + { + /* We need to find and carefully transform any SYMBOL and LABEL + references; so go back to the original address expression. */ + rtx new_x = nios2_legitimize_pic_address (orig_x, mode, NULL_RTX); + + if (new_x != orig_x) + x = new_x; + } + + return x; +} + +/***************************************** + * Defining the Output Assembler Language + *****************************************/ + +/* -------------- * + * Output of Data + * -------------- */ + + +/* -------------------------------- * + * Output of Assembler Instructions + * -------------------------------- */ + + +/* print the operand OP to file stream + FILE modified by LETTER. LETTER + can be one of: + i: print "i" if OP is an immediate, except 0 + o: print "io" if OP is volatile + + z: for const0_rtx print $0 instead of 0 + H: for %hiadj + L: for %lo + U: for upper half of 32 bit value + D: for the upper 32-bits of a 64-bit double value + */ + +void +nios2_print_operand (FILE *file, rtx op, int letter) +{ + + switch (letter) + { + case 'i': + if (CONSTANT_P (op) && (op != const0_rtx)) + fprintf (file, "i"); + return; + + case 'o': + if (GET_CODE (op) == MEM && TARGET_BYPASS_CACHE) + fprintf (file, "io"); + return; + + default: + break; + } + + if (comparison_operator (op, VOIDmode)) + { + if (letter == 0) + { + fprintf (file, "%s", GET_RTX_NAME (GET_CODE (op))); + return; + } + } + + + switch (GET_CODE (op)) + { + case REG: + if (letter == 0 || letter == 'z') + { + fprintf (file, "%s", reg_names[REGNO (op)]); + return; + } + else if (letter == 'D') + { + fprintf (file, "%s", reg_names[REGNO (op)+1]); + return; + } + break; + + case CONST_INT: + if (INTVAL (op) == 0 && letter == 'z') + { + fprintf (file, "zero"); + return; + } + else if (letter == 'U') + { + HOST_WIDE_INT val = INTVAL (op); + rtx new_op; + val = (val / 65536) & 0xFFFF; + new_op = GEN_INT (val); + output_addr_const (file, new_op); + return; + } + + /* else, fall through. */ + case CONST: + case LABEL_REF: + case SYMBOL_REF: + case CONST_DOUBLE: + if (letter == 0 || letter == 'z') + { + output_addr_const (file, op); + return; + } + else if (letter == 'H') + { + fprintf (file, "%%hiadj("); + output_addr_const (file, op); + fprintf (file, ")"); + return; + } + else if (letter == 'L') + { + fprintf (file, "%%lo("); + output_addr_const (file, op); + fprintf (file, ")"); + return; + } + break; + + + case SUBREG: + case MEM: + if (letter == 0) + { + output_address (op); + return; + } + break; + + case CODE_LABEL: + if (letter == 0) + { + output_addr_const (file, op); + return; + } + break; + + default: + break; + } + + fprintf (stderr, "Missing way to print (%c) ", letter); + debug_rtx (op); + gcc_unreachable (); +} + +static int gprel_constant (rtx); + +static int +gprel_constant (rtx op) +{ + if (GET_CODE (op) == SYMBOL_REF + && SYMBOL_REF_IN_NIOS2_SMALL_DATA_P (op)) + return 1; + else if (GET_CODE (op) == CONST + && GET_CODE (XEXP (op, 0)) == PLUS) + return gprel_constant (XEXP (XEXP (op, 0), 0)); + else + return 0; +} + +void +nios2_print_operand_address (FILE *file, rtx op) +{ + switch (GET_CODE (op)) + { + case CONST: + case CONST_INT: + case LABEL_REF: + case CONST_DOUBLE: + case SYMBOL_REF: + if (gprel_constant (op)) + { + fprintf (file, "%%gprel("); + output_addr_const (file, op); + fprintf (file, ")(%s)", reg_names[GP_REGNO]); + return; + } + + break; + + case PLUS: + { + rtx op0 = XEXP (op, 0); + rtx op1 = XEXP (op, 1); + + if (REG_P (op0) && CONSTANT_P (op1)) + { + output_addr_const (file, op1); + fprintf (file, "(%s)", reg_names[REGNO (op0)]); + return; + } + else if (REG_P (op1) && CONSTANT_P (op0)) + { + output_addr_const (file, op0); + fprintf (file, "(%s)", reg_names[REGNO (op1)]); + return; + } + } + break; + + case REG: + fprintf (file, "0(%s)", reg_names[REGNO (op)]); + return; + + case MEM: + { + rtx base = XEXP (op, 0); + PRINT_OPERAND_ADDRESS (file, base); + return; + } + default: + break; + } + + fprintf (stderr, "Missing way to print address\n"); + debug_rtx (op); + gcc_unreachable (); +} + + + +/**************************** + * Debug information + ****************************/ + +static void +nios2_output_dwarf_dtprel (FILE *file, int size, rtx x) +{ + gcc_assert (size == 4); + fputs ("\t.4byte\t%tls_ldo(", file); + output_addr_const (file, x); + fputs (")", file); +} + + +/**************************** + * Predicates + ****************************/ + +/* An operand to a call or sibcall. This must be an immediate operand + or a register. */ +int +call_operand (rtx x, enum machine_mode mode) +{ + return (immediate_operand (x, mode) + || register_operand (x, mode)); +} + +int +arith_operand (rtx op, enum machine_mode mode) +{ + if (GET_CODE (op) == CONST_INT && SMALL_INT (INTVAL (op))) + return 1; + + return register_operand (op, mode); +} + +int +uns_arith_operand (rtx op, enum machine_mode mode) +{ + if (GET_CODE (op) == CONST_INT && SMALL_INT_UNSIGNED (INTVAL (op))) + return 1; + + return register_operand (op, mode); +} + +int +logical_operand (rtx op, enum machine_mode mode) +{ + if (GET_CODE (op) == CONST_INT + && (SMALL_INT_UNSIGNED (INTVAL (op)) || UPPER16_INT (INTVAL (op)))) + return 1; + + return register_operand (op, mode); +} + +int +shift_operand (rtx op, enum machine_mode mode) +{ + if (GET_CODE (op) == CONST_INT && SHIFT_INT (INTVAL (op))) + return 1; + + return register_operand (op, mode); +} + +int +rdwrctl_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + return GET_CODE (op) == CONST_INT && RDWRCTL_INT (INTVAL (op)); +} + +/* Return truth value of whether OP is a register or the constant 0. */ + +int +reg_or_0_operand (rtx op, enum machine_mode mode) +{ + switch (GET_CODE (op)) + { + case CONST_INT: + return INTVAL (op) == 0; + + case CONST_DOUBLE: + return op == CONST0_RTX (mode); + + default: + break; + } + + return register_operand (op, mode); +} + + +int +equality_op (rtx op, enum machine_mode mode) +{ + if (mode != GET_MODE (op)) + return 0; + + return GET_CODE (op) == EQ || GET_CODE (op) == NE; +} + +int +custom_insn_opcode (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) +{ + return GET_CODE (op) == CONST_INT && CUSTOM_INSN_OPCODE (INTVAL (op)); +} + + + + +/***************************************************************************** +** +** custom fpu instruction output +** +*****************************************************************************/ + +static const char *nios2_custom_fpu_insn_zdz (rtx, int, const char *); +static const char *nios2_custom_fpu_insn_zsz (rtx, int, const char *); +static const char *nios2_custom_fpu_insn_szz (rtx, int, const char *); +static const char *nios2_custom_fpu_insn_sss (rtx, int, const char *); +static const char *nios2_custom_fpu_insn_ssz (rtx, int, const char *); +static const char *nios2_custom_fpu_insn_iss (rtx, int, const char *); +static const char *nios2_custom_fpu_insn_ddd (rtx, int, const char *); +static const char *nios2_custom_fpu_insn_ddz (rtx, int, const char *); +static const char *nios2_custom_fpu_insn_idd (rtx, int, const char *); +static const char *nios2_custom_fpu_insn_siz (rtx, int, const char *); +static const char *nios2_custom_fpu_insn_suz (rtx, int, const char *); +static const char *nios2_custom_fpu_insn_diz (rtx, int, const char *); +static const char *nios2_custom_fpu_insn_duz (rtx, int, const char *); +static const char *nios2_custom_fpu_insn_isz (rtx, int, const char *); +static const char *nios2_custom_fpu_insn_usz (rtx, int, const char *); +static const char *nios2_custom_fpu_insn_idz (rtx, int, const char *); +static const char *nios2_custom_fpu_insn_udz (rtx, int, const char *); +static const char *nios2_custom_fpu_insn_dsz (rtx, int, const char *); +static const char *nios2_custom_fpu_insn_sdz (rtx, int, const char *); + +static const char * +nios2_custom_fpu_insn_zdz (rtx insn, int N, const char *opt) +{ + static char buf[1024]; + + if (N < 0) + fatal_insn ("attempt to use disabled fpu instruction", insn); + if (snprintf (buf, sizeof (buf), + "custom\t%d, zero, %%0, %%D0 # %s %%0", + N, opt) >= (int)sizeof (buf)) + fatal_insn ("buffer overflow", insn); + return buf; +} + +static const char * +nios2_custom_fpu_insn_zsz (rtx insn, int N, const char *opt) +{ + static char buf[1024]; + + if (N < 0) + fatal_insn ("attempt to use disabled fpu instruction", insn); + if (snprintf (buf, sizeof (buf), + "custom\t%d, zero, %%0, zero # %s %%0", + N, opt) >= (int)sizeof (buf)) + fatal_insn ("buffer overflow", insn); + return buf; +} + +static const char * +nios2_custom_fpu_insn_szz (rtx insn, int N, const char *opt) +{ + static char buf[1024]; + + if (N < 0) + fatal_insn ("attempt to use disabled fpu instruction", insn); + if (snprintf (buf, sizeof (buf), + "custom\t%d, %%0, zero, zero # %s %%0", + N, opt) >= (int)sizeof (buf)) + fatal_insn ("buffer overflow", insn); + return buf; +} + +static const char * +nios2_custom_fpu_insn_sss (rtx insn, int N, const char *opt) +{ + static char buf[1024]; + + if (N < 0) + fatal_insn ("attempt to use disabled fpu instruction", insn); + if (snprintf (buf, sizeof (buf), + "custom\t%d, %%0, %%1, %%2 # %s %%0, %%1, %%2", + N, opt) >= (int)sizeof (buf)) + fatal_insn ("buffer overflow", insn); + return buf; +} + +static const char * +nios2_custom_fpu_insn_ssz (rtx insn, int N, const char *opt) +{ + static char buf[1024]; + + if (N < 0) + fatal_insn ("attempt to use disabled fpu instruction", insn); + if (snprintf (buf, sizeof (buf), + "custom\t%d, %%0, %%1, zero # %s %%0, %%1", + N, opt) >= (int)sizeof (buf)) + fatal_insn ("buffer overflow", insn); + return buf; +} + +static const char * +nios2_custom_fpu_insn_iss (rtx insn, int N, const char *opt) +{ + return nios2_custom_fpu_insn_sss (insn, N, opt); +} + +static const char * +nios2_custom_fpu_insn_ddd (rtx insn, int N, const char *opt) +{ + static char buf[1024]; + + if (N < 0 + || nios2_fpu_insns[nios2_fpu_nios2_frdy].N < 0 + || nios2_fpu_insns[nios2_fpu_nios2_fwrx].N < 0) + fatal_insn ("attempt to use disabled fpu instruction", insn); + if (snprintf (buf, sizeof (buf), + "custom\t%d, zero, %%1, %%D1 # fwrx %%1\n\t" + "custom\t%d, %%D0, %%2, %%D2 # %s %%0, %%1, %%2\n\t" + "custom\t%d, %%0, zero, zero # frdy %%0", + nios2_fpu_insns[nios2_fpu_nios2_fwrx].N, + N, opt, + nios2_fpu_insns[nios2_fpu_nios2_frdy].N) >= (int)sizeof (buf)) + fatal_insn ("buffer overflow", insn); + return buf; +} + +static const char * +nios2_custom_fpu_insn_ddz (rtx insn, int N, const char *opt) +{ + static char buf[1024]; + + if (N < 0 || nios2_fpu_insns[nios2_fpu_nios2_frdy].N < 0) + fatal_insn ("attempt to use disabled fpu instruction", insn); + if (snprintf (buf, sizeof (buf), + "custom\t%d, %%D0, %%1, %%D1 # %s %%0, %%1\n\t" + "custom\t%d, %%0, zero, zero # frdy %%0", + N, opt, + nios2_fpu_insns[nios2_fpu_nios2_frdy].N) >= (int)sizeof (buf)) + fatal_insn ("buffer overflow", insn); + return buf; +} + +static const char * +nios2_custom_fpu_insn_idd (rtx insn, int N, const char *opt) +{ + static char buf[1024]; + + if (N < 0 || nios2_fpu_insns[nios2_fpu_nios2_fwrx].N < 0) + fatal_insn ("attempt to use disabled fpu instruction", insn); + if (snprintf (buf, sizeof (buf), + "custom\t%d, zero, %%1, %%D1 # fwrx %%1\n\t" + "custom\t%d, %%0, %%2, %%D2 # %s %%0, %%1, %%2", + nios2_fpu_insns[nios2_fpu_nios2_fwrx].N, + N, opt) >= (int)sizeof (buf)) + fatal_insn ("buffer overflow", insn); + return buf; +} + +static const char * +nios2_custom_fpu_insn_siz (rtx insn, int N, const char *opt) +{ + return nios2_custom_fpu_insn_ssz (insn, N, opt); +} + +static const char * +nios2_custom_fpu_insn_suz (rtx insn, int N, const char *opt) +{ + return nios2_custom_fpu_insn_ssz (insn, N, opt); +} + +static const char * +nios2_custom_fpu_insn_diz (rtx insn, int N, const char *opt) +{ + return nios2_custom_fpu_insn_dsz (insn, N, opt); +} + +static const char * +nios2_custom_fpu_insn_duz (rtx insn, int N, const char *opt) +{ + return nios2_custom_fpu_insn_dsz (insn, N, opt); +} + +static const char * +nios2_custom_fpu_insn_isz (rtx insn, int N, const char *opt) +{ + return nios2_custom_fpu_insn_ssz (insn, N, opt); +} + +static const char * +nios2_custom_fpu_insn_usz (rtx insn, int N, const char *opt) +{ + return nios2_custom_fpu_insn_ssz (insn, N, opt); +} + +static const char * +nios2_custom_fpu_insn_idz (rtx insn, int N, const char *opt) +{ + return nios2_custom_fpu_insn_sdz (insn, N, opt); +} + +static const char * +nios2_custom_fpu_insn_udz (rtx insn, int N, const char *opt) +{ + return nios2_custom_fpu_insn_sdz (insn, N, opt); +} + +static const char * +nios2_custom_fpu_insn_dsz (rtx insn, int N, const char *opt) +{ + static char buf[1024]; + + if (N < 0 || nios2_fpu_insns[nios2_fpu_nios2_frdy].N < 0) + fatal_insn ("attempt to use disabled fpu instruction", insn); + if (snprintf (buf, sizeof (buf), + "custom\t%d, %%D0, %%1, zero # %s %%0, %%1\n\t" + "custom\t%d, %%0, zero, zero # frdy %%0", + N, opt, + nios2_fpu_insns[nios2_fpu_nios2_frdy].N) >= (int)sizeof (buf)) + fatal_insn ("buffer overflow", insn); + return buf; +} + +static const char * +nios2_custom_fpu_insn_sdz (rtx insn, int N, const char *opt) +{ + static char buf[1024]; + + if (N < 0) + fatal_insn ("attempt to use disabled fpu instruction", insn); + if (snprintf (buf, sizeof (buf), + "custom\t%d, %%0, %%1, %%D1 # %s %%0, %%1", + N, opt) >= (int)sizeof (buf)) + fatal_insn ("buffer overflow", insn); + return buf; +} + +#undef NIOS2_FPU_INSN +#define NIOS2_FPU_INSN(opt, insn, args) \ +static const char * \ +NIOS2_CONCAT (nios2_output_fpu_insn_, insn) (rtx i) \ +{ \ + return NIOS2_CONCAT (nios2_custom_fpu_insn_, args) \ + (i, \ + nios2_fpu_insns[NIOS2_CONCAT (nios2_fpu_, insn)].N, \ + nios2_fpu_insns[NIOS2_CONCAT (nios2_fpu_, insn)].option); \ +} +NIOS2_FOR_ALL_FPU_INSNS + + + +const char * +nios2_output_fpu_insn_cmps (rtx insn, enum rtx_code cond) +{ + static char buf[1024]; + int N; + const char *opt; + + int operandL = 2; + int operandR = 3; + + if (!have_nios2_fpu_cmp_insn(cond, CMP_SF) && + have_nios2_fpu_cmp_insn(get_reverse_cond(cond), CMP_SF) ) { + + int temp = operandL; + operandL = operandR; + operandR = temp; + + cond = get_reverse_cond(cond); + } + + switch (cond) + { + case EQ: + N = nios2_fpu_insns[nios2_fpu_nios2_seqsf].N; + opt = "fcmpeqs"; + break; + case NE: + N = nios2_fpu_insns[nios2_fpu_nios2_snesf].N; + opt = "fcmpnes"; + break; + case GT: + N = nios2_fpu_insns[nios2_fpu_nios2_sgtsf].N; + opt = "fcmpgts"; + break; + case GE: + N = nios2_fpu_insns[nios2_fpu_nios2_sgesf].N; + opt = "fcmpges"; + break; + case LT: + N = nios2_fpu_insns[nios2_fpu_nios2_sltsf].N; + opt = "fcmplts"; + break; + case LE: + N = nios2_fpu_insns[nios2_fpu_nios2_slesf].N; + opt = "fcmples"; break; + default: + fatal_insn ("bad single compare", insn); + } + + if (N < 0) + fatal_insn ("attempt to use disabled fpu instruction", insn); + + /* ??? This raises the whole vexing issue of how to handle + out-of-range branches. Punt for now, seeing as how nios2-elf-as + doesn't even _try_ to handle out-of-range branches yet! */ + if (snprintf (buf, sizeof (buf), + ".set\tnoat\n\t" + "custom\t%d, at, %%%d, %%%d # %s at, %%%d, %%%d\n\t" + "bne\tat, zero, %%l1\n\t" + ".set\tat", + N, operandL, operandR, opt, operandL, operandR + ) >= (int)sizeof (buf)) + fatal_insn ("buffer overflow", insn); + return buf; +} + +const char * +nios2_output_fpu_insn_cmpd (rtx insn, enum rtx_code cond) +{ + static char buf[1024]; + int N; + const char *opt; + + int operandL = 2; + int operandR = 3; + + if ( !have_nios2_fpu_cmp_insn(cond, CMP_DF) && + have_nios2_fpu_cmp_insn(get_reverse_cond(cond), CMP_DF) ) + { + + int temp = operandL; + operandL = operandR; + operandR = temp; + + cond = get_reverse_cond(cond); + } + + switch (cond) + { + case EQ: + N = nios2_fpu_insns[nios2_fpu_nios2_seqdf].N; + opt = "fcmpeqd"; + break; + case NE: + N = nios2_fpu_insns[nios2_fpu_nios2_snedf].N; + opt = "fcmpned"; + break; + case GT: + N = nios2_fpu_insns[nios2_fpu_nios2_sgtdf].N; + opt = "fcmpgtd"; + break; + case GE: + N = nios2_fpu_insns[nios2_fpu_nios2_sgedf].N; + opt = "fcmpged"; + break; + case LT: + N = nios2_fpu_insns[nios2_fpu_nios2_sltdf].N; + opt = "fcmpltd"; + break; + case LE: + N = nios2_fpu_insns[nios2_fpu_nios2_sledf].N; + opt = "fcmpled"; + break; + default: + fatal_insn ("bad double compare", insn); + } + + if (N < 0 || nios2_fpu_insns[nios2_fpu_nios2_fwrx].N < 0) + fatal_insn ("attempt to use disabled fpu instruction", insn); + if (snprintf (buf, sizeof (buf), + ".set\tnoat\n\t" + "custom\t%d, zero, %%%d, %%D%d # fwrx %%%d\n\t" + "custom\t%d, at, %%%d, %%D%d # %s at, %%%d, %%%d\n\t" + "bne\tat, zero, %%l1\n\t" + ".set\tat", + nios2_fpu_insns[nios2_fpu_nios2_fwrx].N, operandL, operandL, + operandL, N, operandR, operandR, opt, operandL, operandR + ) >= (int)sizeof (buf)) + fatal_insn ("buffer overflow", insn); + return buf; +} + + + + +/***************************************************************************** +** +** Instruction scheduler +** +*****************************************************************************/ +static int +nios2_issue_rate (void) +{ +#ifdef MAX_DFA_ISSUE_RATE + return MAX_DFA_ISSUE_RATE; +#else + return 1; +#endif +} + + +const char * +asm_output_opcode (FILE *file ATTRIBUTE_UNUSED, + const char *ptr ATTRIBUTE_UNUSED) +{ + const char *p; + + p = ptr; + return ptr; +} + + + +/***************************************************************************** +** +** Function arguments +** +*****************************************************************************/ + +void +init_cumulative_args (CUMULATIVE_ARGS *cum, + tree fntype ATTRIBUTE_UNUSED, + rtx libname ATTRIBUTE_UNUSED, + tree fndecl ATTRIBUTE_UNUSED, + int n_named_args ATTRIBUTE_UNUSED) +{ + cum->regs_used = 0; +} + + +/* Define where to put the arguments to a function. Value is zero to + push the argument on the stack, or a hard register in which to + store the argument. + + MODE is the argument's machine mode. + TYPE is the data type of the argument (as a tree). + This is null for libcalls where that information may + not be available. + CUM is a variable of type CUMULATIVE_ARGS which gives info about + the preceding args and about the function being called. + NAMED is nonzero if this argument is a named parameter + (otherwise it is an extra parameter matching an ellipsis). */ +rtx +function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode, + tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED) +{ + rtx return_rtx = NULL_RTX; + + if (cum->regs_used < NUM_ARG_REGS) + return_rtx = gen_rtx_REG (mode, FIRST_ARG_REGNO + cum->regs_used); + + return return_rtx; +} + +/* Return number of bytes, at the beginning of the argument, that must be + put in registers. 0 is the argument is entirely in registers or entirely + in memory. */ + +static int +nios2_arg_partial_bytes (CUMULATIVE_ARGS *cum, + enum machine_mode mode, tree type, + bool named ATTRIBUTE_UNUSED) +{ + HOST_WIDE_INT param_size; + + if (mode == BLKmode) + { + param_size = int_size_in_bytes (type); + if (param_size < 0) + internal_error + ("Do not know how to handle large structs or variable length types"); + } + else + param_size = GET_MODE_SIZE (mode); + + /* Convert to words (round up). */ + param_size = (3 + param_size) / 4; + + if (cum->regs_used < NUM_ARG_REGS + && cum->regs_used + param_size > NUM_ARG_REGS) + return (NUM_ARG_REGS - cum->regs_used) * UNITS_PER_WORD; + else + return 0; +} + +static bool +nios2_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + tree type ATTRIBUTE_UNUSED, + bool named ATTRIBUTE_UNUSED) +{ + return false; +} + + +/* Update the data in CUM to advance over an argument + of mode MODE and data type TYPE. + (TYPE is null for libcalls where that information may not be available.) */ + +void +function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, + tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED) +{ + HOST_WIDE_INT param_size; + + if (mode == BLKmode) + { + param_size = int_size_in_bytes (type); + if (param_size < 0) + internal_error + ("Do not know how to handle large structs or variable length types"); + } + else + param_size = GET_MODE_SIZE (mode); + + /* Convert to words (round up). */ + param_size = (3 + param_size) / 4; + + if (cum->regs_used + param_size > NUM_ARG_REGS) + cum->regs_used = NUM_ARG_REGS; + else + cum->regs_used += param_size; + + return; +} + +int +nios2_function_arg_padding_upward (enum machine_mode mode, tree type) +{ + /* On little-endian targets, the first byte of every stack argument + is passed in the first byte of the stack slot. */ + if (!BYTES_BIG_ENDIAN) + return 1; + + /* Otherwise, integral types are padded downward: the last byte of a + stack argument is passed in the last byte of the stack slot. */ + if (type != 0 + ? INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type) + : GET_MODE_CLASS (mode) == MODE_INT) + return 0; + + /* Arguments smaller than a stack slot are padded downward. */ + if (mode != BLKmode) + return (GET_MODE_BITSIZE (mode) >= PARM_BOUNDARY) ? 1 : 0; + else + return ((int_size_in_bytes (type) >= (PARM_BOUNDARY / BITS_PER_UNIT)) + ? 1 : 0); +} + +int +nios2_block_reg_padding_upward (enum machine_mode mode, tree type, + int first ATTRIBUTE_UNUSED) +{ + /* ??? Do we need to treat floating point specially, ala MIPS? */ + return nios2_function_arg_padding_upward (mode, type); +} + +int +nios2_return_in_memory (tree type) +{ + int res = ((int_size_in_bytes (type) > (2 * UNITS_PER_WORD)) + || (int_size_in_bytes (type) == -1)); + + return res; +} + +/* ??? It may be possible to eliminate the copyback and implement + my own va_arg type, but that is more work for now. */ +void +nios2_setup_incoming_varargs (CUMULATIVE_ARGS *cum, + enum machine_mode mode, tree type, + int *pretend_size, int second_time) +{ + CUMULATIVE_ARGS local_cum; + int regs_to_push; + int pret_size; + + local_cum = *cum; + FUNCTION_ARG_ADVANCE (local_cum, mode, type, 1); + + regs_to_push = NUM_ARG_REGS - local_cum.regs_used; + + if (!second_time) + { + if (regs_to_push > 0) + { + rtx ptr, mem; + + ptr = virtual_incoming_args_rtx; + mem = gen_rtx_MEM (BLKmode, ptr); + + /* va_arg is an array access in this case, which causes + it to get MEM_IN_STRUCT_P set. We must set it here + so that the insn scheduler won't assume that these + stores can't possibly overlap with the va_arg loads. */ + MEM_SET_IN_STRUCT_P (mem, 1); + + emit_insn (gen_blockage ()); + move_block_from_reg (local_cum.regs_used + FIRST_ARG_REGNO, mem, + regs_to_push); + emit_insn (gen_blockage ()); + } + } + + pret_size = regs_to_push * UNITS_PER_WORD; + + if (pret_size) + *pretend_size = pret_size; +} + + + +/***************************************************************************** +** +** builtins +** +** This method for handling builtins is from CSP where _many_ more types of +** expanders have already been written. Check there first before writing +** new ones. +** +*****************************************************************************/ + +enum nios2_builtins +{ + NIOS2_BUILTIN_LDBIO, + NIOS2_BUILTIN_LDBUIO, + NIOS2_BUILTIN_LDHIO, + NIOS2_BUILTIN_LDHUIO, + NIOS2_BUILTIN_LDWIO, + NIOS2_BUILTIN_STBIO, + NIOS2_BUILTIN_STHIO, + NIOS2_BUILTIN_STWIO, + NIOS2_BUILTIN_SYNC, + NIOS2_BUILTIN_RDCTL, + NIOS2_BUILTIN_WRCTL, + +#undef NIOS2_DO_BUILTIN +#define NIOS2_DO_BUILTIN(upper, lower, handler) \ + NIOS2_CONCAT (NIOS2_BUILTIN_CUSTOM_, upper), +NIOS2_FOR_ALL_CUSTOM_BUILTINS + + NIOS2_FIRST_FPU_INSN, + +#undef NIOS2_FPU_INSN +#define NIOS2_FPU_INSN(opt, insn, args) \ + NIOS2_CONCAT (NIOS2_BUILTIN_FPU_, opt), +NIOS2_FOR_ALL_FPU_INSNS + + NIOS2_LAST_FPU_INSN, + + LIM_NIOS2_BUILTINS +}; + +struct builtin_description +{ + const enum insn_code icode; + const char *const name; + const enum nios2_builtins code; + const tree *type; + rtx (* expander) (const struct builtin_description *, + tree, rtx, rtx, enum machine_mode, int); +}; + +static rtx nios2_expand_STXIO (const struct builtin_description *, + tree, rtx, rtx, enum machine_mode, int); +static rtx nios2_expand_LDXIO (const struct builtin_description *, + tree, rtx, rtx, enum machine_mode, int); +static rtx nios2_expand_sync (const struct builtin_description *, + tree, rtx, rtx, enum machine_mode, int); +static rtx nios2_expand_rdctl (const struct builtin_description *, + tree, rtx, rtx, enum machine_mode, int); +static rtx nios2_expand_wrctl (const struct builtin_description *, + tree, rtx, rtx, enum machine_mode, int); + +static rtx nios2_expand_custom_n (const struct builtin_description *, + tree, rtx, rtx, enum machine_mode, int); +static rtx nios2_expand_custom_Xn (const struct builtin_description *, + tree, rtx, rtx, enum machine_mode, int); +static rtx nios2_expand_custom_nX (const struct builtin_description *, + tree, rtx, rtx, enum machine_mode, int); +static rtx nios2_expand_custom_XnX (const struct builtin_description *, + tree, rtx, rtx, enum machine_mode, int); +static rtx nios2_expand_custom_nXX (const struct builtin_description *, + tree, rtx, rtx, enum machine_mode, int); +static rtx nios2_expand_custom_XnXX (const struct builtin_description *, + tree, rtx, rtx, enum machine_mode, int); + +static rtx nios2_expand_custom_zdz (const struct builtin_description *, + tree, rtx, rtx, enum machine_mode, int); +static rtx nios2_expand_custom_zsz (const struct builtin_description *, + tree, rtx, rtx, enum machine_mode, int); +static rtx nios2_expand_custom_szz (const struct builtin_description *, + tree, rtx, rtx, enum machine_mode, int); +static rtx nios2_expand_custom_sss (const struct builtin_description *, + tree, rtx, rtx, enum machine_mode, int); +static rtx nios2_expand_custom_ssz (const struct builtin_description *, + tree, rtx, rtx, enum machine_mode, int); +static rtx nios2_expand_custom_iss (const struct builtin_description *, + tree, rtx, rtx, enum machine_mode, int); +static rtx nios2_expand_custom_ddd (const struct builtin_description *, + tree, rtx, rtx, enum machine_mode, int); +static rtx nios2_expand_custom_ddz (const struct builtin_description *, + tree, rtx, rtx, enum machine_mode, int); +static rtx nios2_expand_custom_idd (const struct builtin_description *, + tree, rtx, rtx, enum machine_mode, int); +static rtx nios2_expand_custom_siz (const struct builtin_description *, + tree, rtx, rtx, enum machine_mode, int); +static rtx nios2_expand_custom_suz (const struct builtin_description *, + tree, rtx, rtx, enum machine_mode, int); +static rtx nios2_expand_custom_diz (const struct builtin_description *, + tree, rtx, rtx, enum machine_mode, int); +static rtx nios2_expand_custom_duz (const struct builtin_description *, + tree, rtx, rtx, enum machine_mode, int); +static rtx nios2_expand_custom_isz (const struct builtin_description *, + tree, rtx, rtx, enum machine_mode, int); +static rtx nios2_expand_custom_usz (const struct builtin_description *, + tree, rtx, rtx, enum machine_mode, int); +static rtx nios2_expand_custom_idz (const struct builtin_description *, + tree, rtx, rtx, enum machine_mode, int); +static rtx nios2_expand_custom_udz (const struct builtin_description *, + tree, rtx, rtx, enum machine_mode, int); +static rtx nios2_expand_custom_dsz (const struct builtin_description *, + tree, rtx, rtx, enum machine_mode, int); +static rtx nios2_expand_custom_sdz (const struct builtin_description *, + tree, rtx, rtx, enum machine_mode, int); + +static tree endlink; + +/* int fn (volatile const void *) + */ +static tree int_ftype_volatile_const_void_p; + +/* int fn (int) + */ +static tree int_ftype_int; + +/* void fn (int, int) + */ +static tree void_ftype_int_int; + +/* void fn (volatile void *, int) + */ +static tree void_ftype_volatile_void_p_int; + +/* void fn (void) + */ +static tree void_ftype_void; + +#undef NIOS2_DO_BUILTIN +#define NIOS2_DO_BUILTIN(upper, lower, handler) \ + static tree NIOS2_CONCAT (custom_, lower); +NIOS2_FOR_ALL_CUSTOM_BUILTINS + +static tree custom_zdz; +static tree custom_zsz; +static tree custom_szz; +static tree custom_sss; +static tree custom_ssz; +static tree custom_iss; +static tree custom_ddd; +static tree custom_ddz; +static tree custom_idd; +static tree custom_siz; +static tree custom_suz; +static tree custom_diz; +static tree custom_duz; +static tree custom_isz; +static tree custom_usz; +static tree custom_idz; +static tree custom_udz; +static tree custom_dsz; +static tree custom_sdz; + +static const struct builtin_description bdesc[] = { + {CODE_FOR_ldbio, "__builtin_ldbio", NIOS2_BUILTIN_LDBIO, + &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, + {CODE_FOR_ldbuio, "__builtin_ldbuio", NIOS2_BUILTIN_LDBUIO, + &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, + {CODE_FOR_ldhio, "__builtin_ldhio", NIOS2_BUILTIN_LDHIO, + &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, + {CODE_FOR_ldhuio, "__builtin_ldhuio", NIOS2_BUILTIN_LDHUIO, + &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, + {CODE_FOR_ldwio, "__builtin_ldwio", NIOS2_BUILTIN_LDWIO, + &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, + + {CODE_FOR_stbio, "__builtin_stbio", NIOS2_BUILTIN_STBIO, + &void_ftype_volatile_void_p_int, nios2_expand_STXIO}, + {CODE_FOR_sthio, "__builtin_sthio", NIOS2_BUILTIN_STHIO, + &void_ftype_volatile_void_p_int, nios2_expand_STXIO}, + {CODE_FOR_stwio, "__builtin_stwio", NIOS2_BUILTIN_STWIO, + &void_ftype_volatile_void_p_int, nios2_expand_STXIO}, + + {CODE_FOR_sync, "__builtin_sync", NIOS2_BUILTIN_SYNC, + &void_ftype_void, nios2_expand_sync}, + {CODE_FOR_rdctl, "__builtin_rdctl", NIOS2_BUILTIN_RDCTL, + &int_ftype_int, nios2_expand_rdctl}, + {CODE_FOR_wrctl, "__builtin_wrctl", NIOS2_BUILTIN_WRCTL, + &void_ftype_int_int, nios2_expand_wrctl}, + +#undef NIOS2_DO_BUILTIN +#define NIOS2_DO_BUILTIN(upper, lower, handler) \ + {NIOS2_CONCAT (CODE_FOR_custom_, lower), \ + "__builtin_custom_" NIOS2_STRINGIFY (lower), \ + NIOS2_CONCAT (NIOS2_BUILTIN_CUSTOM_, upper), \ + &NIOS2_CONCAT (custom_, lower), \ + NIOS2_CONCAT (nios2_expand_custom_, handler)}, +NIOS2_FOR_ALL_CUSTOM_BUILTINS + +#undef NIOS2_FPU_INSN +#define NIOS2_FPU_INSN(opt, insn, args) \ + {NIOS2_CONCAT (CODE_FOR_, insn), \ + "__builtin_custom_" NIOS2_STRINGIFY (opt), \ + NIOS2_CONCAT (NIOS2_BUILTIN_FPU_, opt), \ + &NIOS2_CONCAT (custom_, args), \ + NIOS2_CONCAT (nios2_expand_custom_, args)}, +NIOS2_FOR_ALL_FPU_INSNS + + {0, 0, 0, 0, 0}, +}; + +static void +nios2_init_builtins (void) +{ + const struct builtin_description *d; + + + endlink = void_list_node; + + /* int fn (volatile const void *) + */ + int_ftype_volatile_const_void_p = build_function_type ( + integer_type_node, + tree_cons (NULL_TREE, + build_qualified_type (ptr_type_node, + TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE), + endlink)); + + /* void fn (volatile void *, int) + */ + void_ftype_volatile_void_p_int = build_function_type ( + void_type_node, + tree_cons (NULL_TREE, + build_qualified_type (ptr_type_node, TYPE_QUAL_VOLATILE), + tree_cons (NULL_TREE, integer_type_node, endlink))); + + /* void fn (void) + */ + void_ftype_void + = build_function_type (void_type_node, + endlink); + + /* int fn (int) + */ + int_ftype_int + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + endlink)); + + /* void fn (int, int) + */ + void_ftype_int_int + = build_function_type (void_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + endlink))); + + custom_n + = build_function_type (void_type_node, + tree_cons (NULL_TREE, integer_type_node, + endlink)); + custom_ni + = build_function_type (void_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + endlink))); + custom_nf + = build_function_type (void_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, float_type_node, + endlink))); + custom_np + = build_function_type (void_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, ptr_type_node, + endlink))); + custom_nii + = build_function_type (void_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + endlink)))); + custom_nif + = build_function_type (void_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, float_type_node, + endlink)))); + custom_nip + = build_function_type (void_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, ptr_type_node, + endlink)))); + custom_nfi + = build_function_type (void_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, float_type_node, + tree_cons (NULL_TREE, integer_type_node, + endlink)))); + custom_nff + = build_function_type (void_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, float_type_node, + tree_cons (NULL_TREE, float_type_node, + endlink)))); + custom_nfp + = build_function_type (void_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, float_type_node, + tree_cons (NULL_TREE, ptr_type_node, + endlink)))); + custom_npi + = build_function_type (void_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, integer_type_node, + endlink)))); + custom_npf + = build_function_type (void_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, float_type_node, + endlink)))); + custom_npp + = build_function_type (void_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, ptr_type_node, + endlink)))); + + custom_in + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + endlink)); + custom_ini + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + endlink))); + custom_inf + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, float_type_node, + endlink))); + custom_inp + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, ptr_type_node, + endlink))); + custom_inii + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + endlink)))); + custom_inif + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, float_type_node, + endlink)))); + custom_inip + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, ptr_type_node, + endlink)))); + custom_infi + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, float_type_node, + tree_cons (NULL_TREE, integer_type_node, + endlink)))); + custom_inff + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, float_type_node, + tree_cons (NULL_TREE, float_type_node, + endlink)))); + custom_infp + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, float_type_node, + tree_cons (NULL_TREE, ptr_type_node, + endlink)))); + custom_inpi + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, integer_type_node, + endlink)))); + custom_inpf + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, float_type_node, + endlink)))); + custom_inpp + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, ptr_type_node, + endlink)))); + + custom_fn + = build_function_type (float_type_node, + tree_cons (NULL_TREE, integer_type_node, + endlink)); + custom_fni + = build_function_type (float_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + endlink))); + custom_fnf + = build_function_type (float_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, float_type_node, + endlink))); + custom_fnp + = build_function_type (float_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, ptr_type_node, + endlink))); + custom_fnii + = build_function_type (float_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + endlink)))); + custom_fnif + = build_function_type (float_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, float_type_node, + endlink)))); + custom_fnip + = build_function_type (float_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, ptr_type_node, + endlink)))); + custom_fnfi + = build_function_type (float_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, float_type_node, + tree_cons (NULL_TREE, integer_type_node, + endlink)))); + custom_fnff + = build_function_type (float_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, float_type_node, + tree_cons (NULL_TREE, float_type_node, + endlink)))); + custom_fnfp + = build_function_type (float_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, float_type_node, + tree_cons (NULL_TREE, ptr_type_node, + endlink)))); + custom_fnpi + = build_function_type (float_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, integer_type_node, + endlink)))); + custom_fnpf + = build_function_type (float_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, float_type_node, + endlink)))); + custom_fnpp + = build_function_type (float_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, ptr_type_node, + endlink)))); + + + custom_pn + = build_function_type (ptr_type_node, + tree_cons (NULL_TREE, integer_type_node, + endlink)); + custom_pni + = build_function_type (ptr_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + endlink))); + custom_pnf + = build_function_type (ptr_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, float_type_node, + endlink))); + custom_pnp + = build_function_type (ptr_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, ptr_type_node, + endlink))); + custom_pnii + = build_function_type (ptr_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + endlink)))); + custom_pnif + = build_function_type (ptr_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, float_type_node, + endlink)))); + custom_pnip + = build_function_type (ptr_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, ptr_type_node, + endlink)))); + custom_pnfi + = build_function_type (ptr_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, float_type_node, + tree_cons (NULL_TREE, integer_type_node, + endlink)))); + custom_pnff + = build_function_type (ptr_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, float_type_node, + tree_cons (NULL_TREE, float_type_node, + endlink)))); + custom_pnfp + = build_function_type (ptr_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, float_type_node, + tree_cons (NULL_TREE, ptr_type_node, + endlink)))); + custom_pnpi + = build_function_type (ptr_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, integer_type_node, + endlink)))); + custom_pnpf + = build_function_type (ptr_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, float_type_node, + endlink)))); + custom_pnpp + = build_function_type (ptr_type_node, + tree_cons (NULL_TREE, integer_type_node, + tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, ptr_type_node, + endlink)))); + + custom_zdz + = build_function_type (void_type_node, + tree_cons (NULL_TREE, double_type_node, + endlink)); + + custom_zsz + = build_function_type (void_type_node, + tree_cons (NULL_TREE, float_type_node, + endlink)); + + custom_szz + = build_function_type (float_type_node, + tree_cons (NULL_TREE, void_type_node, + endlink)); + + custom_sss + = build_function_type (float_type_node, + tree_cons (NULL_TREE, float_type_node, + tree_cons (NULL_TREE, float_type_node, + endlink))); + + custom_ssz + = build_function_type (float_type_node, + tree_cons (NULL_TREE, float_type_node, + endlink)); + + custom_iss + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, float_type_node, + tree_cons (NULL_TREE, float_type_node, + endlink))); + + custom_ddd + = build_function_type (double_type_node, + tree_cons (NULL_TREE, double_type_node, + tree_cons (NULL_TREE, double_type_node, + endlink))); + + custom_ddz + = build_function_type (double_type_node, + tree_cons (NULL_TREE, double_type_node, + endlink)); + + custom_idd + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, double_type_node, + tree_cons (NULL_TREE, double_type_node, + endlink))); + + custom_siz + = build_function_type (float_type_node, + tree_cons (NULL_TREE, integer_type_node, + endlink)); + + custom_suz + = build_function_type (float_type_node, + tree_cons (NULL_TREE, unsigned_type_node, + endlink)); + + custom_diz + = build_function_type (double_type_node, + tree_cons (NULL_TREE, integer_type_node, + endlink)); + + custom_duz + = build_function_type (double_type_node, + tree_cons (NULL_TREE, unsigned_type_node, + endlink)); + + custom_isz + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, float_type_node, + endlink)); + + custom_usz + = build_function_type (unsigned_type_node, + tree_cons (NULL_TREE, float_type_node, + endlink)); + + custom_idz + = build_function_type (integer_type_node, + tree_cons (NULL_TREE, double_type_node, + endlink)); + + custom_udz + = build_function_type (unsigned_type_node, + tree_cons (NULL_TREE, double_type_node, + endlink)); + + custom_dsz + = build_function_type (double_type_node, + tree_cons (NULL_TREE, float_type_node, + endlink)); + + custom_sdz + = build_function_type (float_type_node, + tree_cons (NULL_TREE, double_type_node, + endlink)); + + + for (d = bdesc; d->name; d++) + builtin_function (d->name, *d->type, d->code, + BUILT_IN_MD, NULL, NULL); +} +/* Expand an expression EXP that calls a built-in function, + with result going to TARGET if that's convenient + (and in mode MODE if that's convenient). + SUBTARGET may be used as the target for computing one of EXP's operands. + IGNORE is nonzero if the value is to be ignored. */ + +static rtx +nios2_expand_builtin (tree exp, rtx target, rtx subtarget, + enum machine_mode mode, int ignore) +{ + const struct builtin_description *d; + tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); + unsigned int fcode = DECL_FUNCTION_CODE (fndecl); + + for (d = bdesc; d->name; d++) + if (d->code == fcode) + { + if (d->code > NIOS2_FIRST_FPU_INSN && d->code < NIOS2_LAST_FPU_INSN) + { + nios2_fpu_info *inf = &nios2_fpu_insns[d->code - + (NIOS2_FIRST_FPU_INSN + 1)]; + const struct insn_data *idata = &insn_data[d->icode]; + if (inf->N < 0) + fatal_error ("Cannot call `%s' without specifying switch" + " `-mcustom-%s'", + d->name, + inf->option); + if (inf->args[0] != 'z' + && (!target + || !(idata->operand[0].predicate) (target, + idata->operand[0].mode))) + target = gen_reg_rtx (idata->operand[0].mode); + } + return (d->expander) (d, exp, target, subtarget, mode, ignore); + } + + /* We should have seen one of the functins we registered. */ + gcc_unreachable (); +} + +static rtx nios2_create_target (const struct builtin_description *, rtx); + + +static rtx +nios2_create_target (const struct builtin_description *d, rtx target) +{ + if (!target + || !(*insn_data[d->icode].operand[0].predicate) ( + target, insn_data[d->icode].operand[0].mode)) + { + target = gen_reg_rtx (insn_data[d->icode].operand[0].mode); + } + + return target; +} + + +static rtx nios2_extract_opcode (const struct builtin_description *, int, tree); +static rtx nios2_extract_operand (const struct builtin_description *, int, int, + tree); + +static rtx +nios2_extract_opcode (const struct builtin_description *d, int op, tree arglist) +{ + enum machine_mode mode = insn_data[d->icode].operand[op].mode; + tree arg = TREE_VALUE (arglist); + rtx opcode = expand_expr (arg, NULL_RTX, mode, 0); + + if (!(*insn_data[d->icode].operand[op].predicate) (opcode, mode)) + error ("Custom instruction opcode must be compile time constant in the " + "range 0-255 for %s", d->name); + + builtin_custom_seen[INTVAL (opcode)] = d->name; + nios2_custom_check_insns (0); + return opcode; +} + +static rtx +nios2_extract_operand (const struct builtin_description *d, int op, int argnum, + tree arglist) +{ + enum machine_mode mode = insn_data[d->icode].operand[op].mode; + tree arg = TREE_VALUE (arglist); + rtx operand = expand_expr (arg, NULL_RTX, mode, 0); + + if (!(*insn_data[d->icode].operand[op].predicate) (operand, mode)) + operand = copy_to_mode_reg (mode, operand); + + /* ??? Better errors would be nice. */ + if (!(*insn_data[d->icode].operand[op].predicate) (operand, mode)) + error ("Invalid argument %d to %s", argnum, d->name); + + return operand; +} + + +static rtx +nios2_expand_custom_n (const struct builtin_description *d, tree exp, + rtx target ATTRIBUTE_UNUSED, + rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree arglist = TREE_OPERAND (exp, 1); + rtx pat; + rtx opcode; + + /* custom_n should have exactly one operand. */ + gcc_assert (insn_data[d->icode].n_operands == 1); + + opcode = nios2_extract_opcode (d, 0, arglist); + + pat = GEN_FCN (d->icode) (opcode); + if (!pat) + return 0; + emit_insn (pat); + return 0; +} + +static rtx +nios2_expand_custom_Xn (const struct builtin_description *d, tree exp, + rtx target, rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree arglist = TREE_OPERAND (exp, 1); + rtx pat; + rtx opcode; + + /* custom_Xn should have exactly two operands. */ + gcc_assert (insn_data[d->icode].n_operands == 2); + + target = nios2_create_target (d, target); + opcode = nios2_extract_opcode (d, 1, arglist); + + pat = GEN_FCN (d->icode) (target, opcode); + if (!pat) + return 0; + emit_insn (pat); + return target; +} + +static rtx +nios2_expand_custom_nX (const struct builtin_description *d, tree exp, + rtx target ATTRIBUTE_UNUSED, + rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree arglist = TREE_OPERAND (exp, 1); + rtx pat; + rtx opcode; + rtx operands[1]; + int i; + + + /* custom_nX should have exactly two operands. */ + gcc_assert (insn_data[d->icode].n_operands == 2); + + opcode = nios2_extract_opcode (d, 0, arglist); + for (i = 0; i < 1; i++) + { + arglist = TREE_CHAIN (arglist); + operands[i] = nios2_extract_operand (d, i + 1, i + 1, arglist); + } + + pat = GEN_FCN (d->icode) (opcode, operands[0]); + if (!pat) + return 0; + emit_insn (pat); + return 0; +} + +static rtx +nios2_expand_custom_XnX (const struct builtin_description *d, tree exp, + rtx target, rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree arglist = TREE_OPERAND (exp, 1); + rtx pat; + rtx opcode; + rtx operands[1]; + int i; + + /* custom_Xn should have exactly three operands. */ + gcc_assert (insn_data[d->icode].n_operands == 3); + + target = nios2_create_target (d, target); + opcode = nios2_extract_opcode (d, 1, arglist); + + for (i = 0; i < 1; i++) + { + arglist = TREE_CHAIN (arglist); + operands[i] = nios2_extract_operand (d, i + 2, i + 1, arglist); + } + + pat = GEN_FCN (d->icode) (target, opcode, operands[0]); + + if (!pat) + return 0; + emit_insn (pat); + return target; +} + +static rtx +nios2_expand_custom_nXX (const struct builtin_description *d, tree exp, + rtx target ATTRIBUTE_UNUSED, + rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree arglist = TREE_OPERAND (exp, 1); + rtx pat; + rtx opcode; + rtx operands[2]; + int i; + + + /* custom_nX should have exactly three operands. */ + gcc_assert (insn_data[d->icode].n_operands == 3); + + opcode = nios2_extract_opcode (d, 0, arglist); + for (i = 0; i < 2; i++) + { + arglist = TREE_CHAIN (arglist); + operands[i] = nios2_extract_operand (d, i + 1, i + 1, arglist); + } + + pat = GEN_FCN (d->icode) (opcode, operands[0], operands[1]); + if (!pat) + return 0; + emit_insn (pat); + return 0; +} + +static rtx +nios2_expand_custom_XnXX (const struct builtin_description *d, tree exp, + rtx target, rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree arglist = TREE_OPERAND (exp, 1); + rtx pat; + rtx opcode; + rtx operands[2]; + int i; + + + /* custom_XnX should have exactly four operands. */ + gcc_assert (insn_data[d->icode].n_operands == 4); + + target = nios2_create_target (d, target); + opcode = nios2_extract_opcode (d, 1, arglist); + for (i = 0; i < 2; i++) + { + arglist = TREE_CHAIN (arglist); + operands[i] = nios2_extract_operand (d, i + 2, i + 1, arglist); + } + + pat = GEN_FCN (d->icode) (target, opcode, operands[0], operands[1]); + + if (!pat) + return 0; + emit_insn (pat); + return target; +} + + + +static rtx +nios2_expand_STXIO (const struct builtin_description *d, tree exp, + rtx target ATTRIBUTE_UNUSED, + rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree arglist = TREE_OPERAND (exp, 1); + rtx pat; + rtx store_dest, store_val; + enum insn_code icode = d->icode; + + /* Stores should have exactly two operands. */ + gcc_assert (insn_data[icode].n_operands == 2); + + /* Process the destination of the store. */ + { + enum machine_mode mode = insn_data[icode].operand[0].mode; + tree arg = TREE_VALUE (arglist); + store_dest = expand_expr (arg, NULL_RTX, VOIDmode, 0); + + store_dest = gen_rtx_MEM (mode, copy_to_mode_reg (Pmode, store_dest)); + + /* ??? Better errors would be nice. */ + if (!(*insn_data[icode].operand[0].predicate) (store_dest, mode)) + error ("Invalid argument 1 to %s", d->name); + } + + + /* Process the value to store. */ + { + enum machine_mode mode = insn_data[icode].operand[1].mode; + tree arg = TREE_VALUE (TREE_CHAIN (arglist)); + store_val = expand_expr (arg, NULL_RTX, mode, 0); + + if (!(*insn_data[icode].operand[1].predicate) (store_val, mode)) + store_val = copy_to_mode_reg (mode, store_val); + + /* ??? Better errors would be nice. */ + if (!(*insn_data[icode].operand[1].predicate) (store_val, mode)) + error ("Invalid argument 2 to %s", d->name); + } + + pat = GEN_FCN (d->icode) (store_dest, store_val); + if (!pat) + return 0; + emit_insn (pat); + return 0; +} + + +static rtx +nios2_expand_LDXIO (const struct builtin_description * d, tree exp, rtx target, + rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree arglist = TREE_OPERAND (exp, 1); + rtx pat; + rtx ld_src; + enum insn_code icode = d->icode; + + /* Loads should have exactly two operands. */ + gcc_assert (insn_data[icode].n_operands == 2); + + target = nios2_create_target (d, target); + + { + enum machine_mode mode = insn_data[icode].operand[1].mode; + tree arg = TREE_VALUE (arglist); + ld_src = expand_expr (arg, NULL_RTX, VOIDmode, 0); + + ld_src = gen_rtx_MEM (mode, copy_to_mode_reg (Pmode, ld_src)); + + /* ??? Better errors would be nice. */ + if (!(*insn_data[icode].operand[1].predicate) (ld_src, mode)) + error ("Invalid argument 1 to %s", d->name); + } + + pat = GEN_FCN (d->icode) (target, ld_src); + if (!pat) + return 0; + emit_insn (pat); + return target; +} + + +static rtx +nios2_expand_sync (const struct builtin_description * d ATTRIBUTE_UNUSED, + tree exp ATTRIBUTE_UNUSED, rtx target ATTRIBUTE_UNUSED, + rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + emit_insn (gen_sync ()); + return 0; +} + +static rtx +nios2_expand_rdctl (const struct builtin_description * d ATTRIBUTE_UNUSED, + tree exp ATTRIBUTE_UNUSED, rtx target ATTRIBUTE_UNUSED, + rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree arglist = TREE_OPERAND (exp, 1); + rtx pat; + rtx rdctl_reg; + enum insn_code icode = d->icode; + + /* rdctl should have exactly two operands. */ + gcc_assert (insn_data[icode].n_operands == 2); + + target = nios2_create_target (d, target); + + { + enum machine_mode mode = insn_data[icode].operand[1].mode; + tree arg = TREE_VALUE (arglist); + rdctl_reg = expand_expr (arg, NULL_RTX, VOIDmode, 0); + + if (!(*insn_data[icode].operand[1].predicate) (rdctl_reg, mode)) + error ("Control register number must be in range 0-31 for %s", d->name); + } + + pat = GEN_FCN (d->icode) (target, rdctl_reg); + if (!pat) + return 0; + emit_insn (pat); + return target; +} + +static rtx +nios2_expand_wrctl (const struct builtin_description * d ATTRIBUTE_UNUSED, + tree exp ATTRIBUTE_UNUSED, rtx target ATTRIBUTE_UNUSED, + rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree arglist = TREE_OPERAND (exp, 1); + rtx pat; + rtx wrctl_reg, store_val; + enum insn_code icode = d->icode; + + /* Stores should have exactly two operands. */ + gcc_assert (insn_data[icode].n_operands == 2); + + /* Process the destination of the store. */ + { + enum machine_mode mode = insn_data[icode].operand[0].mode; + tree arg = TREE_VALUE (arglist); + wrctl_reg = expand_expr (arg, NULL_RTX, VOIDmode, 0); + + if (!(*insn_data[icode].operand[0].predicate) (wrctl_reg, mode)) + error ("Control register number must be in range 0-31 for %s", d->name); + } + + + /* Process the value to store. */ + { + enum machine_mode mode = insn_data[icode].operand[1].mode; + tree arg = TREE_VALUE (TREE_CHAIN (arglist)); + store_val = expand_expr (arg, NULL_RTX, mode, 0); + + if (!(*insn_data[icode].operand[1].predicate) (store_val, mode)) + store_val = copy_to_mode_reg (mode, store_val); + + /* ??? Better errors would be nice. */ + if (!(*insn_data[icode].operand[1].predicate) (store_val, mode)) + error ("Invalid argument 2 to %s", d->name); + } + + pat = GEN_FCN (d->icode) (wrctl_reg, store_val); + if (!pat) + return 0; + emit_insn (pat); + return 0; +} + +static rtx +nios2_extract_double (const struct insn_data *idata, tree arglist, int index) +{ + rtx arg; + + while (index--) + arglist = TREE_CHAIN (arglist); + arg = expand_expr (TREE_VALUE (arglist), NULL_RTX, DFmode, 0); + if (!(*(idata->operand[index+1].predicate)) (arg, DFmode)) + arg = copy_to_mode_reg (DFmode, arg); + return arg; +} + +static rtx +nios2_extract_float (const struct insn_data *idata, tree arglist, int index) +{ + rtx arg; + + while (index--) + arglist = TREE_CHAIN (arglist); + arg = expand_expr (TREE_VALUE (arglist), NULL_RTX, SFmode, 0); + if (!(*(idata->operand[index+1].predicate)) (arg, SFmode)) + arg = copy_to_mode_reg (SFmode, arg); + return arg; +} + +static rtx +nios2_extract_integer (const struct insn_data *idata, tree arglist, int index) +{ + rtx arg; + + while (index--) + arglist = TREE_CHAIN (arglist); + arg = expand_expr (TREE_VALUE (arglist), NULL_RTX, SImode, 0); + if (!(*(idata->operand[index+1].predicate)) (arg, SImode)) + arg = copy_to_mode_reg (SImode, arg); + return arg; +} + +static rtx +nios2_expand_custom_zdz (const struct builtin_description *d, + tree exp, + rtx target ATTRIBUTE_UNUSED, + rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree arglist = TREE_OPERAND (exp, 1); + rtx pat = GEN_FCN (d->icode) (nios2_extract_double (&insn_data[d->icode], + arglist, 0)); + if (pat) + emit_insn (pat); + return 0; +} + +static rtx +nios2_expand_custom_zsz (const struct builtin_description *d, + tree exp, + rtx target ATTRIBUTE_UNUSED, + rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree arglist = TREE_OPERAND (exp, 1); + rtx pat = GEN_FCN (d->icode) (nios2_extract_float (&insn_data[d->icode], + arglist, 0)); + if (pat) + emit_insn (pat); + return 0; +} + +static rtx +nios2_expand_custom_szz (const struct builtin_description *d, + tree exp ATTRIBUTE_UNUSED, + rtx target, + rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + rtx pat = GEN_FCN (d->icode) (target); + if (pat) + emit_insn (pat); + return target; +} + +static rtx +nios2_expand_custom_sss (const struct builtin_description *d, + tree exp, + rtx target, + rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree arglist = TREE_OPERAND (exp, 1); + rtx pat = GEN_FCN (d->icode) (target, + nios2_extract_float (&insn_data[d->icode], + arglist, 0), + nios2_extract_float (&insn_data[d->icode], + arglist, 1)); + if (pat) + emit_insn (pat); + return target; +} + +static rtx +nios2_expand_custom_ssz (const struct builtin_description *d, + tree exp, + rtx target, + rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree arglist = TREE_OPERAND (exp, 1); + rtx pat = GEN_FCN (d->icode) (target, + nios2_extract_float (&insn_data[d->icode], + arglist, 0)); + if (pat) + emit_insn (pat); + return target; +} + +static rtx +nios2_expand_custom_iss (const struct builtin_description *d, + tree exp, + rtx target, + rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree arglist = TREE_OPERAND (exp, 1); + rtx pat = GEN_FCN (d->icode) (target, + nios2_extract_float (&insn_data[d->icode], + arglist, 0), + nios2_extract_float (&insn_data[d->icode], + arglist, 1)); + if (pat) + emit_insn (pat); + return target; +} + +static rtx +nios2_expand_custom_ddd (const struct builtin_description *d, + tree exp, + rtx target, + rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree arglist = TREE_OPERAND (exp, 1); + rtx pat = GEN_FCN (d->icode) (target, + nios2_extract_double (&insn_data[d->icode], + arglist, 0), + nios2_extract_double (&insn_data[d->icode], + arglist, 1)); + if (pat) + emit_insn (pat); + return target; +} + +static rtx +nios2_expand_custom_ddz (const struct builtin_description *d, + tree exp, + rtx target, + rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree arglist = TREE_OPERAND (exp, 1); + rtx pat = GEN_FCN (d->icode) (target, + nios2_extract_double (&insn_data[d->icode], + arglist, 0)); + if (pat) + emit_insn (pat); + return target; +} + +static rtx +nios2_expand_custom_idd (const struct builtin_description *d, + tree exp, + rtx target, + rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree arglist = TREE_OPERAND (exp, 1); + rtx pat = GEN_FCN (d->icode) (target, + nios2_extract_double (&insn_data[d->icode], + arglist, 0), + nios2_extract_double (&insn_data[d->icode], + arglist, 1)); + if (pat) + emit_insn (pat); + return target; +} + +static rtx +nios2_expand_custom_siz (const struct builtin_description *d, + tree exp, + rtx target, + rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree arglist = TREE_OPERAND (exp, 1); + rtx pat = GEN_FCN (d->icode) (target, + nios2_extract_integer (&insn_data[d->icode], + arglist, 0)); + if (pat) + emit_insn (pat); + return target; +} + +static rtx +nios2_expand_custom_suz (const struct builtin_description *d, + tree exp, + rtx target, + rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree arglist = TREE_OPERAND (exp, 1); + rtx pat = GEN_FCN (d->icode) (target, + nios2_extract_integer (&insn_data[d->icode], + arglist, 0)); + if (pat) + emit_insn (pat); + return target; +} + +static rtx +nios2_expand_custom_diz (const struct builtin_description *d, + tree exp, + rtx target, + rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree arglist = TREE_OPERAND (exp, 1); + rtx pat = GEN_FCN (d->icode) (target, + nios2_extract_integer (&insn_data[d->icode], + arglist, 0)); + if (pat) + emit_insn (pat); + return target; +} + +static rtx +nios2_expand_custom_duz (const struct builtin_description *d, + tree exp, + rtx target, + rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree arglist = TREE_OPERAND (exp, 1); + rtx pat = GEN_FCN (d->icode) (target, + nios2_extract_integer (&insn_data[d->icode], + arglist, 0)); + if (pat) + emit_insn (pat); + return target; +} + +static rtx +nios2_expand_custom_isz (const struct builtin_description *d, + tree exp, + rtx target, + rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree arglist = TREE_OPERAND (exp, 1); + rtx pat = GEN_FCN (d->icode) (target, + nios2_extract_float (&insn_data[d->icode], + arglist, 0)); + if (pat) + emit_insn (pat); + return target; +} + +static rtx +nios2_expand_custom_usz (const struct builtin_description *d, + tree exp, + rtx target, + rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree arglist = TREE_OPERAND (exp, 1); + rtx pat = GEN_FCN (d->icode) (target, + nios2_extract_float (&insn_data[d->icode], + arglist, 0)); + if (pat) + emit_insn (pat); + return target; +} + +static rtx +nios2_expand_custom_idz (const struct builtin_description *d, + tree exp, + rtx target, + rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree arglist = TREE_OPERAND (exp, 1); + rtx pat = GEN_FCN (d->icode) (target, + nios2_extract_double (&insn_data[d->icode], + arglist, 0)); + if (pat) + emit_insn (pat); + return target; +} + +static rtx +nios2_expand_custom_udz (const struct builtin_description *d, + tree exp, + rtx target, + rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree arglist = TREE_OPERAND (exp, 1); + rtx pat = GEN_FCN (d->icode) (target, + nios2_extract_double (&insn_data[d->icode], + arglist, 0)); + if (pat) + emit_insn (pat); + return target; +} + +static rtx +nios2_expand_custom_dsz (const struct builtin_description *d, + tree exp, + rtx target, + rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree arglist = TREE_OPERAND (exp, 1); + rtx pat = GEN_FCN (d->icode) (target, + nios2_extract_float (&insn_data[d->icode], + arglist, 0)); + if (pat) + emit_insn (pat); + return target; +} + +static rtx +nios2_expand_custom_sdz (const struct builtin_description *d, + tree exp, + rtx target, + rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree arglist = TREE_OPERAND (exp, 1); + rtx pat = GEN_FCN (d->icode) (target, + nios2_extract_double (&insn_data[d->icode], + arglist, 0)); + if (pat) + emit_insn (pat); + return target; +} + +#include "gt-nios2.h" + Index: gcc-4.1.2/gcc/config/nios2/nios2.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gcc-4.1.2/gcc/config/nios2/nios2.h 2010-06-30 08:50:26.000000000 +0200 @@ -0,0 +1,1064 @@ +/* NOT ASSIGNED TO FSF. COPYRIGHT ALTERA. */ +/* Definitions of target machine for Altera NIOS 2G NIOS2 version. + Copyright (C) 2007 Altera + Contributed by Jonah Graham (jgraham@altera.com), + Will Reece (wreece@altera.com), and Jeff DaSilva (jdasilva@altera.com). + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + + + +#define TARGET_CPU_CPP_BUILTINS() \ + do \ + { \ + builtin_define_std ("NIOS2"); \ + builtin_define_std ("nios2"); \ + if (TARGET_BIG_ENDIAN) \ + builtin_define_std ("nios2_big_endian"); \ + else \ + builtin_define_std ("nios2_little_endian"); \ + } \ + while (0) +#define TARGET_VERSION fprintf (stderr, " (Altera Nios II)") + + + + + +/********************************* + * Run-time Target Specification + *********************************/ + +extern int target_flags; + +/* + * There's a lot of error-prone tedium with all the different + * custom floating point instructions. Try to automate it a bit + * to make it easier to deal with. + */ +#define NIOS2_STRINGIFY_INNER(x) #x +#define NIOS2_STRINGIFY(x) NIOS2_STRINGIFY_INNER(x) +#define NIOS2_CONCAT_INNER(x, y) x ## y +#define NIOS2_CONCAT(x, y) NIOS2_CONCAT_INNER (x, y) + +#define NIOS2_FOR_ALL_FPU_INSNS \ + NIOS2_FPU_INSN (fwrx, nios2_fwrx, zdz) \ + NIOS2_FPU_INSN (fwry, nios2_fwry, zsz) \ + NIOS2_FPU_INSN (frdxlo, nios2_frdxlo, szz) \ + NIOS2_FPU_INSN (frdxhi, nios2_frdxhi, szz) \ + NIOS2_FPU_INSN (frdy, nios2_frdy, szz) \ +\ + NIOS2_FPU_INSN (fadds, addsf3, sss) \ + NIOS2_FPU_INSN (fsubs, subsf3, sss) \ + NIOS2_FPU_INSN (fmuls, mulsf3, sss) \ + NIOS2_FPU_INSN (fdivs, divsf3, sss) \ + NIOS2_FPU_INSN (fmins, minsf3, sss) \ + NIOS2_FPU_INSN (fmaxs, maxsf3, sss) \ + NIOS2_FPU_INSN (fnegs, negsf2, ssz) \ + NIOS2_FPU_INSN (fabss, abssf2, ssz) \ + NIOS2_FPU_INSN (fsqrts, sqrtsf2, ssz) \ + NIOS2_FPU_INSN (fcoss, cossf2, ssz) \ + NIOS2_FPU_INSN (fsins, sinsf2, ssz) \ + NIOS2_FPU_INSN (ftans, tansf2, ssz) \ + NIOS2_FPU_INSN (fatans, atansf2, ssz) \ + NIOS2_FPU_INSN (fexps, expsf2, ssz) \ + NIOS2_FPU_INSN (flogs, logsf2, ssz) \ + NIOS2_FPU_INSN (fcmplts, nios2_sltsf, iss) \ + NIOS2_FPU_INSN (fcmples, nios2_slesf, iss) \ + NIOS2_FPU_INSN (fcmpgts, nios2_sgtsf, iss) \ + NIOS2_FPU_INSN (fcmpges, nios2_sgesf, iss) \ + NIOS2_FPU_INSN (fcmpeqs, nios2_seqsf, iss) \ + NIOS2_FPU_INSN (fcmpnes, nios2_snesf, iss) \ +\ + NIOS2_FPU_INSN (faddd, adddf3, ddd) \ + NIOS2_FPU_INSN (fsubd, subdf3, ddd) \ + NIOS2_FPU_INSN (fmuld, muldf3, ddd) \ + NIOS2_FPU_INSN (fdivd, divdf3, ddd) \ + NIOS2_FPU_INSN (fmind, mindf3, ddd) \ + NIOS2_FPU_INSN (fmaxd, maxdf3, ddd) \ + NIOS2_FPU_INSN (fnegd, negdf2, ddz) \ + NIOS2_FPU_INSN (fabsd, absdf2, ddz) \ + NIOS2_FPU_INSN (fsqrtd, sqrtdf2, ddz) \ + NIOS2_FPU_INSN (fcosd, cosdf2, ddz) \ + NIOS2_FPU_INSN (fsind, sindf2, ddz) \ + NIOS2_FPU_INSN (ftand, tandf2, ddz) \ + NIOS2_FPU_INSN (fatand, atandf2, ddz) \ + NIOS2_FPU_INSN (fexpd, expdf2, ddz) \ + NIOS2_FPU_INSN (flogd, logdf2, ddz) \ + NIOS2_FPU_INSN (fcmpltd, nios2_sltdf, idd) \ + NIOS2_FPU_INSN (fcmpled, nios2_sledf, idd) \ + NIOS2_FPU_INSN (fcmpgtd, nios2_sgtdf, idd) \ + NIOS2_FPU_INSN (fcmpged, nios2_sgedf, idd) \ + NIOS2_FPU_INSN (fcmpeqd, nios2_seqdf, idd) \ + NIOS2_FPU_INSN (fcmpned, nios2_snedf, idd) \ +\ + NIOS2_FPU_INSN (floatis, floatsisf2, siz) \ + NIOS2_FPU_INSN (floatus, floatunssisf2, suz) \ + NIOS2_FPU_INSN (floatid, floatsidf2, diz) \ + NIOS2_FPU_INSN (floatud, floatunssidf2, duz) \ + NIOS2_FPU_INSN (fixsi, fixsfsi2, isz) \ + NIOS2_FPU_INSN (fixsu, fixunssfsi2, usz) \ + NIOS2_FPU_INSN (fixdi, fixdfsi2, idz) \ + NIOS2_FPU_INSN (fixdu, fixunsdfsi2, udz) \ + NIOS2_FPU_INSN (fextsd, extendsfdf2, dsz) \ + NIOS2_FPU_INSN (ftruncds, truncdfsf2, sdz) + +enum +{ +#define NIOS2_FPU_INSN(opt, insn, args) \ + NIOS2_CONCAT (nios2_fpu_, insn), +NIOS2_FOR_ALL_FPU_INSNS + nios2_fpu_max_insn +}; + +struct cpp_reader; +typedef const char * (*nios2_outputfn) (rtx); +typedef void (*nios2_pragmafn) (struct cpp_reader *); + +typedef struct +{ + const char *option; /* name of switch, e.g. fadds */ + const char *insnnm; /* name of gcc insn, e.g. addsf3 */ + const char *args; /* args to gcc insn, e.g. sss */ + int N; /* value of switch as an integer, -1 = not used */ + nios2_outputfn output; /* output function for use in .md file */ + const char *pname; /* name of corresponding #pragma custom- */ + nios2_pragmafn pragma; /* pragma function for register_target_pragmas */ + const char *nopname; /* name of corresponding #pragma no-custom- */ + nios2_pragmafn nopragma; /* pragma function for register_target_pragmas */ + int is_double; /* does this insn have any double operands */ + int needed_by_double; /* is this insn needed if doubles are used? */ + int needs_unsafe; /* does this insn require + -funsafe-math-optimizations to work? */ + int needs_finite; /* does this insn require + -ffinite-math-only to work? */ + int pragma_seen; /* have we seen the corresponding #pragma? */ + int* pN; /* pointer to the value as set by the option + parser. */ +} nios2_fpu_info; + +extern nios2_fpu_info nios2_fpu_insns[nios2_fpu_max_insn]; +extern const char *nios2_custom_fpu_cfg_string; + +#undef NIOS2_FPU_INSN +#define NIOS2_FPU_INSN(opt, insn, args) \ + extern int NIOS2_CONCAT (nios2_custom_, opt); +NIOS2_FOR_ALL_FPU_INSNS + +/* We're little endian, unless otherwise specified by defining BIG_ENDIAN_FLAG +*/ +#ifndef TARGET_ENDIAN_DEFAULT +# define TARGET_ENDIAN_DEFAULT 0 +#endif + +/* Default target_flags if no switches specified. */ +#ifndef TARGET_DEFAULT +# define TARGET_DEFAULT (MASK_HAS_MUL | \ + TARGET_ENDIAN_DEFAULT) +#endif + +/* Switch Recognition by gcc.c. Add -G xx support */ +#undef SWITCH_TAKES_ARG +#define SWITCH_TAKES_ARG(CHAR) \ + (DEFAULT_SWITCH_TAKES_ARG (CHAR) || (CHAR) == 'G') + +#define OVERRIDE_OPTIONS override_options () +#define OPTIMIZATION_OPTIONS(LEVEL, SIZE) optimization_options (LEVEL, SIZE) +#define CAN_DEBUG_WITHOUT_FP + +#define CC1_SPEC "\ +%{G*} %{EB:-meb} %{EL:-mel} %{EB:%{EL:%emay not use both -EB and -EL}}" + +#if TARGET_ENDIAN_DEFAULT == 0 +# define ASM_SPEC "\ +%{!EB:%{!meb:-EL}} %{EB|meb:-EB}" +# define LINK_SPEC_ENDIAN "\ +%{!EB:%{!meb:-EL}} %{EB|meb:-EB}" +# define MULTILIB_DEFAULTS { "EL" } +#else +# define ASM_SPEC "\ +%{!EL:%{!mel:-EB}} %{EL|mel:-EL}" +# define LINK_SPEC_ENDIAN "\ +%{!EL:%{!mel:-EB}} %{EL|mel:-EL}" +# define MULTILIB_DEFAULTS { "EB" } +#endif + +#define LINK_SPEC LINK_SPEC_ENDIAN \ + " %{shared:-shared} \ + %{static:-Bstatic}" + +#undef LIB_SPEC +#define LIB_SPEC \ +"--start-group -lc -lgcc \ + -lnosys -lstack \ + --end-group \ +" + + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC \ +"crt0%O%s" + +#undef ENDFILE_SPEC +#define ENDFILE_SPEC \ + "" + + +/*********************** + * Storage Layout + ***********************/ + +#define DEFAULT_SIGNED_CHAR 1 +#define BITS_BIG_ENDIAN 0 +#define BYTES_BIG_ENDIAN (TARGET_BIG_ENDIAN != 0) +#define WORDS_BIG_ENDIAN (TARGET_BIG_ENDIAN != 0) +#if defined(__nios2_big_endian__) +#define LIBGCC2_WORDS_BIG_ENDIAN 1 +#else +#define LIBGCC2_WORDS_BIG_ENDIAN 0 +#endif +#define BITS_PER_UNIT 8 +#define BITS_PER_WORD 32 +#define UNITS_PER_WORD 4 +#define POINTER_SIZE 32 +#define BIGGEST_ALIGNMENT 32 +#define STRICT_ALIGNMENT 1 +#define FUNCTION_BOUNDARY 32 +#define PARM_BOUNDARY 32 +#define STACK_BOUNDARY 32 +#define PREFERRED_STACK_BOUNDARY 32 +#define MAX_FIXED_MODE_SIZE 64 + +#define CONSTANT_ALIGNMENT(EXP, ALIGN) \ + ((TREE_CODE (EXP) == STRING_CST) \ + && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN)) + + +/********************** + * Layout of Source Language Data Types + **********************/ + +#define INT_TYPE_SIZE 32 +#define SHORT_TYPE_SIZE 16 +#define LONG_TYPE_SIZE 32 +#define LONG_LONG_TYPE_SIZE 64 +#define FLOAT_TYPE_SIZE 32 +#define DOUBLE_TYPE_SIZE 64 +#define LONG_DOUBLE_TYPE_SIZE DOUBLE_TYPE_SIZE + + +/************************* + * Condition Code Status + ************************/ + +/* comparison type */ +/* ??? Currently CMP_DI is unused. CMP_SF and CMP_DF are only used if + the corresponding -mcustom- switches are present. */ +enum cmp_type { + CMP_SI, /* compare four byte integers */ + CMP_DI, /* compare eight byte integers */ + CMP_SF, /* compare single precision floats */ + CMP_DF, /* compare double precision floats */ + CMP_MAX /* max comparison type */ +}; + +extern GTY(()) rtx branch_cmp[2]; /* operands for compare */ +extern enum cmp_type branch_type; /* what type of branch to use */ + +/********************** + * Register Usage + **********************/ + +/* ---------------------------------- * + * Basic Characteristics of Registers + * ---------------------------------- */ + +/* +Register Number + Register Name + Alternate Name + Purpose +0 r0 zero always zero +1 r1 at Assembler Temporary +2-3 r2-r3 Return Location +4-7 r4-r7 Register Arguments +8-15 r8-r15 Caller Saved Registers +16-22 r16-r22 Callee Saved Registers +21 r21 sc Static Chain (Callee Saved) + ??? Does $sc want to be caller or callee + saved. If caller, 15, else 21. +22 r22 Global Offset Table pointer +23 r23 Thread pointer +24 r24 et Exception Temporary +25 r25 bt Breakpoint Temporary +26 r26 gp Global Pointer +27 r27 sp Stack Pointer +28 r28 fp Frame Pointer +29 r29 ea Exception Return Address +30 r30 ba Breakpoint Return Address +31 r31 ra Return Address + +32 ctl0 status +33 ctl1 estatus STATUS saved by exception ? +34 ctl2 bstatus STATUS saved by break ? +35 ctl3 ipri Interrupt Priority Mask ? +36 ctl4 ecause Exception Cause ? + +37 pc Not an actual register + +38 fake_fp Fake Frame Pointer which will always be eliminated. +39 fake_ap Fake Argument Pointer which will always be eliminated. + +40 First Pseudo Register + + +The definitions for all the hard register numbers +are located in nios2.md. +*/ + +#define ET_REGNO (24) +#define GP_REGNO (26) +#define SP_REGNO (27) +#define FP_REGNO (28) +#define EA_REGNO (29) +#define RA_REGNO (31) +#define FIRST_RETVAL_REGNO (2) +#define LAST_RETVAL_REGNO (3) +#define FIRST_ARG_REGNO (4) +#define LAST_ARG_REGNO (7) +#define SC_REGNO (21) +#define PC_REGNO (37) +#define FAKE_FP_REGNO (38) +#define FAKE_AP_REGNO (39) + +#define FIRST_PSEUDO_REGISTER 40 +#define NUM_ARG_REGS (LAST_ARG_REGNO - FIRST_ARG_REGNO + 1) + + + +#define FIXED_REGISTERS \ + { \ +/* +0 1 2 3 4 5 6 7 8 9 */ \ +/* 0 */ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, \ +/* 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ +/* 20 */ 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, \ +/* 30 */ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, \ + } + +/* call used is the same as caller saved + + fixed regs + args + ret vals */ +#define CALL_USED_REGISTERS \ + { \ +/* +0 1 2 3 4 5 6 7 8 9 */ \ +/* 0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ +/* 10 */ 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, \ +/* 20 */ 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, \ +/* 30 */ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, \ + } + +#define THREAD_POINTER_REGNUM 23 + +#define HARD_REGNO_NREGS(REGNO, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \ + / UNITS_PER_WORD) + +/* --------------------------- * + * How Values Fit in Registers + * --------------------------- */ + +#define HARD_REGNO_MODE_OK(REGNO, MODE) 1 + +#define MODES_TIEABLE_P(MODE1, MODE2) 1 + + +/************************* + * Register Classes + *************************/ + +enum reg_class +{ + NO_REGS, + D00_REG, + D01_REG, + D02_REG, + D03_REG, + D04_REG, + D05_REG, + D06_REG, + D07_REG, + D08_REG, + D09_REG, + D10_REG, + D11_REG, + D12_REG, + D13_REG, + D14_REG, + D15_REG, + D16_REG, + D17_REG, + D18_REG, + D19_REG, + D20_REG, + D21_REG, + D22_REG, + D23_REG, + D24_REG, + D25_REG, + D26_REG, + D27_REG, + D28_REG, + D29_REG, + D30_REG, + D31_REG, + SIB_REGS, + GP_REGS, + ALL_REGS, + LIM_REG_CLASSES +}; + +#define N_REG_CLASSES (int) LIM_REG_CLASSES + +#define REG_CLASS_NAMES \ + {"NO_REGS", \ + "D00_REG", \ + "D01_REG", \ + "D02_REG", \ + "D03_REG", \ + "D04_REG", \ + "D05_REG", \ + "D06_REG", \ + "D07_REG", \ + "D08_REG", \ + "D09_REG", \ + "D10_REG", \ + "D11_REG", \ + "D12_REG", \ + "D13_REG", \ + "D14_REG", \ + "D15_REG", \ + "D16_REG", \ + "D17_REG", \ + "D18_REG", \ + "D19_REG", \ + "D20_REG", \ + "D21_REG", \ + "D22_REG", \ + "D23_REG", \ + "D24_REG", \ + "D25_REG", \ + "D26_REG", \ + "D27_REG", \ + "D28_REG", \ + "D29_REG", \ + "D30_REG", \ + "D31_REG", \ + "SIB_REGS", \ + "GP_REGS", \ + "ALL_REGS"} + +#define GENERAL_REGS ALL_REGS + +#define REG_CLASS_CONTENTS \ +/* NO_REGS */ {{ 0, 0}, \ +/* D00_REG */ { 1 << 0, 0}, \ +/* D01_REG */ { 1 << 1, 0}, \ +/* D02_REG */ { 1 << 2, 0}, \ +/* D03_REG */ { 1 << 3, 0}, \ +/* D04_REG */ { 1 << 4, 0}, \ +/* D05_REG */ { 1 << 5, 0}, \ +/* D06_REG */ { 1 << 6, 0}, \ +/* D07_REG */ { 1 << 7, 0}, \ +/* D08_REG */ { 1 << 8, 0}, \ +/* D09_REG */ { 1 << 9, 0}, \ +/* D10_REG */ { 1 << 10, 0}, \ +/* D11_REG */ { 1 << 11, 0}, \ +/* D12_REG */ { 1 << 12, 0}, \ +/* D13_REG */ { 1 << 13, 0}, \ +/* D14_REG */ { 1 << 14, 0}, \ +/* D15_REG */ { 1 << 15, 0}, \ +/* D16_REG */ { 1 << 16, 0}, \ +/* D17_REG */ { 1 << 17, 0}, \ +/* D18_REG */ { 1 << 18, 0}, \ +/* D19_REG */ { 1 << 19, 0}, \ +/* D20_REG */ { 1 << 20, 0}, \ +/* D21_REG */ { 1 << 21, 0}, \ +/* D22_REG */ { 1 << 22, 0}, \ +/* D23_REG */ { 1 << 23, 0}, \ +/* D24_REG */ { 1 << 24, 0}, \ +/* D25_REG */ { 1 << 25, 0}, \ +/* D26_REG */ { 1 << 26, 0}, \ +/* D27_REG */ { 1 << 27, 0}, \ +/* D28_REG */ { 1 << 28, 0}, \ +/* D29_REG */ { 1 << 29, 0}, \ +/* D30_REG */ { 1 << 30, 0}, \ +/* D31_REG */ { 1 << 31, 0}, \ +/* SIB_REGS */ { 0xfe0c, 0}, \ +/* GP_REGS */ {~0, 0}, \ +/* ALL_REGS */ {~0,~0}} \ + +#define GP_REGNO_P(REGNO) ((REGNO) < 32) +#define REGNO_REG_CLASS(REGNO) (GP_REGNO_P (REGNO) ? GP_REGS : ALL_REGS) + +#define BASE_REG_CLASS ALL_REGS +#define INDEX_REG_CLASS ALL_REGS + +/* 'r', is handled automatically */ +#define REG_CLASS_FROM_LETTER(C) ((C) == 'j' ? SIB_REGS : NO_REGS) + +#define REG_CLASS_FROM_CONSTRAINT(CHAR, STR) \ + ((CHAR) == 'j' ? SIB_REGS : \ + reg_class_from_constraint ((CHAR), (STR))) + + +#define REGNO_OK_FOR_BASE_P2(REGNO, STRICT) \ + ((STRICT) \ + ? (REGNO) < FIRST_PSEUDO_REGISTER \ + : (REGNO) < FIRST_PSEUDO_REGISTER || \ + (reg_renumber && reg_renumber[REGNO] < FIRST_PSEUDO_REGISTER)) + +#define REGNO_OK_FOR_INDEX_P2(REGNO, STRICT) \ + (REGNO_OK_FOR_BASE_P2 (REGNO, STRICT)) + +#define REGNO_OK_FOR_BASE_P(REGNO) \ + (REGNO_OK_FOR_BASE_P2 (REGNO, 1)) + +#define REGNO_OK_FOR_INDEX_P(REGNO) \ + (REGNO_OK_FOR_INDEX_P2 (REGNO, 1)) + +#define REG_OK_FOR_BASE_P2(X, STRICT) \ + (STRICT \ + ? REGNO_OK_FOR_BASE_P2 (REGNO (X), 1) \ + : REGNO_OK_FOR_BASE_P2 (REGNO (X), 1) || \ + REGNO(X) >= FIRST_PSEUDO_REGISTER) + +#define REG_OK_FOR_INDEX_P2(X, STRICT) \ + (STRICT \ + ? REGNO_OK_FOR_INDEX_P2 (REGNO (X), 1) \ + : REGNO_OK_FOR_INDEX_P2 (REGNO (X), 1) || \ + REGNO(X) >= FIRST_PSEUDO_REGISTER) + +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \ + / UNITS_PER_WORD) + + +#define SMALL_INT(X) ((unsigned HOST_WIDE_INT) ((X) + 0x8000) < 0x10000) +#define SMALL_INT_UNSIGNED(X) ((unsigned HOST_WIDE_INT) (X) < 0x10000) +#define UPPER16_INT(X) (((X) & 0xffff) == 0) +#define SHIFT_INT(X) ((X) >= 0 && (X) <= 31) +#define RDWRCTL_INT(X) ((X) >= 0 && (X) <= 31) +#define CUSTOM_INSN_OPCODE(X) ((X) >= 0 && (X) <= 255) + +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ( \ + (C) == 'I' ? SMALL_INT (VALUE) : \ + (C) == 'J' ? SMALL_INT_UNSIGNED (VALUE) : \ + (C) == 'K' ? UPPER16_INT (VALUE) : \ + (C) == 'L' ? SHIFT_INT (VALUE) : \ + (C) == 'M' ? (VALUE) == 0 : \ + (C) == 'N' ? CUSTOM_INSN_OPCODE (VALUE) : \ + (C) == 'O' ? RDWRCTL_INT (VALUE) : \ + 0) + +#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) 0 + +#define PREFERRED_RELOAD_CLASS(X, CLASS) \ + ((CLASS) == NO_REGS ? GENERAL_REGS : (CLASS)) + +#define CONSTRAINT_LEN(C, STR) \ + ((C) == 'D' ? 3 : DEFAULT_CONSTRAINT_LEN ((C), (STR))) + +/* 'S' matches immediates which are in small data + and therefore can be added to gp to create a + 32-bit value. */ +#define EXTRA_CONSTRAINT(VALUE, C) \ + ((C) == 'S' \ + && (GET_CODE (VALUE) == SYMBOL_REF) \ + && SYMBOL_REF_IN_NIOS2_SMALL_DATA_P (VALUE)) + + + + +/* Say that the epilogue uses the return address register. Note that + in the case of sibcalls, the values "used by the epilogue" are + considered live at the start of the called function. */ +#define EPILOGUE_USES(REGNO) ((REGNO) == RA_REGNO) + + +/********************************** + * Trampolines for Nested Functions + ***********************************/ + +#define TRAMPOLINE_TEMPLATE(FILE) \ + error ("trampolines not yet implemented") +#define TRAMPOLINE_SIZE 20 +#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \ + error ("trampolines not yet implemented") + +/*************************** + * Stack Layout and Calling Conventions + ***************************/ + +/* ------------------ * + * Basic Stack Layout + * ------------------ */ + +/* The downward variants are used by the compiler, + the upward ones serve as documentation */ +#define STACK_GROWS_DOWNWARD +#define FRAME_GROWS_UPWARD +#define ARGS_GROW_UPWARD + +#define STARTING_FRAME_OFFSET 0 +#define FIRST_PARM_OFFSET(FUNDECL) 0 + +/* Before the prologue, RA lives in r31. */ +#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (VOIDmode, RA_REGNO) +#define RETURN_ADDR_RTX(C,F) nios2_get_return_address (C) + +/* -------------------------------------- * + * Registers That Address the Stack Frame + * -------------------------------------- */ + +#define STACK_POINTER_REGNUM SP_REGNO +#define STATIC_CHAIN_REGNUM SC_REGNO +#define PC_REGNUM PC_REGNO +#define DWARF_FRAME_RETURN_COLUMN RA_REGNO + +/* The DWARF 2 CFA column which tracks the return address from a + signal handler context. */ +#define SIGNAL_UNWIND_RETURN_COLUMN EA_REGNO + +/* Base register for access to local variables of the function. We + pretend that the frame pointer is a non-existent hard register, and + then eliminate it to HARD_FRAME_POINTER_REGNUM. */ +#define FRAME_POINTER_REGNUM FAKE_FP_REGNO + +#define HARD_FRAME_POINTER_REGNUM FP_REGNO +/* the argumnet pointer needs to always be eliminated + so it is set to a fake hard register. */ +#define ARG_POINTER_REGNUM FAKE_AP_REGNO + +/* The CFA includes the pretend args */ +#define ARG_POINTER_CFA_OFFSET(FNDECL) \ + (gcc_assert ((FNDECL) == current_function_decl), \ + FIRST_PARM_OFFSET (FNDECL) + current_function_pretend_args_size) + +/* ----------------------------------------- * + * Eliminating Frame Pointer and Arg Pointer + * ----------------------------------------- */ + +#define FRAME_POINTER_REQUIRED 0 + +#define ELIMINABLE_REGS \ +{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ + { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \ + { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ + { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}} + +#define CAN_ELIMINATE(FROM, TO) \ + ((TO) == STACK_POINTER_REGNUM ? ! frame_pointer_needed : 1) + +#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ + (OFFSET) = nios2_initial_elimination_offset ((FROM), (TO)) + +/* Treat LOC as a byte offset from the stack pointer and round it up + to the next fully-aligned offset. */ +#define STACK_ALIGN(LOC) \ + (((LOC) + ((PREFERRED_STACK_BOUNDARY / 8) - 1)) & \ + ~((PREFERRED_STACK_BOUNDARY / 8) - 1)) + + +/* ------------------------------ * + * Passing Arguments in Registers + * ------------------------------ */ + +/* see nios2.c */ +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ + (function_arg (&CUM, MODE, TYPE, NAMED)) + +#define FUNCTION_ARG_CALLEE_COPIES(CUM, MODE, TYPE, NAMED) 0 + +typedef struct nios2_args +{ + int regs_used; +} CUMULATIVE_ARGS; + +/* This is to initialize the above unused CUM data type */ +#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS) \ + (init_cumulative_args (&CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS)) + +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + (function_arg_advance (&CUM, MODE, TYPE, NAMED)) + +#define FUNCTION_ARG_PADDING(MODE, TYPE) \ + (nios2_function_arg_padding_upward ((MODE), (TYPE)) ? upward : downward) + +#define PAD_VARARGS_DOWN \ + (FUNCTION_ARG_PADDING (TYPE_MODE (type), type) == downward) + +#define BLOCK_REG_PADDING(MODE, TYPE, FIRST) \ + (nios2_block_reg_padding_upward ((MODE), (TYPE), (FIRST)) ? upward : \ + downward) + +#define FUNCTION_ARG_REGNO_P(REGNO) \ + ((REGNO) >= FIRST_ARG_REGNO && (REGNO) <= LAST_ARG_REGNO) + +/* ----------------------------- * + * Generating Code for Profiling + * ----------------------------- */ + + +#define PROFILE_BEFORE_PROLOGUE +#define NO_PROFILE_COUNTERS 1 +#define FUNCTION_PROFILER(FILE, LABELNO) \ + function_profiler ((FILE), (LABELNO)) + +/* --------------------------------------- * + * Passing Function Arguments on the Stack + * --------------------------------------- */ + +#define PUSH_ARGS 0 +#define ACCUMULATE_OUTGOING_ARGS 1 + +#define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, STACKSIZE) 0 + +/* --------------------------------------- * + * How Scalar Function Values Are Returned + * --------------------------------------- */ + +#define FUNCTION_VALUE(VALTYPE, FUNC) \ + gen_rtx_REG(TYPE_MODE(VALTYPE), FIRST_RETVAL_REGNO) + +#define LIBCALL_VALUE(MODE) \ + gen_rtx_REG(MODE, FIRST_RETVAL_REGNO) + +#define FUNCTION_VALUE_REGNO_P(REGNO) ((REGNO) == FIRST_RETVAL_REGNO) + +/* ----------------------------- * + * How Large Values Are Returned + * ----------------------------- */ + + +#define RETURN_IN_MEMORY(TYPE) \ + nios2_return_in_memory (TYPE) + + +#define STRUCT_VALUE 0 + +#define DEFAULT_PCC_STRUCT_RETURN 0 + +/******************* + * Addressing Modes + *******************/ + + +#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \ + do \ + { \ + X = nios2_legitimize_address (X, OLDX, MODE); \ + if (memory_address_p (MODE, X)) \ + goto WIN; \ + } \ + while (0) + +#define CONSTANT_ADDRESS_P(X) \ + (CONSTANT_P (X) && nios2_legitimate_address (X, Pmode, 0)) + +#define MAX_REGS_PER_ADDRESS 1 + +/* Go to ADDR if X is a valid address. */ +#ifndef REG_OK_STRICT +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ + { \ + if (nios2_legitimate_address ((X), (MODE), 0)) \ + goto ADDR; \ + } +#else +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ + { \ + if (nios2_legitimate_address ((X), (MODE), 1)) \ + goto ADDR; \ + } +#endif + +#ifndef REG_OK_STRICT +#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P2 (REGNO (X), 0) +#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P2 (REGNO (X), 0) +#else +#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P2 (REGNO (X), 1) +#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P2 (REGNO (X), 1) +#endif + +#define LEGITIMATE_CONSTANT_P(X) nios2_legitimate_constant (X) + +/* Nios II has no mode dependent addresses. */ +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) + +/* Set if this has a weak declaration */ +#define SYMBOL_FLAG_WEAK_DECL (1 << SYMBOL_FLAG_MACH_DEP_SHIFT) +#define SYMBOL_REF_WEAK_DECL_P(RTX) \ + ((SYMBOL_REF_FLAGS (RTX) & SYMBOL_FLAG_WEAK_DECL) != 0) + + +/* true if a symbol is both small and not weak. In this case, gp + relative access can be used. gp relative access cannot be used in + position independent code. gp relative access cannot be used for externally + defined symbols, because the compilation unit which defines the symbol may + place it in a section that cannot be reached from gp. */ +#define SYMBOL_REF_IN_NIOS2_SMALL_DATA_P(RTX) \ + (!flag_pic && SYMBOL_REF_SMALL_P(RTX) && !SYMBOL_REF_WEAK_DECL_P(RTX) && \ + !SYMBOL_REF_EXTERNAL_P(RTX) && SYMBOL_REF_TLS_MODEL(RTX)==0) + +/***************** + * Describing Relative Costs of Operations + *****************/ + +#define SLOW_BYTE_ACCESS 1 + +/* It is as good to call a constant function address as to call an address + kept in a register. + ??? Not true anymore really. Now that call cannot address full range + of memory callr may need to be used */ + +#define NO_FUNCTION_CSE + +/*************************** + * Position Independent Code + ***************************/ + +#define PIC_OFFSET_TABLE_REGNUM 22 + +#define LEGITIMATE_PIC_OPERAND_P(X) nios2_legitimate_pic_operand_p (X) + +/***************************************** + * Defining the Output Assembler Language + *****************************************/ + +/* ------------------------------------------ * + * The Overall Framework of an Assembler File + * ------------------------------------------ */ + +#define ASM_APP_ON "#APP\n" +#define ASM_APP_OFF "#NO_APP\n" + +#define ASM_COMMENT_START "# " + +/* ------------------------------- * + * Output and Generation of Labels + * ------------------------------- */ + +#define GLOBAL_ASM_OP "\t.global\t" + + +/* -------------- * + * Output of Data + * -------------- */ + +/* -------------------------------- * + * Assembler Commands for Alignment + * -------------------------------- */ + +#define ASM_OUTPUT_ALIGN(FILE, LOG) \ + do { \ + fprintf ((FILE), "%s%d\n", ALIGN_ASM_OP, (LOG)); \ + } while (0) + + +/* -------------------------------- * + * Output of Assembler Instructions + * -------------------------------- */ + +#define REGISTER_NAMES \ +{ \ + "zero", \ + "at", \ + "r2", \ + "r3", \ + "r4", \ + "r5", \ + "r6", \ + "r7", \ + "r8", \ + "r9", \ + "r10", \ + "r11", \ + "r12", \ + "r13", \ + "r14", \ + "r15", \ + "r16", \ + "r17", \ + "r18", \ + "r19", \ + "r20", \ + "r21", \ + "r22", \ + "r23", \ + "et", \ + "bt", \ + "gp", \ + "sp", \ + "fp", \ + "ta", \ + "ba", \ + "ra", \ + "status", \ + "estatus", \ + "bstatus", \ + "ipri", \ + "ecause", \ + "pc", \ + "fake_fp", \ + "fake_ap", \ +} + +#define ADDITIONAL_REGISTER_NAMES \ +{ \ + {"r0", 0}, \ + {"r1", 1}, \ + {"r24", 24}, \ + {"r25", 25}, \ + {"r26", 26}, \ + {"r27", 27}, \ + {"r28", 28}, \ + {"r29", 29}, \ + {"r30", 30}, \ + {"r31", 31} \ +} + + +#define ASM_OUTPUT_OPCODE(STREAM, PTR)\ + (PTR) = asm_output_opcode (STREAM, PTR) + +#define PRINT_OPERAND(STREAM, X, CODE) \ + nios2_print_operand (STREAM, X, CODE) + +#define PRINT_OPERAND_ADDRESS(STREAM, X) \ + nios2_print_operand_address (STREAM, X) + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ +do { fputs (integer_asm_op (POINTER_SIZE / BITS_PER_UNIT, TRUE), FILE); \ + fprintf (FILE, ".L%u\n", (unsigned) (VALUE)); \ + } while (0) + +#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM, BODY, VALUE, REL)\ +do { fputs (integer_asm_op (POINTER_SIZE / BITS_PER_UNIT, TRUE), STREAM); \ + fprintf (STREAM, ".L%u-.L%u\n", (unsigned) (VALUE), (unsigned) (REL)); \ + } while (0) + + +/* ------------ * + * Label Output + * ------------ */ + + +/* ---------------------------------------------------- * + * Dividing the Output into Sections (Texts, Data, ...) + * ---------------------------------------------------- */ + +/* Output before read-only data. */ +#define TEXT_SECTION_ASM_OP "\t.section\t.text" + +/* Output before writable data. */ +#define DATA_SECTION_ASM_OP "\t.section\t.data" + + +/* Default the definition of "small data" to 8 bytes. */ +/* ??? How come I can't use HOST_WIDE_INT here? */ +extern unsigned long nios2_section_threshold; +#define NIOS2_DEFAULT_GVALUE 8 + + + +/* This says how to output assembler code to declare an + uninitialized external linkage data object. Under SVR4, + the linker seems to want the alignment of data objects + to depend on their types. We do exactly that here. */ + +#undef COMMON_ASM_OP +#define COMMON_ASM_OP "\t.comm\t" + +#undef ASM_OUTPUT_ALIGNED_COMMON +#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \ +do \ +{ \ + fprintf ((FILE), "%s", COMMON_ASM_OP); \ + assemble_name ((FILE), (NAME)); \ + fprintf ((FILE), ","HOST_WIDE_INT_PRINT_UNSIGNED",%u\n", (SIZE), \ + (ALIGN) / BITS_PER_UNIT); \ +} \ +while (0) + + +/* This says how to output assembler code to declare an + uninitialized internal linkage data object. Under SVR4, + the linker seems to want the alignment of data objects + to depend on their types. We do exactly that here. */ + +#undef ASM_OUTPUT_ALIGNED_LOCAL +#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \ +do { \ + if ((SIZE) <= nios2_section_threshold) \ + named_section (0, ".sbss", 0); \ + else \ + named_section (0, ".bss", 0); \ + ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object"); \ + if (!flag_inhibit_size_directive) \ + ASM_OUTPUT_SIZE_DIRECTIVE (FILE, NAME, SIZE); \ + ASM_OUTPUT_ALIGN ((FILE), exact_log2((ALIGN) / BITS_PER_UNIT)); \ + ASM_OUTPUT_LABEL(FILE, NAME); \ + ASM_OUTPUT_SKIP((FILE), (SIZE) ? (SIZE) : 1); \ +} while (0) + +/* Put the jump tables in .text because when using position independent code, + Nios II elf has no relocation that can represent arbitrary differences + between symbols in different sections. */ +#define JUMP_TABLES_IN_TEXT_SECTION 1 + +/* Exception Handling */ + +/* Describe __builtin_eh_return */ +#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, LAST_RETVAL_REGNO) +#define EH_RETURN_DATA_REGNO(N) ((N) <= (LAST_ARG_REGNO - FIRST_ARG_REGNO) \ + ? (N) + FIRST_ARG_REGNO : INVALID_REGNUM) +#define ASM_PREFERRED_EH_DATA_FORMAT(CODE, GLOBAL) \ + (!flag_pic ? DW_EH_PE_sdata4 \ + /* FIXME: These get expanded to dynamic relocs, which is wrong */ \ + /* : !(GLOBAL) ? DW_EH_PE_pcrel | DW_EH_PE_sdata4 */ \ + : DW_EH_PE_aligned) + +/*************************** + * Miscellaneous Parameters + ***************************/ + +#define MOVE_MAX 4 + +#define STORE_FLAG_VALUE 1 +#define Pmode SImode +#define FUNCTION_MODE QImode + +#define REGISTER_TARGET_PRAGMAS() nios2_register_target_pragmas () + +#define CASE_VECTOR_MODE Pmode + +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 + +#define LOAD_EXTEND_OP(MODE) (ZERO_EXTEND) + +#define WORD_REGISTER_OPERATIONS Index: gcc-4.1.2/gcc/config/nios2/nios2.md =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gcc-4.1.2/gcc/config/nios2/nios2.md 2010-06-30 08:50:26.000000000 +0200 @@ -0,0 +1,3012 @@ +;; NOT ASSIGNED TO FSF. COPYRIGHT ALTERA. +;; +;; Machine Description for Altera NIOS 2G NIOS2 version. +;; Copyright (C) 2005 Altera +;; Contributed by Jonah Graham (jgraham@altera.com) and +;; Will Reece (wreece@altera.com). +;; +;; This file is part of GNU CC. +;; +;; GNU CC is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2, or (at your option) +;; any later version. +;; +;; GNU CC is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with GNU CC; see the file COPYING. If not, write to +;; the Free Software Foundation, 59 Temple Place - Suite 330, +;; Boston, MA 02111-1307, USA. */ + + + + +;***************************************************************************** +;* +;* constraint strings +;* +;***************************************************************************** +; +; We use the following constraint letters for constants +; +; I: -32768 to -32767 +; J: 0 to 65535 +; K: $nnnn0000 for some nnnn +; L: 0 to 31 (for shift counts) +; M: 0 +; N: 0 to 255 (for custom instruction numbers) +; O: 0 to 31 (for control register numbers) +; +; We use the following built-in register classes: +; +; r: general purpose register (r0..r31) +; m: memory operand +; +; Plus, we define the following constraint strings: +; +; S: symbol that is in the "small data" area +; Dnn: Dnn_REG (just rnn) +; + + + +;***************************************************************************** +;* +;* constants +;* +;***************************************************************************** +(define_constants [ + (UNSPEC_BLOCKAGE 0) + (UNSPEC_LDBIO 1) + (UNSPEC_LDBUIO 2) + (UNSPEC_LDHIO 3) + (UNSPEC_LDHUIO 4) + (UNSPEC_LDWIO 5) + (UNSPEC_STBIO 6) + (UNSPEC_STHIO 7) + (UNSPEC_STWIO 8) + (UNSPEC_SYNC 9) + (UNSPEC_WRCTL 10) + (UNSPEC_RDCTL 11) + (UNSPEC_TRAP 12) + (UNSPEC_STACK_OVERFLOW_DETECT_AND_TRAP 13) + (UNSPEC_FCOSS 14) + (UNSPEC_FCOSD 15) + (UNSPEC_FSINS 16) + (UNSPEC_FSIND 17) + (UNSPEC_FTANS 18) + (UNSPEC_FTAND 19) + (UNSPEC_FATANS 20) + (UNSPEC_FATAND 21) + (UNSPEC_FEXPS 22) + (UNSPEC_FEXPD 23) + (UNSPEC_FLOGS 24) + (UNSPEC_FLOGD 25) + (UNSPEC_FWRX 26) + (UNSPEC_FWRY 27) + (UNSPEC_FRDXLO 28) + (UNSPEC_FRDXHI 29) + (UNSPEC_FRDY 30) + (UNSPEC_LOAD_GOT_REGISTER 31) + (UNSPEC_PIC_SYM 32) + (UNSPEC_PIC_CALL_SYM 33) + (UNSPEC_TLS 34) + (UNSPEC_TLS_LDM 35) + (UNSPEC_LOAD_TLS_IE 36) + (UNSPEC_ADD_TLS_LE 37) + (UNSPEC_ADD_TLS_GD 38) + (UNSPEC_ADD_TLS_LDM 39) + (UNSPEC_ADD_TLS_LDO 40) + + (UNSPEC_EH_RETURN 41) + + ;; Note that values 100..151 are used by custom instructions, see below. +]) + + + +;***************************************************************************** +;* +;* instruction scheduler +;* +;***************************************************************************** + +; No schedule info is currently available, using an assumption that no +; instruction can use the results of the previous instruction without +; incuring a stall. + +; length of an instruction (in bytes) +(define_attr "length" "" (const_int 4)) +(define_attr "type" + "unknown,complex,control,alu,cond_alu,st,ld,shift,mul,div,custom" + (const_string "complex")) + +(define_asm_attributes + [(set_attr "length" "4") + (set_attr "type" "complex")]) + +(define_automaton "nios2") +(automata_option "v") +;(automata_option "no-minimization") +(automata_option "ndfa") + +; The nios2 pipeline is fairly straightforward for the fast model. +; Every alu operation is pipelined so that an instruction can +; be issued every cycle. However, there are still potential +; stalls which this description tries to deal with. + +(define_cpu_unit "cpu" "nios2") + +(define_insn_reservation "complex" 1 + (eq_attr "type" "complex") + "cpu") + +(define_insn_reservation "control" 1 + (eq_attr "type" "control") + "cpu") + +(define_insn_reservation "alu" 1 + (eq_attr "type" "alu") + "cpu") + +(define_insn_reservation "cond_alu" 1 + (eq_attr "type" "cond_alu") + "cpu") + +(define_insn_reservation "st" 1 + (eq_attr "type" "st") + "cpu") + +(define_insn_reservation "custom" 1 + (eq_attr "type" "custom") + "cpu") + +; shifts, muls and lds have three cycle latency +(define_insn_reservation "ld" 3 + (eq_attr "type" "ld") + "cpu") + +(define_insn_reservation "shift" 3 + (eq_attr "type" "shift") + "cpu") + +(define_insn_reservation "mul" 3 + (eq_attr "type" "mul") + "cpu") + +(define_insn_reservation "div" 1 + (eq_attr "type" "div") + "cpu") + + +;***************************************************************************** +;* +;* MOV Instructions +;* +;***************************************************************************** + +(define_expand "movqi" + [(set (match_operand:QI 0 "nonimmediate_operand" "") + (match_operand:QI 1 "general_operand" ""))] + "" +{ + if (nios2_emit_move_sequence (operands, QImode)) + DONE; +}) + +(define_insn "movqi_internal" + [(set (match_operand:QI 0 "nonimmediate_operand" "=m, r,r, r") + (match_operand:QI 1 "general_operand" "rM,m,rM,I"))] + "(register_operand (operands[0], QImode) + || reg_or_0_operand (operands[1], QImode))" + "@ + stb%o0\\t%z1, %0 + ldbu%o1\\t%0, %1 + mov\\t%0, %z1 + movi\\t%0, %1" + [(set_attr "type" "st,ld,alu,alu")]) + +(define_insn "ldbio" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(const_int 0)] UNSPEC_LDBIO)) + (use (match_operand:SI 1 "memory_operand" "m"))] + "" + "ldbio\\t%0, %1" + [(set_attr "type" "ld")]) + +(define_insn "ldbuio" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(const_int 0)] UNSPEC_LDBUIO)) + (use (match_operand:SI 1 "memory_operand" "m"))] + "" + "ldbuio\\t%0, %1" + [(set_attr "type" "ld")]) + +(define_insn "stbio" + [(set (match_operand:SI 0 "memory_operand" "=m") + (match_operand:SI 1 "reg_or_0_operand" "rM")) + (unspec_volatile:SI [(const_int 0)] UNSPEC_STBIO)] + "" + "stbio\\t%z1, %0" + [(set_attr "type" "st")]) + + +(define_expand "movhi" + [(set (match_operand:HI 0 "nonimmediate_operand" "") + (match_operand:HI 1 "general_operand" ""))] + "" +{ + if (nios2_emit_move_sequence (operands, HImode)) + DONE; +}) + +(define_insn "movhi_internal" + [(set (match_operand:HI 0 "nonimmediate_operand" "=m, r,r, r,r") + (match_operand:HI 1 "general_operand" "rM,m,rM,I,J"))] + "(register_operand (operands[0], HImode) + || reg_or_0_operand (operands[1], HImode))" + "@ + sth%o0\\t%z1, %0 + ldhu%o1\\t%0, %1 + mov\\t%0, %z1 + movi\\t%0, %1 + movui\\t%0, %1" + [(set_attr "type" "st,ld,alu,alu,alu")]) + +(define_insn "ldhio" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(const_int 0)] UNSPEC_LDHIO)) + (use (match_operand:SI 1 "memory_operand" "m"))] + "" + "ldhio\\t%0, %1" + [(set_attr "type" "ld")]) + +(define_insn "ldhuio" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(const_int 0)] UNSPEC_LDHUIO)) + (use (match_operand:SI 1 "memory_operand" "m"))] + "" + "ldhuio\\t%0, %1" + [(set_attr "type" "ld")]) + +(define_insn "sthio" + [(set (match_operand:SI 0 "memory_operand" "=m") + (match_operand:SI 1 "reg_or_0_operand" "rM")) + (unspec_volatile:SI [(const_int 0)] UNSPEC_STHIO)] + "" + "sthio\\t%z1, %0" + [(set_attr "type" "st")]) + +(define_expand "movsi" + [(set (match_operand:SI 0 "nonimmediate_operand" "") + (match_operand:SI 1 "general_operand" ""))] + "" +{ + if (nios2_emit_move_sequence (operands, SImode)) + DONE; +}) + +(define_insn "movsi_internal" + [(set (match_operand:SI 0 "nonimmediate_operand" "=m, r,r, r,r,r,r") + (match_operand:SI 1 "general_operand" "rM,m,rM,I,J,S,i"))] + "(register_operand (operands[0], SImode) + || reg_or_0_operand (operands[1], SImode))" + "@ + stw%o0\\t%z1, %0 + ldw%o1\\t%0, %1 + mov\\t%0, %z1 + movi\\t%0, %1 + movui\\t%0, %1 + addi\\t%0, gp, %%gprel(%1) + movhi\\t%0, %H1\;addi\\t%0, %0, %L1" + [(set_attr "type" "st,ld,alu,alu,alu,alu,alu")]) + +(define_insn "ldwio" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(const_int 0)] UNSPEC_LDWIO)) + (use (match_operand:SI 1 "memory_operand" "m"))] + "" + "ldwio\\t%0, %1" + [(set_attr "type" "ld")]) + +(define_insn "stwio" + [(set (match_operand:SI 0 "memory_operand" "=m") + (match_operand:SI 1 "reg_or_0_operand" "rM")) + (unspec_volatile:SI [(const_int 0)] UNSPEC_STWIO)] + "" + "stwio\\t%z1, %0" + [(set_attr "type" "st")]) + + + +;***************************************************************************** +;* +;* zero extension +;* +;***************************************************************************** + + +(define_insn "zero_extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))] + "" + "@ + andi\\t%0, %1, 0xffff + ldhu%o1\\t%0, %1" + [(set_attr "type" "alu,ld")]) + +(define_insn "zero_extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r,r") + (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "r,m")))] + "" + "@ + andi\\t%0, %1, 0xff + ldbu%o1\\t%0, %1" + [(set_attr "type" "alu,ld")]) + +(define_insn "zero_extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,m")))] + "" + "@ + andi\\t%0, %1, 0xff + ldbu%o1\\t%0, %1" + [(set_attr "type" "alu,ld")]) + + + +;***************************************************************************** +;* +;* sign extension +;* +;***************************************************************************** +(define_expand "extendhisi2" + [(set (match_operand:SI 0 "register_operand" "") + (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] + "" +{ +}) + +(define_insn "*extendhisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI (match_operand:HI 1 "register_operand" "r")))] + "" + "#") + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (sign_extend:SI (match_operand:HI 1 "register_operand" "")))] + "reload_completed" + [(set (match_dup 0) + (and:SI (match_dup 1) (const_int 65535))) + (set (match_dup 0) + (xor:SI (match_dup 0) (const_int 32768))) + (set (match_dup 0) + (plus:SI (match_dup 0) (const_int -32768)))] + "operands[1] = gen_lowpart (SImode, operands[1]);") + +(define_insn "extendhisi2_internal" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))] + "" + "ldh%o1\\t%0, %1" + [(set_attr "type" "ld")]) + + +(define_expand "extendqihi2" + [(set (match_operand:HI 0 "register_operand" "") + (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))] + "" +{ +}) + +(define_insn "*extendqihi2" + [(set (match_operand:HI 0 "register_operand" "=r") + (sign_extend:HI (match_operand:QI 1 "register_operand" "r")))] + "" + "#") + +(define_split + [(set (match_operand:HI 0 "register_operand" "") + (sign_extend:HI (match_operand:QI 1 "register_operand" "")))] + "reload_completed" + [(set (match_dup 0) + (and:SI (match_dup 1) (const_int 255))) + (set (match_dup 0) + (xor:SI (match_dup 0) (const_int 128))) + (set (match_dup 0) + (plus:SI (match_dup 0) (const_int -128)))] + "operands[0] = gen_lowpart (SImode, operands[0]); + operands[1] = gen_lowpart (SImode, operands[1]);") + + + +(define_insn "extendqihi2_internal" + [(set (match_operand:HI 0 "register_operand" "=r") + (sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))] + "" + "ldb%o1\\t%0, %1" + [(set_attr "type" "ld")]) + + +(define_expand "extendqisi2" + [(set (match_operand:SI 0 "register_operand" "") + (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] + "" +{ +}) + +(define_insn "*extendqisi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI (match_operand:QI 1 "register_operand" "r")))] + "" + "#") + +(define_split + [(set (match_operand:SI 0 "register_operand" "") + (sign_extend:SI (match_operand:QI 1 "register_operand" "")))] + "reload_completed" + [(set (match_dup 0) + (and:SI (match_dup 1) (const_int 255))) + (set (match_dup 0) + (xor:SI (match_dup 0) (const_int 128))) + (set (match_dup 0) + (plus:SI (match_dup 0) (const_int -128)))] + "operands[1] = gen_lowpart (SImode, operands[1]);") + +(define_insn "extendqisi2_insn" + [(set (match_operand:SI 0 "register_operand" "=r") + (sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))] + "" + "ldb%o1\\t%0, %1" + [(set_attr "type" "ld")]) + + + + +;***************************************************************************** +;* +;* Arithmetic Operations +;* +;***************************************************************************** + +(define_insn "addsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (plus:SI (match_operand:SI 1 "register_operand" "%r,r") + (match_operand:SI 2 "arith_operand" "r,I")))] + "" + "add%i2\\t%0, %1, %z2" + [(set_attr "type" "alu")]) + +(define_insn "addsf3" + [(set (match_operand:SF 0 "register_operand" "=r") + (plus:SF (match_operand:SF 1 "register_operand" "%r") + (match_operand:SF 2 "register_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_addsf3].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_addsf3].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "adddf3" + [(set (match_operand:DF 0 "register_operand" "=r") + (plus:DF (match_operand:DF 1 "register_operand" "%r") + (match_operand:DF 2 "register_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_adddf3].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_adddf3].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "subsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rM") + (match_operand:SI 2 "register_operand" "r")))] + "" + "sub\\t%0, %z1, %2" + [(set_attr "type" "alu")]) + +(define_insn "subsf3" + [(set (match_operand:SF 0 "register_operand" "=r") + (minus:SF (match_operand:SF 1 "register_operand" "r") + (match_operand:SF 2 "register_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_subsf3].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_subsf3].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "subdf3" + [(set (match_operand:DF 0 "register_operand" "=r") + (minus:DF (match_operand:DF 1 "register_operand" "r") + (match_operand:DF 2 "register_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_subdf3].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_subdf3].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "mulsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (mult:SI (match_operand:SI 1 "register_operand" "r,r") + (match_operand:SI 2 "arith_operand" "r,I")))] + "TARGET_HAS_MUL" + "mul%i2\\t%0, %1, %z2" + [(set_attr "type" "mul")]) + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "register_operand" "=r") + (mult:SF (match_operand:SF 1 "register_operand" "%r") + (match_operand:SF 2 "register_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_mulsf3].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_mulsf3].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "muldf3" + [(set (match_operand:DF 0 "register_operand" "=r") + (mult:DF (match_operand:DF 1 "register_operand" "%r") + (match_operand:DF 2 "register_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_muldf3].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_muldf3].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_expand "divsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (div:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r")))] + "" +{ + if (!TARGET_HAS_DIV) + { + if (!TARGET_FAST_SW_DIV) + FAIL; + else + { + if (nios2_emit_expensive_div (operands, SImode)) + DONE; + } + } +}) + +(define_insn "divsi3_insn" + [(set (match_operand:SI 0 "register_operand" "=r") + (div:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r")))] + "TARGET_HAS_DIV" + "div\\t%0, %1, %2" + [(set_attr "type" "div")]) + +(define_insn "divsf3" + [(set (match_operand:SF 0 "register_operand" "=r") + (div:SF (match_operand:SF 1 "register_operand" "r") + (match_operand:SF 2 "register_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_divsf3].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_divsf3].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "divdf3" + [(set (match_operand:DF 0 "register_operand" "=r") + (div:DF (match_operand:DF 1 "register_operand" "r") + (match_operand:DF 2 "register_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_divdf3].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_divdf3].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "udivsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (udiv:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r")))] + "TARGET_HAS_DIV" + "divu\\t%0, %1, %2" + [(set_attr "type" "div")]) + +(define_insn "smulsi3_highpart" + [(set (match_operand:SI 0 "register_operand" "=r") + (truncate:SI + (lshiftrt:DI + (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r")) + (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))) + (const_int 32))))] + "TARGET_HAS_MULX" + "mulxss\\t%0, %1, %2" + [(set_attr "type" "mul")]) + +(define_insn "umulsi3_highpart" + [(set (match_operand:SI 0 "register_operand" "=r") + (truncate:SI + (lshiftrt:DI + (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r")) + (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))) + (const_int 32))))] + "TARGET_HAS_MULX" + "mulxuu\\t%0, %1, %2" + [(set_attr "type" "mul")]) + + +(define_expand "mulsidi3_little_endian" + [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 0) + (mult:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "register_operand" ""))) + (set (subreg:SI (match_dup 0) 4) + (truncate:SI (lshiftrt:DI (mult:DI (sign_extend:DI (match_dup 1)) + (sign_extend:DI (match_dup 2))) + (const_int 32))))] + "TARGET_HAS_MULX && !WORDS_BIG_ENDIAN" + "") + +(define_expand "mulsidi3_big_endian" + [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 4) + (mult:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "register_operand" ""))) + (set (subreg:SI (match_dup 0) 0) + (truncate:SI (lshiftrt:DI (mult:DI (sign_extend:DI (match_dup 1)) + (sign_extend:DI (match_dup 2))) + (const_int 32))))] + "TARGET_HAS_MULX && WORDS_BIG_ENDIAN" + "") + +(define_expand "mulsidi3" + [(match_operand:DI 0 "register_operand" "") + (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "register_operand" "")] + "TARGET_HAS_MULX" + { + if (WORDS_BIG_ENDIAN) + { + emit_insn (gen_mulsidi3_big_endian (operands[0], + operands[1], + operands[2])); + } + else + { + emit_insn (gen_mulsidi3_little_endian (operands[0], + operands[1], + operands[2])); + } + DONE; + }) + +(define_expand "umulsidi3_little_endian" + [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 0) + (mult:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "register_operand" ""))) + (set (subreg:SI (match_dup 0) 4) + (truncate:SI (lshiftrt:DI (mult:DI (zero_extend:DI (match_dup 1)) + (zero_extend:DI (match_dup 2))) + (const_int 32))))] + "TARGET_HAS_MULX && !WORDS_BIG_ENDIAN" + "") + +(define_expand "umulsidi3_big_endian" + [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 4) + (mult:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "register_operand" ""))) + (set (subreg:SI (match_dup 0) 0) + (truncate:SI (lshiftrt:DI (mult:DI (zero_extend:DI (match_dup 1)) + (zero_extend:DI (match_dup 2))) + (const_int 32))))] + "TARGET_HAS_MULX && WORDS_BIG_ENDIAN" + "") + +(define_expand "umulsidi3" + [(match_operand:DI 0 "register_operand" "") + (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "register_operand" "")] + "TARGET_HAS_MULX" + { + if (WORDS_BIG_ENDIAN) + { + emit_insn (gen_umulsidi3_big_endian (operands[0], + operands[1], + operands[2])); + } + else + { + emit_insn (gen_umulsidi3_little_endian (operands[0], + operands[1], + operands[2])); + } + DONE; + }) + + +;***************************************************************************** +;* +;* Negate and ones complement +;* +;***************************************************************************** + +(define_insn "negsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (neg:SI (match_operand:SI 1 "register_operand" "r")))] + "" +{ + operands[2] = const0_rtx; + return "sub\\t%0, %z2, %1"; +} + [(set_attr "type" "alu")]) + +(define_insn "negsf2" + [(set (match_operand:SF 0 "register_operand" "=r") + (neg:SF (match_operand:SF 1 "register_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_negsf2].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_negsf2].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "negdf2" + [(set (match_operand:DF 0 "register_operand" "=r") + (neg:DF (match_operand:DF 1 "register_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_negdf2].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_negdf2].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (not:SI (match_operand:SI 1 "register_operand" "r")))] + "" +{ + operands[2] = const0_rtx; + return "nor\\t%0, %z2, %1"; +} + [(set_attr "type" "alu")]) + + +;***************************************************************************** +;* +;* Miscellaneous floating point +;* +;***************************************************************************** +(define_insn "nios2_fwrx" + [(unspec_volatile [(match_operand:DF 0 "register_operand" "r")] UNSPEC_FWRX)] + "nios2_fpu_insns[nios2_fpu_nios2_fwrx].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_nios2_fwrx].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "nios2_fwry" + [(unspec_volatile [(match_operand:SF 0 "register_operand" "r")] UNSPEC_FWRY)] + "nios2_fpu_insns[nios2_fpu_nios2_fwry].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_nios2_fwry].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "nios2_frdxlo" + [(set (match_operand:SF 0 "register_operand" "=r") + (unspec_volatile:SF [(const_int 0)] UNSPEC_FRDXLO))] + "nios2_fpu_insns[nios2_fpu_nios2_frdxlo].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_nios2_frdxlo].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "nios2_frdxhi" + [(set (match_operand:SF 0 "register_operand" "=r") + (unspec_volatile:SF [(const_int 0)] UNSPEC_FRDXHI))] + "nios2_fpu_insns[nios2_fpu_nios2_frdxhi].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_nios2_frdxhi].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "nios2_frdy" + [(set (match_operand:SF 0 "register_operand" "=r") + (unspec_volatile:SF [(const_int 0)] UNSPEC_FRDY))] + "nios2_fpu_insns[nios2_fpu_nios2_frdy].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_nios2_frdy].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "minsf3" + [(set (match_operand:SF 0 "register_operand" "=r") + (if_then_else:SF (lt:SF (match_operand:SF 1 "register_operand" "%r") + (match_operand:SF 2 "register_operand" "r")) + (match_dup 1) + (match_dup 2)))] + "nios2_fpu_insns[nios2_fpu_minsf3].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_minsf3].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "mindf3" + [(set (match_operand:DF 0 "register_operand" "=r") + (if_then_else:DF (lt:DF (match_operand:DF 1 "register_operand" "%r") + (match_operand:DF 2 "register_operand" "r")) + (match_dup 1) + (match_dup 2)))] + "nios2_fpu_insns[nios2_fpu_mindf3].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_mindf3].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "maxsf3" + [(set (match_operand:SF 0 "register_operand" "=r") + (if_then_else:SF (lt:SF (match_operand:SF 1 "register_operand" "%r") + (match_operand:SF 2 "register_operand" "r")) + (match_dup 2) + (match_dup 1)))] + "nios2_fpu_insns[nios2_fpu_maxsf3].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_maxsf3].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "maxdf3" + [(set (match_operand:DF 0 "register_operand" "=r") + (if_then_else:DF (lt:DF (match_operand:DF 1 "register_operand" "%r") + (match_operand:DF 2 "register_operand" "r")) + (match_dup 2) + (match_dup 1)))] + "nios2_fpu_insns[nios2_fpu_maxdf3].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_maxdf3].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "abssf2" + [(set (match_operand:SF 0 "register_operand" "=r") + (abs:SF (match_operand:SF 1 "register_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_abssf2].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_abssf2].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "absdf2" + [(set (match_operand:DF 0 "register_operand" "=r") + (abs:DF (match_operand:DF 1 "register_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_absdf2].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_absdf2].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "sqrtsf2" + [(set (match_operand:SF 0 "register_operand" "=r") + (sqrt:SF (match_operand:SF 1 "register_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_sqrtsf2].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_sqrtsf2].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "sqrtdf2" + [(set (match_operand:DF 0 "register_operand" "=r") + (sqrt:DF (match_operand:DF 1 "register_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_sqrtdf2].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_sqrtdf2].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "cossf2" + [(set (match_operand:SF 0 "register_operand" "=r") + (unspec:SF [(match_operand:SF 1 "register_operand" "r")] UNSPEC_FCOSS))] + "nios2_fpu_insns[nios2_fpu_cossf2].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_cossf2].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "cosdf2" + [(set (match_operand:DF 0 "register_operand" "=r") + (unspec:DF [(match_operand:DF 1 "register_operand" "r")] UNSPEC_FCOSD))] + "nios2_fpu_insns[nios2_fpu_cosdf2].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_cosdf2].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "sinsf2" + [(set (match_operand:SF 0 "register_operand" "=r") + (unspec:SF [(match_operand:SF 1 "register_operand" "r")] UNSPEC_FSINS))] + "nios2_fpu_insns[nios2_fpu_sinsf2].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_sinsf2].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "sindf2" + [(set (match_operand:DF 0 "register_operand" "=r") + (unspec:DF [(match_operand:DF 1 "register_operand" "r")] UNSPEC_FSIND))] + "nios2_fpu_insns[nios2_fpu_sindf2].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_sindf2].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "tansf2" + [(set (match_operand:SF 0 "register_operand" "=r") + (unspec:SF [(match_operand:SF 1 "register_operand" "r")] UNSPEC_FTANS))] + "nios2_fpu_insns[nios2_fpu_tansf2].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_tansf2].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "tandf2" + [(set (match_operand:DF 0 "register_operand" "=r") + (unspec:DF [(match_operand:DF 1 "register_operand" "r")] UNSPEC_FTAND))] + "nios2_fpu_insns[nios2_fpu_tandf2].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_tandf2].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "atansf2" + [(set (match_operand:SF 0 "register_operand" "=r") + (unspec:SF [(match_operand:SF 1 "register_operand" "r")] UNSPEC_FATANS))] + "nios2_fpu_insns[nios2_fpu_atansf2].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_atansf2].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "atandf2" + [(set (match_operand:DF 0 "register_operand" "=r") + (unspec:DF [(match_operand:DF 1 "register_operand" "r")] UNSPEC_FATAND))] + "nios2_fpu_insns[nios2_fpu_atandf2].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_atandf2].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "expsf2" + [(set (match_operand:SF 0 "register_operand" "=r") + (unspec:SF [(match_operand:SF 1 "register_operand" "r")] UNSPEC_FEXPS))] + "nios2_fpu_insns[nios2_fpu_expsf2].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_expsf2].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "expdf2" + [(set (match_operand:DF 0 "register_operand" "=r") + (unspec:DF [(match_operand:DF 1 "register_operand" "r")] UNSPEC_FEXPD))] + "nios2_fpu_insns[nios2_fpu_expdf2].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_expdf2].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "logsf2" + [(set (match_operand:SF 0 "register_operand" "=r") + (unspec:SF [(match_operand:SF 1 "register_operand" "r")] UNSPEC_FLOGS))] + "nios2_fpu_insns[nios2_fpu_logsf2].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_logsf2].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "logdf2" + [(set (match_operand:DF 0 "register_operand" "=r") + (unspec:DF [(match_operand:DF 1 "register_operand" "r")] UNSPEC_FLOGD))] + "nios2_fpu_insns[nios2_fpu_logdf2].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_logdf2].output) (insn); + } + [(set_attr "type" "custom")]) + + +;***************************************************************************** +;* +;* Logical Operantions +;* +;***************************************************************************** + +(define_insn "andsi3" + [(set (match_operand:SI 0 "register_operand" "=r, r,r") + (and:SI (match_operand:SI 1 "register_operand" "%r, r,r") + (match_operand:SI 2 "logical_operand" "rM,J,K")))] + "" + "@ + and\\t%0, %1, %z2 + and%i2\\t%0, %1, %2 + andh%i2\\t%0, %1, %U2" + [(set_attr "type" "alu")]) + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "register_operand" "=r, r,r") + (ior:SI (match_operand:SI 1 "register_operand" "%r, r,r") + (match_operand:SI 2 "logical_operand" "rM,J,K")))] + "" + "@ + or\\t%0, %1, %z2 + or%i2\\t%0, %1, %2 + orh%i2\\t%0, %1, %U2" + [(set_attr "type" "alu")]) + +(define_insn "*norsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (and:SI (not:SI (match_operand:SI 1 "register_operand" "%r")) + (not:SI (match_operand:SI 2 "reg_or_0_operand" "rM"))))] + "" + "nor\\t%0, %1, %z2" + [(set_attr "type" "alu")]) + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "register_operand" "=r, r,r") + (xor:SI (match_operand:SI 1 "register_operand" "%r, r,r") + (match_operand:SI 2 "logical_operand" "rM,J,K")))] + "" + "@ + xor\\t%0, %1, %z2 + xor%i2\\t%0, %1, %2 + xorh%i2\\t%0, %1, %U2" + [(set_attr "type" "alu")]) + + + +;***************************************************************************** +;* +;* Shifts +;* +;***************************************************************************** + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (ashift:SI (match_operand:SI 1 "register_operand" "r,r") + (match_operand:SI 2 "shift_operand" "r,L")))] + "" + +{ + if( GET_CODE ( operands[2] ) == CONST_INT && INTVAL( operands[2] ) == 1 ) + return "add\t%0,%1,%1"; + return "sll%i2\t%0,%1,%z2"; +} + [(set_attr "type" "shift")]) + +(define_insn "ashrsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (ashiftrt:SI (match_operand:SI 1 "register_operand" "r,r") + (match_operand:SI 2 "shift_operand" "r,L")))] + "" + "sra%i2\\t%0, %1, %z2" + [(set_attr "type" "shift")]) + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (lshiftrt:SI (match_operand:SI 1 "register_operand" "r,r") + (match_operand:SI 2 "shift_operand" "r,L")))] + "" + "srl%i2\\t%0, %1, %z2" + [(set_attr "type" "shift")]) + +(define_insn "rotlsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (rotate:SI (match_operand:SI 1 "register_operand" "r,r") + (match_operand:SI 2 "shift_operand" "r,L")))] + "" + "rol%i2\\t%0, %1, %z2" + [(set_attr "type" "shift")]) + +(define_insn "rotrsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (rotatert:SI (match_operand:SI 1 "register_operand" "r,r") + (match_operand:SI 2 "register_operand" "r,r")))] + "" + "ror\\t%0, %1, %2" + [(set_attr "type" "shift")]) + +(define_insn "*shift_mul_constants" + [(set (match_operand:SI 0 "register_operand" "=r") + (ashift:SI (mult:SI (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "const_int_operand" "I")) + (match_operand:SI 3 "const_int_operand" "I")))] + "TARGET_HAS_MUL && SMALL_INT (INTVAL (operands[2]) << INTVAL (operands[3]))" +{ + HOST_WIDE_INT mul = INTVAL (operands[2]) << INTVAL (operands[3]); + rtx ops[3]; + + ops[0] = operands[0]; + ops[1] = operands[1]; + ops[2] = GEN_INT (mul); + + output_asm_insn ("muli\t%0, %1, %2", ops); + return ""; +} + [(set_attr "type" "mul")]) + + + + +;***************************************************************************** +;* +;* Converting between floating point and fixed point +;* +;***************************************************************************** +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "register_operand" "=r") + (float:SF (match_operand:SI 1 "register_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_floatsisf2].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_floatsisf2].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "floatsidf2" + [(set (match_operand:DF 0 "register_operand" "=r") + (float:DF (match_operand:SI 1 "register_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_floatsidf2].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_floatsidf2].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "floatunssisf2" + [(set (match_operand:SF 0 "register_operand" "=r") + (unsigned_float:SF (match_operand:SI 1 "register_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_floatunssisf2].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_floatunssisf2].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "floatunssidf2" + [(set (match_operand:DF 0 "register_operand" "=r") + (unsigned_float:DF (match_operand:SI 1 "register_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_floatunssidf2].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_floatunssidf2].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "fixsfsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (fix:SI (match_operand:SF 1 "general_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_fixsfsi2].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_fixsfsi2].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "fixdfsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (fix:SI (match_operand:DF 1 "general_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_fixdfsi2].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_fixdfsi2].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "fixunssfsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (unsigned_fix:SI (match_operand:SF 1 "general_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_fixunssfsi2].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_fixunssfsi2].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "fixunsdfsi2" + [(set (match_operand:SI 0 "register_operand" "=r") + (unsigned_fix:SI (match_operand:DF 1 "general_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_fixunsdfsi2].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_fixunsdfsi2].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "extendsfdf2" + [(set (match_operand:DF 0 "register_operand" "=r") + (float_extend:DF (match_operand:SF 1 "general_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_extendsfdf2].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_extendsfdf2].output) (insn); + } + [(set_attr "type" "custom")]) + +(define_insn "truncdfsf2" + [(set (match_operand:SF 0 "register_operand" "=r") + (float_truncate:SF (match_operand:DF 1 "general_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_truncdfsf2].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_truncdfsf2].output) (insn); + } + [(set_attr "type" "custom")]) + + + + + + + + +;***************************************************************************** +;* +;* Prologue, Epilogue and Return +;* +;***************************************************************************** + +(define_expand "prologue" + [(const_int 1)] + "" +{ + expand_prologue (); + DONE; +}) + +(define_expand "epilogue" + [(return)] + "" +{ + expand_epilogue (false); + DONE; +}) + +(define_expand "sibcall_epilogue" + [(return)] + "" +{ + expand_epilogue (true); + DONE; +}) + +(define_insn "return" + [(return)] + "reload_completed && nios2_can_use_return_insn ()" + "ret\\t" +) + +(define_insn "return_from_epilogue" + [(use (match_operand 0 "pmode_register_operand" "")) + (return)] + "reload_completed" + "ret\\t" +) + +;; Block any insns from being moved before this point, since the +;; profiling call to mcount can use various registers that aren't +;; saved or used to pass arguments. + +(define_insn "blockage" + [(unspec_volatile [(const_int 0)] UNSPEC_BLOCKAGE)] + "" + "" + [(set_attr "type" "unknown") + (set_attr "length" "0")]) + +;; This is used in compiling the unwind routines. +(define_expand "eh_return" + [(use (match_operand 0 "general_operand"))] + "" +{ + if (GET_MODE (operands[0]) != Pmode) + operands[0] = convert_to_mode (Pmode, operands[0], 0); + emit_insn (gen_eh_set_ra (operands[0])); + + DONE; +}) + +;; Clobber the return address on the stack. We can't expand this +;; until we know where it will be put in the stack frame. + +(define_insn "eh_set_ra" + [(unspec [(match_operand:SI 0 "register_operand" "r")] UNSPEC_EH_RETURN) + (clobber (match_scratch:SI 1 "=&r"))] + "" + "#") + +(define_split + [(unspec [(match_operand 0 "register_operand")] UNSPEC_EH_RETURN) + (clobber (match_scratch 1))] + "reload_completed" + [(const_int 0)] +{ + nios2_set_return_address (operands[0], operands[1]); + DONE; +}) + + +;***************************************************************************** +;* +;* Jumps and Calls +;* +;***************************************************************************** + +(define_insn "indirect_jump" + [(set (pc) (match_operand:SI 0 "register_operand" "r"))] + "" + "jmp\\t%0" + [(set_attr "type" "control")]) + +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "br\\t%0" + [(set_attr "type" "control")]) + + +(define_expand "call" + [(parallel [(call (match_operand 0 "" "") + (match_operand 1 "" "")) + (clobber (reg:SI 31))])] + "" + { + nios2_adjust_call_address (&XEXP (operands[0], 0)); + } +) + +(define_expand "call_value" + [(parallel [(set (match_operand 0 "" "") + (call (match_operand 1 "" "") + (match_operand 2 "" ""))) + (clobber (reg:SI 31))])] + "" + { + nios2_adjust_call_address (&XEXP (operands[1], 0)); + } +) + +(define_insn "*call" + [(call (mem:QI (match_operand:SI 0 "call_operand" "i,r")) + (match_operand 1 "" "")) + (clobber (reg:SI 31))] + "" + "@ + call\\t%0 + callr\\t%0" + [(set_attr "type" "control,control")]) + +(define_insn "*call_value" + [(set (match_operand 0 "" "") + (call (mem:QI (match_operand:SI 1 "call_operand" "i,r")) + (match_operand 2 "" ""))) + (clobber (reg:SI 31))] + "" + "@ + call\\t%1 + callr\\t%1" + [(set_attr "type" "control,control")]) + +(define_expand "sibcall" + [(parallel [(call (match_operand 0 "" "") + (match_operand 1 "" "")) + (return)])] + "" + { + nios2_adjust_call_address (&XEXP (operands[0], 0)); + } +) + +(define_expand "sibcall_value" + [(parallel [(set (match_operand 0 "" "") + (call (match_operand 1 "" "") + (match_operand 2 "" ""))) + (return)])] + "" + { + nios2_adjust_call_address (&XEXP (operands[1], 0)); + } +) + +(define_insn "*sibcall" + [(call (mem:QI (match_operand:SI 0 "call_operand" "i,j")) + (match_operand 1 "" "")) + (return)] + "" + "@ + jmpi\\t%0 + jmp\\t%0" +) + +(define_insn "*sibcall_value" + [(set (match_operand 0 "register_operand" "") + (call (mem:QI (match_operand:SI 1 "call_operand" "i,j")) + (match_operand 2 "" ""))) + (return)] + "" + "@ + jmpi\\t%1 + jmp\\t%1" +) + + + + +(define_expand "tablejump" + [(parallel [(set (pc) (match_operand 0 "register_operand" "r")) + (use (label_ref (match_operand 1 "" "")))])] + "" + { + if (flag_pic) + { + /* Hopefully, CSE will eliminate this copy. */ + rtx reg1 = copy_addr_to_reg (gen_rtx_LABEL_REF (Pmode, operands[1])); + rtx reg2 = gen_reg_rtx (SImode); + + emit_insn (gen_addsi3 (reg2, operands[0], reg1)); + operands[0] = reg2; + } + } +) + +(define_insn "*tablejump" + [(set (pc) + (match_operand:SI 0 "register_operand" "r")) + (use (label_ref (match_operand 1 "" "")))] + "" + "jmp\\t%0" + [(set_attr "type" "control")]) + + + +;***************************************************************************** +;* +;* Comparisons +;* +;***************************************************************************** +;; Flow here is rather complex (based on MIPS): +;; +;; 1) The cmp{si,di,sf,df} routine is called. It deposits the +;; arguments into the branch_cmp array, and the type into +;; branch_type. No RTL is generated. +;; +;; 2) The appropriate branch define_expand is called, which then +;; creates the appropriate RTL for the comparison and branch. +;; Different CC modes are used, based on what type of branch is +;; done, so that we can constrain things appropriately. There +;; are assumptions in the rest of GCC that break if we fold the +;; operands into the branchs for integer operations, and use cc0 +;; for floating point, so we use the fp status register instead. +;; If needed, an appropriate temporary is created to hold the +;; of the integer compare. + +(define_expand "cmpsi" + [(set (cc0) + (compare:CC (match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "arith_operand" "")))] + "" +{ + branch_cmp[0] = operands[0]; + branch_cmp[1] = operands[1]; + branch_type = CMP_SI; + DONE; +}) + +(define_expand "tstsi" + [(set (cc0) + (match_operand:SI 0 "register_operand" ""))] + "" +{ + branch_cmp[0] = operands[0]; + branch_cmp[1] = const0_rtx; + branch_type = CMP_SI; + DONE; +}) + +(define_expand "cmpsf" + [(set (cc0) + (compare:CC (match_operand:SF 0 "register_operand" "") + (match_operand:SF 1 "register_operand" "")))] + "(nios2_fpu_insns[nios2_fpu_nios2_sltsf].N >= 0 + || nios2_fpu_insns[nios2_fpu_nios2_sgtsf].N >= 0) + && (nios2_fpu_insns[nios2_fpu_nios2_sgesf].N >= 0 + || nios2_fpu_insns[nios2_fpu_nios2_slesf].N >= 0) + && nios2_fpu_insns[nios2_fpu_nios2_seqsf].N >= 0 + && nios2_fpu_insns[nios2_fpu_nios2_snesf].N >= 0" +{ + branch_cmp[0] = operands[0]; + branch_cmp[1] = operands[1]; + branch_type = CMP_SF; + DONE; +}) + +(define_expand "cmpdf" + [(set (cc0) + (compare:CC (match_operand:DF 0 "register_operand" "") + (match_operand:DF 1 "register_operand" "")))] + "(nios2_fpu_insns[nios2_fpu_nios2_sltdf].N >= 0 + || nios2_fpu_insns[nios2_fpu_nios2_sgtdf].N >= 0) + && (nios2_fpu_insns[nios2_fpu_nios2_sgedf].N >= 0 + || nios2_fpu_insns[nios2_fpu_nios2_sledf].N >= 0) + && nios2_fpu_insns[nios2_fpu_nios2_seqdf].N >= 0 + && nios2_fpu_insns[nios2_fpu_nios2_snedf].N >= 0" +{ + branch_cmp[0] = operands[0]; + branch_cmp[1] = operands[1]; + branch_type = CMP_DF; + DONE; +}) + + +;***************************************************************************** +;* +;* setting a register from a comparison +;* +;***************************************************************************** + +(define_expand "seq" + [(set (match_operand:SI 0 "register_operand" "=r") + (eq:SI (match_dup 1) + (match_dup 2)))] + "" +{ + if (branch_type != CMP_SI && branch_type != CMP_SF && branch_type != CMP_DF) + FAIL; + + /* set up operands from compare. */ + operands[1] = branch_cmp[0]; + operands[2] = branch_cmp[1]; + + gen_int_relational (EQ, operands[0], operands[1], operands[2], NULL_RTX); + DONE; +}) + + +(define_insn "*seq" + [(set (match_operand:SI 0 "register_operand" "=r") + (eq:SI (match_operand:SI 1 "reg_or_0_operand" "%rM") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "cmpeq%i2\\t%0, %z1, %z2" + [(set_attr "type" "alu")]) + + +(define_insn "nios2_seqsf" + [(set (match_operand:SI 0 "register_operand" "=r") + (eq:SI (match_operand:SF 1 "register_operand" "%r") + (match_operand:SF 2 "register_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_nios2_seqsf].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_nios2_seqsf].output) (insn); + } + [(set_attr "type" "custom")]) + + +(define_insn "nios2_seqdf" + [(set (match_operand:SI 0 "register_operand" "=r") + (eq:SI (match_operand:DF 1 "register_operand" "%r") + (match_operand:DF 2 "register_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_nios2_seqdf].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_nios2_seqdf].output) (insn); + } + [(set_attr "type" "custom")]) + + +(define_expand "sne" + [(set (match_operand:SI 0 "register_operand" "=r") + (ne:SI (match_dup 1) + (match_dup 2)))] + "" +{ + if (branch_type != CMP_SI && branch_type != CMP_SF && branch_type != CMP_DF) + FAIL; + + /* set up operands from compare. */ + operands[1] = branch_cmp[0]; + operands[2] = branch_cmp[1]; + + gen_int_relational (NE, operands[0], operands[1], operands[2], NULL_RTX); + DONE; +}) + + +(define_insn "*sne" + [(set (match_operand:SI 0 "register_operand" "=r") + (ne:SI (match_operand:SI 1 "reg_or_0_operand" "%rM") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "cmpne%i2\\t%0, %z1, %z2" + [(set_attr "type" "alu")]) + + +(define_insn "nios2_snesf" + [(set (match_operand:SI 0 "register_operand" "=r") + (ne:SI (match_operand:SF 1 "register_operand" "%r") + (match_operand:SF 2 "register_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_nios2_snesf].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_nios2_snesf].output) (insn); + } + [(set_attr "type" "custom")]) + + +(define_insn "nios2_snedf" + [(set (match_operand:SI 0 "register_operand" "=r") + (ne:SI (match_operand:DF 1 "register_operand" "%r") + (match_operand:DF 2 "register_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_nios2_snedf].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_nios2_snedf].output) (insn); + } + [(set_attr "type" "custom")]) + + +(define_expand "sgt" + [(set (match_operand:SI 0 "register_operand" "=r") + (gt:SI (match_dup 1) + (match_dup 2)))] + "" +{ + if (branch_type != CMP_SI && branch_type != CMP_SF && branch_type != CMP_DF) + FAIL; + + /* set up operands from compare. */ + operands[1] = branch_cmp[0]; + operands[2] = branch_cmp[1]; + + gen_int_relational (GT, operands[0], operands[1], operands[2], NULL_RTX); + DONE; +}) + + +(define_insn "*sgt" + [(set (match_operand:SI 0 "register_operand" "=r") + (gt:SI (match_operand:SI 1 "reg_or_0_operand" "rM") + (match_operand:SI 2 "reg_or_0_operand" "rM")))] + "" + "cmplt\\t%0, %z2, %z1" + [(set_attr "type" "alu")]) + + +(define_insn "nios2_sgtsf" + [(set (match_operand:SI 0 "register_operand" "=r") + (gt:SI (match_operand:SF 1 "register_operand" "r") + (match_operand:SF 2 "register_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_nios2_sgtsf].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_nios2_sgtsf].output) (insn); + } + [(set_attr "type" "custom")]) + + +(define_insn "nios2_sgtdf" + [(set (match_operand:SI 0 "register_operand" "=r") + (gt:SI (match_operand:DF 1 "register_operand" "r") + (match_operand:DF 2 "register_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_nios2_sgtdf].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_nios2_sgtdf].output) (insn); + } + [(set_attr "type" "custom")]) + + +(define_expand "sge" + [(set (match_operand:SI 0 "register_operand" "=r") + (ge:SI (match_dup 1) + (match_dup 2)))] + "" +{ + if (branch_type != CMP_SI && branch_type != CMP_SF && branch_type != CMP_DF) + FAIL; + + /* set up operands from compare. */ + operands[1] = branch_cmp[0]; + operands[2] = branch_cmp[1]; + + gen_int_relational (GE, operands[0], operands[1], operands[2], NULL_RTX); + DONE; +}) + + +(define_insn "*sge" + [(set (match_operand:SI 0 "register_operand" "=r") + (ge:SI (match_operand:SI 1 "reg_or_0_operand" "rM") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "cmpge%i2\\t%0, %z1, %z2" + [(set_attr "type" "alu")]) + + +(define_insn "nios2_sgesf" + [(set (match_operand:SI 0 "register_operand" "=r") + (ge:SI (match_operand:SF 1 "register_operand" "r") + (match_operand:SF 2 "register_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_nios2_sgesf].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_nios2_sgesf].output) (insn); + } + [(set_attr "type" "custom")]) + + +(define_insn "nios2_sgedf" + [(set (match_operand:SI 0 "register_operand" "=r") + (ge:SI (match_operand:DF 1 "register_operand" "r") + (match_operand:DF 2 "register_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_nios2_sgedf].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_nios2_sgedf].output) (insn); + } + [(set_attr "type" "custom")]) + + +(define_expand "sle" + [(set (match_operand:SI 0 "register_operand" "=r") + (le:SI (match_dup 1) + (match_dup 2)))] + "" +{ + if (branch_type != CMP_SI && branch_type != CMP_SF && branch_type != CMP_DF) + FAIL; + + /* set up operands from compare. */ + operands[1] = branch_cmp[0]; + operands[2] = branch_cmp[1]; + + gen_int_relational (LE, operands[0], operands[1], operands[2], NULL_RTX); + DONE; +}) + + +(define_insn "*sle" + [(set (match_operand:SI 0 "register_operand" "=r") + (le:SI (match_operand:SI 1 "reg_or_0_operand" "rM") + (match_operand:SI 2 "reg_or_0_operand" "rM")))] + "" + "cmpge\\t%0, %z2, %z1" + [(set_attr "type" "alu")]) + + +(define_insn "nios2_slesf" + [(set (match_operand:SI 0 "register_operand" "=r") + (le:SI (match_operand:SF 1 "register_operand" "r") + (match_operand:SF 2 "register_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_nios2_slesf].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_nios2_slesf].output) (insn); + } + [(set_attr "type" "custom")]) + + +(define_insn "nios2_sledf" + [(set (match_operand:SI 0 "register_operand" "=r") + (le:SI (match_operand:DF 1 "register_operand" "r") + (match_operand:DF 2 "register_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_nios2_sledf].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_nios2_sledf].output) (insn); + } + [(set_attr "type" "custom")]) + + +(define_expand "slt" + [(set (match_operand:SI 0 "register_operand" "=r") + (lt:SI (match_dup 1) + (match_dup 2)))] + "" +{ + if (branch_type != CMP_SI && branch_type != CMP_SF && branch_type != CMP_DF) + FAIL; + + /* set up operands from compare. */ + operands[1] = branch_cmp[0]; + operands[2] = branch_cmp[1]; + + gen_int_relational (LT, operands[0], operands[1], operands[2], NULL_RTX); + DONE; +}) + + +(define_insn "*slt" + [(set (match_operand:SI 0 "register_operand" "=r") + (lt:SI (match_operand:SI 1 "reg_or_0_operand" "rM") + (match_operand:SI 2 "arith_operand" "rI")))] + "" + "cmplt%i2\\t%0, %z1, %z2" + [(set_attr "type" "alu")]) + + +(define_insn "nios2_sltsf" + [(set (match_operand:SI 0 "register_operand" "=r") + (lt:SI (match_operand:SF 1 "register_operand" "r") + (match_operand:SF 2 "register_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_nios2_sltsf].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_nios2_sltsf].output) (insn); + } + [(set_attr "type" "custom")]) + + +(define_insn "nios2_sltdf" + [(set (match_operand:SI 0 "register_operand" "=r") + (lt:SI (match_operand:DF 1 "register_operand" "r") + (match_operand:DF 2 "register_operand" "r")))] + "nios2_fpu_insns[nios2_fpu_nios2_sltdf].N >= 0" + { + return (*nios2_fpu_insns[nios2_fpu_nios2_sltdf].output) (insn); + } + [(set_attr "type" "custom")]) + + +(define_expand "sgtu" + [(set (match_operand:SI 0 "register_operand" "=r") + (gtu:SI (match_dup 1) + (match_dup 2)))] + "" +{ + if (branch_type != CMP_SI) + FAIL; + + /* set up operands from compare. */ + operands[1] = branch_cmp[0]; + operands[2] = branch_cmp[1]; + + gen_int_relational (GTU, operands[0], operands[1], operands[2], NULL_RTX); + DONE; +}) + + +(define_insn "*sgtu" + [(set (match_operand:SI 0 "register_operand" "=r") + (gtu:SI (match_operand:SI 1 "reg_or_0_operand" "rM") + (match_operand:SI 2 "reg_or_0_operand" "rM")))] + "" + "cmpltu\\t%0, %z2, %z1" + [(set_attr "type" "alu")]) + + +(define_expand "sgeu" + [(set (match_operand:SI 0 "register_operand" "=r") + (geu:SI (match_dup 1) + (match_dup 2)))] + "" +{ + if (branch_type != CMP_SI) + FAIL; + + /* set up operands from compare. */ + operands[1] = branch_cmp[0]; + operands[2] = branch_cmp[1]; + + gen_int_relational (GEU, operands[0], operands[1], operands[2], NULL_RTX); + DONE; +}) + + +(define_insn "*sgeu" + [(set (match_operand:SI 0 "register_operand" "=r") + (geu:SI (match_operand:SI 1 "reg_or_0_operand" "rM") + (match_operand:SI 2 "uns_arith_operand" "rJ")))] + "" + "cmpgeu%i2\\t%0, %z1, %z2" + [(set_attr "type" "alu")]) + +(define_expand "sleu" + [(set (match_operand:SI 0 "register_operand" "=r") + (leu:SI (match_dup 1) + (match_dup 2)))] + "" +{ + if (branch_type != CMP_SI) + FAIL; + + /* set up operands from compare. */ + operands[1] = branch_cmp[0]; + operands[2] = branch_cmp[1]; + + gen_int_relational (LEU, operands[0], operands[1], operands[2], NULL_RTX); + DONE; +}) + + +(define_insn "*sleu" + [(set (match_operand:SI 0 "register_operand" "=r") + (leu:SI (match_operand:SI 1 "reg_or_0_operand" "rM") + (match_operand:SI 2 "reg_or_0_operand" "rM")))] + "" + "cmpgeu\\t%0, %z2, %z1" + [(set_attr "type" "alu")]) + + +(define_expand "sltu" + [(set (match_operand:SI 0 "register_operand" "=r") + (ltu:SI (match_dup 1) + (match_dup 2)))] + "" +{ + if (branch_type != CMP_SI) + FAIL; + + /* set up operands from compare. */ + operands[1] = branch_cmp[0]; + operands[2] = branch_cmp[1]; + + gen_int_relational (LTU, operands[0], operands[1], operands[2], NULL_RTX); + DONE; +}) + + +(define_insn "*sltu" + [(set (match_operand:SI 0 "register_operand" "=r") + (ltu:SI (match_operand:SI 1 "reg_or_0_operand" "rM") + (match_operand:SI 2 "uns_arith_operand" "rJ")))] + "" + "cmpltu%i2\\t%0, %z1, %z2" + [(set_attr "type" "alu")]) + + + + +;***************************************************************************** +;* +;* branches +;* +;***************************************************************************** + +(define_insn "*cbranch" + [(set (pc) + (if_then_else + (match_operator:SI 0 "comparison_operator" + [(match_operand:SI 2 "reg_or_0_operand" "rM") + (match_operand:SI 3 "reg_or_0_operand" "rM")]) + (label_ref (match_operand 1 "" "")) + (pc)))] + "" + "b%0\\t%z2, %z3, %l1" + [(set_attr "type" "control")]) + + +(define_insn "nios2_cbranch_sf" + [(set (pc) + (if_then_else + (match_operator:SI 0 "comparison_operator" + [(match_operand:SF 2 "register_operand" "r") + (match_operand:SF 3 "register_operand" "r")]) + (label_ref (match_operand 1 "" "")) + (pc)))] + "" + { + return nios2_output_fpu_insn_cmps (insn, GET_CODE (operands[0])); + } + [(set_attr "type" "custom")]) + + +(define_insn "nios2_cbranch_df" + [(set (pc) + (if_then_else + (match_operator:SI 0 "comparison_operator" + [(match_operand:DF 2 "register_operand" "r") + (match_operand:DF 3 "register_operand" "r")]) + (label_ref (match_operand 1 "" "")) + (pc)))] + "" + { + return nios2_output_fpu_insn_cmpd (insn, GET_CODE (operands[0])); + } + [(set_attr "type" "custom")]) + + +(define_expand "beq" + [(set (pc) + (if_then_else (eq:CC (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" +{ + gen_int_relational (EQ, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); + DONE; +}) + + +(define_expand "bne" + [(set (pc) + (if_then_else (ne:CC (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" +{ + gen_int_relational (NE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); + DONE; +}) + + +(define_expand "bgt" + [(set (pc) + (if_then_else (gt:CC (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" +{ + gen_int_relational (GT, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); + DONE; +}) + +(define_expand "bge" + [(set (pc) + (if_then_else (ge:CC (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" +{ + gen_int_relational (GE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); + DONE; +}) + +(define_expand "ble" + [(set (pc) + (if_then_else (le:CC (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" +{ + gen_int_relational (LE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); + DONE; +}) + +(define_expand "blt" + [(set (pc) + (if_then_else (lt:CC (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" +{ + gen_int_relational (LT, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); + DONE; +}) + + +(define_expand "bgtu" + [(set (pc) + (if_then_else (gtu:CC (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" +{ + gen_int_relational (GTU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); + DONE; +}) + +(define_expand "bgeu" + [(set (pc) + (if_then_else (geu:CC (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" +{ + gen_int_relational (GEU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); + DONE; +}) + +(define_expand "bleu" + [(set (pc) + (if_then_else (leu:CC (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" +{ + gen_int_relational (LEU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); + DONE; +}) + +(define_expand "bltu" + [(set (pc) + (if_then_else (ltu:CC (cc0) + (const_int 0)) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" +{ + gen_int_relational (LTU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); + DONE; +}) + + +;***************************************************************************** +;* +;* String and Block Operations +;* +;***************************************************************************** + +; ??? This is all really a hack to get Dhrystone to work as fast as possible +; things to be fixed: +; * let the compiler core handle all of this, for that to work the extra +; aliasing needs to be addressed. +; * we use three temporary registers for loading and storing to ensure no +; ld use stalls, this is excessive, because after the first ld/st only +; two are needed. Only two would be needed all the way through if +; we could schedule with other code. Consider: +; 1 ld $1, 0($src) +; 2 ld $2, 4($src) +; 3 ld $3, 8($src) +; 4 st $1, 0($dest) +; 5 ld $1, 12($src) +; 6 st $2, 4($src) +; 7 etc. +; The first store has to wait until 4. If it does not there will be one +; cycle of stalling. However, if any other instruction could be placed +; between 1 and 4, $3 would not be needed. +; * In small we probably don't want to ever do this ourself because there +; is no ld use stall. + +(define_expand "movstrsi" + [(parallel [(set (match_operand:BLK 0 "general_operand" "") + (match_operand:BLK 1 "general_operand" "")) + (use (match_operand:SI 2 "const_int_operand" "")) + (use (match_operand:SI 3 "const_int_operand" "")) + (clobber (match_scratch:SI 4 "=&r")) + (clobber (match_scratch:SI 5 "=&r")) + (clobber (match_scratch:SI 6 "=&r"))])] + "TARGET_INLINE_MEMCPY" +{ + rtx ld_addr_reg, st_addr_reg; + + /* If the predicate for op2 fails in expr.c:emit_block_move_via_movstr + it trys to copy to a register, but does not re-try the predicate. + ??? Intead of fixing expr.c, I fix it here. */ + if (!const_int_operand (operands[2], SImode)) + FAIL; + + /* ??? there are some magic numbers which need to be sorted out here. + the basis for them is not increasing code size hugely or going + out of range of offset addressing */ + if (INTVAL (operands[3]) < 4) + FAIL; + if (!optimize + || (optimize_size && INTVAL (operands[2]) > 12) + || (optimize < 3 && INTVAL (operands[2]) > 100) + || INTVAL (operands[2]) > 200) + FAIL; + + st_addr_reg + = replace_equiv_address (operands[0], + copy_to_mode_reg (Pmode, XEXP (operands[0], 0))); + ld_addr_reg + = replace_equiv_address (operands[1], + copy_to_mode_reg (Pmode, XEXP (operands[1], 0))); + emit_insn (gen_movstrsi_internal (st_addr_reg, ld_addr_reg, + operands[2], operands[3])); + + DONE; +}) + + +(define_insn "movstrsi_internal" + [(set (match_operand:BLK 0 "memory_operand" "=o") + (match_operand:BLK 1 "memory_operand" "o")) + (use (match_operand:SI 2 "const_int_operand" "i")) + (use (match_operand:SI 3 "const_int_operand" "i")) + (clobber (match_scratch:SI 4 "=&r")) + (clobber (match_scratch:SI 5 "=&r")) + (clobber (match_scratch:SI 6 "=&r"))] + "TARGET_INLINE_MEMCPY" +{ + int ld_offset = INTVAL (operands[2]); + int ld_len = INTVAL (operands[2]); + int ld_reg = 0; + rtx ld_addr_reg = XEXP (operands[1], 0); + int st_offset = INTVAL (operands[2]); + int st_len = INTVAL (operands[2]); + int st_reg = 0; + rtx st_addr_reg = XEXP (operands[0], 0); + int delay_count = 0; + + /* ops[0] is the address used by the insn + ops[1] is the register being loaded or stored */ + rtx ops[2]; + + gcc_assert (INTVAL (operands[3]) >= 4); + + while (ld_offset >= 4) + { + /* if the load use delay has been met, I can start + storing */ + if (delay_count >= 3) + { + ops[0] = gen_rtx_MEM (SImode, + plus_constant (st_addr_reg, st_len - st_offset)); + ops[1] = operands[st_reg + 4]; + output_asm_insn ("stw\t%1, %0", ops); + + st_reg = (st_reg + 1) % 3; + st_offset -= 4; + } + + ops[0] = gen_rtx_MEM (SImode, + plus_constant (ld_addr_reg, ld_len - ld_offset)); + ops[1] = operands[ld_reg + 4]; + output_asm_insn ("ldw\t%1, %0", ops); + + ld_reg = (ld_reg + 1) % 3; + ld_offset -= 4; + delay_count++; + } + + if (ld_offset >= 2) + { + /* if the load use delay has been met, I can start + storing */ + if (delay_count >= 3) + { + ops[0] = gen_rtx_MEM (SImode, + plus_constant (st_addr_reg, st_len - st_offset)); + ops[1] = operands[st_reg + 4]; + output_asm_insn ("stw\t%1, %0", ops); + + st_reg = (st_reg + 1) % 3; + st_offset -= 4; + } + + ops[0] = gen_rtx_MEM (HImode, + plus_constant (ld_addr_reg, ld_len - ld_offset)); + ops[1] = operands[ld_reg + 4]; + output_asm_insn ("ldh\t%1, %0", ops); + + ld_reg = (ld_reg + 1) % 3; + ld_offset -= 2; + delay_count++; + } + + if (ld_offset >= 1) + { + /* if the load use delay has been met, I can start + storing */ + if (delay_count >= 3) + { + ops[0] = gen_rtx_MEM (SImode, + plus_constant (st_addr_reg, st_len - st_offset)); + ops[1] = operands[st_reg + 4]; + output_asm_insn ("stw\t%1, %0", ops); + + st_reg = (st_reg + 1) % 3; + st_offset -= 4; + } + + ops[0] = gen_rtx_MEM (QImode, + plus_constant (ld_addr_reg, ld_len - ld_offset)); + ops[1] = operands[ld_reg + 4]; + output_asm_insn ("ldb\t%1, %0", ops); + + ld_reg = (ld_reg + 1) % 3; + ld_offset -= 1; + delay_count++; + } + + while (st_offset >= 4) + { + ops[0] = gen_rtx_MEM (SImode, + plus_constant (st_addr_reg, st_len - st_offset)); + ops[1] = operands[st_reg + 4]; + output_asm_insn ("stw\t%1, %0", ops); + + st_reg = (st_reg + 1) % 3; + st_offset -= 4; + } + + while (st_offset >= 2) + { + ops[0] = gen_rtx_MEM (HImode, + plus_constant (st_addr_reg, st_len - st_offset)); + ops[1] = operands[st_reg + 4]; + output_asm_insn ("sth\t%1, %0", ops); + + st_reg = (st_reg + 1) % 3; + st_offset -= 2; + } + + while (st_offset >= 1) + { + ops[0] = gen_rtx_MEM (QImode, + plus_constant (st_addr_reg, st_len - st_offset)); + ops[1] = operands[st_reg + 4]; + output_asm_insn ("stb\t%1, %0", ops); + + st_reg = (st_reg + 1) % 3; + st_offset -= 1; + } + + return ""; +} +; ??? lengths are not being used yet, but I will probably forget +; to update this once I am using lengths, so set it to something +; definetely big enough to cover it. 400 allows for 200 bytes +; of motion. + [(set_attr "length" "400")]) + + + +;***************************************************************************** +;* +;* Custom instructions +;* +;***************************************************************************** + +(define_constants [ + (CUSTOM_N 100) + (CUSTOM_NI 101) + (CUSTOM_NF 102) + (CUSTOM_NP 103) + (CUSTOM_NII 104) + (CUSTOM_NIF 105) + (CUSTOM_NIP 106) + (CUSTOM_NFI 107) + (CUSTOM_NFF 108) + (CUSTOM_NFP 109) + (CUSTOM_NPI 110) + (CUSTOM_NPF 111) + (CUSTOM_NPP 112) + (CUSTOM_IN 113) + (CUSTOM_INI 114) + (CUSTOM_INF 115) + (CUSTOM_INP 116) + (CUSTOM_INII 117) + (CUSTOM_INIF 118) + (CUSTOM_INIP 119) + (CUSTOM_INFI 120) + (CUSTOM_INFF 121) + (CUSTOM_INFP 122) + (CUSTOM_INPI 123) + (CUSTOM_INPF 124) + (CUSTOM_INPP 125) + (CUSTOM_FN 126) + (CUSTOM_FNI 127) + (CUSTOM_FNF 128) + (CUSTOM_FNP 129) + (CUSTOM_FNII 130) + (CUSTOM_FNIF 131) + (CUSTOM_FNIP 132) + (CUSTOM_FNFI 133) + (CUSTOM_FNFF 134) + (CUSTOM_FNFP 135) + (CUSTOM_FNPI 136) + (CUSTOM_FNPF 137) + (CUSTOM_FNPP 138) + (CUSTOM_PN 139) + (CUSTOM_PNI 140) + (CUSTOM_PNF 141) + (CUSTOM_PNP 142) + (CUSTOM_PNII 143) + (CUSTOM_PNIF 144) + (CUSTOM_PNIP 145) + (CUSTOM_PNFI 146) + (CUSTOM_PNFF 147) + (CUSTOM_PNFP 148) + (CUSTOM_PNPI 149) + (CUSTOM_PNPF 150) + (CUSTOM_PNPP 151) +]) + + +(define_insn "custom_n" + [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")] CUSTOM_N)] + "" + "custom\\t%0, zero, zero, zero" + [(set_attr "type" "custom")]) + +(define_insn "custom_ni" + [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") + (match_operand:SI 1 "register_operand" "r")] CUSTOM_NI)] + "" + "custom\\t%0, zero, %1, zero" + [(set_attr "type" "custom")]) + +(define_insn "custom_nf" + [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") + (match_operand:SF 1 "register_operand" "r")] CUSTOM_NF)] + "" + "custom\\t%0, zero, %1, zero" + [(set_attr "type" "custom")]) + +(define_insn "custom_np" + [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") + (match_operand:SI 1 "register_operand" "r")] CUSTOM_NP)] + "" + "custom\\t%0, zero, %1, zero" + [(set_attr "type" "custom")]) + +(define_insn "custom_nii" + [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") + (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r")] CUSTOM_NII)] + "" + "custom\\t%0, zero, %1, %2" + [(set_attr "type" "custom")]) + +(define_insn "custom_nif" + [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") + (match_operand:SI 1 "register_operand" "r") + (match_operand:SF 2 "register_operand" "r")] CUSTOM_NIF)] + "" + "custom\\t%0, zero, %1, %2" + [(set_attr "type" "custom")]) + +(define_insn "custom_nip" + [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") + (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r")] CUSTOM_NIP)] + "" + "custom\\t%0, zero, %1, %2" + [(set_attr "type" "custom")]) + +(define_insn "custom_nfi" + [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") + (match_operand:SF 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r")] CUSTOM_NFI)] + "" + "custom\\t%0, zero, %1, %2" + [(set_attr "type" "custom")]) + +(define_insn "custom_nff" + [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") + (match_operand:SF 1 "register_operand" "r") + (match_operand:SF 2 "register_operand" "r")] CUSTOM_NFF)] + "" + "custom\\t%0, zero, %1, %2" + [(set_attr "type" "custom")]) + +(define_insn "custom_nfp" + [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") + (match_operand:SF 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r")] CUSTOM_NFP)] + "" + "custom\\t%0, zero, %1, %2" + [(set_attr "type" "custom")]) + +(define_insn "custom_npi" + [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") + (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r")] CUSTOM_NPI)] + "" + "custom\\t%0, zero, %1, %2" + [(set_attr "type" "custom")]) + +(define_insn "custom_npf" + [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") + (match_operand:SI 1 "register_operand" "r") + (match_operand:SF 2 "register_operand" "r")] CUSTOM_NPF)] + "" + "custom\\t%0, zero, %1, %2" + [(set_attr "type" "custom")]) + +(define_insn "custom_npp" + [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") + (match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "register_operand" "r")] CUSTOM_NPP)] + "" + "custom\\t%0, zero, %1, %2" + [(set_attr "type" "custom")]) + + + +(define_insn "custom_in" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")] + CUSTOM_IN))] + "" + "custom\\t%1, %0, zero, zero" + [(set_attr "type" "custom")]) + +(define_insn "custom_ini" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SI 2 "register_operand" "r")] + CUSTOM_INI))] + "" + "custom\\t%1, %0, %2, zero" + [(set_attr "type" "custom")]) + +(define_insn "custom_inf" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SF 2 "register_operand" "r")] + CUSTOM_INF))] + "" + "custom\\t%1, %0, %2, zero" + [(set_attr "type" "custom")]) + +(define_insn "custom_inp" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SI 2 "register_operand" "r")] + CUSTOM_INP))] + "" + "custom\\t%1, %0, %2, zero" + [(set_attr "type" "custom")]) + +(define_insn "custom_inii" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SI 2 "register_operand" "r") + (match_operand:SI 3 "register_operand" "r")] + CUSTOM_INII))] + "" + "custom\\t%1, %0, %2, %3" + [(set_attr "type" "custom")]) + +(define_insn "custom_inif" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SI 2 "register_operand" "r") + (match_operand:SF 3 "register_operand" "r")] + CUSTOM_INIF))] + "" + "custom\\t%1, %0, %2, %3" + [(set_attr "type" "custom")]) + +(define_insn "custom_inip" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SI 2 "register_operand" "r") + (match_operand:SI 3 "register_operand" "r")] + CUSTOM_INIP))] + "" + "custom\\t%1, %0, %2, %3" + [(set_attr "type" "custom")]) + +(define_insn "custom_infi" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SF 2 "register_operand" "r") + (match_operand:SI 3 "register_operand" "r")] + CUSTOM_INFI))] + "" + "custom\\t%1, %0, %2, %3" + [(set_attr "type" "custom")]) + +(define_insn "custom_inff" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SF 2 "register_operand" "r") + (match_operand:SF 3 "register_operand" "r")] + CUSTOM_INFF))] + "" + "custom\\t%1, %0, %2, %3" + [(set_attr "type" "custom")]) + +(define_insn "custom_infp" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SF 2 "register_operand" "r") + (match_operand:SI 3 "register_operand" "r")] + CUSTOM_INFP))] + "" + "custom\\t%1, %0, %2, %3" + [(set_attr "type" "custom")]) + +(define_insn "custom_inpi" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SI 2 "register_operand" "r") + (match_operand:SI 3 "register_operand" "r")] + CUSTOM_INPI))] + "" + "custom\\t%1, %0, %2, %3" + [(set_attr "type" "custom")]) + +(define_insn "custom_inpf" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SI 2 "register_operand" "r") + (match_operand:SF 3 "register_operand" "r")] + CUSTOM_INPF))] + "" + "custom\\t%1, %0, %2, %3" + [(set_attr "type" "custom")]) + +(define_insn "custom_inpp" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SI 2 "register_operand" "r") + (match_operand:SI 3 "register_operand" "r")] + CUSTOM_INPP))] + "" + "custom\\t%1, %0, %2, %3" + [(set_attr "type" "custom")]) + + + + + +(define_insn "custom_fn" + [(set (match_operand:SF 0 "register_operand" "=r") + (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")] + CUSTOM_FN))] + "" + "custom\\t%1, %0, zero, zero" + [(set_attr "type" "custom")]) + +(define_insn "custom_fni" + [(set (match_operand:SF 0 "register_operand" "=r") + (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SI 2 "register_operand" "r")] + CUSTOM_FNI))] + "" + "custom\\t%1, %0, %2, zero" + [(set_attr "type" "custom")]) + +(define_insn "custom_fnf" + [(set (match_operand:SF 0 "register_operand" "=r") + (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SF 2 "register_operand" "r")] + CUSTOM_FNF))] + "" + "custom\\t%1, %0, %2, zero" + [(set_attr "type" "custom")]) + +(define_insn "custom_fnp" + [(set (match_operand:SF 0 "register_operand" "=r") + (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SI 2 "register_operand" "r")] + CUSTOM_FNP))] + "" + "custom\\t%1, %0, %2, zero" + [(set_attr "type" "custom")]) + +(define_insn "custom_fnii" + [(set (match_operand:SF 0 "register_operand" "=r") + (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SI 2 "register_operand" "r") + (match_operand:SI 3 "register_operand" "r")] + CUSTOM_FNII))] + "" + "custom\\t%1, %0, %2, %3" + [(set_attr "type" "custom")]) + +(define_insn "custom_fnif" + [(set (match_operand:SF 0 "register_operand" "=r") + (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SI 2 "register_operand" "r") + (match_operand:SF 3 "register_operand" "r")] + CUSTOM_FNIF))] + "" + "custom\\t%1, %0, %2, %3" + [(set_attr "type" "custom")]) + +(define_insn "custom_fnip" + [(set (match_operand:SF 0 "register_operand" "=r") + (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SI 2 "register_operand" "r") + (match_operand:SI 3 "register_operand" "r")] + CUSTOM_FNIP))] + "" + "custom\\t%1, %0, %2, %3" + [(set_attr "type" "custom")]) + +(define_insn "custom_fnfi" + [(set (match_operand:SF 0 "register_operand" "=r") + (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SF 2 "register_operand" "r") + (match_operand:SI 3 "register_operand" "r")] + CUSTOM_FNFI))] + "" + "custom\\t%1, %0, %2, %3" + [(set_attr "type" "custom")]) + +(define_insn "custom_fnff" + [(set (match_operand:SF 0 "register_operand" "=r") + (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SF 2 "register_operand" "r") + (match_operand:SF 3 "register_operand" "r")] + CUSTOM_FNFF))] + "" + "custom\\t%1, %0, %2, %3" + [(set_attr "type" "custom")]) + +(define_insn "custom_fnfp" + [(set (match_operand:SF 0 "register_operand" "=r") + (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SF 2 "register_operand" "r") + (match_operand:SI 3 "register_operand" "r")] + CUSTOM_FNFP))] + "" + "custom\\t%1, %0, %2, %3" + [(set_attr "type" "custom")]) + +(define_insn "custom_fnpi" + [(set (match_operand:SF 0 "register_operand" "=r") + (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SI 2 "register_operand" "r") + (match_operand:SI 3 "register_operand" "r")] + CUSTOM_FNPI))] + "" + "custom\\t%1, %0, %2, %3" + [(set_attr "type" "custom")]) + +(define_insn "custom_fnpf" + [(set (match_operand:SF 0 "register_operand" "=r") + (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SI 2 "register_operand" "r") + (match_operand:SF 3 "register_operand" "r")] + CUSTOM_FNPF))] + "" + "custom\\t%1, %0, %2, %3" + [(set_attr "type" "custom")]) + +(define_insn "custom_fnpp" + [(set (match_operand:SF 0 "register_operand" "=r") + (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SI 2 "register_operand" "r") + (match_operand:SI 3 "register_operand" "r")] + CUSTOM_FNPP))] + "" + "custom\\t%1, %0, %2, %3" + [(set_attr "type" "custom")]) + + + +(define_insn "custom_pn" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")] + CUSTOM_PN))] + "" + "custom\\t%1, %0, zero, zero" + [(set_attr "type" "custom")]) + +(define_insn "custom_pni" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SI 2 "register_operand" "r")] + CUSTOM_PNI))] + "" + "custom\\t%1, %0, %2, zero" + [(set_attr "type" "custom")]) + +(define_insn "custom_pnf" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SF 2 "register_operand" "r")] + CUSTOM_PNF))] + "" + "custom\\t%1, %0, %2, zero" + [(set_attr "type" "custom")]) + +(define_insn "custom_pnp" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SI 2 "register_operand" "r")] + CUSTOM_PNP))] + "" + "custom\\t%1, %0, %2, zero" + [(set_attr "type" "custom")]) + +(define_insn "custom_pnii" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SI 2 "register_operand" "r") + (match_operand:SI 3 "register_operand" "r")] + CUSTOM_PNII))] + "" + "custom\\t%1, %0, %2, %3" + [(set_attr "type" "custom")]) + +(define_insn "custom_pnif" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SI 2 "register_operand" "r") + (match_operand:SF 3 "register_operand" "r")] + CUSTOM_PNIF))] + "" + "custom\\t%1, %0, %2, %3" + [(set_attr "type" "custom")]) + +(define_insn "custom_pnip" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SI 2 "register_operand" "r") + (match_operand:SI 3 "register_operand" "r")] + CUSTOM_PNIP))] + "" + "custom\\t%1, %0, %2, %3" + [(set_attr "type" "custom")]) + +(define_insn "custom_pnfi" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SF 2 "register_operand" "r") + (match_operand:SI 3 "register_operand" "r")] + CUSTOM_PNFI))] + "" + "custom\\t%1, %0, %2, %3" + [(set_attr "type" "custom")]) + +(define_insn "custom_pnff" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SF 2 "register_operand" "r") + (match_operand:SF 3 "register_operand" "r")] + CUSTOM_PNFF))] + "" + "custom\\t%1, %0, %2, %3" + [(set_attr "type" "custom")]) + +(define_insn "custom_pnfp" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SF 2 "register_operand" "r") + (match_operand:SI 3 "register_operand" "r")] + CUSTOM_PNFP))] + "" + "custom\\t%1, %0, %2, %3" + [(set_attr "type" "custom")]) + +(define_insn "custom_pnpi" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SI 2 "register_operand" "r") + (match_operand:SI 3 "register_operand" "r")] + CUSTOM_PNPI))] + "" + "custom\\t%1, %0, %2, %3" + [(set_attr "type" "custom")]) + +(define_insn "custom_pnpf" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SI 2 "register_operand" "r") + (match_operand:SF 3 "register_operand" "r")] + CUSTOM_PNPF))] + "" + "custom\\t%1, %0, %2, %3" + [(set_attr "type" "custom")]) + +(define_insn "custom_pnpp" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") + (match_operand:SI 2 "register_operand" "r") + (match_operand:SI 3 "register_operand" "r")] + CUSTOM_PNPP))] + "" + "custom\\t%1, %0, %2, %3" + [(set_attr "type" "custom")]) + + + + + + +;***************************************************************************** +;* +;* Misc +;* +;***************************************************************************** + +(define_insn "nop" + [(const_int 0)] + "" + "nop\\t" + [(set_attr "type" "alu")]) + +(define_insn "sync" + [(unspec_volatile [(const_int 0)] UNSPEC_SYNC)] + "" + "sync\\t" + [(set_attr "type" "control")]) + + +(define_insn "rdctl" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "rdwrctl_operand" "O")] + UNSPEC_RDCTL))] + "" + "rdctl\\t%0, ctl%1" + [(set_attr "type" "control")]) + +(define_insn "wrctl" + [(unspec_volatile:SI [(match_operand:SI 0 "rdwrctl_operand" "O") + (match_operand:SI 1 "reg_or_0_operand" "rM")] + UNSPEC_WRCTL)] + "" + "wrctl\\tctl%0, %z1" + [(set_attr "type" "control")]) + +;Used to signal a stack overflow +(define_insn "trap" + [(unspec_volatile [(const_int 0)] UNSPEC_TRAP)] + "" + "break\\t3" + [(set_attr "type" "control")]) + +(define_insn "stack_overflow_detect_and_trap" + [(unspec_volatile [(const_int 0)] UNSPEC_STACK_OVERFLOW_DETECT_AND_TRAP)] + "" + "bgeu\\tsp, et, 1f\;break\\t3\;1:" + [(set_attr "type" "control")]) + +;Load the GOT register. +(define_insn "load_got_register" + [(set (match_operand:SI 0 "register_operand" "=&r") + (unspec:SI [(const_int 0)] UNSPEC_LOAD_GOT_REGISTER)) + (set (match_operand:SI 1 "register_operand" "=r") + (unspec:SI [(const_int 0)] UNSPEC_LOAD_GOT_REGISTER))] + "" + "nextpc\\t%0 +\\t1: +\\tmovhi\\t%1, %%hiadj(_GLOBAL_OFFSET_TABLE_ - 1b) +\\taddi\\t%1, %1, %%lo(_GLOBAL_OFFSET_TABLE_ - 1b)" + [(set_attr "length" "12")]) + +;; When generating pic, we need to load the symbol offset into a register. +;; So that the optimizer does not confuse this with a normal symbol load +;; we use an unspec. The offset will be loaded from a constant pool entry, +;; since that is the only type of relocation we can use. + +;; The rather odd constraints on the following are to force reload to leave +;; the insn alone, and to force the minipool generation pass to then move +;; the GOT symbol to memory. + +;; FIXME:these uses look unnecessary. +(define_insn "pic_load_addr" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "" "mX")] UNSPEC_PIC_SYM)) + (use (match_dup 1))] + "flag_pic" + "ldw\\t%0, %%got(%2)(%1)") + +(define_insn "pic_load_call_addr" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "" "mX")] UNSPEC_PIC_CALL_SYM)) + (use (match_dup 1))] + "flag_pic" + "ldw\\t%0, %%call(%2)(%1)") + +;; TLS support + +(define_insn "add_tls_gd" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "" "mX")] UNSPEC_ADD_TLS_GD))] + "" + "addi\t%0, %1, %%tls_gd(%2)") + +(define_insn "load_tls_ie" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "" "mX")] UNSPEC_LOAD_TLS_IE))] + "" + "ldw\t%0, %%tls_ie(%2)(%1)") + +(define_insn "add_tls_ldm" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "" "mX")] UNSPEC_ADD_TLS_LDM))] + "" + "addi\t%0, %1, %%tls_ldm(%2)") + +(define_insn "add_tls_ldo" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "" "mX")] UNSPEC_ADD_TLS_LDO))] + "" + "addi\t%0, %1, %%tls_ldo(%2)") + +(define_insn "add_tls_le" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:SI 1 "register_operand" "r") + (match_operand:SI 2 "" "mX")] UNSPEC_ADD_TLS_LE))] + "" + "addi\t%0, %1, %%tls_le(%2)") + + +;***************************************************************************** +;* +;* Peepholes +;* +;***************************************************************************** + + +;; Local Variables: +;; mode: lisp +;; End: Index: gcc-4.1.2/gcc/config/nios2/nios2.opt =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gcc-4.1.2/gcc/config/nios2/nios2.opt 2010-06-30 08:50:26.000000000 +0200 @@ -0,0 +1,519 @@ +; NOT ASSIGNED TO FSF. COPYRIGHT ALTERA. +; Options for the Nios II port of the compiler. + +; This file is part of GCC. +; +; GCC is free software; you can redistribute it and/or modify it under +; the terms of the GNU General Public License as published by the Free +; Software Foundation; either version 2, or (at your option) any later +; version. +; +; GCC is distributed in the hope that it will be useful, but WITHOUT ANY +; WARRANTY; without even the implied warranty of MERCHANTABILITY or +; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +; for more details. +; +; You should have received a copy of the GNU General Public License +; along with GCC; see the file COPYING. If not, write to the Free +; Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +; 02110-1301, USA. + +mhw-div +Target Report Mask(HAS_DIV) +Enable DIV, DIVU + +mhw-mul +Target Report Mask(HAS_MUL) +Enable MUL instructions + +mhw-mulx +Target Report Mask(HAS_MULX) +Enable MULX instructions, assume fast shifter + +mfast-sw-div +Target Report Mask(FAST_SW_DIV) +Use table based fast divide (default at -O3) + +minline-memory +Target Report Mask(INLINE_MEMCPY) +Inline small memcpy (default when optimizing) + +mbypass-cache +Target Report Mask(BYPASS_CACHE) +All ld/st instructions use io variants + +mstack-check +Target Report Mask(STACK_CHECK) +Enable stack limit checking + +mreverse-bitfields +Target Report Mask(REVERSE_BITFIELDS) +Reverse the order of bitfields in a struct + +meb +Target Report RejectNegative Mask(BIG_ENDIAN) +Use big-endian byte order + +mel +Target Report RejectNegative InverseMask(BIG_ENDIAN) +Use little-endian byte order + +mcustom-fpu-cfg= +Target RejectNegative Joined Var(nios2_custom_fpu_cfg_string) VarExists +Floating point custom instruction configuration name + +mno-custom-ftruncds +Target Report RejectNegative Var(nios2_custom_ftruncds, -1) VarExists +Do not use the ftruncds custom instruction + +mcustom-ftruncds= +Target Report RejectNegative Joined UInteger Var(nios2_custom_ftruncds) VarExists +Integer id (N) of ftruncds custom instruction + +mno-custom-fextsd +Target Report RejectNegative Var(nios2_custom_fextsd, -1) VarExists +Do not use the fextsd custom instruction + +mcustom-fextsd= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fextsd) VarExists +Integer id (N) of fextsd custom instruction + +mno-custom-fixdu +Target Report RejectNegative Var(nios2_custom_fixdu, -1) VarExists +Do not use the fixdu custom instruction + +mcustom-fixdu= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fixdu) VarExists +Integer id (N) of fixdu custom instruction + +mno-custom-fixdi +Target Report RejectNegative Var(nios2_custom_fixdi, -1) VarExists +Do not use the fixdi custom instruction + +mcustom-fixdi= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fixdi) VarExists +Integer id (N) of fixdi custom instruction + +mno-custom-fixsu +Target Report RejectNegative Var(nios2_custom_fixsu, -1) VarExists +Do not use the fixsu custom instruction + +mcustom-fixsu= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fixsu) VarExists +Integer id (N) of fixsu custom instruction + +mno-custom-fixsi +Target Report RejectNegative Var(nios2_custom_fixsi, -1) VarExists +Do not use the fixsi custom instruction + +mcustom-fixsi= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fixsi) VarExists +Integer id (N) of fixsi custom instruction + +mno-custom-floatud +Target Report RejectNegative Var(nios2_custom_floatud, -1) VarExists +Do not use the floatud custom instruction + +mcustom-floatud= +Target Report RejectNegative Joined UInteger Var(nios2_custom_floatud) VarExists +Integer id (N) of floatud custom instruction + +mno-custom-floatid +Target Report RejectNegative Var(nios2_custom_floatid, -1) VarExists +Do not use the floatid custom instruction + +mcustom-floatid= +Target Report RejectNegative Joined UInteger Var(nios2_custom_floatid) VarExists +Integer id (N) of floatid custom instruction + +mno-custom-floatus +Target Report RejectNegative Var(nios2_custom_floatus, -1) VarExists +Do not use the floatus custom instruction + +mcustom-floatus= +Target Report RejectNegative Joined UInteger Var(nios2_custom_floatus) VarExists +Integer id (N) of floatus custom instruction + +mno-custom-floatis +Target Report RejectNegative Var(nios2_custom_floatis, -1) VarExists +Do not use the floatis custom instruction + +mcustom-floatis= +Target Report RejectNegative Joined UInteger Var(nios2_custom_floatis) VarExists +Integer id (N) of floatis custom instruction + +mno-custom-fcmpned +Target Report RejectNegative Var(nios2_custom_fcmpned, -1) VarExists +Do not use the fcmpned custom instruction + +mcustom-fcmpned= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmpned) VarExists +Integer id (N) of fcmpned custom instruction + +mno-custom-fcmpeqd +Target Report RejectNegative Var(nios2_custom_fcmpeqd, -1) VarExists +Do not use the fcmpeqd custom instruction + +mcustom-fcmpeqd= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmpeqd) VarExists +Integer id (N) of fcmpeqd custom instruction + +mno-custom-fcmpged +Target Report RejectNegative Var(nios2_custom_fcmpged, -1) VarExists +Do not use the fcmpged custom instruction + +mcustom-fcmpged= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmpged) VarExists +Integer id (N) of fcmpged custom instruction + +mno-custom-fcmpgtd +Target Report RejectNegative Var(nios2_custom_fcmpgtd, -1) VarExists +Do not use the fcmpgtd custom instruction + +mcustom-fcmpgtd= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmpgtd) VarExists +Integer id (N) of fcmpgtd custom instruction + +mno-custom-fcmpled +Target Report RejectNegative Var(nios2_custom_fcmpled, -1) VarExists +Do not use the fcmpled custom instruction + +mcustom-fcmpled= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmpled) VarExists +Integer id (N) of fcmpled custom instruction + +mno-custom-fcmpltd +Target Report RejectNegative Var(nios2_custom_fcmpltd, -1) VarExists +Do not use the fcmpltd custom instruction + +mcustom-fcmpltd= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmpltd) VarExists +Integer id (N) of fcmpltd custom instruction + +mno-custom-flogd +Target Report RejectNegative Var(nios2_custom_flogd, -1) VarExists +Do not use the flogd custom instruction + +mcustom-flogd= +Target Report RejectNegative Joined UInteger Var(nios2_custom_flogd) VarExists +Integer id (N) of flogd custom instruction + +mno-custom-fexpd +Target Report RejectNegative Var(nios2_custom_fexpd, -1) VarExists +Do not use the fexpd custom instruction + +mcustom-fexpd= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fexpd) VarExists +Integer id (N) of fexpd custom instruction + +mno-custom-fatand +Target Report RejectNegative Var(nios2_custom_fatand, -1) VarExists +Do not use the fatand custom instruction + +mcustom-fatand= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fatand) VarExists +Integer id (N) of fatand custom instruction + +mno-custom-ftand +Target Report RejectNegative Var(nios2_custom_ftand, -1) VarExists +Do not use the ftand custom instruction + +mcustom-ftand= +Target Report RejectNegative Joined UInteger Var(nios2_custom_ftand) VarExists +Integer id (N) of ftand custom instruction + +mno-custom-fsind +Target Report RejectNegative Var(nios2_custom_fsind, -1) VarExists +Do not use the fsind custom instruction + +mcustom-fsind= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fsind) VarExists +Integer id (N) of fsind custom instruction + +mno-custom-fcosd +Target Report RejectNegative Var(nios2_custom_fcosd, -1) VarExists +Do not use the fcosd custom instruction + +mcustom-fcosd= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fcosd) VarExists +Integer id (N) of fcosd custom instruction + +mno-custom-fsqrtd +Target Report RejectNegative Var(nios2_custom_fsqrtd, -1) VarExists +Do not use the fsqrtd custom instruction + +mcustom-fsqrtd= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fsqrtd) VarExists +Integer id (N) of fsqrtd custom instruction + +mno-custom-fabsd +Target Report RejectNegative Var(nios2_custom_fabsd, -1) VarExists +Do not use the fabsd custom instruction + +mcustom-fabsd= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fabsd) VarExists +Integer id (N) of fabsd custom instruction + +mno-custom-fnegd +Target Report RejectNegative Var(nios2_custom_fnegd, -1) VarExists +Do not use the fnegd custom instruction + +mcustom-fnegd= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fnegd) VarExists +Integer id (N) of fnegd custom instruction + +mno-custom-fmaxd +Target Report RejectNegative Var(nios2_custom_fmaxd, -1) VarExists +Do not use the fmaxd custom instruction + +mcustom-fmaxd= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fmaxd) VarExists +Integer id (N) of fmaxd custom instruction + +mno-custom-fmind +Target Report RejectNegative Var(nios2_custom_fmind, -1) VarExists +Do not use the fmind custom instruction + +mcustom-fmind= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fmind) VarExists +Integer id (N) of fmind custom instruction + +mno-custom-fdivd +Target Report RejectNegative Var(nios2_custom_fdivd, -1) VarExists +Do not use the fdivd custom instruction + +mcustom-fdivd= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fdivd) VarExists +Integer id (N) of fdivd custom instruction + +mno-custom-fmuld +Target Report RejectNegative Var(nios2_custom_fmuld, -1) VarExists +Do not use the fmuld custom instruction + +mcustom-fmuld= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fmuld) VarExists +Integer id (N) of fmuld custom instruction + +mno-custom-fsubd +Target Report RejectNegative Var(nios2_custom_fsubd, -1) VarExists +Do not use the fsubd custom instruction + +mcustom-fsubd= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fsubd) VarExists +Integer id (N) of fsubd custom instruction + +mno-custom-faddd +Target Report RejectNegative Var(nios2_custom_faddd, -1) VarExists +Do not use the faddd custom instruction + +mcustom-faddd= +Target Report RejectNegative Joined UInteger Var(nios2_custom_faddd) VarExists +Integer id (N) of faddd custom instruction + +mno-custom-fcmpnes +Target Report RejectNegative Var(nios2_custom_fcmpnes, -1) VarExists +Do not use the fcmpnes custom instruction + +mcustom-fcmpnes= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmpnes) VarExists +Integer id (N) of fcmpnes custom instruction + +mno-custom-fcmpeqs +Target Report RejectNegative Var(nios2_custom_fcmpeqs, -1) VarExists +Do not use the fcmpeqs custom instruction + +mcustom-fcmpeqs= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmpeqs) VarExists +Integer id (N) of fcmpeqs custom instruction + +mno-custom-fcmpges +Target Report RejectNegative Var(nios2_custom_fcmpges, -1) VarExists +Do not use the fcmpges custom instruction + +mcustom-fcmpges= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmpges) VarExists +Integer id (N) of fcmpges custom instruction + +mno-custom-fcmpgts +Target Report RejectNegative Var(nios2_custom_fcmpgts, -1) VarExists +Do not use the fcmpgts custom instruction + +mcustom-fcmpgts= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmpgts) VarExists +Integer id (N) of fcmpgts custom instruction + +mno-custom-fcmples +Target Report RejectNegative Var(nios2_custom_fcmples, -1) VarExists +Do not use the fcmples custom instruction + +mcustom-fcmples= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmples) VarExists +Integer id (N) of fcmples custom instruction + +mno-custom-fcmplts +Target Report RejectNegative Var(nios2_custom_fcmplts, -1) VarExists +Do not use the fcmplts custom instruction + +mcustom-fcmplts= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fcmplts) VarExists +Integer id (N) of fcmplts custom instruction + +mno-custom-flogs +Target Report RejectNegative Var(nios2_custom_flogs, -1) VarExists +Do not use the flogs custom instruction + +mcustom-flogs= +Target Report RejectNegative Joined UInteger Var(nios2_custom_flogs) VarExists +Integer id (N) of flogs custom instruction + +mno-custom-fexps +Target Report RejectNegative Var(nios2_custom_fexps, -1) VarExists +Do not use the fexps custom instruction + +mcustom-fexps= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fexps) VarExists +Integer id (N) of fexps custom instruction + +mno-custom-fatans +Target Report RejectNegative Var(nios2_custom_fatans, -1) VarExists +Do not use the fatans custom instruction + +mcustom-fatans= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fatans) VarExists +Integer id (N) of fatans custom instruction + +mno-custom-ftans +Target Report RejectNegative Var(nios2_custom_ftans, -1) VarExists +Do not use the ftans custom instruction + +mcustom-ftans= +Target Report RejectNegative Joined UInteger Var(nios2_custom_ftans) VarExists +Integer id (N) of ftans custom instruction + +mno-custom-fsins +Target Report RejectNegative Var(nios2_custom_fsins, -1) VarExists +Do not use the fsins custom instruction + +mcustom-fsins= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fsins) VarExists +Integer id (N) of fsins custom instruction + +mno-custom-fcoss +Target Report RejectNegative Var(nios2_custom_fcoss, -1) VarExists +Do not use the fcoss custom instruction + +mcustom-fcoss= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fcoss) VarExists +Integer id (N) of fcoss custom instruction + +mno-custom-fsqrts +Target Report RejectNegative Var(nios2_custom_fsqrts, -1) VarExists +Do not use the fsqrts custom instruction + +mcustom-fsqrts= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fsqrts) VarExists +Integer id (N) of fsqrts custom instruction + +mno-custom-fabss +Target Report RejectNegative Var(nios2_custom_fabss, -1) VarExists +Do not use the fabss custom instr + +mcustom-fabss= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fabss) VarExists +Integer id (N) of fabss custom instruction + +mno-custom-fnegs +Target Report RejectNegative Var(nios2_custom_fnegs, -1) VarExists +Do not use the fnegs custom instruction + +mcustom-fnegs= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fnegs) VarExists +Integer id (N) of fnegs custom instruction + +mno-custom-fmaxs +Target Report RejectNegative Var(nios2_custom_fmaxs, -1) VarExists +Do not use the fmaxs custom instruction + +mcustom-fmaxs= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fmaxs) VarExists +Integer id (N) of fmaxs custom instruction + +mno-custom-fmins +Target Report RejectNegative Var(nios2_custom_fmins, -1) VarExists +Do not use the fmins custom instruction + +mcustom-fmins= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fmins) VarExists +Integer id (N) of fmins custom instruction + +mno-custom-fdivs +Target Report RejectNegative Var(nios2_custom_fdivs, -1) VarExists +Do not use the fdivs custom instruction + +mcustom-fdivs= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fdivs) VarExists +Integer id (N) of fdivs custom instruction + +mno-custom-fmuls +Target Report RejectNegative Var(nios2_custom_fmuls, -1) VarExists +Do not use the fmuls custom instruction + +mcustom-fmuls= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fmuls) VarExists +Integer id (N) of fmuls custom instruction + +mno-custom-fsubs +Target Report RejectNegative Var(nios2_custom_fsubs, -1) VarExists +Do not use the fsubs custom instruction + +mcustom-fsubs= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fsubs) VarExists +Integer id (N) of fsubs custom instruction + +mno-custom-fadds +Target Report RejectNegative Var(nios2_custom_fadds, -1) VarExists +Do not use the fadds custom instruction + +mcustom-fadds= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fadds) VarExists +Integer id (N) of fadds custom instruction + +mno-custom-frdy +Target Report RejectNegative Var(nios2_custom_frdy, -1) VarExists +Do not use the frdy custom instruction + +mcustom-frdy= +Target Report RejectNegative Joined UInteger Var(nios2_custom_frdy) VarExists +Integer id (N) of frdy custom instruction + +mno-custom-frdxhi +Target Report RejectNegative Var(nios2_custom_frdxhi, -1) VarExists +Do not use the frdxhi custom instruction + +mcustom-frdxhi= +Target Report RejectNegative Joined UInteger Var(nios2_custom_frdxhi) VarExists +Integer id (N) of frdxhi custom instruction + +mno-custom-frdxlo +Target Report RejectNegative Var(nios2_custom_frdxlo, -1) VarExists +Do not use the frdxlo custom instruction + +mcustom-frdxlo= +Target Report RejectNegative Joined UInteger Var(nios2_custom_frdxlo) VarExists +Integer id (N) of frdxlo custom instruction + +mno-custom-fwry +Target Report RejectNegative Var(nios2_custom_fwry, -1) VarExists +Do not use the fwry custom instruction + +mcustom-fwry= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fwry) VarExists +Integer id (N) of fwry custom instruction + +mno-custom-fwrx +Target Report RejectNegative Var(nios2_custom_fwrx, -1) VarExists +Do not use the fwrx custom instruction + +mcustom-fwrx= +Target Report RejectNegative Joined UInteger Var(nios2_custom_fwrx) VarExists +Integer id (N) of fwrx custom instruction Index: gcc-4.1.2/gcc/config/nios2/t-linux =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gcc-4.1.2/gcc/config/nios2/t-linux 2010-06-30 08:50:26.000000000 +0200 @@ -0,0 +1,9 @@ +# Soft-float functions go in glibc only, to facilitate the possible +# future addition of exception and rounding mode support integrated +# with . + +FPBIT= +DPBIT= +LIB2FUNCS_EXCLUDE = _floatdidf _floatdisf _fixunsdfsi _fixunssfsi \ + _fixunsdfdi _fixdfdi _fixunssfdi _fixsfdi _floatundidf _floatundisf +LIB2FUNCS_EXTRA += $(srcdir)/config/nios2/linux-atomic.c Index: gcc-4.1.2/gcc/config/nios2/t-nios2 =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gcc-4.1.2/gcc/config/nios2/t-nios2 2010-06-30 08:50:26.000000000 +0200 @@ -0,0 +1,176 @@ +## +## Compiler flags to use when compiling libgcc2.c. +## +## LIB2FUNCS_EXTRA +## A list of source file names to be compiled or assembled and inserted into +## libgcc.a. + +LIB2FUNCS_EXTRA=$(srcdir)/config/nios2/lib2-divmod.c \ + $(srcdir)/config/nios2/lib2-divmod-hi.c \ + $(srcdir)/config/nios2/lib2-divtable.c \ + $(srcdir)/config/nios2/lib2-mul.c + +## +## Floating Point Emulation +## To have GCC include software floating point libraries in libgcc.a define FPBIT +## and DPBIT along with a few rules as follows: +## +## # We want fine grained libraries, so use the new code +## # to build the floating point emulation libraries. +FPBIT=fp-bit.c +DPBIT=dp-bit.c + +TARGET_LIBGCC2_CFLAGS = -O2 -fpic + +# FLOAT_ONLY - no doubles +# SMALL_MACHINE - QI/HI is faster than SI +# Actually SMALL_MACHINE uses chars and shorts instead of ints +# since ints (16-bit ones as they are today) are at least as fast +# as chars and shorts, don't define SMALL_MACHINE +# CMPtype - type returned by FP compare, i.e. INT (hard coded in fp-bit - see code ) + +$(FPBIT): $(srcdir)/config/fp-bit.c Makefile + echo '#define FLOAT' > ${FPBIT} + echo '#ifndef __nios2_big_endian__' >> ${FPBIT} + echo '#define FLOAT_BIT_ORDER_MISMATCH' >> ${FPBIT} + echo '#endif' >> ${FPBIT} + cat $(srcdir)/config/fp-bit.c >> ${FPBIT} + +$(DPBIT): $(srcdir)/config/fp-bit.c Makefile + echo '' > ${DPBIT} + echo '#ifndef __nios2_big_endian__' >> ${DPBIT} + echo '#define FLOAT_BIT_ORDER_MISMATCH' >> ${DPBIT} + echo '#endif' >> ${DPBIT} + cat $(srcdir)/config/fp-bit.c >> ${DPBIT} + +EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o crti.o crtn.o crtbeginS.o \ + crtbeginT.o crtendS.o + +# Assemble startup files. +$(T)crti.o: $(srcdir)/config/nios2/crti.asm $(GCC_PASSES) + $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \ + -c -o $(T)crti.o -x assembler-with-cpp $(srcdir)/config/nios2/crti.asm + +$(T)crtn.o: $(srcdir)/config/nios2/crtn.asm $(GCC_PASSES) + $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \ + -c -o $(T)crtn.o -x assembler-with-cpp $(srcdir)/config/nios2/crtn.asm + + +## You may need to provide additional #defines at the beginning of +## fp-bit.c and dp-bit.c to control target endianness and other options +## +## CRTSTUFF_T_CFLAGS +## Special flags used when compiling crtstuff.c. See Initialization. +## +## CRTSTUFF_T_CFLAGS_S +## Special flags used when compiling crtstuff.c for shared linking. Used +## if you use crtbeginS.o and crtendS.o in EXTRA-PARTS. See Initialization. +## +## MULTILIB_OPTIONS +## For some targets, invoking GCC in different ways produces objects that +## can not be linked together. For example, for some targets GCC produces +## both big and little endian code. For these targets, you must arrange +## for multiple versions of libgcc.a to be compiled, one for each set of +## incompatible options. When GCC invokes the linker, it arranges to link +## in the right version of libgcc.a, based on the command line options +## used. +## The MULTILIB_OPTIONS macro lists the set of options for which special +## versions of libgcc.a must be built. Write options that are mutually +## incompatible side by side, separated by a slash. Write options that may +## be used together separated by a space. The build procedure will build +## all combinations of compatible options. +## +## For example, if you set MULTILIB_OPTIONS to m68000/m68020 msoft-float, +## Makefile will build special versions of libgcc.a using the following +## sets of options: -m68000, -m68020, -msoft-float, -m68000 -msoft-float, +## and -m68020 -msoft-float. + + +## The BUILD_BE_MULTILIB and BUILD_PG_MULTILIB variables allow the +## makefile user to enable/disable the generation of the precompiled +## big endian and profiling libraries. By default, the big endian +## libraries are not created on a windows build and the profiling +## libraries are not created on a Solaris build. All other library +## combinations are created by default. + +# Uncomment to temporarily avoid building big endian and profiling libraries during a Windows build. +#ifeq ($(DEV_HOST_OS), win32) +#BUILD_BE_MULTILIB ?= 0 +#BUILD_PG_MULTILIB ?= 0 +#endif + +#By default, avoid building the profiling libraries during a Solaris build. +ifeq ($(DEV_HOST_OS), solaris) +BUILD_PG_MULTILIB ?= 0 +endif + +BUILD_BE_MULTILIB ?= 0 +BUILD_PG_MULTILIB ?= 1 +BUILD_MULTILIB ?= 0 + +ifeq ($(BUILD_MULTILIB), 1) + +MULTILIB_OPTIONS = mno-hw-mul mhw-mulx mstack-check mcustom-fpu-cfg=60-1 mcustom-fpu-cfg=60-2 + +#Add the profiling flag to the multilib variable if required +ifeq ($(BUILD_PG_MULTILIB), 1) +MULTILIB_OPTIONS += pg +endif + +#Add the big endian flag to the multilib variable if required +ifeq ($(BUILD_BE_MULTILIB), 1) +MULTILIB_OPTIONS += EB/EL +endif + +endif + +## MULTILIB_DIRNAMES +## If MULTILIB_OPTIONS is used, this variable specifies the directory names +## that should be used to hold the various libraries. Write one element in +## MULTILIB_DIRNAMES for each element in MULTILIB_OPTIONS. If +## MULTILIB_DIRNAMES is not used, the default value will be +## MULTILIB_OPTIONS, with all slashes treated as spaces. +## For example, if MULTILIB_OPTIONS is set to m68000/m68020 msoft-float, +## then the default value of MULTILIB_DIRNAMES is m68000 m68020 +## msoft-float. You may specify a different value if you desire a +## different set of directory names. + +# MULTILIB_DIRNAMES = + +## MULTILIB_MATCHES +## Sometimes the same option may be written in two different ways. If an +## option is listed in MULTILIB_OPTIONS, GCC needs to know about any +## synonyms. In that case, set MULTILIB_MATCHES to a list of items of the +## form option=option to describe all relevant synonyms. For example, +## m68000=mc68000 m68020=mc68020. + +ifeq ($(BUILD_MULTILIB), 1) +ifeq ($(BUILD_BE_MULTILIB), 1) +MULTILIB_MATCHES = EL=mel EB=meb +endif +endif + +## +## MULTILIB_EXCEPTIONS +## Sometimes when there are multiple sets of MULTILIB_OPTIONS being +## specified, there are combinations that should not be built. In that +## case, set MULTILIB_EXCEPTIONS to be all of the switch exceptions in +## shell case syntax that should not be built. +## For example, in the PowerPC embedded ABI support, it is not desirable to +## build libraries compiled with the -mcall-aix option and either of the +## -fleading-underscore or -mlittle options at the same time. Therefore +## MULTILIB_EXCEPTIONS is set to +## +## *mcall-aix/*fleading-underscore* *mlittle/*mcall-aix* +## + +ifeq ($(BUILD_MULTILIB), 1) +MULTILIB_EXCEPTIONS = *mno-hw-mul/*mhw-mulx* *mcustom-fpu-cfg=60-1/*mcustom-fpu-cfg=60-2* +endif + +## +## MULTILIB_EXTRA_OPTS Sometimes it is desirable that when building +## multiple versions of libgcc.a certain options should always be passed on +## to the compiler. In that case, set MULTILIB_EXTRA_OPTS to be the list +## of options to be used for all builds. +##