summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/config/sparc
diff options
context:
space:
mode:
authorkan <kan@FreeBSD.org>2007-05-19 01:19:51 +0000
committerkan <kan@FreeBSD.org>2007-05-19 01:19:51 +0000
commit1f9ea4d0a40cca64d60cf4dab152349da7b9dddf (patch)
tree0cb530c9c38af219e6dda2994c078b6b2b9ad853 /contrib/gcc/config/sparc
parent4895159b2b4f648051c1f139faa7b6dc50c2bfcb (diff)
downloadFreeBSD-src-1f9ea4d0a40cca64d60cf4dab152349da7b9dddf.zip
FreeBSD-src-1f9ea4d0a40cca64d60cf4dab152349da7b9dddf.tar.gz
GCC 4.2.0 release.
Diffstat (limited to 'contrib/gcc/config/sparc')
-rw-r--r--contrib/gcc/config/sparc/biarch64.h4
-rw-r--r--contrib/gcc/config/sparc/crtfastmath.c4
-rw-r--r--contrib/gcc/config/sparc/cypress.md4
-rw-r--r--contrib/gcc/config/sparc/freebsd.h32
-rw-r--r--contrib/gcc/config/sparc/hypersparc.md4
-rw-r--r--contrib/gcc/config/sparc/libgcc-sparc-glibc.ver33
-rw-r--r--contrib/gcc/config/sparc/linux-unwind.h158
-rw-r--r--contrib/gcc/config/sparc/linux.h186
-rw-r--r--contrib/gcc/config/sparc/linux64.h232
-rw-r--r--contrib/gcc/config/sparc/little-endian.opt28
-rw-r--r--contrib/gcc/config/sparc/long-double-switch.opt28
-rw-r--r--contrib/gcc/config/sparc/netbsd-elf.h38
-rw-r--r--contrib/gcc/config/sparc/niagara.md119
-rw-r--r--contrib/gcc/config/sparc/openbsd1-64.h4
-rw-r--r--contrib/gcc/config/sparc/openbsd64.h9
-rw-r--r--contrib/gcc/config/sparc/predicates.md478
-rw-r--r--contrib/gcc/config/sparc/rtemself.h13
-rw-r--r--contrib/gcc/config/sparc/sol2-64.h11
-rw-r--r--contrib/gcc/config/sparc/sol2-bi.h27
-rw-r--r--contrib/gcc/config/sparc/sol2-c1.asm4
-rw-r--r--contrib/gcc/config/sparc/sol2-ci.asm4
-rw-r--r--contrib/gcc/config/sparc/sol2-cn.asm4
-rw-r--r--contrib/gcc/config/sparc/sol2-gas-bi.h6
-rw-r--r--contrib/gcc/config/sparc/sol2-gas.h13
-rw-r--r--contrib/gcc/config/sparc/sol2.h60
-rw-r--r--contrib/gcc/config/sparc/sp-elf.h80
-rw-r--r--contrib/gcc/config/sparc/sp64-elf.h58
-rw-r--r--contrib/gcc/config/sparc/sparc-modes.def10
-rw-r--r--contrib/gcc/config/sparc/sparc-protos.h43
-rw-r--r--contrib/gcc/config/sparc/sparc.c6072
-rw-r--r--contrib/gcc/config/sparc/sparc.h805
-rw-r--r--contrib/gcc/config/sparc/sparc.md3155
-rw-r--r--contrib/gcc/config/sparc/sparc.opt126
-rw-r--r--contrib/gcc/config/sparc/sparclet.md4
-rw-r--r--contrib/gcc/config/sparc/supersparc.md4
-rw-r--r--contrib/gcc/config/sparc/sync.md208
-rw-r--r--contrib/gcc/config/sparc/sysv4-only.h7
-rw-r--r--contrib/gcc/config/sparc/sysv4.h4
-rw-r--r--contrib/gcc/config/sparc/t-linux5
-rw-r--r--contrib/gcc/config/sparc/t-linux646
-rw-r--r--contrib/gcc/config/sparc/ultra1_2.md8
-rw-r--r--contrib/gcc/config/sparc/ultra3.md8
42 files changed, 5886 insertions, 6220 deletions
diff --git a/contrib/gcc/config/sparc/biarch64.h b/contrib/gcc/config/sparc/biarch64.h
index b825f4f..097831f 100644
--- a/contrib/gcc/config/sparc/biarch64.h
+++ b/contrib/gcc/config/sparc/biarch64.h
@@ -16,8 +16,8 @@ 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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
/* Specify this in a cover file to provide bi-architecture (32/64) support. */
diff --git a/contrib/gcc/config/sparc/crtfastmath.c b/contrib/gcc/config/sparc/crtfastmath.c
index df3f907..d46a16a 100644
--- a/contrib/gcc/config/sparc/crtfastmath.c
+++ b/contrib/gcc/config/sparc/crtfastmath.c
@@ -22,8 +22,8 @@
*
* 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.
+ * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
*
* As a special exception, if you link this library with files
* compiled with GCC to produce an executable, this does not cause
diff --git a/contrib/gcc/config/sparc/cypress.md b/contrib/gcc/config/sparc/cypress.md
index c234594..67596b0 100644
--- a/contrib/gcc/config/sparc/cypress.md
+++ b/contrib/gcc/config/sparc/cypress.md
@@ -15,8 +15,8 @@
;;
;; 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, 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
;; The Cypress is a pretty simple single-issue processor.
diff --git a/contrib/gcc/config/sparc/freebsd.h b/contrib/gcc/config/sparc/freebsd.h
index c6f7398..9e432a3 100644
--- a/contrib/gcc/config/sparc/freebsd.h
+++ b/contrib/gcc/config/sparc/freebsd.h
@@ -1,5 +1,5 @@
/* Definitions for Sun SPARC64 running FreeBSD using the ELF format
- Copyright (C) 2001, 2002, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2001, 2002, 2004, 2005, 2006 Free Software Foundation, Inc.
Contributed by David E. O'Brien <obrien@FreeBSD.org> and BSDi.
This file is part of GCC.
@@ -16,8 +16,8 @@ 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
#undef SUBTARGET_EXTRA_SPECS
#define SUBTARGET_EXTRA_SPECS \
@@ -32,8 +32,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#define LINK_SPEC "%(link_arch) \
%{!mno-relax:%{!r:-relax}} \
- %{p:%nconsider using `-pg' instead of `-p' with gprof(1)} \
- %{Wl,*:%*} \
+ %{p:%nconsider using `-pg' instead of `-p' with gprof(1)} \
%{assert*} %{R*} %{rpath*} %{defsym*} \
%{shared:-Bshareable %{h*} %{soname*}} \
%{symbolic:-Bsymbolic} \
@@ -62,10 +61,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#undef LONG_DOUBLE_TYPE_SIZE
#define LONG_DOUBLE_TYPE_SIZE (TARGET_LONG_DOUBLE_128 ? 128 : 64)
-/* Constant which presents upper bound of the above value. */
-#undef MAX_LONG_DOUBLE_TYPE_SIZE
-#define MAX_LONG_DOUBLE_TYPE_SIZE 128
-
/* Define this to set long double type size to use in libgcc2.c, which can
not depend on target_flags. */
#if defined(__arch64__) || defined(__LONG_DOUBLE_128__)
@@ -76,11 +71,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Definitions for 64-bit SPARC running systems with ELF. */
-#undef SUBTARGET_SWITCHES
-#define SUBTARGET_SWITCHES \
- {"long-double-64", -MASK_LONG_DOUBLE_128, N_("Use 64 bit long doubles") }, \
- {"long-double-128", MASK_LONG_DOUBLE_128, N_("Use 128 bit long doubles") },
-
#undef TARGET_VERSION
#define TARGET_VERSION fprintf (stderr, " (FreeBSD/sparc64 ELF)");
@@ -132,14 +122,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#define LOCAL_LABEL_PREFIX "."
/* XXX2 */
-/* This is how to output a reference to an internal numbered label where
- PREFIX is the class of label and NUM is the number within the class. */
-
-#undef ASM_OUTPUT_INTERNAL_LABELREF
-#define ASM_OUTPUT_INTERNAL_LABELREF(FILE,PREFIX,NUM) \
- fprintf (FILE, ".L%s%d", PREFIX, NUM)
-
-/* XXX2 */
/* This is how to store into the string LABEL
the symbol_ref name of an internal numbered label where
PREFIX is the class of label and NUM is the number within the class.
@@ -168,9 +150,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* #define DWARF_OFFSET_SIZE PTR_SIZE */
#undef ENDFILE_SPEC
-#define ENDFILE_SPEC \
- "%{ffast-math|funsafe-math-optimizations:crtfastmath.o%s}" \
- FBSD_ENDFILE_SPEC
+#define ENDFILE_SPEC \
+ "%{ffast-math|funsafe-math-optimizations:crtfastmath.o%s} " \
+ FBSD_ENDFILE_SPEC
/* We use GNU ld so undefine this so that attribute((init_priority)) works. */
#undef CTORS_SECTION_ASM_OP
diff --git a/contrib/gcc/config/sparc/hypersparc.md b/contrib/gcc/config/sparc/hypersparc.md
index d617efd..185be6f 100644
--- a/contrib/gcc/config/sparc/hypersparc.md
+++ b/contrib/gcc/config/sparc/hypersparc.md
@@ -15,8 +15,8 @@
;;
;; 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, 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
;; The HyperSPARC is a dual-issue processor. It is not all that fancy.
diff --git a/contrib/gcc/config/sparc/libgcc-sparc-glibc.ver b/contrib/gcc/config/sparc/libgcc-sparc-glibc.ver
index e3ba0bb..ed280fe 100644
--- a/contrib/gcc/config/sparc/libgcc-sparc-glibc.ver
+++ b/contrib/gcc/config/sparc/libgcc-sparc-glibc.ver
@@ -26,3 +26,36 @@ GLIBC_VER {
__frame_state_for
__register_frame_info_table
}
+
+%if !defined (__arch64__) && defined (__LONG_DOUBLE_128__)
+
+# long double 128 bit support from 32-bit libgcc_s.so.1 is only available
+# when configured with --with-long-double-128. Make sure all the
+# symbols are available at @@GCC_LDBL_* versions to make it clear
+# there is a configurable symbol set.
+
+%exclude {
+ __fixtfdi
+ __fixunstfdi
+ __floatditf
+
+ __divtc3
+ __multc3
+ __powitf2
+}
+
+%inherit GCC_LDBL_3.0 GCC_3.0
+GCC_LDBL_3.0 {
+ __fixtfdi
+ __fixunstfdi
+ __floatditf
+}
+
+%inherit GCC_LDBL_4.0.0 GCC_4.0.0
+GCC_LDBL_4.0.0 {
+ __divtc3
+ __multc3
+ __powitf2
+}
+
+%endif
diff --git a/contrib/gcc/config/sparc/linux-unwind.h b/contrib/gcc/config/sparc/linux-unwind.h
new file mode 100644
index 0000000..958cb2d
--- /dev/null
+++ b/contrib/gcc/config/sparc/linux-unwind.h
@@ -0,0 +1,158 @@
+/* DWARF2 EH unwinding support for SPARC Linux.
+ Copyright 2004, 2005 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. */
+
+/* Do code reading to identify a signal frame, and set the frame
+ state data appropriately. See unwind-dw2.c for the structs. */
+
+/* Handle multilib correctly. */
+#if defined(__arch64__)
+
+/* 64-bit SPARC version */
+#define MD_FALLBACK_FRAME_STATE_FOR sparc64_fallback_frame_state
+
+static _Unwind_Reason_Code
+sparc64_fallback_frame_state (struct _Unwind_Context *context,
+ _Unwind_FrameState *fs)
+{
+ unsigned int *pc = context->ra;
+ long new_cfa, i;
+ long regs_off, fpu_save_off;
+ long this_cfa, fpu_save;
+
+ if (pc[0] != 0x82102065 /* mov NR_rt_sigreturn, %g1 */
+ || pc[1] != 0x91d0206d) /* ta 0x6d */
+ return _URC_END_OF_STACK;
+ regs_off = 192 + 128;
+ fpu_save_off = regs_off + (16 * 8) + (3 * 8) + (2 * 4);
+ this_cfa = (long) context->cfa;
+ new_cfa = *(long *)((context->cfa) + (regs_off + (14 * 8)));
+ new_cfa += 2047; /* Stack bias */
+ fpu_save = *(long *)((this_cfa) + (fpu_save_off));
+ fs->cfa_how = CFA_REG_OFFSET;
+ fs->cfa_reg = 14;
+ fs->cfa_offset = new_cfa - (long) context->cfa;
+ for (i = 1; i < 16; ++i)
+ {
+ fs->regs.reg[i].how = REG_SAVED_OFFSET;
+ fs->regs.reg[i].loc.offset =
+ this_cfa + (regs_off + (i * 8)) - new_cfa;
+ }
+ for (i = 0; i < 16; ++i)
+ {
+ fs->regs.reg[i + 16].how = REG_SAVED_OFFSET;
+ fs->regs.reg[i + 16].loc.offset =
+ this_cfa + (i * 8) - new_cfa;
+ }
+ if (fpu_save)
+ {
+ for (i = 0; i < 64; ++i)
+ {
+ if (i > 32 && (i & 0x1))
+ continue;
+ fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
+ fs->regs.reg[i + 32].loc.offset =
+ (fpu_save + (i * 4)) - new_cfa;
+ }
+ }
+ /* Stick return address into %g0, same trick Alpha uses. */
+ fs->regs.reg[0].how = REG_SAVED_OFFSET;
+ fs->regs.reg[0].loc.offset =
+ this_cfa + (regs_off + (16 * 8) + 8) - new_cfa;
+ fs->retaddr_column = 0;
+ return _URC_NO_REASON;
+}
+
+#else
+
+/* 32-bit SPARC version */
+#define MD_FALLBACK_FRAME_STATE_FOR sparc_fallback_frame_state
+
+static _Unwind_Reason_Code
+sparc_fallback_frame_state (struct _Unwind_Context *context,
+ _Unwind_FrameState *fs)
+{
+ unsigned int *pc = context->ra;
+ int new_cfa, i, oldstyle;
+ int regs_off, fpu_save_off;
+ int fpu_save, this_cfa;
+
+ if (pc[1] != 0x91d02010) /* ta 0x10 */
+ return _URC_END_OF_STACK;
+ if (pc[0] == 0x821020d8) /* mov NR_sigreturn, %g1 */
+ oldstyle = 1;
+ else if (pc[0] == 0x82102065) /* mov NR_rt_sigreturn, %g1 */
+ oldstyle = 0;
+ else
+ return _URC_END_OF_STACK;
+ if (oldstyle)
+ {
+ regs_off = 96;
+ fpu_save_off = regs_off + (4 * 4) + (16 * 4);
+ }
+ else
+ {
+ regs_off = 96 + 128;
+ fpu_save_off = regs_off + (4 * 4) + (16 * 4) + (2 * 4);
+ }
+ this_cfa = (int) context->cfa;
+ new_cfa = *(int *)((context->cfa) + (regs_off+(4*4)+(14 * 4)));
+ fpu_save = *(int *)((this_cfa) + (fpu_save_off));
+ fs->cfa_how = CFA_REG_OFFSET;
+ fs->cfa_reg = 14;
+ fs->cfa_offset = new_cfa - (int) context->cfa;
+ for (i = 1; i < 16; ++i)
+ {
+ if (i == 14)
+ continue;
+ fs->regs.reg[i].how = REG_SAVED_OFFSET;
+ fs->regs.reg[i].loc.offset =
+ this_cfa + (regs_off+(4 * 4)+(i * 4)) - new_cfa;
+ }
+ for (i = 0; i < 16; ++i)
+ {
+ fs->regs.reg[i + 16].how = REG_SAVED_OFFSET;
+ fs->regs.reg[i + 16].loc.offset =
+ this_cfa + (i * 4) - new_cfa;
+ }
+ if (fpu_save)
+ {
+ for (i = 0; i < 32; ++i)
+ {
+ fs->regs.reg[i + 32].how = REG_SAVED_OFFSET;
+ fs->regs.reg[i + 32].loc.offset =
+ (fpu_save + (i * 4)) - new_cfa;
+ }
+ }
+ /* Stick return address into %g0, same trick Alpha uses. */
+ fs->regs.reg[0].how = REG_SAVED_OFFSET;
+ fs->regs.reg[0].loc.offset = this_cfa+(regs_off+4)-new_cfa;
+ fs->retaddr_column = 0;
+ return _URC_NO_REASON;
+}
+
+#endif
diff --git a/contrib/gcc/config/sparc/linux.h b/contrib/gcc/config/sparc/linux.h
index 7ddf2a3..5af67a6 100644
--- a/contrib/gcc/config/sparc/linux.h
+++ b/contrib/gcc/config/sparc/linux.h
@@ -1,5 +1,5 @@
/* Definitions for SPARC running Linux-based GNU systems with ELF.
- Copyright (C) 1996, 1997, 1998, 1999, 2000, 2002, 2003, 2004
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
Contributed by Eddie C. Dost (ecd@skynet.be)
@@ -17,18 +17,20 @@ 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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
#define TARGET_OS_CPP_BUILTINS() \
do \
{ \
- builtin_define_std ("unix"); \
- builtin_define_std ("linux"); \
- builtin_define ("__gnu_linux__"); \
- builtin_assert ("system=linux"); \
- builtin_assert ("system=unix"); \
- builtin_assert ("system=posix"); \
+ builtin_define_std ("unix"); \
+ builtin_define_std ("linux"); \
+ builtin_define ("__gnu_linux__"); \
+ builtin_assert ("system=linux"); \
+ builtin_assert ("system=unix"); \
+ builtin_assert ("system=posix"); \
+ if (TARGET_LONG_DOUBLE_128) \
+ builtin_define ("__LONG_DOUBLE_128__"); \
} \
while (0)
@@ -44,12 +46,7 @@ Boston, MA 02111-1307, USA. */
object constructed before entering `main'. */
#undef STARTFILE_SPEC
-#ifdef USE_GNULIBC_1
-#define STARTFILE_SPEC \
- "%{!shared: \
- %{pg:gcrt1.o%s} %{!pg:%{p:gcrt1.o%s} %{!p:crt1.o%s}}}\
- crti.o%s %{!shared:crtbegin.o%s} %{shared:crtbeginS.o%s}"
-#elif defined HAVE_LD_PIE
+#if defined HAVE_LD_PIE
#define STARTFILE_SPEC \
"%{!shared: %{pg|p:gcrt1.o%s;pie:Scrt1.o%s;:crt1.o%s}}\
crti.o%s %{static:crtbeginT.o%s;shared|pie:crtbeginS.o%s;:crtbegin.o%s}"
@@ -86,11 +83,6 @@ Boston, MA 02111-1307, USA. */
#undef TARGET_VERSION
#define TARGET_VERSION fprintf (stderr, " (sparc GNU/Linux with ELF)");
-#undef SUBTARGET_SWITCHES
-#define SUBTARGET_SWITCHES \
-{"long-double-64", -MASK_LONG_DOUBLE_128, N_("Use 64 bit long doubles") }, \
-{"long-double-128", MASK_LONG_DOUBLE_128, N_("Use 128 bit long doubles") },
-
#undef SIZE_TYPE
#define SIZE_TYPE "unsigned int"
@@ -104,37 +96,14 @@ Boston, MA 02111-1307, USA. */
#define WCHAR_TYPE_SIZE 32
#undef CPP_SUBTARGET_SPEC
-#ifdef USE_GNULIBC_1
#define CPP_SUBTARGET_SPEC \
-"%{fPIC|fPIE|fpic|fpie:-D__PIC__ -D__pic__} %{posix:-D_POSIX_SOURCE} \
-%{mlong-double-128:-D__LONG_DOUBLE_128__}"
-#else
-#define CPP_SUBTARGET_SPEC \
-"%{fPIC|fPIE|fpic|fpie:-D__PIC__ -D__pic__} %{posix:-D_POSIX_SOURCE} \
-%{pthread:-D_REENTRANT} %{mlong-double-128:-D__LONG_DOUBLE_128__}"
-#endif
+"%{posix:-D_POSIX_SOURCE} %{pthread:-D_REENTRANT}"
#undef LIB_SPEC
-/* We no longer link with libc_p.a or libg.a by default. If you
- want to profile or debug the GNU/Linux C library, please add
- -lc_p or -ggdb to LDFLAGS at the link time, respectively. */
-#if 1
-#ifdef USE_GNULIBC_1
-#define LIB_SPEC \
- "%{!shared: %{p:-lgmon} %{pg:-lgmon} %{profile:-lgmon -lc_p} \
- %{!profile:%{!ggdb:-lc} %{ggdb:-lg}}}"
-#else
#define LIB_SPEC \
"%{pthread:-lpthread} \
%{shared:-lc} \
%{!shared:%{mieee-fp:-lieee} %{profile:-lc_p}%{!profile:-lc}}"
-#endif
-#else
-#define LIB_SPEC \
- "%{!shared: \
- %{mieee-fp:-lieee} %{p:-lgmon -lc_p} %{pg:-lgmon -lc_p} \
- %{!p:%{!pg:%{!g*:-lc} %{g*:-lg}}}}"
-#endif
/* Provide a LINK_SPEC appropriate for GNU/Linux. Here we provide support
for the special GCC options -static and -shared, which allow us to
@@ -152,25 +121,26 @@ Boston, MA 02111-1307, USA. */
/* If ELF is the default format, we should not use /lib/elf. */
-#undef LINK_SPEC
-#ifdef USE_GNULIBC_1
-#define LINK_SPEC "-m elf32_sparc -Y P,/usr/lib %{shared:-shared} \
- %{!shared: \
- %{!ibcs: \
- %{!static: \
- %{rdynamic:-export-dynamic} \
- %{!dynamic-linker:-dynamic-linker /lib/ld-linux.so.1}} \
- %{static:-static}}}"
+#define GLIBC_DYNAMIC_LINKER "/lib/ld-linux.so.2"
+#define UCLIBC_DYNAMIC_LINKER "/lib/ld-uClibc.so.0"
+#if UCLIBC_DEFAULT
+#define CHOOSE_DYNAMIC_LINKER(G, U) "%{mglibc:%{muclibc:%e-mglibc and -muclibc used together}" G ";:" U "}"
#else
+#define CHOOSE_DYNAMIC_LINKER(G, U) "%{muclibc:%{mglibc:%e-mglibc and -muclibc used together}" U ";:" G "}"
+#endif
+#define LINUX_DYNAMIC_LINKER \
+ CHOOSE_DYNAMIC_LINKER (GLIBC_DYNAMIC_LINKER, UCLIBC_DYNAMIC_LINKER)
+
+
+#undef LINK_SPEC
#define LINK_SPEC "-m elf32_sparc -Y P,/usr/lib %{shared:-shared} \
%{!mno-relax:%{!r:-relax}} \
%{!shared: \
%{!ibcs: \
%{!static: \
%{rdynamic:-export-dynamic} \
- %{!dynamic-linker:-dynamic-linker /lib/ld-linux.so.2}} \
+ %{!dynamic-linker:-dynamic-linker " LINUX_DYNAMIC_LINKER "}} \
%{static:-static}}}"
-#endif
/* The sun bundled assembler doesn't accept -Yd, (and neither does gas).
It's safe to pass -s always, even if -g is not used. */
@@ -198,13 +168,6 @@ do { \
#undef LOCAL_LABEL_PREFIX
#define LOCAL_LABEL_PREFIX "."
-/* This is how to output a reference to an internal numbered label where
- PREFIX is the class of label and NUM is the number within the class. */
-
-#undef ASM_OUTPUT_INTERNAL_LABELREF
-#define ASM_OUTPUT_INTERNAL_LABELREF(FILE,PREFIX,NUM) \
- fprintf (FILE, ".L%s%d", PREFIX, NUM)
-
/* This is how to store into the string LABEL
the symbol_ref name of an internal numbered label where
PREFIX is the class of label and NUM is the number within the class.
@@ -219,9 +182,6 @@ do { \
SPARC ABI says that long double is 4 words. */
#define LONG_DOUBLE_TYPE_SIZE (TARGET_LONG_DOUBLE_128 ? 128 : 64)
-/* Constant which presents upper bound of the above value. */
-#define MAX_LONG_DOUBLE_TYPE_SIZE 128
-
/* Define this to set long double type size to use in libgcc2.c, which can
not depend on target_flags. */
#ifdef __LONG_DOUBLE_128__
@@ -233,7 +193,7 @@ do { \
#undef DITF_CONVERSION_LIBFUNCS
#define DITF_CONVERSION_LIBFUNCS 1
-#if !defined(USE_GNULIBC_1) && defined(HAVE_LD_EH_FRAME_HDR)
+#if defined(HAVE_LD_EH_FRAME_HDR)
#define LINK_EH_SPEC "%{!static:--eh-frame-hdr} "
#endif
@@ -251,78 +211,36 @@ do { \
#undef CTORS_SECTION_ASM_OP
#undef DTORS_SECTION_ASM_OP
-#define TARGET_ASM_FILE_END file_end_indicate_exec_stack
-
-/* Determine whether the the entire c99 runtime is present in the
+/* Determine whether the entire c99 runtime is present in the
runtime library. */
-#define TARGET_C99_FUNCTIONS 1
+#define TARGET_C99_FUNCTIONS (OPTION_GLIBC)
-#define TARGET_HAS_F_SETLKW
+#define TARGET_POSIX_IO
#undef LINK_GCC_C_SEQUENCE_SPEC
#define LINK_GCC_C_SEQUENCE_SPEC \
"%{static:--start-group} %G %L %{static:--end-group}%{!static:%G}"
-/* Do code reading to identify a signal frame, and set the frame
- state data appropriately. See unwind-dw2.c for the structs. */
-
-#define MD_FALLBACK_FRAME_STATE_FOR(CONTEXT, FS, SUCCESS) \
- do { \
- unsigned int *pc_ = (CONTEXT)->ra; \
- int new_cfa_, i_, oldstyle_; \
- int regs_off_, fpu_save_off_; \
- int fpu_save_, this_cfa_; \
- \
- if (pc_[1] != 0x91d02010) /* ta 0x10 */ \
- break; \
- if (pc_[0] == 0x821020d8) /* mov NR_sigreturn, %g1 */ \
- oldstyle_ = 1; \
- else if (pc_[0] == 0x82102065) /* mov NR_rt_sigreturn, %g1 */ \
- oldstyle_ = 0; \
- else \
- break; \
- if (oldstyle_) \
- { \
- regs_off_ = 96; \
- fpu_save_off_ = regs_off_ + (4 * 4) + (16 * 4); \
- } \
- else \
- { \
- regs_off_ = 96 + 128; \
- fpu_save_off_ = regs_off_ + (4 * 4) + (16 * 4) + (2 * 4); \
- } \
- this_cfa_ = (int) (CONTEXT)->cfa; \
- new_cfa_ = *(int *)(((CONTEXT)->cfa) + (regs_off_+(4*4)+(14 * 4))); \
- fpu_save_ = *(int *)((this_cfa_) + (fpu_save_off_)); \
- (FS)->cfa_how = CFA_REG_OFFSET; \
- (FS)->cfa_reg = 14; \
- (FS)->cfa_offset = new_cfa_ - (int) (CONTEXT)->cfa; \
- for (i_ = 1; i_ < 16; ++i_) \
- { \
- if (i_ == 14) \
- continue; \
- (FS)->regs.reg[i_].how = REG_SAVED_OFFSET; \
- (FS)->regs.reg[i_].loc.offset = \
- this_cfa_ + (regs_off_+(4 * 4)+(i_ * 4)) - new_cfa_; \
- } \
- for (i_ = 0; i_ < 16; ++i_) \
- { \
- (FS)->regs.reg[i_ + 16].how = REG_SAVED_OFFSET; \
- (FS)->regs.reg[i_ + 16].loc.offset = \
- this_cfa_ + (i_ * 4) - new_cfa_; \
- } \
- if (fpu_save_) \
- { \
- for (i_ = 0; i_ < 32; ++i_) \
- { \
- (FS)->regs.reg[i_ + 32].how = REG_SAVED_OFFSET; \
- (FS)->regs.reg[i_ + 32].loc.offset = \
- (fpu_save_ + (i_ * 4)) - new_cfa_; \
- } \
- } \
- /* Stick return address into %g0, same trick Alpha uses. */ \
- (FS)->regs.reg[0].how = REG_SAVED_OFFSET; \
- (FS)->regs.reg[0].loc.offset = this_cfa_+(regs_off_+4)-new_cfa_; \
- (FS)->retaddr_column = 0; \
- goto SUCCESS; \
- } while (0)
+/* Use --as-needed -lgcc_s for eh support. */
+#ifdef HAVE_LD_AS_NEEDED
+#define USE_LD_AS_NEEDED 1
+#endif
+
+#define MD_UNWIND_SUPPORT "config/sparc/linux-unwind.h"
+
+/* Linux currently uses RMO in uniprocessor mode, which is equivalent to
+ TMO, and TMO in multiprocessor mode. But they reserve the right to
+ change their minds. */
+#undef SPARC_RELAXED_ORDERING
+#define SPARC_RELAXED_ORDERING true
+
+#undef NEED_INDICATE_EXEC_STACK
+#define NEED_INDICATE_EXEC_STACK 1
+
+#ifdef TARGET_LIBC_PROVIDES_SSP
+/* sparc glibc provides __stack_chk_guard in [%g7 + 0x14]. */
+#define TARGET_THREAD_SSP_OFFSET 0x14
+#endif
+
+/* Define if long doubles should be mangled as 'g'. */
+#define TARGET_ALTERNATE_LONG_DOUBLE_MANGLING
diff --git a/contrib/gcc/config/sparc/linux64.h b/contrib/gcc/config/sparc/linux64.h
index bb1c591..b0ddf4b 100644
--- a/contrib/gcc/config/sparc/linux64.h
+++ b/contrib/gcc/config/sparc/linux64.h
@@ -1,5 +1,5 @@
/* Definitions for 64-bit SPARC running Linux-based GNU systems with ELF.
- Copyright 1996, 1997, 1998, 2000, 2002, 2003, 2004
+ Copyright 1996, 1997, 1998, 2000, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
Contributed by David S. Miller (davem@caip.rutgers.edu)
@@ -17,20 +17,22 @@ 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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
-
-#define TARGET_OS_CPP_BUILTINS() \
- do \
- { \
- builtin_define_std ("unix"); \
- builtin_define_std ("linux"); \
- builtin_define ("_LONGLONG"); \
- builtin_define ("__gnu_linux__"); \
- builtin_assert ("system=linux"); \
- builtin_assert ("system=unix"); \
- builtin_assert ("system=posix"); \
- } \
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
+
+#define TARGET_OS_CPP_BUILTINS() \
+ do \
+ { \
+ builtin_define_std ("unix"); \
+ builtin_define_std ("linux"); \
+ builtin_define ("_LONGLONG"); \
+ builtin_define ("__gnu_linux__"); \
+ builtin_assert ("system=linux"); \
+ builtin_assert ("system=unix"); \
+ builtin_assert ("system=posix"); \
+ if (TARGET_ARCH32 && TARGET_LONG_DOUBLE_128) \
+ builtin_define ("__LONG_DOUBLE_128__"); \
+ } \
while (0)
/* Don't assume anything about the header files. */
@@ -41,7 +43,8 @@ Boston, MA 02111-1307, USA. */
#if TARGET_CPU_DEFAULT == TARGET_CPU_v9 \
|| TARGET_CPU_DEFAULT == TARGET_CPU_ultrasparc \
- || TARGET_CPU_DEFAULT == TARGET_CPU_ultrasparc3
+ || TARGET_CPU_DEFAULT == TARGET_CPU_ultrasparc3 \
+ || TARGET_CPU_DEFAULT == TARGET_CPU_niagara
/* A 64 bit v9 compiler with stack-bias,
in a Medium/Low code model environment. */
@@ -54,13 +57,6 @@ Boston, MA 02111-1307, USA. */
#undef ASM_CPU_DEFAULT_SPEC
#define ASM_CPU_DEFAULT_SPEC "-Av9a"
-#ifdef SPARC_BI_ARCH
-
-#undef CPP_ARCH32_SPEC
-#define CPP_ARCH32_SPEC "%{mlong-double-128:-D__LONG_DOUBLE_128__}"
-
-#endif
-
/* Provide a STARTFILE_SPEC appropriate for GNU/Linux. Here we add
the GNU/Linux magical crtbegin.o file (see crtstuff.c) which
provides part of the support for getting C++ file-scope static
@@ -101,11 +97,6 @@ Boston, MA 02111-1307, USA. */
#undef SPARC_DEFAULT_CMODEL
#define SPARC_DEFAULT_CMODEL CM_MEDLOW
-#undef SUBTARGET_SWITCHES
-#define SUBTARGET_SWITCHES \
-{"long-double-64", -MASK_LONG_DOUBLE_128, N_("Use 64 bit long doubles") }, \
-{"long-double-128", MASK_LONG_DOUBLE_128, N_("Use 128 bit long doubles") },
-
#undef WCHAR_TYPE
#define WCHAR_TYPE "int"
@@ -117,10 +108,6 @@ Boston, MA 02111-1307, USA. */
#undef LONG_DOUBLE_TYPE_SIZE
#define LONG_DOUBLE_TYPE_SIZE (TARGET_LONG_DOUBLE_128 ? 128 : 64)
-/* Constant which presents upper bound of the above value. */
-#undef MAX_LONG_DOUBLE_TYPE_SIZE
-#define MAX_LONG_DOUBLE_TYPE_SIZE 128
-
/* Define this to set long double type size to use in libgcc2.c, which can
not depend on target_flags. */
#if defined(__arch64__) || defined(__LONG_DOUBLE_128__)
@@ -131,7 +118,6 @@ Boston, MA 02111-1307, USA. */
#undef CPP_SUBTARGET_SPEC
#define CPP_SUBTARGET_SPEC "\
-%{fPIC|fpic|fPIE|fpie:-D__PIC__ -D__pic__} \
%{posix:-D_POSIX_SOURCE} \
%{pthread:-D_REENTRANT} \
"
@@ -158,6 +144,20 @@ Boston, MA 02111-1307, USA. */
/* If ELF is the default format, we should not use /lib/elf. */
+#define GLIBC_DYNAMIC_LINKER32 "/lib/ld-linux.so.2"
+#define GLIBC_DYNAMIC_LINKER64 "/lib64/ld-linux.so.2"
+#define UCLIBC_DYNAMIC_LINKER32 "/lib/ld-uClibc.so.0"
+#define UCLIBC_DYNAMIC_LINKER64 "/lib/ld64-uClibc.so.0"
+#if UCLIBC_DEFAULT
+#define CHOOSE_DYNAMIC_LINKER(G, U) "%{mglibc:%{muclibc:%e-mglibc and -muclibc used together}" G ";:" U "}"
+#else
+#define CHOOSE_DYNAMIC_LINKER(G, U) "%{muclibc:%{mglibc:%e-mglibc and -muclibc used together}" U ";:" G "}"
+#endif
+#define LINUX_DYNAMIC_LINKER32 \
+ CHOOSE_DYNAMIC_LINKER (GLIBC_DYNAMIC_LINKER32, UCLIBC_DYNAMIC_LINKER32)
+#define LINUX_DYNAMIC_LINKER64 \
+ CHOOSE_DYNAMIC_LINKER (GLIBC_DYNAMIC_LINKER64, UCLIBC_DYNAMIC_LINKER64)
+
#ifdef SPARC_BI_ARCH
#undef SUBTARGET_EXTRA_SPECS
@@ -166,13 +166,13 @@ Boston, MA 02111-1307, USA. */
{ "link_arch64", LINK_ARCH64_SPEC }, \
{ "link_arch_default", LINK_ARCH_DEFAULT_SPEC }, \
{ "link_arch", LINK_ARCH_SPEC },
-
+
#define LINK_ARCH32_SPEC "-m elf32_sparc -Y P,/usr/lib %{shared:-shared} \
%{!shared: \
%{!ibcs: \
%{!static: \
%{rdynamic:-export-dynamic} \
- %{!dynamic-linker:-dynamic-linker /lib/ld-linux.so.2}} \
+ %{!dynamic-linker:-dynamic-linker " LINUX_DYNAMIC_LINKER32 "}} \
%{static:-static}}} \
"
@@ -181,7 +181,7 @@ Boston, MA 02111-1307, USA. */
%{!ibcs: \
%{!static: \
%{rdynamic:-export-dynamic} \
- %{!dynamic-linker:-dynamic-linker /lib64/ld-linux.so.2}} \
+ %{!dynamic-linker:-dynamic-linker " LINUX_DYNAMIC_LINKER64 "}} \
%{static:-static}}} \
"
@@ -262,7 +262,7 @@ Boston, MA 02111-1307, USA. */
%{!ibcs: \
%{!static: \
%{rdynamic:-export-dynamic} \
- %{!dynamic-linker:-dynamic-linker /lib64/ld-linux.so.2}} \
+ %{!dynamic-linker:-dynamic-linker " LINUX_DYNAMIC_LINKER64 "}} \
%{static:-static}}} \
%{mlittle-endian:-EL} \
%{!mno-relax:%{!r:-relax}} \
@@ -289,9 +289,6 @@ Boston, MA 02111-1307, USA. */
#undef DBX_REGISTER_NUMBER
#define DBX_REGISTER_NUMBER(REGNO) (REGNO)
-#define DWARF2_DEBUGGING_INFO 1
-#define DBX_DEBUGGING_INFO 1
-
#undef ASM_OUTPUT_ALIGNED_LOCAL
#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \
do { \
@@ -307,13 +304,6 @@ do { \
#undef LOCAL_LABEL_PREFIX
#define LOCAL_LABEL_PREFIX "."
-/* This is how to output a reference to an internal numbered label where
- PREFIX is the class of label and NUM is the number within the class. */
-
-#undef ASM_OUTPUT_INTERNAL_LABELREF
-#define ASM_OUTPUT_INTERNAL_LABELREF(FILE,PREFIX,NUM) \
- fprintf (FILE, ".L%s%d", PREFIX, NUM)
-
/* This is how to store into the string LABEL
the symbol_ref name of an internal numbered label where
PREFIX is the class of label and NUM is the number within the class.
@@ -353,133 +343,37 @@ do { \
#undef CTORS_SECTION_ASM_OP
#undef DTORS_SECTION_ASM_OP
-#define TARGET_ASM_FILE_END file_end_indicate_exec_stack
-
-/* Determine whether the the entire c99 runtime is present in the
+/* Determine whether the entire c99 runtime is present in the
runtime library. */
-#define TARGET_C99_FUNCTIONS 1
+#define TARGET_C99_FUNCTIONS (OPTION_GLIBC)
-#define TARGET_HAS_F_SETLKW
+#define TARGET_POSIX_IO
#undef LINK_GCC_C_SEQUENCE_SPEC
#define LINK_GCC_C_SEQUENCE_SPEC \
"%{static:--start-group} %G %L %{static:--end-group}%{!static:%G}"
-/* Do code reading to identify a signal frame, and set the frame
- state data appropriately. See unwind-dw2.c for the structs. */
-
-/* Handle multilib correctly. */
-#if defined(__arch64__)
-/* 64-bit SPARC version */
-#define MD_FALLBACK_FRAME_STATE_FOR(CONTEXT, FS, SUCCESS) \
- do { \
- unsigned int *pc_ = (CONTEXT)->ra; \
- long new_cfa_, i_; \
- long regs_off_, fpu_save_off_; \
- long this_cfa_, fpu_save_; \
- \
- if (pc_[0] != 0x82102065 /* mov NR_rt_sigreturn, %g1 */ \
- || pc_[1] != 0x91d0206d) /* ta 0x6d */ \
- break; \
- regs_off_ = 192 + 128; \
- fpu_save_off_ = regs_off_ + (16 * 8) + (3 * 8) + (2 * 4); \
- this_cfa_ = (long) (CONTEXT)->cfa; \
- new_cfa_ = *(long *)(((CONTEXT)->cfa) + (regs_off_ + (14 * 8))); \
- new_cfa_ += 2047; /* Stack bias */ \
- fpu_save_ = *(long *)((this_cfa_) + (fpu_save_off_)); \
- (FS)->cfa_how = CFA_REG_OFFSET; \
- (FS)->cfa_reg = 14; \
- (FS)->cfa_offset = new_cfa_ - (long) (CONTEXT)->cfa; \
- for (i_ = 1; i_ < 16; ++i_) \
- { \
- (FS)->regs.reg[i_].how = REG_SAVED_OFFSET; \
- (FS)->regs.reg[i_].loc.offset = \
- this_cfa_ + (regs_off_ + (i_ * 8)) - new_cfa_; \
- } \
- for (i_ = 0; i_ < 16; ++i_) \
- { \
- (FS)->regs.reg[i_ + 16].how = REG_SAVED_OFFSET; \
- (FS)->regs.reg[i_ + 16].loc.offset = \
- this_cfa_ + (i_ * 8) - new_cfa_; \
- } \
- if (fpu_save_) \
- { \
- for (i_ = 0; i_ < 64; ++i_) \
- { \
- if (i_ > 32 && (i_ & 0x1)) \
- continue; \
- (FS)->regs.reg[i_ + 32].how = REG_SAVED_OFFSET; \
- (FS)->regs.reg[i_ + 32].loc.offset = \
- (fpu_save_ + (i_ * 4)) - new_cfa_; \
- } \
- } \
- /* Stick return address into %g0, same trick Alpha uses. */ \
- (FS)->regs.reg[0].how = REG_SAVED_OFFSET; \
- (FS)->regs.reg[0].loc.offset = \
- this_cfa_ + (regs_off_ + (16 * 8) + 8) - new_cfa_; \
- (FS)->retaddr_column = 0; \
- goto SUCCESS; \
- } while (0)
-#else
-/* 32-bit SPARC version */
-#define MD_FALLBACK_FRAME_STATE_FOR(CONTEXT, FS, SUCCESS) \
- do { \
- unsigned int *pc_ = (CONTEXT)->ra; \
- int new_cfa_, i_, oldstyle_; \
- int regs_off_, fpu_save_off_; \
- int fpu_save_, this_cfa_; \
- \
- if (pc_[1] != 0x91d02010) /* ta 0x10 */ \
- break; \
- if (pc_[0] == 0x821020d8) /* mov NR_sigreturn, %g1 */ \
- oldstyle_ = 1; \
- else if (pc_[0] == 0x82102065) /* mov NR_rt_sigreturn, %g1 */ \
- oldstyle_ = 0; \
- else \
- break; \
- if (oldstyle_) \
- { \
- regs_off_ = 96; \
- fpu_save_off_ = regs_off_ + (4 * 4) + (16 * 4); \
- } \
- else \
- { \
- regs_off_ = 96 + 128; \
- fpu_save_off_ = regs_off_ + (4 * 4) + (16 * 4) + (2 * 4); \
- } \
- this_cfa_ = (int) (CONTEXT)->cfa; \
- new_cfa_ = *(int *)(((CONTEXT)->cfa) + (regs_off_+(4*4)+(14 * 4))); \
- fpu_save_ = *(int *)((this_cfa_) + (fpu_save_off_)); \
- (FS)->cfa_how = CFA_REG_OFFSET; \
- (FS)->cfa_reg = 14; \
- (FS)->cfa_offset = new_cfa_ - (int) (CONTEXT)->cfa; \
- for (i_ = 1; i_ < 16; ++i_) \
- { \
- if (i_ == 14) \
- continue; \
- (FS)->regs.reg[i_].how = REG_SAVED_OFFSET; \
- (FS)->regs.reg[i_].loc.offset = \
- this_cfa_ + (regs_off_+(4 * 4)+(i_ * 4)) - new_cfa_; \
- } \
- for (i_ = 0; i_ < 16; ++i_) \
- { \
- (FS)->regs.reg[i_ + 16].how = REG_SAVED_OFFSET; \
- (FS)->regs.reg[i_ + 16].loc.offset = \
- this_cfa_ + (i_ * 4) - new_cfa_; \
- } \
- if (fpu_save_) \
- { \
- for (i_ = 0; i_ < 32; ++i_) \
- { \
- (FS)->regs.reg[i_ + 32].how = REG_SAVED_OFFSET; \
- (FS)->regs.reg[i_ + 32].loc.offset = \
- (fpu_save_ + (i_ * 4)) - new_cfa_; \
- } \
- } \
- /* Stick return address into %g0, same trick Alpha uses. */ \
- (FS)->regs.reg[0].how = REG_SAVED_OFFSET; \
- (FS)->regs.reg[0].loc.offset = this_cfa_+(regs_off_+4)-new_cfa_; \
- (FS)->retaddr_column = 0; \
- goto SUCCESS; \
- } while (0)
+/* Use --as-needed -lgcc_s for eh support. */
+#ifdef HAVE_LD_AS_NEEDED
+#define USE_LD_AS_NEEDED 1
#endif
+
+#define MD_UNWIND_SUPPORT "config/sparc/linux-unwind.h"
+
+/* Linux currently uses RMO in uniprocessor mode, which is equivalent to
+ TMO, and TMO in multiprocessor mode. But they reserve the right to
+ change their minds. */
+#undef SPARC_RELAXED_ORDERING
+#define SPARC_RELAXED_ORDERING true
+
+#undef NEED_INDICATE_EXEC_STACK
+#define NEED_INDICATE_EXEC_STACK 1
+
+#ifdef TARGET_LIBC_PROVIDES_SSP
+/* sparc glibc provides __stack_chk_guard in [%g7 + 0x14],
+ sparc64 glibc provides it at [%g7 + 0x28]. */
+#define TARGET_THREAD_SSP_OFFSET (TARGET_ARCH64 ? 0x28 : 0x14)
+#endif
+
+/* Define if long doubles should be mangled as 'g'. */
+#define TARGET_ALTERNATE_LONG_DOUBLE_MANGLING
diff --git a/contrib/gcc/config/sparc/little-endian.opt b/contrib/gcc/config/sparc/little-endian.opt
new file mode 100644
index 0000000..eb039fd
--- /dev/null
+++ b/contrib/gcc/config/sparc/little-endian.opt
@@ -0,0 +1,28 @@
+; Options for the SPARC port of the compiler
+;
+; Copyright (C) 2005 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.
+
+mlittle-endian
+Target Report RejectNegative Mask(LITTLE_ENDIAN) MaskExists
+Generate code for little-endian
+
+mbig-endian
+Target Report RejectNegative InverseMask(LITTLE_ENDIAN)
+Generate code for big-endian
diff --git a/contrib/gcc/config/sparc/long-double-switch.opt b/contrib/gcc/config/sparc/long-double-switch.opt
new file mode 100644
index 0000000..ffbecbe
--- /dev/null
+++ b/contrib/gcc/config/sparc/long-double-switch.opt
@@ -0,0 +1,28 @@
+; Options for the SPARC port of the compiler
+;
+; Copyright (C) 2005 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.
+
+mlong-double-128
+Target Report RejectNegative Mask(LONG_DOUBLE_128) MaskExists
+Use 128-bit long double
+
+mlong-double-64
+Target Report RejectNegative InverseMask(LONG_DOUBLE_128)
+Use 64-bit long double
diff --git a/contrib/gcc/config/sparc/netbsd-elf.h b/contrib/gcc/config/sparc/netbsd-elf.h
index bc92eb2..b07fee3 100644
--- a/contrib/gcc/config/sparc/netbsd-elf.h
+++ b/contrib/gcc/config/sparc/netbsd-elf.h
@@ -1,6 +1,6 @@
/* Definitions of target machine for GCC, for ELF on NetBSD/sparc
and NetBSD/sparc64.
- Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
Contributed by Matthew Green (mrg@eterna.com.au).
This file is part of GCC.
@@ -17,8 +17,8 @@ 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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
#define TARGET_OS_CPP_BUILTINS() \
do \
@@ -51,28 +51,14 @@ Boston, MA 02111-1307, USA. */
#undef PTRDIFF_TYPE
#define PTRDIFF_TYPE "long int"
-#undef PREFERRED_DEBUGGING_TYPE
-#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
-
/* This is the char to use for continuation (in case we need to turn
continuation back on). */
#undef DBX_CONTIN_CHAR
#define DBX_CONTIN_CHAR '?'
-#undef DBX_REGISTER_NUMBER
-#define DBX_REGISTER_NUMBER(REGNO) \
- (TARGET_FLAT && REGNO == HARD_FRAME_POINTER_REGNUM ? 31 : REGNO)
-
#undef LOCAL_LABEL_PREFIX
#define LOCAL_LABEL_PREFIX "."
-/* This is how to output a reference to an internal numbered label where
- PREFIX is the class of label and NUM is the number within the class. */
-
-#undef ASM_OUTPUT_INTERNAL_LABELREF
-#define ASM_OUTPUT_INTERNAL_LABELREF(FILE,PREFIX,NUM) \
- fprintf (FILE, ".L%s%d", PREFIX, NUM)
-
/* This is how to store into the string LABEL
the symbol_ref name of an internal numbered label where
PREFIX is the class of label and NUM is the number within the class.
@@ -209,13 +195,6 @@ Boston, MA 02111-1307, USA. */
{ "netbsd_entry_point", NETBSD_ENTRY_POINT },
-/* What extra switches do we need? */
-#undef SUBTARGET_SWITCHES
-#define SUBTARGET_SWITCHES \
- {"long-double-64", -MASK_LONG_DOUBLE_128, N_("Use 64 bit long doubles") }, \
- {"long-double-128", MASK_LONG_DOUBLE_128, N_("Use 128 bit long doubles") },
-
-
/* Build a compiler that supports -m32 and -m64? */
#ifdef SPARC_BI_ARCH
@@ -223,9 +202,6 @@ Boston, MA 02111-1307, USA. */
#undef LONG_DOUBLE_TYPE_SIZE
#define LONG_DOUBLE_TYPE_SIZE (TARGET_LONG_DOUBLE_128 ? 128 : 64)
-#undef MAX_LONG_DOUBLE_TYPE_SIZE
-#define MAX_LONG_DOUBLE_TYPE_SIZE 128
-
#if defined(__arch64__) || defined(__LONG_DOUBLE_128__)
#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE 128
#else
@@ -245,7 +221,7 @@ Boston, MA 02111-1307, USA. */
#define MULTILIB_DEFAULTS { "m64" }
#endif
-/* Name the port. */
+/* Name the port. */
#undef TARGET_NAME
#define TARGET_NAME (DEFAULT_ARCH32_P ? TARGET_NAME32 : TARGET_NAME64)
@@ -257,9 +233,6 @@ Boston, MA 02111-1307, USA. */
#undef LONG_DOUBLE_TYPE_SIZE
#define LONG_DOUBLE_TYPE_SIZE 128
-#undef MAX_LONG_DOUBLE_TYPE_SIZE
-#define MAX_LONG_DOUBLE_TYPE_SIZE 128
-
#undef LIBGCC2_LONG_DOUBLE_TYPE_SIZE
#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE 128
@@ -278,9 +251,6 @@ Boston, MA 02111-1307, USA. */
#undef LONG_DOUBLE_TYPE_SIZE
#define LONG_DOUBLE_TYPE_SIZE 64
-#undef MAX_LONG_DOUBLE_TYPE_SIZE
-#define MAX_LONG_DOUBLE_TYPE_SIZE 64
-
#undef LIBGCC2_LONG_DOUBLE_TYPE_SIZE
#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE 64
diff --git a/contrib/gcc/config/sparc/niagara.md b/contrib/gcc/config/sparc/niagara.md
new file mode 100644
index 0000000..ea431b5
--- /dev/null
+++ b/contrib/gcc/config/sparc/niagara.md
@@ -0,0 +1,119 @@
+;; Scheduling description for Niagara.
+;; Copyright (C) 2006 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.
+
+;; Niagara is a single-issue processor.
+
+(define_automaton "niagara_0")
+
+(define_cpu_unit "niag_pipe" "niagara_0")
+
+(define_insn_reservation "niag_5cycle" 5
+ (and (eq_attr "cpu" "niagara")
+ (eq_attr "type" "multi,flushw,iflush,trap"))
+ "niag_pipe*5")
+
+(define_insn_reservation "niag_4cycle" 4
+ (and (eq_attr "cpu" "niagara")
+ (eq_attr "type" "savew"))
+ "niag_pipe*4")
+
+/* Most basic operations are single-cycle. */
+(define_insn_reservation "niag_ialu" 1
+ (and (eq_attr "cpu" "niagara")
+ (eq_attr "type" "ialu,shift,compare,cmove"))
+ "niag_pipe")
+
+(define_insn_reservation "niag_imul" 11
+ (and (eq_attr "cpu" "niagara")
+ (eq_attr "type" "imul"))
+ "niag_pipe*11")
+
+(define_insn_reservation "niag_idiv" 72
+ (and (eq_attr "cpu" "niagara")
+ (eq_attr "type" "idiv"))
+ "niag_pipe*72")
+
+(define_insn_reservation "niag_branch" 3
+ (and (eq_attr "cpu" "niagara")
+ (eq_attr "type" "call,sibcall,call_no_delay_slot,uncond_branch,branch"))
+ "niag_pipe*3")
+
+(define_insn_reservation "niag_3cycle_load" 3
+ (and (eq_attr "cpu" "niagara")
+ (eq_attr "type" "load"))
+ "niag_pipe*3")
+
+(define_insn_reservation "niag_9cycle_load" 9
+ (and (eq_attr "cpu" "niagara")
+ (eq_attr "type" "fpload"))
+ "niag_pipe*9")
+
+(define_insn_reservation "niag_1cycle_store" 1
+ (and (eq_attr "cpu" "niagara")
+ (eq_attr "type" "store"))
+ "niag_pipe")
+
+(define_insn_reservation "niag_8cycle_store" 8
+ (and (eq_attr "cpu" "niagara")
+ (eq_attr "type" "fpstore"))
+ "niag_pipe*8")
+
+/* Things incorrectly modelled here:
+ * FPADD{s,d}: 26 cycles
+ * FPSUB{s,d}: 26 cycles
+ * FABSD: 26 cycles
+ * F{s,d}TO{s,d}: 26 cycles
+ * F{s,d}TO{i,x}: 26 cycles
+ * FSMULD: 29 cycles
+ */
+(define_insn_reservation "niag_fmov" 8
+ (and (eq_attr "cpu" "niagara")
+ (eq_attr "type" "fpmove,fpcmove,fpcrmove"))
+ "niag_pipe*8")
+
+(define_insn_reservation "niag_fpcmp" 26
+ (and (eq_attr "cpu" "niagara")
+ (eq_attr "type" "fpcmp"))
+ "niag_pipe*26")
+
+(define_insn_reservation "niag_fmult" 29
+ (and (eq_attr "cpu" "niagara")
+ (eq_attr "type" "fpmul"))
+ "niag_pipe*29")
+
+(define_insn_reservation "niag_fdivs" 54
+ (and (eq_attr "cpu" "niagara")
+ (eq_attr "type" "fpdivs"))
+ "niag_pipe*54")
+
+(define_insn_reservation "niag_fdivd" 83
+ (and (eq_attr "cpu" "niagara")
+ (eq_attr "type" "fpdivd"))
+ "niag_pipe*83")
+
+/* Things incorrectly modelled here:
+ * FPADD{16,32}: 10 cycles
+ * FPSUB{16,32}: 10 cycles
+ * FALIGNDATA: 10 cycles
+ */
+(define_insn_reservation "niag_vis" 8
+ (and (eq_attr "cpu" "niagara")
+ (eq_attr "type" "fga,fgm_pack,fgm_mul,fgm_cmp,fgm_pdist"))
+ "niag_pipe*8")
diff --git a/contrib/gcc/config/sparc/openbsd1-64.h b/contrib/gcc/config/sparc/openbsd1-64.h
index 1310538..4af8c44 100644
--- a/contrib/gcc/config/sparc/openbsd1-64.h
+++ b/contrib/gcc/config/sparc/openbsd1-64.h
@@ -15,8 +15,8 @@ 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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
#define OBSD_HAS_DECLARE_FUNCTION_NAME
#define OBSD_HAS_DECLARE_FUNCTION_SIZE
diff --git a/contrib/gcc/config/sparc/openbsd64.h b/contrib/gcc/config/sparc/openbsd64.h
index e13c886..49f8d28 100644
--- a/contrib/gcc/config/sparc/openbsd64.h
+++ b/contrib/gcc/config/sparc/openbsd64.h
@@ -1,5 +1,5 @@
/* Configuration file for sparc64 OpenBSD target.
- Copyright (C) 1999 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2005 Free Software Foundation, Inc.
This file is part of GCC.
@@ -15,8 +15,8 @@ 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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
#undef TARGET_VERSION
#define TARGET_VERSION fprintf (stderr, " (sparc64 OpenBSD ELF)")
@@ -51,6 +51,9 @@ Boston, MA 02111-1307, USA. */
#undef MD_EXEC_PREFIX
#undef MD_STARTFILE_PREFIX
+/* Inherited from sp64-elf. */
+#undef NO_IMPLICIT_EXTERN_C
+
#undef ASM_SPEC
#define ASM_SPEC "\
%{v:-V} -s %{fpic|fPIC|fpie|fPIE:-K PIC} \
diff --git a/contrib/gcc/config/sparc/predicates.md b/contrib/gcc/config/sparc/predicates.md
new file mode 100644
index 0000000..048d651
--- /dev/null
+++ b/contrib/gcc/config/sparc/predicates.md
@@ -0,0 +1,478 @@
+;; Predicate definitions for SPARC.
+;; Copyright (C) 2005 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.
+
+;; Predicates for numerical constants.
+
+;; Return true if OP is the zero constant for MODE.
+(define_predicate "const_zero_operand"
+ (and (match_code "const_int,const_double,const_vector")
+ (match_test "op == CONST0_RTX (mode)")))
+
+;; Return true if OP is the one constant for MODE.
+(define_predicate "const_one_operand"
+ (and (match_code "const_int,const_double,const_vector")
+ (match_test "op == CONST1_RTX (mode)")))
+
+;; Return true if OP is the integer constant 4096.
+(define_predicate "const_4096_operand"
+ (and (match_code "const_int")
+ (match_test "INTVAL (op) == 4096")))
+
+;; Return true if OP is a constant that is representable by a 13-bit
+;; signed field. This is an acceptable immediate operand for most
+;; 3-address instructions.
+(define_predicate "small_int_operand"
+ (and (match_code "const_int")
+ (match_test "SPARC_SIMM13_P (INTVAL (op))")))
+
+;; Return true if OP is a constant operand for the umul instruction. That
+;; instruction sign-extends immediate values just like all other SPARC
+;; instructions, but interprets the extended result as an unsigned number.
+(define_predicate "uns_small_int_operand"
+ (match_code "const_int,const_double")
+{
+#if HOST_BITS_PER_WIDE_INT == 32
+ return ((GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 0x1000)
+ || (GET_CODE (op) == CONST_DOUBLE
+ && CONST_DOUBLE_HIGH (op) == 0
+ && (unsigned) CONST_DOUBLE_LOW (op) - 0xFFFFF000 < 0x1000));
+#else
+ return (GET_CODE (op) == CONST_INT
+ && ((INTVAL (op) >= 0 && INTVAL (op) < 0x1000)
+ || (INTVAL (op) >= 0xFFFFF000
+ && INTVAL (op) <= 0xFFFFFFFF)));
+#endif
+})
+
+;; Return true if OP is a constant that can be loaded by the sethi instruction.
+;; The first test avoids emitting sethi to load zero for example.
+(define_predicate "const_high_operand"
+ (and (match_code "const_int")
+ (and (not (match_operand 0 "small_int_operand"))
+ (match_test "SPARC_SETHI_P (INTVAL (op) & GET_MODE_MASK (mode))"))))
+
+;; Return true if OP is a constant whose 1's complement can be loaded by the
+;; sethi instruction.
+(define_predicate "const_compl_high_operand"
+ (and (match_code "const_int")
+ (and (not (match_operand 0 "small_int_operand"))
+ (match_test "SPARC_SETHI_P (~INTVAL (op) & GET_MODE_MASK (mode))"))))
+
+;; Return true if OP is a FP constant that needs to be loaded by the sethi/losum
+;; pair of instructions.
+(define_predicate "fp_const_high_losum_operand"
+ (match_operand 0 "const_double_operand")
+{
+ gcc_assert (mode == SFmode);
+ return fp_high_losum_p (op);
+})
+
+
+;; Predicates for symbolic constants.
+
+;; Return true if OP is either a symbol reference or a sum of a symbol
+;; reference and a constant.
+(define_predicate "symbolic_operand"
+ (match_code "symbol_ref,label_ref,const")
+{
+ enum machine_mode omode = GET_MODE (op);
+
+ if (omode != mode && omode != VOIDmode && mode != VOIDmode)
+ return false;
+
+ switch (GET_CODE (op))
+ {
+ case SYMBOL_REF:
+ return !SYMBOL_REF_TLS_MODEL (op);
+
+ case LABEL_REF:
+ return true;
+
+ case CONST:
+ op = XEXP (op, 0);
+ return (((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
+ && !SYMBOL_REF_TLS_MODEL (XEXP (op, 0)))
+ || GET_CODE (XEXP (op, 0)) == LABEL_REF)
+ && GET_CODE (XEXP (op, 1)) == CONST_INT);
+
+ default:
+ gcc_unreachable ();
+ }
+})
+
+;; Return true if OP is a symbolic operand for the TLS Global Dynamic model.
+(define_predicate "tgd_symbolic_operand"
+ (and (match_code "symbol_ref")
+ (match_test "SYMBOL_REF_TLS_MODEL (op) == TLS_MODEL_GLOBAL_DYNAMIC")))
+
+;; Return true if OP is a symbolic operand for the TLS Local Dynamic model.
+(define_predicate "tld_symbolic_operand"
+ (and (match_code "symbol_ref")
+ (match_test "SYMBOL_REF_TLS_MODEL (op) == TLS_MODEL_LOCAL_DYNAMIC")))
+
+;; Return true if OP is a symbolic operand for the TLS Initial Exec model.
+(define_predicate "tie_symbolic_operand"
+ (and (match_code "symbol_ref")
+ (match_test "SYMBOL_REF_TLS_MODEL (op) == TLS_MODEL_INITIAL_EXEC")))
+
+;; Return true if OP is a symbolic operand for the TLS Local Exec model.
+(define_predicate "tle_symbolic_operand"
+ (and (match_code "symbol_ref")
+ (match_test "SYMBOL_REF_TLS_MODEL (op) == TLS_MODEL_LOCAL_EXEC")))
+
+;; Return true if the operand is an argument used in generating PIC references
+;; in either the medium/low or embedded medium/anywhere code models on V9.
+;; Check for (const (minus (symbol_ref:GOT)
+;; (const (minus (label) (pc)))))
+(define_predicate "medium_pic_operand"
+ (match_code "const")
+{
+ /* Check for (const (minus (symbol_ref:GOT)
+ (const (minus (label) (pc))))). */
+ op = XEXP (op, 0);
+ return GET_CODE (op) == MINUS
+ && GET_CODE (XEXP (op, 0)) == SYMBOL_REF
+ && GET_CODE (XEXP (op, 1)) == CONST
+ && GET_CODE (XEXP (XEXP (op, 1), 0)) == MINUS;
+})
+
+;; Return true if OP is a LABEL_REF of mode MODE.
+(define_predicate "label_ref_operand"
+ (and (match_code "label_ref")
+ (match_test "GET_MODE (op) == mode")))
+
+;; Return true if OP is a data segment reference. This includes the readonly
+;; data segment or, in other words, anything but the text segment.
+;; This is needed in the embedded medium/anywhere code model on V9. These
+;; values are accessed with EMBMEDANY_BASE_REG. */
+(define_predicate "data_segment_operand"
+ (match_code "symbol_ref,plus,const")
+{
+ switch (GET_CODE (op))
+ {
+ case SYMBOL_REF :
+ return ! SYMBOL_REF_FUNCTION_P (op);
+ case PLUS :
+ /* Assume canonical format of symbol + constant.
+ Fall through. */
+ case CONST :
+ return data_segment_operand (XEXP (op, 0), VOIDmode);
+ default :
+ gcc_unreachable ();
+ }
+})
+
+;; Return true if OP is a text segment reference.
+;; This is needed in the embedded medium/anywhere code model on V9.
+(define_predicate "text_segment_operand"
+ (match_code "label_ref,symbol_ref,plus,const")
+{
+ switch (GET_CODE (op))
+ {
+ case LABEL_REF :
+ return true;
+ case SYMBOL_REF :
+ return SYMBOL_REF_FUNCTION_P (op);
+ case PLUS :
+ /* Assume canonical format of symbol + constant.
+ Fall through. */
+ case CONST :
+ return text_segment_operand (XEXP (op, 0), VOIDmode);
+ default :
+ gcc_unreachable ();
+ }
+})
+
+
+;; Predicates for registers.
+
+;; Return true if OP is either the zero constant or a register.
+(define_predicate "register_or_zero_operand"
+ (ior (match_operand 0 "register_operand")
+ (match_operand 0 "const_zero_operand")))
+
+;; Return true if OP is a register operand in a floating point register.
+(define_predicate "fp_register_operand"
+ (match_operand 0 "register_operand")
+{
+ if (GET_CODE (op) == SUBREG)
+ op = SUBREG_REG (op); /* Possibly a MEM */
+ return REG_P (op) && SPARC_FP_REG_P (REGNO (op));
+})
+
+;; Return true if OP is an integer register.
+(define_special_predicate "int_register_operand"
+ (ior (match_test "register_operand (op, SImode)")
+ (match_test "TARGET_ARCH64 && register_operand (op, DImode)")))
+
+;; Return true if OP is a floating point condition code register.
+(define_predicate "fcc_register_operand"
+ (match_code "reg")
+{
+ if (mode != VOIDmode && mode != GET_MODE (op))
+ return false;
+ if (mode == VOIDmode
+ && (GET_MODE (op) != CCFPmode && GET_MODE (op) != CCFPEmode))
+ return false;
+
+#if 0 /* ??? 1 when %fcc0-3 are pseudos first. See gen_compare_reg(). */
+ if (reg_renumber == 0)
+ return REGNO (op) >= FIRST_PSEUDO_REGISTER;
+ return REGNO_OK_FOR_CCFP_P (REGNO (op));
+#else
+ return ((unsigned) REGNO (op) - SPARC_FIRST_V9_FCC_REG) < 4;
+#endif
+})
+
+;; Return true if OP is the floating point condition code register fcc0.
+(define_predicate "fcc0_register_operand"
+ (match_code "reg")
+{
+ if (mode != VOIDmode && mode != GET_MODE (op))
+ return false;
+ if (mode == VOIDmode
+ && (GET_MODE (op) != CCFPmode && GET_MODE (op) != CCFPEmode))
+ return false;
+
+ return REGNO (op) == SPARC_FCC_REG;
+})
+
+;; Return true if OP is an integer or floating point condition code register.
+(define_predicate "icc_or_fcc_register_operand"
+ (match_code "reg")
+{
+ if (REGNO (op) == SPARC_ICC_REG)
+ {
+ if (mode != VOIDmode && mode != GET_MODE (op))
+ return false;
+ if (mode == VOIDmode
+ && GET_MODE (op) != CCmode && GET_MODE (op) != CCXmode)
+ return false;
+
+ return true;
+ }
+
+ return fcc_register_operand (op, mode);
+})
+
+
+;; Predicates for arithmetic instructions.
+
+;; Return true if OP is a register, or is a constant that is representable
+;; by a 13-bit signed field. This is an acceptable operand for most
+;; 3-address instructions.
+(define_predicate "arith_operand"
+ (ior (match_operand 0 "register_operand")
+ (match_operand 0 "small_int_operand")))
+
+;; 64-bit: Same as above.
+;; 32-bit: Return true if OP is a register, or is a constant that is
+;; representable by a couple of 13-bit signed fields. This is an
+;; acceptable operand for most 3-address splitters.
+(define_predicate "arith_double_operand"
+ (match_code "const_int,const_double,reg,subreg")
+{
+ bool arith_simple_operand = arith_operand (op, mode);
+ HOST_WIDE_INT m1, m2;
+
+ if (TARGET_ARCH64 || arith_simple_operand)
+ return arith_simple_operand;
+
+#if HOST_BITS_PER_WIDE_INT == 32
+ if (GET_CODE (op) != CONST_DOUBLE)
+ return false;
+ m1 = CONST_DOUBLE_LOW (op);
+ m2 = CONST_DOUBLE_HIGH (op);
+#else
+ if (GET_CODE (op) != CONST_INT)
+ return false;
+ m1 = trunc_int_for_mode (INTVAL (op), SImode);
+ m2 = trunc_int_for_mode (INTVAL (op) >> 32, SImode);
+#endif
+
+ return SPARC_SIMM13_P (m1) && SPARC_SIMM13_P (m2);
+})
+
+;; Return true if OP is suitable as second operand for add/sub.
+(define_predicate "arith_add_operand"
+ (ior (match_operand 0 "arith_operand")
+ (match_operand 0 "const_4096_operand")))
+
+;; Return true if OP is suitable as second double operand for add/sub.
+(define_predicate "arith_double_add_operand"
+ (match_code "const_int,const_double,reg,subreg")
+{
+ bool _arith_double_operand = arith_double_operand (op, mode);
+
+ if (_arith_double_operand)
+ return true;
+
+ return TARGET_ARCH64 && const_4096_operand (op, mode);
+})
+
+;; Return true if OP is a register, or is a CONST_INT that can fit in a
+;; signed 10-bit immediate field. This is an acceptable SImode operand for
+;; the movrcc instructions.
+(define_predicate "arith10_operand"
+ (ior (match_operand 0 "register_operand")
+ (and (match_code "const_int")
+ (match_test "SPARC_SIMM10_P (INTVAL (op))"))))
+
+;; Return true if OP is a register, or is a CONST_INT that can fit in a
+;; signed 11-bit immediate field. This is an acceptable SImode operand for
+;; the movcc instructions.
+(define_predicate "arith11_operand"
+ (ior (match_operand 0 "register_operand")
+ (and (match_code "const_int")
+ (match_test "SPARC_SIMM11_P (INTVAL (op))"))))
+
+;; Return true if OP is a register or a constant for the umul instruction.
+(define_predicate "uns_arith_operand"
+ (ior (match_operand 0 "register_operand")
+ (match_operand 0 "uns_small_int_operand")))
+
+
+;; Predicates for miscellaneous instructions.
+
+;; Return true if OP is valid for the lhs of a comparison insn.
+(define_predicate "compare_operand"
+ (match_code "reg,subreg,zero_extract")
+{
+ if (GET_CODE (op) == ZERO_EXTRACT)
+ return (register_operand (XEXP (op, 0), mode)
+ && small_int_operand (XEXP (op, 1), mode)
+ && small_int_operand (XEXP (op, 2), mode)
+ /* This matches cmp_zero_extract. */
+ && ((mode == SImode
+ && INTVAL (XEXP (op, 2)) > 19)
+ /* This matches cmp_zero_extract_sp64. */
+ || (TARGET_ARCH64
+ && mode == DImode
+ && INTVAL (XEXP (op, 2)) > 51)));
+ else
+ return register_operand (op, mode);
+})
+
+;; Return true if OP is a valid operand for the source of a move insn.
+(define_predicate "input_operand"
+ (match_code "const_int,const_double,const_vector,reg,subreg,mem")
+{
+ enum mode_class mclass;
+
+ /* If both modes are non-void they must be the same. */
+ if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
+ return false;
+
+ mclass = GET_MODE_CLASS (mode);
+
+ /* Allow any 1-instruction integer constant. */
+ if (mclass == MODE_INT
+ && (small_int_operand (op, mode) || const_high_operand (op, mode)))
+ return true;
+
+ /* If 32-bit mode and this is a DImode constant, allow it
+ so that the splits can be generated. */
+ if (TARGET_ARCH32
+ && mode == DImode
+ && (GET_CODE (op) == CONST_DOUBLE || GET_CODE (op) == CONST_INT))
+ return true;
+
+ if ((mclass == MODE_FLOAT && GET_CODE (op) == CONST_DOUBLE)
+ || (mclass == MODE_VECTOR_INT && GET_CODE (op) == CONST_VECTOR))
+ return true;
+
+ if (register_operand (op, mode))
+ return true;
+
+ /* If this is a SUBREG, look inside so that we handle paradoxical ones. */
+ if (GET_CODE (op) == SUBREG)
+ op = SUBREG_REG (op);
+
+ /* Check for valid MEM forms. */
+ if (GET_CODE (op) == MEM)
+ return memory_address_p (mode, XEXP (op, 0));
+
+ return false;
+})
+
+;; Return true if OP is an address suitable for a call insn.
+;; Call insn on SPARC can take a PC-relative constant address
+;; or any regular memory address.
+(define_predicate "call_address_operand"
+ (ior (match_operand 0 "symbolic_operand")
+ (match_test "memory_address_p (Pmode, op)")))
+
+;; Return true if OP is an operand suitable for a call insn.
+(define_predicate "call_operand"
+ (and (match_code "mem")
+ (match_test "call_address_operand (XEXP (op, 0), mode)")))
+
+
+;; Predicates for operators.
+
+;; Return true if OP is a comparison operator. This allows the use of
+;; MATCH_OPERATOR to recognize all the branch insns.
+(define_predicate "noov_compare_operator"
+ (match_code "ne,eq,ge,gt,le,lt,geu,gtu,leu,ltu")
+{
+ enum rtx_code code = GET_CODE (op);
+ if (GET_MODE (XEXP (op, 0)) == CC_NOOVmode
+ || GET_MODE (XEXP (op, 0)) == CCX_NOOVmode)
+ /* These are the only branches which work with CC_NOOVmode. */
+ return (code == EQ || code == NE || code == GE || code == LT);
+ return true;
+})
+
+;; Return true if OP is a 64-bit comparison operator. This allows the use of
+;; MATCH_OPERATOR to recognize all the branch insns.
+(define_predicate "noov_compare64_operator"
+ (and (match_code "ne,eq,ge,gt,le,lt,geu,gtu,leu,ltu")
+ (match_test "TARGET_V9"))
+{
+ enum rtx_code code = GET_CODE (op);
+ if (GET_MODE (XEXP (op, 0)) == CCX_NOOVmode)
+ /* These are the only branches which work with CCX_NOOVmode. */
+ return (code == EQ || code == NE || code == GE || code == LT);
+ return (GET_MODE (XEXP (op, 0)) == CCXmode);
+})
+
+;; Return true if OP is a comparison operator suitable for use in V9
+;; conditional move or branch on register contents instructions.
+(define_predicate "v9_register_compare_operator"
+ (match_code "eq,ne,ge,lt,le,gt"))
+
+;; Return true if OP is an operator which can set the condition codes
+;; explicitly. We do not include PLUS and MINUS because these
+;; require CC_NOOVmode, which we handle explicitly.
+(define_predicate "cc_arith_operator"
+ (match_code "and,ior,xor"))
+
+;; Return true if OP is an operator which can bitwise complement its
+;; second operand and set the condition codes explicitly.
+;; XOR is not here because combine canonicalizes (xor (not ...) ...)
+;; and (xor ... (not ...)) to (not (xor ...)). */
+(define_predicate "cc_arith_not_operator"
+ (match_code "and,ior"))
+
+;; Return true if OP is memory operand with just [%reg] addressing mode.
+(define_predicate "memory_reg_operand"
+ (and (match_code "mem")
+ (and (match_operand 0 "memory_operand")
+ (match_test "REG_P (XEXP (op, 0))"))))
diff --git a/contrib/gcc/config/sparc/rtemself.h b/contrib/gcc/config/sparc/rtemself.h
index ffb2a72..f94b0a2 100644
--- a/contrib/gcc/config/sparc/rtemself.h
+++ b/contrib/gcc/config/sparc/rtemself.h
@@ -1,5 +1,5 @@
/* Definitions for rtems targeting a SPARC using ELF.
- Copyright (C) 1996, 1997, 2000, 2002 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 2000, 2002, 2005 Free Software Foundation, Inc.
Contributed by Joel Sherrill (joel@OARcorp.com).
This file is part of GCC.
@@ -16,16 +16,19 @@ 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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
/* Target OS builtins. */
-#define TARGET_SUB_OS_CPP_BUILTINS() \
+#undef TARGET_OS_CPP_BUILTINS
+#define TARGET_OS_CPP_BUILTINS() \
do \
{ \
- builtin_define_std ("sparc"); \
builtin_define ("__rtems__"); \
builtin_define ("__USE_INIT_FINI__"); \
builtin_assert ("system=rtems"); \
} \
while (0)
+
+/* Use the default */
+#undef LINK_GCC_C_SEQUENCE_SPEC
diff --git a/contrib/gcc/config/sparc/sol2-64.h b/contrib/gcc/config/sparc/sol2-64.h
index d53747a..d0dd284 100644
--- a/contrib/gcc/config/sparc/sol2-64.h
+++ b/contrib/gcc/config/sparc/sol2-64.h
@@ -4,13 +4,4 @@
#undef TARGET_DEFAULT
#define TARGET_DEFAULT \
(MASK_V9 + MASK_PTR64 + MASK_64BIT /* + MASK_HARD_QUAD */ + \
- MASK_STACK_BIAS + MASK_FPU + MASK_LONG_DOUBLE_128)
-
-/* Target OS builtins. */
-#undef TARGET_SUB_OS_CPP_BUILTINS
-#define TARGET_SUB_OS_CPP_BUILTINS() \
- do \
- { \
- builtin_define_std ("sparc"); \
- } \
- while (0)
+ MASK_STACK_BIAS + MASK_APP_REGS + MASK_FPU + MASK_LONG_DOUBLE_128)
diff --git a/contrib/gcc/config/sparc/sol2-bi.h b/contrib/gcc/config/sparc/sol2-bi.h
index 80ec1da..87d14f0 100644
--- a/contrib/gcc/config/sparc/sol2-bi.h
+++ b/contrib/gcc/config/sparc/sol2-bi.h
@@ -1,9 +1,11 @@
/* Definitions of target machine for GCC, for bi-arch SPARC
running Solaris 2 using the system assembler and linker. */
-/* The default code model. */
+/* The default code model used to be CM_MEDANY on Solaris
+ but even Sun eventually found it to be quite wasteful
+ and changed it to CM_MEDMID in the Studio 9 compiler. */
#undef SPARC_DEFAULT_CMODEL
-#define SPARC_DEFAULT_CMODEL CM_MEDANY
+#define SPARC_DEFAULT_CMODEL CM_MEDMID
#define AS_SPARC64_FLAG "-xarch=v9"
@@ -37,6 +39,15 @@
#define ASM_CPU64_DEFAULT_SPEC AS_SPARC64_FLAG "b"
#endif
+#if TARGET_CPU_DEFAULT == TARGET_CPU_niagara
+#undef CPP_CPU64_DEFAULT_SPEC
+#define CPP_CPU64_DEFAULT_SPEC ""
+#undef ASM_CPU32_DEFAULT_SPEC
+#define ASM_CPU32_DEFAULT_SPEC "-xarch=v8plusb"
+#undef ASM_CPU64_DEFAULT_SPEC
+#define ASM_CPU64_DEFAULT_SPEC AS_SPARC64_FLAG "b"
+#endif
+
#if DEFAULT_ARCH32_P
#define DEF_ARCH32_SPEC(__str) "%{!m64:" __str "}"
#define DEF_ARCH64_SPEC(__str) "%{m64:" __str "}"
@@ -55,7 +66,7 @@
%{mcpu=sparclite|mcpu-f930|mcpu=f934:-D__sparclite__} \
%{mcpu=v8:" DEF_ARCH32_SPEC("-D__sparcv8") "} \
%{mcpu=supersparc:-D__supersparc__ " DEF_ARCH32_SPEC("-D__sparcv8") "} \
-%{mcpu=v9|mcpu=ultrasparc|mcpu=ultrasparc3:" DEF_ARCH32_SPEC("-D__sparcv8") "} \
+%{mcpu=v9|mcpu=ultrasparc|mcpu=ultrasparc3|mcpu=niagara:" DEF_ARCH32_SPEC("-D__sparcv8") "} \
%{!mcpu*:%{!mcypress:%{!msparclite:%{!mf930:%{!mf934:%{!mv8:%{!msupersparc:%(cpp_cpu_default)}}}}}}} \
"
@@ -64,7 +75,8 @@
%{mcpu=v9:" DEF_ARCH32_SPEC("-xarch=v8plus") DEF_ARCH64_SPEC(AS_SPARC64_FLAG) "} \
%{mcpu=ultrasparc:" DEF_ARCH32_SPEC("-xarch=v8plusa") DEF_ARCH64_SPEC(AS_SPARC64_FLAG "a") "} \
%{mcpu=ultrasparc3:" DEF_ARCH32_SPEC("-xarch=v8plusb") DEF_ARCH64_SPEC(AS_SPARC64_FLAG "b") "} \
-%{!mcpu=ultrasparc3:%{!mcpu=ultrasparc:%{!mcpu=v9:%{mcpu*:" DEF_ARCH32_SPEC("-xarch=v8") DEF_ARCH64_SPEC(AS_SPARC64_FLAG) "}}}} \
+%{mcpu=niagara:" DEF_ARCH32_SPEC("-xarch=v8plusb") DEF_ARCH64_SPEC(AS_SPARC64_FLAG "b") "} \
+%{!mcpu=niagara:%{!mcpu=ultrasparc3:%{!mcpu=ultrasparc:%{!mcpu=v9:%{mcpu*:" DEF_ARCH32_SPEC("-xarch=v8") DEF_ARCH64_SPEC(AS_SPARC64_FLAG) "}}}}} \
%{!mcpu*:%(asm_cpu_default)} \
"
@@ -236,10 +248,3 @@
#else
#define MULTILIB_DEFAULTS { "m64" }
#endif
-
-#undef PREFERRED_DEBUGGING_TYPE
-#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
-
-#if defined(HAVE_AS_GDWARF2_DEBUG_FLAG) && defined(HAVE_AS_GSTABS_DEBUG_FLAG)
-# define ASM_DEBUG_SPEC "%{gstabs*:--gstabs}%{!gstabs*:%{g*:--gdwarf2}}"
-#endif
diff --git a/contrib/gcc/config/sparc/sol2-c1.asm b/contrib/gcc/config/sparc/sol2-c1.asm
index a1cc68d..fdd6e2b 100644
--- a/contrib/gcc/config/sparc/sol2-c1.asm
+++ b/contrib/gcc/config/sparc/sol2-c1.asm
@@ -23,8 +23,8 @@
!
! 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.
+! the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+! Boston, MA 02110-1301, USA.
!
! As a special exception, if you link this library with files
! compiled with GCC to produce an executable, this does not cause
diff --git a/contrib/gcc/config/sparc/sol2-ci.asm b/contrib/gcc/config/sparc/sol2-ci.asm
index 3dc793c..5726d62 100644
--- a/contrib/gcc/config/sparc/sol2-ci.asm
+++ b/contrib/gcc/config/sparc/sol2-ci.asm
@@ -23,8 +23,8 @@
!
! 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.
+! the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+! Boston, MA 02110-1301, USA.
!
! As a special exception, if you link this library with files
! compiled with GCC to produce an executable, this does not cause
diff --git a/contrib/gcc/config/sparc/sol2-cn.asm b/contrib/gcc/config/sparc/sol2-cn.asm
index 49e070f..6e2fb2c 100644
--- a/contrib/gcc/config/sparc/sol2-cn.asm
+++ b/contrib/gcc/config/sparc/sol2-cn.asm
@@ -23,8 +23,8 @@
!
! 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.
+! the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+! Boston, MA 02110-1301, USA.
!
! As a special exception, if you link this library with files
! compiled with GCC to produce an executable, this does not cause
diff --git a/contrib/gcc/config/sparc/sol2-gas-bi.h b/contrib/gcc/config/sparc/sol2-gas-bi.h
index bea2b3c..88b3954 100644
--- a/contrib/gcc/config/sparc/sol2-gas-bi.h
+++ b/contrib/gcc/config/sparc/sol2-gas-bi.h
@@ -3,9 +3,3 @@
#undef AS_SPARC64_FLAG
#define AS_SPARC64_FLAG "-TSO -64 -Av9"
-
-/* Emit a DTP-relative reference to a TLS variable. */
-#ifdef HAVE_AS_TLS
-#define ASM_OUTPUT_DWARF_DTPREL(FILE, SIZE, X) \
- sparc_output_dwarf_dtprel (FILE, SIZE, X)
-#endif
diff --git a/contrib/gcc/config/sparc/sol2-gas.h b/contrib/gcc/config/sparc/sol2-gas.h
new file mode 100644
index 0000000..942e39d
--- /dev/null
+++ b/contrib/gcc/config/sparc/sol2-gas.h
@@ -0,0 +1,13 @@
+/* Definitions of target machine for GCC, for SPARC running Solaris 2
+ using the GNU assembler. */
+
+/* Undefine this so that BNSYM/ENSYM pairs are emitted by STABS+. */
+#undef NO_DBX_BNSYM_ENSYM
+
+/* Use GNU extensions to TLS support. */
+#ifdef HAVE_AS_TLS
+#undef TARGET_SUN_TLS
+#undef TARGET_GNU_TLS
+#define TARGET_SUN_TLS 0
+#define TARGET_GNU_TLS 1
+#endif
diff --git a/contrib/gcc/config/sparc/sol2.h b/contrib/gcc/config/sparc/sol2.h
index e5ed818..d07e0c6 100644
--- a/contrib/gcc/config/sparc/sol2.h
+++ b/contrib/gcc/config/sparc/sol2.h
@@ -1,6 +1,6 @@
/* Definitions of target machine for GCC, for SPARC running Solaris 2
- Copyright 1992, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2004
- Free Software Foundation, Inc.
+ Copyright 1992, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2004, 2005,
+ 2006 Free Software Foundation, Inc.
Contributed by Ron Guilmette (rfg@netcom.com).
Additional changes by David V. Henkel-Wallace (gumby@cygnus.com).
@@ -18,8 +18,8 @@ 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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
/* Supposedly the same as vanilla sparc svr4, except for the stuff below: */
@@ -41,11 +41,17 @@ Boston, MA 02111-1307, USA. */
#define ASM_CPU_DEFAULT_SPEC "-xarch=v8plusb"
#endif
+#if TARGET_CPU_DEFAULT == TARGET_CPU_niagara
+#undef ASM_CPU_DEFAULT_SPEC
+#define ASM_CPU_DEFAULT_SPEC "-xarch=v8plusb"
+#endif
+
#undef ASM_CPU_SPEC
#define ASM_CPU_SPEC "\
%{mcpu=v9:-xarch=v8plus} \
%{mcpu=ultrasparc:-xarch=v8plusa} \
%{mcpu=ultrasparc3:-xarch=v8plusb} \
+%{mcpu=niagara:-xarch=v8plusb} \
%{!mcpu*:%(asm_cpu_default)} \
"
@@ -57,11 +63,6 @@ Boston, MA 02111-1307, USA. */
/* However it appears that Solaris 2.0 uses the same reg numbering as
the old BSD-style system did. */
-/* Same as sparc.h */
-#undef DBX_REGISTER_NUMBER
-#define DBX_REGISTER_NUMBER(REGNO) \
- (TARGET_FLAT && (REGNO) == HARD_FRAME_POINTER_REGNUM ? 31 : REGNO)
-
/* The Solaris 2 assembler uses .skip, not .zero, so put this back. */
#undef ASM_OUTPUT_SKIP
#define ASM_OUTPUT_SKIP(FILE,SIZE) \
@@ -70,13 +71,6 @@ Boston, MA 02111-1307, USA. */
#undef LOCAL_LABEL_PREFIX
#define LOCAL_LABEL_PREFIX "."
-/* This is how to output a reference to an internal numbered label where
- PREFIX is the class of label and NUM is the number within the class. */
-
-#undef ASM_OUTPUT_INTERNAL_LABELREF
-#define ASM_OUTPUT_INTERNAL_LABELREF(FILE,PREFIX,NUM) \
- fprintf (FILE, ".L%s%d", PREFIX, NUM)
-
/* This is how to store into the string LABEL
the symbol_ref name of an internal numbered label where
PREFIX is the class of label and NUM is the number within the class.
@@ -95,7 +89,7 @@ Boston, MA 02111-1307, USA. */
{ \
HOST_WIDE_INT size; \
\
- if (DECL_THREAD_LOCAL (DECL)) \
+ if (DECL_THREAD_LOCAL_P (DECL)) \
ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "tls_object"); \
else \
ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object"); \
@@ -113,12 +107,9 @@ Boston, MA 02111-1307, USA. */
} \
while (0)
-/* The Solaris assembler cannot grok r_tls_dtpoff. This is
- a kludge as ASM_OUTPUT_DWARF_DTPREL is defined in sparc.h,
- undefined here and defined again in sol2-gas-bi.h. */
-#ifdef HAVE_AS_TLS
-#undef ASM_OUTPUT_DWARF_DTPREL
-#endif
+/* The Solaris assembler cannot grok .stabd directives. */
+#undef NO_DBX_BNSYM_ENSYM
+#define NO_DBX_BNSYM_ENSYM 1
#undef ENDFILE_SPEC
@@ -137,12 +128,7 @@ Boston, MA 02111-1307, USA. */
((flag_pic || GLOBAL) ? DW_EH_PE_aligned : DW_EH_PE_absptr)
#endif
-/* The Solaris linker doesn't understand constructor priorities. */
-#undef SUPPORTS_INIT_PRIORITY
-#define SUPPORTS_INIT_PRIORITY 0
-/* ??? This does not work in SunOS 4.x, so it is not enabled in sparc.h.
- Instead, it is enabled here, because it does work under Solaris. */
/* Define for support of TFmode long double.
SPARC ABI says that long double is 4 words. */
#define LONG_DOUBLE_TYPE_SIZE 128
@@ -168,4 +154,20 @@ Boston, MA 02111-1307, USA. */
/* Solaris allows 64 bit out and global registers in 32 bit mode.
sparc_override_options will disable V8+ if not generating V9 code. */
#undef TARGET_DEFAULT
-#define TARGET_DEFAULT (MASK_V8PLUS + MASK_FPU + MASK_LONG_DOUBLE_128)
+#define TARGET_DEFAULT (MASK_V8PLUS + MASK_APP_REGS + MASK_FPU \
+ + MASK_LONG_DOUBLE_128)
+
+/* Solaris-specific #pragmas are implemented on top of attributes. Hook in
+ the bits from config/sol2.c. */
+#define SUBTARGET_INSERT_ATTRIBUTES solaris_insert_attributes
+#define SUBTARGET_ATTRIBUTE_TABLE SOLARIS_ATTRIBUTE_TABLE
+
+/* Output a simple call for .init/.fini. */
+#define ASM_OUTPUT_CALL(FILE, FN) \
+ do \
+ { \
+ fprintf (FILE, "\tcall\t"); \
+ print_operand (FILE, XEXP (DECL_RTL (FN), 0), 0); \
+ fprintf (FILE, "\n\tnop\n"); \
+ } \
+ while (0)
diff --git a/contrib/gcc/config/sparc/sp-elf.h b/contrib/gcc/config/sparc/sp-elf.h
new file mode 100644
index 0000000..ef49b82
--- /dev/null
+++ b/contrib/gcc/config/sparc/sp-elf.h
@@ -0,0 +1,80 @@
+/* Definitions of target machine for GCC,
+ for SPARC running in an embedded environment using the ELF file format.
+ Copyright (C) 2005 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 TARGET_VERSION
+#define TARGET_VERSION fprintf (stderr, " (sparc-elf)")
+
+/* Don't assume anything about the header files. */
+#define NO_IMPLICIT_EXTERN_C
+
+/* The sun bundled assembler doesn't accept -Yd, (and neither does gas).
+ It's safe to pass -s always, even if -g is not used. */
+#undef ASM_SPEC
+#define ASM_SPEC \
+ "%{v:-V} %{Qy:} %{!Qn:-Qy} %{n} %{T} %{Ym,*} %{Wa,*:%*} -s \
+ %{fpic|fpie|fPIC|fPIE:-K PIC} %(asm_cpu)"
+
+/* Use the default. */
+#undef LINK_SPEC
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC "crt0.o%s crti.o%s crtbegin.o%s"
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC \
+ "%{ffast-math|funsafe-math-optimizations:crtfastmath.o%s} \
+ crtend.o%s crtn.o%s"
+
+/* Don't set the target flags, this is done by the linker script */
+#undef LIB_SPEC
+#define LIB_SPEC ""
+
+/* This defines which switch letters take arguments.
+ It is as in svr4.h but with -R added. */
+#undef SWITCH_TAKES_ARG
+#define SWITCH_TAKES_ARG(CHAR) \
+ (DEFAULT_SWITCH_TAKES_ARG(CHAR) \
+ || (CHAR) == 'R' \
+ || (CHAR) == 'h' \
+ || (CHAR) == 'z')
+
+#undef LOCAL_LABEL_PREFIX
+#define LOCAL_LABEL_PREFIX "."
+
+/* This is how to store into the string LABEL
+ the symbol_ref name of an internal numbered label where
+ PREFIX is the class of label and NUM is the number within the class.
+ This is suitable for output with `assemble_name'. */
+
+#undef ASM_GENERATE_INTERNAL_LABEL
+#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \
+ sprintf ((LABEL), "*.L%s%ld", (PREFIX), (long)(NUM))
+
+/* ??? Inherited from sol2.h. Probably wrong. */
+#undef WCHAR_TYPE
+#define WCHAR_TYPE "long int"
+
+#undef WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE BITS_PER_WORD
+
+/* ??? until fixed. */
+#undef LONG_DOUBLE_TYPE_SIZE
+#define LONG_DOUBLE_TYPE_SIZE 64
diff --git a/contrib/gcc/config/sparc/sp64-elf.h b/contrib/gcc/config/sparc/sp64-elf.h
index 650c3ff..53f2144 100644
--- a/contrib/gcc/config/sparc/sp64-elf.h
+++ b/contrib/gcc/config/sparc/sp64-elf.h
@@ -1,5 +1,5 @@
/* Definitions of target machine for GCC, for SPARC64, ELF.
- Copyright (C) 1994, 1995, 1996, 1997, 1998, 2000
+ Copyright (C) 1994, 1995, 1996, 1997, 1998, 2000, 2004, 2005
Free Software Foundation, Inc.
Contributed by Doug Evans, dje@cygnus.com.
@@ -17,19 +17,13 @@ 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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
-
-/* ??? We're taking the scheme of including another file and then overriding
- the values we don't like a bit too far here. The alternative is to more or
- less duplicate all of svr4.h, sparc/sysv4.h, and sparc/sol2.h here
- (suitably cleaned up). */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
#undef TARGET_VERSION
#define TARGET_VERSION fprintf (stderr, " (sparc64-elf)")
/* A 64 bit v9 compiler in a Medium/Anywhere code model environment. */
-
#undef TARGET_DEFAULT
#define TARGET_DEFAULT \
(MASK_V9 + MASK_PTR64 + MASK_64BIT + MASK_HARD_QUAD \
@@ -38,14 +32,8 @@ Boston, MA 02111-1307, USA. */
#undef SPARC_DEFAULT_CMODEL
#define SPARC_DEFAULT_CMODEL CM_EMBMEDANY
-/* Target OS builtins for config/sol.h. */
-#undef TARGET_SUB_OS_CPP_BUILTINS
-#define TARGET_SUB_OS_CPP_BUILTINS() \
- do \
- { \
- builtin_define_std ("sparc"); \
- } \
- while (0)
+/* Don't assume anything about the header files. */
+#define NO_IMPLICIT_EXTERN_C
/* __svr4__ is used by the C library (FIXME) */
#undef CPP_SUBTARGET_SPEC
@@ -84,18 +72,33 @@ crtbegin.o%s \
/* Use the default (for now). */
#undef LIB_SPEC
-/* V9 chips can handle either endianness. */
-#undef SUBTARGET_SWITCHES
-#define SUBTARGET_SWITCHES \
-{"big-endian", -MASK_LITTLE_ENDIAN, N_("Generate code for big endian") }, \
-{"little-endian", MASK_LITTLE_ENDIAN, N_("Generate code for little endian") },
+/* This defines which switch letters take arguments.
+ It is as in svr4.h but with -R added. */
+#undef SWITCH_TAKES_ARG
+#define SWITCH_TAKES_ARG(CHAR) \
+ (DEFAULT_SWITCH_TAKES_ARG(CHAR) \
+ || (CHAR) == 'R' \
+ || (CHAR) == 'h' \
+ || (CHAR) == 'z')
#undef BYTES_BIG_ENDIAN
#define BYTES_BIG_ENDIAN (! TARGET_LITTLE_ENDIAN)
#undef WORDS_BIG_ENDIAN
#define WORDS_BIG_ENDIAN (! TARGET_LITTLE_ENDIAN)
-
+
+#undef LOCAL_LABEL_PREFIX
+#define LOCAL_LABEL_PREFIX "."
+
+/* This is how to store into the string LABEL
+ the symbol_ref name of an internal numbered label where
+ PREFIX is the class of label and NUM is the number within the class.
+ This is suitable for output with `assemble_name'. */
+
+#undef ASM_GENERATE_INTERNAL_LABEL
+#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \
+ sprintf ((LABEL), "*.L%s%ld", (PREFIX), (long)(NUM))
+
/* ??? This should be 32 bits for v9 but what can we do? */
#undef WCHAR_TYPE
#define WCHAR_TYPE "short unsigned int"
@@ -113,12 +116,3 @@ crtbegin.o%s \
this 0 to not confuse the branch shortening code. */
#undef JUMP_TABLES_IN_TEXT_SECTION
#define JUMP_TABLES_IN_TEXT_SECTION 0
-
-/* System V Release 4 uses DWARF debugging info.
- GDB doesn't support 64 bit stabs yet and the desired debug format is DWARF
- anyway so it is the default. */
-
-#define DBX_DEBUGGING_INFO 1
-
-#undef PREFERRED_DEBUGGING_TYPE
-#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
diff --git a/contrib/gcc/config/sparc/sparc-modes.def b/contrib/gcc/config/sparc/sparc-modes.def
index ea2a99d..5687a44 100644
--- a/contrib/gcc/config/sparc/sparc-modes.def
+++ b/contrib/gcc/config/sparc/sparc-modes.def
@@ -1,5 +1,5 @@
/* Definitions of target machine for GCC, for Sun SPARC.
- Copyright (C) 2002 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com).
64 bit SPARC V9 support by Michael Tiemann, Jim Wilson, and Doug Evans,
at Cygnus Support.
@@ -18,8 +18,8 @@ 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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
/* 128-bit floating point */
FLOAT_MODE (TF, 16, ieee_quad_format);
@@ -42,3 +42,7 @@ CC_MODE (CC_NOOV);
CC_MODE (CCX_NOOV);
CC_MODE (CCFP);
CC_MODE (CCFPE);
+
+/* Vector modes. */
+VECTOR_MODES (INT, 8); /* V8QI V4HI V2SI */
+VECTOR_MODES (INT, 4); /* V4QI V2HI */
diff --git a/contrib/gcc/config/sparc/sparc-protos.h b/contrib/gcc/config/sparc/sparc-protos.h
index 3216f38..4fb862c 100644
--- a/contrib/gcc/config/sparc/sparc-protos.h
+++ b/contrib/gcc/config/sparc/sparc-protos.h
@@ -1,5 +1,5 @@
/* Prototypes of target machine for SPARC.
- Copyright (C) 1999, 2000, 2003 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com).
64-bit SPARC-V9 support by Michael Tiemann, Jim Wilson, and Doug Evans,
at Cygnus Support.
@@ -18,30 +18,22 @@ 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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
#ifndef __SPARC_PROTOS_H__
#define __SPARC_PROTOS_H__
-extern bool sparc_emitting_epilogue;
-
#ifdef TREE_CODE
extern struct rtx_def *function_value (tree, enum machine_mode, int);
extern void function_arg_advance (CUMULATIVE_ARGS *,
enum machine_mode, tree, int);
extern struct rtx_def *function_arg (const CUMULATIVE_ARGS *,
enum machine_mode, tree, int, int);
-extern int function_arg_partial_nregs (const CUMULATIVE_ARGS *,
- enum machine_mode, tree, int);
-extern int function_arg_pass_by_reference (const CUMULATIVE_ARGS *,
- enum machine_mode, tree, int);
-extern struct rtx_def *sparc_builtin_saveregs (void);
#ifdef RTX_CODE
extern void init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree);
extern void sparc_va_start (tree, rtx);
#endif
-extern struct rtx_def *sparc_va_arg (tree, tree);
extern unsigned long sparc_type_code (tree);
#ifdef ARGS_SIZE_RTX
/* expr.h defines ARGS_SIZE_RTX and `enum direction' */
@@ -49,24 +41,24 @@ extern enum direction function_arg_padding (enum machine_mode, tree);
#endif /* ARGS_SIZE_RTX */
#endif /* TREE_CODE */
-extern void load_pic_register (void);
extern void order_regs_for_local_alloc (void);
-extern HOST_WIDE_INT compute_frame_size (HOST_WIDE_INT, int);
+extern HOST_WIDE_INT sparc_compute_frame_size (HOST_WIDE_INT, int);
+extern void sparc_expand_prologue (void);
+extern void sparc_expand_epilogue (void);
+extern bool sparc_can_use_return_insn_p (void);
extern int check_pic (int);
extern int short_branch (int, int);
-extern int sparc_flat_epilogue_delay_slots (void);
-extern HOST_WIDE_INT sparc_flat_compute_frame_size (HOST_WIDE_INT);
extern void sparc_profile_hook (int);
extern void sparc_override_options (void);
-extern int leaf_return_peephole_ok (void);
extern void sparc_output_scratch_registers (FILE *);
#ifdef RTX_CODE
extern enum machine_mode select_cc_mode (enum rtx_code, rtx, rtx);
/* Define the function that build the compare insn for scc and bcc. */
-extern rtx gen_compare_reg (enum rtx_code code, rtx, rtx);
+extern rtx gen_compare_reg (enum rtx_code code);
extern void sparc_emit_float_lib_cmp (rtx, rtx, enum rtx_code);
-extern void sparc_emit_floatunsdi (rtx [2]);
+extern void sparc_emit_floatunsdi (rtx [2], enum machine_mode);
+extern void sparc_emit_fixunsdi (rtx [2], enum machine_mode);
extern void emit_tfmode_binop (enum rtx_code, rtx *);
extern void emit_tfmode_unop (enum rtx_code, rtx *);
extern void emit_tfmode_cvt (enum rtx_code, rtx *);
@@ -82,15 +74,18 @@ extern rtx legitimize_pic_address (rtx, enum machine_mode, rtx);
extern rtx legitimize_tls_address (rtx);
extern rtx legitimize_address (rtx, rtx, enum machine_mode);
extern void sparc_defer_case_vector (rtx, rtx, int);
+extern bool sparc_expand_move (enum machine_mode, rtx *);
extern void sparc_emit_set_const32 (rtx, rtx);
extern void sparc_emit_set_const64 (rtx, rtx);
extern void sparc_emit_set_symbolic_const64 (rtx, rtx, rtx);
extern int sparc_splitdi_legitimate (rtx, rtx);
extern int sparc_absnegfloat_split_legitimate (rtx, rtx);
extern const char *output_ubranch (rtx, int, rtx);
-extern char *output_cbranch (rtx, rtx, int, int, int, int, rtx);
+extern const char *output_cbranch (rtx, rtx, int, int, int, rtx);
+extern const char *output_return (rtx);
extern const char *output_sibcall (rtx, rtx);
-extern char *output_v9branch (rtx, rtx, int, int, int, int, int, rtx);
+extern const char *output_v8plus_shift (rtx *, rtx, const char *);
+extern const char *output_v9branch (rtx, rtx, int, int, int, int, rtx);
extern void emit_v9_brxx_insn (enum rtx_code, rtx, rtx);
extern void print_operand (FILE *, rtx, int);
extern int mems_ok_for_ldd_peep (rtx, rtx, rtx);
@@ -99,29 +94,27 @@ extern int arith_4096_operand (rtx, enum machine_mode);
extern int zero_operand (rtx, enum machine_mode);
extern int fp_zero_operand (rtx, enum machine_mode);
extern int reg_or_0_operand (rtx, enum machine_mode);
-extern int tls_symbolic_operand (rtx);
extern int empty_delay_slot (rtx);
-extern int eligible_for_epilogue_delay (rtx, int);
+extern int eligible_for_return_delay (rtx);
extern int eligible_for_sibcall_delay (rtx);
extern int tls_call_delay (rtx);
extern int emit_move_sequence (rtx, enum machine_mode);
extern int fp_sethi_p (rtx);
extern int fp_mov_p (rtx);
extern int fp_high_losum_p (rtx);
+extern bool sparc_tls_referenced_p (rtx);
extern int mem_min_alignment (rtx, int);
extern int pic_address_needs_scratch (rtx);
extern int reg_unused_after (rtx, rtx);
extern int register_ok_for_ldd (rtx);
extern int registers_ok_for_ldd_peep (rtx, rtx);
-extern int sparc_flat_eligible_for_epilogue_delay (rtx, int);
extern int v9_regcmp_p (enum rtx_code);
-extern char *sparc_v8plus_shift (rtx *, rtx, const char *);
/* Function used for V8+ code generation. Returns 1 if the high
32 bits of REG are 0 before INSN. */
extern int sparc_check_64 (rtx, rtx);
extern rtx gen_df_reg (rtx, int);
extern int sparc_extra_constraint_check (rtx, int, int);
-extern void sparc_output_dwarf_dtprel (FILE*, int, rtx);
+extern void sparc_expand_compare_and_swap_12 (rtx, rtx, rtx, rtx);
#endif /* RTX_CODE */
#endif /* __SPARC_PROTOS_H__ */
diff --git a/contrib/gcc/config/sparc/sparc.c b/contrib/gcc/config/sparc/sparc.c
index 86524cc..692e46e 100644
--- a/contrib/gcc/config/sparc/sparc.c
+++ b/contrib/gcc/config/sparc/sparc.c
@@ -1,6 +1,7 @@
/* Subroutines for insn-output.c for SPARC.
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
+ Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
64-bit SPARC-V9 support by Michael Tiemann, Jim Wilson, and Doug Evans,
at Cygnus Support.
@@ -19,8 +20,8 @@ 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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
#include "config.h"
#include "system.h"
@@ -32,6 +33,7 @@ Boston, MA 02111-1307, USA. */
#include "hard-reg-set.h"
#include "real.h"
#include "insn-config.h"
+#include "insn-codes.h"
#include "conditions.h"
#include "output.h"
#include "insn-attr.h"
@@ -47,24 +49,197 @@ Boston, MA 02111-1307, USA. */
#include "target.h"
#include "target-def.h"
#include "cfglayout.h"
+#include "tree-gimple.h"
+#include "langhooks.h"
+
+/* Processor costs */
+static const
+struct processor_costs cypress_costs = {
+ COSTS_N_INSNS (2), /* int load */
+ COSTS_N_INSNS (2), /* int signed load */
+ COSTS_N_INSNS (2), /* int zeroed load */
+ COSTS_N_INSNS (2), /* float load */
+ COSTS_N_INSNS (5), /* fmov, fneg, fabs */
+ COSTS_N_INSNS (5), /* fadd, fsub */
+ COSTS_N_INSNS (1), /* fcmp */
+ COSTS_N_INSNS (1), /* fmov, fmovr */
+ COSTS_N_INSNS (7), /* fmul */
+ COSTS_N_INSNS (37), /* fdivs */
+ COSTS_N_INSNS (37), /* fdivd */
+ COSTS_N_INSNS (63), /* fsqrts */
+ COSTS_N_INSNS (63), /* fsqrtd */
+ COSTS_N_INSNS (1), /* imul */
+ COSTS_N_INSNS (1), /* imulX */
+ 0, /* imul bit factor */
+ COSTS_N_INSNS (1), /* idiv */
+ COSTS_N_INSNS (1), /* idivX */
+ COSTS_N_INSNS (1), /* movcc/movr */
+ 0, /* shift penalty */
+};
+
+static const
+struct processor_costs supersparc_costs = {
+ COSTS_N_INSNS (1), /* int load */
+ COSTS_N_INSNS (1), /* int signed load */
+ COSTS_N_INSNS (1), /* int zeroed load */
+ COSTS_N_INSNS (0), /* float load */
+ COSTS_N_INSNS (3), /* fmov, fneg, fabs */
+ COSTS_N_INSNS (3), /* fadd, fsub */
+ COSTS_N_INSNS (3), /* fcmp */
+ COSTS_N_INSNS (1), /* fmov, fmovr */
+ COSTS_N_INSNS (3), /* fmul */
+ COSTS_N_INSNS (6), /* fdivs */
+ COSTS_N_INSNS (9), /* fdivd */
+ COSTS_N_INSNS (12), /* fsqrts */
+ COSTS_N_INSNS (12), /* fsqrtd */
+ COSTS_N_INSNS (4), /* imul */
+ COSTS_N_INSNS (4), /* imulX */
+ 0, /* imul bit factor */
+ COSTS_N_INSNS (4), /* idiv */
+ COSTS_N_INSNS (4), /* idivX */
+ COSTS_N_INSNS (1), /* movcc/movr */
+ 1, /* shift penalty */
+};
+
+static const
+struct processor_costs hypersparc_costs = {
+ COSTS_N_INSNS (1), /* int load */
+ COSTS_N_INSNS (1), /* int signed load */
+ COSTS_N_INSNS (1), /* int zeroed load */
+ COSTS_N_INSNS (1), /* float load */
+ COSTS_N_INSNS (1), /* fmov, fneg, fabs */
+ COSTS_N_INSNS (1), /* fadd, fsub */
+ COSTS_N_INSNS (1), /* fcmp */
+ COSTS_N_INSNS (1), /* fmov, fmovr */
+ COSTS_N_INSNS (1), /* fmul */
+ COSTS_N_INSNS (8), /* fdivs */
+ COSTS_N_INSNS (12), /* fdivd */
+ COSTS_N_INSNS (17), /* fsqrts */
+ COSTS_N_INSNS (17), /* fsqrtd */
+ COSTS_N_INSNS (17), /* imul */
+ COSTS_N_INSNS (17), /* imulX */
+ 0, /* imul bit factor */
+ COSTS_N_INSNS (17), /* idiv */
+ COSTS_N_INSNS (17), /* idivX */
+ COSTS_N_INSNS (1), /* movcc/movr */
+ 0, /* shift penalty */
+};
+
+static const
+struct processor_costs sparclet_costs = {
+ COSTS_N_INSNS (3), /* int load */
+ COSTS_N_INSNS (3), /* int signed load */
+ COSTS_N_INSNS (1), /* int zeroed load */
+ COSTS_N_INSNS (1), /* float load */
+ COSTS_N_INSNS (1), /* fmov, fneg, fabs */
+ COSTS_N_INSNS (1), /* fadd, fsub */
+ COSTS_N_INSNS (1), /* fcmp */
+ COSTS_N_INSNS (1), /* fmov, fmovr */
+ COSTS_N_INSNS (1), /* fmul */
+ COSTS_N_INSNS (1), /* fdivs */
+ COSTS_N_INSNS (1), /* fdivd */
+ COSTS_N_INSNS (1), /* fsqrts */
+ COSTS_N_INSNS (1), /* fsqrtd */
+ COSTS_N_INSNS (5), /* imul */
+ COSTS_N_INSNS (5), /* imulX */
+ 0, /* imul bit factor */
+ COSTS_N_INSNS (5), /* idiv */
+ COSTS_N_INSNS (5), /* idivX */
+ COSTS_N_INSNS (1), /* movcc/movr */
+ 0, /* shift penalty */
+};
-/* 1 if the caller has placed an "unimp" insn immediately after the call.
- This is used in v8 code when calling a function that returns a structure.
- v9 doesn't have this. Be careful to have this test be the same as that
- used on the call. */
+static const
+struct processor_costs ultrasparc_costs = {
+ COSTS_N_INSNS (2), /* int load */
+ COSTS_N_INSNS (3), /* int signed load */
+ COSTS_N_INSNS (2), /* int zeroed load */
+ COSTS_N_INSNS (2), /* float load */
+ COSTS_N_INSNS (1), /* fmov, fneg, fabs */
+ COSTS_N_INSNS (4), /* fadd, fsub */
+ COSTS_N_INSNS (1), /* fcmp */
+ COSTS_N_INSNS (2), /* fmov, fmovr */
+ COSTS_N_INSNS (4), /* fmul */
+ COSTS_N_INSNS (13), /* fdivs */
+ COSTS_N_INSNS (23), /* fdivd */
+ COSTS_N_INSNS (13), /* fsqrts */
+ COSTS_N_INSNS (23), /* fsqrtd */
+ COSTS_N_INSNS (4), /* imul */
+ COSTS_N_INSNS (4), /* imulX */
+ 2, /* imul bit factor */
+ COSTS_N_INSNS (37), /* idiv */
+ COSTS_N_INSNS (68), /* idivX */
+ COSTS_N_INSNS (2), /* movcc/movr */
+ 2, /* shift penalty */
+};
-#define SKIP_CALLERS_UNIMP_P \
-(!TARGET_ARCH64 && current_function_returns_struct \
- && ! integer_zerop (DECL_SIZE (DECL_RESULT (current_function_decl))) \
- && (TREE_CODE (DECL_SIZE (DECL_RESULT (current_function_decl))) \
- == INTEGER_CST))
+static const
+struct processor_costs ultrasparc3_costs = {
+ COSTS_N_INSNS (2), /* int load */
+ COSTS_N_INSNS (3), /* int signed load */
+ COSTS_N_INSNS (3), /* int zeroed load */
+ COSTS_N_INSNS (2), /* float load */
+ COSTS_N_INSNS (3), /* fmov, fneg, fabs */
+ COSTS_N_INSNS (4), /* fadd, fsub */
+ COSTS_N_INSNS (5), /* fcmp */
+ COSTS_N_INSNS (3), /* fmov, fmovr */
+ COSTS_N_INSNS (4), /* fmul */
+ COSTS_N_INSNS (17), /* fdivs */
+ COSTS_N_INSNS (20), /* fdivd */
+ COSTS_N_INSNS (20), /* fsqrts */
+ COSTS_N_INSNS (29), /* fsqrtd */
+ COSTS_N_INSNS (6), /* imul */
+ COSTS_N_INSNS (6), /* imulX */
+ 0, /* imul bit factor */
+ COSTS_N_INSNS (40), /* idiv */
+ COSTS_N_INSNS (71), /* idivX */
+ COSTS_N_INSNS (2), /* movcc/movr */
+ 0, /* shift penalty */
+};
+
+static const
+struct processor_costs niagara_costs = {
+ COSTS_N_INSNS (3), /* int load */
+ COSTS_N_INSNS (3), /* int signed load */
+ COSTS_N_INSNS (3), /* int zeroed load */
+ COSTS_N_INSNS (9), /* float load */
+ COSTS_N_INSNS (8), /* fmov, fneg, fabs */
+ COSTS_N_INSNS (8), /* fadd, fsub */
+ COSTS_N_INSNS (26), /* fcmp */
+ COSTS_N_INSNS (8), /* fmov, fmovr */
+ COSTS_N_INSNS (29), /* fmul */
+ COSTS_N_INSNS (54), /* fdivs */
+ COSTS_N_INSNS (83), /* fdivd */
+ COSTS_N_INSNS (100), /* fsqrts - not implemented in hardware */
+ COSTS_N_INSNS (100), /* fsqrtd - not implemented in hardware */
+ COSTS_N_INSNS (11), /* imul */
+ COSTS_N_INSNS (11), /* imulX */
+ 0, /* imul bit factor */
+ COSTS_N_INSNS (72), /* idiv */
+ COSTS_N_INSNS (72), /* idivX */
+ COSTS_N_INSNS (1), /* movcc/movr */
+ 0, /* shift penalty */
+};
+
+const struct processor_costs *sparc_costs = &cypress_costs;
+
+#ifdef HAVE_AS_RELAX_OPTION
+/* If 'as' and 'ld' are relaxing tail call insns into branch always, use
+ "or %o7,%g0,X; call Y; or X,%g0,%o7" always, so that it can be optimized.
+ With sethi/jmp, neither 'as' nor 'ld' has an easy way how to find out if
+ somebody does not branch between the sethi and jmp. */
+#define LEAF_SIBCALL_SLOT_RESERVED_P 1
+#else
+#define LEAF_SIBCALL_SLOT_RESERVED_P \
+ ((TARGET_ARCH64 && !TARGET_CM_MEDLOW) || flag_pic)
+#endif
/* Global variables for machine-dependent things. */
/* Size of frame. Need to know this to emit return insns from leaf procedures.
- ACTUAL_FSIZE is set by compute_frame_size() which is called during the
- reload pass. This is important as the value is later used in insn
- scheduling (to see what can go in a delay slot).
+ ACTUAL_FSIZE is set by sparc_compute_frame_size() which is called during the
+ reload pass. This is important as the value is later used for scheduling
+ (to see what can go in a delay slot).
APPARENT_FSIZE is the size of the stack less the register save area and less
the outgoing argument area. It is used when saving call preserved regs. */
static HOST_WIDE_INT apparent_fsize;
@@ -74,13 +249,15 @@ static HOST_WIDE_INT actual_fsize;
saved (as 4-byte quantities). */
static int num_gfregs;
+/* The alias set for prologue/epilogue register save/restore. */
+static GTY(()) int sparc_sr_alias_set;
+
+/* The alias set for the structure return value. */
+static GTY(()) int struct_value_alias_set;
+
/* Save the operands last given to a compare for use when we
generate a scc or bcc insn. */
-rtx sparc_compare_op0, sparc_compare_op1;
-
-/* Coordinate with the md file wrt special insns created by
- sparc_nonflat_function_epilogue. */
-bool sparc_emitting_epilogue;
+rtx sparc_compare_op0, sparc_compare_op1, sparc_compare_emitted;
/* Vector to say how input registers are mapped to output registers.
HARD_FRAME_POINTER_REGNUM cannot be remapped by this function to
@@ -123,20 +300,32 @@ struct machine_function GTY(())
{
/* Some local-dynamic TLS symbol name. */
const char *some_ld_name;
+
+ /* True if the current function is leaf and uses only leaf regs,
+ so that the SPARC leaf function optimization can be applied.
+ Private version of current_function_uses_only_leaf_regs, see
+ sparc_expand_prologue for the rationale. */
+ int leaf_function_p;
+
+ /* True if the data calculated by sparc_expand_prologue are valid. */
+ bool prologue_data_valid_p;
};
-/* Name of where we pretend to think the frame pointer points.
- Normally, this is "%fp", but if we are in a leaf procedure,
- this is "%sp+something". We record "something" separately as it may be
- too big for reg+constant addressing. */
+#define sparc_leaf_function_p cfun->machine->leaf_function_p
+#define sparc_prologue_data_valid_p cfun->machine->prologue_data_valid_p
-static const char *frame_base_name;
+/* Register we pretend to think the frame pointer is allocated to.
+ Normally, this is %fp, but if we are in a leaf procedure, this
+ is %sp+"something". We record "something" separately as it may
+ be too big for reg+constant addressing. */
+static rtx frame_base_reg;
static HOST_WIDE_INT frame_base_offset;
+/* 1 if the next opcode is to be specially indented. */
+int sparc_indent_opcode = 0;
+
+static bool sparc_handle_option (size_t, const char *, int);
static void sparc_init_modes (void);
-static int save_regs (FILE *, int, int, const char *, int, int, HOST_WIDE_INT);
-static int restore_regs (FILE *, int, int, const char *, int, int);
-static void build_big_number (FILE *, HOST_WIDE_INT, const char *);
static void scan_record_type (tree, int *, int *, int *);
static int function_arg_slotno (const CUMULATIVE_ARGS *, enum machine_mode,
tree, int, int, int *, int *);
@@ -147,34 +336,23 @@ static int hypersparc_adjust_cost (rtx, rtx, rtx, int);
static void sparc_output_addr_vec (rtx);
static void sparc_output_addr_diff_vec (rtx);
static void sparc_output_deferred_case_vectors (void);
-static int check_return_regs (rtx);
+static rtx sparc_builtin_saveregs (void);
static int epilogue_renumber (rtx *, int);
static bool sparc_assemble_integer (rtx, unsigned int, int);
static int set_extends (rtx);
-static void output_restore_regs (FILE *, int);
-static void sparc_output_function_prologue (FILE *, HOST_WIDE_INT);
-static void sparc_output_function_epilogue (FILE *, HOST_WIDE_INT);
-static void sparc_flat_function_epilogue (FILE *, HOST_WIDE_INT);
-static void sparc_flat_function_prologue (FILE *, HOST_WIDE_INT);
-static void sparc_flat_save_restore (FILE *, const char *, int,
- unsigned long, unsigned long,
- const char *, const char *,
- HOST_WIDE_INT);
-static void sparc_nonflat_function_epilogue (FILE *, HOST_WIDE_INT, int);
-static void sparc_nonflat_function_prologue (FILE *, HOST_WIDE_INT, int);
+static void emit_pic_helper (void);
+static void load_pic_register (bool);
+static int save_or_restore_regs (int, int, rtx, int, int);
+static void emit_save_or_restore_regs (int);
+static void sparc_asm_function_prologue (FILE *, HOST_WIDE_INT);
+static void sparc_asm_function_epilogue (FILE *, HOST_WIDE_INT);
#ifdef OBJECT_FORMAT_ELF
-static void sparc_elf_asm_named_section (const char *, unsigned int);
+static void sparc_elf_asm_named_section (const char *, unsigned int, tree);
#endif
-static void sparc_aout_select_section (tree, int, unsigned HOST_WIDE_INT)
- ATTRIBUTE_UNUSED;
-static void sparc_aout_select_rtx_section (enum machine_mode, rtx,
- unsigned HOST_WIDE_INT)
- ATTRIBUTE_UNUSED;
static int sparc_adjust_cost (rtx, rtx, rtx, int);
static int sparc_issue_rate (void);
static void sparc_sched_init (FILE *, int, int);
-static int sparc_use_dfa_pipeline_interface (void);
static int sparc_use_sched_lookahead (void);
static void emit_soft_tfmode_libcall (const char *, int, rtx *);
@@ -185,6 +363,12 @@ static void emit_hard_tfmode_operation (enum rtx_code, rtx *);
static bool sparc_function_ok_for_sibcall (tree, tree);
static void sparc_init_libfuncs (void);
+static void sparc_init_builtins (void);
+static void sparc_vis_init_builtins (void);
+static rtx sparc_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
+static tree sparc_fold_builtin (tree, tree, bool);
+static int sparc_vis_mul8x16 (int, int);
+static tree sparc_handle_vis_mul8x16 (int, tree, tree, tree);
static void sparc_output_mi_thunk (FILE *, tree, HOST_WIDE_INT,
HOST_WIDE_INT, tree);
static bool sparc_can_output_mi_thunk (tree, HOST_WIDE_INT,
@@ -196,11 +380,28 @@ static rtx sparc_tls_got (void);
static const char *get_some_local_dynamic_name (void);
static int get_some_local_dynamic_name_1 (rtx *, void *);
static bool sparc_rtx_costs (rtx, int, int, int *);
+static bool sparc_promote_prototypes (tree);
+static rtx sparc_struct_value_rtx (tree, int);
+static bool sparc_return_in_memory (tree, tree);
+static bool sparc_strict_argument_naming (CUMULATIVE_ARGS *);
+static tree sparc_gimplify_va_arg (tree, tree, tree *, tree *);
+static bool sparc_vector_mode_supported_p (enum machine_mode);
+static bool sparc_pass_by_reference (CUMULATIVE_ARGS *,
+ enum machine_mode, tree, bool);
+static int sparc_arg_partial_bytes (CUMULATIVE_ARGS *,
+ enum machine_mode, tree, bool);
+static void sparc_dwarf_handle_frame_unspec (const char *, rtx, int);
+static void sparc_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED;
+static void sparc_file_end (void);
+#ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING
+static const char *sparc_mangle_fundamental_type (tree);
+#endif
+#ifdef SUBTARGET_ATTRIBUTE_TABLE
+const struct attribute_spec sparc_attribute_table[];
+#endif
/* Option handling. */
-/* Code model option as passed by user. */
-const char *sparc_cmodel_string;
/* Parsed value. */
enum cmodel sparc_cmodel;
@@ -217,7 +418,10 @@ struct sparc_cpu_select sparc_select[] =
/* CPU type. This is set from TARGET_CPU_DEFAULT and -m{cpu,tune}=xxx. */
enum processor_type sparc_cpu;
-
+
+/* Whether an FPU option was specified. */
+static bool fpu_option_set = false;
+
/* Initialize the GCC target structure. */
/* The sparc default is to use .half rather than .short for aligned
@@ -241,9 +445,9 @@ enum processor_type sparc_cpu;
#define TARGET_ASM_INTEGER sparc_assemble_integer
#undef TARGET_ASM_FUNCTION_PROLOGUE
-#define TARGET_ASM_FUNCTION_PROLOGUE sparc_output_function_prologue
+#define TARGET_ASM_FUNCTION_PROLOGUE sparc_asm_function_prologue
#undef TARGET_ASM_FUNCTION_EPILOGUE
-#define TARGET_ASM_FUNCTION_EPILOGUE sparc_output_function_epilogue
+#define TARGET_ASM_FUNCTION_EPILOGUE sparc_asm_function_epilogue
#undef TARGET_SCHED_ADJUST_COST
#define TARGET_SCHED_ADJUST_COST sparc_adjust_cost
@@ -251,8 +455,6 @@ enum processor_type sparc_cpu;
#define TARGET_SCHED_ISSUE_RATE sparc_issue_rate
#undef TARGET_SCHED_INIT
#define TARGET_SCHED_INIT sparc_sched_init
-#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE
-#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE sparc_use_dfa_pipeline_interface
#undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD
#define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD sparc_use_sched_lookahead
@@ -261,11 +463,19 @@ enum processor_type sparc_cpu;
#undef TARGET_INIT_LIBFUNCS
#define TARGET_INIT_LIBFUNCS sparc_init_libfuncs
+#undef TARGET_INIT_BUILTINS
+#define TARGET_INIT_BUILTINS sparc_init_builtins
-#ifdef HAVE_AS_TLS
+#undef TARGET_EXPAND_BUILTIN
+#define TARGET_EXPAND_BUILTIN sparc_expand_builtin
+#undef TARGET_FOLD_BUILTIN
+#define TARGET_FOLD_BUILTIN sparc_fold_builtin
+
+#if TARGET_TLS
#undef TARGET_HAVE_TLS
#define TARGET_HAVE_TLS true
#endif
+
#undef TARGET_CANNOT_FORCE_CONST_MEM
#define TARGET_CANNOT_FORCE_CONST_MEM sparc_cannot_force_const_mem
@@ -279,8 +489,104 @@ enum processor_type sparc_cpu;
#undef TARGET_ADDRESS_COST
#define TARGET_ADDRESS_COST hook_int_rtx_0
+/* This is only needed for TARGET_ARCH64, but since PROMOTE_FUNCTION_MODE is a
+ no-op for TARGET_ARCH32 this is ok. Otherwise we'd need to add a runtime
+ test for this value. */
+#undef TARGET_PROMOTE_FUNCTION_ARGS
+#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
+
+/* This is only needed for TARGET_ARCH64, but since PROMOTE_FUNCTION_MODE is a
+ no-op for TARGET_ARCH32 this is ok. Otherwise we'd need to add a runtime
+ test for this value. */
+#undef TARGET_PROMOTE_FUNCTION_RETURN
+#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
+
+#undef TARGET_PROMOTE_PROTOTYPES
+#define TARGET_PROMOTE_PROTOTYPES sparc_promote_prototypes
+
+#undef TARGET_STRUCT_VALUE_RTX
+#define TARGET_STRUCT_VALUE_RTX sparc_struct_value_rtx
+#undef TARGET_RETURN_IN_MEMORY
+#define TARGET_RETURN_IN_MEMORY sparc_return_in_memory
+#undef TARGET_MUST_PASS_IN_STACK
+#define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
+#undef TARGET_PASS_BY_REFERENCE
+#define TARGET_PASS_BY_REFERENCE sparc_pass_by_reference
+#undef TARGET_ARG_PARTIAL_BYTES
+#define TARGET_ARG_PARTIAL_BYTES sparc_arg_partial_bytes
+
+#undef TARGET_EXPAND_BUILTIN_SAVEREGS
+#define TARGET_EXPAND_BUILTIN_SAVEREGS sparc_builtin_saveregs
+#undef TARGET_STRICT_ARGUMENT_NAMING
+#define TARGET_STRICT_ARGUMENT_NAMING sparc_strict_argument_naming
+
+#undef TARGET_GIMPLIFY_VA_ARG_EXPR
+#define TARGET_GIMPLIFY_VA_ARG_EXPR sparc_gimplify_va_arg
+
+#undef TARGET_VECTOR_MODE_SUPPORTED_P
+#define TARGET_VECTOR_MODE_SUPPORTED_P sparc_vector_mode_supported_p
+
+#undef TARGET_DWARF_HANDLE_FRAME_UNSPEC
+#define TARGET_DWARF_HANDLE_FRAME_UNSPEC sparc_dwarf_handle_frame_unspec
+
+#ifdef SUBTARGET_INSERT_ATTRIBUTES
+#undef TARGET_INSERT_ATTRIBUTES
+#define TARGET_INSERT_ATTRIBUTES SUBTARGET_INSERT_ATTRIBUTES
+#endif
+
+#ifdef SUBTARGET_ATTRIBUTE_TABLE
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE sparc_attribute_table
+#endif
+
+#undef TARGET_RELAXED_ORDERING
+#define TARGET_RELAXED_ORDERING SPARC_RELAXED_ORDERING
+
+#undef TARGET_DEFAULT_TARGET_FLAGS
+#define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
+#undef TARGET_HANDLE_OPTION
+#define TARGET_HANDLE_OPTION sparc_handle_option
+
+#if TARGET_GNU_TLS
+#undef TARGET_ASM_OUTPUT_DWARF_DTPREL
+#define TARGET_ASM_OUTPUT_DWARF_DTPREL sparc_output_dwarf_dtprel
+#endif
+
+#undef TARGET_ASM_FILE_END
+#define TARGET_ASM_FILE_END sparc_file_end
+
+#ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING
+#undef TARGET_MANGLE_FUNDAMENTAL_TYPE
+#define TARGET_MANGLE_FUNDAMENTAL_TYPE sparc_mangle_fundamental_type
+#endif
+
struct gcc_target targetm = TARGET_INITIALIZER;
-
+
+/* Implement TARGET_HANDLE_OPTION. */
+
+static bool
+sparc_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED)
+{
+ switch (code)
+ {
+ case OPT_mfpu:
+ case OPT_mhard_float:
+ case OPT_msoft_float:
+ fpu_option_set = true;
+ break;
+
+ case OPT_mcpu_:
+ sparc_select[1].string = arg;
+ break;
+
+ case OPT_mtune_:
+ sparc_select[2].string = arg;
+ break;
+ }
+
+ return true;
+}
+
/* Validate and override various options, and do some machine dependent
initialization. */
@@ -315,6 +621,7 @@ sparc_override_options (void)
{ TARGET_CPU_v9, "v9" },
{ TARGET_CPU_ultrasparc, "ultrasparc" },
{ TARGET_CPU_ultrasparc3, "ultrasparc3" },
+ { TARGET_CPU_niagara, "niagara" },
{ 0, 0 }
};
const struct cpu_default *def;
@@ -350,6 +657,8 @@ sparc_override_options (void)
/* TI ultrasparc III */
/* ??? Check if %y issue still holds true in ultra3. */
{ "ultrasparc3", PROCESSOR_ULTRASPARC3, MASK_ISA, MASK_V9|MASK_DEPRECATED_V8_INSNS},
+ /* UltraSPARC T1 */
+ { "niagara", PROCESSOR_NIAGARA, MASK_ISA, MASK_V9|MASK_DEPRECATED_V8_INSNS},
{ 0, 0, 0, 0 }
};
const struct cpu_table *cpu;
@@ -400,8 +709,7 @@ sparc_override_options (void)
for (def = &cpu_default[0]; def->name; ++def)
if (def->cpu == TARGET_CPU_DEFAULT)
break;
- if (! def->name)
- abort ();
+ gcc_assert (def->name);
sparc_select[0].string = def->name;
for (sel = &sparc_select[0]; sel->name; ++sel)
@@ -428,13 +736,9 @@ sparc_override_options (void)
}
/* If -mfpu or -mno-fpu was explicitly used, don't override with
- the processor default. Clear MASK_FPU_SET to avoid confusing
- the reverse mapping from switch values to names. */
- if (TARGET_FPU_SET)
- {
- target_flags = (target_flags & ~MASK_FPU) | fpu;
- target_flags &= ~MASK_FPU_SET;
- }
+ the processor default. */
+ if (fpu_option_set)
+ target_flags = (target_flags & ~MASK_FPU) | fpu;
/* Don't allow -mvis if FPU is disabled. */
if (! TARGET_FPU)
@@ -464,7 +768,8 @@ sparc_override_options (void)
/* Supply a default value for align_functions. */
if (align_functions == 0
&& (sparc_cpu == PROCESSOR_ULTRASPARC
- || sparc_cpu == PROCESSOR_ULTRASPARC3))
+ || sparc_cpu == PROCESSOR_ULTRASPARC3
+ || sparc_cpu == PROCESSOR_NIAGARA))
align_functions = 32;
/* Validate PCC_STRUCT_RETURN. */
@@ -478,10 +783,62 @@ sparc_override_options (void)
/* Do various machine dependent initializations. */
sparc_init_modes ();
+ /* Acquire unique alias sets for our private stuff. */
+ sparc_sr_alias_set = new_alias_set ();
+ struct_value_alias_set = new_alias_set ();
+
/* Set up function hooks. */
init_machine_status = sparc_init_machine_status;
+
+ switch (sparc_cpu)
+ {
+ case PROCESSOR_V7:
+ case PROCESSOR_CYPRESS:
+ sparc_costs = &cypress_costs;
+ break;
+ case PROCESSOR_V8:
+ case PROCESSOR_SPARCLITE:
+ case PROCESSOR_SUPERSPARC:
+ sparc_costs = &supersparc_costs;
+ break;
+ case PROCESSOR_F930:
+ case PROCESSOR_F934:
+ case PROCESSOR_HYPERSPARC:
+ case PROCESSOR_SPARCLITE86X:
+ sparc_costs = &hypersparc_costs;
+ break;
+ case PROCESSOR_SPARCLET:
+ case PROCESSOR_TSC701:
+ sparc_costs = &sparclet_costs;
+ break;
+ case PROCESSOR_V9:
+ case PROCESSOR_ULTRASPARC:
+ sparc_costs = &ultrasparc_costs;
+ break;
+ case PROCESSOR_ULTRASPARC3:
+ sparc_costs = &ultrasparc3_costs;
+ break;
+ case PROCESSOR_NIAGARA:
+ sparc_costs = &niagara_costs;
+ break;
+ };
+
+#ifdef TARGET_DEFAULT_LONG_DOUBLE_128
+ if (!(target_flags_explicit & MASK_LONG_DOUBLE_128))
+ target_flags |= MASK_LONG_DOUBLE_128;
+#endif
}
+#ifdef SUBTARGET_ATTRIBUTE_TABLE
+/* Table of valid machine attributes. */
+const struct attribute_spec sparc_attribute_table[] =
+{
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ SUBTARGET_ATTRIBUTE_TABLE,
+ { NULL, 0, 0, false, false, false, NULL }
+};
+#endif
+
/* Miscellaneous utilities. */
/* Nonzero if CODE, a comparison, is suitable for use in v9 conditional move
@@ -494,58 +851,6 @@ v9_regcmp_p (enum rtx_code code)
|| code == LE || code == GT);
}
-
-/* Operand constraints. */
-
-/* Return nonzero only if OP is a register of mode MODE,
- or const0_rtx. */
-
-int
-reg_or_0_operand (rtx op, enum machine_mode mode)
-{
- if (register_operand (op, mode))
- return 1;
- if (op == const0_rtx)
- return 1;
- if (GET_MODE (op) == VOIDmode && GET_CODE (op) == CONST_DOUBLE
- && CONST_DOUBLE_HIGH (op) == 0
- && CONST_DOUBLE_LOW (op) == 0)
- return 1;
- if (fp_zero_operand (op, mode))
- return 1;
- return 0;
-}
-
-/* Return nonzero only if OP is const1_rtx. */
-
-int
-const1_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- return op == const1_rtx;
-}
-
-/* Nonzero if OP is a floating point value with value 0.0. */
-
-int
-fp_zero_operand (rtx op, enum machine_mode mode)
-{
- if (GET_MODE_CLASS (GET_MODE (op)) != MODE_FLOAT)
- return 0;
- return op == CONST0_RTX (mode);
-}
-
-/* Nonzero if OP is a register operand in floating point register. */
-
-int
-fp_register_operand (rtx op, enum machine_mode mode)
-{
- if (! register_operand (op, mode))
- return 0;
- if (GET_CODE (op) == SUBREG)
- op = SUBREG_REG (op);
- return GET_CODE (op) == REG && SPARC_FP_REG_P (REGNO (op));
-}
-
/* Nonzero if OP is a floating point constant which can
be loaded into an integer register using a single
sethi instruction. */
@@ -559,12 +864,8 @@ fp_sethi_p (rtx op)
long i;
REAL_VALUE_FROM_CONST_DOUBLE (r, op);
- if (REAL_VALUES_EQUAL (r, dconst0) &&
- ! REAL_VALUE_MINUS_ZERO (r))
- return 0;
REAL_VALUE_TO_TARGET_SINGLE (r, i);
- if (SPARC_SETHI_P (i))
- return 1;
+ return !SPARC_SIMM13_P (i) && SPARC_SETHI_P (i);
}
return 0;
@@ -583,12 +884,8 @@ fp_mov_p (rtx op)
long i;
REAL_VALUE_FROM_CONST_DOUBLE (r, op);
- if (REAL_VALUES_EQUAL (r, dconst0) &&
- ! REAL_VALUE_MINUS_ZERO (r))
- return 0;
REAL_VALUE_TO_TARGET_SINGLE (r, i);
- if (SPARC_SIMM13_P (i))
- return 1;
+ return SPARC_SIMM13_P (i);
}
return 0;
@@ -610,763 +907,161 @@ fp_high_losum_p (rtx op)
long i;
REAL_VALUE_FROM_CONST_DOUBLE (r, op);
- if (REAL_VALUES_EQUAL (r, dconst0) &&
- ! REAL_VALUE_MINUS_ZERO (r))
- return 0;
REAL_VALUE_TO_TARGET_SINGLE (r, i);
- if (! SPARC_SETHI_P (i)
- && ! SPARC_SIMM13_P (i))
- return 1;
+ return !SPARC_SIMM13_P (i) && !SPARC_SETHI_P (i);
}
return 0;
}
-/* Nonzero if OP is an integer register. */
+/* Expand a move instruction. Return true if all work is done. */
-int
-intreg_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- return (register_operand (op, SImode)
- || (TARGET_ARCH64 && register_operand (op, DImode)));
-}
-
-/* Nonzero if OP is a floating point condition code register. */
-
-int
-fcc_reg_operand (rtx op, enum machine_mode mode)
-{
- /* This can happen when recog is called from combine. Op may be a MEM.
- Fail instead of calling abort in this case. */
- if (GET_CODE (op) != REG)
- return 0;
-
- if (mode != VOIDmode && mode != GET_MODE (op))
- return 0;
- if (mode == VOIDmode
- && (GET_MODE (op) != CCFPmode && GET_MODE (op) != CCFPEmode))
- return 0;
-
-#if 0 /* ??? ==> 1 when %fcc0-3 are pseudos first. See gen_compare_reg(). */
- if (reg_renumber == 0)
- return REGNO (op) >= FIRST_PSEUDO_REGISTER;
- return REGNO_OK_FOR_CCFP_P (REGNO (op));
-#else
- return (unsigned) REGNO (op) - SPARC_FIRST_V9_FCC_REG < 4;
-#endif
-}
-
-/* Nonzero if OP is a floating point condition code fcc0 register. */
-
-int
-fcc0_reg_operand (rtx op, enum machine_mode mode)
-{
- /* This can happen when recog is called from combine. Op may be a MEM.
- Fail instead of calling abort in this case. */
- if (GET_CODE (op) != REG)
- return 0;
-
- if (mode != VOIDmode && mode != GET_MODE (op))
- return 0;
- if (mode == VOIDmode
- && (GET_MODE (op) != CCFPmode && GET_MODE (op) != CCFPEmode))
- return 0;
-
- return REGNO (op) == SPARC_FCC_REG;
-}
-
-/* Nonzero if OP is an integer or floating point condition code register. */
-
-int
-icc_or_fcc_reg_operand (rtx op, enum machine_mode mode)
+bool
+sparc_expand_move (enum machine_mode mode, rtx *operands)
{
- if (GET_CODE (op) == REG && REGNO (op) == SPARC_ICC_REG)
+ /* Handle sets of MEM first. */
+ if (GET_CODE (operands[0]) == MEM)
{
- if (mode != VOIDmode && mode != GET_MODE (op))
- return 0;
- if (mode == VOIDmode
- && GET_MODE (op) != CCmode && GET_MODE (op) != CCXmode)
- return 0;
- return 1;
- }
-
- return fcc_reg_operand (op, mode);
-}
-
-/* Nonzero if OP can appear as the dest of a RESTORE insn. */
-int
-restore_operand (rtx op, enum machine_mode mode)
-{
- return (GET_CODE (op) == REG && GET_MODE (op) == mode
- && (REGNO (op) < 8 || (REGNO (op) >= 24 && REGNO (op) < 32)));
-}
-
-/* Call insn on SPARC can take a PC-relative constant address, or any regular
- memory address. */
-
-int
-call_operand (rtx op, enum machine_mode mode)
-{
- if (GET_CODE (op) != MEM)
- abort ();
- op = XEXP (op, 0);
- return (symbolic_operand (op, mode) || memory_address_p (Pmode, op));
-}
-
-int
-call_operand_address (rtx op, enum machine_mode mode)
-{
- return (symbolic_operand (op, mode) || memory_address_p (Pmode, op));
-}
-
-/* If OP is a SYMBOL_REF of a thread-local symbol, return its TLS mode,
- otherwise return 0. */
-
-int
-tls_symbolic_operand (rtx op)
-{
- if (GET_CODE (op) != SYMBOL_REF)
- return 0;
- return SYMBOL_REF_TLS_MODEL (op);
-}
-
-int
-tgd_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- return tls_symbolic_operand (op) == TLS_MODEL_GLOBAL_DYNAMIC;
-}
-
-int
-tld_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- return tls_symbolic_operand (op) == TLS_MODEL_LOCAL_DYNAMIC;
-}
-
-int
-tie_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- return tls_symbolic_operand (op) == TLS_MODEL_INITIAL_EXEC;
-}
-
-int
-tle_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- return tls_symbolic_operand (op) == TLS_MODEL_LOCAL_EXEC;
-}
-
-/* Returns 1 if OP is either a symbol reference or a sum of a symbol
- reference and a constant. */
-
-int
-symbolic_operand (register rtx op, enum machine_mode mode)
-{
- enum machine_mode omode = GET_MODE (op);
+ /* 0 is a register (or a pair of registers) on SPARC. */
+ if (register_or_zero_operand (operands[1], mode))
+ return false;
- if (omode != mode && omode != VOIDmode && mode != VOIDmode)
- return 0;
+ if (!reload_in_progress)
+ {
+ operands[0] = validize_mem (operands[0]);
+ operands[1] = force_reg (mode, operands[1]);
+ }
+ }
- switch (GET_CODE (op))
+ /* Fixup TLS cases. */
+ if (TARGET_HAVE_TLS
+ && CONSTANT_P (operands[1])
+ && GET_CODE (operands[1]) != HIGH
+ && sparc_tls_referenced_p (operands [1]))
{
- case SYMBOL_REF:
- return !SYMBOL_REF_TLS_MODEL (op);
+ rtx sym = operands[1];
+ rtx addend = NULL;
- case LABEL_REF:
- return 1;
+ if (GET_CODE (sym) == CONST && GET_CODE (XEXP (sym, 0)) == PLUS)
+ {
+ addend = XEXP (XEXP (sym, 0), 1);
+ sym = XEXP (XEXP (sym, 0), 0);
+ }
- case CONST:
- op = XEXP (op, 0);
- return (((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
- && !SYMBOL_REF_TLS_MODEL (XEXP (op, 0)))
- || GET_CODE (XEXP (op, 0)) == LABEL_REF)
- && GET_CODE (XEXP (op, 1)) == CONST_INT);
+ gcc_assert (SPARC_SYMBOL_REF_TLS_P (sym));
- default:
- return 0;
+ sym = legitimize_tls_address (sym);
+ if (addend)
+ {
+ sym = gen_rtx_PLUS (mode, sym, addend);
+ sym = force_operand (sym, operands[0]);
+ }
+ operands[1] = sym;
}
-}
-
-/* Return truth value of statement that OP is a symbolic memory
- operand of mode MODE. */
-
-int
-symbolic_memory_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- if (GET_CODE (op) == SUBREG)
- op = SUBREG_REG (op);
- if (GET_CODE (op) != MEM)
- return 0;
- op = XEXP (op, 0);
- return ((GET_CODE (op) == SYMBOL_REF && !SYMBOL_REF_TLS_MODEL (op))
- || GET_CODE (op) == CONST || GET_CODE (op) == HIGH
- || GET_CODE (op) == LABEL_REF);
-}
-
-/* Return truth value of statement that OP is a LABEL_REF of mode MODE. */
-
-int
-label_ref_operand (rtx op, enum machine_mode mode)
-{
- if (GET_CODE (op) != LABEL_REF)
- return 0;
- if (GET_MODE (op) != mode)
- return 0;
- return 1;
-}
-
-/* Return 1 if the operand is an argument used in generating pic references
- in either the medium/low or medium/anywhere code models of sparc64. */
+
+ /* Fixup PIC cases. */
+ if (flag_pic && CONSTANT_P (operands[1]))
+ {
+ if (pic_address_needs_scratch (operands[1]))
+ operands[1] = legitimize_pic_address (operands[1], mode, 0);
-int
-sp64_medium_pic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- /* Check for (const (minus (symbol_ref:GOT)
- (const (minus (label) (pc))))). */
- if (GET_CODE (op) != CONST)
- return 0;
- op = XEXP (op, 0);
- if (GET_CODE (op) != MINUS)
- return 0;
- if (GET_CODE (XEXP (op, 0)) != SYMBOL_REF)
- return 0;
- /* ??? Ensure symbol is GOT. */
- if (GET_CODE (XEXP (op, 1)) != CONST)
- return 0;
- if (GET_CODE (XEXP (XEXP (op, 1), 0)) != MINUS)
- return 0;
- return 1;
-}
+ if (GET_CODE (operands[1]) == LABEL_REF && mode == SImode)
+ {
+ emit_insn (gen_movsi_pic_label_ref (operands[0], operands[1]));
+ return true;
+ }
-/* Return 1 if the operand is a data segment reference. This includes
- the readonly data segment, or in other words anything but the text segment.
- This is needed in the medium/anywhere code model on v9. These values
- are accessed with EMBMEDANY_BASE_REG. */
+ if (GET_CODE (operands[1]) == LABEL_REF && mode == DImode)
+ {
+ gcc_assert (TARGET_ARCH64);
+ emit_insn (gen_movdi_pic_label_ref (operands[0], operands[1]));
+ return true;
+ }
-int
-data_segment_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- switch (GET_CODE (op))
- {
- case SYMBOL_REF :
- return ! SYMBOL_REF_FUNCTION_P (op);
- case PLUS :
- /* Assume canonical format of symbol + constant.
- Fall through. */
- case CONST :
- return data_segment_operand (XEXP (op, 0), VOIDmode);
- default :
- return 0;
+ if (symbolic_operand (operands[1], mode))
+ {
+ operands[1] = legitimize_pic_address (operands[1],
+ mode,
+ (reload_in_progress ?
+ operands[0] :
+ NULL_RTX));
+ return false;
+ }
}
-}
-
-/* Return 1 if the operand is a text segment reference.
- This is needed in the medium/anywhere code model on v9. */
-int
-text_segment_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- switch (GET_CODE (op))
+ /* If we are trying to toss an integer constant into FP registers,
+ or loading a FP or vector constant, force it into memory. */
+ if (CONSTANT_P (operands[1])
+ && REG_P (operands[0])
+ && (SPARC_FP_REG_P (REGNO (operands[0]))
+ || SCALAR_FLOAT_MODE_P (mode)
+ || VECTOR_MODE_P (mode)))
{
- case LABEL_REF :
- return 1;
- case SYMBOL_REF :
- return SYMBOL_REF_FUNCTION_P (op);
- case PLUS :
- /* Assume canonical format of symbol + constant.
- Fall through. */
- case CONST :
- return text_segment_operand (XEXP (op, 0), VOIDmode);
- default :
- return 0;
- }
-}
-
-/* Return 1 if the operand is either a register or a memory operand that is
- not symbolic. */
-
-int
-reg_or_nonsymb_mem_operand (register rtx op, enum machine_mode mode)
-{
- if (register_operand (op, mode))
- return 1;
-
- if (memory_operand (op, mode) && ! symbolic_memory_operand (op, mode))
- return 1;
-
- return 0;
-}
-
-int
-splittable_symbolic_memory_operand (rtx op,
- enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- if (GET_CODE (op) != MEM)
- return 0;
- if (! symbolic_operand (XEXP (op, 0), Pmode))
- return 0;
- return 1;
-}
-
-int
-splittable_immediate_memory_operand (rtx op,
- enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- if (GET_CODE (op) != MEM)
- return 0;
- if (! immediate_operand (XEXP (op, 0), Pmode))
- return 0;
- return 1;
-}
-
-/* Return truth value of whether OP is EQ or NE. */
-
-int
-eq_or_neq (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- return (GET_CODE (op) == EQ || GET_CODE (op) == NE);
-}
-
-/* Return 1 if this is a comparison operator, but not an EQ, NE, GEU,
- or LTU for non-floating-point. We handle those specially. */
-
-int
-normal_comp_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- enum rtx_code code = GET_CODE (op);
-
- if (GET_RTX_CLASS (code) != '<')
- return 0;
-
- if (GET_MODE (XEXP (op, 0)) == CCFPmode
- || GET_MODE (XEXP (op, 0)) == CCFPEmode)
- return 1;
-
- return (code != NE && code != EQ && code != GEU && code != LTU);
-}
-
-/* Return 1 if this is a comparison operator. This allows the use of
- MATCH_OPERATOR to recognize all the branch insns. */
-
-int
-noov_compare_op (register rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- enum rtx_code code = GET_CODE (op);
+ /* emit_group_store will send such bogosity to us when it is
+ not storing directly into memory. So fix this up to avoid
+ crashes in output_constant_pool. */
+ if (operands [1] == const0_rtx)
+ operands[1] = CONST0_RTX (mode);
- if (GET_RTX_CLASS (code) != '<')
- return 0;
-
- if (GET_MODE (XEXP (op, 0)) == CC_NOOVmode
- || GET_MODE (XEXP (op, 0)) == CCX_NOOVmode)
- /* These are the only branches which work with CC_NOOVmode. */
- return (code == EQ || code == NE || code == GE || code == LT);
- return 1;
-}
-
-/* Return 1 if this is a 64-bit comparison operator. This allows the use of
- MATCH_OPERATOR to recognize all the branch insns. */
-
-int
-noov_compare64_op (register rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- enum rtx_code code = GET_CODE (op);
-
- if (! TARGET_V9)
- return 0;
-
- if (GET_RTX_CLASS (code) != '<')
- return 0;
-
- if (GET_MODE (XEXP (op, 0)) == CCX_NOOVmode)
- /* These are the only branches which work with CCX_NOOVmode. */
- return (code == EQ || code == NE || code == GE || code == LT);
- return (GET_MODE (XEXP (op, 0)) == CCXmode);
-}
-
-/* Nonzero if OP is a comparison operator suitable for use in v9
- conditional move or branch on register contents instructions. */
-
-int
-v9_regcmp_op (register rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- enum rtx_code code = GET_CODE (op);
-
- if (GET_RTX_CLASS (code) != '<')
- return 0;
-
- return v9_regcmp_p (code);
-}
-
-/* Return 1 if this is a SIGN_EXTEND or ZERO_EXTEND operation. */
-
-int
-extend_op (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- return GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND;
-}
-
-/* Return nonzero if OP is an operator of mode MODE which can set
- the condition codes explicitly. We do not include PLUS and MINUS
- because these require CC_NOOVmode, which we handle explicitly. */
-
-int
-cc_arithop (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- if (GET_CODE (op) == AND
- || GET_CODE (op) == IOR
- || GET_CODE (op) == XOR)
- return 1;
-
- return 0;
-}
-
-/* Return nonzero if OP is an operator of mode MODE which can bitwise
- complement its second operand and set the condition codes explicitly. */
-
-int
-cc_arithopn (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- /* XOR is not here because combine canonicalizes (xor (not ...) ...)
- and (xor ... (not ...)) to (not (xor ...)). */
- return (GET_CODE (op) == AND
- || GET_CODE (op) == IOR);
-}
-
-/* Return true if OP is a register, or is a CONST_INT that can fit in a
- signed 13 bit immediate field. This is an acceptable SImode operand for
- most 3 address instructions. */
-
-int
-arith_operand (rtx op, enum machine_mode mode)
-{
- if (register_operand (op, mode))
- return 1;
- if (GET_CODE (op) != CONST_INT)
- return 0;
- return SMALL_INT32 (op);
-}
-
-/* Return true if OP is a constant 4096 */
-
-int
-arith_4096_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- if (GET_CODE (op) != CONST_INT)
- return 0;
- else
- return INTVAL (op) == 4096;
-}
-
-/* Return true if OP is suitable as second operand for add/sub */
-
-int
-arith_add_operand (rtx op, enum machine_mode mode)
-{
- return arith_operand (op, mode) || arith_4096_operand (op, mode);
-}
-
-/* Return true if OP is a CONST_INT or a CONST_DOUBLE which can fit in the
- immediate field of OR and XOR instructions. Used for 64-bit
- constant formation patterns. */
-int
-const64_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- return ((GET_CODE (op) == CONST_INT
- && SPARC_SIMM13_P (INTVAL (op)))
-#if HOST_BITS_PER_WIDE_INT != 64
- || (GET_CODE (op) == CONST_DOUBLE
- && SPARC_SIMM13_P (CONST_DOUBLE_LOW (op))
- && (CONST_DOUBLE_HIGH (op) ==
- ((CONST_DOUBLE_LOW (op) & 0x80000000) != 0 ?
- (HOST_WIDE_INT)-1 : 0)))
-#endif
- );
-}
-
-/* The same, but only for sethi instructions. */
-int
-const64_high_operand (rtx op, enum machine_mode mode)
-{
- return ((GET_CODE (op) == CONST_INT
- && (INTVAL (op) & ~(HOST_WIDE_INT)0x3ff) != 0
- && SPARC_SETHI_P (INTVAL (op) & GET_MODE_MASK (mode))
- )
- || (GET_CODE (op) == CONST_DOUBLE
- && CONST_DOUBLE_HIGH (op) == 0
- && (CONST_DOUBLE_LOW (op) & ~(HOST_WIDE_INT)0x3ff) != 0
- && SPARC_SETHI_P (CONST_DOUBLE_LOW (op))));
-}
-
-/* Return true if OP is a register, or is a CONST_INT that can fit in a
- signed 11 bit immediate field. This is an acceptable SImode operand for
- the movcc instructions. */
-
-int
-arith11_operand (rtx op, enum machine_mode mode)
-{
- return (register_operand (op, mode)
- || (GET_CODE (op) == CONST_INT && SPARC_SIMM11_P (INTVAL (op))));
-}
-
-/* Return true if OP is a register, or is a CONST_INT that can fit in a
- signed 10 bit immediate field. This is an acceptable SImode operand for
- the movrcc instructions. */
-
-int
-arith10_operand (rtx op, enum machine_mode mode)
-{
- return (register_operand (op, mode)
- || (GET_CODE (op) == CONST_INT && SPARC_SIMM10_P (INTVAL (op))));
-}
-
-/* Return true if OP is a register, is a CONST_INT that fits in a 13 bit
- immediate field, or is a CONST_DOUBLE whose both parts fit in a 13 bit
- immediate field.
- v9: Return true if OP is a register, or is a CONST_INT or CONST_DOUBLE that
- can fit in a 13 bit immediate field. This is an acceptable DImode operand
- for most 3 address instructions. */
-
-int
-arith_double_operand (rtx op, enum machine_mode mode)
-{
- return (register_operand (op, mode)
- || (GET_CODE (op) == CONST_INT && SMALL_INT (op))
- || (! TARGET_ARCH64
- && GET_CODE (op) == CONST_DOUBLE
- && (unsigned HOST_WIDE_INT) (CONST_DOUBLE_LOW (op) + 0x1000) < 0x2000
- && (unsigned HOST_WIDE_INT) (CONST_DOUBLE_HIGH (op) + 0x1000) < 0x2000)
- || (TARGET_ARCH64
- && GET_CODE (op) == CONST_DOUBLE
- && (unsigned HOST_WIDE_INT) (CONST_DOUBLE_LOW (op) + 0x1000) < 0x2000
- && ((CONST_DOUBLE_HIGH (op) == -1
- && (CONST_DOUBLE_LOW (op) & 0x1000) == 0x1000)
- || (CONST_DOUBLE_HIGH (op) == 0
- && (CONST_DOUBLE_LOW (op) & 0x1000) == 0))));
-}
-
-/* Return true if OP is a constant 4096 for DImode on ARCH64 */
-
-int
-arith_double_4096_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- return (TARGET_ARCH64 &&
- ((GET_CODE (op) == CONST_INT && INTVAL (op) == 4096) ||
- (GET_CODE (op) == CONST_DOUBLE &&
- CONST_DOUBLE_LOW (op) == 4096 &&
- CONST_DOUBLE_HIGH (op) == 0)));
-}
-
-/* Return true if OP is suitable as second operand for add/sub in DImode */
-
-int
-arith_double_add_operand (rtx op, enum machine_mode mode)
-{
- return arith_double_operand (op, mode) || arith_double_4096_operand (op, mode);
-}
-
-/* Return true if OP is a register, or is a CONST_INT or CONST_DOUBLE that
- can fit in an 11 bit immediate field. This is an acceptable DImode
- operand for the movcc instructions. */
-/* ??? Replace with arith11_operand? */
-
-int
-arith11_double_operand (rtx op, enum machine_mode mode)
-{
- return (register_operand (op, mode)
- || (GET_CODE (op) == CONST_DOUBLE
- && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)
- && (unsigned HOST_WIDE_INT) (CONST_DOUBLE_LOW (op) + 0x400) < 0x800
- && ((CONST_DOUBLE_HIGH (op) == -1
- && (CONST_DOUBLE_LOW (op) & 0x400) == 0x400)
- || (CONST_DOUBLE_HIGH (op) == 0
- && (CONST_DOUBLE_LOW (op) & 0x400) == 0)))
- || (GET_CODE (op) == CONST_INT
- && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)
- && (unsigned HOST_WIDE_INT) (INTVAL (op) + 0x400) < 0x800));
-}
-
-/* Return true if OP is a register, or is a CONST_INT or CONST_DOUBLE that
- can fit in an 10 bit immediate field. This is an acceptable DImode
- operand for the movrcc instructions. */
-/* ??? Replace with arith10_operand? */
-
-int
-arith10_double_operand (rtx op, enum machine_mode mode)
-{
- return (register_operand (op, mode)
- || (GET_CODE (op) == CONST_DOUBLE
- && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)
- && (unsigned) (CONST_DOUBLE_LOW (op) + 0x200) < 0x400
- && ((CONST_DOUBLE_HIGH (op) == -1
- && (CONST_DOUBLE_LOW (op) & 0x200) == 0x200)
- || (CONST_DOUBLE_HIGH (op) == 0
- && (CONST_DOUBLE_LOW (op) & 0x200) == 0)))
- || (GET_CODE (op) == CONST_INT
- && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)
- && (unsigned HOST_WIDE_INT) (INTVAL (op) + 0x200) < 0x400));
-}
-
-/* Return truth value of whether OP is an integer which fits the
- range constraining immediate operands in most three-address insns,
- which have a 13 bit immediate field. */
-
-int
-small_int (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- return (GET_CODE (op) == CONST_INT && SMALL_INT (op));
-}
-
-int
-small_int_or_double (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- return ((GET_CODE (op) == CONST_INT && SMALL_INT (op))
- || (GET_CODE (op) == CONST_DOUBLE
- && CONST_DOUBLE_HIGH (op) == 0
- && SPARC_SIMM13_P (CONST_DOUBLE_LOW (op))));
-}
-
-/* Recognize operand values for the umul instruction. That instruction sign
- extends immediate values just like all other sparc instructions, but
- interprets the extended result as an unsigned number. */
-
-int
-uns_small_int (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-#if HOST_BITS_PER_WIDE_INT > 32
- /* All allowed constants will fit a CONST_INT. */
- return (GET_CODE (op) == CONST_INT
- && ((INTVAL (op) >= 0 && INTVAL (op) < 0x1000)
- || (INTVAL (op) >= 0xFFFFF000
- && INTVAL (op) <= 0xFFFFFFFF)));
-#else
- return ((GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 0x1000)
- || (GET_CODE (op) == CONST_DOUBLE
- && CONST_DOUBLE_HIGH (op) == 0
- && (unsigned) CONST_DOUBLE_LOW (op) - 0xFFFFF000 < 0x1000));
-#endif
-}
-
-int
-uns_arith_operand (rtx op, enum machine_mode mode)
-{
- return register_operand (op, mode) || uns_small_int (op, mode);
-}
-
-/* Return truth value of statement that OP is a call-clobbered register. */
-int
-clobbered_register (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
- return (GET_CODE (op) == REG && call_used_regs[REGNO (op)]);
-}
-
-/* Return 1 if OP is a valid operand for the source of a move insn. */
-
-int
-input_operand (rtx op, enum machine_mode mode)
-{
- /* If both modes are non-void they must be the same. */
- if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
- return 0;
-
- /* Accept CONSTANT_P_RTX, since it will be gone by CSE1 and result in 0/1. */
- if (GET_CODE (op) == CONSTANT_P_RTX)
- return 1;
+ /* We can clear FP registers if TARGET_VIS, and always other regs. */
+ if ((TARGET_VIS || REGNO (operands[0]) < SPARC_FIRST_FP_REG)
+ && const_zero_operand (operands[1], mode))
+ return false;
- /* Allow any one instruction integer constant, and all CONST_INT
- variants when we are working in DImode and !arch64. */
- if (GET_MODE_CLASS (mode) == MODE_INT
- && ((GET_CODE (op) == CONST_INT
- && (SPARC_SETHI_P (INTVAL (op) & GET_MODE_MASK (mode))
- || SPARC_SIMM13_P (INTVAL (op))
- || (mode == DImode
- && ! TARGET_ARCH64)))
- || (TARGET_ARCH64
- && GET_CODE (op) == CONST_DOUBLE
- && ((CONST_DOUBLE_HIGH (op) == 0
- && SPARC_SETHI_P (CONST_DOUBLE_LOW (op)))
- ||
-#if HOST_BITS_PER_WIDE_INT == 64
- (CONST_DOUBLE_HIGH (op) == 0
- && SPARC_SIMM13_P (CONST_DOUBLE_LOW (op)))
-#else
- (SPARC_SIMM13_P (CONST_DOUBLE_LOW (op))
- && (((CONST_DOUBLE_LOW (op) & 0x80000000) == 0
- && CONST_DOUBLE_HIGH (op) == 0)
- || (CONST_DOUBLE_HIGH (op) == -1
- && CONST_DOUBLE_LOW (op) & 0x80000000) != 0))
-#endif
- ))))
- return 1;
+ if (REGNO (operands[0]) < SPARC_FIRST_FP_REG
+ /* We are able to build any SF constant in integer registers
+ with at most 2 instructions. */
+ && (mode == SFmode
+ /* And any DF constant in integer registers. */
+ || (mode == DFmode
+ && (reload_completed || reload_in_progress))))
+ return false;
- /* If !arch64 and this is a DImode const, allow it so that
- the splits can be generated. */
- if (! TARGET_ARCH64
- && mode == DImode
- && GET_CODE (op) == CONST_DOUBLE)
- return 1;
+ operands[1] = force_const_mem (mode, operands[1]);
+ if (!reload_in_progress)
+ operands[1] = validize_mem (operands[1]);
+ return false;
+ }
- if (register_operand (op, mode))
- return 1;
+ /* Accept non-constants and valid constants unmodified. */
+ if (!CONSTANT_P (operands[1])
+ || GET_CODE (operands[1]) == HIGH
+ || input_operand (operands[1], mode))
+ return false;
- if (GET_MODE_CLASS (mode) == MODE_FLOAT
- && GET_CODE (op) == CONST_DOUBLE)
- return 1;
+ switch (mode)
+ {
+ case QImode:
+ /* All QImode constants require only one insn, so proceed. */
+ break;
- /* If this is a SUBREG, look inside so that we handle
- paradoxical ones. */
- if (GET_CODE (op) == SUBREG)
- op = SUBREG_REG (op);
+ case HImode:
+ case SImode:
+ sparc_emit_set_const32 (operands[0], operands[1]);
+ return true;
- /* Check for valid MEM forms. */
- if (GET_CODE (op) == MEM)
- return memory_address_p (mode, XEXP (op, 0));
+ case DImode:
+ /* input_operand should have filtered out 32-bit mode. */
+ sparc_emit_set_const64 (operands[0], operands[1]);
+ return true;
+
+ default:
+ gcc_unreachable ();
+ }
- return 0;
+ return false;
}
-/* Return 1 if OP is valid for the lhs of a compare insn. */
-
-int
-compare_operand (rtx op, enum machine_mode mode)
-{
- if (GET_CODE (op) == ZERO_EXTRACT)
- return (register_operand (XEXP (op, 0), mode)
- && small_int_or_double (XEXP (op, 1), mode)
- && small_int_or_double (XEXP (op, 2), mode)
- /* This matches cmp_zero_extract. */
- && ((mode == SImode
- && ((GET_CODE (XEXP (op, 2)) == CONST_INT
- && INTVAL (XEXP (op, 2)) > 19)
- || (GET_CODE (XEXP (op, 2)) == CONST_DOUBLE
- && CONST_DOUBLE_LOW (XEXP (op, 2)) > 19)))
- /* This matches cmp_zero_extract_sp64. */
- || (mode == DImode
- && TARGET_ARCH64
- && ((GET_CODE (XEXP (op, 2)) == CONST_INT
- && INTVAL (XEXP (op, 2)) > 51)
- || (GET_CODE (XEXP (op, 2)) == CONST_DOUBLE
- && CONST_DOUBLE_LOW (XEXP (op, 2)) > 51)))));
- else
- return register_operand (op, mode);
-}
+/* Load OP1, a 32-bit constant, into OP0, a register.
+ We know it can't be done in one insn when we get
+ here, the move expander guarantees this. */
-
-/* We know it can't be done in one insn when we get here,
- the movsi expander guarantees this. */
void
sparc_emit_set_const32 (rtx op0, rtx op1)
{
enum machine_mode mode = GET_MODE (op0);
rtx temp;
- if (GET_CODE (op1) == CONST_INT)
- {
- HOST_WIDE_INT value = INTVAL (op1);
-
- if (SPARC_SETHI_P (value & GET_MODE_MASK (mode))
- || SPARC_SIMM13_P (value))
- abort ();
- }
-
- /* Full 2-insn decomposition is needed. */
if (reload_in_progress || reload_completed)
temp = op0;
else
@@ -1374,20 +1069,15 @@ sparc_emit_set_const32 (rtx op0, rtx op1)
if (GET_CODE (op1) == CONST_INT)
{
+ gcc_assert (!small_int_operand (op1, mode)
+ && !const_high_operand (op1, mode));
+
/* Emit them as real moves instead of a HIGH/LO_SUM,
this way CSE can see everything and reuse intermediate
values if it wants. */
- if (TARGET_ARCH64
- && HOST_BITS_PER_WIDE_INT != 64
- && (INTVAL (op1) & 0x80000000) != 0)
- emit_insn (gen_rtx_SET
- (VOIDmode, temp,
- immed_double_const (INTVAL (op1) & ~(HOST_WIDE_INT)0x3ff,
- 0, DImode)));
- else
- emit_insn (gen_rtx_SET (VOIDmode, temp,
- GEN_INT (INTVAL (op1)
- & ~(HOST_WIDE_INT)0x3ff)));
+ emit_insn (gen_rtx_SET (VOIDmode, temp,
+ GEN_INT (INTVAL (op1)
+ & ~(HOST_WIDE_INT)0x3ff)));
emit_insn (gen_rtx_SET (VOIDmode,
op0,
@@ -1401,17 +1091,16 @@ sparc_emit_set_const32 (rtx op0, rtx op1)
gen_rtx_HIGH (mode, op1)));
emit_insn (gen_rtx_SET (VOIDmode,
op0, gen_rtx_LO_SUM (mode, temp, op1)));
-
}
}
-
/* Load OP1, a symbolic 64-bit constant, into OP0, a DImode register.
- If TEMP is non-zero, we are forbidden to use any other scratch
+ If TEMP is nonzero, we are forbidden to use any other scratch
registers. Otherwise, we are allowed to generate them as needed.
Note that TEMP may have TImode if the code model is TARGET_CM_MEDANY
or TARGET_CM_EMBMEDANY (see the reload_indi and reload_outdi patterns). */
+
void
sparc_emit_set_symbolic_const64 (rtx op0, rtx op1, rtx temp)
{
@@ -1502,10 +1191,8 @@ sparc_emit_set_symbolic_const64 (rtx op0, rtx op1, rtx temp)
it TImode). Pick the other one to use as our scratch. */
if (rtx_equal_p (temp, op0))
{
- if (ti_temp)
- temp = gen_rtx_REG (DImode, REGNO (temp) + 1);
- else
- abort();
+ gcc_assert (ti_temp);
+ temp = gen_rtx_REG (DImode, REGNO (temp) + 1);
}
temp1 = op0;
temp2 = temp; /* op0 is _not_ allowed, see above. */
@@ -1576,10 +1263,8 @@ sparc_emit_set_symbolic_const64 (rtx op0, rtx op1, rtx temp)
it TImode). Pick the other one to use as our scratch. */
if (rtx_equal_p (temp, op0))
{
- if (ti_temp)
- temp = gen_rtx_REG (DImode, REGNO (temp) + 1);
- else
- abort();
+ gcc_assert (ti_temp);
+ temp = gen_rtx_REG (DImode, REGNO (temp) + 1);
}
temp1 = op0;
temp2 = temp; /* op0 is _not_ allowed, see above. */
@@ -1608,56 +1293,52 @@ sparc_emit_set_symbolic_const64 (rtx op0, rtx op1, rtx temp)
break;
default:
- abort();
+ gcc_unreachable ();
}
}
+#if HOST_BITS_PER_WIDE_INT == 32
+void
+sparc_emit_set_const64 (rtx op0 ATTRIBUTE_UNUSED, rtx op1 ATTRIBUTE_UNUSED)
+{
+ gcc_unreachable ();
+}
+#else
/* These avoid problems when cross compiling. If we do not
go through all this hair then the optimizer will see
invalid REG_EQUAL notes or in some cases none at all. */
-static void sparc_emit_set_safe_HIGH64 (rtx, HOST_WIDE_INT);
+static rtx gen_safe_HIGH64 (rtx, HOST_WIDE_INT);
static rtx gen_safe_SET64 (rtx, HOST_WIDE_INT);
static rtx gen_safe_OR64 (rtx, HOST_WIDE_INT);
static rtx gen_safe_XOR64 (rtx, HOST_WIDE_INT);
-#if HOST_BITS_PER_WIDE_INT == 64
-#define GEN_HIGHINT64(__x) GEN_INT ((__x) & ~(HOST_WIDE_INT)0x3ff)
-#define GEN_INT64(__x) GEN_INT (__x)
-#else
-#define GEN_HIGHINT64(__x) \
- immed_double_const ((__x) & ~(HOST_WIDE_INT)0x3ff, 0, DImode)
-#define GEN_INT64(__x) \
- immed_double_const ((__x) & 0xffffffff, \
- ((__x) & 0x80000000 ? -1 : 0), DImode)
-#endif
-
/* The optimizer is not to assume anything about exactly
which bits are set for a HIGH, they are unspecified.
Unfortunately this leads to many missed optimizations
during CSE. We mask out the non-HIGH bits, and matches
a plain movdi, to alleviate this problem. */
-static void
-sparc_emit_set_safe_HIGH64 (rtx dest, HOST_WIDE_INT val)
+static rtx
+gen_safe_HIGH64 (rtx dest, HOST_WIDE_INT val)
{
- emit_insn (gen_rtx_SET (VOIDmode, dest, GEN_HIGHINT64 (val)));
+ return gen_rtx_SET (VOIDmode, dest, GEN_INT (val & ~(HOST_WIDE_INT)0x3ff));
}
static rtx
gen_safe_SET64 (rtx dest, HOST_WIDE_INT val)
{
- return gen_rtx_SET (VOIDmode, dest, GEN_INT64 (val));
+ return gen_rtx_SET (VOIDmode, dest, GEN_INT (val));
}
static rtx
gen_safe_OR64 (rtx src, HOST_WIDE_INT val)
{
- return gen_rtx_IOR (DImode, src, GEN_INT64 (val));
+ return gen_rtx_IOR (DImode, src, GEN_INT (val));
}
static rtx
gen_safe_XOR64 (rtx src, HOST_WIDE_INT val)
{
- return gen_rtx_XOR (DImode, src, GEN_INT64 (val));
+ return gen_rtx_XOR (DImode, src, GEN_INT (val));
}
/* Worker routines for 64-bit constant formation on arch64.
@@ -1682,7 +1363,7 @@ sparc_emit_set_const64_quick1 (rtx op0, rtx temp,
else
high_bits = low_bits;
- sparc_emit_set_safe_HIGH64 (temp, high_bits);
+ emit_insn (gen_safe_HIGH64 (temp, high_bits));
if (!is_neg)
{
emit_insn (gen_rtx_SET (VOIDmode, op0,
@@ -1721,7 +1402,7 @@ sparc_emit_set_const64_quick2 (rtx op0, rtx temp,
if ((high_bits & 0xfffffc00) != 0)
{
- sparc_emit_set_safe_HIGH64 (temp, high_bits);
+ emit_insn (gen_safe_HIGH64 (temp, high_bits));
if ((high_bits & ~0xfffffc00) != 0)
emit_insn (gen_rtx_SET (VOIDmode, op0,
gen_safe_OR64 (temp, (high_bits & 0x3ff))));
@@ -1765,7 +1446,7 @@ sparc_emit_set_const64_longway (rtx op0, rtx temp,
if ((high_bits & 0xfffffc00) != 0)
{
- sparc_emit_set_safe_HIGH64 (temp, high_bits);
+ emit_insn (gen_safe_HIGH64 (temp, high_bits));
if ((high_bits & ~0xfffffc00) != 0)
emit_insn (gen_rtx_SET (VOIDmode,
sub_temp,
@@ -1789,7 +1470,7 @@ sparc_emit_set_const64_longway (rtx op0, rtx temp,
gen_rtx_ASHIFT (DImode, sub_temp,
GEN_INT (32))));
- sparc_emit_set_safe_HIGH64 (temp2, low_bits);
+ emit_insn (gen_safe_HIGH64 (temp2, low_bits));
if ((low_bits & ~0xfffffc00) != 0)
{
emit_insn (gen_rtx_SET (VOIDmode, temp3,
@@ -1896,9 +1577,7 @@ analyze_64bit_constant (unsigned HOST_WIDE_INT high_bits,
}
/* If there are no bits set this should have gone out
as one instruction! */
- if (lowest_bit_set == -1
- || highest_bit_set == -1)
- abort ();
+ gcc_assert (lowest_bit_set != -1 && highest_bit_set != -1);
all_bits_between_are_set = 1;
for (i = lowest_bit_set; i <= highest_bit_set; i++)
{
@@ -1968,8 +1647,7 @@ create_simple_focus_bits (unsigned HOST_WIDE_INT high_bits,
lo = 0;
hi = ((high_bits >> (lowest_bit_set - 32)) << shift);
}
- if (hi & lo)
- abort ();
+ gcc_assert (! (hi & lo));
return (hi | lo);
}
@@ -1986,22 +1664,14 @@ sparc_emit_set_const64 (rtx op0, rtx op1)
rtx temp = 0;
/* Sanity check that we know what we are working with. */
- if (! TARGET_ARCH64)
- abort ();
-
- if (GET_CODE (op0) != SUBREG)
- {
- if (GET_CODE (op0) != REG
- || (REGNO (op0) >= SPARC_FIRST_FP_REG
- && REGNO (op0) <= SPARC_LAST_V9_FP_REG))
- abort ();
- }
+ gcc_assert (TARGET_ARCH64
+ && (GET_CODE (op0) == SUBREG
+ || (REG_P (op0) && ! SPARC_FP_REG_P (REGNO (op0)))));
if (reload_in_progress || reload_completed)
temp = op0;
- if (GET_CODE (op1) != CONST_DOUBLE
- && GET_CODE (op1) != CONST_INT)
+ if (GET_CODE (op1) != CONST_INT)
{
sparc_emit_set_symbolic_const64 (op0, op1, temp);
return;
@@ -2010,28 +1680,8 @@ sparc_emit_set_const64 (rtx op0, rtx op1)
if (! temp)
temp = gen_reg_rtx (DImode);
- if (GET_CODE (op1) == CONST_DOUBLE)
- {
-#if HOST_BITS_PER_WIDE_INT == 64
- high_bits = (CONST_DOUBLE_LOW (op1) >> 32) & 0xffffffff;
- low_bits = CONST_DOUBLE_LOW (op1) & 0xffffffff;
-#else
- high_bits = CONST_DOUBLE_HIGH (op1);
- low_bits = CONST_DOUBLE_LOW (op1);
-#endif
- }
- else
- {
-#if HOST_BITS_PER_WIDE_INT == 64
- high_bits = ((INTVAL (op1) >> 32) & 0xffffffff);
- low_bits = (INTVAL (op1) & 0xffffffff);
-#else
- high_bits = ((INTVAL (op1) < 0) ?
- 0xffffffff :
- 0x00000000);
- low_bits = INTVAL (op1);
-#endif
- }
+ high_bits = ((INTVAL (op1) >> 32) & 0xffffffff);
+ low_bits = (INTVAL (op1) & 0xffffffff);
/* low_bits bits 0 --> 31
high_bits bits 32 --> 63 */
@@ -2070,8 +1720,8 @@ sparc_emit_set_const64 (rtx op0, rtx op1)
else if (lowest_bit_set == 0)
shift = -(63 - highest_bit_set);
- if (! SPARC_SIMM13_P (the_const))
- abort ();
+ gcc_assert (SPARC_SIMM13_P (the_const));
+ gcc_assert (shift != 0);
emit_insn (gen_safe_SET64 (temp, the_const));
if (shift > 0)
@@ -2086,8 +1736,6 @@ sparc_emit_set_const64 (rtx op0, rtx op1)
gen_rtx_LSHIFTRT (DImode,
temp,
GEN_INT (-shift))));
- else
- abort ();
return;
}
@@ -2103,10 +1751,10 @@ sparc_emit_set_const64 (rtx op0, rtx op1)
create_simple_focus_bits (high_bits, low_bits,
lowest_bit_set, 10);
- if (! SPARC_SETHI_P (focus_bits))
- abort ();
+ gcc_assert (SPARC_SETHI_P (focus_bits));
+ gcc_assert (lowest_bit_set != 10);
- sparc_emit_set_safe_HIGH64 (temp, focus_bits);
+ emit_insn (gen_safe_HIGH64 (temp, focus_bits));
/* If lowest_bit_set == 10 then a sethi alone could have done it. */
if (lowest_bit_set < 10)
@@ -2119,8 +1767,6 @@ sparc_emit_set_const64 (rtx op0, rtx op1)
op0,
gen_rtx_ASHIFT (DImode, temp,
GEN_INT (lowest_bit_set - 10))));
- else
- abort ();
return;
}
@@ -2163,26 +1809,20 @@ sparc_emit_set_const64 (rtx op0, rtx op1)
|| (((~high_bits) & 0xffffffff) == 0xffffffff
&& ((~low_bits) & 0x80000000) != 0))
{
- int fast_int = (~low_bits & 0xffffffff);
+ unsigned HOST_WIDE_INT fast_int = (~low_bits & 0xffffffff);
if ((SPARC_SETHI_P (fast_int)
&& (~high_bits & 0xffffffff) == 0)
|| SPARC_SIMM13_P (fast_int))
emit_insn (gen_safe_SET64 (temp, fast_int));
else
- sparc_emit_set_const64 (temp, GEN_INT64 (fast_int));
+ sparc_emit_set_const64 (temp, GEN_INT (fast_int));
}
else
{
rtx negated_const;
-#if HOST_BITS_PER_WIDE_INT == 64
negated_const = GEN_INT (((~low_bits) & 0xfffffc00) |
(((HOST_WIDE_INT)((~high_bits) & 0xffffffff))<<32));
-#else
- negated_const = immed_double_const ((~low_bits) & 0xfffffc00,
- (~high_bits) & 0xffffffff,
- DImode);
-#endif
sparc_emit_set_const64 (temp, negated_const);
}
@@ -2218,9 +1858,7 @@ sparc_emit_set_const64 (rtx op0, rtx op1)
lowest_bit_set, 0);
/* We can't get here in this state. */
- if (highest_bit_set < 32
- || lowest_bit_set >= 32)
- abort ();
+ gcc_assert (highest_bit_set >= 32 && lowest_bit_set < 32);
/* So what we know is that the set bits straddle the
middle of the 64-bit word. */
@@ -2249,6 +1887,7 @@ sparc_emit_set_const64 (rtx op0, rtx op1)
#endif
sparc_emit_set_const64_longway (op0, temp, high_bits, low_bits);
}
+#endif /* HOST_BITS_PER_WIDE_INT == 32 */
/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
return the mode to be used for the comparison. For floating-point,
@@ -2282,7 +1921,7 @@ select_cc_mode (enum rtx_code op, rtx x, rtx y ATTRIBUTE_UNUSED)
return CCFPEmode;
default:
- abort ();
+ gcc_unreachable ();
}
}
else if (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS
@@ -2306,11 +1945,20 @@ select_cc_mode (enum rtx_code op, rtx x, rtx y ATTRIBUTE_UNUSED)
return the rtx for the cc reg in the proper mode. */
rtx
-gen_compare_reg (enum rtx_code code, rtx x, rtx y)
+gen_compare_reg (enum rtx_code code)
{
+ rtx x = sparc_compare_op0;
+ rtx y = sparc_compare_op1;
enum machine_mode mode = SELECT_CC_MODE (code, x, y);
rtx cc_reg;
+ if (sparc_compare_emitted != NULL_RTX)
+ {
+ cc_reg = sparc_compare_emitted;
+ sparc_compare_emitted = NULL_RTX;
+ return cc_reg;
+ }
+
/* ??? We don't have movcc patterns so we cannot generate pseudo regs for the
fcc regs (cse can't tell they're really call clobbered regs and will
remove a duplicate comparison even if there is an intervening function
@@ -2389,22 +2037,20 @@ gen_compare_reg (enum rtx_code code, rtx x, rtx y)
int
gen_v9_scc (enum rtx_code compare_code, register rtx *operands)
{
- rtx temp, op0, op1;
-
if (! TARGET_ARCH64
&& (GET_MODE (sparc_compare_op0) == DImode
|| GET_MODE (operands[0]) == DImode))
return 0;
- op0 = sparc_compare_op0;
- op1 = sparc_compare_op1;
-
/* Try to use the movrCC insns. */
if (TARGET_ARCH64
- && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
- && op1 == const0_rtx
+ && GET_MODE_CLASS (GET_MODE (sparc_compare_op0)) == MODE_INT
+ && sparc_compare_op1 == const0_rtx
&& v9_regcmp_p (compare_code))
{
+ rtx op0 = sparc_compare_op0;
+ rtx temp;
+
/* Special case for op0 != 0. This can be done with one instruction if
operands[0] == sparc_compare_op0. */
@@ -2447,7 +2093,7 @@ gen_v9_scc (enum rtx_code compare_code, register rtx *operands)
}
else
{
- operands[1] = gen_compare_reg (compare_code, op0, op1);
+ operands[1] = gen_compare_reg (compare_code);
switch (GET_MODE (operands[1]))
{
@@ -2457,7 +2103,7 @@ gen_v9_scc (enum rtx_code compare_code, register rtx *operands)
case CCFPmode :
break;
default :
- abort ();
+ gcc_unreachable ();
}
emit_insn (gen_rtx_SET (VOIDmode, operands[0], const0_rtx));
emit_insn (gen_rtx_SET (VOIDmode, operands[0],
@@ -2477,6 +2123,7 @@ gen_v9_scc (enum rtx_code compare_code, register rtx *operands)
void
emit_v9_brxx_insn (enum rtx_code code, rtx op0, rtx label)
{
+ gcc_assert (sparc_compare_emitted == NULL_RTX);
emit_jump_insn (gen_rtx_SET (VOIDmode,
pc_rtx,
gen_rtx_IF_THEN_ELSE (VOIDmode,
@@ -2511,8 +2158,7 @@ emit_soft_tfmode_libcall (const char *func_name, int nargs, rtx *operands)
int i;
/* We only expect to be called for conversions, unary, and binary ops. */
- if (nargs < 2 || nargs > 3)
- abort ();
+ gcc_assert (nargs == 2 || nargs == 3);
for (i = 0; i < nargs; ++i)
{
@@ -2575,8 +2221,7 @@ emit_soft_tfmode_libcall (const char *func_name, int nargs, rtx *operands)
{
rtx ret;
- if (nargs != 2)
- abort ();
+ gcc_assert (nargs == 2);
ret = emit_library_call_value (func_sym, operands[0], LCT_NORMAL,
GET_MODE (operands[0]), 1,
@@ -2609,7 +2254,7 @@ emit_soft_tfmode_binop (enum rtx_code code, rtx *operands)
func = "_Qp_div";
break;
default:
- abort ();
+ gcc_unreachable ();
}
emit_soft_tfmode_libcall (func, 3, operands);
@@ -2620,14 +2265,8 @@ emit_soft_tfmode_unop (enum rtx_code code, rtx *operands)
{
const char *func;
- switch (code)
- {
- case SQRT:
- func = "_Qp_sqrt";
- break;
- default:
- abort ();
- }
+ gcc_assert (code == SQRT);
+ func = "_Qp_sqrt";
emit_soft_tfmode_libcall (func, 2, operands);
}
@@ -2649,7 +2288,7 @@ emit_soft_tfmode_cvt (enum rtx_code code, rtx *operands)
func = "_Qp_dtoq";
break;
default:
- abort ();
+ gcc_unreachable ();
}
break;
@@ -2663,7 +2302,7 @@ emit_soft_tfmode_cvt (enum rtx_code code, rtx *operands)
func = "_Qp_qtod";
break;
default:
- abort ();
+ gcc_unreachable ();
}
break;
@@ -2677,7 +2316,7 @@ emit_soft_tfmode_cvt (enum rtx_code code, rtx *operands)
func = "_Qp_xtoq";
break;
default:
- abort ();
+ gcc_unreachable ();
}
break;
@@ -2691,7 +2330,7 @@ emit_soft_tfmode_cvt (enum rtx_code code, rtx *operands)
func = "_Qp_uxtoq";
break;
default:
- abort ();
+ gcc_unreachable ();
}
break;
@@ -2705,7 +2344,7 @@ emit_soft_tfmode_cvt (enum rtx_code code, rtx *operands)
func = "_Qp_qtox";
break;
default:
- abort ();
+ gcc_unreachable ();
}
break;
@@ -2719,12 +2358,12 @@ emit_soft_tfmode_cvt (enum rtx_code code, rtx *operands)
func = "_Qp_qtoux";
break;
default:
- abort ();
+ gcc_unreachable ();
}
break;
default:
- abort ();
+ gcc_unreachable ();
}
emit_soft_tfmode_libcall (func, 2, operands);
@@ -2738,7 +2377,7 @@ emit_hard_tfmode_operation (enum rtx_code code, rtx *operands)
{
rtx op, dest;
- if (GET_RTX_CLASS (code) == '1')
+ if (GET_RTX_CLASS (code) == RTX_UNARY)
{
operands[1] = force_reg (GET_MODE (operands[1]), operands[1]);
op = gen_rtx_fmt_e (code, GET_MODE (operands[0]), operands[1]);
@@ -2789,14 +2428,6 @@ emit_tfmode_cvt (enum rtx_code code, rtx *operands)
emit_soft_tfmode_cvt (code, operands);
}
-/* Return nonzero if a return peephole merging return with
- setting of output register is ok. */
-int
-leaf_return_peephole_ok (void)
-{
- return (actual_fsize == 0);
-}
-
/* Return nonzero if a branch/jump/call instruction will be emitting
nop into its delay slot. */
@@ -2816,69 +2447,56 @@ empty_delay_slot (rtx insn)
return 1;
}
-/* Return nonzero if TRIAL can go into the function epilogue's
- delay slot. SLOT is the slot we are trying to fill. */
+/* Return nonzero if TRIAL can go into the call delay slot. */
int
-eligible_for_epilogue_delay (rtx trial, int slot)
+tls_call_delay (rtx trial)
{
- rtx pat, src;
-
- if (slot >= 1)
- return 0;
-
- if (GET_CODE (trial) != INSN || GET_CODE (PATTERN (trial)) != SET)
- return 0;
-
- if (get_attr_length (trial) != 1)
- return 0;
+ rtx pat;
- /* If there are any call-saved registers, we should scan TRIAL if it
- does not reference them. For now just make it easy. */
- if (num_gfregs)
- return 0;
+ /* Binutils allows
+ call __tls_get_addr, %tgd_call (foo)
+ add %l7, %o0, %o0, %tgd_add (foo)
+ while Sun as/ld does not. */
+ if (TARGET_GNU_TLS || !TARGET_TLS)
+ return 1;
- /* If the function uses __builtin_eh_return, the eh_return machinery
- occupies the delay slot. */
- if (current_function_calls_eh_return)
- return 0;
+ pat = PATTERN (trial);
- /* In the case of a true leaf function, anything can go into the delay slot.
- A delay slot only exists however if the frame size is zero, otherwise
- we will put an insn to adjust the stack after the return. */
- if (current_function_uses_only_leaf_regs)
+ /* We must reject tgd_add{32|64}, i.e.
+ (set (reg) (plus (reg) (unspec [(reg) (symbol_ref)] UNSPEC_TLSGD)))
+ and tldm_add{32|64}, i.e.
+ (set (reg) (plus (reg) (unspec [(reg) (symbol_ref)] UNSPEC_TLSLDM)))
+ for Sun as/ld. */
+ if (GET_CODE (pat) == SET
+ && GET_CODE (SET_SRC (pat)) == PLUS)
{
- if (leaf_return_peephole_ok ())
- return ((get_attr_in_uncond_branch_delay (trial)
- == IN_BRANCH_DELAY_TRUE));
- return 0;
- }
+ rtx unspec = XEXP (SET_SRC (pat), 1);
- pat = PATTERN (trial);
+ if (GET_CODE (unspec) == UNSPEC
+ && (XINT (unspec, 1) == UNSPEC_TLSGD
+ || XINT (unspec, 1) == UNSPEC_TLSLDM))
+ return 0;
+ }
- /* Otherwise, only operations which can be done in tandem with
- a `restore' or `return' insn can go into the delay slot. */
- if (GET_CODE (SET_DEST (pat)) != REG
- || REGNO (SET_DEST (pat)) < 24)
- return 0;
+ return 1;
+}
- /* If this instruction sets up floating point register and we have a return
- instruction, it can probably go in. But restore will not work
- with FP_REGS. */
- if (REGNO (SET_DEST (pat)) >= 32)
- {
- if (TARGET_V9 && ! epilogue_renumber (&pat, 1)
- && (get_attr_in_uncond_branch_delay (trial) == IN_BRANCH_DELAY_TRUE))
- return 1;
- return 0;
- }
+/* Return nonzero if TRIAL, an insn, can be combined with a 'restore'
+ instruction. RETURN_P is true if the v9 variant 'return' is to be
+ considered in the test too.
- /* The set of insns matched here must agree precisely with the set of
- patterns paired with a RETURN in sparc.md. */
+ TRIAL must be a SET whose destination is a REG appropriate for the
+ 'restore' instruction or, if RETURN_P is true, for the 'return'
+ instruction. */
- src = SET_SRC (pat);
+static int
+eligible_for_restore_insn (rtx trial, bool return_p)
+{
+ rtx pat = PATTERN (trial);
+ rtx src = SET_SRC (pat);
- /* This matches "*return_[qhs]i" or even "*return_di" on TARGET_ARCH64. */
+ /* The 'restore src,%g0,dest' pattern for word mode and below. */
if (GET_MODE_CLASS (GET_MODE (src)) != MODE_FLOAT
&& arith_operand (src, GET_MODE (src)))
{
@@ -2888,41 +2506,39 @@ eligible_for_epilogue_delay (rtx trial, int slot)
return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (SImode);
}
- /* This matches "*return_di". */
+ /* The 'restore src,%g0,dest' pattern for double-word mode. */
else if (GET_MODE_CLASS (GET_MODE (src)) != MODE_FLOAT
&& arith_double_operand (src, GET_MODE (src)))
return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode);
- /* This matches "*return_sf_no_fpu". */
- else if (! TARGET_FPU && restore_operand (SET_DEST (pat), SFmode)
- && register_operand (src, SFmode))
+ /* The 'restore src,%g0,dest' pattern for float if no FPU. */
+ else if (! TARGET_FPU && register_operand (src, SFmode))
+ return 1;
+
+ /* The 'restore src,%g0,dest' pattern for double if no FPU. */
+ else if (! TARGET_FPU && TARGET_ARCH64 && register_operand (src, DFmode))
return 1;
- /* If we have return instruction, anything that does not use
+ /* If we have the 'return' instruction, anything that does not use
local or output registers and can go into a delay slot wins. */
- else if (TARGET_V9 && ! epilogue_renumber (&pat, 1)
- && (get_attr_in_uncond_branch_delay (trial) == IN_BRANCH_DELAY_TRUE))
+ else if (return_p && TARGET_V9 && ! epilogue_renumber (&pat, 1)
+ && (get_attr_in_uncond_branch_delay (trial)
+ == IN_UNCOND_BRANCH_DELAY_TRUE))
return 1;
- /* This matches "*return_addsi". */
+ /* The 'restore src1,src2,dest' pattern for SImode. */
else if (GET_CODE (src) == PLUS
- && arith_operand (XEXP (src, 0), SImode)
- && arith_operand (XEXP (src, 1), SImode)
- && (register_operand (XEXP (src, 0), SImode)
- || register_operand (XEXP (src, 1), SImode)))
+ && register_operand (XEXP (src, 0), SImode)
+ && arith_operand (XEXP (src, 1), SImode))
return 1;
- /* This matches "*return_adddi". */
+ /* The 'restore src1,src2,dest' pattern for DImode. */
else if (GET_CODE (src) == PLUS
- && arith_double_operand (XEXP (src, 0), DImode)
- && arith_double_operand (XEXP (src, 1), DImode)
- && (register_operand (XEXP (src, 0), DImode)
- || register_operand (XEXP (src, 1), DImode)))
+ && register_operand (XEXP (src, 0), DImode)
+ && arith_double_operand (XEXP (src, 1), DImode))
return 1;
- /* This can match "*return_losum_[sd]i".
- Catch only some cases, so that return_losum* don't have
- to be too big. */
+ /* The 'restore src1,%lo(src2),dest' pattern. */
else if (GET_CODE (src) == LO_SUM
&& ! TARGET_CM_MEDMID
&& ((register_operand (XEXP (src, 0), SImode)
@@ -2932,7 +2548,7 @@ eligible_for_epilogue_delay (rtx trial, int slot)
&& immediate_operand (XEXP (src, 1), DImode))))
return 1;
- /* sll{,x} reg,1,reg2 is add reg,reg,reg2 as well. */
+ /* The 'restore src,src,dest' pattern. */
else if (GET_CODE (src) == ASHIFT
&& (register_operand (XEXP (src, 0), SImode)
|| register_operand (XEXP (src, 0), DImode))
@@ -2942,47 +2558,62 @@ eligible_for_epilogue_delay (rtx trial, int slot)
return 0;
}
-/* Return nonzero if TRIAL can go into the call delay slot. */
+/* Return nonzero if TRIAL can go into the function return's
+ delay slot. */
+
int
-tls_call_delay (rtx trial)
+eligible_for_return_delay (rtx trial)
{
rtx pat;
- /* Binutils allows
- call __tls_get_addr, %tgd_call (foo)
- add %l7, %o0, %o0, %tgd_add (foo)
- while Sun as/ld does not. */
- if (TARGET_GNU_TLS || !TARGET_TLS)
- return 1;
+ if (GET_CODE (trial) != INSN || GET_CODE (PATTERN (trial)) != SET)
+ return 0;
+
+ if (get_attr_length (trial) != 1)
+ return 0;
+
+ /* If there are any call-saved registers, we should scan TRIAL if it
+ does not reference them. For now just make it easy. */
+ if (num_gfregs)
+ return 0;
+
+ /* If the function uses __builtin_eh_return, the eh_return machinery
+ occupies the delay slot. */
+ if (current_function_calls_eh_return)
+ return 0;
+
+ /* In the case of a true leaf function, anything can go into the slot. */
+ if (sparc_leaf_function_p)
+ return get_attr_in_uncond_branch_delay (trial)
+ == IN_UNCOND_BRANCH_DELAY_TRUE;
pat = PATTERN (trial);
- /* We must reject tgd_add{32|64}, i.e.
- (set (reg) (plus (reg) (unspec [(reg) (symbol_ref)] UNSPEC_TLSGD)))
- and tldm_add{32|64}, i.e.
- (set (reg) (plus (reg) (unspec [(reg) (symbol_ref)] UNSPEC_TLSLDM)))
- for Sun as/ld. */
- if (GET_CODE (pat) == SET
- && GET_CODE (SET_SRC (pat)) == PLUS)
- {
- rtx unspec = XEXP (SET_SRC (pat), 1);
+ /* Otherwise, only operations which can be done in tandem with
+ a `restore' or `return' insn can go into the delay slot. */
+ if (GET_CODE (SET_DEST (pat)) != REG
+ || (REGNO (SET_DEST (pat)) >= 8 && REGNO (SET_DEST (pat)) < 24))
+ return 0;
- if (GET_CODE (unspec) == UNSPEC
- && (XINT (unspec, 1) == UNSPEC_TLSGD
- || XINT (unspec, 1) == UNSPEC_TLSLDM))
- return 0;
- }
+ /* If this instruction sets up floating point register and we have a return
+ instruction, it can probably go in. But restore will not work
+ with FP_REGS. */
+ if (REGNO (SET_DEST (pat)) >= 32)
+ return (TARGET_V9
+ && ! epilogue_renumber (&pat, 1)
+ && (get_attr_in_uncond_branch_delay (trial)
+ == IN_UNCOND_BRANCH_DELAY_TRUE));
- return 1;
+ return eligible_for_restore_insn (trial, true);
}
-/* Return nonzero if TRIAL can go into the sibling call
+/* Return nonzero if TRIAL can go into the sibling call's
delay slot. */
int
eligible_for_sibcall_delay (rtx trial)
{
- rtx pat, src;
+ rtx pat;
if (GET_CODE (trial) != INSN || GET_CODE (PATTERN (trial)) != SET)
return 0;
@@ -2992,11 +2623,11 @@ eligible_for_sibcall_delay (rtx trial)
pat = PATTERN (trial);
- if (current_function_uses_only_leaf_regs)
+ if (sparc_leaf_function_p)
{
/* If the tail call is done using the call instruction,
we have to restore %o7 in the delay slot. */
- if ((TARGET_ARCH64 && ! TARGET_CM_MEDLOW) || flag_pic)
+ if (LEAF_SIBCALL_SLOT_RESERVED_P)
return 0;
/* %g1 is used to build the function address */
@@ -3009,7 +2640,7 @@ eligible_for_sibcall_delay (rtx trial)
/* Otherwise, only operations which can be done in tandem with
a `restore' insn can go into the delay slot. */
if (GET_CODE (SET_DEST (pat)) != REG
- || REGNO (SET_DEST (pat)) < 24
+ || (REGNO (SET_DEST (pat)) >= 8 && REGNO (SET_DEST (pat)) < 24)
|| REGNO (SET_DEST (pat)) >= 32)
return 0;
@@ -3018,89 +2649,7 @@ eligible_for_sibcall_delay (rtx trial)
if (reg_mentioned_p (gen_rtx_REG (Pmode, 15), pat))
return 0;
- src = SET_SRC (pat);
-
- if (GET_MODE_CLASS (GET_MODE (src)) != MODE_FLOAT
- && arith_operand (src, GET_MODE (src)))
- {
- if (TARGET_ARCH64)
- return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode);
- else
- return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (SImode);
- }
-
- else if (GET_MODE_CLASS (GET_MODE (src)) != MODE_FLOAT
- && arith_double_operand (src, GET_MODE (src)))
- return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode);
-
- else if (! TARGET_FPU && restore_operand (SET_DEST (pat), SFmode)
- && register_operand (src, SFmode))
- return 1;
-
- else if (GET_CODE (src) == PLUS
- && arith_operand (XEXP (src, 0), SImode)
- && arith_operand (XEXP (src, 1), SImode)
- && (register_operand (XEXP (src, 0), SImode)
- || register_operand (XEXP (src, 1), SImode)))
- return 1;
-
- else if (GET_CODE (src) == PLUS
- && arith_double_operand (XEXP (src, 0), DImode)
- && arith_double_operand (XEXP (src, 1), DImode)
- && (register_operand (XEXP (src, 0), DImode)
- || register_operand (XEXP (src, 1), DImode)))
- return 1;
-
- else if (GET_CODE (src) == LO_SUM
- && ! TARGET_CM_MEDMID
- && ((register_operand (XEXP (src, 0), SImode)
- && immediate_operand (XEXP (src, 1), SImode))
- || (TARGET_ARCH64
- && register_operand (XEXP (src, 0), DImode)
- && immediate_operand (XEXP (src, 1), DImode))))
- return 1;
-
- else if (GET_CODE (src) == ASHIFT
- && (register_operand (XEXP (src, 0), SImode)
- || register_operand (XEXP (src, 0), DImode))
- && XEXP (src, 1) == const1_rtx)
- return 1;
-
- return 0;
-}
-
-static int
-check_return_regs (rtx x)
-{
- switch (GET_CODE (x))
- {
- case REG:
- return IN_OR_GLOBAL_P (x);
-
- case CONST_INT:
- case CONST_DOUBLE:
- case CONST:
- case SYMBOL_REF:
- case LABEL_REF:
- return 1;
-
- case SET:
- case IOR:
- case AND:
- case XOR:
- case PLUS:
- case MINUS:
- if (check_return_regs (XEXP (x, 1)) == 0)
- return 0;
- case NOT:
- case NEG:
- case MEM:
- return check_return_regs (XEXP (x, 0));
-
- default:
- return 0;
- }
-
+ return eligible_for_restore_insn (trial, false);
}
int
@@ -3132,7 +2681,7 @@ reg_unused_after (rtx reg, rtx insn)
if (GET_CODE (insn) == CODE_LABEL)
return 1;
- if (GET_RTX_CLASS (code) == 'i')
+ if (INSN_P (insn))
{
rtx set = single_set (insn);
int in_src = set && reg_overlap_mentioned_p (reg, SET_SRC (set));
@@ -3159,6 +2708,7 @@ sparc_cannot_force_const_mem (rtx x)
{
case CONST_INT:
case CONST_DOUBLE:
+ case CONST_VECTOR:
/* Accept all non-symbolic constants. */
return false;
@@ -3183,17 +2733,16 @@ sparc_cannot_force_const_mem (rtx x)
case UNSPEC:
return true;
default:
- abort ();
+ gcc_unreachable ();
}
}
-/* The table we use to reference PIC data. */
+/* PIC support. */
+static GTY(()) char pic_helper_symbol_name[256];
+static GTY(()) rtx pic_helper_symbol;
+static GTY(()) bool pic_helper_emitted_p = false;
static GTY(()) rtx global_offset_table;
-/* The function we use to get at it. */
-static GTY(()) rtx get_pc_symbol;
-static GTY(()) char get_pc_symbol_name[256];
-
/* Ensure that we are not using patterns that are not OK with PIC. */
int
@@ -3202,14 +2751,13 @@ check_pic (int i)
switch (flag_pic)
{
case 1:
- if (GET_CODE (recog_data.operand[i]) == SYMBOL_REF
- || (GET_CODE (recog_data.operand[i]) == CONST
- && ! (GET_CODE (XEXP (recog_data.operand[i], 0)) == MINUS
- && (XEXP (XEXP (recog_data.operand[i], 0), 0)
- == global_offset_table)
- && (GET_CODE (XEXP (XEXP (recog_data.operand[i], 0), 1))
- == CONST))))
- abort ();
+ gcc_assert (GET_CODE (recog_data.operand[i]) != SYMBOL_REF
+ && (GET_CODE (recog_data.operand[i]) != CONST
+ || (GET_CODE (XEXP (recog_data.operand[i], 0)) == MINUS
+ && (XEXP (XEXP (recog_data.operand[i], 0), 0)
+ == global_offset_table)
+ && (GET_CODE (XEXP (XEXP (recog_data.operand[i], 0), 1))
+ == CONST))));
case 2:
default:
return 1;
@@ -3254,7 +2802,7 @@ legitimate_constant_p (rtx x)
/* Offsets of TLS symbols are never valid.
Discourage CSE from creating them. */
if (GET_CODE (inner) == PLUS
- && tls_symbolic_operand (XEXP (inner, 0)))
+ && SPARC_SYMBOL_REF_TLS_P (XEXP (inner, 0)))
return false;
break;
@@ -3265,10 +2813,17 @@ legitimate_constant_p (rtx x)
/* Floating point constants are generally not ok.
The only exception is 0.0 in VIS. */
if (TARGET_VIS
- && (GET_MODE (x) == SFmode
- || GET_MODE (x) == DFmode
- || GET_MODE (x) == TFmode)
- && fp_zero_operand (x, GET_MODE (x)))
+ && SCALAR_FLOAT_MODE_P (GET_MODE (x))
+ && const_zero_operand (x, GET_MODE (x)))
+ return true;
+
+ return false;
+
+ case CONST_VECTOR:
+ /* Vector constants are generally not ok.
+ The only exception is 0 in VIS. */
+ if (TARGET_VIS
+ && const_zero_operand (x, GET_MODE (x)))
return true;
return false;
@@ -3314,10 +2869,10 @@ legitimate_pic_operand_p (rtx x)
{
if (pic_address_needs_scratch (x))
return false;
- if (tls_symbolic_operand (x)
+ if (SPARC_SYMBOL_REF_TLS_P (x)
|| (GET_CODE (x) == CONST
&& GET_CODE (XEXP (x, 0)) == PLUS
- && tls_symbolic_operand (XEXP (XEXP (x, 0), 0))))
+ && SPARC_SYMBOL_REF_TLS_P (XEXP (XEXP (x, 0), 0))))
return false;
return true;
}
@@ -3355,7 +2910,7 @@ legitimate_address_p (enum machine_mode mode, rtx addr, int strict)
&& GET_CODE (rs2) != SUBREG
&& GET_CODE (rs2) != LO_SUM
&& GET_CODE (rs2) != MEM
- && !tls_symbolic_operand (rs2)
+ && ! SPARC_SYMBOL_REF_TLS_P (rs2)
&& (! symbolic_operand (rs2, VOIDmode) || mode == Pmode)
&& (GET_CODE (rs2) != CONST_INT || SMALL_INT (rs2)))
|| ((REG_P (rs1)
@@ -3395,7 +2950,7 @@ legitimate_address_p (enum machine_mode mode, rtx addr, int strict)
rs2 = NULL;
imm1 = XEXP (rs1, 1);
rs1 = XEXP (rs1, 0);
- if (! CONSTANT_P (imm1) || tls_symbolic_operand (rs1))
+ if (! CONSTANT_P (imm1) || SPARC_SYMBOL_REF_TLS_P (rs1))
return 0;
}
}
@@ -3404,7 +2959,7 @@ legitimate_address_p (enum machine_mode mode, rtx addr, int strict)
rs1 = XEXP (addr, 0);
imm1 = XEXP (addr, 1);
- if (! CONSTANT_P (imm1) || tls_symbolic_operand (rs1))
+ if (! CONSTANT_P (imm1) || SPARC_SYMBOL_REF_TLS_P (rs1))
return 0;
/* We can't allow TFmode in 32-bit mode, because an offset greater
@@ -3453,6 +3008,7 @@ legitimate_address_p (enum machine_mode mode, rtx addr, int strict)
/* Construct the SYMBOL_REF for the tls_get_offset function. */
static GTY(()) rtx sparc_tls_symbol;
+
static rtx
sparc_tls_get_addr (void)
{
@@ -3479,6 +3035,24 @@ sparc_tls_got (void)
return temp;
}
+/* Return 1 if *X is a thread-local symbol. */
+
+static int
+sparc_tls_symbol_ref_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
+{
+ return SPARC_SYMBOL_REF_TLS_P (*x);
+}
+
+/* Return 1 if X contains a thread-local symbol. */
+
+bool
+sparc_tls_referenced_p (rtx x)
+{
+ if (!TARGET_HAVE_TLS)
+ return false;
+
+ return for_each_rtx (&x, &sparc_tls_symbol_ref_1, 0);
+}
/* ADDR contains a thread-local SYMBOL_REF. Generate code to compute
this (thread-local) address. */
@@ -3488,8 +3062,7 @@ legitimize_tls_address (rtx addr)
{
rtx temp1, temp2, temp3, ret, o0, got, insn;
- if (no_new_pseudos)
- abort ();
+ gcc_assert (! no_new_pseudos);
if (GET_CODE (addr) == SYMBOL_REF)
switch (SYMBOL_REF_TLS_MODEL (addr))
@@ -3605,11 +3178,11 @@ legitimize_tls_address (rtx addr)
break;
default:
- abort ();
+ gcc_unreachable ();
}
else
- abort (); /* for now ... */
+ gcc_unreachable (); /* for now ... */
return ret;
}
@@ -3631,10 +3204,8 @@ legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED,
if (reg == 0)
{
- if (reload_in_progress || reload_completed)
- abort ();
- else
- reg = gen_reg_rtx (Pmode);
+ gcc_assert (! reload_in_progress && ! reload_completed);
+ reg = gen_reg_rtx (Pmode);
}
if (flag_pic == 2)
@@ -3649,26 +3220,25 @@ legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED,
won't get confused into thinking that these two instructions
are loading in the true address of the symbol. If in the
future a PIC rtx exists, that should be used instead. */
- if (Pmode == SImode)
+ if (TARGET_ARCH64)
{
- emit_insn (gen_movsi_high_pic (temp_reg, orig));
- emit_insn (gen_movsi_lo_sum_pic (temp_reg, temp_reg, orig));
+ emit_insn (gen_movdi_high_pic (temp_reg, orig));
+ emit_insn (gen_movdi_lo_sum_pic (temp_reg, temp_reg, orig));
}
else
{
- emit_insn (gen_movdi_high_pic (temp_reg, orig));
- emit_insn (gen_movdi_lo_sum_pic (temp_reg, temp_reg, orig));
+ emit_insn (gen_movsi_high_pic (temp_reg, orig));
+ emit_insn (gen_movsi_lo_sum_pic (temp_reg, temp_reg, orig));
}
address = temp_reg;
}
else
address = orig;
- pic_ref = gen_rtx_MEM (Pmode,
- gen_rtx_PLUS (Pmode,
- pic_offset_table_rtx, address));
+ pic_ref = gen_const_mem (Pmode,
+ gen_rtx_PLUS (Pmode,
+ pic_offset_table_rtx, address));
current_function_uses_pic_offset_table = 1;
- RTX_UNCHANGING_P (pic_ref) = 1;
insn = emit_move_insn (reg, pic_ref);
/* Put a REG_EQUAL note on this insn, so that it can be optimized
by loop. */
@@ -3686,20 +3256,14 @@ legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED,
if (reg == 0)
{
- if (reload_in_progress || reload_completed)
- abort ();
- else
- reg = gen_reg_rtx (Pmode);
+ gcc_assert (! reload_in_progress && ! reload_completed);
+ reg = gen_reg_rtx (Pmode);
}
- if (GET_CODE (XEXP (orig, 0)) == PLUS)
- {
- base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);
- offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
- base == reg ? 0 : reg);
- }
- else
- abort ();
+ gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS);
+ base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);
+ offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
+ base == reg ? 0 : reg);
if (GET_CODE (offset) == CONST_INT)
{
@@ -3709,7 +3273,7 @@ legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED,
offset = force_reg (Pmode, offset);
else
/* If we reach here, then something is seriously wrong. */
- abort ();
+ gcc_unreachable ();
}
return gen_rtx_PLUS (Pmode, base, offset);
}
@@ -3751,7 +3315,7 @@ legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, enum machine_mode mode)
if (x != orig_x && legitimate_address_p (mode, x, FALSE))
return x;
- if (tls_symbolic_operand (x))
+ if (SPARC_SYMBOL_REF_TLS_P (x))
x = legitimize_tls_address (x);
else if (flag_pic)
x = legitimize_pic_address (x, mode, 0);
@@ -3768,41 +3332,57 @@ legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, enum machine_mode mode)
return x;
}
-/* Emit special PIC prologues. */
+/* Emit the special PIC helper function. */
-void
-load_pic_register (void)
+static void
+emit_pic_helper (void)
{
- /* Labels to get the PC in the prologue of this function. */
- int orig_flag_pic = flag_pic;
+ const char *pic_name = reg_names[REGNO (pic_offset_table_rtx)];
+ int align;
- if (! flag_pic)
- abort ();
+ switch_to_section (text_section);
- /* If we haven't emitted the special get_pc helper function, do so now. */
- if (get_pc_symbol_name[0] == 0)
- {
- int align;
+ align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
+ if (align > 0)
+ ASM_OUTPUT_ALIGN (asm_out_file, align);
+ ASM_OUTPUT_LABEL (asm_out_file, pic_helper_symbol_name);
+ if (flag_delayed_branch)
+ fprintf (asm_out_file, "\tjmp\t%%o7+8\n\t add\t%%o7, %s, %s\n",
+ pic_name, pic_name);
+ else
+ fprintf (asm_out_file, "\tadd\t%%o7, %s, %s\n\tjmp\t%%o7+8\n\t nop\n",
+ pic_name, pic_name);
- ASM_GENERATE_INTERNAL_LABEL (get_pc_symbol_name, "LGETPC", 0);
- text_section ();
+ pic_helper_emitted_p = true;
+}
- align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
- if (align > 0)
- ASM_OUTPUT_ALIGN (asm_out_file, align);
- (*targetm.asm_out.internal_label) (asm_out_file, "LGETPC", 0);
- fputs ("\tretl\n\tadd\t%o7, %l7, %l7\n", asm_out_file);
- }
+/* Emit code to load the PIC register. */
- /* Initialize every time through, since we can't easily
- know this to be permanent. */
- global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
- get_pc_symbol = gen_rtx_SYMBOL_REF (Pmode, get_pc_symbol_name);
- flag_pic = 0;
+static void
+load_pic_register (bool delay_pic_helper)
+{
+ int orig_flag_pic = flag_pic;
+
+ /* If we haven't initialized the special PIC symbols, do so now. */
+ if (!pic_helper_symbol_name[0])
+ {
+ ASM_GENERATE_INTERNAL_LABEL (pic_helper_symbol_name, "LADDPC", 0);
+ pic_helper_symbol = gen_rtx_SYMBOL_REF (Pmode, pic_helper_symbol_name);
+ global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
+ }
- emit_insn (gen_get_pc (pic_offset_table_rtx, global_offset_table,
- get_pc_symbol));
+ /* If we haven't emitted the special PIC helper function, do so now unless
+ we are requested to delay it. */
+ if (!delay_pic_helper && !pic_helper_emitted_p)
+ emit_pic_helper ();
+ flag_pic = 0;
+ if (TARGET_ARCH64)
+ emit_insn (gen_load_pcrel_symdi (pic_offset_table_rtx, global_offset_table,
+ pic_helper_symbol));
+ else
+ emit_insn (gen_load_pcrel_symsi (pic_offset_table_rtx, global_offset_table,
+ pic_helper_symbol));
flag_pic = orig_flag_pic;
/* Need to emit this whether or not we obey regdecls,
@@ -3824,6 +3404,13 @@ mem_min_alignment (rtx mem, int desired)
if (GET_CODE (mem) != MEM)
return 0;
+ /* Obviously... */
+ if (!TARGET_UNALIGNED_DOUBLES
+ && MEM_ALIGN (mem) / BITS_PER_UNIT >= (unsigned)desired)
+ return 1;
+
+ /* ??? The rest of the function predates MEM_ALIGN so
+ there is probably a bit of redundancy. */
addr = XEXP (mem, 0);
base = offset = NULL_RTX;
if (GET_CODE (addr) == PLUS)
@@ -4031,6 +3618,12 @@ sparc_init_modes (void)
else
sparc_mode_class[i] = 0;
break;
+ case MODE_VECTOR_INT:
+ if (GET_MODE_SIZE (i) <= 4)
+ sparc_mode_class[i] = 1 << (int)SF_MODE;
+ else if (GET_MODE_SIZE (i) == 8)
+ sparc_mode_class[i] = 1 << (int)DF_MODE;
+ break;
case MODE_FLOAT:
case MODE_COMPLEX_FLOAT:
if (GET_MODE_SIZE (i) <= 4)
@@ -4079,128 +3672,16 @@ sparc_init_modes (void)
}
}
-/* Save non call used registers from LOW to HIGH at BASE+OFFSET.
- N_REGS is the number of 4-byte regs saved thus far. This applies even to
- v9 int regs as it simplifies the code. */
-
-static int
-save_regs (FILE *file, int low, int high, const char *base,
- int offset, int n_regs, HOST_WIDE_INT real_offset)
-{
- int i;
-
- if (TARGET_ARCH64 && high <= 32)
- {
- for (i = low; i < high; i++)
- {
- if (regs_ever_live[i] && ! call_used_regs[i])
- {
- fprintf (file, "\tstx\t%s, [%s+%d]\n",
- reg_names[i], base, offset + 4 * n_regs);
- if (dwarf2out_do_frame ())
- dwarf2out_reg_save ("", i, real_offset + 4 * n_regs);
- n_regs += 2;
- }
- }
- }
- else
- {
- for (i = low; i < high; i += 2)
- {
- if (regs_ever_live[i] && ! call_used_regs[i])
- {
- if (regs_ever_live[i+1] && ! call_used_regs[i+1])
- {
- fprintf (file, "\tstd\t%s, [%s+%d]\n",
- reg_names[i], base, offset + 4 * n_regs);
- if (dwarf2out_do_frame ())
- {
- char *l = dwarf2out_cfi_label ();
- dwarf2out_reg_save (l, i, real_offset + 4 * n_regs);
- dwarf2out_reg_save (l, i+1, real_offset + 4 * n_regs + 4);
- }
- n_regs += 2;
- }
- else
- {
- fprintf (file, "\tst\t%s, [%s+%d]\n",
- reg_names[i], base, offset + 4 * n_regs);
- if (dwarf2out_do_frame ())
- dwarf2out_reg_save ("", i, real_offset + 4 * n_regs);
- n_regs += 2;
- }
- }
- else
- {
- if (regs_ever_live[i+1] && ! call_used_regs[i+1])
- {
- fprintf (file, "\tst\t%s, [%s+%d]\n",
- reg_names[i+1], base, offset + 4 * n_regs + 4);
- if (dwarf2out_do_frame ())
- dwarf2out_reg_save ("", i + 1, real_offset + 4 * n_regs + 4);
- n_regs += 2;
- }
- }
- }
- }
- return n_regs;
-}
-
-/* Restore non call used registers from LOW to HIGH at BASE+OFFSET.
-
- N_REGS is the number of 4-byte regs saved thus far. This applies even to
- v9 int regs as it simplifies the code. */
-
-static int
-restore_regs (FILE *file, int low, int high, const char *base,
- int offset, int n_regs)
-{
- int i;
-
- if (TARGET_ARCH64 && high <= 32)
- {
- for (i = low; i < high; i++)
- {
- if (regs_ever_live[i] && ! call_used_regs[i])
- fprintf (file, "\tldx\t[%s+%d], %s\n",
- base, offset + 4 * n_regs, reg_names[i]),
- n_regs += 2;
- }
- }
- else
- {
- for (i = low; i < high; i += 2)
- {
- if (regs_ever_live[i] && ! call_used_regs[i])
- if (regs_ever_live[i+1] && ! call_used_regs[i+1])
- fprintf (file, "\tldd\t[%s+%d], %s\n",
- base, offset + 4 * n_regs, reg_names[i]),
- n_regs += 2;
- else
- fprintf (file, "\tld\t[%s+%d], %s\n",
- base, offset + 4 * n_regs, reg_names[i]),
- n_regs += 2;
- else if (regs_ever_live[i+1] && ! call_used_regs[i+1])
- fprintf (file, "\tld\t[%s+%d], %s\n",
- base, offset + 4 * n_regs + 4, reg_names[i+1]),
- n_regs += 2;
- }
- }
- return n_regs;
-}
-
/* Compute the frame size required by the function. This function is called
- during the reload pass and also by output_function_prologue(). */
+ during the reload pass and also by sparc_expand_prologue. */
HOST_WIDE_INT
-compute_frame_size (HOST_WIDE_INT size, int leaf_function)
+sparc_compute_frame_size (HOST_WIDE_INT size, int leaf_function_p)
{
- int n_regs = 0, i;
int outgoing_args_size = (current_function_outgoing_args_size
+ REG_PARM_STACK_SPACE (current_function_decl));
-
- /* N_REGS is the number of 4-byte regs saved thus far. This applies
- even to v9 int regs to be consistent with save_regs/restore_regs. */
+ int n_regs = 0; /* N_REGS is the number of 4-byte regs saved thus far. */
+ int i;
if (TARGET_ARCH64)
{
@@ -4221,14 +3702,14 @@ compute_frame_size (HOST_WIDE_INT size, int leaf_function)
|| (regs_ever_live[i+1] && ! call_used_regs[i+1]))
n_regs += 2;
- /* Set up values for use in `function_epilogue'. */
+ /* Set up values for use in prologue and epilogue. */
num_gfregs = n_regs;
- if (leaf_function && n_regs == 0
- && size == 0 && current_function_outgoing_args_size == 0)
- {
- actual_fsize = apparent_fsize = 0;
- }
+ if (leaf_function_p
+ && n_regs == 0
+ && size == 0
+ && current_function_outgoing_args_size == 0)
+ actual_fsize = apparent_fsize = 0;
else
{
/* We subtract STARTING_FRAME_OFFSET, remember it's negative. */
@@ -4239,108 +3720,15 @@ compute_frame_size (HOST_WIDE_INT size, int leaf_function)
/* Make sure nothing can clobber our register windows.
If a SAVE must be done, or there is a stack-local variable,
- the register window area must be allocated.
- ??? For v8 we apparently need an additional 8 bytes of reserved space. */
- if (leaf_function == 0 || size > 0)
- actual_fsize += (16 * UNITS_PER_WORD) + (TARGET_ARCH64 ? 0 : 8);
+ the register window area must be allocated. */
+ if (! leaf_function_p || size > 0)
+ actual_fsize += FIRST_PARM_OFFSET (current_function_decl);
return SPARC_STACK_ALIGN (actual_fsize);
}
-/* Build big number NUM in register REG and output the result to FILE.
- REG is guaranteed to be the only clobbered register. The function
- will very likely emit several instructions, so it must not be called
- from within a delay slot. */
-
-static void
-build_big_number (FILE *file, HOST_WIDE_INT num, const char *reg)
-{
-#if HOST_BITS_PER_WIDE_INT == 64
- HOST_WIDE_INT high_bits = (num >> 32) & 0xffffffff;
-
- if (high_bits == 0
-#else
- if (num >= 0
-#endif
- || ! TARGET_ARCH64)
- {
- /* We don't use the 'set' macro because it appears to be broken
- in the Solaris 7 assembler. */
- fprintf (file, "\tsethi\t%%hi("HOST_WIDE_INT_PRINT_DEC"), %s\n",
- num, reg);
- if ((num & 0x3ff) != 0)
- fprintf (file, "\tor\t%s, %%lo("HOST_WIDE_INT_PRINT_DEC"), %s\n",
- reg, num, reg);
- }
-#if HOST_BITS_PER_WIDE_INT == 64
- else if (high_bits == 0xffffffff) /* && TARGET_ARCH64 */
-#else
- else /* num < 0 && TARGET_ARCH64 */
-#endif
- {
- /* Sethi does not sign extend, so we must use a little trickery
- to use it for negative numbers. Invert the constant before
- loading it in, then use xor immediate to invert the loaded bits
- (along with the upper 32 bits) to the desired constant. This
- works because the sethi and immediate fields overlap. */
- HOST_WIDE_INT inv = ~num;
- HOST_WIDE_INT low = -0x400 + (num & 0x3ff);
-
- fprintf (file, "\tsethi\t%%hi("HOST_WIDE_INT_PRINT_DEC"), %s\n",
- inv, reg);
- fprintf (file, "\txor\t%s, "HOST_WIDE_INT_PRINT_DEC", %s\n",
- reg, low, reg);
- }
-#if HOST_BITS_PER_WIDE_INT == 64
- else /* TARGET_ARCH64 */
- {
- /* We don't use the 'setx' macro because if requires a scratch register.
- This is the translation of sparc_emit_set_const64_longway into asm.
- Hopefully we will soon have prologue/epilogue emitted as RTL. */
- HOST_WIDE_INT low1 = (num >> (32 - 12)) & 0xfff;
- HOST_WIDE_INT low2 = (num >> (32 - 12 - 12)) & 0xfff;
- HOST_WIDE_INT low3 = (num >> (32 - 12 - 12 - 8)) & 0x0ff;
- int to_shift = 12;
-
- /* We don't use the 'set' macro because it appears to be broken
- in the Solaris 7 assembler. */
- fprintf (file, "\tsethi\t%%hi("HOST_WIDE_INT_PRINT_DEC"), %s\n",
- high_bits, reg);
- if ((high_bits & 0x3ff) != 0)
- fprintf (file, "\tor\t%s, %%lo("HOST_WIDE_INT_PRINT_DEC"), %s\n",
- reg, high_bits, reg);
-
- if (low1 != 0)
- {
- fprintf (file, "\tsllx\t%s, %d, %s\n", reg, to_shift, reg);
- fprintf (file, "\tor\t%s, "HOST_WIDE_INT_PRINT_DEC", %s\n",
- reg, low1, reg);
- to_shift = 12;
- }
- else
- {
- to_shift += 12;
- }
- if (low2 != 0)
- {
- fprintf (file, "\tsllx\t%s, %d, %s\n", reg, to_shift, reg);
- fprintf (file, "\tor\t%s, "HOST_WIDE_INT_PRINT_DEC", %s\n",
- reg, low2, reg);
- to_shift = 8;
- }
- else
- {
- to_shift += 8;
- }
- fprintf (file, "\tsllx\t%s, %d, %s\n", reg, to_shift, reg);
- if (low3 != 0)
- fprintf (file, "\tor\t%s, "HOST_WIDE_INT_PRINT_DEC", %s\n",
- reg, low3, reg);
- }
-#endif
-}
-
/* Output any necessary .register pseudo-ops. */
+
void
sparc_output_scratch_registers (FILE *file ATTRIBUTE_UNUSED)
{
@@ -4358,341 +3746,469 @@ sparc_output_scratch_registers (FILE *file ATTRIBUTE_UNUSED)
&& ! sparc_hard_reg_printed [i])
{
sparc_hard_reg_printed [i] = 1;
- fprintf (file, "\t.register\t%%g%d, #scratch\n", i);
+ /* %g7 is used as TLS base register, use #ignore
+ for it instead of #scratch. */
+ fprintf (file, "\t.register\t%%g%d, #%s\n", i,
+ i == 7 ? "ignore" : "scratch");
}
if (i == 3) i = 5;
}
#endif
}
-/* This function generates the assembly code for function entry.
- FILE is a stdio stream to output the code to.
- SIZE is an int: how many units of temporary storage to allocate.
- Refer to the array `regs_ever_live' to determine which registers
- to save; `regs_ever_live[I]' is nonzero if register number I
- is ever used in the function. This macro is responsible for
- knowing which registers should not be saved even if used. */
+/* Save/restore call-saved registers from LOW to HIGH at BASE+OFFSET
+ as needed. LOW should be double-word aligned for 32-bit registers.
+ Return the new OFFSET. */
+
+#define SORR_SAVE 0
+#define SORR_RESTORE 1
+
+static int
+save_or_restore_regs (int low, int high, rtx base, int offset, int action)
+{
+ rtx mem, insn;
+ int i;
+
+ if (TARGET_ARCH64 && high <= 32)
+ {
+ for (i = low; i < high; i++)
+ {
+ if (regs_ever_live[i] && ! call_used_regs[i])
+ {
+ mem = gen_rtx_MEM (DImode, plus_constant (base, offset));
+ set_mem_alias_set (mem, sparc_sr_alias_set);
+ if (action == SORR_SAVE)
+ {
+ insn = emit_move_insn (mem, gen_rtx_REG (DImode, i));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ else /* action == SORR_RESTORE */
+ emit_move_insn (gen_rtx_REG (DImode, i), mem);
+ offset += 8;
+ }
+ }
+ }
+ else
+ {
+ for (i = low; i < high; i += 2)
+ {
+ bool reg0 = regs_ever_live[i] && ! call_used_regs[i];
+ bool reg1 = regs_ever_live[i+1] && ! call_used_regs[i+1];
+ enum machine_mode mode;
+ int regno;
+
+ if (reg0 && reg1)
+ {
+ mode = i < 32 ? DImode : DFmode;
+ regno = i;
+ }
+ else if (reg0)
+ {
+ mode = i < 32 ? SImode : SFmode;
+ regno = i;
+ }
+ else if (reg1)
+ {
+ mode = i < 32 ? SImode : SFmode;
+ regno = i + 1;
+ offset += 4;
+ }
+ else
+ continue;
+
+ mem = gen_rtx_MEM (mode, plus_constant (base, offset));
+ set_mem_alias_set (mem, sparc_sr_alias_set);
+ if (action == SORR_SAVE)
+ {
+ insn = emit_move_insn (mem, gen_rtx_REG (mode, regno));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ else /* action == SORR_RESTORE */
+ emit_move_insn (gen_rtx_REG (mode, regno), mem);
-/* On SPARC, move-double insns between fpu and cpu need an 8-byte block
- of memory. If any fpu reg is used in the function, we allocate
- such a block here, at the bottom of the frame, just in case it's needed.
+ /* Always preserve double-word alignment. */
+ offset = (offset + 7) & -8;
+ }
+ }
- If this function is a leaf procedure, then we may choose not
- to do a "save" insn. The decision about whether or not
- to do this is made in regclass.c. */
+ return offset;
+}
+
+/* Emit code to save call-saved registers. */
static void
-sparc_output_function_prologue (FILE *file, HOST_WIDE_INT size)
+emit_save_or_restore_regs (int action)
{
- if (TARGET_FLAT)
- sparc_flat_function_prologue (file, size);
+ HOST_WIDE_INT offset;
+ rtx base;
+
+ offset = frame_base_offset - apparent_fsize;
+
+ if (offset < -4096 || offset + num_gfregs * 4 > 4095)
+ {
+ /* ??? This might be optimized a little as %g1 might already have a
+ value close enough that a single add insn will do. */
+ /* ??? Although, all of this is probably only a temporary fix
+ because if %g1 can hold a function result, then
+ sparc_expand_epilogue will lose (the result will be
+ clobbered). */
+ base = gen_rtx_REG (Pmode, 1);
+ emit_move_insn (base, GEN_INT (offset));
+ emit_insn (gen_rtx_SET (VOIDmode,
+ base,
+ gen_rtx_PLUS (Pmode, frame_base_reg, base)));
+ offset = 0;
+ }
else
- sparc_nonflat_function_prologue (file, size,
- current_function_uses_only_leaf_regs);
+ base = frame_base_reg;
+
+ offset = save_or_restore_regs (0, 8, base, offset, action);
+ save_or_restore_regs (32, TARGET_V9 ? 96 : 64, base, offset, action);
}
-/* Output code for the function prologue. */
+/* Generate a save_register_window insn. */
-static void
-sparc_nonflat_function_prologue (FILE *file, HOST_WIDE_INT size,
- int leaf_function)
+static rtx
+gen_save_register_window (rtx increment)
{
- sparc_output_scratch_registers (file);
+ if (TARGET_ARCH64)
+ return gen_save_register_windowdi (increment);
+ else
+ return gen_save_register_windowsi (increment);
+}
+
+/* Generate an increment for the stack pointer. */
+
+static rtx
+gen_stack_pointer_inc (rtx increment)
+{
+ return gen_rtx_SET (VOIDmode,
+ stack_pointer_rtx,
+ gen_rtx_PLUS (Pmode,
+ stack_pointer_rtx,
+ increment));
+}
+
+/* Generate a decrement for the stack pointer. */
+
+static rtx
+gen_stack_pointer_dec (rtx decrement)
+{
+ return gen_rtx_SET (VOIDmode,
+ stack_pointer_rtx,
+ gen_rtx_MINUS (Pmode,
+ stack_pointer_rtx,
+ decrement));
+}
+
+/* Expand the function prologue. The prologue is responsible for reserving
+ storage for the frame, saving the call-saved registers and loading the
+ PIC register if needed. */
+
+void
+sparc_expand_prologue (void)
+{
+ rtx insn;
+ int i;
+
+ /* Compute a snapshot of current_function_uses_only_leaf_regs. Relying
+ on the final value of the flag means deferring the prologue/epilogue
+ expansion until just before the second scheduling pass, which is too
+ late to emit multiple epilogues or return insns.
+
+ Of course we are making the assumption that the value of the flag
+ will not change between now and its final value. Of the three parts
+ of the formula, only the last one can reasonably vary. Let's take a
+ closer look, after assuming that the first two ones are set to true
+ (otherwise the last value is effectively silenced).
+
+ If only_leaf_regs_used returns false, the global predicate will also
+ be false so the actual frame size calculated below will be positive.
+ As a consequence, the save_register_window insn will be emitted in
+ the instruction stream; now this insn explicitly references %fp
+ which is not a leaf register so only_leaf_regs_used will always
+ return false subsequently.
+
+ If only_leaf_regs_used returns true, we hope that the subsequent
+ optimization passes won't cause non-leaf registers to pop up. For
+ example, the regrename pass has special provisions to not rename to
+ non-leaf registers in a leaf function. */
+ sparc_leaf_function_p
+ = optimize > 0 && leaf_function_p () && only_leaf_regs_used ();
/* Need to use actual_fsize, since we are also allocating
space for our callee (and our own register save area). */
- actual_fsize = compute_frame_size (size, leaf_function);
+ actual_fsize
+ = sparc_compute_frame_size (get_frame_size(), sparc_leaf_function_p);
- if (leaf_function)
+ /* Advertise that the data calculated just above are now valid. */
+ sparc_prologue_data_valid_p = true;
+
+ if (sparc_leaf_function_p)
{
- frame_base_name = "%sp";
+ frame_base_reg = stack_pointer_rtx;
frame_base_offset = actual_fsize + SPARC_STACK_BIAS;
}
else
{
- frame_base_name = "%fp";
+ frame_base_reg = hard_frame_pointer_rtx;
frame_base_offset = SPARC_STACK_BIAS;
}
- /* This is only for the human reader. */
- fprintf (file, "\t%s#PROLOGUE# 0\n", ASM_COMMENT_START);
-
if (actual_fsize == 0)
/* do nothing. */ ;
- else if (! leaf_function)
+ else if (sparc_leaf_function_p)
{
if (actual_fsize <= 4096)
- fprintf (file, "\tsave\t%%sp, -"HOST_WIDE_INT_PRINT_DEC", %%sp\n",
- actual_fsize);
+ insn = emit_insn (gen_stack_pointer_inc (GEN_INT (-actual_fsize)));
else if (actual_fsize <= 8192)
{
- fprintf (file, "\tsave\t%%sp, -4096, %%sp\n");
- fprintf (file, "\tadd\t%%sp, -"HOST_WIDE_INT_PRINT_DEC", %%sp\n",
- actual_fsize - 4096);
+ insn = emit_insn (gen_stack_pointer_inc (GEN_INT (-4096)));
+ /* %sp is still the CFA register. */
+ RTX_FRAME_RELATED_P (insn) = 1;
+ insn
+ = emit_insn (gen_stack_pointer_inc (GEN_INT (4096-actual_fsize)));
}
else
{
- build_big_number (file, -actual_fsize, "%g1");
- fprintf (file, "\tsave\t%%sp, %%g1, %%sp\n");
+ rtx reg = gen_rtx_REG (Pmode, 1);
+ emit_move_insn (reg, GEN_INT (-actual_fsize));
+ insn = emit_insn (gen_stack_pointer_inc (reg));
+ REG_NOTES (insn) =
+ gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+ gen_stack_pointer_inc (GEN_INT (-actual_fsize)),
+ REG_NOTES (insn));
}
+
+ RTX_FRAME_RELATED_P (insn) = 1;
}
- else /* leaf function */
+ else
{
if (actual_fsize <= 4096)
- fprintf (file, "\tadd\t%%sp, -"HOST_WIDE_INT_PRINT_DEC", %%sp\n",
- actual_fsize);
+ insn = emit_insn (gen_save_register_window (GEN_INT (-actual_fsize)));
else if (actual_fsize <= 8192)
{
- fprintf (file, "\tadd\t%%sp, -4096, %%sp\n");
- fprintf (file, "\tadd\t%%sp, -"HOST_WIDE_INT_PRINT_DEC", %%sp\n",
- actual_fsize - 4096);
+ insn = emit_insn (gen_save_register_window (GEN_INT (-4096)));
+ /* %sp is not the CFA register anymore. */
+ emit_insn (gen_stack_pointer_inc (GEN_INT (4096-actual_fsize)));
}
else
{
- build_big_number (file, -actual_fsize, "%g1");
- fprintf (file, "\tadd\t%%sp, %%g1, %%sp\n");
+ rtx reg = gen_rtx_REG (Pmode, 1);
+ emit_move_insn (reg, GEN_INT (-actual_fsize));
+ insn = emit_insn (gen_save_register_window (reg));
}
+
+ RTX_FRAME_RELATED_P (insn) = 1;
+ for (i=0; i < XVECLEN (PATTERN (insn), 0); i++)
+ RTX_FRAME_RELATED_P (XVECEXP (PATTERN (insn), 0, i)) = 1;
}
- if (dwarf2out_do_frame () && actual_fsize)
- {
- char *label = dwarf2out_cfi_label ();
+ if (num_gfregs)
+ emit_save_or_restore_regs (SORR_SAVE);
- /* The canonical frame address refers to the top of the frame. */
- dwarf2out_def_cfa (label, (leaf_function ? STACK_POINTER_REGNUM
- : HARD_FRAME_POINTER_REGNUM),
- frame_base_offset);
+ /* Load the PIC register if needed. */
+ if (flag_pic && current_function_uses_pic_offset_table)
+ load_pic_register (false);
+}
+
+/* This function generates the assembly code for function entry, which boils
+ down to emitting the necessary .register directives. */
- if (! leaf_function)
- {
- /* Note the register window save. This tells the unwinder that
- it needs to restore the window registers from the previous
- frame's window save area at 0(cfa). */
- dwarf2out_window_save (label);
+static void
+sparc_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
+{
+ /* Check that the assumption we made in sparc_expand_prologue is valid. */
+ gcc_assert (sparc_leaf_function_p == current_function_uses_only_leaf_regs);
- /* The return address (-8) is now in %i7. */
- dwarf2out_return_reg (label, 31);
- }
- }
+ sparc_output_scratch_registers (file);
+}
- /* If doing anything with PIC, do it now. */
- if (! flag_pic)
- fprintf (file, "\t%s#PROLOGUE# 1\n", ASM_COMMENT_START);
+/* Expand the function epilogue, either normal or part of a sibcall.
+ We emit all the instructions except the return or the call. */
- /* Call saved registers are saved just above the outgoing argument area. */
+void
+sparc_expand_epilogue (void)
+{
if (num_gfregs)
+ emit_save_or_restore_regs (SORR_RESTORE);
+
+ if (actual_fsize == 0)
+ /* do nothing. */ ;
+ else if (sparc_leaf_function_p)
{
- HOST_WIDE_INT offset, real_offset;
- int n_regs;
- const char *base;
-
- real_offset = -apparent_fsize;
- offset = -apparent_fsize + frame_base_offset;
- if (offset < -4096 || offset + num_gfregs * 4 > 4096)
- {
- /* ??? This might be optimized a little as %g1 might already have a
- value close enough that a single add insn will do. */
- /* ??? Although, all of this is probably only a temporary fix
- because if %g1 can hold a function result, then
- output_function_epilogue will lose (the result will get
- clobbered). */
- build_big_number (file, offset, "%g1");
- fprintf (file, "\tadd\t%s, %%g1, %%g1\n", frame_base_name);
- base = "%g1";
- offset = 0;
+ if (actual_fsize <= 4096)
+ emit_insn (gen_stack_pointer_dec (GEN_INT (- actual_fsize)));
+ else if (actual_fsize <= 8192)
+ {
+ emit_insn (gen_stack_pointer_dec (GEN_INT (-4096)));
+ emit_insn (gen_stack_pointer_dec (GEN_INT (4096 - actual_fsize)));
}
else
{
- base = frame_base_name;
+ rtx reg = gen_rtx_REG (Pmode, 1);
+ emit_move_insn (reg, GEN_INT (-actual_fsize));
+ emit_insn (gen_stack_pointer_dec (reg));
}
-
- n_regs = save_regs (file, 0, 8, base, offset, 0, real_offset);
- save_regs (file, 32, TARGET_V9 ? 96 : 64, base, offset, n_regs,
- real_offset);
}
}
-/* Output code to restore any call saved registers. */
+/* Return true if it is appropriate to emit `return' instructions in the
+ body of a function. */
+bool
+sparc_can_use_return_insn_p (void)
+{
+ return sparc_prologue_data_valid_p
+ && (actual_fsize == 0 || !sparc_leaf_function_p);
+}
+
+/* This function generates the assembly code for function exit. */
+
static void
-output_restore_regs (FILE *file, int leaf_function ATTRIBUTE_UNUSED)
+sparc_asm_function_epilogue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
{
- HOST_WIDE_INT offset;
- int n_regs;
- const char *base;
+ /* If code does not drop into the epilogue, we have to still output
+ a dummy nop for the sake of sane backtraces. Otherwise, if the
+ last two instructions of a function were "call foo; dslot;" this
+ can make the return PC of foo (i.e. address of call instruction
+ plus 8) point to the first instruction in the next function. */
- offset = -apparent_fsize + frame_base_offset;
- if (offset < -4096 || offset + num_gfregs * 4 > 4096 - 8 /*double*/)
- {
- build_big_number (file, offset, "%g1");
- fprintf (file, "\tadd\t%s, %%g1, %%g1\n", frame_base_name);
- base = "%g1";
- offset = 0;
- }
- else
- {
- base = frame_base_name;
- }
+ rtx insn, last_real_insn;
- n_regs = restore_regs (file, 0, 8, base, offset, 0);
- restore_regs (file, 32, TARGET_V9 ? 96 : 64, base, offset, n_regs);
-}
+ insn = get_last_insn ();
-/* This function generates the assembly code for function exit,
- on machines that need it.
+ last_real_insn = prev_real_insn (insn);
+ if (last_real_insn
+ && GET_CODE (last_real_insn) == INSN
+ && GET_CODE (PATTERN (last_real_insn)) == SEQUENCE)
+ last_real_insn = XVECEXP (PATTERN (last_real_insn), 0, 0);
- The function epilogue should not depend on the current stack pointer!
- It should use the frame pointer only. This is mandatory because
- of alloca; we also take advantage of it to omit stack adjustments
- before returning. */
+ if (last_real_insn && GET_CODE (last_real_insn) == CALL_INSN)
+ fputs("\tnop\n", file);
-static void
-sparc_output_function_epilogue (FILE *file, HOST_WIDE_INT size)
-{
- if (TARGET_FLAT)
- sparc_flat_function_epilogue (file, size);
- else
- sparc_nonflat_function_epilogue (file, size,
- current_function_uses_only_leaf_regs);
+ sparc_output_deferred_case_vectors ();
}
-
-/* Output code for the function epilogue. */
-
+
+/* Output a 'restore' instruction. */
+
static void
-sparc_nonflat_function_epilogue (FILE *file,
- HOST_WIDE_INT size ATTRIBUTE_UNUSED,
- int leaf_function)
+output_restore (rtx pat)
{
- const char *ret;
+ rtx operands[3];
- if (current_function_epilogue_delay_list == 0)
+ if (! pat)
{
- /* If code does not drop into the epilogue, we need
- do nothing except output pending case vectors.
-
- We have to still output a dummy nop for the sake of
- sane backtraces. Otherwise, if the last two instructions
- of a function were call foo; dslot; this can make the return
- PC of foo (ie. address of call instruction plus 8) point to
- the first instruction in the next function. */
- rtx insn, last_real_insn;
-
- insn = get_last_insn ();
+ fputs ("\t restore\n", asm_out_file);
+ return;
+ }
- last_real_insn = prev_real_insn (insn);
- if (last_real_insn
- && GET_CODE (last_real_insn) == INSN
- && GET_CODE (PATTERN (last_real_insn)) == SEQUENCE)
- last_real_insn = XVECEXP (PATTERN (last_real_insn), 0, 0);
+ gcc_assert (GET_CODE (pat) == SET);
- if (last_real_insn && GET_CODE (last_real_insn) == CALL_INSN)
- fputs("\tnop\n", file);
+ operands[0] = SET_DEST (pat);
+ pat = SET_SRC (pat);
- if (GET_CODE (insn) == NOTE)
- insn = prev_nonnote_insn (insn);
- if (insn && GET_CODE (insn) == BARRIER)
- goto output_vectors;
+ switch (GET_CODE (pat))
+ {
+ case PLUS:
+ operands[1] = XEXP (pat, 0);
+ operands[2] = XEXP (pat, 1);
+ output_asm_insn (" restore %r1, %2, %Y0", operands);
+ break;
+ case LO_SUM:
+ operands[1] = XEXP (pat, 0);
+ operands[2] = XEXP (pat, 1);
+ output_asm_insn (" restore %r1, %%lo(%a2), %Y0", operands);
+ break;
+ case ASHIFT:
+ operands[1] = XEXP (pat, 0);
+ gcc_assert (XEXP (pat, 1) == const1_rtx);
+ output_asm_insn (" restore %r1, %r1, %Y0", operands);
+ break;
+ default:
+ operands[1] = pat;
+ output_asm_insn (" restore %%g0, %1, %Y0", operands);
+ break;
}
+}
+
+/* Output a return. */
- if (num_gfregs)
- output_restore_regs (file, leaf_function);
+const char *
+output_return (rtx insn)
+{
+ if (sparc_leaf_function_p)
+ {
+ /* This is a leaf function so we don't have to bother restoring the
+ register window, which frees us from dealing with the convoluted
+ semantics of restore/return. We simply output the jump to the
+ return address and the insn in the delay slot (if any). */
- /* Work out how to skip the caller's unimp instruction if required. */
- if (leaf_function)
- ret = (SKIP_CALLERS_UNIMP_P ? "jmp\t%o7+12" : "retl");
- else
- ret = (SKIP_CALLERS_UNIMP_P ? "jmp\t%i7+12" : "ret");
+ gcc_assert (! current_function_calls_eh_return);
- if (! leaf_function)
+ return "jmp\t%%o7+%)%#";
+ }
+ else
{
+ /* This is a regular function so we have to restore the register window.
+ We may have a pending insn for the delay slot, which will be either
+ combined with the 'restore' instruction or put in the delay slot of
+ the 'return' instruction. */
+
if (current_function_calls_eh_return)
{
- if (current_function_epilogue_delay_list)
- abort ();
- if (SKIP_CALLERS_UNIMP_P)
- abort ();
+ /* If the function uses __builtin_eh_return, the eh_return
+ machinery occupies the delay slot. */
+ gcc_assert (! final_sequence);
- fputs ("\trestore\n\tretl\n\tadd\t%sp, %g1, %sp\n", file);
+ if (! flag_delayed_branch)
+ fputs ("\tadd\t%fp, %g1, %fp\n", asm_out_file);
+
+ if (TARGET_V9)
+ fputs ("\treturn\t%i7+8\n", asm_out_file);
+ else
+ fputs ("\trestore\n\tjmp\t%o7+8\n", asm_out_file);
+
+ if (flag_delayed_branch)
+ fputs ("\t add\t%sp, %g1, %sp\n", asm_out_file);
+ else
+ fputs ("\t nop\n", asm_out_file);
}
- /* If we wound up with things in our delay slot, flush them here. */
- else if (current_function_epilogue_delay_list)
+ else if (final_sequence)
{
- rtx delay = PATTERN (XEXP (current_function_epilogue_delay_list, 0));
+ rtx delay, pat;
+
+ delay = NEXT_INSN (insn);
+ gcc_assert (delay);
- if (TARGET_V9 && ! epilogue_renumber (&delay, 1))
+ pat = PATTERN (delay);
+
+ if (TARGET_V9 && ! epilogue_renumber (&pat, 1))
{
- epilogue_renumber (&delay, 0);
- fputs (SKIP_CALLERS_UNIMP_P
- ? "\treturn\t%i7+12\n"
- : "\treturn\t%i7+8\n", file);
- final_scan_insn (XEXP (current_function_epilogue_delay_list, 0),
- file, 1, 0, 0, NULL);
+ epilogue_renumber (&pat, 0);
+ return "return\t%%i7+%)%#";
}
else
{
- rtx insn, src;
-
- if (GET_CODE (delay) != SET)
- abort();
-
- src = SET_SRC (delay);
- if (GET_CODE (src) == ASHIFT)
- {
- if (XEXP (src, 1) != const1_rtx)
- abort();
- SET_SRC (delay)
- = gen_rtx_PLUS (GET_MODE (src), XEXP (src, 0),
- XEXP (src, 0));
- }
-
- insn = gen_rtx_PARALLEL (VOIDmode,
- gen_rtvec (2, delay,
- gen_rtx_RETURN (VOIDmode)));
- insn = emit_jump_insn (insn);
-
- sparc_emitting_epilogue = true;
- final_scan_insn (insn, file, 1, 0, 1, NULL);
- sparc_emitting_epilogue = false;
+ output_asm_insn ("jmp\t%%i7+%)", NULL);
+ output_restore (pat);
+ PATTERN (delay) = gen_blockage ();
+ INSN_CODE (delay) = -1;
}
}
- else if (TARGET_V9 && ! SKIP_CALLERS_UNIMP_P)
- fputs ("\treturn\t%i7+8\n\tnop\n", file);
else
- fprintf (file, "\t%s\n\trestore\n", ret);
- }
- /* All of the following cases are for leaf functions. */
- else if (current_function_calls_eh_return)
- abort ();
- else if (current_function_epilogue_delay_list)
- {
- /* eligible_for_epilogue_delay_slot ensures that if this is a
- leaf function, then we will only have insn in the delay slot
- if the frame size is zero, thus no adjust for the stack is
- needed here. */
- if (actual_fsize != 0)
- abort ();
- fprintf (file, "\t%s\n", ret);
- final_scan_insn (XEXP (current_function_epilogue_delay_list, 0),
- file, 1, 0, 1, NULL);
- }
- /* Output 'nop' instead of 'sub %sp,-0,%sp' when no frame, so as to
- avoid generating confusing assembly language output. */
- else if (actual_fsize == 0)
- fprintf (file, "\t%s\n\tnop\n", ret);
- else if (actual_fsize <= 4096)
- fprintf (file, "\t%s\n\tsub\t%%sp, -"HOST_WIDE_INT_PRINT_DEC", %%sp\n",
- ret, actual_fsize);
- else if (actual_fsize <= 8192)
- fprintf (file, "\tsub\t%%sp, -4096, %%sp\n\t%s\n\tsub\t%%sp, -"HOST_WIDE_INT_PRINT_DEC", %%sp\n",
- ret, actual_fsize - 4096);
- else
- {
- build_big_number (file, actual_fsize, "%g1");
- fprintf (file, "\t%s\n\tadd\t%%sp, %%g1, %%sp\n", ret);
+ {
+ /* The delay slot is empty. */
+ if (TARGET_V9)
+ return "return\t%%i7+%)\n\t nop";
+ else if (flag_delayed_branch)
+ return "jmp\t%%i7+%)\n\t restore";
+ else
+ return "restore\n\tjmp\t%%o7+%)\n\t nop";
+ }
}
- output_vectors:
- sparc_output_deferred_case_vectors ();
+ return "";
}
/* Output a sibling call. */
@@ -4700,144 +4216,61 @@ sparc_nonflat_function_epilogue (FILE *file,
const char *
output_sibcall (rtx insn, rtx call_operand)
{
- int leaf_regs = current_function_uses_only_leaf_regs;
- rtx operands[3];
- int delay_slot = dbr_sequence_length () > 0;
+ rtx operands[1];
- if (num_gfregs)
- {
- /* Call to restore global regs might clobber
- the delay slot. Instead of checking for this
- output the delay slot now. */
- if (delay_slot)
- {
- rtx delay = NEXT_INSN (insn);
+ gcc_assert (flag_delayed_branch);
- if (! delay)
- abort ();
+ operands[0] = call_operand;
- final_scan_insn (delay, asm_out_file, 1, 0, 1, NULL);
- PATTERN (delay) = gen_blockage ();
- INSN_CODE (delay) = -1;
- delay_slot = 0;
- }
- output_restore_regs (asm_out_file, leaf_regs);
- }
+ if (sparc_leaf_function_p)
+ {
+ /* This is a leaf function so we don't have to bother restoring the
+ register window. We simply output the jump to the function and
+ the insn in the delay slot (if any). */
- operands[0] = call_operand;
+ gcc_assert (!(LEAF_SIBCALL_SLOT_RESERVED_P && final_sequence));
- if (leaf_regs)
+ if (final_sequence)
+ output_asm_insn ("sethi\t%%hi(%a0), %%g1\n\tjmp\t%%g1 + %%lo(%a0)%#",
+ operands);
+ else
+ /* Use or with rs2 %%g0 instead of mov, so that as/ld can optimize
+ it into branch if possible. */
+ output_asm_insn ("or\t%%o7, %%g0, %%g1\n\tcall\t%a0, 0\n\t or\t%%g1, %%g0, %%o7",
+ operands);
+ }
+ else
{
-#ifdef HAVE_AS_RELAX_OPTION
- /* If as and ld are relaxing tail call insns into branch always,
- use or %o7,%g0,X; call Y; or X,%g0,%o7 always, so that it can
- be optimized. With sethi/jmpl as nor ld has no easy way how to
- find out if somebody does not branch between the sethi and jmpl. */
- int spare_slot = 0;
-#else
- int spare_slot = ((TARGET_ARCH32 || TARGET_CM_MEDLOW) && ! flag_pic);
-#endif
- HOST_WIDE_INT size = 0;
+ /* This is a regular function so we have to restore the register window.
+ We may have a pending insn for the delay slot, which will be combined
+ with the 'restore' instruction. */
+
+ output_asm_insn ("call\t%a0, 0", operands);
- if ((actual_fsize || ! spare_slot) && delay_slot)
+ if (final_sequence)
{
rtx delay = NEXT_INSN (insn);
+ gcc_assert (delay);
- if (! delay)
- abort ();
+ output_restore (PATTERN (delay));
- final_scan_insn (delay, asm_out_file, 1, 0, 1, NULL);
PATTERN (delay) = gen_blockage ();
INSN_CODE (delay) = -1;
- delay_slot = 0;
- }
- if (actual_fsize)
- {
- if (actual_fsize <= 4096)
- size = actual_fsize;
- else if (actual_fsize <= 8192)
- {
- fputs ("\tsub\t%sp, -4096, %sp\n", asm_out_file);
- size = actual_fsize - 4096;
- }
- else
- {
- build_big_number (asm_out_file, actual_fsize, "%g1");
- fputs ("\tadd\t%%sp, %%g1, %%sp\n", asm_out_file);
- }
- }
- if (spare_slot)
- {
- output_asm_insn ("sethi\t%%hi(%a0), %%g1", operands);
- output_asm_insn ("jmpl\t%%g1 + %%lo(%a0), %%g0", operands);
- if (size)
- fprintf (asm_out_file, "\t sub\t%%sp, -"HOST_WIDE_INT_PRINT_DEC", %%sp\n", size);
- else if (! delay_slot)
- fputs ("\t nop\n", asm_out_file);
}
else
- {
- if (size)
- fprintf (asm_out_file, "\tsub\t%%sp, -"HOST_WIDE_INT_PRINT_DEC", %%sp\n", size);
- /* Use or with rs2 %%g0 instead of mov, so that as/ld can optimize
- it into branch if possible. */
- output_asm_insn ("or\t%%o7, %%g0, %%g1", operands);
- output_asm_insn ("call\t%a0, 0", operands);
- output_asm_insn (" or\t%%g1, %%g0, %%o7", operands);
- }
- return "";
+ output_restore (NULL_RTX);
}
- output_asm_insn ("call\t%a0, 0", operands);
- if (delay_slot)
- {
- rtx delay = NEXT_INSN (insn), pat;
-
- if (! delay)
- abort ();
-
- pat = PATTERN (delay);
- if (GET_CODE (pat) != SET)
- abort ();
-
- operands[0] = SET_DEST (pat);
- pat = SET_SRC (pat);
- switch (GET_CODE (pat))
- {
- case PLUS:
- operands[1] = XEXP (pat, 0);
- operands[2] = XEXP (pat, 1);
- output_asm_insn (" restore %r1, %2, %Y0", operands);
- break;
- case LO_SUM:
- operands[1] = XEXP (pat, 0);
- operands[2] = XEXP (pat, 1);
- output_asm_insn (" restore %r1, %%lo(%a2), %Y0", operands);
- break;
- case ASHIFT:
- operands[1] = XEXP (pat, 0);
- output_asm_insn (" restore %r1, %r1, %Y0", operands);
- break;
- default:
- operands[1] = pat;
- output_asm_insn (" restore %%g0, %1, %Y0", operands);
- break;
- }
- PATTERN (delay) = gen_blockage ();
- INSN_CODE (delay) = -1;
- }
- else
- fputs ("\t restore\n", asm_out_file);
return "";
}
/* Functions for handling argument passing.
- For v8 the first six args are normally in registers and the rest are
+ For 32-bit, the first 6 args are normally in registers and the rest are
pushed. Any arg that starts within the first 6 words is at least
partially passed in a register unless its data type forbids.
- For v9, the argument registers are laid out as an array of 16 elements
+ For 64-bit, the argument registers are laid out as an array of 16 elements
and arguments are added sequentially. The first 6 int args and up to the
first 16 fp args (depending on size) are passed in regs.
@@ -4862,7 +4295,7 @@ output_sibcall (rtx insn, rtx call_operand)
Here SP = %sp if -mno-stack-bias or %sp+stack_bias otherwise.
- Integral arguments are always passed as 64 bit quantities appropriately
+ Integral arguments are always passed as 64-bit quantities appropriately
extended.
Passing of floating point values is handled as follows.
@@ -4879,7 +4312,80 @@ output_sibcall (rtx insn, rtx call_operand)
appropriate integer reg and the appropriate fp reg.
If the value is not one of the first 6 arguments the value is passed in
the appropriate fp reg and in memory.
- */
+
+
+ Summary of the calling conventions implemented by GCC on SPARC:
+
+ 32-bit ABI:
+ size argument return value
+
+ small integer <4 int. reg. int. reg.
+ word 4 int. reg. int. reg.
+ double word 8 int. reg. int. reg.
+
+ _Complex small integer <8 int. reg. int. reg.
+ _Complex word 8 int. reg. int. reg.
+ _Complex double word 16 memory int. reg.
+
+ vector integer <=8 int. reg. FP reg.
+ vector integer >8 memory memory
+
+ float 4 int. reg. FP reg.
+ double 8 int. reg. FP reg.
+ long double 16 memory memory
+
+ _Complex float 8 memory FP reg.
+ _Complex double 16 memory FP reg.
+ _Complex long double 32 memory FP reg.
+
+ vector float any memory memory
+
+ aggregate any memory memory
+
+
+
+ 64-bit ABI:
+ size argument return value
+
+ small integer <8 int. reg. int. reg.
+ word 8 int. reg. int. reg.
+ double word 16 int. reg. int. reg.
+
+ _Complex small integer <16 int. reg. int. reg.
+ _Complex word 16 int. reg. int. reg.
+ _Complex double word 32 memory int. reg.
+
+ vector integer <=16 FP reg. FP reg.
+ vector integer 16<s<=32 memory FP reg.
+ vector integer >32 memory memory
+
+ float 4 FP reg. FP reg.
+ double 8 FP reg. FP reg.
+ long double 16 FP reg. FP reg.
+
+ _Complex float 8 FP reg. FP reg.
+ _Complex double 16 FP reg. FP reg.
+ _Complex long double 32 memory FP reg.
+
+ vector float <=16 FP reg. FP reg.
+ vector float 16<s<=32 memory FP reg.
+ vector float >32 memory memory
+
+ aggregate <=16 reg. reg.
+ aggregate 16<s<=32 memory reg.
+ aggregate >32 memory memory
+
+
+
+Note #1: complex floating-point types follow the extended SPARC ABIs as
+implemented by the Sun compiler.
+
+Note #2: integral vector types follow the scalar floating-point types
+conventions to match what is implemented by the Sun VIS SDK.
+
+Note #3: floating-point vector types follow the aggregate types
+conventions. */
+
/* Maximum number of int regs for args. */
#define SPARC_INT_ARG_MAX 6
@@ -4903,6 +4409,23 @@ init_cumulative_args (struct sparc_args *cum, tree fntype,
cum->libcall_p = fntype == 0;
}
+/* Handle the TARGET_PROMOTE_PROTOTYPES target hook.
+ When a prototype says `char' or `short', really pass an `int'. */
+
+static bool
+sparc_promote_prototypes (tree fntype ATTRIBUTE_UNUSED)
+{
+ return TARGET_ARCH32 ? true : false;
+}
+
+/* Handle the TARGET_STRICT_ARGUMENT_NAMING target hook. */
+
+static bool
+sparc_strict_argument_naming (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED)
+{
+ return TARGET_ARCH64 ? true : false;
+}
+
/* Scan the record type TYPE and return the following predicates:
- INTREGS_P: the record contains at least one field or sub-field
that is eligible for promotion in integer registers.
@@ -4923,7 +4446,9 @@ scan_record_type (tree type, int *intregs_p, int *fpregs_p, int *packed_p)
{
if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE)
scan_record_type (TREE_TYPE (field), intregs_p, fpregs_p, 0);
- else if (FLOAT_TYPE_P (TREE_TYPE (field)) && TARGET_FPU)
+ else if ((FLOAT_TYPE_P (TREE_TYPE (field))
+ || TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE)
+ && TARGET_FPU)
*fpregs_p = 1;
else
*intregs_p = 1;
@@ -4958,91 +4483,100 @@ function_arg_slotno (const struct sparc_args *cum, enum machine_mode mode,
? SPARC_INCOMING_INT_ARG_FIRST
: SPARC_OUTGOING_INT_ARG_FIRST);
int slotno = cum->words;
+ enum mode_class mclass;
int regno;
*ppadding = 0;
- if (type != 0 && TREE_ADDRESSABLE (type))
+ if (type && TREE_ADDRESSABLE (type))
return -1;
+
if (TARGET_ARCH32
- && type != 0 && mode == BLKmode
+ && mode == BLKmode
+ && type
&& TYPE_ALIGN (type) % PARM_BOUNDARY != 0)
return -1;
- switch (mode)
+ /* For SPARC64, objects requiring 16-byte alignment get it. */
+ if (TARGET_ARCH64
+ && (type ? TYPE_ALIGN (type) : GET_MODE_ALIGNMENT (mode)) >= 128
+ && (slotno & 1) != 0)
+ slotno++, *ppadding = 1;
+
+ mclass = GET_MODE_CLASS (mode);
+ if (type && TREE_CODE (type) == VECTOR_TYPE)
{
- case VOIDmode :
- /* MODE is VOIDmode when generating the actual call.
- See emit_call_1. */
- return -1;
+ /* Vector types deserve special treatment because they are
+ polymorphic wrt their mode, depending upon whether VIS
+ instructions are enabled. */
+ if (TREE_CODE (TREE_TYPE (type)) == REAL_TYPE)
+ {
+ /* The SPARC port defines no floating-point vector modes. */
+ gcc_assert (mode == BLKmode);
+ }
+ else
+ {
+ /* Integral vector types should either have a vector
+ mode or an integral mode, because we are guaranteed
+ by pass_by_reference that their size is not greater
+ than 16 bytes and TImode is 16-byte wide. */
+ gcc_assert (mode != BLKmode);
- case TImode : case CTImode :
- if (TARGET_ARCH64 && (slotno & 1) != 0)
- slotno++, *ppadding = 1;
+ /* Vector integers are handled like floats according to
+ the Sun VIS SDK. */
+ mclass = MODE_FLOAT;
+ }
+ }
+
+ switch (mclass)
+ {
+ case MODE_FLOAT:
+ case MODE_COMPLEX_FLOAT:
+ if (TARGET_ARCH64 && TARGET_FPU && named)
+ {
+ if (slotno >= SPARC_FP_ARG_MAX)
+ return -1;
+ regno = SPARC_FP_ARG_FIRST + slotno * 2;
+ /* Arguments filling only one single FP register are
+ right-justified in the outer double FP register. */
+ if (GET_MODE_SIZE (mode) <= 4)
+ regno++;
+ break;
+ }
/* fallthrough */
- case QImode : case CQImode :
- case HImode : case CHImode :
- case SImode : case CSImode :
- case DImode : case CDImode :
+ case MODE_INT:
+ case MODE_COMPLEX_INT:
if (slotno >= SPARC_INT_ARG_MAX)
return -1;
regno = regbase + slotno;
break;
- case TFmode : case TCmode :
- if (TARGET_ARCH64 && (slotno & 1) != 0)
- slotno++, *ppadding = 1;
- /* fallthrough */
-
- case SFmode : case SCmode :
- case DFmode : case DCmode :
- if (TARGET_ARCH32)
- {
- if (slotno >= SPARC_INT_ARG_MAX)
- return -1;
- regno = regbase + slotno;
- }
- else
- {
- if (TARGET_FPU && named)
- {
- if (slotno >= SPARC_FP_ARG_MAX)
- return -1;
- regno = SPARC_FP_ARG_FIRST + slotno * 2;
- if (mode == SFmode)
- regno++;
- }
- else
- {
- if (slotno >= SPARC_INT_ARG_MAX)
- return -1;
- regno = regbase + slotno;
- }
- }
- break;
+ case MODE_RANDOM:
+ if (mode == VOIDmode)
+ /* MODE is VOIDmode when generating the actual call. */
+ return -1;
- case BLKmode :
- /* For sparc64, objects requiring 16 byte alignment get it. */
- if (TARGET_ARCH64)
- {
- if (type && TYPE_ALIGN (type) == 128 && (slotno & 1) != 0)
- slotno++, *ppadding = 1;
- }
+ gcc_assert (mode == BLKmode);
if (TARGET_ARCH32
- || (type && TREE_CODE (type) == UNION_TYPE))
+ || !type
+ || (TREE_CODE (type) != VECTOR_TYPE
+ && TREE_CODE (type) != RECORD_TYPE))
{
if (slotno >= SPARC_INT_ARG_MAX)
return -1;
regno = regbase + slotno;
}
- else
+ else /* TARGET_ARCH64 && type */
{
int intregs_p = 0, fpregs_p = 0, packed_p = 0;
/* First see what kinds of registers we would need. */
- scan_record_type (type, &intregs_p, &fpregs_p, &packed_p);
+ if (TREE_CODE (type) == VECTOR_TYPE)
+ fpregs_p = 1;
+ else
+ scan_record_type (type, &intregs_p, &fpregs_p, &packed_p);
/* The ABI obviously doesn't specify how packed structures
are passed. These are defined to be passed in int regs
@@ -5053,10 +4587,12 @@ function_arg_slotno (const struct sparc_args *cum, enum machine_mode mode,
/* If all arg slots are filled, then must pass on stack. */
if (fpregs_p && slotno >= SPARC_FP_ARG_MAX)
return -1;
+
/* If there are only int args and all int arg slots are filled,
then must pass on stack. */
if (!fpregs_p && intregs_p && slotno >= SPARC_INT_ARG_MAX)
return -1;
+
/* Note that even if all int arg slots are filled, fp members may
still be passed in regs if such regs are available.
*PREGNO isn't set because there may be more than one, it's up
@@ -5066,7 +4602,7 @@ function_arg_slotno (const struct sparc_args *cum, enum machine_mode mode,
break;
default :
- abort ();
+ gcc_unreachable ();
}
*pregno = regno;
@@ -5129,9 +4665,14 @@ function_arg_record_value_1 (tree type, HOST_WIDE_INT startbitpos,
{
HOST_WIDE_INT bitpos = startbitpos;
- if (DECL_SIZE (field) != 0
- && host_integerp (bit_position (field), 1))
- bitpos += int_bit_position (field);
+ if (DECL_SIZE (field) != 0)
+ {
+ if (integer_zerop (DECL_SIZE (field)))
+ continue;
+
+ if (host_integerp (bit_position (field), 1))
+ bitpos += int_bit_position (field);
+ }
/* ??? FIXME: else assume zero offset. */
@@ -5140,7 +4681,8 @@ function_arg_record_value_1 (tree type, HOST_WIDE_INT startbitpos,
bitpos,
parms,
packed_p);
- else if (FLOAT_TYPE_P (TREE_TYPE (field))
+ else if ((FLOAT_TYPE_P (TREE_TYPE (field))
+ || TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE)
&& TARGET_FPU
&& parms->named
&& ! packed_p)
@@ -5170,8 +4712,12 @@ function_arg_record_value_1 (tree type, HOST_WIDE_INT startbitpos,
/* There's no need to check this_slotno < SPARC_FP_ARG MAX.
If it wasn't true we wouldn't be here. */
- parms->nregs += 1;
- if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE)
+ if (TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE
+ && DECL_MODE (field) == BLKmode)
+ parms->nregs += TYPE_VECTOR_SUBPARTS (TREE_TYPE (field));
+ else if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE)
+ parms->nregs += 2;
+ else
parms->nregs += 1;
}
else
@@ -5217,8 +4763,8 @@ function_arg_record_value_3 (HOST_WIDE_INT bitpos,
at the moment but may wish to revisit. */
if (intoffset % BITS_PER_WORD != 0)
- mode = mode_for_size (BITS_PER_WORD - intoffset % BITS_PER_WORD,
- MODE_INT, 0);
+ mode = smallest_mode_for_size (BITS_PER_WORD - intoffset % BITS_PER_WORD,
+ MODE_INT);
else
mode = word_mode;
@@ -5267,9 +4813,14 @@ function_arg_record_value_2 (tree type, HOST_WIDE_INT startbitpos,
{
HOST_WIDE_INT bitpos = startbitpos;
- if (DECL_SIZE (field) != 0
- && host_integerp (bit_position (field), 1))
- bitpos += int_bit_position (field);
+ if (DECL_SIZE (field) != 0)
+ {
+ if (integer_zerop (DECL_SIZE (field)))
+ continue;
+
+ if (host_integerp (bit_position (field), 1))
+ bitpos += int_bit_position (field);
+ }
/* ??? FIXME: else assume zero offset. */
@@ -5278,40 +4829,48 @@ function_arg_record_value_2 (tree type, HOST_WIDE_INT startbitpos,
bitpos,
parms,
packed_p);
- else if (FLOAT_TYPE_P (TREE_TYPE (field))
+ else if ((FLOAT_TYPE_P (TREE_TYPE (field))
+ || TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE)
&& TARGET_FPU
&& parms->named
&& ! packed_p)
{
int this_slotno = parms->slotno + bitpos / BITS_PER_WORD;
- int regno;
+ int regno, nregs, pos;
enum machine_mode mode = DECL_MODE (field);
rtx reg;
function_arg_record_value_3 (bitpos, parms);
- regno = SPARC_FP_ARG_FIRST + this_slotno * 2
- + ((mode == SFmode || mode == SCmode)
- && (bitpos & 32) != 0);
- switch (mode)
- {
- case SCmode: mode = SFmode; break;
- case DCmode: mode = DFmode; break;
- case TCmode: mode = TFmode; break;
- default: break;
+
+ if (TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE
+ && mode == BLKmode)
+ {
+ mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (field)));
+ nregs = TYPE_VECTOR_SUBPARTS (TREE_TYPE (field));
+ }
+ else if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE)
+ {
+ mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (field)));
+ nregs = 2;
}
+ else
+ nregs = 1;
+
+ regno = SPARC_FP_ARG_FIRST + this_slotno * 2;
+ if (GET_MODE_SIZE (mode) <= 4 && (bitpos & 32) != 0)
+ regno++;
reg = gen_rtx_REG (mode, regno);
+ pos = bitpos / BITS_PER_UNIT;
XVECEXP (parms->ret, 0, parms->stack + parms->nregs)
- = gen_rtx_EXPR_LIST (VOIDmode, reg,
- GEN_INT (bitpos / BITS_PER_UNIT));
+ = gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (pos));
parms->nregs += 1;
- if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE)
+ while (--nregs > 0)
{
regno += GET_MODE_SIZE (mode) / 4;
reg = gen_rtx_REG (mode, regno);
+ pos += GET_MODE_SIZE (mode);
XVECEXP (parms->ret, 0, parms->stack + parms->nregs)
- = gen_rtx_EXPR_LIST (VOIDmode, reg,
- GEN_INT ((bitpos + GET_MODE_BITSIZE (mode))
- / BITS_PER_UNIT));
+ = gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (pos));
parms->nregs += 1;
}
}
@@ -5400,15 +4959,14 @@ function_arg_record_value (tree type, enum machine_mode mode,
if (nregs + slotno > SPARC_INT_ARG_MAX)
nregs = SPARC_INT_ARG_MAX - slotno;
}
- if (nregs == 0)
- abort ();
+ gcc_assert (nregs != 0);
parms.ret = gen_rtx_PARALLEL (mode, rtvec_alloc (parms.stack + nregs));
/* If at least one field must be passed on the stack, generate
(parallel [(expr_list (nil) ...) ...]) so that all fields will
also be passed on the stack. We can't do much better because the
- semantics of FUNCTION_ARG_PARTIAL_NREGS doesn't handle the case
+ semantics of TARGET_ARG_PARTIAL_BYTES doesn't handle the case
of structures for which the fields passed exclusively in registers
are not at the beginning of the structure. */
if (parms.stack)
@@ -5421,8 +4979,7 @@ function_arg_record_value (tree type, enum machine_mode mode,
function_arg_record_value_2 (type, 0, &parms, false);
function_arg_record_value_3 (typesize * BITS_PER_UNIT, &parms);
- if (parms.nregs != nregs)
- abort ();
+ gcc_assert (parms.nregs == nregs);
return parms.ret;
}
@@ -5450,14 +5007,47 @@ function_arg_union_value (int size, enum machine_mode mode, int slotno,
if (slotno == SPARC_INT_ARG_MAX - 1)
nwords = 1;
- /* Unions are passed left-justified. */
regs = gen_rtx_PARALLEL (mode, rtvec_alloc (nwords));
for (i = 0; i < nwords; i++)
- XVECEXP (regs, 0, i)
- = gen_rtx_EXPR_LIST (VOIDmode,
- gen_rtx_REG (word_mode, regno + i),
- GEN_INT (UNITS_PER_WORD * i));
+ {
+ /* Unions are passed left-justified. */
+ XVECEXP (regs, 0, i)
+ = gen_rtx_EXPR_LIST (VOIDmode,
+ gen_rtx_REG (word_mode, regno),
+ GEN_INT (UNITS_PER_WORD * i));
+ regno++;
+ }
+
+ return regs;
+}
+
+/* Used by function_arg and function_value to implement the conventions
+ for passing and returning large (BLKmode) vectors.
+ Return an expression valid as a return value for the two macros
+ FUNCTION_ARG and FUNCTION_VALUE.
+
+ SIZE is the size in bytes of the vector.
+ BASE_MODE is the argument's base machine mode.
+ REGNO is the FP hard register the vector will be passed in. */
+
+static rtx
+function_arg_vector_value (int size, enum machine_mode base_mode, int regno)
+{
+ unsigned short base_mode_size = GET_MODE_SIZE (base_mode);
+ int nregs = size / base_mode_size, i;
+ rtx regs;
+
+ regs = gen_rtx_PARALLEL (BLKmode, rtvec_alloc (nregs));
+
+ for (i = 0; i < nregs; i++)
+ {
+ XVECEXP (regs, 0, i)
+ = gen_rtx_EXPR_LIST (VOIDmode,
+ gen_rtx_REG (base_mode, regno),
+ GEN_INT (base_mode_size * i));
+ regno += base_mode_size / 4;
+ }
return regs;
}
@@ -5485,48 +5075,59 @@ function_arg (const struct sparc_args *cum, enum machine_mode mode,
? SPARC_INCOMING_INT_ARG_FIRST
: SPARC_OUTGOING_INT_ARG_FIRST);
int slotno, regno, padding;
- rtx reg;
+ enum mode_class mclass = GET_MODE_CLASS (mode);
slotno = function_arg_slotno (cum, mode, type, named, incoming_p,
&regno, &padding);
-
if (slotno == -1)
return 0;
- if (TARGET_ARCH32)
+ /* Vector types deserve special treatment because they are polymorphic wrt
+ their mode, depending upon whether VIS instructions are enabled. */
+ if (type && TREE_CODE (type) == VECTOR_TYPE)
{
- reg = gen_rtx_REG (mode, regno);
- return reg;
+ HOST_WIDE_INT size = int_size_in_bytes (type);
+ gcc_assert ((TARGET_ARCH32 && size <= 8)
+ || (TARGET_ARCH64 && size <= 16));
+
+ if (mode == BLKmode)
+ return function_arg_vector_value (size,
+ TYPE_MODE (TREE_TYPE (type)),
+ SPARC_FP_ARG_FIRST + 2*slotno);
+ else
+ mclass = MODE_FLOAT;
}
-
+
+ if (TARGET_ARCH32)
+ return gen_rtx_REG (mode, regno);
+
+ /* Structures up to 16 bytes in size are passed in arg slots on the stack
+ and are promoted to registers if possible. */
if (type && TREE_CODE (type) == RECORD_TYPE)
{
- /* Structures up to 16 bytes in size are passed in arg slots on the
- stack and are promoted to registers where possible. */
-
- if (int_size_in_bytes (type) > 16)
- abort (); /* shouldn't get here */
+ HOST_WIDE_INT size = int_size_in_bytes (type);
+ gcc_assert (size <= 16);
return function_arg_record_value (type, mode, slotno, named, regbase);
}
+
+ /* Unions up to 16 bytes in size are passed in integer registers. */
else if (type && TREE_CODE (type) == UNION_TYPE)
{
HOST_WIDE_INT size = int_size_in_bytes (type);
-
- if (size > 16)
- abort (); /* shouldn't get here */
+ gcc_assert (size <= 16);
return function_arg_union_value (size, mode, slotno, regno);
}
+
/* v9 fp args in reg slots beyond the int reg slots get passed in regs
but also have the slot allocated for them.
If no prototype is in scope fp values in register slots get passed
in two places, either fp regs and int regs or fp regs and memory. */
- else if ((GET_MODE_CLASS (mode) == MODE_FLOAT
- || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
- && SPARC_FP_REG_P (regno))
+ else if ((mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT)
+ && SPARC_FP_REG_P (regno))
{
- reg = gen_rtx_REG (mode, regno);
+ rtx reg = gen_rtx_REG (mode, regno);
if (cum->prototype_p || cum->libcall_p)
{
/* "* 2" because fp reg numbers are recorded in 4 byte
@@ -5587,18 +5188,22 @@ function_arg (const struct sparc_args *cum, enum machine_mode mode,
}
}
}
- else
+
+ /* All other aggregate types are passed in an integer register in a mode
+ corresponding to the size of the type. */
+ else if (type && AGGREGATE_TYPE_P (type))
{
- /* Scalar or complex int. */
- reg = gen_rtx_REG (mode, regno);
+ HOST_WIDE_INT size = int_size_in_bytes (type);
+ gcc_assert (size <= 16);
+
+ mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
}
- return reg;
+ return gen_rtx_REG (mode, regno);
}
-/* Handle the FUNCTION_ARG_PARTIAL_NREGS macro.
- For an arg passed partly in registers and partly in memory,
- this is the number of registers used.
+/* For an arg passed partly in registers and partly in memory,
+ this is the number of bytes of registers used.
For args passed entirely in registers or entirely in memory, zero.
Any arg that starts in the first 6 regs but won't entirely fit in them
@@ -5607,9 +5212,9 @@ function_arg (const struct sparc_args *cum, enum machine_mode mode,
values that begin in the last fp reg [where "last fp reg" varies with the
mode] will be split between that reg and memory. */
-int
-function_arg_partial_nregs (const struct sparc_args *cum,
- enum machine_mode mode, tree type, int named)
+static int
+sparc_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+ tree type, bool named)
{
int slotno, regno, padding;
@@ -5624,84 +5229,92 @@ function_arg_partial_nregs (const struct sparc_args *cum,
if ((slotno + (mode == BLKmode
? ROUND_ADVANCE (int_size_in_bytes (type))
: ROUND_ADVANCE (GET_MODE_SIZE (mode))))
- > NPARM_REGS (SImode))
- return NPARM_REGS (SImode) - slotno;
- return 0;
+ > SPARC_INT_ARG_MAX)
+ return (SPARC_INT_ARG_MAX - slotno) * UNITS_PER_WORD;
}
else
{
+ /* We are guaranteed by pass_by_reference that the size of the
+ argument is not greater than 16 bytes, so we only need to return
+ one word if the argument is partially passed in registers. */
+
if (type && AGGREGATE_TYPE_P (type))
{
int size = int_size_in_bytes (type);
- int align = TYPE_ALIGN (type);
- if (align == 16)
- slotno += slotno & 1;
- if (size > 8 && size <= 16
+ if (size > UNITS_PER_WORD
&& slotno == SPARC_INT_ARG_MAX - 1)
- return 1;
+ return UNITS_PER_WORD;
}
else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
|| (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
&& ! (TARGET_FPU && named)))
{
/* The complex types are passed as packed types. */
- if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
- return 0;
-
- if (GET_MODE_ALIGNMENT (mode) == 128)
- {
- slotno += slotno & 1;
-
- /* ??? The mode needs 3 slots? */
- if (slotno == SPARC_INT_ARG_MAX - 2)
- return 1;
- }
- else
- {
- if (slotno == SPARC_INT_ARG_MAX - 1)
- return 1;
- }
+ if (GET_MODE_SIZE (mode) > UNITS_PER_WORD
+ && slotno == SPARC_INT_ARG_MAX - 1)
+ return UNITS_PER_WORD;
}
else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
{
- if (GET_MODE_ALIGNMENT (mode) == 128)
- slotno += slotno & 1;
if ((slotno + GET_MODE_SIZE (mode) / UNITS_PER_WORD)
> SPARC_FP_ARG_MAX)
- return 1;
+ return UNITS_PER_WORD;
}
- return 0;
}
+
+ return 0;
}
-/* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
- !v9: The SPARC ABI stipulates passing struct arguments (of any size) and
- quad-precision floats by invisible reference.
- v9: Aggregates greater than 16 bytes are passed by reference.
- For Pascal, also pass arrays by reference. */
+/* Handle the TARGET_PASS_BY_REFERENCE target hook.
+ Specify whether to pass the argument by reference. */
-int
-function_arg_pass_by_reference (const struct sparc_args *cum ATTRIBUTE_UNUSED,
- enum machine_mode mode, tree type,
- int named ATTRIBUTE_UNUSED)
+static bool
+sparc_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
+ enum machine_mode mode, tree type,
+ bool named ATTRIBUTE_UNUSED)
{
if (TARGET_ARCH32)
- {
- return ((type && AGGREGATE_TYPE_P (type))
- || mode == SCmode
- || GET_MODE_SIZE (mode) > 8);
- }
+ /* Original SPARC 32-bit ABI says that structures and unions,
+ and quad-precision floats are passed by reference. For Pascal,
+ also pass arrays by reference. All other base types are passed
+ in registers.
+
+ Extended ABI (as implemented by the Sun compiler) says that all
+ complex floats are passed by reference. Pass complex integers
+ in registers up to 8 bytes. More generally, enforce the 2-word
+ cap for passing arguments in registers.
+
+ Vector ABI (as implemented by the Sun VIS SDK) says that vector
+ integers are passed like floats of the same size, that is in
+ registers up to 8 bytes. Pass all vector floats by reference
+ like structure and unions. */
+ return ((type && (AGGREGATE_TYPE_P (type) || VECTOR_FLOAT_TYPE_P (type)))
+ || mode == SCmode
+ /* Catch CDImode, TFmode, DCmode and TCmode. */
+ || GET_MODE_SIZE (mode) > 8
+ || (type
+ && TREE_CODE (type) == VECTOR_TYPE
+ && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 8));
else
- {
- return ((type && TREE_CODE (type) == ARRAY_TYPE)
- /* Consider complex values as aggregates, so care
- for CTImode and TCmode. */
- || GET_MODE_SIZE (mode) > 16
- || (type
- && AGGREGATE_TYPE_P (type)
- && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 16));
- }
+ /* Original SPARC 64-bit ABI says that structures and unions
+ smaller than 16 bytes are passed in registers, as well as
+ all other base types.
+
+ Extended ABI (as implemented by the Sun compiler) says that
+ complex floats are passed in registers up to 16 bytes. Pass
+ all complex integers in registers up to 16 bytes. More generally,
+ enforce the 2-word cap for passing arguments in registers.
+
+ Vector ABI (as implemented by the Sun VIS SDK) says that vector
+ integers are passed like floats of the same size, that is in
+ registers (up to 16 bytes). Pass all vector floats like structure
+ and unions. */
+ return ((type
+ && (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == VECTOR_TYPE)
+ && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 16)
+ /* Catch CTImode and TCmode. */
+ || GET_MODE_SIZE (mode) > 16);
}
/* Handle the FUNCTION_ARG_ADVANCE macro.
@@ -5764,50 +5377,177 @@ function_arg_padding (enum machine_mode mode, tree type)
return DEFAULT_FUNCTION_ARG_PADDING (mode, type);
}
+/* Handle the TARGET_RETURN_IN_MEMORY target hook.
+ Specify whether to return the return value in memory. */
+
+static bool
+sparc_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
+{
+ if (TARGET_ARCH32)
+ /* Original SPARC 32-bit ABI says that structures and unions,
+ and quad-precision floats are returned in memory. All other
+ base types are returned in registers.
+
+ Extended ABI (as implemented by the Sun compiler) says that
+ all complex floats are returned in registers (8 FP registers
+ at most for '_Complex long double'). Return all complex integers
+ in registers (4 at most for '_Complex long long').
+
+ Vector ABI (as implemented by the Sun VIS SDK) says that vector
+ integers are returned like floats of the same size, that is in
+ registers up to 8 bytes and in memory otherwise. Return all
+ vector floats in memory like structure and unions; note that
+ they always have BLKmode like the latter. */
+ return (TYPE_MODE (type) == BLKmode
+ || TYPE_MODE (type) == TFmode
+ || (TREE_CODE (type) == VECTOR_TYPE
+ && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 8));
+ else
+ /* Original SPARC 64-bit ABI says that structures and unions
+ smaller than 32 bytes are returned in registers, as well as
+ all other base types.
+
+ Extended ABI (as implemented by the Sun compiler) says that all
+ complex floats are returned in registers (8 FP registers at most
+ for '_Complex long double'). Return all complex integers in
+ registers (4 at most for '_Complex TItype').
+
+ Vector ABI (as implemented by the Sun VIS SDK) says that vector
+ integers are returned like floats of the same size, that is in
+ registers. Return all vector floats like structure and unions;
+ note that they always have BLKmode like the latter. */
+ return ((TYPE_MODE (type) == BLKmode
+ && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 32));
+}
+
+/* Handle the TARGET_STRUCT_VALUE target hook.
+ Return where to find the structure return value address. */
+
+static rtx
+sparc_struct_value_rtx (tree fndecl, int incoming)
+{
+ if (TARGET_ARCH64)
+ return 0;
+ else
+ {
+ rtx mem;
+
+ if (incoming)
+ mem = gen_rtx_MEM (Pmode, plus_constant (frame_pointer_rtx,
+ STRUCT_VALUE_OFFSET));
+ else
+ mem = gen_rtx_MEM (Pmode, plus_constant (stack_pointer_rtx,
+ STRUCT_VALUE_OFFSET));
+
+ /* Only follow the SPARC ABI for fixed-size structure returns.
+ Variable size structure returns are handled per the normal
+ procedures in GCC. This is enabled by -mstd-struct-return */
+ if (incoming == 2
+ && sparc_std_struct_return
+ && TYPE_SIZE_UNIT (TREE_TYPE (fndecl))
+ && TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (fndecl))) == INTEGER_CST)
+ {
+ /* We must check and adjust the return address, as it is
+ optional as to whether the return object is really
+ provided. */
+ rtx ret_rtx = gen_rtx_REG (Pmode, 31);
+ rtx scratch = gen_reg_rtx (SImode);
+ rtx endlab = gen_label_rtx ();
+
+ /* Calculate the return object size */
+ tree size = TYPE_SIZE_UNIT (TREE_TYPE (fndecl));
+ rtx size_rtx = GEN_INT (TREE_INT_CST_LOW (size) & 0xfff);
+ /* Construct a temporary return value */
+ rtx temp_val = assign_stack_local (Pmode, TREE_INT_CST_LOW (size), 0);
+
+ /* Implement SPARC 32-bit psABI callee returns struck checking
+ requirements:
+
+ Fetch the instruction where we will return to and see if
+ it's an unimp instruction (the most significant 10 bits
+ will be zero). */
+ emit_move_insn (scratch, gen_rtx_MEM (SImode,
+ plus_constant (ret_rtx, 8)));
+ /* Assume the size is valid and pre-adjust */
+ emit_insn (gen_add3_insn (ret_rtx, ret_rtx, GEN_INT (4)));
+ emit_cmp_and_jump_insns (scratch, size_rtx, EQ, const0_rtx, SImode, 0, endlab);
+ emit_insn (gen_sub3_insn (ret_rtx, ret_rtx, GEN_INT (4)));
+ /* Assign stack temp:
+ Write the address of the memory pointed to by temp_val into
+ the memory pointed to by mem */
+ emit_move_insn (mem, XEXP (temp_val, 0));
+ emit_label (endlab);
+ }
+
+ set_mem_alias_set (mem, struct_value_alias_set);
+ return mem;
+ }
+}
+
/* Handle FUNCTION_VALUE, FUNCTION_OUTGOING_VALUE, and LIBCALL_VALUE macros.
For v9, function return values are subject to the same rules as arguments,
- except that up to 32-bytes may be returned in registers. */
+ except that up to 32 bytes may be returned in registers. */
rtx
function_value (tree type, enum machine_mode mode, int incoming_p)
{
+ /* Beware that the two values are swapped here wrt function_arg. */
+ int regbase = (incoming_p
+ ? SPARC_OUTGOING_INT_ARG_FIRST
+ : SPARC_INCOMING_INT_ARG_FIRST);
+ enum mode_class mclass = GET_MODE_CLASS (mode);
int regno;
- if (TARGET_ARCH64 && type)
+ /* Vector types deserve special treatment because they are polymorphic wrt
+ their mode, depending upon whether VIS instructions are enabled. */
+ if (type && TREE_CODE (type) == VECTOR_TYPE)
{
- int regbase = (incoming_p
- ? SPARC_OUTGOING_INT_ARG_FIRST
- : SPARC_INCOMING_INT_ARG_FIRST);
+ HOST_WIDE_INT size = int_size_in_bytes (type);
+ gcc_assert ((TARGET_ARCH32 && size <= 8)
+ || (TARGET_ARCH64 && size <= 32));
+
+ if (mode == BLKmode)
+ return function_arg_vector_value (size,
+ TYPE_MODE (TREE_TYPE (type)),
+ SPARC_FP_ARG_FIRST);
+ else
+ mclass = MODE_FLOAT;
+ }
+ if (TARGET_ARCH64 && type)
+ {
+ /* Structures up to 32 bytes in size are returned in registers. */
if (TREE_CODE (type) == RECORD_TYPE)
{
- /* Structures up to 32 bytes in size are passed in registers,
- promoted to fp registers where possible. */
-
- if (int_size_in_bytes (type) > 32)
- abort (); /* shouldn't get here */
+ HOST_WIDE_INT size = int_size_in_bytes (type);
+ gcc_assert (size <= 32);
return function_arg_record_value (type, mode, 0, 1, regbase);
}
+
+ /* Unions up to 32 bytes in size are returned in integer registers. */
else if (TREE_CODE (type) == UNION_TYPE)
{
HOST_WIDE_INT size = int_size_in_bytes (type);
-
- if (size > 32)
- abort (); /* shouldn't get here */
+ gcc_assert (size <= 32);
return function_arg_union_value (size, mode, 0, regbase);
}
+
+ /* Objects that require it are returned in FP registers. */
+ else if (mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT)
+ ;
+
+ /* All other aggregate types are returned in an integer register in a
+ mode corresponding to the size of the type. */
else if (AGGREGATE_TYPE_P (type))
{
/* All other aggregate types are passed in an integer register
in a mode corresponding to the size of the type. */
- HOST_WIDE_INT bytes = int_size_in_bytes (type);
-
- if (bytes > 32)
- abort ();
+ HOST_WIDE_INT size = int_size_in_bytes (type);
+ gcc_assert (size <= 32);
- mode = mode_for_size (bytes * BITS_PER_UNIT, MODE_INT, 0);
+ mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
/* ??? We probably should have made the same ABI change in
3.4.0 as the one we made for unions. The latter was
@@ -5819,17 +5559,20 @@ function_value (tree type, enum machine_mode mode, int incoming_p)
try to be unduly clever, and simply follow the ABI
for unions in that case. */
if (mode == BLKmode)
- return function_arg_union_value (bytes, mode, 0, regbase);
+ return function_arg_union_value (size, mode, 0, regbase);
+ else
+ mclass = MODE_INT;
}
- else if (GET_MODE_CLASS (mode) == MODE_INT
- && GET_MODE_SIZE (mode) < UNITS_PER_WORD)
+
+ /* This must match PROMOTE_FUNCTION_MODE. */
+ else if (mclass == MODE_INT && GET_MODE_SIZE (mode) < UNITS_PER_WORD)
mode = word_mode;
}
- if (incoming_p)
- regno = BASE_RETURN_VALUE_REG (mode);
+ if ((mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT) && TARGET_FPU)
+ regno = SPARC_FP_ARG_FIRST;
else
- regno = BASE_OUTGOING_VALUE_REG (mode);
+ regno = regbase;
return gen_rtx_REG (mode, regno);
}
@@ -5838,14 +5581,14 @@ function_value (tree type, enum machine_mode mode, int incoming_p)
to determine if stdarg or varargs is used and return the address of
the first unnamed parameter. */
-rtx
+static rtx
sparc_builtin_saveregs (void)
{
int first_reg = current_function_args_info.words;
rtx address;
int regno;
- for (regno = first_reg; regno < NPARM_REGS (word_mode); regno++)
+ for (regno = first_reg; regno < SPARC_INT_ARG_MAX; regno++)
emit_move_insn (gen_rtx_MEM (word_mode,
gen_rtx_PLUS (Pmode,
frame_pointer_rtx,
@@ -5853,7 +5596,7 @@ sparc_builtin_saveregs (void)
+ (UNITS_PER_WORD
* regno)))),
gen_rtx_REG (word_mode,
- BASE_INCOMING_ARG_REG (word_mode) + regno));
+ SPARC_INCOMING_INT_ARG_FIRST + regno));
address = gen_rtx_PLUS (Pmode,
frame_pointer_rtx,
@@ -5863,7 +5606,7 @@ sparc_builtin_saveregs (void)
return address;
}
-/* Implement `va_start' for varargs and stdarg. */
+/* Implement `va_start' for stdarg. */
void
sparc_va_start (tree valist, rtx nextarg)
@@ -5872,119 +5615,105 @@ sparc_va_start (tree valist, rtx nextarg)
std_expand_builtin_va_start (valist, nextarg);
}
-/* Implement `va_arg'. */
+/* Implement `va_arg' for stdarg. */
-rtx
-sparc_va_arg (tree valist, tree type)
+static tree
+sparc_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
{
HOST_WIDE_INT size, rsize, align;
tree addr, incr;
- rtx addr_rtx;
- int indirect = 0;
-
- /* Round up sizeof(type) to a word. */
- size = int_size_in_bytes (type);
- rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
- align = 0;
+ bool indirect;
+ tree ptrtype = build_pointer_type (type);
- if (TARGET_ARCH64)
+ if (pass_by_reference (NULL, TYPE_MODE (type), type, false))
{
- if (TYPE_ALIGN (type) >= 2 * (unsigned) BITS_PER_WORD)
- align = 2 * UNITS_PER_WORD;
-
- /* Consider complex values as aggregates, so care
- for CTImode and TCmode. */
- if ((unsigned HOST_WIDE_INT) size > 16)
- {
- indirect = 1;
- size = rsize = UNITS_PER_WORD;
- align = 0;
- }
- else if (AGGREGATE_TYPE_P (type))
- {
- /* SPARC-V9 ABI states that structures up to 16 bytes in size
- are given whole slots as needed. */
- if (size == 0)
- size = rsize = UNITS_PER_WORD;
- else
- size = rsize;
- }
+ indirect = true;
+ size = rsize = UNITS_PER_WORD;
+ align = 0;
}
else
{
- if (AGGREGATE_TYPE_P (type)
- || TYPE_MODE (type) == SCmode
- || GET_MODE_SIZE (TYPE_MODE (type)) > 8)
+ indirect = false;
+ size = int_size_in_bytes (type);
+ rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
+ align = 0;
+
+ if (TARGET_ARCH64)
{
- indirect = 1;
- size = rsize = UNITS_PER_WORD;
+ /* For SPARC64, objects requiring 16-byte alignment get it. */
+ if (TYPE_ALIGN (type) >= 2 * (unsigned) BITS_PER_WORD)
+ align = 2 * UNITS_PER_WORD;
+
+ /* SPARC-V9 ABI states that structures up to 16 bytes in size
+ are left-justified in their slots. */
+ if (AGGREGATE_TYPE_P (type))
+ {
+ if (size == 0)
+ size = rsize = UNITS_PER_WORD;
+ else
+ size = rsize;
+ }
}
}
incr = valist;
if (align)
{
- incr = fold (build (PLUS_EXPR, ptr_type_node, incr,
- build_int_2 (align - 1, 0)));
- incr = fold (build (BIT_AND_EXPR, ptr_type_node, incr,
- build_int_2 (-align, -1)));
+ incr = fold (build2 (PLUS_EXPR, ptr_type_node, incr,
+ ssize_int (align - 1)));
+ incr = fold (build2 (BIT_AND_EXPR, ptr_type_node, incr,
+ ssize_int (-align)));
}
- addr = incr = save_expr (incr);
+ gimplify_expr (&incr, pre_p, post_p, is_gimple_val, fb_rvalue);
+ addr = incr;
+
if (BYTES_BIG_ENDIAN && size < rsize)
+ addr = fold (build2 (PLUS_EXPR, ptr_type_node, incr,
+ ssize_int (rsize - size)));
+
+ if (indirect)
{
- addr = fold (build (PLUS_EXPR, ptr_type_node, incr,
- build_int_2 (rsize - size, 0)));
+ addr = fold_convert (build_pointer_type (ptrtype), addr);
+ addr = build_va_arg_indirect_ref (addr);
}
- incr = fold (build (PLUS_EXPR, ptr_type_node, incr,
- build_int_2 (rsize, 0)));
-
- incr = build (MODIFY_EXPR, ptr_type_node, valist, incr);
- TREE_SIDE_EFFECTS (incr) = 1;
- expand_expr (incr, const0_rtx, VOIDmode, EXPAND_NORMAL);
-
- addr_rtx = expand_expr (addr, NULL, Pmode, EXPAND_NORMAL);
-
/* If the address isn't aligned properly for the type,
we may need to copy to a temporary.
FIXME: This is inefficient. Usually we can do this
in registers. */
- if (align == 0
- && TYPE_ALIGN (type) > BITS_PER_WORD
- && !indirect)
- {
- /* FIXME: We really need to specify that the temporary is live
- for the whole function because expand_builtin_va_arg wants
- the alias set to be get_varargs_alias_set (), but in this
- case the alias set is that for TYPE and if the memory gets
- reused it will be reused with alias set TYPE. */
- rtx tmp = assign_temp (type, 0, 1, 0);
- rtx dest_addr;
-
- addr_rtx = force_reg (Pmode, addr_rtx);
- addr_rtx = gen_rtx_MEM (BLKmode, addr_rtx);
- set_mem_alias_set (addr_rtx, get_varargs_alias_set ());
- set_mem_align (addr_rtx, BITS_PER_WORD);
- tmp = shallow_copy_rtx (tmp);
- PUT_MODE (tmp, BLKmode);
- set_mem_alias_set (tmp, 0);
-
- dest_addr = emit_block_move (tmp, addr_rtx, GEN_INT (rsize),
- BLOCK_OP_NORMAL);
- if (dest_addr != NULL_RTX)
- addr_rtx = dest_addr;
- else
- addr_rtx = XCEXP (tmp, 0, MEM);
- }
-
- if (indirect)
+ else if (align == 0
+ && TYPE_ALIGN (type) > BITS_PER_WORD)
{
- addr_rtx = force_reg (Pmode, addr_rtx);
- addr_rtx = gen_rtx_MEM (Pmode, addr_rtx);
- set_mem_alias_set (addr_rtx, get_varargs_alias_set ());
+ tree tmp = create_tmp_var (type, "va_arg_tmp");
+ tree dest_addr = build_fold_addr_expr (tmp);
+
+ tree copy = build_function_call_expr
+ (implicit_built_in_decls[BUILT_IN_MEMCPY],
+ tree_cons (NULL_TREE, dest_addr,
+ tree_cons (NULL_TREE, addr,
+ tree_cons (NULL_TREE, size_int (rsize),
+ NULL_TREE))));
+
+ gimplify_and_add (copy, pre_p);
+ addr = dest_addr;
}
+ else
+ addr = fold_convert (ptrtype, addr);
+
+ incr = fold (build2 (PLUS_EXPR, ptr_type_node, incr, ssize_int (rsize)));
+ incr = build2 (MODIFY_EXPR, ptr_type_node, valist, incr);
+ gimplify_and_add (incr, post_p);
+
+ return build_va_arg_indirect_ref (addr);
+}
+
+/* Implement the TARGET_VECTOR_MODE_SUPPORTED_P target hook.
+ Specify whether the vector mode is supported by the hardware. */
- return addr_rtx;
+static bool
+sparc_vector_mode_supported_p (enum machine_mode mode)
+{
+ return TARGET_VIS && VECTOR_MODE_P (mode) ? true : false;
}
/* Return the string to output an unconditional branch to LABEL, which is
@@ -5996,51 +5725,29 @@ const char *
output_ubranch (rtx dest, int label, rtx insn)
{
static char string[64];
- bool noop = false;
+ bool v9_form = false;
char *p;
- /* TurboSPARC is reported to have problems with
- with
- foo: b,a foo
- i.e. an empty loop with the annul bit set. The workaround is to use
- foo: b foo; nop
- instead. */
-
- if (! TARGET_V9 && flag_delayed_branch
- && (INSN_ADDRESSES (INSN_UID (dest))
- == INSN_ADDRESSES (INSN_UID (insn))))
+ if (TARGET_V9 && INSN_ADDRESSES_SET_P ())
{
- strcpy (string, "b\t");
- noop = true;
+ int delta = (INSN_ADDRESSES (INSN_UID (dest))
+ - INSN_ADDRESSES (INSN_UID (insn)));
+ /* Leave some instructions for "slop". */
+ if (delta >= -260000 && delta < 260000)
+ v9_form = true;
}
- else
- {
- bool v9_form = false;
- if (TARGET_V9 && INSN_ADDRESSES_SET_P ())
- {
- int delta = (INSN_ADDRESSES (INSN_UID (dest))
- - INSN_ADDRESSES (INSN_UID (insn)));
- /* Leave some instructions for "slop". */
- if (delta >= -260000 && delta < 260000)
- v9_form = true;
- }
-
- if (v9_form)
- strcpy (string, "ba%*,pt\t%%xcc, ");
- else
- strcpy (string, "b%*\t");
- }
+ if (v9_form)
+ strcpy (string, "ba%*,pt\t%%xcc, ");
+ else
+ strcpy (string, "b%*\t");
p = strchr (string, '\0');
*p++ = '%';
*p++ = 'l';
*p++ = '0' + label;
*p++ = '%';
- if (noop)
- *p++ = '#';
- else
- *p++ = '(';
+ *p++ = '(';
*p = '\0';
return string;
@@ -6055,15 +5762,13 @@ output_ubranch (rtx dest, int label, rtx insn)
REVERSED is nonzero if we should reverse the sense of the comparison.
- ANNUL is nonzero if we should generate an annulling branch.
-
- NOOP is nonzero if we have to follow this branch by a noop. */
+ ANNUL is nonzero if we should generate an annulling branch. */
-char *
+const char *
output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
- int noop, rtx insn)
+ rtx insn)
{
- static char string[50];
+ static char string[64];
enum rtx_code code = GET_CODE (op);
rtx cc_reg = XEXP (op, 0);
enum machine_mode mode = GET_MODE (cc_reg);
@@ -6079,7 +5784,7 @@ output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
to
be,pn %xcc, .+12
- nop
+ nop
ba .LC30
and
@@ -6089,7 +5794,7 @@ output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
to
fbe,pt %fcc2, .+16
- nop
+ nop
ba .LC29 */
far = TARGET_V9 && (get_attr_length (insn) >= 3);
@@ -6152,7 +5857,7 @@ output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
break;
default:
- abort ();
+ gcc_unreachable ();
}
/* ??? !v9: FP branches cannot be preceded by another floating point
@@ -6207,7 +5912,7 @@ output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
break;
default:
- abort ();
+ gcc_unreachable ();
}
strcpy (string, branch);
}
@@ -6244,17 +5949,14 @@ output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
labelno = v9_fcc_labelno;
if (v8)
{
- if (REGNO (cc_reg) == SPARC_FCC_REG)
- labelno = "";
- else
- abort ();
+ gcc_assert (REGNO (cc_reg) == SPARC_FCC_REG);
+ labelno = "";
}
}
else if (mode == CCXmode || mode == CCX_NOOVmode)
{
labelno = "%%xcc, ";
- if (v8)
- abort ();
+ gcc_assert (! v8);
}
else
{
@@ -6283,19 +5985,19 @@ output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
p = strchr (p, '\0');
if (far)
{
- strcpy (p, ".+12\n\tnop\n\tb\t");
- if (annul || noop)
+ strcpy (p, ".+12\n\t nop\n\tb\t");
+ /* Skip the next insn if requested or
+ if we know that it will be a nop. */
+ if (annul || ! final_sequence)
p[3] = '6';
- p += 13;
+ p += 14;
}
*p++ = '%';
*p++ = 'l';
- /* Set the char indicating the number of the operand containing the
- label_ref. */
*p++ = label + '0';
+ *p++ = '%';
+ *p++ = '#';
*p = '\0';
- if (noop)
- strcpy (p, "\n\tnop");
return string;
}
@@ -6350,8 +6052,7 @@ sparc_emit_float_lib_cmp (rtx x, rtx y, enum rtx_code comparison)
break;
default:
- abort();
- break;
+ gcc_unreachable ();
}
if (TARGET_ARCH64)
@@ -6359,7 +6060,7 @@ sparc_emit_float_lib_cmp (rtx x, rtx y, enum rtx_code comparison)
if (GET_CODE (x) != MEM)
{
slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
- emit_insn (gen_rtx_SET (VOIDmode, slot0, x));
+ emit_move_insn (slot0, x);
}
else
slot0 = x;
@@ -6367,7 +6068,7 @@ sparc_emit_float_lib_cmp (rtx x, rtx y, enum rtx_code comparison)
if (GET_CODE (y) != MEM)
{
slot1 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
- emit_insn (gen_rtx_SET (VOIDmode, slot1, y));
+ emit_move_insn (slot1, y);
}
else
slot1 = y;
@@ -6443,14 +6144,12 @@ sparc_emit_float_lib_cmp (rtx x, rtx y, enum rtx_code comparison)
optabs would emit if we didn't have TFmode patterns. */
void
-sparc_emit_floatunsdi (rtx *operands)
+sparc_emit_floatunsdi (rtx *operands, enum machine_mode mode)
{
rtx neglab, donelab, i0, i1, f0, in, out;
- enum machine_mode mode;
out = operands[0];
in = force_reg (DImode, operands[1]);
- mode = GET_MODE (out);
neglab = gen_label_rtx ();
donelab = gen_label_rtx ();
i0 = gen_reg_rtx (DImode);
@@ -6474,6 +6173,47 @@ sparc_emit_floatunsdi (rtx *operands)
emit_label (donelab);
}
+/* Generate an FP to unsigned DImode conversion. This is the same code
+ optabs would emit if we didn't have TFmode patterns. */
+
+void
+sparc_emit_fixunsdi (rtx *operands, enum machine_mode mode)
+{
+ rtx neglab, donelab, i0, i1, f0, in, out, limit;
+
+ out = operands[0];
+ in = force_reg (mode, operands[1]);
+ neglab = gen_label_rtx ();
+ donelab = gen_label_rtx ();
+ i0 = gen_reg_rtx (DImode);
+ i1 = gen_reg_rtx (DImode);
+ limit = gen_reg_rtx (mode);
+ f0 = gen_reg_rtx (mode);
+
+ emit_move_insn (limit,
+ CONST_DOUBLE_FROM_REAL_VALUE (
+ REAL_VALUE_ATOF ("9223372036854775808.0", mode), mode));
+ emit_cmp_and_jump_insns (in, limit, GE, NULL_RTX, mode, 0, neglab);
+
+ emit_insn (gen_rtx_SET (VOIDmode,
+ out,
+ gen_rtx_FIX (DImode, gen_rtx_FIX (mode, in))));
+ emit_jump_insn (gen_jump (donelab));
+ emit_barrier ();
+
+ emit_label (neglab);
+
+ emit_insn (gen_rtx_SET (VOIDmode, f0, gen_rtx_MINUS (mode, in, limit)));
+ emit_insn (gen_rtx_SET (VOIDmode,
+ i0,
+ gen_rtx_FIX (DImode, gen_rtx_FIX (mode, f0))));
+ emit_insn (gen_movdi (i1, const1_rtx));
+ emit_insn (gen_ashldi3 (i1, i1, GEN_INT (63)));
+ emit_insn (gen_xordi3 (out, i0, i1));
+
+ emit_label (donelab);
+}
+
/* Return the string to output a conditional branch to LABEL, testing
register REG. LABEL is the operand number of the label; REG is the
operand number of the reg. OP is the conditional expression. The mode
@@ -6483,15 +6223,13 @@ sparc_emit_floatunsdi (rtx *operands)
REVERSED is nonzero if we should reverse the sense of the comparison.
- ANNUL is nonzero if we should generate an annulling branch.
+ ANNUL is nonzero if we should generate an annulling branch. */
- NOOP is nonzero if we have to follow this branch by a noop. */
-
-char *
+const char *
output_v9branch (rtx op, rtx dest, int reg, int label, int reversed,
- int annul, int noop, rtx insn)
+ int annul, rtx insn)
{
- static char string[50];
+ static char string[64];
enum rtx_code code = GET_CODE (op);
enum machine_mode mode = GET_MODE (XEXP (op, 0));
rtx note;
@@ -6506,7 +6244,7 @@ output_v9branch (rtx op, rtx dest, int reg, int label, int reversed,
to
brz,pn %g1, .+12
- nop
+ nop
ba,pt %xcc, .LC30
and
@@ -6516,7 +6254,7 @@ output_v9branch (rtx op, rtx dest, int reg, int label, int reversed,
to
brlz,pt %o1, .+16
- nop
+ nop
ba,pt %xcc, .LC29 */
far = get_attr_length (insn) >= 3;
@@ -6526,8 +6264,7 @@ output_v9branch (rtx op, rtx dest, int reg, int label, int reversed,
code = reverse_condition (code);
/* Only 64 bit versions of these instructions exist. */
- if (mode != DImode)
- abort ();
+ gcc_assert (mode == DImode);
/* Start by writing the branch condition. */
@@ -6558,7 +6295,7 @@ output_v9branch (rtx op, rtx dest, int reg, int label, int reversed,
break;
default:
- abort ();
+ gcc_unreachable ();
}
p = strchr (string, '\0');
@@ -6597,10 +6334,12 @@ output_v9branch (rtx op, rtx dest, int reg, int label, int reversed,
veryfar = 0;
}
- strcpy (p, ".+12\n\tnop\n\t");
- if (annul || noop)
+ strcpy (p, ".+12\n\t nop\n\t");
+ /* Skip the next insn if requested or
+ if we know that it will be a nop. */
+ if (annul || ! final_sequence)
p[3] = '6';
- p += 11;
+ p += 12;
if (veryfar)
{
strcpy (p, "b\t");
@@ -6615,11 +6354,10 @@ output_v9branch (rtx op, rtx dest, int reg, int label, int reversed,
*p++ = '%';
*p++ = 'l';
*p++ = '0' + label;
+ *p++ = '%';
+ *p++ = '#';
*p = '\0';
- if (noop)
- strcpy (p, "\n\tnop");
-
return string;
}
@@ -6646,7 +6384,7 @@ epilogue_renumber (register rtx *where, int test)
if (REGNO (*where) >= 8 && REGNO (*where) < 24) /* oX or lX */
return 1;
if (! test && REGNO (*where) >= 24 && REGNO (*where) < 32)
- *where = gen_rtx (REG, GET_MODE (*where), OUTGOING_REGNO (REGNO(*where)));
+ *where = gen_rtx_REG (GET_MODE (*where), OUTGOING_REGNO (REGNO(*where)));
case SCRATCH:
case CC0:
case PC:
@@ -6733,8 +6471,7 @@ int
sparc_splitdi_legitimate (rtx reg, rtx mem)
{
/* Punt if we are here by mistake. */
- if (! reload_completed)
- abort ();
+ gcc_assert (reload_completed);
/* We must have an offsettable memory reference. */
if (! offsettable_memref_p (mem))
@@ -6916,42 +6653,60 @@ print_operand (FILE *file, rtx x, int code)
switch (code)
{
case '#':
- /* Output a 'nop' if there's nothing for the delay slot. */
- if (dbr_sequence_length () == 0)
+ /* Output an insn in a delay slot. */
+ if (final_sequence)
+ sparc_indent_opcode = 1;
+ else
fputs ("\n\t nop", file);
return;
case '*':
/* Output an annul flag if there's nothing for the delay slot and we
- are optimizing. This is always used with '(' below. */
- /* Sun OS 4.1.1 dbx can't handle an annulled unconditional branch;
- this is a dbx bug. So, we only do this when optimizing. */
- /* On UltraSPARC, a branch in a delay slot causes a pipeline flush.
+ are optimizing. This is always used with '(' below.
+ Sun OS 4.1.1 dbx can't handle an annulled unconditional branch;
+ this is a dbx bug. So, we only do this when optimizing.
+ On UltraSPARC, a branch in a delay slot causes a pipeline flush.
Always emit a nop in case the next instruction is a branch. */
- if (dbr_sequence_length () == 0
- && (optimize && (int)sparc_cpu < PROCESSOR_V9))
+ if (! final_sequence && (optimize && (int)sparc_cpu < PROCESSOR_V9))
fputs (",a", file);
return;
case '(':
/* Output a 'nop' if there's nothing for the delay slot and we are
not optimizing. This is always used with '*' above. */
- if (dbr_sequence_length () == 0
- && ! (optimize && (int)sparc_cpu < PROCESSOR_V9))
+ if (! final_sequence && ! (optimize && (int)sparc_cpu < PROCESSOR_V9))
fputs ("\n\t nop", file);
+ else if (final_sequence)
+ sparc_indent_opcode = 1;
+ return;
+ case ')':
+ /* Output the right displacement from the saved PC on function return.
+ The caller may have placed an "unimp" insn immediately after the call
+ so we have to account for it. This insn is used in the 32-bit ABI
+ when calling a function that returns a non zero-sized structure. The
+ 64-bit ABI doesn't have it. Be careful to have this test be the same
+ as that used on the call. The exception here is that when
+ sparc_std_struct_return is enabled, the psABI is followed exactly
+ and the adjustment is made by the code in sparc_struct_value_rtx.
+ The call emitted is the same when sparc_std_struct_return is
+ present. */
+ if (! TARGET_ARCH64
+ && current_function_returns_struct
+ && ! sparc_std_struct_return
+ && (TREE_CODE (DECL_SIZE (DECL_RESULT (current_function_decl)))
+ == INTEGER_CST)
+ && ! integer_zerop (DECL_SIZE (DECL_RESULT (current_function_decl))))
+ fputs ("12", file);
+ else
+ fputc ('8', file);
return;
case '_':
/* Output the Embedded Medium/Anywhere code model base register. */
fputs (EMBMEDANY_BASE_REG, file);
return;
- case '@':
- /* Print out what we are using as the frame pointer. This might
- be %fp, or might be %sp+offset. */
- /* ??? What if offset is too big? Perhaps the caller knows it isn't? */
- fprintf (file, "%s+"HOST_WIDE_INT_PRINT_DEC, frame_base_name, frame_base_offset);
- return;
case '&':
/* Print some local dynamic TLS name. */
assemble_name (file, get_some_local_dynamic_name ());
return;
+
case 'Y':
/* Adjust the operand to take into account a RESTORE operation. */
if (GET_CODE (x) == CONST_INT)
@@ -7005,7 +6760,7 @@ print_operand (FILE *file, rtx x, int code)
else if (GET_MODE (x) == CCXmode)
fputs ("%xcc", file);
else
- abort ();
+ gcc_unreachable ();
}
else
/* %fccN register */
@@ -7308,7 +7063,7 @@ sparc_type_code (register tree type)
/* Carefully distinguish all the standard types of C,
without messing up if the language is not C. We do this by
- testing TYPE_PRECISION and TREE_UNSIGNED. The old code used to
+ testing TYPE_PRECISION and TYPE_UNSIGNED. The old code used to
look at both the names and the above fields, but that's redundant.
Any type whose size is between two C types will be considered
to be the wider of the two types. Also, we do not have a
@@ -7318,16 +7073,16 @@ sparc_type_code (register tree type)
size, but that's fine, since neither can the assembler. */
if (TYPE_PRECISION (type) <= CHAR_TYPE_SIZE)
- return (qualifiers | (TREE_UNSIGNED (type) ? 12 : 2));
+ return (qualifiers | (TYPE_UNSIGNED (type) ? 12 : 2));
else if (TYPE_PRECISION (type) <= SHORT_TYPE_SIZE)
- return (qualifiers | (TREE_UNSIGNED (type) ? 13 : 3));
+ return (qualifiers | (TYPE_UNSIGNED (type) ? 13 : 3));
else if (TYPE_PRECISION (type) <= INT_TYPE_SIZE)
- return (qualifiers | (TREE_UNSIGNED (type) ? 14 : 4));
+ return (qualifiers | (TYPE_UNSIGNED (type) ? 14 : 4));
else
- return (qualifiers | (TREE_UNSIGNED (type) ? 15 : 5));
+ return (qualifiers | (TYPE_UNSIGNED (type) ? 15 : 5));
case REAL_TYPE:
/* If this is a range type, consider it to be the underlying
@@ -7350,15 +7105,13 @@ sparc_type_code (register tree type)
existing front-ends. */
return (qualifiers | 7); /* Who knows? */
- case CHAR_TYPE: /* GNU Pascal CHAR type. Not used in C. */
- case BOOLEAN_TYPE: /* GNU Fortran BOOLEAN type. */
- case FILE_TYPE: /* GNU Pascal FILE type. */
- case SET_TYPE: /* GNU Pascal SET type. */
+ case VECTOR_TYPE:
+ case BOOLEAN_TYPE: /* Boolean truth value type. */
case LANG_TYPE: /* ? */
return qualifiers;
default:
- abort (); /* Not a type! */
+ gcc_unreachable (); /* Not a type! */
}
}
@@ -7426,14 +7179,15 @@ sparc_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
aligned on a 16 byte boundary so one flush clears it all. */
emit_insn (gen_flush (validize_mem (gen_rtx_MEM (SImode, tramp))));
if (sparc_cpu != PROCESSOR_ULTRASPARC
- && sparc_cpu != PROCESSOR_ULTRASPARC3)
+ && sparc_cpu != PROCESSOR_ULTRASPARC3
+ && sparc_cpu != PROCESSOR_NIAGARA)
emit_insn (gen_flush (validize_mem (gen_rtx_MEM (SImode,
plus_constant (tramp, 8)))));
/* Call __enable_execute_stack after writing onto the stack to make sure
the stack address is accessible. */
#ifdef ENABLE_EXECUTE_STACK
- emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__enable_execute_stack"),
+ emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__enable_execute_stack"),
LCT_NORMAL, VOIDmode, 1, tramp, Pmode);
#endif
@@ -7468,735 +7222,18 @@ sparc64_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
emit_insn (gen_flushdi (validize_mem (gen_rtx_MEM (DImode, tramp))));
if (sparc_cpu != PROCESSOR_ULTRASPARC
- && sparc_cpu != PROCESSOR_ULTRASPARC3)
+ && sparc_cpu != PROCESSOR_ULTRASPARC3
+ && sparc_cpu != PROCESSOR_NIAGARA)
emit_insn (gen_flushdi (validize_mem (gen_rtx_MEM (DImode, plus_constant (tramp, 8)))));
/* Call __enable_execute_stack after writing onto the stack to make sure
the stack address is accessible. */
#ifdef ENABLE_EXECUTE_STACK
- emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__enable_execute_stack"),
+ emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__enable_execute_stack"),
LCT_NORMAL, VOIDmode, 1, tramp, Pmode);
#endif
}
-/* Subroutines to support a flat (single) register window calling
- convention. */
-
-/* Single-register window sparc stack frames look like:
-
- Before call After call
- +-----------------------+ +-----------------------+
- high | | | |
- mem | caller's temps. | | caller's temps. |
- | | | |
- +-----------------------+ +-----------------------+
- | | | |
- | arguments on stack. | | arguments on stack. |
- | | | |
- +-----------------------+FP+92->+-----------------------+
- | 6 words to save | | 6 words to save |
- | arguments passed | | arguments passed |
- | in registers, even | | in registers, even |
- | if not passed. | | if not passed. |
- SP+68->+-----------------------+FP+68->+-----------------------+
- | 1 word struct addr | | 1 word struct addr |
- +-----------------------+FP+64->+-----------------------+
- | | | |
- | 16 word reg save area | | 16 word reg save area |
- | | | |
- SP->+-----------------------+ FP->+-----------------------+
- | 4 word area for |
- | fp/alu reg moves |
- FP-16->+-----------------------+
- | |
- | local variables |
- | |
- +-----------------------+
- | |
- | fp register save |
- | |
- +-----------------------+
- | |
- | gp register save |
- | |
- +-----------------------+
- | |
- | alloca allocations |
- | |
- +-----------------------+
- | |
- | arguments on stack |
- | |
- SP+92->+-----------------------+
- | 6 words to save |
- | arguments passed |
- | in registers, even |
- low | if not passed. |
- memory SP+68->+-----------------------+
- | 1 word struct addr |
- SP+64->+-----------------------+
- | |
- I 16 word reg save area |
- | |
- SP->+-----------------------+ */
-
-/* Structure to be filled in by sparc_flat_compute_frame_size with register
- save masks, and offsets for the current function. */
-
-struct sparc_frame_info
-{
- HOST_WIDE_INT total_size; /* # bytes that the entire frame takes up. */
- HOST_WIDE_INT var_size; /* # bytes that variables take up. */
- int args_size; /* # bytes that outgoing arguments take up. */
- int extra_size; /* # bytes of extra gunk. */
- int gp_reg_size; /* # bytes needed to store gp regs. */
- int fp_reg_size; /* # bytes needed to store fp regs. */
- unsigned long gmask; /* Mask of saved gp registers. */
- unsigned long fmask; /* Mask of saved fp registers. */
- int reg_offset; /* Offset from new sp to store regs. */
- int initialized; /* Nonzero if frame size already calculated. */
-};
-
-/* Current frame information calculated by sparc_flat_compute_frame_size. */
-struct sparc_frame_info current_frame_info;
-
-/* Zero structure to initialize current_frame_info. */
-struct sparc_frame_info zero_frame_info;
-
-#define RETURN_ADDR_REGNUM 15
-#define HARD_FRAME_POINTER_MASK (1 << (HARD_FRAME_POINTER_REGNUM))
-#define RETURN_ADDR_MASK (1 << (RETURN_ADDR_REGNUM))
-
-/* Tell prologue and epilogue if register REGNO should be saved / restored. */
-
-static bool
-sparc_flat_must_save_register_p (int regno)
-{
- /* General case: call-saved registers live at some point. */
- if (!call_used_regs[regno] && regs_ever_live[regno])
- return true;
-
- /* Frame pointer register (%i7) if needed. */
- if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed)
- return true;
-
- /* PIC register (%l7) if needed. */
- if (regno == (int) PIC_OFFSET_TABLE_REGNUM
- && flag_pic && current_function_uses_pic_offset_table)
- return true;
-
- /* Return address register (%o7) if needed. */
- if (regno == RETURN_ADDR_REGNUM
- && (regs_ever_live[RETURN_ADDR_REGNUM]
- /* When the PIC offset table is used, the PIC register
- is set by using a bare call that clobbers %o7. */
- || (flag_pic && current_function_uses_pic_offset_table)))
- return true;
-
- return false;
-}
-
-/* Return the bytes needed to compute the frame pointer from the current
- stack pointer. */
-
-HOST_WIDE_INT
-sparc_flat_compute_frame_size (HOST_WIDE_INT size)
- /* # of var. bytes allocated. */
-{
- int regno;
- HOST_WIDE_INT total_size; /* # bytes that the entire frame takes up. */
- HOST_WIDE_INT var_size; /* # bytes that variables take up. */
- int args_size; /* # bytes that outgoing arguments take up. */
- int extra_size; /* # extra bytes. */
- int gp_reg_size; /* # bytes needed to store gp regs. */
- int fp_reg_size; /* # bytes needed to store fp regs. */
- unsigned long gmask; /* Mask of saved gp registers. */
- unsigned long fmask; /* Mask of saved fp registers. */
- int reg_offset; /* Offset to register save area. */
- int need_aligned_p; /* 1 if need the save area 8 byte aligned. */
-
- /* This is the size of the 16 word reg save area, 1 word struct addr
- area, and 4 word fp/alu register copy area. */
- extra_size = -STARTING_FRAME_OFFSET + FIRST_PARM_OFFSET(0);
- var_size = size;
- gp_reg_size = 0;
- fp_reg_size = 0;
- gmask = 0;
- fmask = 0;
- reg_offset = 0;
- need_aligned_p = 0;
-
- args_size = 0;
- if (!leaf_function_p ())
- {
- /* Also include the size needed for the 6 parameter registers. */
- args_size = current_function_outgoing_args_size + 24;
- }
- total_size = var_size + args_size;
-
- /* Calculate space needed for gp registers. */
- for (regno = 1; regno <= 31; regno++)
- {
- if (sparc_flat_must_save_register_p (regno))
- {
- /* If we need to save two regs in a row, ensure there's room to bump
- up the address to align it to a doubleword boundary. */
- if ((regno & 0x1) == 0 && sparc_flat_must_save_register_p (regno+1))
- {
- if (gp_reg_size % 8 != 0)
- gp_reg_size += 4;
- gp_reg_size += 2 * UNITS_PER_WORD;
- gmask |= 3 << regno;
- regno++;
- need_aligned_p = 1;
- }
- else
- {
- gp_reg_size += UNITS_PER_WORD;
- gmask |= 1 << regno;
- }
- }
- }
-
- /* Calculate space needed for fp registers. */
- for (regno = 32; regno <= 63; regno++)
- {
- if (regs_ever_live[regno] && !call_used_regs[regno])
- {
- fp_reg_size += UNITS_PER_WORD;
- fmask |= 1 << (regno - 32);
- }
- }
-
- if (gmask || fmask)
- {
- int n;
- reg_offset = FIRST_PARM_OFFSET(0) + args_size;
- /* Ensure save area is 8 byte aligned if we need it. */
- n = reg_offset % 8;
- if (need_aligned_p && n != 0)
- {
- total_size += 8 - n;
- reg_offset += 8 - n;
- }
- total_size += gp_reg_size + fp_reg_size;
- }
-
- /* If we must allocate a stack frame at all, we must also allocate
- room for register window spillage, so as to be binary compatible
- with libraries and operating systems that do not use -mflat. */
- if (total_size > 0)
- total_size += extra_size;
- else
- extra_size = 0;
-
- total_size = SPARC_STACK_ALIGN (total_size);
-
- /* Save other computed information. */
- current_frame_info.total_size = total_size;
- current_frame_info.var_size = var_size;
- current_frame_info.args_size = args_size;
- current_frame_info.extra_size = extra_size;
- current_frame_info.gp_reg_size = gp_reg_size;
- current_frame_info.fp_reg_size = fp_reg_size;
- current_frame_info.gmask = gmask;
- current_frame_info.fmask = fmask;
- current_frame_info.reg_offset = reg_offset;
- current_frame_info.initialized = reload_completed;
-
- /* Ok, we're done. */
- return total_size;
-}
-
-/* Save/restore registers in GMASK and FMASK at register BASE_REG plus offset
- OFFSET.
-
- BASE_REG must be 8 byte aligned. This allows us to test OFFSET for
- appropriate alignment and use DOUBLEWORD_OP when we can. We assume
- [BASE_REG+OFFSET] will always be a valid address.
-
- WORD_OP is either "st" for save, "ld" for restore.
- DOUBLEWORD_OP is either "std" for save, "ldd" for restore. */
-
-static void
-sparc_flat_save_restore (FILE *file, const char *base_reg, int offset,
- unsigned long gmask, unsigned long fmask,
- const char *word_op, const char *doubleword_op,
- HOST_WIDE_INT base_offset)
-{
- int regno;
-
- if (gmask == 0 && fmask == 0)
- return;
-
- /* Save registers starting from high to low. We've already saved the
- previous frame pointer and previous return address for the debugger's
- sake. The debugger allows us to not need a nop in the epilog if at least
- one register is reloaded in addition to return address. */
-
- if (gmask)
- {
- for (regno = 1; regno <= 31; regno++)
- {
- if ((gmask & (1L << regno)) != 0)
- {
- if ((regno & 0x1) == 0 && ((gmask & (1L << (regno+1))) != 0))
- {
- /* We can save two registers in a row. If we're not at a
- double word boundary, move to one.
- sparc_flat_compute_frame_size ensures there's room to do
- this. */
- if (offset % 8 != 0)
- offset += UNITS_PER_WORD;
-
- if (word_op[0] == 's')
- {
- fprintf (file, "\t%s\t%s, [%s+%d]\n",
- doubleword_op, reg_names[regno],
- base_reg, offset);
- if (dwarf2out_do_frame ())
- {
- char *l = dwarf2out_cfi_label ();
- dwarf2out_reg_save (l, regno, offset + base_offset);
- dwarf2out_reg_save
- (l, regno+1, offset+base_offset + UNITS_PER_WORD);
- }
- }
- else
- fprintf (file, "\t%s\t[%s+%d], %s\n",
- doubleword_op, base_reg, offset,
- reg_names[regno]);
-
- offset += 2 * UNITS_PER_WORD;
- regno++;
- }
- else
- {
- if (word_op[0] == 's')
- {
- fprintf (file, "\t%s\t%s, [%s+%d]\n",
- word_op, reg_names[regno],
- base_reg, offset);
- if (dwarf2out_do_frame ())
- dwarf2out_reg_save ("", regno, offset + base_offset);
- }
- else
- fprintf (file, "\t%s\t[%s+%d], %s\n",
- word_op, base_reg, offset, reg_names[regno]);
-
- offset += UNITS_PER_WORD;
- }
- }
- }
- }
-
- if (fmask)
- {
- for (regno = 32; regno <= 63; regno++)
- {
- if ((fmask & (1L << (regno - 32))) != 0)
- {
- if (word_op[0] == 's')
- {
- fprintf (file, "\t%s\t%s, [%s+%d]\n",
- word_op, reg_names[regno],
- base_reg, offset);
- if (dwarf2out_do_frame ())
- dwarf2out_reg_save ("", regno, offset + base_offset);
- }
- else
- fprintf (file, "\t%s\t[%s+%d], %s\n",
- word_op, base_reg, offset, reg_names[regno]);
-
- offset += UNITS_PER_WORD;
- }
- }
- }
-}
-
-/* Set up the stack and frame (if desired) for the function. */
-
-static void
-sparc_flat_function_prologue (FILE *file, HOST_WIDE_INT size)
-{
- const char *sp_str = reg_names[STACK_POINTER_REGNUM];
- unsigned long gmask = current_frame_info.gmask;
-
- sparc_output_scratch_registers (file);
-
- /* This is only for the human reader. */
- fprintf (file, "\t%s#PROLOGUE# 0\n", ASM_COMMENT_START);
- fprintf (file, "\t%s# vars= "HOST_WIDE_INT_PRINT_DEC", "
- "regs= %d/%d, args= %d, extra= %d\n",
- ASM_COMMENT_START,
- current_frame_info.var_size,
- current_frame_info.gp_reg_size / 4,
- current_frame_info.fp_reg_size / 4,
- current_function_outgoing_args_size,
- current_frame_info.extra_size);
-
- size = SPARC_STACK_ALIGN (size);
- size = (! current_frame_info.initialized
- ? sparc_flat_compute_frame_size (size)
- : current_frame_info.total_size);
-
- /* These cases shouldn't happen. Catch them now. */
- if (size == 0 && (gmask || current_frame_info.fmask))
- abort ();
-
- /* Allocate our stack frame by decrementing %sp.
- At present, the only algorithm gdb can use to determine if this is a
- flat frame is if we always set %i7 if we set %sp. This can be optimized
- in the future by putting in some sort of debugging information that says
- this is a `flat' function. However, there is still the case of debugging
- code without such debugging information (including cases where most fns
- have such info, but there is one that doesn't). So, always do this now
- so we don't get a lot of code out there that gdb can't handle.
- If the frame pointer isn't needn't then that's ok - gdb won't be able to
- distinguish us from a non-flat function but there won't (and shouldn't)
- be any differences anyway. The return pc is saved (if necessary) right
- after %i7 so gdb won't have to look too far to find it. */
- if (size > 0)
- {
- int reg_offset = current_frame_info.reg_offset;
- const char *const fp_str = reg_names[HARD_FRAME_POINTER_REGNUM];
- static const char *const t1_str = "%g1";
-
- /* Things get a little tricky if local variables take up more than ~4096
- bytes and outgoing arguments take up more than ~4096 bytes. When that
- happens, the register save area can't be accessed from either end of
- the frame. Handle this by decrementing %sp to the start of the gp
- register save area, save the regs, update %i7, and then set %sp to its
- final value. Given that we only have one scratch register to play
- with it is the cheapest solution, and it helps gdb out as it won't
- slow down recognition of flat functions.
- Don't change the order of insns emitted here without checking with
- the gdb folk first. */
-
- /* Is the entire register save area offsettable from %sp? */
- if (reg_offset < 4096 - 64 * UNITS_PER_WORD)
- {
- if (size <= 4096)
- {
- fprintf (file, "\tadd\t%s, -"HOST_WIDE_INT_PRINT_DEC", %s\n",
- sp_str, size, sp_str);
- if (gmask & HARD_FRAME_POINTER_MASK)
- {
- fprintf (file, "\tst\t%s, [%s+%d]\n",
- fp_str, sp_str, reg_offset);
- fprintf (file, "\tsub\t%s, -"HOST_WIDE_INT_PRINT_DEC", %s"
- "\t%s# set up frame pointer\n",
- sp_str, size, fp_str, ASM_COMMENT_START);
- reg_offset += 4;
- }
- }
- else
- {
- build_big_number (file, size, t1_str);
- fprintf (file, "\tsub\t%s, %s, %s\n", sp_str, t1_str, sp_str);
- if (gmask & HARD_FRAME_POINTER_MASK)
- {
- fprintf (file, "\tst\t%s, [%s+%d]\n",
- fp_str, sp_str, reg_offset);
- fprintf (file, "\tadd\t%s, %s, %s\t%s# set up frame pointer\n",
- sp_str, t1_str, fp_str, ASM_COMMENT_START);
- reg_offset += 4;
- }
- }
- if (dwarf2out_do_frame ())
- {
- char *l = dwarf2out_cfi_label ();
- if (gmask & HARD_FRAME_POINTER_MASK)
- {
- dwarf2out_reg_save (l, HARD_FRAME_POINTER_REGNUM,
- reg_offset - 4 - size);
- dwarf2out_def_cfa (l, HARD_FRAME_POINTER_REGNUM, 0);
- }
- else
- dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, size);
- }
- if (gmask & RETURN_ADDR_MASK)
- {
- fprintf (file, "\tst\t%s, [%s+%d]\n",
- reg_names[RETURN_ADDR_REGNUM], sp_str, reg_offset);
- if (dwarf2out_do_frame ())
- dwarf2out_return_save ("", reg_offset - size);
- reg_offset += 4;
- }
- sparc_flat_save_restore (file, sp_str, reg_offset,
- gmask & ~(HARD_FRAME_POINTER_MASK | RETURN_ADDR_MASK),
- current_frame_info.fmask,
- "st", "std", -size);
- }
- else
- {
- /* Subtract %sp in two steps, but make sure there is always a
- 64-byte register save area, and %sp is properly aligned. */
-
- /* Amount to decrement %sp by, the first time. */
- HOST_WIDE_INT size1 = ((size - reg_offset + 64) + 15) & -16;
-
- /* Amount to decrement %sp by, the second time. */
- HOST_WIDE_INT size2 = size - size1;
-
- /* Offset to register save area from %sp after first decrement. */
- int offset = (int)(size1 - (size - reg_offset));
-
- if (size1 <= 4096)
- {
- fprintf (file, "\tadd\t%s, -"HOST_WIDE_INT_PRINT_DEC", %s\n",
- sp_str, size1, sp_str);
- if (gmask & HARD_FRAME_POINTER_MASK)
- {
- fprintf (file, "\tst\t%s, [%s+%d]\n"
- "\tsub\t%s, -"HOST_WIDE_INT_PRINT_DEC", %s"
- "\t%s# set up frame pointer\n",
- fp_str, sp_str, offset, sp_str, size1,
- fp_str, ASM_COMMENT_START);
- offset += 4;
- }
- }
- else
- {
- build_big_number (file, size1, t1_str);
- fprintf (file, "\tsub\t%s, %s, %s\n", sp_str, t1_str, sp_str);
- if (gmask & HARD_FRAME_POINTER_MASK)
- {
- fprintf (file, "\tst\t%s, [%s+%d]\n"
- "\tadd\t%s, %s, %s\t%s# set up frame pointer\n",
- fp_str, sp_str, offset, sp_str, t1_str,
- fp_str, ASM_COMMENT_START);
- offset += 4;
- }
- }
- if (dwarf2out_do_frame ())
- {
- char *l = dwarf2out_cfi_label ();
- if (gmask & HARD_FRAME_POINTER_MASK)
- {
- dwarf2out_reg_save (l, HARD_FRAME_POINTER_REGNUM,
- offset - 4 - size1);
- dwarf2out_def_cfa (l, HARD_FRAME_POINTER_REGNUM, 0);
- }
- else
- dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, size1);
- }
- if (gmask & RETURN_ADDR_MASK)
- {
- fprintf (file, "\tst\t%s, [%s+%d]\n",
- reg_names[RETURN_ADDR_REGNUM], sp_str, offset);
- if (dwarf2out_do_frame ())
- /* offset - size1 == reg_offset - size
- if reg_offset were updated above like offset. */
- dwarf2out_return_save ("", offset - size1);
- offset += 4;
- }
- sparc_flat_save_restore (file, sp_str, offset,
- gmask & ~(HARD_FRAME_POINTER_MASK | RETURN_ADDR_MASK),
- current_frame_info.fmask,
- "st", "std", -size1);
- if (size2 <= 4096)
- fprintf (file, "\tadd\t%s, -"HOST_WIDE_INT_PRINT_DEC", %s\n",
- sp_str, size2, sp_str);
- else
- {
- build_big_number (file, size2, t1_str);
- fprintf (file, "\tsub\t%s, %s, %s\n", sp_str, t1_str, sp_str);
- }
- if (dwarf2out_do_frame ())
- if (! (gmask & HARD_FRAME_POINTER_MASK))
- dwarf2out_def_cfa ("", STACK_POINTER_REGNUM, size);
- }
- }
-
- fprintf (file, "\t%s#PROLOGUE# 1\n", ASM_COMMENT_START);
-}
-
-/* Do any necessary cleanup after a function to restore stack, frame,
- and regs. */
-
-static void
-sparc_flat_function_epilogue (FILE *file, HOST_WIDE_INT size)
-{
- rtx epilogue_delay = current_function_epilogue_delay_list;
- int noepilogue = FALSE;
-
- /* This is only for the human reader. */
- fprintf (file, "\t%s#EPILOGUE#\n", ASM_COMMENT_START);
-
- /* The epilogue does not depend on any registers, but the stack
- registers, so we assume that if we have 1 pending nop, it can be
- ignored, and 2 it must be filled (2 nops occur for integer
- multiply and divide). */
-
- size = SPARC_STACK_ALIGN (size);
- size = (!current_frame_info.initialized
- ? sparc_flat_compute_frame_size (size)
- : current_frame_info.total_size);
-
- if (size == 0 && epilogue_delay == 0)
- {
- rtx insn = get_last_insn ();
-
- /* If the last insn was a BARRIER, we don't have to write any code
- because a jump (aka return) was put there. */
- if (GET_CODE (insn) == NOTE)
- insn = prev_nonnote_insn (insn);
- if (insn && GET_CODE (insn) == BARRIER)
- noepilogue = TRUE;
- }
-
- if (!noepilogue)
- {
- int reg_offset = current_frame_info.reg_offset;
- int reg_offset1;
- const char *const sp_str = reg_names[STACK_POINTER_REGNUM];
- const char *const fp_str = reg_names[HARD_FRAME_POINTER_REGNUM];
- static const char *const t1_str = "%g1";
-
- /* In the reload sequence, we don't need to fill the load delay
- slots for most of the loads, also see if we can fill the final
- delay slot if not otherwise filled by the reload sequence. */
-
- if (size > 4096)
- build_big_number (file, size, t1_str);
-
- if (frame_pointer_needed)
- {
- if (size > 4096)
- fprintf (file,"\tsub\t%s, %s, %s\t\t%s# sp not trusted here\n",
- fp_str, t1_str, sp_str, ASM_COMMENT_START);
- else
- fprintf (file,"\tadd\t%s, -"HOST_WIDE_INT_PRINT_DEC", %s"
- "\t\t%s# sp not trusted here\n",
- fp_str, size, sp_str, ASM_COMMENT_START);
- }
-
- /* Is the entire register save area offsettable from %sp? */
- if (reg_offset < 4096 - 64 * UNITS_PER_WORD)
- {
- reg_offset1 = 0;
- }
- else
- {
- /* Restore %sp in two steps, but make sure there is always a
- 64-byte register save area, and %sp is properly aligned. */
-
- /* Amount to increment %sp by, the first time. */
- reg_offset1 = ((reg_offset - 64 - 16) + 15) & -16;
-
- /* Offset to register save area from %sp. */
- reg_offset = reg_offset1 - reg_offset;
-
- if (reg_offset1 > 4096)
- {
- build_big_number (file, reg_offset1, t1_str);
- fprintf (file, "\tadd\t%s, %s, %s\n", sp_str, t1_str, sp_str);
- }
- else
- fprintf (file, "\tsub\t%s, -%d, %s\n", sp_str, reg_offset1, sp_str);
- }
-
- /* We must restore the frame pointer and return address reg first
- because they are treated specially by the prologue output code. */
- if (current_frame_info.gmask & HARD_FRAME_POINTER_MASK)
- {
- fprintf (file, "\tld\t[%s+%d], %s\n",
- sp_str, reg_offset, fp_str);
- reg_offset += 4;
- }
- if (current_frame_info.gmask & RETURN_ADDR_MASK)
- {
- fprintf (file, "\tld\t[%s+%d], %s\n",
- sp_str, reg_offset, reg_names[RETURN_ADDR_REGNUM]);
- reg_offset += 4;
- }
-
- /* Restore any remaining saved registers. */
- sparc_flat_save_restore (file, sp_str, reg_offset,
- current_frame_info.gmask & ~(HARD_FRAME_POINTER_MASK | RETURN_ADDR_MASK),
- current_frame_info.fmask,
- "ld", "ldd", 0);
-
- /* If we had to increment %sp in two steps, record it so the second
- restoration in the epilogue finishes up. */
- if (reg_offset1 > 0)
- {
- size -= reg_offset1;
- if (size > 4096)
- build_big_number (file, size, t1_str);
- }
-
- if (current_function_returns_struct)
- fprintf (file, "\tjmp\t%%o7+12\n");
- else
- fprintf (file, "\tretl\n");
-
- /* If the only register saved is the return address, we need a
- nop, unless we have an instruction to put into it. Otherwise
- we don't since reloading multiple registers doesn't reference
- the register being loaded. */
-
- if (epilogue_delay)
- {
- if (size)
- abort ();
- final_scan_insn (XEXP (epilogue_delay, 0), file, 1, -2, 1, NULL);
- }
-
- else if (size > 4096)
- fprintf (file, "\tadd\t%s, %s, %s\n", sp_str, t1_str, sp_str);
-
- else if (size > 0)
- fprintf (file, "\tsub\t%s, -"HOST_WIDE_INT_PRINT_DEC", %s\n",
- sp_str, size, sp_str);
-
- else
- fprintf (file, "\tnop\n");
- }
-
- /* Reset state info for each function. */
- current_frame_info = zero_frame_info;
-
- sparc_output_deferred_case_vectors ();
-}
-
-/* Define the number of delay slots needed for the function epilogue.
-
- On the sparc, we need a slot if either no stack has been allocated,
- or the only register saved is the return register. */
-
-int
-sparc_flat_epilogue_delay_slots (void)
-{
- if (!current_frame_info.initialized)
- (void) sparc_flat_compute_frame_size (get_frame_size ());
-
- if (current_frame_info.total_size == 0)
- return 1;
-
- return 0;
-}
-
-/* Return true if TRIAL is a valid insn for the epilogue delay slot.
- Any single length instruction which doesn't reference the stack or frame
- pointer is OK. */
-
-int
-sparc_flat_eligible_for_epilogue_delay (rtx trial, int slot ATTRIBUTE_UNUSED)
-{
- rtx pat = PATTERN (trial);
-
- if (get_attr_length (trial) != 1)
- return 0;
-
- if (! reg_mentioned_p (stack_pointer_rtx, pat)
- && ! reg_mentioned_p (frame_pointer_rtx, pat))
- return 1;
-
- return 0;
-}
-
/* Adjust the cost of a scheduling dependency. Return the new cost of
a dependency LINK or INSN on DEP_INSN. COST is the current cost. */
@@ -8364,20 +7401,10 @@ sparc_sched_init (FILE *dump ATTRIBUTE_UNUSED,
}
static int
-sparc_use_dfa_pipeline_interface (void)
-{
- if ((1 << sparc_cpu) &
- ((1 << PROCESSOR_ULTRASPARC) | (1 << PROCESSOR_CYPRESS) |
- (1 << PROCESSOR_SUPERSPARC) | (1 << PROCESSOR_HYPERSPARC) |
- (1 << PROCESSOR_SPARCLITE86X) | (1 << PROCESSOR_TSC701) |
- (1 << PROCESSOR_ULTRASPARC3)))
- return 1;
- return 0;
-}
-
-static int
sparc_use_sched_lookahead (void)
{
+ if (sparc_cpu == PROCESSOR_NIAGARA)
+ return 0;
if (sparc_cpu == PROCESSOR_ULTRASPARC
|| sparc_cpu == PROCESSOR_ULTRASPARC3)
return 4;
@@ -8393,6 +7420,7 @@ sparc_issue_rate (void)
{
switch (sparc_cpu)
{
+ case PROCESSOR_NIAGARA:
default:
return 1;
case PROCESSOR_V9:
@@ -8558,7 +7586,7 @@ sparc_output_deferred_case_vectors (void)
return;
/* Align to cache line in the function's code section. */
- function_section (current_function_decl);
+ switch_to_section (current_function_section ());
align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
if (align > 0)
@@ -8585,8 +7613,7 @@ sparc_check_64 (rtx x, rtx insn)
int set_once = 0;
rtx y = x;
- if (GET_CODE (x) != REG)
- abort ();
+ gcc_assert (GET_CODE (x) == REG);
if (GET_MODE (x) == DImode)
y = gen_rtx_REG (SImode, REGNO (x) + WORDS_BIG_ENDIAN);
@@ -8635,8 +7662,8 @@ sparc_check_64 (rtx x, rtx insn)
/* Returns assembly code to perform a DImode shift using
a 64-bit global or out register on SPARC-V8+. */
-char *
-sparc_v8plus_shift (rtx *operands, rtx insn, const char *opcode)
+const char *
+output_v8plus_shift (rtx *operands, rtx insn, const char *opcode)
{
static char asm_code[60];
@@ -8687,13 +7714,14 @@ sparc_profile_hook (int labelno)
#ifdef OBJECT_FORMAT_ELF
static void
-sparc_elf_asm_named_section (const char *name, unsigned int flags)
+sparc_elf_asm_named_section (const char *name, unsigned int flags,
+ tree decl)
{
if (flags & SECTION_MERGE)
{
/* entsize cannot be expressed in this section attributes
encoding style. */
- default_elf_asm_named_section (name, flags);
+ default_elf_asm_named_section (name, flags, decl);
return;
}
@@ -8714,10 +7742,12 @@ sparc_elf_asm_named_section (const char *name, unsigned int flags)
}
#endif /* OBJECT_FORMAT_ELF */
-/* We do not allow sibling calls if -mflat, nor
- we do not allow indirect calls to be optimized into sibling calls.
-
- Also, on sparc 32-bit we cannot emit a sibling call when the
+/* We do not allow indirect calls to be optimized into sibling calls.
+
+ We cannot use sibling calls when delayed branches are disabled
+ because they will likely require the call delay slot to be filled.
+
+ Also, on SPARC 32-bit we cannot emit a sibling call when the
current function returns a structure. This is because the "unimp
after call" convention would cause the callee to return to the
wrong place. The generic code already disallows cases where the
@@ -8726,7 +7756,7 @@ sparc_elf_asm_named_section (const char *name, unsigned int flags)
It may seem strange how this last case could occur. Usually there
is code after the call which jumps to epilogue code which dumps the
return value into the struct return area. That ought to invalidate
- the sibling call right? Well, in the c++ case we can end up passing
+ the sibling call right? Well, in the C++ case we can end up passing
the pointer to the struct return area to a constructor (which returns
void) and then nothing else happens. Such a sibling call would look
valid without the added check here. */
@@ -8734,7 +7764,7 @@ static bool
sparc_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
{
return (decl
- && ! TARGET_FLAT
+ && flag_delayed_branch
&& (TARGET_ARCH64 || ! current_function_returns_struct));
}
@@ -8749,7 +7779,7 @@ sparc_init_libfuncs (void)
/* Use the subroutines that Sun's library provides for integer
multiply and divide. The `*' prevents an underscore from
being prepended by the compiler. .umul is a little faster
- than .mul. */
+ than .mul. */
set_optab_libfunc (smul_optab, SImode, "*.umul");
set_optab_libfunc (sdiv_optab, SImode, "*.div");
set_optab_libfunc (udiv_optab, SImode, "*.udiv");
@@ -8786,12 +7816,14 @@ sparc_init_libfuncs (void)
set_conv_libfunc (sfix_optab, SImode, TFmode, "_Q_qtoi");
set_conv_libfunc (ufix_optab, SImode, TFmode, "_Q_qtou");
set_conv_libfunc (sfloat_optab, TFmode, SImode, "_Q_itoq");
+ set_conv_libfunc (ufloat_optab, TFmode, SImode, "_Q_utoq");
if (DITF_CONVERSION_LIBFUNCS)
{
set_conv_libfunc (sfix_optab, DImode, TFmode, "_Q_qtoll");
set_conv_libfunc (ufix_optab, DImode, TFmode, "_Q_qtoull");
set_conv_libfunc (sfloat_optab, TFmode, DImode, "_Q_lltoq");
+ set_conv_libfunc (ufloat_optab, TFmode, DImode, "_Q_ulltoq");
}
if (SUN_CONVERSION_LIBFUNCS)
@@ -8835,31 +7867,361 @@ sparc_init_libfuncs (void)
gofast_maybe_init_libfuncs ();
}
-/* ??? Similar to the standard section selection, but force reloc-y-ness
- if SUNOS4_SHARED_LIBRARIES. Unclear why this helps (as opposed to
- pretending PIC always on), but that's what the old code did. */
+#define def_builtin(NAME, CODE, TYPE) \
+ lang_hooks.builtin_function((NAME), (TYPE), (CODE), BUILT_IN_MD, NULL, \
+ NULL_TREE)
+
+/* Implement the TARGET_INIT_BUILTINS target hook.
+ Create builtin functions for special SPARC instructions. */
static void
-sparc_aout_select_section (tree t, int reloc, unsigned HOST_WIDE_INT align)
+sparc_init_builtins (void)
{
- default_select_section (t, reloc | SUNOS4_SHARED_LIBRARIES, align);
+ if (TARGET_VIS)
+ sparc_vis_init_builtins ();
}
-/* Use text section for a constant unless we need more alignment than
- that offers. */
+/* Create builtin functions for VIS 1.0 instructions. */
static void
-sparc_aout_select_rtx_section (enum machine_mode mode, rtx x,
- unsigned HOST_WIDE_INT align)
-{
- if (align <= MAX_TEXT_ALIGN
- && ! (flag_pic && (symbolic_operand (x, mode)
- || SUNOS4_SHARED_LIBRARIES)))
- readonly_data_section ();
+sparc_vis_init_builtins (void)
+{
+ tree v4qi = build_vector_type (unsigned_intQI_type_node, 4);
+ tree v8qi = build_vector_type (unsigned_intQI_type_node, 8);
+ tree v4hi = build_vector_type (intHI_type_node, 4);
+ tree v2hi = build_vector_type (intHI_type_node, 2);
+ tree v2si = build_vector_type (intSI_type_node, 2);
+
+ tree v4qi_ftype_v4hi = build_function_type_list (v4qi, v4hi, 0);
+ tree v8qi_ftype_v2si_v8qi = build_function_type_list (v8qi, v2si, v8qi, 0);
+ tree v2hi_ftype_v2si = build_function_type_list (v2hi, v2si, 0);
+ tree v4hi_ftype_v4qi = build_function_type_list (v4hi, v4qi, 0);
+ tree v8qi_ftype_v4qi_v4qi = build_function_type_list (v8qi, v4qi, v4qi, 0);
+ tree v4hi_ftype_v4qi_v4hi = build_function_type_list (v4hi, v4qi, v4hi, 0);
+ tree v4hi_ftype_v4qi_v2hi = build_function_type_list (v4hi, v4qi, v2hi, 0);
+ tree v2si_ftype_v4qi_v2hi = build_function_type_list (v2si, v4qi, v2hi, 0);
+ tree v4hi_ftype_v8qi_v4hi = build_function_type_list (v4hi, v8qi, v4hi, 0);
+ tree v4hi_ftype_v4hi_v4hi = build_function_type_list (v4hi, v4hi, v4hi, 0);
+ tree v2si_ftype_v2si_v2si = build_function_type_list (v2si, v2si, v2si, 0);
+ tree v8qi_ftype_v8qi_v8qi = build_function_type_list (v8qi, v8qi, v8qi, 0);
+ tree di_ftype_v8qi_v8qi_di = build_function_type_list (intDI_type_node,
+ v8qi, v8qi,
+ intDI_type_node, 0);
+ tree di_ftype_di_di = build_function_type_list (intDI_type_node,
+ intDI_type_node,
+ intDI_type_node, 0);
+ tree ptr_ftype_ptr_si = build_function_type_list (ptr_type_node,
+ ptr_type_node,
+ intSI_type_node, 0);
+ tree ptr_ftype_ptr_di = build_function_type_list (ptr_type_node,
+ ptr_type_node,
+ intDI_type_node, 0);
+
+ /* Packing and expanding vectors. */
+ def_builtin ("__builtin_vis_fpack16", CODE_FOR_fpack16_vis, v4qi_ftype_v4hi);
+ def_builtin ("__builtin_vis_fpack32", CODE_FOR_fpack32_vis,
+ v8qi_ftype_v2si_v8qi);
+ def_builtin ("__builtin_vis_fpackfix", CODE_FOR_fpackfix_vis,
+ v2hi_ftype_v2si);
+ def_builtin ("__builtin_vis_fexpand", CODE_FOR_fexpand_vis, v4hi_ftype_v4qi);
+ def_builtin ("__builtin_vis_fpmerge", CODE_FOR_fpmerge_vis,
+ v8qi_ftype_v4qi_v4qi);
+
+ /* Multiplications. */
+ def_builtin ("__builtin_vis_fmul8x16", CODE_FOR_fmul8x16_vis,
+ v4hi_ftype_v4qi_v4hi);
+ def_builtin ("__builtin_vis_fmul8x16au", CODE_FOR_fmul8x16au_vis,
+ v4hi_ftype_v4qi_v2hi);
+ def_builtin ("__builtin_vis_fmul8x16al", CODE_FOR_fmul8x16al_vis,
+ v4hi_ftype_v4qi_v2hi);
+ def_builtin ("__builtin_vis_fmul8sux16", CODE_FOR_fmul8sux16_vis,
+ v4hi_ftype_v8qi_v4hi);
+ def_builtin ("__builtin_vis_fmul8ulx16", CODE_FOR_fmul8ulx16_vis,
+ v4hi_ftype_v8qi_v4hi);
+ def_builtin ("__builtin_vis_fmuld8sux16", CODE_FOR_fmuld8sux16_vis,
+ v2si_ftype_v4qi_v2hi);
+ def_builtin ("__builtin_vis_fmuld8ulx16", CODE_FOR_fmuld8ulx16_vis,
+ v2si_ftype_v4qi_v2hi);
+
+ /* Data aligning. */
+ def_builtin ("__builtin_vis_faligndatav4hi", CODE_FOR_faligndatav4hi_vis,
+ v4hi_ftype_v4hi_v4hi);
+ def_builtin ("__builtin_vis_faligndatav8qi", CODE_FOR_faligndatav8qi_vis,
+ v8qi_ftype_v8qi_v8qi);
+ def_builtin ("__builtin_vis_faligndatav2si", CODE_FOR_faligndatav2si_vis,
+ v2si_ftype_v2si_v2si);
+ def_builtin ("__builtin_vis_faligndatadi", CODE_FOR_faligndatadi_vis,
+ di_ftype_di_di);
+ if (TARGET_ARCH64)
+ def_builtin ("__builtin_vis_alignaddr", CODE_FOR_alignaddrdi_vis,
+ ptr_ftype_ptr_di);
else
- data_section ();
+ def_builtin ("__builtin_vis_alignaddr", CODE_FOR_alignaddrsi_vis,
+ ptr_ftype_ptr_si);
+
+ /* Pixel distance. */
+ def_builtin ("__builtin_vis_pdist", CODE_FOR_pdist_vis,
+ di_ftype_v8qi_v8qi_di);
+}
+
+/* Handle TARGET_EXPAND_BUILTIN target hook.
+ Expand builtin functions for sparc intrinsics. */
+
+static rtx
+sparc_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
+ enum machine_mode tmode, int ignore ATTRIBUTE_UNUSED)
+{
+ tree arglist;
+ tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+ unsigned int icode = DECL_FUNCTION_CODE (fndecl);
+ rtx pat, op[4];
+ enum machine_mode mode[4];
+ int arg_count = 0;
+
+ mode[arg_count] = tmode;
+
+ if (target == 0
+ || GET_MODE (target) != tmode
+ || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
+ op[arg_count] = gen_reg_rtx (tmode);
+ else
+ op[arg_count] = target;
+
+ for (arglist = TREE_OPERAND (exp, 1); arglist;
+ arglist = TREE_CHAIN (arglist))
+ {
+ tree arg = TREE_VALUE (arglist);
+
+ arg_count++;
+ mode[arg_count] = insn_data[icode].operand[arg_count].mode;
+ op[arg_count] = expand_normal (arg);
+
+ if (! (*insn_data[icode].operand[arg_count].predicate) (op[arg_count],
+ mode[arg_count]))
+ op[arg_count] = copy_to_mode_reg (mode[arg_count], op[arg_count]);
+ }
+
+ switch (arg_count)
+ {
+ case 1:
+ pat = GEN_FCN (icode) (op[0], op[1]);
+ break;
+ case 2:
+ pat = GEN_FCN (icode) (op[0], op[1], op[2]);
+ break;
+ case 3:
+ pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ if (!pat)
+ return NULL_RTX;
+
+ emit_insn (pat);
+
+ return op[0];
}
+static int
+sparc_vis_mul8x16 (int e8, int e16)
+{
+ return (e8 * e16 + 128) / 256;
+}
+
+/* Multiply the vector elements in ELTS0 to the elements in ELTS1 as specified
+ by FNCODE. All of the elements in ELTS0 and ELTS1 lists must be integer
+ constants. A tree list with the results of the multiplications is returned,
+ and each element in the list is of INNER_TYPE. */
+
+static tree
+sparc_handle_vis_mul8x16 (int fncode, tree inner_type, tree elts0, tree elts1)
+{
+ tree n_elts = NULL_TREE;
+ int scale;
+
+ switch (fncode)
+ {
+ case CODE_FOR_fmul8x16_vis:
+ for (; elts0 && elts1;
+ elts0 = TREE_CHAIN (elts0), elts1 = TREE_CHAIN (elts1))
+ {
+ int val
+ = sparc_vis_mul8x16 (TREE_INT_CST_LOW (TREE_VALUE (elts0)),
+ TREE_INT_CST_LOW (TREE_VALUE (elts1)));
+ n_elts = tree_cons (NULL_TREE,
+ build_int_cst (inner_type, val),
+ n_elts);
+ }
+ break;
+
+ case CODE_FOR_fmul8x16au_vis:
+ scale = TREE_INT_CST_LOW (TREE_VALUE (elts1));
+
+ for (; elts0; elts0 = TREE_CHAIN (elts0))
+ {
+ int val
+ = sparc_vis_mul8x16 (TREE_INT_CST_LOW (TREE_VALUE (elts0)),
+ scale);
+ n_elts = tree_cons (NULL_TREE,
+ build_int_cst (inner_type, val),
+ n_elts);
+ }
+ break;
+
+ case CODE_FOR_fmul8x16al_vis:
+ scale = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (elts1)));
+
+ for (; elts0; elts0 = TREE_CHAIN (elts0))
+ {
+ int val
+ = sparc_vis_mul8x16 (TREE_INT_CST_LOW (TREE_VALUE (elts0)),
+ scale);
+ n_elts = tree_cons (NULL_TREE,
+ build_int_cst (inner_type, val),
+ n_elts);
+ }
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return nreverse (n_elts);
+
+}
+/* Handle TARGET_FOLD_BUILTIN target hook.
+ Fold builtin functions for SPARC intrinsics. If IGNORE is true the
+ result of the function call is ignored. NULL_TREE is returned if the
+ function could not be folded. */
+
+static tree
+sparc_fold_builtin (tree fndecl, tree arglist, bool ignore)
+{
+ tree arg0, arg1, arg2;
+ tree rtype = TREE_TYPE (TREE_TYPE (fndecl));
+
+
+ if (ignore && DECL_FUNCTION_CODE (fndecl) != CODE_FOR_alignaddrsi_vis
+ && DECL_FUNCTION_CODE (fndecl) != CODE_FOR_alignaddrdi_vis)
+ return build_int_cst (rtype, 0);
+
+ switch (DECL_FUNCTION_CODE (fndecl))
+ {
+ case CODE_FOR_fexpand_vis:
+ arg0 = TREE_VALUE (arglist);
+ STRIP_NOPS (arg0);
+
+ if (TREE_CODE (arg0) == VECTOR_CST)
+ {
+ tree inner_type = TREE_TYPE (rtype);
+ tree elts = TREE_VECTOR_CST_ELTS (arg0);
+ tree n_elts = NULL_TREE;
+
+ for (; elts; elts = TREE_CHAIN (elts))
+ {
+ unsigned int val = TREE_INT_CST_LOW (TREE_VALUE (elts)) << 4;
+ n_elts = tree_cons (NULL_TREE,
+ build_int_cst (inner_type, val),
+ n_elts);
+ }
+ return build_vector (rtype, nreverse (n_elts));
+ }
+ break;
+
+ case CODE_FOR_fmul8x16_vis:
+ case CODE_FOR_fmul8x16au_vis:
+ case CODE_FOR_fmul8x16al_vis:
+ arg0 = TREE_VALUE (arglist);
+ arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+ STRIP_NOPS (arg0);
+ STRIP_NOPS (arg1);
+
+ if (TREE_CODE (arg0) == VECTOR_CST && TREE_CODE (arg1) == VECTOR_CST)
+ {
+ tree inner_type = TREE_TYPE (rtype);
+ tree elts0 = TREE_VECTOR_CST_ELTS (arg0);
+ tree elts1 = TREE_VECTOR_CST_ELTS (arg1);
+ tree n_elts = sparc_handle_vis_mul8x16 (DECL_FUNCTION_CODE (fndecl),
+ inner_type, elts0, elts1);
+
+ return build_vector (rtype, n_elts);
+ }
+ break;
+
+ case CODE_FOR_fpmerge_vis:
+ arg0 = TREE_VALUE (arglist);
+ arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+ STRIP_NOPS (arg0);
+ STRIP_NOPS (arg1);
+
+ if (TREE_CODE (arg0) == VECTOR_CST && TREE_CODE (arg1) == VECTOR_CST)
+ {
+ tree elts0 = TREE_VECTOR_CST_ELTS (arg0);
+ tree elts1 = TREE_VECTOR_CST_ELTS (arg1);
+ tree n_elts = NULL_TREE;
+
+ for (; elts0 && elts1;
+ elts0 = TREE_CHAIN (elts0), elts1 = TREE_CHAIN (elts1))
+ {
+ n_elts = tree_cons (NULL_TREE, TREE_VALUE (elts0), n_elts);
+ n_elts = tree_cons (NULL_TREE, TREE_VALUE (elts1), n_elts);
+ }
+
+ return build_vector (rtype, nreverse (n_elts));
+ }
+ break;
+
+ case CODE_FOR_pdist_vis:
+ arg0 = TREE_VALUE (arglist);
+ arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+ arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+ STRIP_NOPS (arg0);
+ STRIP_NOPS (arg1);
+ STRIP_NOPS (arg2);
+
+ if (TREE_CODE (arg0) == VECTOR_CST
+ && TREE_CODE (arg1) == VECTOR_CST
+ && TREE_CODE (arg2) == INTEGER_CST)
+ {
+ int overflow = 0;
+ unsigned HOST_WIDE_INT low = TREE_INT_CST_LOW (arg2);
+ HOST_WIDE_INT high = TREE_INT_CST_HIGH (arg2);
+ tree elts0 = TREE_VECTOR_CST_ELTS (arg0);
+ tree elts1 = TREE_VECTOR_CST_ELTS (arg1);
+
+ for (; elts0 && elts1;
+ elts0 = TREE_CHAIN (elts0), elts1 = TREE_CHAIN (elts1))
+ {
+ unsigned HOST_WIDE_INT
+ low0 = TREE_INT_CST_LOW (TREE_VALUE (elts0)),
+ low1 = TREE_INT_CST_LOW (TREE_VALUE (elts1));
+ HOST_WIDE_INT high0 = TREE_INT_CST_HIGH (TREE_VALUE (elts0));
+ HOST_WIDE_INT high1 = TREE_INT_CST_HIGH (TREE_VALUE (elts1));
+
+ unsigned HOST_WIDE_INT l;
+ HOST_WIDE_INT h;
+
+ overflow |= neg_double (low1, high1, &l, &h);
+ overflow |= add_double (low0, high0, l, h, &l, &h);
+ if (h < 0)
+ overflow |= neg_double (l, h, &l, &h);
+
+ overflow |= add_double (low, high, l, h, &low, &high);
+ }
+
+ gcc_assert (overflow == 0);
+
+ return build_int_cst_wide (rtype, low, high);
+ }
+
+ default:
+ break;
+ }
+ return NULL_TREE;
+}
+
int
sparc_extra_constraint_check (rtx op, int c, int strict)
{
@@ -8893,6 +8255,9 @@ sparc_extra_constraint_check (rtx op, int c, int strict)
case 'T':
break;
+ case 'Y':
+ return const_zero_operand (op, GET_MODE (op));
+
default:
return 0;
}
@@ -8926,368 +8291,234 @@ sparc_extra_constraint_check (rtx op, int c, int strict)
static bool
sparc_rtx_costs (rtx x, int code, int outer_code, int *total)
{
+ enum machine_mode mode = GET_MODE (x);
+ bool float_mode_p = FLOAT_MODE_P (mode);
+
switch (code)
{
- case PLUS: case MINUS: case ABS: case NEG:
- case FLOAT: case UNSIGNED_FLOAT:
- case FIX: case UNSIGNED_FIX:
- case FLOAT_EXTEND: case FLOAT_TRUNCATE:
- if (FLOAT_MODE_P (GET_MODE (x)))
+ case CONST_INT:
+ if (INTVAL (x) < 0x1000 && INTVAL (x) >= -0x1000)
{
- switch (sparc_cpu)
- {
- case PROCESSOR_ULTRASPARC:
- case PROCESSOR_ULTRASPARC3:
- *total = COSTS_N_INSNS (4);
- return true;
-
- case PROCESSOR_SUPERSPARC:
- *total = COSTS_N_INSNS (3);
- return true;
-
- case PROCESSOR_CYPRESS:
- *total = COSTS_N_INSNS (5);
- return true;
-
- case PROCESSOR_HYPERSPARC:
- case PROCESSOR_SPARCLITE86X:
- default:
- *total = COSTS_N_INSNS (1);
- return true;
- }
+ *total = 0;
+ return true;
}
+ /* FALLTHRU */
- *total = COSTS_N_INSNS (1);
+ case HIGH:
+ *total = 2;
return true;
- case SQRT:
- switch (sparc_cpu)
- {
- case PROCESSOR_ULTRASPARC:
- if (GET_MODE (x) == SFmode)
- *total = COSTS_N_INSNS (13);
- else
- *total = COSTS_N_INSNS (23);
- return true;
-
- case PROCESSOR_ULTRASPARC3:
- if (GET_MODE (x) == SFmode)
- *total = COSTS_N_INSNS (20);
- else
- *total = COSTS_N_INSNS (29);
- return true;
-
- case PROCESSOR_SUPERSPARC:
- *total = COSTS_N_INSNS (12);
- return true;
-
- case PROCESSOR_CYPRESS:
- *total = COSTS_N_INSNS (63);
- return true;
+ case CONST:
+ case LABEL_REF:
+ case SYMBOL_REF:
+ *total = 4;
+ return true;
- case PROCESSOR_HYPERSPARC:
- case PROCESSOR_SPARCLITE86X:
- *total = COSTS_N_INSNS (17);
- return true;
+ case CONST_DOUBLE:
+ if (GET_MODE (x) == VOIDmode
+ && ((CONST_DOUBLE_HIGH (x) == 0
+ && CONST_DOUBLE_LOW (x) < 0x1000)
+ || (CONST_DOUBLE_HIGH (x) == -1
+ && CONST_DOUBLE_LOW (x) < 0
+ && CONST_DOUBLE_LOW (x) >= -0x1000)))
+ *total = 0;
+ else
+ *total = 8;
+ return true;
- default:
- *total = COSTS_N_INSNS (30);
- return true;
+ case MEM:
+ /* If outer-code was a sign or zero extension, a cost
+ of COSTS_N_INSNS (1) was already added in. This is
+ why we are subtracting it back out. */
+ if (outer_code == ZERO_EXTEND)
+ {
+ *total = sparc_costs->int_zload - COSTS_N_INSNS (1);
}
-
- case COMPARE:
- if (FLOAT_MODE_P (GET_MODE (x)))
+ else if (outer_code == SIGN_EXTEND)
{
- switch (sparc_cpu)
- {
- case PROCESSOR_ULTRASPARC:
- case PROCESSOR_ULTRASPARC3:
- *total = COSTS_N_INSNS (1);
- return true;
-
- case PROCESSOR_SUPERSPARC:
- *total = COSTS_N_INSNS (3);
- return true;
-
- case PROCESSOR_CYPRESS:
- *total = COSTS_N_INSNS (5);
- return true;
-
- case PROCESSOR_HYPERSPARC:
- case PROCESSOR_SPARCLITE86X:
- default:
- *total = COSTS_N_INSNS (1);
- return true;
- }
+ *total = sparc_costs->int_sload - COSTS_N_INSNS (1);
+ }
+ else if (float_mode_p)
+ {
+ *total = sparc_costs->float_load;
+ }
+ else
+ {
+ *total = sparc_costs->int_load;
}
- /* ??? Maybe mark integer compares as zero cost on
- ??? all UltraSPARC processors because the result
- ??? can be bypassed to a branch in the same group. */
-
- *total = COSTS_N_INSNS (1);
return true;
+ case PLUS:
+ case MINUS:
+ if (float_mode_p)
+ *total = sparc_costs->float_plusminus;
+ else
+ *total = COSTS_N_INSNS (1);
+ return false;
+
case MULT:
- if (FLOAT_MODE_P (GET_MODE (x)))
+ if (float_mode_p)
+ *total = sparc_costs->float_mul;
+ else if (! TARGET_HARD_MUL)
+ *total = COSTS_N_INSNS (25);
+ else
{
- switch (sparc_cpu)
- {
- case PROCESSOR_ULTRASPARC:
- case PROCESSOR_ULTRASPARC3:
- *total = COSTS_N_INSNS (4);
- return true;
+ int bit_cost;
- case PROCESSOR_SUPERSPARC:
- *total = COSTS_N_INSNS (3);
- return true;
-
- case PROCESSOR_CYPRESS:
- *total = COSTS_N_INSNS (7);
- return true;
+ bit_cost = 0;
+ if (sparc_costs->int_mul_bit_factor)
+ {
+ int nbits;
- case PROCESSOR_HYPERSPARC:
- case PROCESSOR_SPARCLITE86X:
- *total = COSTS_N_INSNS (1);
- return true;
+ if (GET_CODE (XEXP (x, 1)) == CONST_INT)
+ {
+ unsigned HOST_WIDE_INT value = INTVAL (XEXP (x, 1));
+ for (nbits = 0; value != 0; value &= value - 1)
+ nbits++;
+ }
+ else if (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE
+ && GET_MODE (XEXP (x, 1)) == VOIDmode)
+ {
+ rtx x1 = XEXP (x, 1);
+ unsigned HOST_WIDE_INT value1 = CONST_DOUBLE_LOW (x1);
+ unsigned HOST_WIDE_INT value2 = CONST_DOUBLE_HIGH (x1);
+
+ for (nbits = 0; value1 != 0; value1 &= value1 - 1)
+ nbits++;
+ for (; value2 != 0; value2 &= value2 - 1)
+ nbits++;
+ }
+ else
+ nbits = 7;
- default:
- *total = COSTS_N_INSNS (5);
- return true;
+ if (nbits < 3)
+ nbits = 3;
+ bit_cost = (nbits - 3) / sparc_costs->int_mul_bit_factor;
+ bit_cost = COSTS_N_INSNS (bit_cost);
}
- }
-
- /* The latency is actually variable for Ultra-I/II
- And if one of the inputs have a known constant
- value, we could calculate this precisely.
-
- However, for that to be useful we would need to
- add some machine description changes which would
- make sure small constants ended up in rs1 of the
- multiply instruction. This is because the multiply
- latency is determined by the number of clear (or
- set if the value is negative) bits starting from
- the most significant bit of the first input.
-
- The algorithm for computing num_cycles of a multiply
- on Ultra-I/II is:
-
- if (rs1 < 0)
- highest_bit = highest_clear_bit(rs1);
- else
- highest_bit = highest_set_bit(rs1);
- if (num_bits < 3)
- highest_bit = 3;
- num_cycles = 4 + ((highest_bit - 3) / 2);
-
- If we did that we would have to also consider register
- allocation issues that would result from forcing such
- a value into a register.
-
- There are other similar tricks we could play if we
- knew, for example, that one input was an array index.
- Since we do not play any such tricks currently the
- safest thing to do is report the worst case latency. */
- if (sparc_cpu == PROCESSOR_ULTRASPARC)
- {
- *total = (GET_MODE (x) == DImode
- ? COSTS_N_INSNS (34) : COSTS_N_INSNS (19));
- return true;
- }
-
- /* Multiply latency on Ultra-III, fortunately, is constant. */
- if (sparc_cpu == PROCESSOR_ULTRASPARC3)
- {
- *total = COSTS_N_INSNS (6);
- return true;
- }
-
- if (sparc_cpu == PROCESSOR_HYPERSPARC
- || sparc_cpu == PROCESSOR_SPARCLITE86X)
- {
- *total = COSTS_N_INSNS (17);
- return true;
+ if (mode == DImode)
+ *total = sparc_costs->int_mulX + bit_cost;
+ else
+ *total = sparc_costs->int_mul + bit_cost;
}
+ return false;
- *total = (TARGET_HARD_MUL ? COSTS_N_INSNS (5) : COSTS_N_INSNS (25));
- return true;
+ case ASHIFT:
+ case ASHIFTRT:
+ case LSHIFTRT:
+ *total = COSTS_N_INSNS (1) + sparc_costs->shift_penalty;
+ return false;
case DIV:
case UDIV:
case MOD:
case UMOD:
- if (FLOAT_MODE_P (GET_MODE (x)))
+ if (float_mode_p)
{
- switch (sparc_cpu)
- {
- case PROCESSOR_ULTRASPARC:
- if (GET_MODE (x) == SFmode)
- *total = COSTS_N_INSNS (13);
- else
- *total = COSTS_N_INSNS (23);
- return true;
-
- case PROCESSOR_ULTRASPARC3:
- if (GET_MODE (x) == SFmode)
- *total = COSTS_N_INSNS (17);
- else
- *total = COSTS_N_INSNS (20);
- return true;
-
- case PROCESSOR_SUPERSPARC:
- if (GET_MODE (x) == SFmode)
- *total = COSTS_N_INSNS (6);
- else
- *total = COSTS_N_INSNS (9);
- return true;
-
- case PROCESSOR_HYPERSPARC:
- case PROCESSOR_SPARCLITE86X:
- if (GET_MODE (x) == SFmode)
- *total = COSTS_N_INSNS (8);
- else
- *total = COSTS_N_INSNS (12);
- return true;
-
- default:
- *total = COSTS_N_INSNS (7);
- return true;
- }
+ if (mode == DFmode)
+ *total = sparc_costs->float_div_df;
+ else
+ *total = sparc_costs->float_div_sf;
}
-
- if (sparc_cpu == PROCESSOR_ULTRASPARC)
- *total = (GET_MODE (x) == DImode
- ? COSTS_N_INSNS (68) : COSTS_N_INSNS (37));
- else if (sparc_cpu == PROCESSOR_ULTRASPARC3)
- *total = (GET_MODE (x) == DImode
- ? COSTS_N_INSNS (71) : COSTS_N_INSNS (40));
else
- *total = COSTS_N_INSNS (25);
- return true;
-
- case IF_THEN_ELSE:
- /* Conditional moves. */
- switch (sparc_cpu)
{
- case PROCESSOR_ULTRASPARC:
- *total = COSTS_N_INSNS (2);
- return true;
-
- case PROCESSOR_ULTRASPARC3:
- if (FLOAT_MODE_P (GET_MODE (x)))
- *total = COSTS_N_INSNS (3);
+ if (mode == DImode)
+ *total = sparc_costs->int_divX;
else
- *total = COSTS_N_INSNS (2);
- return true;
+ *total = sparc_costs->int_div;
+ }
+ return false;
- default:
+ case NEG:
+ if (! float_mode_p)
+ {
*total = COSTS_N_INSNS (1);
- return true;
+ return false;
}
+ /* FALLTHRU */
- case MEM:
- /* If outer-code is SIGN/ZERO extension we have to subtract
- out COSTS_N_INSNS (1) from whatever we return in determining
- the cost. */
- switch (sparc_cpu)
- {
- case PROCESSOR_ULTRASPARC:
- if (outer_code == ZERO_EXTEND)
- *total = COSTS_N_INSNS (1);
- else
- *total = COSTS_N_INSNS (2);
- return true;
+ case ABS:
+ case FLOAT:
+ case UNSIGNED_FLOAT:
+ case FIX:
+ case UNSIGNED_FIX:
+ case FLOAT_EXTEND:
+ case FLOAT_TRUNCATE:
+ *total = sparc_costs->float_move;
+ return false;
- case PROCESSOR_ULTRASPARC3:
- if (outer_code == ZERO_EXTEND)
- {
- if (GET_MODE (x) == QImode
- || GET_MODE (x) == HImode
- || outer_code == SIGN_EXTEND)
- *total = COSTS_N_INSNS (2);
- else
- *total = COSTS_N_INSNS (1);
- }
- else
- {
- /* This handles sign extension (3 cycles)
- and everything else (2 cycles). */
- *total = COSTS_N_INSNS (2);
- }
- return true;
+ case SQRT:
+ if (mode == DFmode)
+ *total = sparc_costs->float_sqrt_df;
+ else
+ *total = sparc_costs->float_sqrt_sf;
+ return false;
- case PROCESSOR_SUPERSPARC:
- if (FLOAT_MODE_P (GET_MODE (x))
- || outer_code == ZERO_EXTEND
- || outer_code == SIGN_EXTEND)
- *total = COSTS_N_INSNS (0);
- else
- *total = COSTS_N_INSNS (1);
- return true;
+ case COMPARE:
+ if (float_mode_p)
+ *total = sparc_costs->float_cmp;
+ else
+ *total = COSTS_N_INSNS (1);
+ return false;
- case PROCESSOR_TSC701:
- if (outer_code == ZERO_EXTEND
- || outer_code == SIGN_EXTEND)
- *total = COSTS_N_INSNS (2);
- else
- *total = COSTS_N_INSNS (3);
- return true;
-
- case PROCESSOR_CYPRESS:
- if (outer_code == ZERO_EXTEND
- || outer_code == SIGN_EXTEND)
- *total = COSTS_N_INSNS (1);
- else
- *total = COSTS_N_INSNS (2);
- return true;
-
- case PROCESSOR_HYPERSPARC:
- case PROCESSOR_SPARCLITE86X:
- default:
- if (outer_code == ZERO_EXTEND
- || outer_code == SIGN_EXTEND)
- *total = COSTS_N_INSNS (0);
- else
- *total = COSTS_N_INSNS (1);
- return true;
- }
+ case IF_THEN_ELSE:
+ if (float_mode_p)
+ *total = sparc_costs->float_cmove;
+ else
+ *total = sparc_costs->int_cmove;
+ return false;
- case CONST_INT:
- if (INTVAL (x) < 0x1000 && INTVAL (x) >= -0x1000)
+ case IOR:
+ /* Handle the NAND vector patterns. */
+ if (sparc_vector_mode_supported_p (GET_MODE (x))
+ && GET_CODE (XEXP (x, 0)) == NOT
+ && GET_CODE (XEXP (x, 1)) == NOT)
{
- *total = 0;
+ *total = COSTS_N_INSNS (1);
return true;
}
- /* FALLTHRU */
-
- case HIGH:
- *total = 2;
- return true;
-
- case CONST:
- case LABEL_REF:
- case SYMBOL_REF:
- *total = 4;
- return true;
-
- case CONST_DOUBLE:
- if (GET_MODE (x) == DImode
- && ((XINT (x, 3) == 0
- && (unsigned HOST_WIDE_INT) XINT (x, 2) < 0x1000)
- || (XINT (x, 3) == -1
- && XINT (x, 2) < 0
- && XINT (x, 2) >= -0x1000)))
- *total = 0;
else
- *total = 8;
- return true;
+ return false;
default:
return false;
}
}
+/* Emit the sequence of insns SEQ while preserving the registers REG and REG2.
+ This is achieved by means of a manual dynamic stack space allocation in
+ the current frame. We make the assumption that SEQ doesn't contain any
+ function calls, with the possible exception of calls to the PIC helper. */
+
+static void
+emit_and_preserve (rtx seq, rtx reg, rtx reg2)
+{
+ /* We must preserve the lowest 16 words for the register save area. */
+ HOST_WIDE_INT offset = 16*UNITS_PER_WORD;
+ /* We really need only 2 words of fresh stack space. */
+ HOST_WIDE_INT size = SPARC_STACK_ALIGN (offset + 2*UNITS_PER_WORD);
+
+ rtx slot
+ = gen_rtx_MEM (word_mode, plus_constant (stack_pointer_rtx,
+ SPARC_STACK_BIAS + offset));
+
+ emit_insn (gen_stack_pointer_dec (GEN_INT (size)));
+ emit_insn (gen_rtx_SET (VOIDmode, slot, reg));
+ if (reg2)
+ emit_insn (gen_rtx_SET (VOIDmode,
+ adjust_address (slot, word_mode, UNITS_PER_WORD),
+ reg2));
+ emit_insn (seq);
+ if (reg2)
+ emit_insn (gen_rtx_SET (VOIDmode,
+ reg2,
+ adjust_address (slot, word_mode, UNITS_PER_WORD)));
+ emit_insn (gen_rtx_SET (VOIDmode, reg, slot));
+ emit_insn (gen_stack_pointer_inc (GEN_INT (size)));
+}
+
/* Output the assembler code for a thunk function. THUNK_DECL is the
declaration for the thunk function itself, FUNCTION is the decl for
the target function. DELTA is an immediate constant offset to be
@@ -9300,20 +8531,41 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
tree function)
{
rtx this, insn, funexp;
+ unsigned int int_arg_first;
reload_completed = 1;
epilogue_completed = 1;
no_new_pseudos = 1;
- current_function_uses_only_leaf_regs = 1;
+ reset_block_changes ();
emit_note (NOTE_INSN_PROLOGUE_END);
+ if (flag_delayed_branch)
+ {
+ /* We will emit a regular sibcall below, so we need to instruct
+ output_sibcall that we are in a leaf function. */
+ sparc_leaf_function_p = current_function_uses_only_leaf_regs = 1;
+
+ /* This will cause final.c to invoke leaf_renumber_regs so we
+ must behave as if we were in a not-yet-leafified function. */
+ int_arg_first = SPARC_INCOMING_INT_ARG_FIRST;
+ }
+ else
+ {
+ /* We will emit the sibcall manually below, so we will need to
+ manually spill non-leaf registers. */
+ sparc_leaf_function_p = current_function_uses_only_leaf_regs = 0;
+
+ /* We really are in a leaf function. */
+ int_arg_first = SPARC_OUTGOING_INT_ARG_FIRST;
+ }
+
/* Find the "this" pointer. Normally in %o0, but in ARCH64 if the function
returns a structure, the structure return pointer is there instead. */
if (TARGET_ARCH64 && aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
- this = gen_rtx_REG (Pmode, SPARC_INCOMING_INT_ARG_FIRST + 1);
+ this = gen_rtx_REG (Pmode, int_arg_first + 1);
else
- this = gen_rtx_REG (Pmode, SPARC_INCOMING_INT_ARG_FIRST);
+ this = gen_rtx_REG (Pmode, int_arg_first);
/* Add DELTA. When possible use a plain add, otherwise load it into
a register first. */
@@ -9338,8 +8590,7 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
rtx vcall_offset_rtx = GEN_INT (vcall_offset);
rtx scratch = gen_rtx_REG (Pmode, 1);
- if (vcall_offset >= 0)
- abort ();
+ gcc_assert (vcall_offset < 0);
/* SCRATCH = *THIS. */
emit_move_insn (scratch, gen_rtx_MEM (Pmode, this));
@@ -9392,9 +8643,70 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
TREE_USED (function) = 1;
}
funexp = XEXP (DECL_RTL (function), 0);
- funexp = gen_rtx_MEM (FUNCTION_MODE, funexp);
- insn = emit_call_insn (gen_sibcall (funexp));
- SIBLING_CALL_P (insn) = 1;
+
+ if (flag_delayed_branch)
+ {
+ funexp = gen_rtx_MEM (FUNCTION_MODE, funexp);
+ insn = emit_call_insn (gen_sibcall (funexp));
+ SIBLING_CALL_P (insn) = 1;
+ }
+ else
+ {
+ /* The hoops we have to jump through in order to generate a sibcall
+ without using delay slots... */
+ rtx spill_reg, spill_reg2, seq, scratch = gen_rtx_REG (Pmode, 1);
+
+ if (flag_pic)
+ {
+ spill_reg = gen_rtx_REG (word_mode, 15); /* %o7 */
+ spill_reg2 = gen_rtx_REG (word_mode, PIC_OFFSET_TABLE_REGNUM);
+ start_sequence ();
+ /* Delay emitting the PIC helper function because it needs to
+ change the section and we are emitting assembly code. */
+ load_pic_register (true); /* clobbers %o7 */
+ scratch = legitimize_pic_address (funexp, Pmode, scratch);
+ seq = get_insns ();
+ end_sequence ();
+ emit_and_preserve (seq, spill_reg, spill_reg2);
+ }
+ else if (TARGET_ARCH32)
+ {
+ emit_insn (gen_rtx_SET (VOIDmode,
+ scratch,
+ gen_rtx_HIGH (SImode, funexp)));
+ emit_insn (gen_rtx_SET (VOIDmode,
+ scratch,
+ gen_rtx_LO_SUM (SImode, scratch, funexp)));
+ }
+ else /* TARGET_ARCH64 */
+ {
+ switch (sparc_cmodel)
+ {
+ case CM_MEDLOW:
+ case CM_MEDMID:
+ /* The destination can serve as a temporary. */
+ sparc_emit_set_symbolic_const64 (scratch, funexp, scratch);
+ break;
+
+ case CM_MEDANY:
+ case CM_EMBMEDANY:
+ /* The destination cannot serve as a temporary. */
+ spill_reg = gen_rtx_REG (DImode, 15); /* %o7 */
+ start_sequence ();
+ sparc_emit_set_symbolic_const64 (scratch, funexp, spill_reg);
+ seq = get_insns ();
+ end_sequence ();
+ emit_and_preserve (seq, spill_reg, 0);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+ }
+
+ emit_jump_insn (gen_indirect_jump (scratch));
+ }
+
emit_barrier ();
/* Run just enough of rest_of_compilation to get the insns emitted.
@@ -9405,7 +8717,7 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
insn_locators_initialize ();
shorten_branches (insn);
final_start_function (insn, file, 1);
- final (insn, file, 1, 0);
+ final (insn, file, 1);
final_end_function ();
reload_completed = 0;
@@ -9450,7 +8762,7 @@ get_some_local_dynamic_name (void)
&& for_each_rtx (&PATTERN (insn), get_some_local_dynamic_name_1, 0))
return cfun->machine->some_ld_name;
- abort ();
+ gcc_unreachable ();
}
static int
@@ -9469,10 +8781,22 @@ get_some_local_dynamic_name_1 (rtx *px, void *data ATTRIBUTE_UNUSED)
return 0;
}
-/* This is called from dwarf2out.c via ASM_OUTPUT_DWARF_DTPREL.
+/* Handle the TARGET_DWARF_HANDLE_FRAME_UNSPEC hook.
+ This is called from dwarf2out.c to emit call frame instructions
+ for frame-related insns containing UNSPECs and UNSPEC_VOLATILEs. */
+static void
+sparc_dwarf_handle_frame_unspec (const char *label,
+ rtx pattern ATTRIBUTE_UNUSED,
+ int index ATTRIBUTE_UNUSED)
+{
+ gcc_assert (index == UNSPECV_SAVEW);
+ dwarf2out_window_save (label);
+}
+
+/* This is called from dwarf2out.c via TARGET_ASM_OUTPUT_DWARF_DTPREL.
We need to emit DTP-relative relocations. */
-void
+static void
sparc_output_dwarf_dtprel (FILE *file, int size, rtx x)
{
switch (size)
@@ -9484,10 +8808,142 @@ sparc_output_dwarf_dtprel (FILE *file, int size, rtx x)
fputs ("\t.xword\t%r_tls_dtpoff64(", file);
break;
default:
- abort ();
+ gcc_unreachable ();
}
output_addr_const (file, x);
fputs (")", file);
}
+/* Do whatever processing is required at the end of a file. */
+
+static void
+sparc_file_end (void)
+{
+ /* If we haven't emitted the special PIC helper function, do so now. */
+ if (pic_helper_symbol_name[0] && !pic_helper_emitted_p)
+ emit_pic_helper ();
+
+ if (NEED_INDICATE_EXEC_STACK)
+ file_end_indicate_exec_stack ();
+}
+
+#ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING
+/* Implement TARGET_MANGLE_FUNDAMENTAL_TYPE. */
+
+static const char *
+sparc_mangle_fundamental_type (tree type)
+{
+ if (!TARGET_64BIT
+ && TYPE_MAIN_VARIANT (type) == long_double_type_node
+ && TARGET_LONG_DOUBLE_128)
+ return "g";
+
+ /* For all other types, use normal C++ mangling. */
+ return NULL;
+}
+#endif
+
+/* Expand code to perform a 8 or 16-bit compare and swap by doing 32-bit
+ compare and swap on the word containing the byte or half-word. */
+
+void
+sparc_expand_compare_and_swap_12 (rtx result, rtx mem, rtx oldval, rtx newval)
+{
+ rtx addr1 = force_reg (Pmode, XEXP (mem, 0));
+ rtx addr = gen_reg_rtx (Pmode);
+ rtx off = gen_reg_rtx (SImode);
+ rtx oldv = gen_reg_rtx (SImode);
+ rtx newv = gen_reg_rtx (SImode);
+ rtx oldvalue = gen_reg_rtx (SImode);
+ rtx newvalue = gen_reg_rtx (SImode);
+ rtx res = gen_reg_rtx (SImode);
+ rtx resv = gen_reg_rtx (SImode);
+ rtx memsi, val, mask, end_label, loop_label, cc;
+
+ emit_insn (gen_rtx_SET (VOIDmode, addr,
+ gen_rtx_AND (Pmode, addr1, GEN_INT (-4))));
+
+ if (Pmode != SImode)
+ addr1 = gen_lowpart (SImode, addr1);
+ emit_insn (gen_rtx_SET (VOIDmode, off,
+ gen_rtx_AND (SImode, addr1, GEN_INT (3))));
+
+ memsi = gen_rtx_MEM (SImode, addr);
+ set_mem_alias_set (memsi, ALIAS_SET_MEMORY_BARRIER);
+ MEM_VOLATILE_P (memsi) = MEM_VOLATILE_P (mem);
+
+ val = force_reg (SImode, memsi);
+
+ emit_insn (gen_rtx_SET (VOIDmode, off,
+ gen_rtx_XOR (SImode, off,
+ GEN_INT (GET_MODE (mem) == QImode
+ ? 3 : 2))));
+
+ emit_insn (gen_rtx_SET (VOIDmode, off,
+ gen_rtx_ASHIFT (SImode, off, GEN_INT (3))));
+
+ if (GET_MODE (mem) == QImode)
+ mask = force_reg (SImode, GEN_INT (0xff));
+ else
+ mask = force_reg (SImode, GEN_INT (0xffff));
+
+ emit_insn (gen_rtx_SET (VOIDmode, mask,
+ gen_rtx_ASHIFT (SImode, mask, off)));
+
+ emit_insn (gen_rtx_SET (VOIDmode, val,
+ gen_rtx_AND (SImode, gen_rtx_NOT (SImode, mask),
+ val)));
+
+ oldval = gen_lowpart (SImode, oldval);
+ emit_insn (gen_rtx_SET (VOIDmode, oldv,
+ gen_rtx_ASHIFT (SImode, oldval, off)));
+
+ newval = gen_lowpart_common (SImode, newval);
+ emit_insn (gen_rtx_SET (VOIDmode, newv,
+ gen_rtx_ASHIFT (SImode, newval, off)));
+
+ emit_insn (gen_rtx_SET (VOIDmode, oldv,
+ gen_rtx_AND (SImode, oldv, mask)));
+
+ emit_insn (gen_rtx_SET (VOIDmode, newv,
+ gen_rtx_AND (SImode, newv, mask)));
+
+ end_label = gen_label_rtx ();
+ loop_label = gen_label_rtx ();
+ emit_label (loop_label);
+
+ emit_insn (gen_rtx_SET (VOIDmode, oldvalue,
+ gen_rtx_IOR (SImode, oldv, val)));
+
+ emit_insn (gen_rtx_SET (VOIDmode, newvalue,
+ gen_rtx_IOR (SImode, newv, val)));
+
+ emit_insn (gen_sync_compare_and_swapsi (res, memsi, oldvalue, newvalue));
+
+ emit_cmp_and_jump_insns (res, oldvalue, EQ, NULL, SImode, 0, end_label);
+
+ emit_insn (gen_rtx_SET (VOIDmode, resv,
+ gen_rtx_AND (SImode, gen_rtx_NOT (SImode, mask),
+ res)));
+
+ sparc_compare_op0 = resv;
+ sparc_compare_op1 = val;
+ cc = gen_compare_reg (NE);
+
+ emit_insn (gen_rtx_SET (VOIDmode, val, resv));
+
+ sparc_compare_emitted = cc;
+ emit_jump_insn (gen_bne (loop_label));
+
+ emit_label (end_label);
+
+ emit_insn (gen_rtx_SET (VOIDmode, res,
+ gen_rtx_AND (SImode, res, mask)));
+
+ emit_insn (gen_rtx_SET (VOIDmode, res,
+ gen_rtx_LSHIFTRT (SImode, res, off)));
+
+ emit_move_insn (result, gen_lowpart (GET_MODE (result), res));
+}
+
#include "gt-sparc.h"
diff --git a/contrib/gcc/config/sparc/sparc.h b/contrib/gcc/config/sparc/sparc.h
index 9f72bc8..8a2121c 100644
--- a/contrib/gcc/config/sparc/sparc.h
+++ b/contrib/gcc/config/sparc/sparc.h
@@ -1,6 +1,6 @@
/* Definitions of target machine for GNU compiler, for Sun SPARC.
Copyright (C) 1987, 1988, 1989, 1992, 1994, 1995, 1996, 1997, 1998, 1999
- 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com).
64-bit SPARC-V9 support by Michael Tiemann, Jim Wilson, and Doug Evans,
at Cygnus Support.
@@ -19,12 +19,90 @@ 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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
/* Note that some other tm.h files include this one and then override
whatever definitions are necessary. */
+/* Define the specific costs for a given cpu */
+
+struct processor_costs {
+ /* Integer load */
+ const int int_load;
+
+ /* Integer signed load */
+ const int int_sload;
+
+ /* Integer zeroed load */
+ const int int_zload;
+
+ /* Float load */
+ const int float_load;
+
+ /* fmov, fneg, fabs */
+ const int float_move;
+
+ /* fadd, fsub */
+ const int float_plusminus;
+
+ /* fcmp */
+ const int float_cmp;
+
+ /* fmov, fmovr */
+ const int float_cmove;
+
+ /* fmul */
+ const int float_mul;
+
+ /* fdivs */
+ const int float_div_sf;
+
+ /* fdivd */
+ const int float_div_df;
+
+ /* fsqrts */
+ const int float_sqrt_sf;
+
+ /* fsqrtd */
+ const int float_sqrt_df;
+
+ /* umul/smul */
+ const int int_mul;
+
+ /* mulX */
+ const int int_mulX;
+
+ /* integer multiply cost for each bit set past the most
+ significant 3, so the formula for multiply cost becomes:
+
+ if (rs1 < 0)
+ highest_bit = highest_clear_bit(rs1);
+ else
+ highest_bit = highest_set_bit(rs1);
+ if (highest_bit < 3)
+ highest_bit = 3;
+ cost = int_mul{,X} + ((highest_bit - 3) / int_mul_bit_factor);
+
+ A value of zero indicates that the multiply costs is fixed,
+ and not variable. */
+ const int int_mul_bit_factor;
+
+ /* udiv/sdiv */
+ const int int_div;
+
+ /* divX */
+ const int int_divX;
+
+ /* movcc, movr */
+ const int int_cmove;
+
+ /* penalty for shifts, due to scheduling rules etc. */
+ const int shift_penalty;
+};
+
+extern const struct processor_costs *sparc_costs;
+
/* Target CPU builtins. FIXME: Defining sparc is for the benefit of
Solaris only; otherwise just define __sparc__. Sadly the headers
are such a mess there is no Solaris-specific header. */
@@ -113,8 +191,6 @@ enum cmodel {
CM_EMBMEDANY
};
-/* Value of -mcmodel specified by user. */
-extern const char *sparc_cmodel_string;
/* One of CM_FOO. */
extern enum cmodel sparc_cmodel;
@@ -126,6 +202,19 @@ extern enum cmodel sparc_cmodel;
#define SPARC_DEFAULT_CMODEL CM_32
+/* The SPARC-V9 architecture defines a relaxed memory ordering model (RMO)
+ which requires the following macro to be true if enabled. Prior to V9,
+ there are no instructions to even talk about memory synchronization.
+ Note that the UltraSPARC III processors don't implement RMO, unlike the
+ UltraSPARC II processors. Niagara does not implement RMO either.
+
+ Default to false; for example, Solaris never enables RMO, only ever uses
+ total memory ordering (TMO). */
+#define SPARC_RELAXED_ORDERING false
+
+/* Do not use the .note.GNU-stack convention by default. */
+#define NEED_INDICATE_EXEC_STACK 0
+
/* This is call-clobbered in the normal ABI, but is reserved in the
home grown (aka upward compatible) embedded ABI. */
#define EMBMEDANY_BASE_REG "%g4"
@@ -149,10 +238,12 @@ extern enum cmodel sparc_cmodel;
#define TARGET_CPU_sparc64 7 /* alias */
#define TARGET_CPU_ultrasparc 8
#define TARGET_CPU_ultrasparc3 9
+#define TARGET_CPU_niagara 10
#if TARGET_CPU_DEFAULT == TARGET_CPU_v9 \
|| TARGET_CPU_DEFAULT == TARGET_CPU_ultrasparc \
- || TARGET_CPU_DEFAULT == TARGET_CPU_ultrasparc3
+ || TARGET_CPU_DEFAULT == TARGET_CPU_ultrasparc3 \
+ || TARGET_CPU_DEFAULT == TARGET_CPU_niagara
#define CPP_CPU32_DEFAULT_SPEC ""
#define ASM_CPU32_DEFAULT_SPEC ""
@@ -173,6 +264,10 @@ extern enum cmodel sparc_cmodel;
#define CPP_CPU64_DEFAULT_SPEC "-D__sparc_v9__"
#define ASM_CPU64_DEFAULT_SPEC "-Av9b"
#endif
+#if TARGET_CPU_DEFAULT == TARGET_CPU_niagara
+#define CPP_CPU64_DEFAULT_SPEC "-D__sparc_v9__"
+#define ASM_CPU64_DEFAULT_SPEC "-Av9b"
+#endif
#else
@@ -263,6 +358,7 @@ extern enum cmodel sparc_cmodel;
%{mcpu=v9:-D__sparc_v9__} \
%{mcpu=ultrasparc:-D__sparc_v9__} \
%{mcpu=ultrasparc3:-D__sparc_v9__} \
+%{mcpu=niagara:-D__sparc_v9__} \
%{!mcpu*:%{!mcypress:%{!msparclite:%{!mf930:%{!mf934:%{!mv8:%{!msupersparc:%(cpp_cpu_default)}}}}}}} \
"
#define CPP_ARCH32_SPEC ""
@@ -312,6 +408,7 @@ extern enum cmodel sparc_cmodel;
%{mcpu=v9:-Av9} \
%{mcpu=ultrasparc:%{!mv8plus:-Av9a}} \
%{mcpu=ultrasparc3:%{!mv8plus:-Av9b}} \
+%{mcpu=niagara:%{!mv8plus:-Av9b}} \
%{!mcpu*:%{!mcypress:%{!msparclite:%{!mf930:%{!mf934:%{!mv8:%{!msupersparc:%(asm_cpu_default)}}}}}}} \
"
@@ -392,131 +489,14 @@ extern enum cmodel sparc_cmodel;
/* Show we can debug even without a frame pointer. */
#define CAN_DEBUG_WITHOUT_FP
-#define OVERRIDE_OPTIONS sparc_override_options ()
-
-/* Generate DBX debugging information. */
+/* Option handling. */
-#define DBX_DEBUGGING_INFO 1
+#define OVERRIDE_OPTIONS sparc_override_options ()
-/* Run-time compilation parameters selecting different hardware subsets. */
-
-extern int target_flags;
-
-/* Nonzero if we should generate code to use the fpu. */
-#define MASK_FPU 1
-#define TARGET_FPU (target_flags & MASK_FPU)
-
-/* Nonzero if we should assume that double pointers might be unaligned.
- This can happen when linking gcc compiled code with other compilers,
- because the ABI only guarantees 4 byte alignment. */
-#define MASK_UNALIGNED_DOUBLES 4
-#define TARGET_UNALIGNED_DOUBLES (target_flags & MASK_UNALIGNED_DOUBLES)
-
-/* Nonzero means that we should generate code for a v8 sparc. */
-#define MASK_V8 0x8
-#define TARGET_V8 (target_flags & MASK_V8)
-
-/* Nonzero means that we should generate code for a sparclite.
- This enables the sparclite specific instructions, but does not affect
- whether FPU instructions are emitted. */
-#define MASK_SPARCLITE 0x10
-#define TARGET_SPARCLITE (target_flags & MASK_SPARCLITE)
-
-/* Nonzero if we're compiling for the sparclet. */
-#define MASK_SPARCLET 0x20
-#define TARGET_SPARCLET (target_flags & MASK_SPARCLET)
-
-/* Nonzero if we're compiling for v9 sparc.
- Note that v9's can run in 32 bit mode so this doesn't necessarily mean
- the word size is 64. */
-#define MASK_V9 0x40
-#define TARGET_V9 (target_flags & MASK_V9)
-
-/* Nonzero to generate code that uses the instructions deprecated in
- the v9 architecture. This option only applies to v9 systems. */
-/* ??? This isn't user selectable yet. It's used to enable such insns
- on 32 bit v9 systems and for the moment they're permanently disabled
- on 64 bit v9 systems. */
-#define MASK_DEPRECATED_V8_INSNS 0x80
-#define TARGET_DEPRECATED_V8_INSNS (target_flags & MASK_DEPRECATED_V8_INSNS)
-
/* Mask of all CPU selection flags. */
#define MASK_ISA \
(MASK_V8 + MASK_SPARCLITE + MASK_SPARCLET + MASK_V9 + MASK_DEPRECATED_V8_INSNS)
-/* Nonzero means don't pass `-assert pure-text' to the linker. */
-#define MASK_IMPURE_TEXT 0x100
-#define TARGET_IMPURE_TEXT (target_flags & MASK_IMPURE_TEXT)
-
-/* Nonzero means that we should generate code using a flat register window
- model, i.e. no save/restore instructions are generated, which is
- compatible with normal sparc code.
- The frame pointer is %i7 instead of %fp. */
-#define MASK_FLAT 0x200
-#define TARGET_FLAT (target_flags & MASK_FLAT)
-
-/* Nonzero means use the registers that the SPARC ABI reserves for
- application software. This must be the default to coincide with the
- setting in FIXED_REGISTERS. */
-#define MASK_APP_REGS 0x400
-#define TARGET_APP_REGS (target_flags & MASK_APP_REGS)
-
-/* Option to select how quad word floating point is implemented.
- When TARGET_HARD_QUAD is true, we use the hardware quad instructions.
- Otherwise, we use the SPARC ABI quad library functions. */
-#define MASK_HARD_QUAD 0x800
-#define TARGET_HARD_QUAD (target_flags & MASK_HARD_QUAD)
-
-/* Nonzero on little-endian machines. */
-/* ??? Little endian support currently only exists for sparclet-aout and
- sparc64-elf configurations. May eventually want to expand the support
- to all targets, but for now it's kept local to only those two. */
-#define MASK_LITTLE_ENDIAN 0x1000
-#define TARGET_LITTLE_ENDIAN (target_flags & MASK_LITTLE_ENDIAN)
-
-/* 0x2000, 0x4000 are unused */
-
-/* Nonzero if pointers are 64 bits. */
-#define MASK_PTR64 0x8000
-#define TARGET_PTR64 (target_flags & MASK_PTR64)
-
-/* Nonzero if generating code to run in a 64 bit environment.
- This is intended to only be used by TARGET_ARCH{32,64} as they are the
- mechanism used to control compile time or run time selection. */
-#define MASK_64BIT 0x10000
-#define TARGET_64BIT (target_flags & MASK_64BIT)
-
-/* 0x20000,0x40000 unused */
-
-/* Nonzero means use a stack bias of 2047. Stack offsets are obtained by
- adding 2047 to %sp. This option is for v9 only and is the default. */
-#define MASK_STACK_BIAS 0x80000
-#define TARGET_STACK_BIAS (target_flags & MASK_STACK_BIAS)
-
-/* 0x100000,0x200000 unused */
-
-/* Nonzero means -m{,no-}fpu was passed on the command line. */
-#define MASK_FPU_SET 0x400000
-#define TARGET_FPU_SET (target_flags & MASK_FPU_SET)
-
-/* Use the UltraSPARC Visual Instruction Set extensions. */
-#define MASK_VIS 0x1000000
-#define TARGET_VIS (target_flags & MASK_VIS)
-
-/* Compile for Solaris V8+. 32 bit Solaris preserves the high bits of
- the current out and global registers and Linux 2.2+ as well. */
-#define MASK_V8PLUS 0x2000000
-#define TARGET_V8PLUS (target_flags & MASK_V8PLUS)
-
-/* Force a the fastest alignment on structures to take advantage of
- faster copies. */
-#define MASK_FASTER_STRUCTS 0x4000000
-#define TARGET_FASTER_STRUCTS (target_flags & MASK_FASTER_STRUCTS)
-
-/* Use IEEE quad long double. */
-#define MASK_LONG_DOUBLE_128 0x8000000
-#define TARGET_LONG_DOUBLE_128 (target_flags & MASK_LONG_DOUBLE_128)
-
/* TARGET_HARD_MUL: Use hardware multiply instructions but not %y.
TARGET_HARD_MUL32: Use hardware multiply instructions with rd %y
to get high 32 bits. False in V8+ or V9 because multiply stores
@@ -531,97 +511,11 @@ extern int target_flags;
(TARGET_V8 || TARGET_SPARCLITE || TARGET_SPARCLET \
|| TARGET_DEPRECATED_V8_INSNS || TARGET_V8PLUS)
-
-/* Macro to define tables used to set the flags.
- This is a list in braces of pairs in braces,
- each pair being { "NAME", VALUE }
- where VALUE is the bits to set or minus the bits to clear.
- An empty string NAME is used to identify the default VALUE. */
-
-#define TARGET_SWITCHES \
- { {"fpu", MASK_FPU | MASK_FPU_SET, \
- N_("Use hardware fp") }, \
- {"no-fpu", -MASK_FPU, \
- N_("Do not use hardware fp") }, \
- {"no-fpu", MASK_FPU_SET, NULL, }, \
- {"hard-float", MASK_FPU | MASK_FPU_SET, \
- N_("Use hardware fp") }, \
- {"soft-float", -MASK_FPU, \
- N_("Do not use hardware fp") }, \
- {"soft-float", MASK_FPU_SET, NULL }, \
- {"unaligned-doubles", MASK_UNALIGNED_DOUBLES, \
- N_("Assume possible double misalignment") }, \
- {"no-unaligned-doubles", -MASK_UNALIGNED_DOUBLES, \
- N_("Assume all doubles are aligned") }, \
- {"impure-text", MASK_IMPURE_TEXT, \
- N_("Pass -assert pure-text to linker") }, \
- {"no-impure-text", -MASK_IMPURE_TEXT, \
- N_("Do not pass -assert pure-text to linker") }, \
- {"flat", MASK_FLAT, \
- N_("Use flat register window model") }, \
- {"no-flat", -MASK_FLAT, \
- N_("Do not use flat register window model") }, \
- {"app-regs", MASK_APP_REGS, \
- N_("Use ABI reserved registers") }, \
- {"no-app-regs", -MASK_APP_REGS, \
- N_("Do not use ABI reserved registers") }, \
- {"hard-quad-float", MASK_HARD_QUAD, \
- N_("Use hardware quad fp instructions") }, \
- {"soft-quad-float", -MASK_HARD_QUAD, \
- N_("Do not use hardware quad fp instructions") }, \
- {"v8plus", MASK_V8PLUS, \
- N_("Compile for v8plus ABI") }, \
- {"no-v8plus", -MASK_V8PLUS, \
- N_("Do not compile for v8plus ABI") }, \
- {"vis", MASK_VIS, \
- N_("Utilize Visual Instruction Set") }, \
- {"no-vis", -MASK_VIS, \
- N_("Do not utilize Visual Instruction Set") }, \
- /* ??? These are deprecated, coerced to -mcpu=. Delete in 2.9. */ \
- {"cypress", 0, \
- N_("Optimize for Cypress processors") }, \
- {"sparclite", 0, \
- N_("Optimize for SPARCLite processors") }, \
- {"f930", 0, \
- N_("Optimize for F930 processors") }, \
- {"f934", 0, \
- N_("Optimize for F934 processors") }, \
- {"v8", 0, \
- N_("Use V8 SPARC ISA") }, \
- {"supersparc", 0, \
- N_("Optimize for SuperSPARC processors") }, \
- /* End of deprecated options. */ \
- {"ptr64", MASK_PTR64, \
- N_("Pointers are 64-bit") }, \
- {"ptr32", -MASK_PTR64, \
- N_("Pointers are 32-bit") }, \
- {"32", -MASK_64BIT, \
- N_("Use 32-bit ABI") }, \
- {"64", MASK_64BIT, \
- N_("Use 64-bit ABI") }, \
- {"stack-bias", MASK_STACK_BIAS, \
- N_("Use stack bias") }, \
- {"no-stack-bias", -MASK_STACK_BIAS, \
- N_("Do not use stack bias") }, \
- {"faster-structs", MASK_FASTER_STRUCTS, \
- N_("Use structs on stronger alignment for double-word copies") }, \
- {"no-faster-structs", -MASK_FASTER_STRUCTS, \
- N_("Do not use structs on stronger alignment for double-word copies") }, \
- {"relax", 0, \
- N_("Optimize tail call instructions in assembler and linker") }, \
- {"no-relax", 0, \
- N_("Do not optimize tail call instructions in assembler or linker") }, \
- SUBTARGET_SWITCHES \
- { "", TARGET_DEFAULT, ""}}
-
/* MASK_APP_REGS must always be the default because that's what
FIXED_REGISTERS is set to and -ffixed- is processed before
CONDITIONAL_REGISTER_USAGE is called (where we process -mno-app-regs). */
#define TARGET_DEFAULT (MASK_APP_REGS + MASK_FPU)
-/* This is meant to be redefined in target specific files. */
-#define SUBTARGET_SWITCHES
-
/* Processor type.
These must match the values for the cpu attribute in sparc.md. */
enum processor_type {
@@ -638,7 +532,8 @@ enum processor_type {
PROCESSOR_TSC701,
PROCESSOR_V9,
PROCESSOR_ULTRASPARC,
- PROCESSOR_ULTRASPARC3
+ PROCESSOR_ULTRASPARC3,
+ PROCESSOR_NIAGARA
};
/* This is set from -m{cpu,tune}=xxx. */
@@ -648,20 +543,6 @@ extern enum processor_type sparc_cpu;
Every file includes us, but not every file includes insn-attr.h. */
#define sparc_cpu_attr ((enum attr_cpu) sparc_cpu)
-#define TARGET_OPTIONS \
-{ \
- { "cpu=", &sparc_select[1].string, \
- N_("Use features of and schedule code for given CPU"), 0}, \
- { "tune=", &sparc_select[2].string, \
- N_("Schedule code for given CPU"), 0}, \
- { "cmodel=", &sparc_cmodel_string, \
- N_("Use given SPARC code model"), 0}, \
- SUBTARGET_OPTIONS \
-}
-
-/* This is meant to be redefined in target specific files. */
-#define SUBTARGET_OPTIONS
-
/* Support for a compile-time default CPU, et cetera. The rules are:
--with-cpu is ignored if -mcpu is specified.
--with-tune is ignored if -mtune is specified.
@@ -714,6 +595,8 @@ extern struct sparc_cpu_select sparc_select[];
#define MIN_UNITS_PER_WORD 4
#endif
+#define UNITS_PER_SIMD_WORD (TARGET_VIS ? 8 : UNITS_PER_WORD)
+
/* Now define the sizes of the C data types. */
#define SHORT_TYPE_SIZE 16
@@ -722,18 +605,9 @@ extern struct sparc_cpu_select sparc_select[];
#define LONG_LONG_TYPE_SIZE 64
#define FLOAT_TYPE_SIZE 32
#define DOUBLE_TYPE_SIZE 64
-
-#ifdef SPARC_BI_ARCH
-#define MAX_LONG_TYPE_SIZE 64
-#endif
-
-#if 0
-/* ??? This does not work in SunOS 4.x, so it is not enabled here.
- Instead, it is enabled in sol2.h, because it does work under Solaris. */
-/* Define for support of TFmode long double.
- SPARC ABI says that long double is 4 words. */
-#define LONG_DOUBLE_TYPE_SIZE 128
-#endif
+/* LONG_DOUBLE_TYPE_SIZE is defined per OS even though the
+ SPARC ABI says that it is 128-bit wide. */
+/* #define LONG_DOUBLE_TYPE_SIZE 128 */
/* Width in bits of a pointer.
See also the macro `Pmode' defined below. */
@@ -744,54 +618,24 @@ extern struct sparc_cpu_select sparc_select[];
if ptr_mode and Pmode are the same. */
#define POINTERS_EXTEND_UNSIGNED 1
-/* A macro to update MODE and UNSIGNEDP when an object whose type
- is TYPE and which has the specified mode and signedness is to be
- stored in a register. This macro is only called when TYPE is a
- scalar type. */
-#define PROMOTE_MODE(MODE, UNSIGNEDP, TYPE) \
-if (TARGET_ARCH64 \
- && GET_MODE_CLASS (MODE) == MODE_INT \
- && GET_MODE_SIZE (MODE) < UNITS_PER_WORD) \
- (MODE) = DImode;
-
-/* Define this macro if the promotion described by PROMOTE_MODE
- should also be done for outgoing function arguments. */
-/* This is only needed for TARGET_ARCH64, but since PROMOTE_MODE is a no-op
- for TARGET_ARCH32 this is ok. Otherwise we'd need to add a runtime test
- for this value. */
-#define PROMOTE_FUNCTION_ARGS
-
-/* Define this macro if the promotion described by PROMOTE_MODE
- should also be done for the return value of functions.
- If this macro is defined, FUNCTION_VALUE must perform the same
- promotions done by PROMOTE_MODE. */
-/* This is only needed for TARGET_ARCH64, but since PROMOTE_MODE is a no-op
- for TARGET_ARCH32 this is ok. Otherwise we'd need to add a runtime test
- for this value. */
-#define PROMOTE_FUNCTION_RETURN
-
-/* Define this macro if the promotion described by PROMOTE_MODE
- should _only_ be performed for outgoing function arguments or
- function return values, as specified by PROMOTE_FUNCTION_ARGS
- and PROMOTE_FUNCTION_RETURN, respectively. */
-/* This is only needed for TARGET_ARCH64, but since PROMOTE_MODE is a no-op
- for TARGET_ARCH32 this is ok. Otherwise we'd need to add a runtime test
- for this value. For TARGET_ARCH64 we need it, as we don't have instructions
+/* For TARGET_ARCH64 we need this, as we don't have instructions
for arithmetic operations which do zero/sign extension at the same time,
so without this we end up with a srl/sra after every assignment to an
user variable, which means very very bad code. */
-#define PROMOTE_FOR_CALL_ONLY
+#define PROMOTE_FUNCTION_MODE(MODE, UNSIGNEDP, TYPE) \
+if (TARGET_ARCH64 \
+ && GET_MODE_CLASS (MODE) == MODE_INT \
+ && GET_MODE_SIZE (MODE) < UNITS_PER_WORD) \
+ (MODE) = word_mode;
/* Allocation boundary (in *bits*) for storing arguments in argument list. */
#define PARM_BOUNDARY (TARGET_ARCH64 ? 64 : 32)
/* Boundary (in *bits*) on which stack pointer should be aligned. */
/* FIXME, this is wrong when TARGET_ARCH64 and TARGET_STACK_BIAS, because
- then sp+2047 is 128-bit aligned so sp is really only byte-aligned. */
+ then %sp+2047 is 128-bit aligned so %sp is really only byte-aligned. */
#define STACK_BOUNDARY (TARGET_ARCH64 ? 128 : 64)
-/* Temporary hack until the FIXME above is fixed. This macro is used
- only in pad_to_arg_alignment in function.c; see the comment there
- for details about what it does. */
+/* Temporary hack until the FIXME above is fixed. */
#define SPARC_STACK_BOUNDARY_HACK (TARGET_ARCH64 && TARGET_STACK_BIAS)
/* ALIGN FRAMES on double word boundaries */
@@ -854,15 +698,6 @@ if (TARGET_ARCH64 \
because the linker fails to align the text section enough!
Put them in the data section. This macro is only used in this file. */
#define MAX_TEXT_ALIGN 32
-
-/* This forces all variables and constants to the data section when PIC.
- This is because the SunOS 4 shared library scheme thinks everything in
- text is a function, and patches the address to point to a loader stub. */
-/* This is defined to zero for every system which doesn't use the a.out object
- file format. */
-#ifndef SUNOS4_SHARED_LIBRARIES
-#define SUNOS4_SHARED_LIBRARIES 0
-#endif
/* Standard register usage. */
@@ -875,7 +710,7 @@ if (TARGET_ARCH64 \
SPARC has 32 integer registers and 32 floating point registers.
64 bit SPARC has 32 additional fp regs, but the odd numbered ones are not
accessible. We still account for them to simplify register computations
- (eg: in CLASS_MAX_NREGS). There are also 4 fp condition code registers, so
+ (e.g.: in CLASS_MAX_NREGS). There are also 4 fp condition code registers, so
32+32+32+4 == 100.
Register 100 is used as the integer condition code register.
Register 101 is used as the soft frame pointer register. */
@@ -900,7 +735,7 @@ if (TARGET_ARCH64 \
/* Argument passing regs. */
#define SPARC_OUTGOING_INT_ARG_FIRST 8
-#define SPARC_INCOMING_INT_ARG_FIRST (TARGET_FLAT ? 8 : 24)
+#define SPARC_INCOMING_INT_ARG_FIRST 24
#define SPARC_FP_ARG_FIRST 32
/* 1 for registers that have pervasive standard uses
@@ -1021,19 +856,6 @@ do \
fixed_regs[4] = 1; \
else if (fixed_regs[4] == 2) \
fixed_regs[4] = 0; \
- if (TARGET_FLAT) \
- { \
- int regno; \
- /* Let the compiler believe the frame pointer is still \
- %fp, but output it as %i7. */ \
- fixed_regs[31] = 1; \
- reg_names[HARD_FRAME_POINTER_REGNUM] = "%i7"; \
- /* Disable leaf functions */ \
- memset (sparc_leaf_regs, 0, FIRST_PSEUDO_REGISTER); \
- /* Make LEAF_REG_REMAP a noop. */ \
- for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) \
- leaf_reg_remap [regno] = regno; \
- } \
} \
while (0)
@@ -1071,6 +893,11 @@ extern int sparc_mode_class[];
#define HARD_REGNO_MODE_OK(REGNO, MODE) \
((hard_regno_mode_classes[REGNO] & sparc_mode_class[MODE]) != 0)
+/* Value is 1 if it is OK to rename a hard register FROM to another hard
+ register TO. We cannot rename %g1 as it may be used before the save
+ register window instruction in the prologue. */
+#define HARD_REGNO_RENAME_OK(FROM, TO) ((FROM) != 1)
+
/* Value is 1 if it is a good idea to tie two pseudo registers
when one has mode MODE1 and one has mode MODE2.
If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2,
@@ -1089,9 +916,6 @@ extern int sparc_mode_class[];
/* Specify the registers used for certain standard purposes.
The values of these macros are register numbers. */
-/* SPARC pc isn't overloaded on a register that the compiler knows about. */
-/* #define PC_REGNUM */
-
/* Register to use for pushing function arguments. */
#define STACK_POINTER_REGNUM 14
@@ -1125,17 +949,9 @@ extern int sparc_mode_class[];
/* Value should be nonzero if functions must have frame pointers.
Zero means the frame pointer need not be set up (and parms
may be accessed via the stack pointer) in functions that seem suitable.
- This is computed in `reload', in reload1.c.
- Used in flow.c, global.c, and reload1.c.
-
- Being a non-leaf function does not mean a frame pointer is needed in the
- flat window model. However, the debugger won't be able to backtrace through
- us with out it. */
-#define FRAME_POINTER_REQUIRED \
- (TARGET_FLAT \
- ? (current_function_calls_alloca \
- || !leaf_function_p ()) \
- : ! (leaf_function_p () && only_leaf_regs_used ()))
+ Used in flow.c, global.c, ra.c and reload1.c. */
+#define FRAME_POINTER_REQUIRED \
+ (! (leaf_function_p () && only_leaf_regs_used ()))
/* Base register for access to arguments of the function. */
#define ARG_POINTER_REGNUM FRAME_POINTER_REGNUM
@@ -1155,37 +971,12 @@ extern int sparc_mode_class[];
#define DEFAULT_PCC_STRUCT_RETURN -1
-/* SPARC ABI says that quad-precision floats and all structures are returned
- in memory.
- For v9: unions <= 32 bytes in size are returned in int regs,
- structures up to 32 bytes are returned in int and fp regs. */
-
-#define RETURN_IN_MEMORY(TYPE) \
-(TARGET_ARCH32 \
- ? (TYPE_MODE (TYPE) == BLKmode \
- || TYPE_MODE (TYPE) == TFmode) \
- : (TYPE_MODE (TYPE) == BLKmode \
- && (unsigned HOST_WIDE_INT) int_size_in_bytes (TYPE) > 32))
-
/* Functions which return large structures get the address
to place the wanted value at offset 64 from the frame.
Must reserve 64 bytes for the in and local registers.
v9: Functions which return large structures get the address to place the
wanted value from an invisible first argument. */
-/* Used only in other #defines in this file. */
#define STRUCT_VALUE_OFFSET 64
-
-#define STRUCT_VALUE \
- (TARGET_ARCH64 \
- ? 0 \
- : gen_rtx_MEM (Pmode, plus_constant (stack_pointer_rtx, \
- STRUCT_VALUE_OFFSET)))
-
-#define STRUCT_VALUE_INCOMING \
- (TARGET_ARCH64 \
- ? 0 \
- : gen_rtx_MEM (Pmode, plus_constant (frame_pointer_rtx, \
- STRUCT_VALUE_OFFSET)))
/* Define the classes of registers for register constraints in the
machine description. Also define ranges of constants.
@@ -1224,11 +1015,12 @@ extern int sparc_mode_class[];
because reg_class_subunion[GENERAL_REGS][FP_REGS] will yield FP_REGS,
because FP_REGS > GENERAL_REGS.
- It is also important that one class contain all the general and all the
- fp regs. Otherwise when spilling a DFmode reg, it may be from EXTRA_FP_REGS
- but find_reloads() may use class GENERAL_OR_FP_REGS. This will cause
- allocate_reload_reg() to bypass it causing an abort because the compiler
- thinks it doesn't have a spill reg when in fact it does.
+ It is also important that one class contain all the general and all
+ the fp regs. Otherwise when spilling a DFmode reg, it may be from
+ EXTRA_FP_REGS but find_reloads() may use class
+ GENERAL_OR_FP_REGS. This will cause allocate_reload_reg() to die
+ because the compiler thinks it doesn't have a spill reg when in
+ fact it does.
v9 also has 4 floating point condition code registers. Since we don't
have a class that is the union of FPCC_REGS with either of the others,
@@ -1405,8 +1197,8 @@ extern char leaf_reg_remap[];
: (C) == 'c' ? FPCC_REGS \
: NO_REGS))
-/* The letters I, J, K, L and M in a register constraint string
- can be used to stand for particular ranges of immediate operands.
+/* The letters I, J, K, L, M, N, O, P in a register constraint string
+ can be used to stand for particular ranges of CONST_INTs.
This macro defines what the ranges are.
C is the letter, and VALUE is a constant value.
Return 1 if VALUE is in the range specified by C.
@@ -1417,20 +1209,32 @@ extern char leaf_reg_remap[];
`L' is used for the range of constants supported by the movcc insns.
`M' is used for the range of constants supported by the movrcc insns.
`N' is like K, but for constants wider than 32 bits.
- `O' is used for the range which is just 4096. */
+ `O' is used for the range which is just 4096.
+ `P' is free. */
+/* Predicates for 10-bit, 11-bit and 13-bit signed constants. */
#define SPARC_SIMM10_P(X) ((unsigned HOST_WIDE_INT) (X) + 0x200 < 0x400)
#define SPARC_SIMM11_P(X) ((unsigned HOST_WIDE_INT) (X) + 0x400 < 0x800)
#define SPARC_SIMM13_P(X) ((unsigned HOST_WIDE_INT) (X) + 0x1000 < 0x2000)
-/* 10 and 11 bit immediates are only used for a few specific insns.
+
+/* 10- and 11-bit immediates are only used for a few specific insns.
SMALL_INT is used throughout the port so we continue to use it. */
#define SMALL_INT(X) (SPARC_SIMM13_P (INTVAL (X)))
-/* 13 bit immediate, considering only the low 32 bits */
-#define SMALL_INT32(X) (SPARC_SIMM13_P (trunc_int_for_mode \
- (INTVAL (X), SImode)))
+
+/* Predicate for constants that can be loaded with a sethi instruction.
+ This is the general, 64-bit aware, bitwise version that ensures that
+ only constants whose representation fits in the mask
+
+ 0x00000000fffffc00
+
+ are accepted. It will reject, for example, negative SImode constants
+ on 64-bit hosts, so correct handling is to mask the value beforehand
+ according to the mode of the instruction. */
#define SPARC_SETHI_P(X) \
(((unsigned HOST_WIDE_INT) (X) \
& ((unsigned HOST_WIDE_INT) 0x3ff - GET_MODE_MASK (SImode) - 1)) == 0)
+
+/* Version of the above predicate for SImode constants and below. */
#define SPARC_SETHI32_P(X) \
(SPARC_SETHI_P ((unsigned HOST_WIDE_INT) (X) & GET_MODE_MASK (SImode)))
@@ -1444,13 +1248,12 @@ extern char leaf_reg_remap[];
: (C) == 'O' ? (VALUE) == 4096 \
: 0)
-/* Similar, but for floating constants, and defining letters G and H.
+/* Similar, but for CONST_DOUBLEs, and defining letters G and H.
Here VALUE is the CONST_DOUBLE rtx itself. */
#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) \
- ((C) == 'G' ? fp_zero_operand (VALUE, GET_MODE (VALUE)) \
+ ((C) == 'G' ? const_zero_operand (VALUE, GET_MODE (VALUE)) \
: (C) == 'H' ? arith_double_operand (VALUE, DImode) \
- : (C) == 'O' ? arith_double_4096_operand (VALUE, DImode) \
: 0)
/* Given an rtx X being reloaded into a reg required to be
@@ -1473,7 +1276,7 @@ extern char leaf_reg_remap[];
|| (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT \
&& ! TARGET_FPU) \
|| (GET_MODE (X) == TFmode \
- && ! fp_zero_operand (X, TFmode))) \
+ && ! const_zero_operand (X, TFmode))) \
? NO_REGS \
: (!FP_REG_CLASS_P (CLASS) \
&& GET_MODE_CLASS (GET_MODE (X)) == MODE_INT) \
@@ -1565,41 +1368,26 @@ extern char leaf_reg_remap[];
/* Stack layout; function entry, exit and calling. */
-/* Define the number of register that can hold parameters.
- This macro is only used in other macro definitions below and in sparc.c.
- MODE is the mode of the argument.
- !v9: All args are passed in %o0-%o5.
- v9: %o0-%o5 and %f0-%f31 are cumulatively used to pass values.
- See the description in sparc.c. */
-#define NPARM_REGS(MODE) \
-(TARGET_ARCH64 \
- ? (GET_MODE_CLASS (MODE) == MODE_FLOAT ? 32 : 6) \
- : 6)
-
/* Define this if pushing a word on the stack
makes the stack pointer a smaller address. */
#define STACK_GROWS_DOWNWARD
-/* Define this if the nominal address of the stack frame
+/* Define this to nonzero if the nominal address of the stack frame
is at the high-address end of the local variables;
that is, each additional local variable allocated
goes at a more negative offset in the frame. */
-#define FRAME_GROWS_DOWNWARD
+#define FRAME_GROWS_DOWNWARD 1
/* Offset within stack frame to start allocating local variables at.
If FRAME_GROWS_DOWNWARD, this is the offset to the END of the
first local allocated. Otherwise, it is the offset to the BEGINNING
of the first local allocated. */
-/* This allows space for one TFmode floating point value. */
+/* This allows space for one TFmode floating point value, which is used
+ by SECONDARY_MEMORY_NEEDED_RTX. */
#define STARTING_FRAME_OFFSET \
(TARGET_ARCH64 ? -16 \
: (-SPARC_STACK_ALIGN (LONG_DOUBLE_TYPE_SIZE / BITS_PER_UNIT)))
-/* If we generate an insn to push BYTES bytes,
- this says how many the stack pointer really advances by.
- On SPARC, don't define this because there are no push insns. */
-/* #define PUSH_ROUNDING(BYTES) */
-
/* Offset of first parameter from the argument pointer register value.
!v9: This is 64 for the ins and locals, plus 4 for the struct-return reg
even if this function isn't going to use it.
@@ -1624,7 +1412,6 @@ extern char leaf_reg_remap[];
#define REG_PARM_STACK_SPACE(DECL) (6 * UNITS_PER_WORD)
/* Definitions for register elimination. */
-/* ??? In TARGET_FLAT mode we needn't have a hard frame pointer. */
#define ELIMINABLE_REGS \
{{ FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
@@ -1637,22 +1424,16 @@ extern char leaf_reg_remap[];
#define CAN_ELIMINATE(FROM, TO) \
((TO) == HARD_FRAME_POINTER_REGNUM || !FRAME_POINTER_REQUIRED)
-#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
- do { \
- (OFFSET) = 0; \
- if ((TO) == STACK_POINTER_REGNUM) \
- { \
- /* Note, we always pretend that this is a leaf function \
- because if it's not, there's no point in trying to \
- eliminate the frame pointer. If it is a leaf \
- function, we guessed right! */ \
- if (TARGET_FLAT) \
- (OFFSET) = \
- sparc_flat_compute_frame_size (get_frame_size ()); \
- else \
- (OFFSET) = compute_frame_size (get_frame_size (), 1); \
- } \
- (OFFSET) += SPARC_STACK_BIAS; \
+/* We always pretend that this is a leaf function because if it's not,
+ there's no point in trying to eliminate the frame pointer. If it
+ is a leaf function, we guessed right! */
+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
+ do { \
+ if ((TO) == STACK_POINTER_REGNUM) \
+ (OFFSET) = sparc_compute_frame_size (get_frame_size (), 1); \
+ else \
+ (OFFSET) = 0; \
+ (OFFSET) += SPARC_STACK_BIAS; \
} while (0)
/* Keep the stack pointer constant throughout the function.
@@ -1670,40 +1451,13 @@ extern char leaf_reg_remap[];
#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) 0
-/* Some subroutine macros specific to this machine.
- When !TARGET_FPU, put float return values in the general registers,
- since we don't have any fp registers. */
-#define BASE_RETURN_VALUE_REG(MODE) \
- (TARGET_ARCH64 \
- ? (TARGET_FPU && FLOAT_MODE_P (MODE) ? 32 : 8) \
- : (TARGET_FPU && FLOAT_MODE_P (MODE) && (MODE) != TFmode ? 32 : 8))
-
-#define BASE_OUTGOING_VALUE_REG(MODE) \
- (TARGET_ARCH64 \
- ? (TARGET_FPU && FLOAT_MODE_P (MODE) ? 32 \
- : TARGET_FLAT ? 8 : 24) \
- : (TARGET_FPU && FLOAT_MODE_P (MODE) && (MODE) != TFmode ? 32\
- : (TARGET_FLAT ? 8 : 24)))
-
-#define BASE_PASSING_ARG_REG(MODE) \
- (TARGET_ARCH64 \
- ? (TARGET_FPU && FLOAT_MODE_P (MODE) ? 32 : 8) \
- : 8)
-
-/* ??? FIXME -- seems wrong for v9 structure passing... */
-#define BASE_INCOMING_ARG_REG(MODE) \
- (TARGET_ARCH64 \
- ? (TARGET_FPU && FLOAT_MODE_P (MODE) ? 32 \
- : TARGET_FLAT ? 8 : 24) \
- : (TARGET_FLAT ? 8 : 24))
-
/* Define this macro if the target machine has "register windows". This
C expression returns the register number as seen by the called function
corresponding to register number OUT as seen by the calling function.
Return OUT if register number OUT is not an outbound register. */
#define INCOMING_REGNO(OUT) \
- ((TARGET_FLAT || (OUT) < 8 || (OUT) > 15) ? (OUT) : (OUT) + 16)
+ (((OUT) < 8 || (OUT) > 15) ? (OUT) : (OUT) + 16)
/* Define this macro if the target machine has "register windows". This
C expression returns the register number as seen by the calling function
@@ -1711,14 +1465,14 @@ extern char leaf_reg_remap[];
Return IN if register number IN is not an inbound register. */
#define OUTGOING_REGNO(IN) \
- ((TARGET_FLAT || (IN) < 24 || (IN) > 31) ? (IN) : (IN) - 16)
+ (((IN) < 24 || (IN) > 31) ? (IN) : (IN) - 16)
/* Define this macro if the target machine has register windows. This
C expression returns true if the register is call-saved but is in the
register window. */
#define LOCAL_REGNO(REGNO) \
- (TARGET_FLAT ? 0 : (REGNO) >= 16 && (REGNO) <= 31)
+ ((REGNO) >= 16 && (REGNO) <= 31)
/* Define how to find the value returned by a function.
VALTYPE is the data type of the value (as a tree).
@@ -1751,7 +1505,7 @@ extern char leaf_reg_remap[];
/* Define the size of space to allocate for the return value of an
untyped_call. */
-#define APPLY_RESULT_SIZE 16
+#define APPLY_RESULT_SIZE (TARGET_ARCH64 ? 24 : 16)
/* 1 if N is a possible register number for function argument passing.
On SPARC, these are the "output" registers. v9 also uses %f0-%f31. */
@@ -1795,13 +1549,6 @@ init_cumulative_args (& (CUM), (FNTYPE), (LIBNAME), (FNDECL));
#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \
function_arg_advance (& (CUM), (MODE), (TYPE), (NAMED))
-/* Nonzero if we do not know how to pass TYPE solely in registers. */
-
-#define MUST_PASS_IN_STACK(MODE,TYPE) \
- ((TYPE) != 0 \
- && (TREE_CODE (TYPE_SIZE (TYPE)) != INTEGER_CST \
- || TREE_ADDRESSABLE (TYPE)))
-
/* Determine where to put an argument to a function.
Value is zero to push the argument on the stack,
or a hard register in which to store the argument.
@@ -1824,22 +1571,6 @@ function_arg (& (CUM), (MODE), (TYPE), (NAMED), 0)
#define FUNCTION_INCOMING_ARG(CUM, MODE, TYPE, NAMED) \
function_arg (& (CUM), (MODE), (TYPE), (NAMED), 1)
-/* For an arg passed partly in registers and partly in memory,
- this is the number of registers used.
- For args passed entirely in registers or entirely in memory, zero. */
-
-#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \
-function_arg_partial_nregs (& (CUM), (MODE), (TYPE), (NAMED))
-
-/* A C expression that indicates when an argument must be passed by reference.
- If nonzero for an argument, a copy of that argument is made in memory and a
- pointer to the argument is passed instead of the argument itself.
- The pointer is passed in whatever way is appropriate for passing a pointer
- to that type. */
-
-#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) \
-function_arg_pass_by_reference (& (CUM), (MODE), (TYPE), (NAMED))
-
/* If defined, a C expression which determines whether, and in which direction,
to pad out an argument with extra space. The value should be of type
`enum direction': either `upward' to pad above the argument,
@@ -1865,6 +1596,7 @@ function_arg_padding ((MODE), (TYPE))
extern GTY(()) rtx sparc_compare_op0;
extern GTY(()) rtx sparc_compare_op1;
+extern GTY(()) rtx sparc_compare_emitted;
/* Generate the special assembly code needed to tell the assembler whatever
@@ -1934,15 +1666,9 @@ do { \
(get_frame_size () != 0 \
|| current_function_calls_alloca || current_function_outgoing_args_size)
-#define DELAY_SLOTS_FOR_EPILOGUE \
- (TARGET_FLAT ? sparc_flat_epilogue_delay_slots () : 1)
-#define ELIGIBLE_FOR_EPILOGUE_DELAY(trial, slots_filled) \
- (TARGET_FLAT ? sparc_flat_eligible_for_epilogue_delay (trial, slots_filled) \
- : eligible_for_epilogue_delay (trial, slots_filled))
-
/* Define registers used by the epilogue and return instruction. */
-#define EPILOGUE_USES(REGNO) \
- (!TARGET_FLAT && REGNO == 31)
+#define EPILOGUE_USES(REGNO) ((REGNO) == 31 \
+ || (current_function_calls_eh_return && (REGNO) == 1))
/* Length in units of the trampoline for entering a nested function. */
@@ -1960,31 +1686,10 @@ do { \
else \
sparc_initialize_trampoline (TRAMP, FNADDR, CXT)
-/* Generate necessary RTL for __builtin_saveregs(). */
-
-#define EXPAND_BUILTIN_SAVEREGS() sparc_builtin_saveregs ()
-
/* Implement `va_start' for varargs and stdarg. */
#define EXPAND_BUILTIN_VA_START(valist, nextarg) \
sparc_va_start (valist, nextarg)
-/* Implement `va_arg'. */
-#define EXPAND_BUILTIN_VA_ARG(valist, type) \
- sparc_va_arg (valist, type)
-
-/* Define this macro if the location where a function argument is passed
- depends on whether or not it is a named argument.
-
- This macro controls how the NAMED argument to FUNCTION_ARG
- is set for varargs and stdarg functions. With this macro defined,
- the NAMED argument is always true for named arguments, and false for
- unnamed arguments. If this is not defined, but SETUP_INCOMING_VARARGS
- is defined, then all arguments are treated as named. Otherwise, all named
- arguments except the last are treated as named.
- For the v9 we want NAMED to mean what it says it means. */
-
-#define STRICT_ARGUMENT_NAMING TARGET_V9
-
/* Generate RTL to flush the register windows so as to make arbitrary frames
available. */
#define SETUP_FRAME_ADDRESSES() \
@@ -1992,11 +1697,14 @@ do { \
/* Given an rtx for the address of a frame,
return an rtx for the address of the word in the frame
- that holds the dynamic chain--the previous frame's address.
- ??? -mflat support? */
+ that holds the dynamic chain--the previous frame's address. */
#define DYNAMIC_CHAIN_ADDRESS(frame) \
plus_constant (frame, 14 * UNITS_PER_WORD + SPARC_STACK_BIAS)
+/* Given an rtx for the frame pointer,
+ return an rtx for the address of the frame. */
+#define FRAME_ADDR_RTX(frame) plus_constant (frame, SPARC_STACK_BIAS)
+
/* The return address isn't on the stack, it is in a register, so we can't
access it from the current frame pointer. We can access it from the
previous frame pointer though by reading a value from the register window
@@ -2168,7 +1876,9 @@ do { \
integer register, needed for ldd/std instructions.
'W' handles the memory operand when moving operands in/out
- of 'e' constraint floating point registers. */
+ of 'e' constraint floating point registers.
+
+ 'Y' handles the zero vector constant. */
#ifndef REG_OK_STRICT
@@ -2353,12 +2063,6 @@ do { \
(! TARGET_PTR64 ? SImode : flag_pic ? DImode : TARGET_CM_MEDLOW ? SImode : DImode)
#endif
-/* Define as C expression which evaluates to nonzero if the tablejump
- instruction expects the table to contain offsets from the address of the
- table.
- Do not define this if the table should contain absolute addresses. */
-/* #define CASE_VECTOR_PC_RELATIVE 1 */
-
/* Define this as 1 if `char' should by default be signed; else as 0. */
#define DEFAULT_SIGNED_CHAR 1
@@ -2366,15 +2070,10 @@ do { \
in one reasonably fast instruction. */
#define MOVE_MAX 8
-#if 0 /* Sun 4 has matherr, so this is no good. */
-/* This is the value of the error code EDOM for this machine,
- used by the sqrt instruction. */
-#define TARGET_EDOM 33
+/* If a memory-to-memory move would take MOVE_RATIO or more simple
+ move-instruction pairs, we will do a movmem or libcall instead. */
-/* This is how to refer to the variable errno. */
-#define GEN_ERRNO_RTX \
- gen_rtx_MEM (SImode, gen_rtx_SYMBOL_REF (Pmode, "errno"))
-#endif /* 0 */
+#define MOVE_RATIO (optimize_size ? 3 : 8)
/* Define if operations between registers always perform the operation
on the full register even if a narrower mode is specified. */
@@ -2383,7 +2082,7 @@ do { \
/* Define if loading in MODE, an integral mode narrower than BITS_PER_WORD
will either zero-extend or sign-extend. The value of this macro should
be the code that says which one of the two operations is implicitly
- done, NIL if none. */
+ done, UNKNOWN if none. */
#define LOAD_EXTEND_OP(MODE) ZERO_EXTEND
/* Nonzero if access to memory by bytes is slow and undesirable.
@@ -2392,9 +2091,6 @@ do { \
and maybe make use of that. */
#define SLOW_BYTE_ACCESS 1
-/* When a prototype says `char' or `short', really pass an `int'. */
-#define PROMOTE_PROTOTYPES (TARGET_ARCH32)
-
/* Define this to be nonzero if shift instructions ignore all but the low-order
few bits. */
#define SHIFT_COUNT_TRUNCATED 1
@@ -2406,9 +2102,6 @@ do { \
/* Specify the machine mode used for addresses. */
#define Pmode (TARGET_ARCH64 ? DImode : SImode)
-/* Generate calls to memcpy, memcmp and memset. */
-#define TARGET_MEM_FUNCTIONS
-
/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
return the mode to be used for the comparison. For floating-point,
CCFP[E]mode is used. CC_NOOVmode should be used when the first operand
@@ -2457,7 +2150,8 @@ do { \
|| (GENERAL_OR_I64 (CLASS1) && FP_REG_CLASS_P (CLASS2)) \
|| (CLASS1) == FPCC_REGS || (CLASS2) == FPCC_REGS) \
? ((sparc_cpu == PROCESSOR_ULTRASPARC \
- || sparc_cpu == PROCESSOR_ULTRASPARC3) ? 12 : 6) : 2)
+ || sparc_cpu == PROCESSOR_ULTRASPARC3 \
+ || sparc_cpu == PROCESSOR_NIAGARA) ? 12 : 6) : 2)
/* Provide the cost of a branch. For pre-v9 processors we use
a value of 3 to take into account the potential annulling of
@@ -2467,22 +2161,30 @@ do { \
On v9 and later, which have branch prediction facilities, we set
it to the depth of the pipeline as that is the cost of a
- mispredicted branch. */
+ mispredicted branch.
+
+ On Niagara, normal branches insert 3 bubbles into the pipe
+ and annulled branches insert 4 bubbles. */
#define BRANCH_COST \
((sparc_cpu == PROCESSOR_V9 \
|| sparc_cpu == PROCESSOR_ULTRASPARC) \
? 7 \
: (sparc_cpu == PROCESSOR_ULTRASPARC3 \
- ? 9 : 3))
+ ? 9 \
+ : (sparc_cpu == PROCESSOR_NIAGARA \
+ ? 4 \
+ : 3)))
#define PREFETCH_BLOCK \
((sparc_cpu == PROCESSOR_ULTRASPARC \
- || sparc_cpu == PROCESSOR_ULTRASPARC3) \
+ || sparc_cpu == PROCESSOR_ULTRASPARC3 \
+ || sparc_cpu == PROCESSOR_NIAGARA) \
? 64 : 32)
#define SIMULTANEOUS_PREFETCHES \
- ((sparc_cpu == PROCESSOR_ULTRASPARC) \
+ ((sparc_cpu == PROCESSOR_ULTRASPARC \
+ || sparc_cpu == PROCESSOR_NIAGARA) \
? 2 \
: (sparc_cpu == PROCESSOR_ULTRASPARC3 \
? 8 : 3))
@@ -2505,12 +2207,6 @@ do { \
#define ASM_APP_OFF ""
-/* ??? Try to make the style consistent here (_OP?). */
-
-#define ASM_FLOAT ".single"
-#define ASM_DOUBLE ".double"
-#define ASM_LONGDOUBLE ".xxx" /* ??? Not known (or used yet). */
-
/* How to refer to registers in assembler output.
This sequence is indexed by compiler's hard-register-number (see above). */
@@ -2666,16 +2362,25 @@ do { \
#define ASM_OUTPUT_IDENT(FILE, NAME) \
fprintf (FILE, "%s\"%s\"\n", IDENT_ASM_OP, NAME);
-/* Emit a dtp-relative reference to a TLS variable. */
+/* Prettify the assembly. */
-#ifdef HAVE_AS_TLS
-#define ASM_OUTPUT_DWARF_DTPREL(FILE, SIZE, X) \
- sparc_output_dwarf_dtprel (FILE, SIZE, X)
-#endif
+extern int sparc_indent_opcode;
+
+#define ASM_OUTPUT_OPCODE(FILE, PTR) \
+ do { \
+ if (sparc_indent_opcode) \
+ { \
+ putc (' ', FILE); \
+ sparc_indent_opcode = 0; \
+ } \
+ } while (0)
+
+#define SPARC_SYMBOL_REF_TLS_P(RTX) \
+ (GET_CODE (RTX) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (RTX) != 0)
#define PRINT_OPERAND_PUNCT_VALID_P(CHAR) \
- ((CHAR) == '#' || (CHAR) == '*' || (CHAR) == '^' \
- || (CHAR) == '(' || (CHAR) == '_' || (CHAR) == '&')
+ ((CHAR) == '#' || (CHAR) == '*' || (CHAR) == '(' \
+ || (CHAR) == ')' || (CHAR) == '_' || (CHAR) == '&')
/* Print operand X (an rtx) in assembler syntax to file FILE.
CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
@@ -2701,10 +2406,9 @@ do { \
base = XEXP (addr, 0), index = XEXP (addr, 1); \
if (GET_CODE (base) == LO_SUM) \
{ \
- if (! USE_AS_OFFSETABLE_LO10 \
- || TARGET_ARCH32 \
- || TARGET_CM_MEDMID) \
- abort (); \
+ gcc_assert (USE_AS_OFFSETABLE_LO10 \
+ && TARGET_ARCH64 \
+ && ! TARGET_CM_MEDMID); \
output_operand (XEXP (base, 0), 0); \
fputs ("+%lo(", FILE); \
output_address (XEXP (base, 1)); \
@@ -2720,7 +2424,7 @@ do { \
else if (GET_CODE (index) == SYMBOL_REF \
|| GET_CODE (index) == CONST) \
fputc ('+', FILE), output_addr_const (FILE, index); \
- else abort (); \
+ else gcc_unreachable (); \
} \
} \
else if (GET_CODE (addr) == MINUS \
@@ -2762,69 +2466,16 @@ do { \
} \
}
+/* TLS support defaulting to original Sun flavor. GNU extensions
+ must be activated in separate configuration files. */
#ifdef HAVE_AS_TLS
#define TARGET_TLS 1
#else
#define TARGET_TLS 0
#endif
+
#define TARGET_SUN_TLS TARGET_TLS
#define TARGET_GNU_TLS 0
-/* Define the codes that are matched by predicates in sparc.c. */
-
-#define PREDICATE_CODES \
-{"reg_or_0_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE}}, \
-{"const1_operand", {CONST_INT}}, \
-{"fp_zero_operand", {CONST_DOUBLE}}, \
-{"fp_register_operand", {SUBREG, REG}}, \
-{"intreg_operand", {SUBREG, REG}}, \
-{"fcc_reg_operand", {REG}}, \
-{"fcc0_reg_operand", {REG}}, \
-{"icc_or_fcc_reg_operand", {REG}}, \
-{"restore_operand", {REG}}, \
-{"call_operand", {MEM}}, \
-{"call_operand_address", {SYMBOL_REF, LABEL_REF, CONST, CONST_DOUBLE, \
- ADDRESSOF, SUBREG, REG, PLUS, LO_SUM, CONST_INT}}, \
-{"symbolic_operand", {SYMBOL_REF, LABEL_REF, CONST}}, \
-{"symbolic_memory_operand", {SUBREG, MEM}}, \
-{"label_ref_operand", {LABEL_REF}}, \
-{"sp64_medium_pic_operand", {CONST}}, \
-{"data_segment_operand", {SYMBOL_REF, PLUS, CONST}}, \
-{"text_segment_operand", {LABEL_REF, SYMBOL_REF, PLUS, CONST}}, \
-{"reg_or_nonsymb_mem_operand", {SUBREG, REG, MEM}}, \
-{"splittable_symbolic_memory_operand", {MEM}}, \
-{"splittable_immediate_memory_operand", {MEM}}, \
-{"eq_or_neq", {EQ, NE}}, \
-{"normal_comp_operator", {GE, GT, LE, LT, GTU, LEU}}, \
-{"noov_compare_op", {NE, EQ, GE, GT, LE, LT, GEU, GTU, LEU, LTU}}, \
-{"noov_compare64_op", {NE, EQ, GE, GT, LE, LT, GEU, GTU, LEU, LTU}}, \
-{"v9_regcmp_op", {EQ, NE, GE, LT, LE, GT}}, \
-{"extend_op", {SIGN_EXTEND, ZERO_EXTEND}}, \
-{"cc_arithop", {AND, IOR, XOR}}, \
-{"cc_arithopn", {AND, IOR}}, \
-{"arith_operand", {SUBREG, REG, CONST_INT}}, \
-{"arith_add_operand", {SUBREG, REG, CONST_INT}}, \
-{"arith11_operand", {SUBREG, REG, CONST_INT}}, \
-{"arith10_operand", {SUBREG, REG, CONST_INT}}, \
-{"arith_double_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE}}, \
-{"arith_double_add_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE}}, \
-{"arith11_double_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE}}, \
-{"arith10_double_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE}}, \
-{"small_int", {CONST_INT}}, \
-{"small_int_or_double", {CONST_INT, CONST_DOUBLE}}, \
-{"uns_small_int", {CONST_INT}}, \
-{"uns_arith_operand", {SUBREG, REG, CONST_INT}}, \
-{"clobbered_register", {REG}}, \
-{"input_operand", {SUBREG, REG, CONST_INT, MEM, CONST}}, \
-{"compare_operand", {SUBREG, REG, ZERO_EXTRACT}}, \
-{"const64_operand", {CONST_INT, CONST_DOUBLE}}, \
-{"const64_high_operand", {CONST_INT, CONST_DOUBLE}}, \
-{"tgd_symbolic_operand", {SYMBOL_REF}}, \
-{"tld_symbolic_operand", {SYMBOL_REF}}, \
-{"tie_symbolic_operand", {SYMBOL_REF}}, \
-{"tle_symbolic_operand", {SYMBOL_REF}},
-
/* The number of Pmode words for the setjmp buffer. */
#define JMP_BUF_SIZE 12
-
-#define DONT_ACCESS_GBLS_AFTER_EPILOGUE (flag_pic)
diff --git a/contrib/gcc/config/sparc/sparc.md b/contrib/gcc/config/sparc/sparc.md
index b50d10a..ed68f1e 100644
--- a/contrib/gcc/config/sparc/sparc.md
+++ b/contrib/gcc/config/sparc/sparc.md
@@ -1,6 +1,6 @@
;; Machine description for SPARC chip for GCC
;; Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-;; 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+;; 1999, 2000, 2001, 2002, 2003, 2004, 2005,2006 Free Software Foundation, Inc.
;; Contributed by Michael Tiemann (tiemann@cygnus.com)
;; 64-bit SPARC-V9 support by Michael Tiemann, Jim Wilson, and Doug Evans,
;; at Cygnus Support.
@@ -19,15 +19,15 @@
;; 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, 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
(define_constants
[(UNSPEC_MOVE_PIC 0)
(UNSPEC_UPDATE_RETURN 1)
- (UNSPEC_GET_PC 2)
+ (UNSPEC_LOAD_PCREL_SYM 2)
(UNSPEC_MOVE_PIC_LABEL 5)
(UNSPEC_SETH44 6)
(UNSPEC_SETM44 7)
@@ -45,15 +45,34 @@
(UNSPEC_TLSIE 33)
(UNSPEC_TLSLE 34)
(UNSPEC_TLSLD_BASE 35)
+
+ (UNSPEC_FPACK16 40)
+ (UNSPEC_FPACK32 41)
+ (UNSPEC_FPACKFIX 42)
+ (UNSPEC_FEXPAND 43)
+ (UNSPEC_FPMERGE 44)
+ (UNSPEC_MUL16AL 45)
+ (UNSPEC_MUL8UL 46)
+ (UNSPEC_MULDUL 47)
+ (UNSPEC_ALIGNDATA 48)
+ (UNSPEC_ALIGNADDR 49)
+ (UNSPEC_PDIST 50)
+
+ (UNSPEC_SP_SET 60)
+ (UNSPEC_SP_TEST 61)
])
(define_constants
[(UNSPECV_BLOCKAGE 0)
(UNSPECV_FLUSHW 1)
(UNSPECV_GOTO 2)
- (UNSPECV_GOTO_V9 3)
(UNSPECV_FLUSH 4)
(UNSPECV_SETJMP 5)
+ (UNSPECV_SAVEW 6)
+ (UNSPECV_MEMBAR 7)
+ (UNSPECV_CAS 8)
+ (UNSPECV_SWAP 9)
+ (UNSPECV_LDSTUB 10)
])
;; The upper 32 fp regs on the v9 can't hold SFmode values. To deal with this
@@ -62,6 +81,7 @@
;; constraint letter is 'e'. To avoid any confusion, 'e' is used instead of
;; 'f' for all DF/TFmode values, including those that are specific to the v8.
+
;; Attribute for cpu type.
;; These must match the values for enum processor_type in sparc.h.
(define_attr "cpu"
@@ -74,31 +94,25 @@
sparclet,tsc701,
v9,
ultrasparc,
- ultrasparc3"
+ ultrasparc3,
+ niagara"
(const (symbol_ref "sparc_cpu_attr")))
;; Attribute for the instruction set.
;; At present we only need to distinguish v9/!v9, but for clarity we
;; test TARGET_V8 too.
-(define_attr "isa" "v6,v8,v9,sparclet"
+(define_attr "isa" "v7,v8,v9,sparclet"
(const
(cond [(symbol_ref "TARGET_V9") (const_string "v9")
(symbol_ref "TARGET_V8") (const_string "v8")
(symbol_ref "TARGET_SPARCLET") (const_string "sparclet")]
- (const_string "v6"))))
-
-;; Architecture size.
-(define_attr "arch" "arch32bit,arch64bit"
- (const
- (cond [(symbol_ref "TARGET_ARCH64") (const_string "arch64bit")]
- (const_string "arch32bit"))))
+ (const_string "v7"))))
;; Insn type.
-
(define_attr "type"
"ialu,compare,shift,
load,sload,store,
- uncond_branch,branch,call,sibcall,call_no_delay_slot,
+ uncond_branch,branch,call,sibcall,call_no_delay_slot,return,
imul,idiv,
fpload,fpstore,
fp,fpmove,
@@ -109,34 +123,49 @@
fga,fgm_pack,fgm_mul,fgm_pdist,fgm_cmp,
cmove,
ialuX,
- multi,flushw,iflush,trap"
+ multi,savew,flushw,iflush,trap"
(const_string "ialu"))
-;; true if branch/call has empty delay slot and will emit a nop in it
+;; True if branch/call has empty delay slot and will emit a nop in it
(define_attr "empty_delay_slot" "false,true"
(symbol_ref "empty_delay_slot (insn)"))
-(define_attr "branch_type" "none,icc,fcc,reg" (const_string "none"))
+(define_attr "branch_type" "none,icc,fcc,reg"
+ (const_string "none"))
(define_attr "pic" "false,true"
(symbol_ref "flag_pic != 0"))
-(define_attr "current_function_calls_alloca" "false,true"
+(define_attr "calls_alloca" "false,true"
(symbol_ref "current_function_calls_alloca != 0"))
-(define_attr "flat" "false,true"
- (symbol_ref "TARGET_FLAT != 0"))
+(define_attr "calls_eh_return" "false,true"
+ (symbol_ref "current_function_calls_eh_return !=0 "))
+
+(define_attr "leaf_function" "false,true"
+ (symbol_ref "current_function_uses_only_leaf_regs != 0"))
+
+(define_attr "delayed_branch" "false,true"
+ (symbol_ref "flag_delayed_branch != 0"))
;; Length (in # of insns).
;; Beware that setting a length greater or equal to 3 for conditional branches
;; has a side-effect (see output_cbranch and output_v9branch).
(define_attr "length" ""
- (cond [(eq_attr "type" "uncond_branch,call,sibcall")
+ (cond [(eq_attr "type" "uncond_branch,call")
(if_then_else (eq_attr "empty_delay_slot" "true")
(const_int 2)
(const_int 1))
+ (eq_attr "type" "sibcall")
+ (if_then_else (eq_attr "leaf_function" "true")
+ (if_then_else (eq_attr "empty_delay_slot" "true")
+ (const_int 3)
+ (const_int 2))
+ (if_then_else (eq_attr "empty_delay_slot" "true")
+ (const_int 2)
+ (const_int 1)))
(eq_attr "branch_type" "icc")
- (if_then_else (match_operand 0 "noov_compare64_op" "")
+ (if_then_else (match_operand 0 "noov_compare64_operator" "")
(if_then_else (lt (pc) (match_dup 1))
(if_then_else (lt (minus (match_dup 1) (pc)) (const_int 260000))
(if_then_else (eq_attr "empty_delay_slot" "true")
@@ -156,7 +185,7 @@
(const_int 2)
(const_int 1)))
(eq_attr "branch_type" "fcc")
- (if_then_else (match_operand 0 "fcc0_reg_operand" "")
+ (if_then_else (match_operand 0 "fcc0_register_operand" "")
(if_then_else (eq_attr "empty_delay_slot" "true")
(if_then_else (eq (symbol_ref "TARGET_V9") (const_int 0))
(const_int 3)
@@ -198,17 +227,18 @@
] (const_int 1)))
;; FP precision.
-(define_attr "fptype" "single,double" (const_string "single"))
+(define_attr "fptype" "single,double"
+ (const_string "single"))
;; UltraSPARC-III integer load type.
-(define_attr "us3load_type" "2cycle,3cycle" (const_string "2cycle"))
+(define_attr "us3load_type" "2cycle,3cycle"
+ (const_string "2cycle"))
(define_asm_attributes
[(set_attr "length" "2")
(set_attr "type" "multi")])
;; Attributes for instruction and branch scheduling
-
(define_attr "tls_call_delay" "false,true"
(symbol_ref "tls_call_delay (insn)"))
@@ -224,19 +254,13 @@
(const_string "true")
(const_string "false"))))
-(define_delay (eq_attr "type" "call")
- [(eq_attr "in_call_delay" "true") (nil) (nil)])
-
(define_attr "eligible_for_sibcall_delay" "false,true"
(symbol_ref "eligible_for_sibcall_delay (insn)"))
-(define_delay (eq_attr "type" "sibcall")
- [(eq_attr "eligible_for_sibcall_delay" "true") (nil) (nil)])
-
-(define_attr "leaf_function" "false,true"
- (const (symbol_ref "current_function_uses_only_leaf_regs")))
+(define_attr "eligible_for_return_delay" "false,true"
+ (symbol_ref "eligible_for_return_delay (insn)"))
-;; ??? Should implement the notion of predelay slots for floating point
+;; ??? !v9: Should implement the notion of predelay slots for floating-point
;; branches. This would allow us to remove the nop always inserted before
;; a floating point branch.
@@ -266,6 +290,12 @@
(const_string "true")
(const_string "false")))
+(define_delay (eq_attr "type" "call")
+ [(eq_attr "in_call_delay" "true") (nil) (nil)])
+
+(define_delay (eq_attr "type" "sibcall")
+ [(eq_attr "eligible_for_sibcall_delay" "true") (nil) (nil)])
+
(define_delay (eq_attr "type" "branch")
[(eq_attr "in_branch_delay" "true")
(nil) (eq_attr "in_annul_branch_delay" "true")])
@@ -273,7 +303,11 @@
(define_delay (eq_attr "type" "uncond_branch")
[(eq_attr "in_uncond_branch_delay" "true")
(nil) (nil)])
-
+
+(define_delay (eq_attr "type" "return")
+ [(eq_attr "eligible_for_return_delay" "true") (nil) (nil)])
+
+
;; Include SPARC DFA schedulers
(include "cypress.md")
@@ -282,10 +316,15 @@
(include "sparclet.md")
(include "ultra1_2.md")
(include "ultra3.md")
+(include "niagara.md")
+
+
+;; Operand and operator predicates.
+
+(include "predicates.md")
+
-
;; Compare instructions.
-;; This controls RTL generation and register allocation.
;; We generate RTL for comparisons and branches by having the cmpxx
;; patterns store away the operands. Then, the scc and bcc patterns
@@ -300,8 +339,6 @@
;; the patterns. Finally, we have the DEFINE_SPLITs for some of the scc
;; insns that actually require more than one machine instruction.
-;; Put cmpsi first among compare insns so it matches two CONST_INT operands.
-
(define_expand "cmpsi"
[(set (reg:CC 100)
(compare:CC (match_operand:SI 0 "compare_operand" "")
@@ -319,7 +356,7 @@
(define_expand "cmpdi"
[(set (reg:CCX 100)
(compare:CCX (match_operand:DI 0 "compare_operand" "")
- (match_operand:DI 1 "arith_double_operand" "")))]
+ (match_operand:DI 1 "arith_operand" "")))]
"TARGET_ARCH64"
{
if (GET_CODE (operands[0]) == ZERO_EXTRACT && operands[1] != const0_rtx)
@@ -379,13 +416,13 @@
(define_insn "*cmpdi_sp64"
[(set (reg:CCX 100)
(compare:CCX (match_operand:DI 0 "register_operand" "r")
- (match_operand:DI 1 "arith_double_operand" "rHI")))]
+ (match_operand:DI 1 "arith_operand" "rI")))]
"TARGET_ARCH64"
"cmp\t%0, %1"
[(set_attr "type" "compare")])
(define_insn "*cmpsf_fpe"
- [(set (match_operand:CCFPE 0 "fcc_reg_operand" "=c")
+ [(set (match_operand:CCFPE 0 "fcc_register_operand" "=c")
(compare:CCFPE (match_operand:SF 1 "register_operand" "f")
(match_operand:SF 2 "register_operand" "f")))]
"TARGET_FPU"
@@ -397,7 +434,7 @@
[(set_attr "type" "fpcmp")])
(define_insn "*cmpdf_fpe"
- [(set (match_operand:CCFPE 0 "fcc_reg_operand" "=c")
+ [(set (match_operand:CCFPE 0 "fcc_register_operand" "=c")
(compare:CCFPE (match_operand:DF 1 "register_operand" "e")
(match_operand:DF 2 "register_operand" "e")))]
"TARGET_FPU"
@@ -410,7 +447,7 @@
(set_attr "fptype" "double")])
(define_insn "*cmptf_fpe"
- [(set (match_operand:CCFPE 0 "fcc_reg_operand" "=c")
+ [(set (match_operand:CCFPE 0 "fcc_register_operand" "=c")
(compare:CCFPE (match_operand:TF 1 "register_operand" "e")
(match_operand:TF 2 "register_operand" "e")))]
"TARGET_FPU && TARGET_HARD_QUAD"
@@ -422,7 +459,7 @@
[(set_attr "type" "fpcmp")])
(define_insn "*cmpsf_fp"
- [(set (match_operand:CCFP 0 "fcc_reg_operand" "=c")
+ [(set (match_operand:CCFP 0 "fcc_register_operand" "=c")
(compare:CCFP (match_operand:SF 1 "register_operand" "f")
(match_operand:SF 2 "register_operand" "f")))]
"TARGET_FPU"
@@ -434,7 +471,7 @@
[(set_attr "type" "fpcmp")])
(define_insn "*cmpdf_fp"
- [(set (match_operand:CCFP 0 "fcc_reg_operand" "=c")
+ [(set (match_operand:CCFP 0 "fcc_register_operand" "=c")
(compare:CCFP (match_operand:DF 1 "register_operand" "e")
(match_operand:DF 2 "register_operand" "e")))]
"TARGET_FPU"
@@ -447,7 +484,7 @@
(set_attr "fptype" "double")])
(define_insn "*cmptf_fp"
- [(set (match_operand:CCFP 0 "fcc_reg_operand" "=c")
+ [(set (match_operand:CCFP 0 "fcc_register_operand" "=c")
(compare:CCFP (match_operand:TF 1 "register_operand" "e")
(match_operand:TF 2 "register_operand" "e")))]
"TARGET_FPU && TARGET_HARD_QUAD"
@@ -547,7 +584,7 @@
;; ??? v9: Operand 0 needs a mode, so SImode was chosen.
;; However, the code handles both SImode and DImode.
(define_expand "seq"
- [(set (match_operand:SI 0 "intreg_operand" "")
+ [(set (match_operand:SI 0 "int_register_operand" "")
(eq:SI (match_dup 1) (const_int 0)))]
""
{
@@ -599,7 +636,7 @@
;; ??? v9: Operand 0 needs a mode, so SImode was chosen.
;; However, the code handles both SImode and DImode.
(define_expand "sne"
- [(set (match_operand:SI 0 "intreg_operand" "")
+ [(set (match_operand:SI 0 "int_register_operand" "")
(ne:SI (match_dup 1) (const_int 0)))]
""
{
@@ -649,7 +686,7 @@
})
(define_expand "sgt"
- [(set (match_operand:SI 0 "intreg_operand" "")
+ [(set (match_operand:SI 0 "int_register_operand" "")
(gt:SI (match_dup 1) (const_int 0)))]
""
{
@@ -669,7 +706,7 @@
})
(define_expand "slt"
- [(set (match_operand:SI 0 "intreg_operand" "")
+ [(set (match_operand:SI 0 "int_register_operand" "")
(lt:SI (match_dup 1) (const_int 0)))]
""
{
@@ -689,7 +726,7 @@
})
(define_expand "sge"
- [(set (match_operand:SI 0 "intreg_operand" "")
+ [(set (match_operand:SI 0 "int_register_operand" "")
(ge:SI (match_dup 1) (const_int 0)))]
""
{
@@ -709,7 +746,7 @@
})
(define_expand "sle"
- [(set (match_operand:SI 0 "intreg_operand" "")
+ [(set (match_operand:SI 0 "int_register_operand" "")
(le:SI (match_dup 1) (const_int 0)))]
""
{
@@ -729,7 +766,7 @@
})
(define_expand "sgtu"
- [(set (match_operand:SI 0 "intreg_operand" "")
+ [(set (match_operand:SI 0 "int_register_operand" "")
(gtu:SI (match_dup 1) (const_int 0)))]
""
{
@@ -763,7 +800,7 @@
})
(define_expand "sltu"
- [(set (match_operand:SI 0 "intreg_operand" "")
+ [(set (match_operand:SI 0 "int_register_operand" "")
(ltu:SI (match_dup 1) (const_int 0)))]
""
{
@@ -772,11 +809,11 @@
if (gen_v9_scc (LTU, operands))
DONE;
}
- operands[1] = gen_compare_reg (LTU, sparc_compare_op0, sparc_compare_op1);
+ operands[1] = gen_compare_reg (LTU);
})
(define_expand "sgeu"
- [(set (match_operand:SI 0 "intreg_operand" "")
+ [(set (match_operand:SI 0 "int_register_operand" "")
(geu:SI (match_dup 1) (const_int 0)))]
""
{
@@ -785,11 +822,11 @@
if (gen_v9_scc (GEU, operands))
DONE;
}
- operands[1] = gen_compare_reg (GEU, sparc_compare_op0, sparc_compare_op1);
+ operands[1] = gen_compare_reg (GEU);
})
(define_expand "sleu"
- [(set (match_operand:SI 0 "intreg_operand" "")
+ [(set (match_operand:SI 0 "int_register_operand" "")
(leu:SI (match_dup 1) (const_int 0)))]
""
{
@@ -826,7 +863,7 @@
;; The SEQ and SNE patterns are special because they can be done
;; without any branching and do not involve a COMPARE. We want
-;; them to always use the splitz below so the results can be
+;; them to always use the splits below so the results can be
;; scheduled.
(define_insn_and_split "*snesi_zero"
@@ -1160,7 +1197,7 @@
;; ??? Combine should canonicalize these next two to the same pattern.
(define_insn "*x_minus_y_minus_sltu"
[(set (match_operand:SI 0 "register_operand" "=r")
- (minus:SI (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rJ")
+ (minus:SI (minus:SI (match_operand:SI 1 "register_or_zero_operand" "rJ")
(match_operand:SI 2 "arith_operand" "rI"))
(ltu:SI (reg:CC 100) (const_int 0))))]
""
@@ -1169,7 +1206,7 @@
(define_insn "*x_minus_sltu_plus_y"
[(set (match_operand:SI 0 "register_operand" "=r")
- (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rJ")
+ (minus:SI (match_operand:SI 1 "register_or_zero_operand" "rJ")
(plus:SI (ltu:SI (reg:CC 100) (const_int 0))
(match_operand:SI 2 "arith_operand" "rI"))))]
""
@@ -1194,12 +1231,13 @@
(define_split
[(set (match_operand:SI 0 "register_operand" "")
- (match_operator:SI 2 "noov_compare_op"
- [(match_operand 1 "icc_or_fcc_reg_operand" "")
+ (match_operator:SI 2 "noov_compare_operator"
+ [(match_operand 1 "icc_or_fcc_register_operand" "")
(const_int 0)]))]
- ;; 32 bit LTU/GEU are better implemented using addx/subx
- "TARGET_V9 && REGNO (operands[1]) == SPARC_ICC_REG
+ "TARGET_V9
+ && REGNO (operands[1]) == SPARC_ICC_REG
&& (GET_MODE (operands[1]) == CCXmode
+ /* 32 bit LTU/GEU are better implemented using addx/subx. */
|| (GET_CODE (operands[2]) != LTU && GET_CODE (operands[2]) != GEU))"
[(set (match_dup 0) (const_int 0))
(set (match_dup 0)
@@ -1235,7 +1273,7 @@
emit_jump_insn (gen_bne (operands[0]));
DONE;
}
- operands[1] = gen_compare_reg (EQ, sparc_compare_op0, sparc_compare_op1);
+ operands[1] = gen_compare_reg (EQ);
})
(define_expand "bne"
@@ -1258,7 +1296,7 @@
emit_jump_insn (gen_bne (operands[0]));
DONE;
}
- operands[1] = gen_compare_reg (NE, sparc_compare_op0, sparc_compare_op1);
+ operands[1] = gen_compare_reg (NE);
})
(define_expand "bgt"
@@ -1281,7 +1319,7 @@
emit_jump_insn (gen_bne (operands[0]));
DONE;
}
- operands[1] = gen_compare_reg (GT, sparc_compare_op0, sparc_compare_op1);
+ operands[1] = gen_compare_reg (GT);
})
(define_expand "bgtu"
@@ -1291,7 +1329,7 @@
(pc)))]
""
{
- operands[1] = gen_compare_reg (GTU, sparc_compare_op0, sparc_compare_op1);
+ operands[1] = gen_compare_reg (GTU);
})
(define_expand "blt"
@@ -1314,7 +1352,7 @@
emit_jump_insn (gen_bne (operands[0]));
DONE;
}
- operands[1] = gen_compare_reg (LT, sparc_compare_op0, sparc_compare_op1);
+ operands[1] = gen_compare_reg (LT);
})
(define_expand "bltu"
@@ -1324,7 +1362,7 @@
(pc)))]
""
{
- operands[1] = gen_compare_reg (LTU, sparc_compare_op0, sparc_compare_op1);
+ operands[1] = gen_compare_reg (LTU);
})
(define_expand "bge"
@@ -1347,7 +1385,7 @@
emit_jump_insn (gen_bne (operands[0]));
DONE;
}
- operands[1] = gen_compare_reg (GE, sparc_compare_op0, sparc_compare_op1);
+ operands[1] = gen_compare_reg (GE);
})
(define_expand "bgeu"
@@ -1357,7 +1395,7 @@
(pc)))]
""
{
- operands[1] = gen_compare_reg (GEU, sparc_compare_op0, sparc_compare_op1);
+ operands[1] = gen_compare_reg (GEU);
})
(define_expand "ble"
@@ -1380,7 +1418,7 @@
emit_jump_insn (gen_bne (operands[0]));
DONE;
}
- operands[1] = gen_compare_reg (LE, sparc_compare_op0, sparc_compare_op1);
+ operands[1] = gen_compare_reg (LE);
})
(define_expand "bleu"
@@ -1390,7 +1428,7 @@
(pc)))]
""
{
- operands[1] = gen_compare_reg (LEU, sparc_compare_op0, sparc_compare_op1);
+ operands[1] = gen_compare_reg (LEU);
})
(define_expand "bunordered"
@@ -1407,8 +1445,7 @@
emit_jump_insn (gen_beq (operands[0]));
DONE;
}
- operands[1] = gen_compare_reg (UNORDERED, sparc_compare_op0,
- sparc_compare_op1);
+ operands[1] = gen_compare_reg (UNORDERED);
})
(define_expand "bordered"
@@ -1424,8 +1461,7 @@
emit_jump_insn (gen_bne (operands[0]));
DONE;
}
- operands[1] = gen_compare_reg (ORDERED, sparc_compare_op0,
- sparc_compare_op1);
+ operands[1] = gen_compare_reg (ORDERED);
})
(define_expand "bungt"
@@ -1441,7 +1477,7 @@
emit_jump_insn (gen_bgt (operands[0]));
DONE;
}
- operands[1] = gen_compare_reg (UNGT, sparc_compare_op0, sparc_compare_op1);
+ operands[1] = gen_compare_reg (UNGT);
})
(define_expand "bunlt"
@@ -1457,7 +1493,7 @@
emit_jump_insn (gen_bne (operands[0]));
DONE;
}
- operands[1] = gen_compare_reg (UNLT, sparc_compare_op0, sparc_compare_op1);
+ operands[1] = gen_compare_reg (UNLT);
})
(define_expand "buneq"
@@ -1473,7 +1509,7 @@
emit_jump_insn (gen_beq (operands[0]));
DONE;
}
- operands[1] = gen_compare_reg (UNEQ, sparc_compare_op0, sparc_compare_op1);
+ operands[1] = gen_compare_reg (UNEQ);
})
(define_expand "bunge"
@@ -1489,7 +1525,7 @@
emit_jump_insn (gen_bne (operands[0]));
DONE;
}
- operands[1] = gen_compare_reg (UNGE, sparc_compare_op0, sparc_compare_op1);
+ operands[1] = gen_compare_reg (UNGE);
})
(define_expand "bunle"
@@ -1505,7 +1541,7 @@
emit_jump_insn (gen_bne (operands[0]));
DONE;
}
- operands[1] = gen_compare_reg (UNLE, sparc_compare_op0, sparc_compare_op1);
+ operands[1] = gen_compare_reg (UNLE);
})
(define_expand "bltgt"
@@ -1521,7 +1557,7 @@
emit_jump_insn (gen_bne (operands[0]));
DONE;
}
- operands[1] = gen_compare_reg (LTGT, sparc_compare_op0, sparc_compare_op1);
+ operands[1] = gen_compare_reg (LTGT);
})
;; Now match both normal and inverted jump.
@@ -1529,7 +1565,7 @@
;; XXX fpcmp nop braindamage
(define_insn "*normal_branch"
[(set (pc)
- (if_then_else (match_operator 0 "noov_compare_op"
+ (if_then_else (match_operator 0 "noov_compare_operator"
[(reg 100) (const_int 0)])
(label_ref (match_operand 1 "" ""))
(pc)))]
@@ -1537,7 +1573,7 @@
{
return output_cbranch (operands[0], operands[1], 1, 0,
final_sequence && INSN_ANNULLED_BRANCH_P (insn),
- ! final_sequence, insn);
+ insn);
}
[(set_attr "type" "branch")
(set_attr "branch_type" "icc")])
@@ -1545,7 +1581,7 @@
;; XXX fpcmp nop braindamage
(define_insn "*inverted_branch"
[(set (pc)
- (if_then_else (match_operator 0 "noov_compare_op"
+ (if_then_else (match_operator 0 "noov_compare_operator"
[(reg 100) (const_int 0)])
(pc)
(label_ref (match_operand 1 "" ""))))]
@@ -1553,7 +1589,7 @@
{
return output_cbranch (operands[0], operands[1], 1, 1,
final_sequence && INSN_ANNULLED_BRANCH_P (insn),
- ! final_sequence, insn);
+ insn);
}
[(set_attr "type" "branch")
(set_attr "branch_type" "icc")])
@@ -1562,7 +1598,7 @@
(define_insn "*normal_fp_branch"
[(set (pc)
(if_then_else (match_operator 1 "comparison_operator"
- [(match_operand:CCFP 0 "fcc_reg_operand" "c")
+ [(match_operand:CCFP 0 "fcc_register_operand" "c")
(const_int 0)])
(label_ref (match_operand 2 "" ""))
(pc)))]
@@ -1570,7 +1606,7 @@
{
return output_cbranch (operands[1], operands[2], 2, 0,
final_sequence && INSN_ANNULLED_BRANCH_P (insn),
- ! final_sequence, insn);
+ insn);
}
[(set_attr "type" "branch")
(set_attr "branch_type" "fcc")])
@@ -1579,7 +1615,7 @@
(define_insn "*inverted_fp_branch"
[(set (pc)
(if_then_else (match_operator 1 "comparison_operator"
- [(match_operand:CCFP 0 "fcc_reg_operand" "c")
+ [(match_operand:CCFP 0 "fcc_register_operand" "c")
(const_int 0)])
(pc)
(label_ref (match_operand 2 "" ""))))]
@@ -1587,7 +1623,7 @@
{
return output_cbranch (operands[1], operands[2], 2, 1,
final_sequence && INSN_ANNULLED_BRANCH_P (insn),
- ! final_sequence, insn);
+ insn);
}
[(set_attr "type" "branch")
(set_attr "branch_type" "fcc")])
@@ -1596,7 +1632,7 @@
(define_insn "*normal_fpe_branch"
[(set (pc)
(if_then_else (match_operator 1 "comparison_operator"
- [(match_operand:CCFPE 0 "fcc_reg_operand" "c")
+ [(match_operand:CCFPE 0 "fcc_register_operand" "c")
(const_int 0)])
(label_ref (match_operand 2 "" ""))
(pc)))]
@@ -1604,7 +1640,7 @@
{
return output_cbranch (operands[1], operands[2], 2, 0,
final_sequence && INSN_ANNULLED_BRANCH_P (insn),
- ! final_sequence, insn);
+ insn);
}
[(set_attr "type" "branch")
(set_attr "branch_type" "fcc")])
@@ -1613,7 +1649,7 @@
(define_insn "*inverted_fpe_branch"
[(set (pc)
(if_then_else (match_operator 1 "comparison_operator"
- [(match_operand:CCFPE 0 "fcc_reg_operand" "c")
+ [(match_operand:CCFPE 0 "fcc_register_operand" "c")
(const_int 0)])
(pc)
(label_ref (match_operand 2 "" ""))))]
@@ -1621,7 +1657,7 @@
{
return output_cbranch (operands[1], operands[2], 2, 1,
final_sequence && INSN_ANNULLED_BRANCH_P (insn),
- ! final_sequence, insn);
+ insn);
}
[(set_attr "type" "branch")
(set_attr "branch_type" "fcc")])
@@ -1634,7 +1670,7 @@
;; XXX
(define_insn "*normal_int_branch_sp64"
[(set (pc)
- (if_then_else (match_operator 0 "v9_regcmp_op"
+ (if_then_else (match_operator 0 "v9_register_compare_operator"
[(match_operand:DI 1 "register_operand" "r")
(const_int 0)])
(label_ref (match_operand 2 "" ""))
@@ -1643,7 +1679,7 @@
{
return output_v9branch (operands[0], operands[2], 1, 2, 0,
final_sequence && INSN_ANNULLED_BRANCH_P (insn),
- ! final_sequence, insn);
+ insn);
}
[(set_attr "type" "branch")
(set_attr "branch_type" "reg")])
@@ -1651,7 +1687,7 @@
;; XXX
(define_insn "*inverted_int_branch_sp64"
[(set (pc)
- (if_then_else (match_operator 0 "v9_regcmp_op"
+ (if_then_else (match_operator 0 "v9_register_compare_operator"
[(match_operand:DI 1 "register_operand" "r")
(const_int 0)])
(pc)
@@ -1660,84 +1696,53 @@
{
return output_v9branch (operands[0], operands[2], 1, 2, 1,
final_sequence && INSN_ANNULLED_BRANCH_P (insn),
- ! final_sequence, insn);
+ insn);
}
[(set_attr "type" "branch")
(set_attr "branch_type" "reg")])
-
-;; Load program counter insns.
-
-(define_insn "get_pc"
- [(clobber (reg:SI 15))
- (set (match_operand 0 "register_operand" "=r")
- (unspec [(match_operand 1 "" "") (match_operand 2 "" "")] UNSPEC_GET_PC))]
- "flag_pic && REGNO (operands[0]) == 23"
- "sethi\t%%hi(%a1-4), %0\n\tcall\t%a2\n\tadd\t%0, %%lo(%a1+4), %0"
- [(set_attr "type" "multi")
- (set_attr "length" "3")])
-
-
-;; Move instructions
-
-(define_expand "movqi"
- [(set (match_operand:QI 0 "general_operand" "")
- (match_operand:QI 1 "general_operand" ""))]
- ""
-{
- /* Working with CONST_INTs is easier, so convert
- a double if needed. */
- if (GET_CODE (operands[1]) == CONST_DOUBLE)
- {
- operands[1] = GEN_INT (trunc_int_for_mode
- (CONST_DOUBLE_LOW (operands[1]), QImode));
- }
- /* Handle sets of MEM first. */
- if (GET_CODE (operands[0]) == MEM)
- {
- if (reg_or_0_operand (operands[1], QImode))
- goto movqi_is_ok;
- if (! reload_in_progress)
- {
- operands[0] = validize_mem (operands[0]);
- operands[1] = force_reg (QImode, operands[1]);
- }
- }
+(define_mode_macro P [(SI "Pmode == SImode") (DI "Pmode == DImode")])
- /* Fixup TLS cases. */
- if (tls_symbolic_operand (operands [1]))
- operands[1] = legitimize_tls_address (operands[1]);
+;; Load in operand 0 the (absolute) address of operand 1, which is a symbolic
+;; value subject to a PC-relative relocation. Operand 2 is a helper function
+;; that adds the PC value at the call point to operand 0.
- /* Fixup PIC cases. */
- if (flag_pic)
- {
- if (CONSTANT_P (operands[1])
- && pic_address_needs_scratch (operands[1]))
- operands[1] = legitimize_pic_address (operands[1], QImode, 0);
+(define_insn "load_pcrel_sym<P:mode>"
+ [(set (match_operand:P 0 "register_operand" "=r")
+ (unspec:P [(match_operand:P 1 "symbolic_operand" "")
+ (match_operand:P 2 "call_address_operand" "")] UNSPEC_LOAD_PCREL_SYM))
+ (clobber (reg:P 15))]
+ ""
+{
+ if (flag_delayed_branch)
+ return "sethi\t%%hi(%a1-4), %0\n\tcall\t%a2\n\t add\t%0, %%lo(%a1+4), %0";
+ else
+ return "sethi\t%%hi(%a1-8), %0\n\tadd\t%0, %%lo(%a1-4), %0\n\tcall\t%a2\n\t nop";
+}
+ [(set (attr "type") (const_string "multi"))
+ (set (attr "length")
+ (if_then_else (eq_attr "delayed_branch" "true")
+ (const_int 3)
+ (const_int 4)))])
- if (symbolic_operand (operands[1], QImode))
- {
- operands[1] = legitimize_pic_address (operands[1],
- QImode,
- (reload_in_progress ?
- operands[0] :
- NULL_RTX));
- goto movqi_is_ok;
- }
- }
- /* All QI constants require only one insn, so proceed. */
+;; Integer move instructions
- movqi_is_ok:
- ;
+(define_expand "movqi"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "")
+ (match_operand:QI 1 "general_operand" ""))]
+ ""
+{
+ if (sparc_expand_move (QImode, operands))
+ DONE;
})
(define_insn "*movqi_insn"
[(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,m")
(match_operand:QI 1 "input_operand" "rI,m,rJ"))]
"(register_operand (operands[0], QImode)
- || reg_or_0_operand (operands[1], QImode))"
+ || register_or_zero_operand (operands[1], QImode))"
"@
mov\t%1, %0
ldub\t%1, %0
@@ -1746,75 +1751,19 @@
(set_attr "us3load_type" "*,3cycle,*")])
(define_expand "movhi"
- [(set (match_operand:HI 0 "general_operand" "")
+ [(set (match_operand:HI 0 "nonimmediate_operand" "")
(match_operand:HI 1 "general_operand" ""))]
""
{
- /* Working with CONST_INTs is easier, so convert
- a double if needed. */
- if (GET_CODE (operands[1]) == CONST_DOUBLE)
- operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
-
- /* Handle sets of MEM first. */
- if (GET_CODE (operands[0]) == MEM)
- {
- if (reg_or_0_operand (operands[1], HImode))
- goto movhi_is_ok;
-
- if (! reload_in_progress)
- {
- operands[0] = validize_mem (operands[0]);
- operands[1] = force_reg (HImode, operands[1]);
- }
- }
-
- /* Fixup TLS cases. */
- if (tls_symbolic_operand (operands [1]))
- operands[1] = legitimize_tls_address (operands[1]);
-
- /* Fixup PIC cases. */
- if (flag_pic)
- {
- if (CONSTANT_P (operands[1])
- && pic_address_needs_scratch (operands[1]))
- operands[1] = legitimize_pic_address (operands[1], HImode, 0);
-
- if (symbolic_operand (operands[1], HImode))
- {
- operands[1] = legitimize_pic_address (operands[1],
- HImode,
- (reload_in_progress ?
- operands[0] :
- NULL_RTX));
- goto movhi_is_ok;
- }
- }
-
- /* This makes sure we will not get rematched due to splittage. */
- if (! CONSTANT_P (operands[1]) || input_operand (operands[1], HImode))
- ;
- else if (CONSTANT_P (operands[1])
- && GET_CODE (operands[1]) != HIGH
- && GET_CODE (operands[1]) != LO_SUM)
- {
- sparc_emit_set_const32 (operands[0], operands[1]);
- DONE;
- }
- movhi_is_ok:
- ;
+ if (sparc_expand_move (HImode, operands))
+ DONE;
})
-(define_insn "*movhi_const64_special"
- [(set (match_operand:HI 0 "register_operand" "=r")
- (match_operand:HI 1 "const64_high_operand" ""))]
- "TARGET_ARCH64"
- "sethi\t%%hi(%a1), %0")
-
(define_insn "*movhi_insn"
[(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,m")
(match_operand:HI 1 "input_operand" "rI,K,m,rJ"))]
"(register_operand (operands[0], HImode)
- || reg_or_0_operand (operands[1], HImode))"
+ || register_or_zero_operand (operands[1], HImode))"
"@
mov\t%1, %0
sethi\t%%hi(%a1), %0
@@ -1827,109 +1776,34 @@
(define_insn "*movhi_lo_sum"
[(set (match_operand:HI 0 "register_operand" "=r")
(ior:HI (match_operand:HI 1 "register_operand" "%r")
- (match_operand:HI 2 "small_int" "I")))]
+ (match_operand:HI 2 "small_int_operand" "I")))]
""
"or\t%1, %2, %0")
(define_expand "movsi"
- [(set (match_operand:SI 0 "general_operand" "")
+ [(set (match_operand:SI 0 "nonimmediate_operand" "")
(match_operand:SI 1 "general_operand" ""))]
""
{
- /* Working with CONST_INTs is easier, so convert
- a double if needed. */
- if (GET_CODE (operands[1]) == CONST_DOUBLE)
- operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
-
- /* Handle sets of MEM first. */
- if (GET_CODE (operands[0]) == MEM)
- {
- if (reg_or_0_operand (operands[1], SImode))
- goto movsi_is_ok;
-
- if (! reload_in_progress)
- {
- operands[0] = validize_mem (operands[0]);
- operands[1] = force_reg (SImode, operands[1]);
- }
- }
-
- /* Fixup TLS cases. */
- if (tls_symbolic_operand (operands [1]))
- operands[1] = legitimize_tls_address (operands[1]);
-
- /* Fixup PIC cases. */
- if (flag_pic)
- {
- if (CONSTANT_P (operands[1])
- && pic_address_needs_scratch (operands[1]))
- operands[1] = legitimize_pic_address (operands[1], SImode, 0);
-
- if (GET_CODE (operands[1]) == LABEL_REF)
- {
- /* shit */
- emit_insn (gen_movsi_pic_label_ref (operands[0], operands[1]));
- DONE;
- }
-
- if (symbolic_operand (operands[1], SImode))
- {
- operands[1] = legitimize_pic_address (operands[1],
- SImode,
- (reload_in_progress ?
- operands[0] :
- NULL_RTX));
- goto movsi_is_ok;
- }
- }
-
- /* If we are trying to toss an integer constant into the
- FPU registers, force it into memory. */
- if (GET_CODE (operands[0]) == REG
- && REGNO (operands[0]) >= SPARC_FIRST_FP_REG
- && REGNO (operands[0]) <= SPARC_LAST_V9_FP_REG
- && CONSTANT_P (operands[1]))
- operands[1] = validize_mem (force_const_mem (GET_MODE (operands[0]),
- operands[1]));
-
- /* This makes sure we will not get rematched due to splittage. */
- if (! CONSTANT_P (operands[1]) || input_operand (operands[1], SImode))
- ;
- else if (CONSTANT_P (operands[1])
- && GET_CODE (operands[1]) != HIGH
- && GET_CODE (operands[1]) != LO_SUM)
- {
- sparc_emit_set_const32 (operands[0], operands[1]);
- DONE;
- }
- movsi_is_ok:
- ;
+ if (sparc_expand_move (SImode, operands))
+ DONE;
})
-;; This is needed to show CSE exactly which bits are set
-;; in a 64-bit register by sethi instructions.
-(define_insn "*movsi_const64_special"
- [(set (match_operand:SI 0 "register_operand" "=r")
- (match_operand:SI 1 "const64_high_operand" ""))]
- "TARGET_ARCH64"
- "sethi\t%%hi(%a1), %0")
-
(define_insn "*movsi_insn"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=r,f,r,r,r,f,m,m,d")
- (match_operand:SI 1 "input_operand" "rI,!f,K,J,m,!m,rJ,!f,J"))]
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,m,!f,!f,!m,d")
+ (match_operand:SI 1 "input_operand" "rI,K,m,rJ,f,m,f,J"))]
"(register_operand (operands[0], SImode)
- || reg_or_0_operand (operands[1], SImode))"
+ || register_or_zero_operand (operands[1], SImode))"
"@
mov\t%1, %0
- fmovs\t%1, %0
sethi\t%%hi(%a1), %0
- clr\t%0
- ld\t%1, %0
ld\t%1, %0
st\t%r1, %0
+ fmovs\t%1, %0
+ ld\t%1, %0
st\t%1, %0
fzeros\t%0"
- [(set_attr "type" "*,fpmove,*,*,load,fpload,store,fpstore,fga")])
+ [(set_attr "type" "*,*,load,store,fpmove,fpload,fpstore,fga")])
(define_insn "*movsi_lo_sum"
[(set (match_operand:SI 0 "register_operand" "=r")
@@ -2001,90 +1875,12 @@
"or\t%1, %%lo(%a3-(%a2-.)), %0")
(define_expand "movdi"
- [(set (match_operand:DI 0 "reg_or_nonsymb_mem_operand" "")
+ [(set (match_operand:DI 0 "nonimmediate_operand" "")
(match_operand:DI 1 "general_operand" ""))]
""
{
- /* Where possible, convert CONST_DOUBLE into a CONST_INT. */
- if (GET_CODE (operands[1]) == CONST_DOUBLE
-#if HOST_BITS_PER_WIDE_INT == 32
- && ((CONST_DOUBLE_HIGH (operands[1]) == 0
- && (CONST_DOUBLE_LOW (operands[1]) & 0x80000000) == 0)
- || (CONST_DOUBLE_HIGH (operands[1]) == (HOST_WIDE_INT) 0xffffffff
- && (CONST_DOUBLE_LOW (operands[1]) & 0x80000000) != 0))
-#endif
- )
- operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
-
- /* Handle MEM cases first. */
- if (GET_CODE (operands[0]) == MEM)
- {
- /* If it's a REG, we can always do it.
- The const zero case is more complex, on v9
- we can always perform it. */
- if (register_operand (operands[1], DImode)
- || (TARGET_V9
- && (operands[1] == const0_rtx)))
- goto movdi_is_ok;
-
- if (! reload_in_progress)
- {
- operands[0] = validize_mem (operands[0]);
- operands[1] = force_reg (DImode, operands[1]);
- }
- }
-
- /* Fixup TLS cases. */
- if (tls_symbolic_operand (operands [1]))
- operands[1] = legitimize_tls_address (operands[1]);
-
- if (flag_pic)
- {
- if (CONSTANT_P (operands[1])
- && pic_address_needs_scratch (operands[1]))
- operands[1] = legitimize_pic_address (operands[1], DImode, 0);
-
- if (GET_CODE (operands[1]) == LABEL_REF)
- {
- if (! TARGET_ARCH64)
- abort ();
- emit_insn (gen_movdi_pic_label_ref (operands[0], operands[1]));
- DONE;
- }
-
- if (symbolic_operand (operands[1], DImode))
- {
- operands[1] = legitimize_pic_address (operands[1],
- DImode,
- (reload_in_progress ?
- operands[0] :
- NULL_RTX));
- goto movdi_is_ok;
- }
- }
-
- /* If we are trying to toss an integer constant into the
- FPU registers, force it into memory. */
- if (GET_CODE (operands[0]) == REG
- && REGNO (operands[0]) >= SPARC_FIRST_FP_REG
- && REGNO (operands[0]) <= SPARC_LAST_V9_FP_REG
- && CONSTANT_P (operands[1]))
- operands[1] = validize_mem (force_const_mem (GET_MODE (operands[0]),
- operands[1]));
-
- /* This makes sure we will not get rematched due to splittage. */
- if (! CONSTANT_P (operands[1]) || input_operand (operands[1], DImode))
- ;
- else if (TARGET_ARCH64
- && GET_CODE (operands[1]) != HIGH
- && GET_CODE (operands[1]) != LO_SUM)
- {
- sparc_emit_set_const64 (operands[0], operands[1]);
- DONE;
- }
-
- movdi_is_ok:
- ;
+ if (sparc_expand_move (DImode, operands))
+ DONE;
})
;; Be careful, fmovd does not exist when !v9.
@@ -2099,15 +1895,15 @@
;; (reg:DI 2 %g2))
;;
-(define_insn "*movdi_insn_sp32_v9"
+(define_insn "*movdi_insn_sp32"
[(set (match_operand:DI 0 "nonimmediate_operand"
- "=T,o,T,U,o,r,r,r,?T,?f,?f,?o,?e,?e,?W")
+ "=o,T,U,o,r,r,r,?T,?f,?f,?o,?f")
(match_operand:DI 1 "input_operand"
- " J,J,U,T,r,o,i,r, f, T, o, f, e, W, e"))]
- "! TARGET_ARCH64 && TARGET_V9
- && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
+ " J,U,T,r,o,i,r, f, T, o, f, f"))]
+ "! TARGET_V9
+ && (register_operand (operands[0], DImode)
+ || register_or_zero_operand (operands[1], DImode))"
"@
- stx\t%%g0, %0
#
std\t%1, %0
ldd\t%1, %0
@@ -2119,22 +1915,21 @@
ldd\t%1, %0
#
#
- fmovd\\t%1, %0
- ldd\\t%1, %0
- std\\t%1, %0"
- [(set_attr "type" "store,store,store,load,*,*,*,*,fpstore,fpload,*,*,fpmove,fpload,fpstore")
- (set_attr "length" "*,2,*,*,2,2,2,2,*,*,2,2,*,*,*")
- (set_attr "fptype" "*,*,*,*,*,*,*,*,*,*,*,*,double,*,*")])
+ #"
+ [(set_attr "type" "store,store,load,*,*,*,*,fpstore,fpload,*,*,*")
+ (set_attr "length" "2,*,*,2,2,2,2,*,*,2,2,2")])
-(define_insn "*movdi_insn_sp32"
+(define_insn "*movdi_insn_sp32_v9"
[(set (match_operand:DI 0 "nonimmediate_operand"
- "=o,T,U,o,r,r,r,?T,?f,?f,?o,?f")
+ "=T,o,T,U,o,r,r,r,?T,?f,?f,?o,?e,?e,?W")
(match_operand:DI 1 "input_operand"
- " J,U,T,r,o,i,r, f, T, o, f, f"))]
+ " J,J,U,T,r,o,i,r, f, T, o, f, e, W, e"))]
"! TARGET_ARCH64
+ && TARGET_V9
&& (register_operand (operands[0], DImode)
- || register_operand (operands[1], DImode))"
+ || register_or_zero_operand (operands[1], DImode))"
"@
+ stx\t%%g0, %0
#
std\t%1, %0
ldd\t%1, %0
@@ -2146,62 +1941,30 @@
ldd\t%1, %0
#
#
- #"
- [(set_attr "type" "store,store,load,*,*,*,*,fpstore,fpload,*,*,*")
- (set_attr "length" "2,*,*,2,2,2,2,*,*,2,2,2")])
-
-;; The following are generated by sparc_emit_set_const64
-(define_insn "*movdi_sp64_dbl"
- [(set (match_operand:DI 0 "register_operand" "=r")
- (match_operand:DI 1 "const64_operand" ""))]
- "(TARGET_ARCH64
- && HOST_BITS_PER_WIDE_INT != 64)"
- "mov\t%1, %0")
-
-;; This is needed to show CSE exactly which bits are set
-;; in a 64-bit register by sethi instructions.
-(define_insn "*movdi_const64_special"
- [(set (match_operand:DI 0 "register_operand" "=r")
- (match_operand:DI 1 "const64_high_operand" ""))]
- "TARGET_ARCH64"
- "sethi\t%%hi(%a1), %0")
+ fmovd\\t%1, %0
+ ldd\\t%1, %0
+ std\\t%1, %0"
+ [(set_attr "type" "store,store,store,load,*,*,*,*,fpstore,fpload,*,*,fpmove,fpload,fpstore")
+ (set_attr "length" "*,2,*,*,2,2,2,2,*,*,2,2,*,*,*")
+ (set_attr "fptype" "*,*,*,*,*,*,*,*,*,*,*,*,double,*,*")])
-(define_insn "*movdi_insn_sp64_novis"
- [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,m,?e,?e,?W")
- (match_operand:DI 1 "input_operand" "rI,N,J,m,rJ,e,W,e"))]
- "TARGET_ARCH64 && ! TARGET_VIS
+(define_insn "*movdi_insn_sp64"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,m,?e,?e,?W,b")
+ (match_operand:DI 1 "input_operand" "rI,N,m,rJ,e,W,e,J"))]
+ "TARGET_ARCH64
&& (register_operand (operands[0], DImode)
- || reg_or_0_operand (operands[1], DImode))"
+ || register_or_zero_operand (operands[1], DImode))"
"@
mov\t%1, %0
sethi\t%%hi(%a1), %0
- clr\t%0
- ldx\t%1, %0
- stx\t%r1, %0
- fmovd\t%1, %0
- ldd\t%1, %0
- std\t%1, %0"
- [(set_attr "type" "*,*,*,load,store,fpmove,fpload,fpstore")
- (set_attr "fptype" "*,*,*,*,*,double,*,*")])
-
-(define_insn "*movdi_insn_sp64_vis"
- [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,m,?e,?e,?W,b")
- (match_operand:DI 1 "input_operand" "rI,N,J,m,rJ,e,W,e,J"))]
- "TARGET_ARCH64 && TARGET_VIS &&
- (register_operand (operands[0], DImode)
- || reg_or_0_operand (operands[1], DImode))"
- "@
- mov\t%1, %0
- sethi\t%%hi(%a1), %0
- clr\t%0
ldx\t%1, %0
stx\t%r1, %0
fmovd\t%1, %0
ldd\t%1, %0
std\t%1, %0
fzero\t%0"
- [(set_attr "type" "*,*,*,load,store,fpmove,fpload,fpstore,fga")
- (set_attr "fptype" "*,*,*,*,*,double,*,*,double")])
+ [(set_attr "type" "*,*,load,store,fpmove,fpload,fpstore,fga")
+ (set_attr "fptype" "*,*,*,*,double,*,*,double")])
(define_expand "movdi_pic_label_ref"
[(set (match_dup 3) (high:DI
@@ -2262,7 +2025,7 @@
(define_insn "*sethi_di_medlow_embmedany_pic"
[(set (match_operand:DI 0 "register_operand" "=r")
- (high:DI (match_operand:DI 1 "sp64_medium_pic_operand" "")))]
+ (high:DI (match_operand:DI 1 "medium_pic_operand" "")))]
"(TARGET_CM_MEDLOW || TARGET_CM_EMBMEDANY) && check_pic (1)"
"sethi\t%%hi(%a1), %0")
@@ -2418,7 +2181,9 @@
/* Slick... but this trick loses if this subreg constant part
can be done in one insn. */
- if (low == high && (low & 0x3ff) != 0 && low + 0x1000 >= 0x2000)
+ if (low == high
+ && ! SPARC_SETHI32_P (high)
+ && ! SPARC_SIMM13_P (high))
emit_insn (gen_movsi (gen_lowpart (SImode, operands[0]),
gen_highpart (SImode, operands[0])));
else
@@ -2446,8 +2211,8 @@
/* Slick... but this trick loses if this subreg constant part
can be done in one insn. */
if (CONST_DOUBLE_LOW (operands[1]) == CONST_DOUBLE_HIGH (operands[1])
- && !(SPARC_SETHI32_P (CONST_DOUBLE_HIGH (operands[1]))
- || SPARC_SIMM13_P (CONST_DOUBLE_HIGH (operands[1]))))
+ && ! SPARC_SETHI32_P (CONST_DOUBLE_HIGH (operands[1]))
+ && ! SPARC_SIMM13_P (CONST_DOUBLE_HIGH (operands[1])))
{
emit_insn (gen_movsi (gen_lowpart (SImode, operands[0]),
gen_highpart (SImode, operands[0])));
@@ -2543,7 +2308,7 @@
(define_split
[(set (match_operand:DI 0 "memory_operand" "")
- (const_int 0))]
+ (match_operand:DI 1 "const_zero_operand" ""))]
"reload_completed
&& (! TARGET_V9
|| (! TARGET_ARCH64
@@ -2555,16 +2320,29 @@
emit_insn (gen_movsi (adjust_address (operands[0], SImode, 4), const0_rtx));
DONE;
})
-
-;; Floating point move insns
-(define_insn "*movsf_insn_novis"
- [(set (match_operand:SF 0 "nonimmediate_operand" "=f,*r,*r,*r,*r,*r,f,m,m")
- (match_operand:SF 1 "input_operand" "f,G,Q,*rR,S,m,m,f,*rG"))]
- "(TARGET_FPU && ! TARGET_VIS)
- && (register_operand (operands[0], SFmode)
- || register_operand (operands[1], SFmode)
- || fp_zero_operand (operands[1], SFmode))"
+
+;; Floating point and vector move instructions
+
+;; We don't define V1SI because SI should work just fine.
+(define_mode_macro V32 [SF V2HI V4QI])
+
+;; Yes, you guessed it right, the former movsf expander.
+(define_expand "mov<V32:mode>"
+ [(set (match_operand:V32 0 "nonimmediate_operand" "")
+ (match_operand:V32 1 "general_operand" ""))]
+ "<V32:MODE>mode == SFmode || TARGET_VIS"
+{
+ if (sparc_expand_move (<V32:MODE>mode, operands))
+ DONE;
+})
+
+(define_insn "*movsf_insn"
+ [(set (match_operand:V32 0 "nonimmediate_operand" "=d,f,*r,*r,*r,f,*r,m,m")
+ (match_operand:V32 1 "input_operand" "GY,f,*rRY,Q,S,m,m,f,*rGY"))]
+ "TARGET_FPU
+ && (register_operand (operands[0], <V32:MODE>mode)
+ || register_or_zero_operand (operands[1], <V32:MODE>mode))"
{
if (GET_CODE (operands[1]) == CONST_DOUBLE
&& (which_alternative == 2
@@ -2582,90 +2360,42 @@
switch (which_alternative)
{
case 0:
- return "fmovs\t%1, %0";
+ return "fzeros\t%0";
case 1:
- return "clr\t%0";
- case 2:
- return "sethi\t%%hi(%a1), %0";
- case 3:
- return "mov\t%1, %0";
- case 4:
- return "#";
- case 5:
- case 6:
- return "ld\t%1, %0";
- case 7:
- case 8:
- return "st\t%r1, %0";
- default:
- abort();
- }
-}
- [(set_attr "type" "fpmove,*,*,*,*,load,fpload,fpstore,store")])
-
-(define_insn "*movsf_insn_vis"
- [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,*r,*r,*r,*r,*r,f,m,m")
- (match_operand:SF 1 "input_operand" "f,G,G,Q,*rR,S,m,m,f,*rG"))]
- "(TARGET_FPU && TARGET_VIS)
- && (register_operand (operands[0], SFmode)
- || register_operand (operands[1], SFmode)
- || fp_zero_operand (operands[1], SFmode))"
-{
- if (GET_CODE (operands[1]) == CONST_DOUBLE
- && (which_alternative == 3
- || which_alternative == 4
- || which_alternative == 5))
- {
- REAL_VALUE_TYPE r;
- long i;
-
- REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
- REAL_VALUE_TO_TARGET_SINGLE (r, i);
- operands[1] = GEN_INT (i);
- }
-
- switch (which_alternative)
- {
- case 0:
return "fmovs\t%1, %0";
- case 1:
- return "fzeros\t%0";
case 2:
- return "clr\t%0";
+ return "mov\t%1, %0";
case 3:
return "sethi\t%%hi(%a1), %0";
case 4:
- return "mov\t%1, %0";
- case 5:
return "#";
+ case 5:
case 6:
- case 7:
return "ld\t%1, %0";
+ case 7:
case 8:
- case 9:
return "st\t%r1, %0";
default:
- abort();
+ gcc_unreachable ();
}
}
- [(set_attr "type" "fpmove,fga,*,*,*,*,load,fpload,fpstore,store")])
+ [(set_attr "type" "fga,fpmove,*,*,*,fpload,load,fpstore,store")])
;; Exactly the same as above, except that all `f' cases are deleted.
;; This is necessary to prevent reload from ever trying to use a `f' reg
;; when -mno-fpu.
-(define_insn "*movsf_no_f_insn"
- [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,r,r,r,m")
- (match_operand:SF 1 "input_operand" "G,Q,rR,S,m,rG"))]
+(define_insn "*movsf_insn_no_fpu"
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,r,r,m")
+ (match_operand:SF 1 "input_operand" "rR,Q,S,m,rG"))]
"! TARGET_FPU
&& (register_operand (operands[0], SFmode)
- || register_operand (operands[1], SFmode)
- || fp_zero_operand (operands[1], SFmode))"
+ || register_or_zero_operand (operands[1], SFmode))"
{
if (GET_CODE (operands[1]) == CONST_DOUBLE
- && (which_alternative == 1
- || which_alternative == 2
- || which_alternative == 3))
+ && (which_alternative == 0
+ || which_alternative == 1
+ || which_alternative == 2))
{
REAL_VALUE_TYPE r;
long i;
@@ -2678,28 +2408,28 @@
switch (which_alternative)
{
case 0:
- return "clr\t%0";
+ return "mov\t%1, %0";
case 1:
return "sethi\t%%hi(%a1), %0";
case 2:
- return "mov\t%1, %0";
- case 3:
return "#";
- case 4:
+ case 3:
return "ld\t%1, %0";
- case 5:
+ case 4:
return "st\t%r1, %0";
default:
- abort();
+ gcc_unreachable ();
}
}
- [(set_attr "type" "*,*,*,*,load,store")])
+ [(set_attr "type" "*,*,*,load,store")])
+
+;; The following 3 patterns build SFmode constants in integer registers.
(define_insn "*movsf_lo_sum"
[(set (match_operand:SF 0 "register_operand" "=r")
(lo_sum:SF (match_operand:SF 1 "register_operand" "r")
- (match_operand:SF 2 "const_double_operand" "S")))]
- "fp_high_losum_p (operands[2])"
+ (match_operand:SF 2 "fp_const_high_losum_operand" "S")))]
+ ""
{
REAL_VALUE_TYPE r;
long i;
@@ -2712,8 +2442,8 @@
(define_insn "*movsf_high"
[(set (match_operand:SF 0 "register_operand" "=r")
- (high:SF (match_operand:SF 1 "const_double_operand" "S")))]
- "fp_high_losum_p (operands[1])"
+ (high:SF (match_operand:SF 1 "fp_const_high_losum_operand" "S")))]
+ ""
{
REAL_VALUE_TYPE r;
long i;
@@ -2726,136 +2456,21 @@
(define_split
[(set (match_operand:SF 0 "register_operand" "")
- (match_operand:SF 1 "const_double_operand" ""))]
- "fp_high_losum_p (operands[1])
- && (GET_CODE (operands[0]) == REG
- && REGNO (operands[0]) < 32)"
+ (match_operand:SF 1 "fp_const_high_losum_operand" ""))]
+ "REG_P (operands[0]) && REGNO (operands[0]) < 32"
[(set (match_dup 0) (high:SF (match_dup 1)))
(set (match_dup 0) (lo_sum:SF (match_dup 0) (match_dup 1)))])
-(define_expand "movsf"
- [(set (match_operand:SF 0 "general_operand" "")
- (match_operand:SF 1 "general_operand" ""))]
- ""
-{
- /* Force SFmode constants into memory. */
- if (GET_CODE (operands[0]) == REG
- && CONSTANT_P (operands[1]))
- {
- /* emit_group_store will send such bogosity to us when it is
- not storing directly into memory. So fix this up to avoid
- crashes in output_constant_pool. */
- if (operands [1] == const0_rtx)
- operands[1] = CONST0_RTX (SFmode);
-
- if (TARGET_VIS && fp_zero_operand (operands[1], SFmode))
- goto movsf_is_ok;
-
- /* We are able to build any SF constant in integer registers
- with at most 2 instructions. */
- if (REGNO (operands[0]) < 32)
- goto movsf_is_ok;
-
- operands[1] = validize_mem (force_const_mem (GET_MODE (operands[0]),
- operands[1]));
- }
-
- /* Handle sets of MEM first. */
- if (GET_CODE (operands[0]) == MEM)
- {
- if (register_operand (operands[1], SFmode)
- || fp_zero_operand (operands[1], SFmode))
- goto movsf_is_ok;
-
- if (! reload_in_progress)
- {
- operands[0] = validize_mem (operands[0]);
- operands[1] = force_reg (SFmode, operands[1]);
- }
- }
-
- /* Fixup PIC cases. */
- if (flag_pic)
- {
- if (CONSTANT_P (operands[1])
- && pic_address_needs_scratch (operands[1]))
- operands[1] = legitimize_pic_address (operands[1], SFmode, 0);
-
- if (symbolic_operand (operands[1], SFmode))
- {
- operands[1] = legitimize_pic_address (operands[1],
- SFmode,
- (reload_in_progress ?
- operands[0] :
- NULL_RTX));
- }
- }
-
- movsf_is_ok:
- ;
-})
+(define_mode_macro V64 [DF V2SI V4HI V8QI])
-(define_expand "movdf"
- [(set (match_operand:DF 0 "general_operand" "")
- (match_operand:DF 1 "general_operand" ""))]
- ""
+;; Yes, you again guessed it right, the former movdf expander.
+(define_expand "mov<V64:mode>"
+ [(set (match_operand:V64 0 "nonimmediate_operand" "")
+ (match_operand:V64 1 "general_operand" ""))]
+ "<V64:MODE>mode == DFmode || TARGET_VIS"
{
- /* Force DFmode constants into memory. */
- if (GET_CODE (operands[0]) == REG
- && CONSTANT_P (operands[1]))
- {
- /* emit_group_store will send such bogosity to us when it is
- not storing directly into memory. So fix this up to avoid
- crashes in output_constant_pool. */
- if (operands [1] == const0_rtx)
- operands[1] = CONST0_RTX (DFmode);
-
- if ((TARGET_VIS || REGNO (operands[0]) < 32)
- && fp_zero_operand (operands[1], DFmode))
- goto movdf_is_ok;
-
- /* We are able to build any DF constant in integer registers. */
- if (REGNO (operands[0]) < 32
- && (reload_completed || reload_in_progress))
- goto movdf_is_ok;
-
- operands[1] = validize_mem (force_const_mem (GET_MODE (operands[0]),
- operands[1]));
- }
-
- /* Handle MEM cases first. */
- if (GET_CODE (operands[0]) == MEM)
- {
- if (register_operand (operands[1], DFmode)
- || fp_zero_operand (operands[1], DFmode))
- goto movdf_is_ok;
-
- if (! reload_in_progress)
- {
- operands[0] = validize_mem (operands[0]);
- operands[1] = force_reg (DFmode, operands[1]);
- }
- }
-
- /* Fixup PIC cases. */
- if (flag_pic)
- {
- if (CONSTANT_P (operands[1])
- && pic_address_needs_scratch (operands[1]))
- operands[1] = legitimize_pic_address (operands[1], DFmode, 0);
-
- if (symbolic_operand (operands[1], DFmode))
- {
- operands[1] = legitimize_pic_address (operands[1],
- DFmode,
- (reload_in_progress ?
- operands[0] :
- NULL_RTX));
- }
- }
-
- movdf_is_ok:
- ;
+ if (sparc_expand_move (<V64:MODE>mode, operands))
+ DONE;
})
;; Be careful, fmovd does not exist when !v9.
@@ -2865,8 +2480,7 @@
"TARGET_FPU
&& ! TARGET_V9
&& (register_operand (operands[0], DFmode)
- || register_operand (operands[1], DFmode)
- || fp_zero_operand (operands[1], DFmode))"
+ || register_or_zero_operand (operands[1], DFmode))"
"@
ldd\t%1, %0
std\t%1, %0
@@ -2881,15 +2495,13 @@
[(set_attr "type" "fpload,fpstore,load,store,*,*,*,*,*,*")
(set_attr "length" "*,*,*,*,2,2,2,2,2,2")])
-(define_insn "*movdf_no_e_insn_sp32"
+(define_insn "*movdf_insn_sp32_no_fpu"
[(set (match_operand:DF 0 "nonimmediate_operand" "=U,T,o,r,o")
(match_operand:DF 1 "input_operand" "T,U,G,ro,r"))]
"! TARGET_FPU
&& ! TARGET_V9
- && ! TARGET_ARCH64
&& (register_operand (operands[0], DFmode)
- || register_operand (operands[1], DFmode)
- || fp_zero_operand (operands[1], DFmode))"
+ || register_or_zero_operand (operands[1], DFmode))"
"@
ldd\t%1, %0
std\t%1, %0
@@ -2899,61 +2511,15 @@
[(set_attr "type" "load,store,*,*,*")
(set_attr "length" "*,*,2,2,2")])
-(define_insn "*movdf_no_e_insn_v9_sp32"
- [(set (match_operand:DF 0 "nonimmediate_operand" "=U,T,T,r,o")
- (match_operand:DF 1 "input_operand" "T,U,G,ro,rG"))]
- "! TARGET_FPU
- && TARGET_V9
- && ! TARGET_ARCH64
- && (register_operand (operands[0], DFmode)
- || register_operand (operands[1], DFmode)
- || fp_zero_operand (operands[1], DFmode))"
- "@
- ldd\t%1, %0
- std\t%1, %0
- stx\t%r1, %0
- #
- #"
- [(set_attr "type" "load,store,store,*,*")
- (set_attr "length" "*,*,*,2,2")])
-
-;; We have available v9 double floats but not 64-bit
-;; integer registers and no VIS.
-(define_insn "*movdf_insn_v9only_novis"
- [(set (match_operand:DF 0 "nonimmediate_operand" "=e,e,T,W,U,T,f,*r,o")
- (match_operand:DF 1 "input_operand" "e,W#F,G,e,T,U,o#F,*roF,*rGf"))]
+;; We have available v9 double floats but not 64-bit integer registers.
+(define_insn "*movdf_insn_sp32_v9"
+ [(set (match_operand:V64 0 "nonimmediate_operand" "=b,e,e,T,W,U,T,f,*r,o")
+ (match_operand:V64 1 "input_operand" "GY,e,W#F,GY,e,T,U,o#F,*roGYF,*rGYf"))]
"TARGET_FPU
&& TARGET_V9
- && ! TARGET_VIS
- && ! TARGET_ARCH64
- && (register_operand (operands[0], DFmode)
- || register_operand (operands[1], DFmode)
- || fp_zero_operand (operands[1], DFmode))"
- "@
- fmovd\t%1, %0
- ldd\t%1, %0
- stx\t%r1, %0
- std\t%1, %0
- ldd\t%1, %0
- std\t%1, %0
- #
- #
- #"
- [(set_attr "type" "fpmove,load,store,store,load,store,*,*,*")
- (set_attr "length" "*,*,*,*,*,*,2,2,2")
- (set_attr "fptype" "double,*,*,*,*,*,*,*,*")])
-
-;; We have available v9 double floats but not 64-bit
-;; integer registers but we have VIS.
-(define_insn "*movdf_insn_v9only_vis"
- [(set (match_operand:DF 0 "nonimmediate_operand" "=e,e,e,T,W,U,T,f,*r,o")
- (match_operand:DF 1 "input_operand" "G,e,W#F,G,e,T,U,o#F,*roGF,*rGf"))]
- "TARGET_FPU
- && TARGET_VIS
&& ! TARGET_ARCH64
- && (register_operand (operands[0], DFmode)
- || register_operand (operands[1], DFmode)
- || fp_zero_operand (operands[1], DFmode))"
+ && (register_operand (operands[0], <V64:MODE>mode)
+ || register_or_zero_operand (operands[1], <V64:MODE>mode))"
"@
fzero\t%0
fmovd\t%1, %0
@@ -2969,40 +2535,31 @@
(set_attr "length" "*,*,*,*,*,*,*,2,2,2")
(set_attr "fptype" "double,double,*,*,*,*,*,*,*,*")])
-;; We have available both v9 double floats and 64-bit
-;; integer registers. No VIS though.
-(define_insn "*movdf_insn_sp64_novis"
- [(set (match_operand:DF 0 "nonimmediate_operand" "=e,e,W,*r,*r,m,*r")
- (match_operand:DF 1 "input_operand" "e,W#F,e,*rG,m,*rG,F"))]
- "TARGET_FPU
- && ! TARGET_VIS
- && TARGET_ARCH64
+(define_insn "*movdf_insn_sp32_v9_no_fpu"
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=U,T,T,r,o")
+ (match_operand:DF 1 "input_operand" "T,U,G,ro,rG"))]
+ "! TARGET_FPU
+ && TARGET_V9
+ && ! TARGET_ARCH64
&& (register_operand (operands[0], DFmode)
- || register_operand (operands[1], DFmode)
- || fp_zero_operand (operands[1], DFmode))"
+ || register_or_zero_operand (operands[1], DFmode))"
"@
- fmovd\t%1, %0
ldd\t%1, %0
std\t%1, %0
- mov\t%r1, %0
- ldx\t%1, %0
stx\t%r1, %0
+ #
#"
- [(set_attr "type" "fpmove,load,store,*,load,store,*")
- (set_attr "length" "*,*,*,*,*,*,2")
- (set_attr "fptype" "double,*,*,*,*,*,*")])
-
-;; We have available both v9 double floats and 64-bit
-;; integer registers. And we have VIS.
-(define_insn "*movdf_insn_sp64_vis"
- [(set (match_operand:DF 0 "nonimmediate_operand" "=e,e,e,W,*r,*r,m,*r")
- (match_operand:DF 1 "input_operand" "G,e,W#F,e,*rG,m,*rG,F"))]
+ [(set_attr "type" "load,store,store,*,*")
+ (set_attr "length" "*,*,*,2,2")])
+
+;; We have available both v9 double floats and 64-bit integer registers.
+(define_insn "*movdf_insn_sp64"
+ [(set (match_operand:V64 0 "nonimmediate_operand" "=b,e,e,W,*r,*r,m,*r")
+ (match_operand:V64 1 "input_operand" "GY,e,W#F,e,*rGY,m,*rGY,F"))]
"TARGET_FPU
- && TARGET_VIS
&& TARGET_ARCH64
- && (register_operand (operands[0], DFmode)
- || register_operand (operands[1], DFmode)
- || fp_zero_operand (operands[1], DFmode))"
+ && (register_operand (operands[0], <V64:MODE>mode)
+ || register_or_zero_operand (operands[1], <V64:MODE>mode))"
"@
fzero\t%0
fmovd\t%1, %0
@@ -3016,27 +2573,27 @@
(set_attr "length" "*,*,*,*,*,*,*,2")
(set_attr "fptype" "double,double,*,*,*,*,*,*")])
-(define_insn "*movdf_no_e_insn_sp64"
+(define_insn "*movdf_insn_sp64_no_fpu"
[(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,m")
(match_operand:DF 1 "input_operand" "r,m,rG"))]
"! TARGET_FPU
&& TARGET_ARCH64
&& (register_operand (operands[0], DFmode)
- || register_operand (operands[1], DFmode)
- || fp_zero_operand (operands[1], DFmode))"
+ || register_or_zero_operand (operands[1], DFmode))"
"@
mov\t%1, %0
ldx\t%1, %0
stx\t%r1, %0"
[(set_attr "type" "*,load,store")])
+;; This pattern build DFmode constants in integer registers.
(define_split
[(set (match_operand:DF 0 "register_operand" "")
(match_operand:DF 1 "const_double_operand" ""))]
"TARGET_FPU
&& (GET_CODE (operands[0]) == REG
&& REGNO (operands[0]) < 32)
- && ! fp_zero_operand(operands[1], DFmode)
+ && ! const_zero_operand(operands[1], DFmode)
&& reload_completed"
[(clobber (const_int 0))]
{
@@ -3049,27 +2606,26 @@
if (TARGET_ARCH64)
{
-#if HOST_BITS_PER_WIDE_INT == 64
+#if HOST_BITS_PER_WIDE_INT == 32
+ gcc_unreachable ();
+#else
HOST_WIDE_INT val;
val = ((HOST_WIDE_INT)(unsigned long)l[1] |
((HOST_WIDE_INT)(unsigned long)l[0] << 32));
- emit_insn (gen_movdi (operands[0], GEN_INT (val)));
-#else
- emit_insn (gen_movdi (operands[0],
- immed_double_const (l[1], l[0], DImode)));
+ emit_insn (gen_movdi (operands[0], gen_int_mode (val, DImode)));
#endif
}
else
{
emit_insn (gen_movsi (gen_highpart (SImode, operands[0]),
- GEN_INT (l[0])));
+ gen_int_mode (l[0], SImode)));
/* Slick... but this trick loses if this subreg constant part
can be done in one insn. */
if (l[1] == l[0]
- && !(SPARC_SETHI32_P (l[0])
- || SPARC_SIMM13_P (l[0])))
+ && ! SPARC_SETHI32_P (l[0])
+ && ! SPARC_SIMM13_P (l[0]))
{
emit_insn (gen_movsi (gen_lowpart (SImode, operands[0]),
gen_highpart (SImode, operands[0])));
@@ -3077,7 +2633,7 @@
else
{
emit_insn (gen_movsi (gen_lowpart (SImode, operands[0]),
- GEN_INT (l[1])));
+ gen_int_mode (l[1], SImode)));
}
}
DONE;
@@ -3089,8 +2645,8 @@
;; careful when V9 but not ARCH64 because the integer
;; register DFmode cases must be handled.
(define_split
- [(set (match_operand:DF 0 "register_operand" "")
- (match_operand:DF 1 "register_operand" ""))]
+ [(set (match_operand:V64 0 "register_operand" "")
+ (match_operand:V64 1 "register_operand" ""))]
"(! TARGET_V9
|| (! TARGET_ARCH64
&& ((GET_CODE (operands[0]) == REG
@@ -3105,30 +2661,37 @@
rtx set_src = operands[1];
rtx dest1, dest2;
rtx src1, src2;
+ enum machine_mode half_mode;
- dest1 = gen_highpart (SFmode, set_dest);
- dest2 = gen_lowpart (SFmode, set_dest);
- src1 = gen_highpart (SFmode, set_src);
- src2 = gen_lowpart (SFmode, set_src);
+ /* We can be expanded for DFmode or integral vector modes. */
+ if (<V64:MODE>mode == DFmode)
+ half_mode = SFmode;
+ else
+ half_mode = SImode;
+
+ dest1 = gen_highpart (half_mode, set_dest);
+ dest2 = gen_lowpart (half_mode, set_dest);
+ src1 = gen_highpart (half_mode, set_src);
+ src2 = gen_lowpart (half_mode, set_src);
/* Now emit using the real source and destination we found, swapping
the order if we detect overlap. */
if (reg_overlap_mentioned_p (dest1, src2))
{
- emit_insn (gen_movsf (dest2, src2));
- emit_insn (gen_movsf (dest1, src1));
+ emit_move_insn_1 (dest2, src2);
+ emit_move_insn_1 (dest1, src1);
}
else
{
- emit_insn (gen_movsf (dest1, src1));
- emit_insn (gen_movsf (dest2, src2));
+ emit_move_insn_1 (dest1, src1);
+ emit_move_insn_1 (dest2, src2);
}
DONE;
})
(define_split
- [(set (match_operand:DF 0 "register_operand" "")
- (match_operand:DF 1 "memory_operand" ""))]
+ [(set (match_operand:V64 0 "register_operand" "")
+ (match_operand:V64 1 "memory_operand" ""))]
"reload_completed
&& ! TARGET_ARCH64
&& (((REGNO (operands[0]) % 2) != 0)
@@ -3136,29 +2699,34 @@
&& offsettable_memref_p (operands[1])"
[(clobber (const_int 0))]
{
- rtx word0 = adjust_address (operands[1], SFmode, 0);
- rtx word1 = adjust_address (operands[1], SFmode, 4);
+ enum machine_mode half_mode;
+ rtx word0, word1;
- if (reg_overlap_mentioned_p (gen_highpart (SFmode, operands[0]), word1))
+ /* We can be expanded for DFmode or integral vector modes. */
+ if (<V64:MODE>mode == DFmode)
+ half_mode = SFmode;
+ else
+ half_mode = SImode;
+
+ word0 = adjust_address (operands[1], half_mode, 0);
+ word1 = adjust_address (operands[1], half_mode, 4);
+
+ if (reg_overlap_mentioned_p (gen_highpart (half_mode, operands[0]), word1))
{
- emit_insn (gen_movsf (gen_lowpart (SFmode, operands[0]),
- word1));
- emit_insn (gen_movsf (gen_highpart (SFmode, operands[0]),
- word0));
+ emit_move_insn_1 (gen_lowpart (half_mode, operands[0]), word1);
+ emit_move_insn_1 (gen_highpart (half_mode, operands[0]), word0);
}
else
{
- emit_insn (gen_movsf (gen_highpart (SFmode, operands[0]),
- word0));
- emit_insn (gen_movsf (gen_lowpart (SFmode, operands[0]),
- word1));
+ emit_move_insn_1 (gen_highpart (half_mode, operands[0]), word0);
+ emit_move_insn_1 (gen_lowpart (half_mode, operands[0]), word1);
}
DONE;
})
(define_split
- [(set (match_operand:DF 0 "memory_operand" "")
- (match_operand:DF 1 "register_operand" ""))]
+ [(set (match_operand:V64 0 "memory_operand" "")
+ (match_operand:V64 1 "register_operand" ""))]
"reload_completed
&& ! TARGET_ARCH64
&& (((REGNO (operands[1]) % 2) != 0)
@@ -3166,19 +2734,26 @@
&& offsettable_memref_p (operands[0])"
[(clobber (const_int 0))]
{
- rtx word0 = adjust_address (operands[0], SFmode, 0);
- rtx word1 = adjust_address (operands[0], SFmode, 4);
+ enum machine_mode half_mode;
+ rtx word0, word1;
+
+ /* We can be expanded for DFmode or integral vector modes. */
+ if (<V64:MODE>mode == DFmode)
+ half_mode = SFmode;
+ else
+ half_mode = SImode;
- emit_insn (gen_movsf (word0,
- gen_highpart (SFmode, operands[1])));
- emit_insn (gen_movsf (word1,
- gen_lowpart (SFmode, operands[1])));
+ word0 = adjust_address (operands[0], half_mode, 0);
+ word1 = adjust_address (operands[0], half_mode, 4);
+
+ emit_move_insn_1 (word0, gen_highpart (half_mode, operands[1]));
+ emit_move_insn_1 (word1, gen_lowpart (half_mode, operands[1]));
DONE;
})
(define_split
- [(set (match_operand:DF 0 "memory_operand" "")
- (match_operand:DF 1 "fp_zero_operand" ""))]
+ [(set (match_operand:V64 0 "memory_operand" "")
+ (match_operand:V64 1 "const_zero_operand" ""))]
"reload_completed
&& (! TARGET_V9
|| (! TARGET_ARCH64
@@ -3186,19 +2761,26 @@
&& offsettable_memref_p (operands[0])"
[(clobber (const_int 0))]
{
+ enum machine_mode half_mode;
rtx dest1, dest2;
- dest1 = adjust_address (operands[0], SFmode, 0);
- dest2 = adjust_address (operands[0], SFmode, 4);
+ /* We can be expanded for DFmode or integral vector modes. */
+ if (<V64:MODE>mode == DFmode)
+ half_mode = SFmode;
+ else
+ half_mode = SImode;
+
+ dest1 = adjust_address (operands[0], half_mode, 0);
+ dest2 = adjust_address (operands[0], half_mode, 4);
- emit_insn (gen_movsf (dest1, CONST0_RTX (SFmode)));
- emit_insn (gen_movsf (dest2, CONST0_RTX (SFmode)));
+ emit_move_insn_1 (dest1, CONST0_RTX (half_mode));
+ emit_move_insn_1 (dest2, CONST0_RTX (half_mode));
DONE;
})
(define_split
- [(set (match_operand:DF 0 "register_operand" "")
- (match_operand:DF 1 "fp_zero_operand" ""))]
+ [(set (match_operand:V64 0 "register_operand" "")
+ (match_operand:V64 1 "const_zero_operand" ""))]
"reload_completed
&& ! TARGET_ARCH64
&& ((GET_CODE (operands[0]) == REG
@@ -3208,97 +2790,39 @@
&& REGNO (SUBREG_REG (operands[0])) < 32))"
[(clobber (const_int 0))]
{
+ enum machine_mode half_mode;
rtx set_dest = operands[0];
rtx dest1, dest2;
- dest1 = gen_highpart (SFmode, set_dest);
- dest2 = gen_lowpart (SFmode, set_dest);
- emit_insn (gen_movsf (dest1, CONST0_RTX (SFmode)));
- emit_insn (gen_movsf (dest2, CONST0_RTX (SFmode)));
+ /* We can be expanded for DFmode or integral vector modes. */
+ if (<V64:MODE>mode == DFmode)
+ half_mode = SFmode;
+ else
+ half_mode = SImode;
+
+ dest1 = gen_highpart (half_mode, set_dest);
+ dest2 = gen_lowpart (half_mode, set_dest);
+ emit_move_insn_1 (dest1, CONST0_RTX (half_mode));
+ emit_move_insn_1 (dest2, CONST0_RTX (half_mode));
DONE;
})
(define_expand "movtf"
- [(set (match_operand:TF 0 "general_operand" "")
+ [(set (match_operand:TF 0 "nonimmediate_operand" "")
(match_operand:TF 1 "general_operand" ""))]
""
{
- /* Force TFmode constants into memory. */
- if (GET_CODE (operands[0]) == REG
- && CONSTANT_P (operands[1]))
- {
- /* emit_group_store will send such bogosity to us when it is
- not storing directly into memory. So fix this up to avoid
- crashes in output_constant_pool. */
- if (operands [1] == const0_rtx)
- operands[1] = CONST0_RTX (TFmode);
-
- if (TARGET_VIS && fp_zero_operand (operands[1], TFmode))
- goto movtf_is_ok;
-
- operands[1] = validize_mem (force_const_mem (GET_MODE (operands[0]),
- operands[1]));
- }
-
- /* Handle MEM cases first, note that only v9 guarantees
- full 16-byte alignment for quads. */
- if (GET_CODE (operands[0]) == MEM)
- {
- if (register_operand (operands[1], TFmode)
- || fp_zero_operand (operands[1], TFmode))
- goto movtf_is_ok;
-
- if (! reload_in_progress)
- {
- operands[0] = validize_mem (operands[0]);
- operands[1] = force_reg (TFmode, operands[1]);
- }
- }
-
- /* Fixup PIC cases. */
- if (flag_pic)
- {
- if (CONSTANT_P (operands[1])
- && pic_address_needs_scratch (operands[1]))
- operands[1] = legitimize_pic_address (operands[1], TFmode, 0);
-
- if (symbolic_operand (operands[1], TFmode))
- {
- operands[1] = legitimize_pic_address (operands[1],
- TFmode,
- (reload_in_progress ?
- operands[0] :
- NULL_RTX));
- }
- }
-
- movtf_is_ok:
- ;
+ if (sparc_expand_move (TFmode, operands))
+ DONE;
})
-;; Be careful, fmovq and {st,ld}{x,q} do not exist when !arch64 so
-;; we must split them all. :-(
(define_insn "*movtf_insn_sp32"
- [(set (match_operand:TF 0 "nonimmediate_operand" "=e,o,U,r")
- (match_operand:TF 1 "input_operand" "oe,GeUr,o,roG"))]
+ [(set (match_operand:TF 0 "nonimmediate_operand" "=b,e,o,U,r")
+ (match_operand:TF 1 "input_operand" "G,oe,GeUr,o,roG"))]
"TARGET_FPU
- && ! TARGET_VIS
&& ! TARGET_ARCH64
&& (register_operand (operands[0], TFmode)
- || register_operand (operands[1], TFmode)
- || fp_zero_operand (operands[1], TFmode))"
- "#"
- [(set_attr "length" "4")])
-
-(define_insn "*movtf_insn_vis_sp32"
- [(set (match_operand:TF 0 "nonimmediate_operand" "=e,o,U,r")
- (match_operand:TF 1 "input_operand" "Goe,GeUr,o,roG"))]
- "TARGET_FPU
- && TARGET_VIS
- && ! TARGET_ARCH64
- && (register_operand (operands[0], TFmode)
- || register_operand (operands[1], TFmode)
- || fp_zero_operand (operands[1], TFmode))"
+ || register_or_zero_operand (operands[1], TFmode))"
"#"
[(set_attr "length" "4")])
@@ -3306,94 +2830,52 @@
;; This is necessary to prevent reload from ever trying to use a `e' reg
;; when -mno-fpu.
-(define_insn "*movtf_no_e_insn_sp32"
+(define_insn "*movtf_insn_sp32_no_fpu"
[(set (match_operand:TF 0 "nonimmediate_operand" "=o,U,o,r,o")
(match_operand:TF 1 "input_operand" "G,o,U,roG,r"))]
"! TARGET_FPU
&& ! TARGET_ARCH64
&& (register_operand (operands[0], TFmode)
- || register_operand (operands[1], TFmode)
- || fp_zero_operand (operands[1], TFmode))"
+ || register_or_zero_operand (operands[1], TFmode))"
"#"
[(set_attr "length" "4")])
-;; Now handle the float reg cases directly when arch64,
-;; hard_quad, and proper reg number alignment are all true.
-(define_insn "*movtf_insn_hq_sp64"
- [(set (match_operand:TF 0 "nonimmediate_operand" "=e,e,m,o,r")
- (match_operand:TF 1 "input_operand" "e,m,e,Gr,roG"))]
+(define_insn "*movtf_insn_sp64"
+ [(set (match_operand:TF 0 "nonimmediate_operand" "=b,e,o,r")
+ (match_operand:TF 1 "input_operand" "G,oe,Ger,roG"))]
"TARGET_FPU
- && ! TARGET_VIS
&& TARGET_ARCH64
- && TARGET_HARD_QUAD
+ && ! TARGET_HARD_QUAD
&& (register_operand (operands[0], TFmode)
- || register_operand (operands[1], TFmode)
- || fp_zero_operand (operands[1], TFmode))"
- "@
- fmovq\t%1, %0
- ldq\t%1, %0
- stq\t%1, %0
- #
- #"
- [(set_attr "type" "fpmove,fpload,fpstore,*,*")
- (set_attr "length" "*,*,*,2,2")])
+ || register_or_zero_operand (operands[1], TFmode))"
+ "#"
+ [(set_attr "length" "2")])
-(define_insn "*movtf_insn_hq_vis_sp64"
- [(set (match_operand:TF 0 "nonimmediate_operand" "=e,e,m,eo,r,o")
- (match_operand:TF 1 "input_operand" "e,m,e,G,roG,r"))]
+(define_insn "*movtf_insn_sp64_hq"
+ [(set (match_operand:TF 0 "nonimmediate_operand" "=b,e,e,m,o,r")
+ (match_operand:TF 1 "input_operand" "G,e,m,e,rG,roG"))]
"TARGET_FPU
- && TARGET_VIS
&& TARGET_ARCH64
&& TARGET_HARD_QUAD
&& (register_operand (operands[0], TFmode)
- || register_operand (operands[1], TFmode)
- || fp_zero_operand (operands[1], TFmode))"
+ || register_or_zero_operand (operands[1], TFmode))"
"@
+ #
fmovq\t%1, %0
ldq\t%1, %0
stq\t%1, %0
#
- #
#"
- [(set_attr "type" "fpmove,fpload,fpstore,*,*,*")
- (set_attr "length" "*,*,*,2,2,2")])
+ [(set_attr "type" "*,fpmove,fpload,fpstore,*,*")
+ (set_attr "length" "2,*,*,*,2,2")])
-;; Now we allow the integer register cases even when
-;; only arch64 is true.
-(define_insn "*movtf_insn_sp64"
- [(set (match_operand:TF 0 "nonimmediate_operand" "=e,o,r")
- (match_operand:TF 1 "input_operand" "oe,Ger,orG"))]
- "TARGET_FPU
- && ! TARGET_VIS
- && TARGET_ARCH64
- && ! TARGET_HARD_QUAD
- && (register_operand (operands[0], TFmode)
- || register_operand (operands[1], TFmode)
- || fp_zero_operand (operands[1], TFmode))"
- "#"
- [(set_attr "length" "2")])
-
-(define_insn "*movtf_insn_vis_sp64"
- [(set (match_operand:TF 0 "nonimmediate_operand" "=e,o,r")
- (match_operand:TF 1 "input_operand" "Goe,Ger,orG"))]
- "TARGET_FPU
- && TARGET_VIS
- && TARGET_ARCH64
- && ! TARGET_HARD_QUAD
- && (register_operand (operands[0], TFmode)
- || register_operand (operands[1], TFmode)
- || fp_zero_operand (operands[1], TFmode))"
- "#"
- [(set_attr "length" "2")])
-
-(define_insn "*movtf_no_e_insn_sp64"
+(define_insn "*movtf_insn_sp64_no_fpu"
[(set (match_operand:TF 0 "nonimmediate_operand" "=r,o")
(match_operand:TF 1 "input_operand" "orG,rG"))]
"! TARGET_FPU
&& TARGET_ARCH64
&& (register_operand (operands[0], TFmode)
- || register_operand (operands[1], TFmode)
- || fp_zero_operand (operands[1], TFmode))"
+ || register_or_zero_operand (operands[1], TFmode))"
"#"
[(set_attr "length" "2")])
@@ -3435,7 +2917,7 @@
(define_split
[(set (match_operand:TF 0 "nonimmediate_operand" "")
- (match_operand:TF 1 "fp_zero_operand" ""))]
+ (match_operand:TF 1 "const_zero_operand" ""))]
"reload_completed"
[(clobber (const_int 0))]
{
@@ -3453,7 +2935,7 @@
dest2 = adjust_address (set_dest, DFmode, 8);
break;
default:
- abort ();
+ gcc_unreachable ();
}
emit_insn (gen_movdf (dest1, CONST0_RTX (DFmode)));
@@ -3514,8 +2996,9 @@
gen_df_reg (set_src, 1)));
DONE;
})
-
-;; SPARC V9 conditional move instructions.
+
+
+;; SPARC-V9 conditional move instructions.
;; We can handle larger constants here for some flavors, but for now we keep
;; it simple and only allow those constants supported by all flavors.
@@ -3546,8 +3029,7 @@
}
else
{
- rtx cc_reg = gen_compare_reg (code,
- sparc_compare_op0, sparc_compare_op1);
+ rtx cc_reg = gen_compare_reg (code);
operands[1] = gen_rtx_fmt_ee (code, GET_MODE (cc_reg), cc_reg, const0_rtx);
}
})
@@ -3575,8 +3057,7 @@
}
else
{
- rtx cc_reg = gen_compare_reg (code,
- sparc_compare_op0, sparc_compare_op1);
+ rtx cc_reg = gen_compare_reg (code);
operands[1] = gen_rtx_fmt_ee (code, GET_MODE (cc_reg), cc_reg, const0_rtx);
}
})
@@ -3600,8 +3081,7 @@
}
else
{
- rtx cc_reg = gen_compare_reg (code,
- sparc_compare_op0, sparc_compare_op1);
+ rtx cc_reg = gen_compare_reg (code);
operands[1] = gen_rtx_fmt_ee (code, GET_MODE (cc_reg),
cc_reg, const0_rtx);
}
@@ -3610,8 +3090,8 @@
(define_expand "movdicc"
[(set (match_operand:DI 0 "register_operand" "")
(if_then_else:DI (match_operand 1 "comparison_operator" "")
- (match_operand:DI 2 "arith10_double_operand" "")
- (match_operand:DI 3 "arith10_double_operand" "")))]
+ (match_operand:DI 2 "arith10_operand" "")
+ (match_operand:DI 3 "arith10_operand" "")))]
"TARGET_ARCH64"
{
enum rtx_code code = GET_CODE (operands[1]);
@@ -3626,8 +3106,7 @@
}
else
{
- rtx cc_reg = gen_compare_reg (code,
- sparc_compare_op0, sparc_compare_op1);
+ rtx cc_reg = gen_compare_reg (code);
operands[1] = gen_rtx_fmt_ee (code, GET_MODE (cc_reg),
cc_reg, const0_rtx);
}
@@ -3656,8 +3135,7 @@
}
else
{
- rtx cc_reg = gen_compare_reg (code,
- sparc_compare_op0, sparc_compare_op1);
+ rtx cc_reg = gen_compare_reg (code);
operands[1] = gen_rtx_fmt_ee (code, GET_MODE (cc_reg), cc_reg, const0_rtx);
}
})
@@ -3685,8 +3163,7 @@
}
else
{
- rtx cc_reg = gen_compare_reg (code,
- sparc_compare_op0, sparc_compare_op1);
+ rtx cc_reg = gen_compare_reg (code);
operands[1] = gen_rtx_fmt_ee (code, GET_MODE (cc_reg), cc_reg, const0_rtx);
}
})
@@ -3714,8 +3191,7 @@
}
else
{
- rtx cc_reg = gen_compare_reg (code,
- sparc_compare_op0, sparc_compare_op1);
+ rtx cc_reg = gen_compare_reg (code);
operands[1] = gen_rtx_fmt_ee (code, GET_MODE (cc_reg), cc_reg, const0_rtx);
}
})
@@ -3725,7 +3201,7 @@
(define_insn "*movqi_cc_sp64"
[(set (match_operand:QI 0 "register_operand" "=r,r")
(if_then_else:QI (match_operator 1 "comparison_operator"
- [(match_operand 2 "icc_or_fcc_reg_operand" "X,X")
+ [(match_operand 2 "icc_or_fcc_register_operand" "X,X")
(const_int 0)])
(match_operand:QI 3 "arith11_operand" "rL,0")
(match_operand:QI 4 "arith11_operand" "0,rL")))]
@@ -3738,7 +3214,7 @@
(define_insn "*movhi_cc_sp64"
[(set (match_operand:HI 0 "register_operand" "=r,r")
(if_then_else:HI (match_operator 1 "comparison_operator"
- [(match_operand 2 "icc_or_fcc_reg_operand" "X,X")
+ [(match_operand 2 "icc_or_fcc_register_operand" "X,X")
(const_int 0)])
(match_operand:HI 3 "arith11_operand" "rL,0")
(match_operand:HI 4 "arith11_operand" "0,rL")))]
@@ -3751,7 +3227,7 @@
(define_insn "*movsi_cc_sp64"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(if_then_else:SI (match_operator 1 "comparison_operator"
- [(match_operand 2 "icc_or_fcc_reg_operand" "X,X")
+ [(match_operand 2 "icc_or_fcc_register_operand" "X,X")
(const_int 0)])
(match_operand:SI 3 "arith11_operand" "rL,0")
(match_operand:SI 4 "arith11_operand" "0,rL")))]
@@ -3761,14 +3237,13 @@
mov%c1\t%x2, %4, %0"
[(set_attr "type" "cmove")])
-;; ??? The constraints of operands 3,4 need work.
(define_insn "*movdi_cc_sp64"
[(set (match_operand:DI 0 "register_operand" "=r,r")
(if_then_else:DI (match_operator 1 "comparison_operator"
- [(match_operand 2 "icc_or_fcc_reg_operand" "X,X")
+ [(match_operand 2 "icc_or_fcc_register_operand" "X,X")
(const_int 0)])
- (match_operand:DI 3 "arith11_double_operand" "rLH,0")
- (match_operand:DI 4 "arith11_double_operand" "0,rLH")))]
+ (match_operand:DI 3 "arith11_operand" "rL,0")
+ (match_operand:DI 4 "arith11_operand" "0,rL")))]
"TARGET_ARCH64"
"@
mov%C1\t%x2, %3, %0
@@ -3778,10 +3253,10 @@
(define_insn "*movdi_cc_sp64_trunc"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(if_then_else:SI (match_operator 1 "comparison_operator"
- [(match_operand 2 "icc_or_fcc_reg_operand" "X,X")
+ [(match_operand 2 "icc_or_fcc_register_operand" "X,X")
(const_int 0)])
- (match_operand:SI 3 "arith11_double_operand" "rLH,0")
- (match_operand:SI 4 "arith11_double_operand" "0,rLH")))]
+ (match_operand:SI 3 "arith11_operand" "rL,0")
+ (match_operand:SI 4 "arith11_operand" "0,rL")))]
"TARGET_ARCH64"
"@
mov%C1\t%x2, %3, %0
@@ -3791,7 +3266,7 @@
(define_insn "*movsf_cc_sp64"
[(set (match_operand:SF 0 "register_operand" "=f,f")
(if_then_else:SF (match_operator 1 "comparison_operator"
- [(match_operand 2 "icc_or_fcc_reg_operand" "X,X")
+ [(match_operand 2 "icc_or_fcc_register_operand" "X,X")
(const_int 0)])
(match_operand:SF 3 "register_operand" "f,0")
(match_operand:SF 4 "register_operand" "0,f")))]
@@ -3804,7 +3279,7 @@
(define_insn "movdf_cc_sp64"
[(set (match_operand:DF 0 "register_operand" "=e,e")
(if_then_else:DF (match_operator 1 "comparison_operator"
- [(match_operand 2 "icc_or_fcc_reg_operand" "X,X")
+ [(match_operand 2 "icc_or_fcc_register_operand" "X,X")
(const_int 0)])
(match_operand:DF 3 "register_operand" "e,0")
(match_operand:DF 4 "register_operand" "0,e")))]
@@ -3818,7 +3293,7 @@
(define_insn "*movtf_cc_hq_sp64"
[(set (match_operand:TF 0 "register_operand" "=e,e")
(if_then_else:TF (match_operator 1 "comparison_operator"
- [(match_operand 2 "icc_or_fcc_reg_operand" "X,X")
+ [(match_operand 2 "icc_or_fcc_register_operand" "X,X")
(const_int 0)])
(match_operand:TF 3 "register_operand" "e,0")
(match_operand:TF 4 "register_operand" "0,e")))]
@@ -3831,7 +3306,7 @@
(define_insn_and_split "*movtf_cc_sp64"
[(set (match_operand:TF 0 "register_operand" "=e,e")
(if_then_else:TF (match_operator 1 "comparison_operator"
- [(match_operand 2 "icc_or_fcc_reg_operand" "X,X")
+ [(match_operand 2 "icc_or_fcc_register_operand" "X,X")
(const_int 0)])
(match_operand:TF 3 "register_operand" "e,0")
(match_operand:TF 4 "register_operand" "0,e")))]
@@ -3873,7 +3348,7 @@
(define_insn "*movqi_cc_reg_sp64"
[(set (match_operand:QI 0 "register_operand" "=r,r")
- (if_then_else:QI (match_operator 1 "v9_regcmp_op"
+ (if_then_else:QI (match_operator 1 "v9_register_compare_operator"
[(match_operand:DI 2 "register_operand" "r,r")
(const_int 0)])
(match_operand:QI 3 "arith10_operand" "rM,0")
@@ -3886,7 +3361,7 @@
(define_insn "*movhi_cc_reg_sp64"
[(set (match_operand:HI 0 "register_operand" "=r,r")
- (if_then_else:HI (match_operator 1 "v9_regcmp_op"
+ (if_then_else:HI (match_operator 1 "v9_register_compare_operator"
[(match_operand:DI 2 "register_operand" "r,r")
(const_int 0)])
(match_operand:HI 3 "arith10_operand" "rM,0")
@@ -3899,7 +3374,7 @@
(define_insn "*movsi_cc_reg_sp64"
[(set (match_operand:SI 0 "register_operand" "=r,r")
- (if_then_else:SI (match_operator 1 "v9_regcmp_op"
+ (if_then_else:SI (match_operator 1 "v9_register_compare_operator"
[(match_operand:DI 2 "register_operand" "r,r")
(const_int 0)])
(match_operand:SI 3 "arith10_operand" "rM,0")
@@ -3910,27 +3385,13 @@
movr%d1\t%2, %r4, %0"
[(set_attr "type" "cmove")])
-;; ??? The constraints of operands 3,4 need work.
(define_insn "*movdi_cc_reg_sp64"
[(set (match_operand:DI 0 "register_operand" "=r,r")
- (if_then_else:DI (match_operator 1 "v9_regcmp_op"
- [(match_operand:DI 2 "register_operand" "r,r")
- (const_int 0)])
- (match_operand:DI 3 "arith10_double_operand" "rMH,0")
- (match_operand:DI 4 "arith10_double_operand" "0,rMH")))]
- "TARGET_ARCH64"
- "@
- movr%D1\t%2, %r3, %0
- movr%d1\t%2, %r4, %0"
- [(set_attr "type" "cmove")])
-
-(define_insn "*movdi_cc_reg_sp64_trunc"
- [(set (match_operand:SI 0 "register_operand" "=r,r")
- (if_then_else:SI (match_operator 1 "v9_regcmp_op"
+ (if_then_else:DI (match_operator 1 "v9_register_compare_operator"
[(match_operand:DI 2 "register_operand" "r,r")
(const_int 0)])
- (match_operand:SI 3 "arith10_double_operand" "rMH,0")
- (match_operand:SI 4 "arith10_double_operand" "0,rMH")))]
+ (match_operand:DI 3 "arith10_operand" "rM,0")
+ (match_operand:DI 4 "arith10_operand" "0,rM")))]
"TARGET_ARCH64"
"@
movr%D1\t%2, %r3, %0
@@ -3939,7 +3400,7 @@
(define_insn "*movsf_cc_reg_sp64"
[(set (match_operand:SF 0 "register_operand" "=f,f")
- (if_then_else:SF (match_operator 1 "v9_regcmp_op"
+ (if_then_else:SF (match_operator 1 "v9_register_compare_operator"
[(match_operand:DI 2 "register_operand" "r,r")
(const_int 0)])
(match_operand:SF 3 "register_operand" "f,0")
@@ -3952,7 +3413,7 @@
(define_insn "movdf_cc_reg_sp64"
[(set (match_operand:DF 0 "register_operand" "=e,e")
- (if_then_else:DF (match_operator 1 "v9_regcmp_op"
+ (if_then_else:DF (match_operator 1 "v9_register_compare_operator"
[(match_operand:DI 2 "register_operand" "r,r")
(const_int 0)])
(match_operand:DF 3 "register_operand" "e,0")
@@ -3966,7 +3427,7 @@
(define_insn "*movtf_cc_reg_hq_sp64"
[(set (match_operand:TF 0 "register_operand" "=e,e")
- (if_then_else:TF (match_operator 1 "v9_regcmp_op"
+ (if_then_else:TF (match_operator 1 "v9_register_compare_operator"
[(match_operand:DI 2 "register_operand" "r,r")
(const_int 0)])
(match_operand:TF 3 "register_operand" "e,0")
@@ -3979,7 +3440,7 @@
(define_insn_and_split "*movtf_cc_reg_sp64"
[(set (match_operand:TF 0 "register_operand" "=e,e")
- (if_then_else:TF (match_operator 1 "v9_regcmp_op"
+ (if_then_else:TF (match_operator 1 "v9_register_compare_operator"
[(match_operand:DI 2 "register_operand" "r,r")
(const_int 0)])
(match_operand:TF 3 "register_operand" "e,0")
@@ -4021,7 +3482,7 @@
[(set_attr "length" "2")])
-;;- zero extension instructions
+;; Zero-extension instructions
;; These patterns originally accepted general_operands, however, slightly
;; better code is generated by only accepting register_operands, and then
@@ -4137,7 +3598,6 @@
[(set_attr "type" "load")
(set_attr "us3load_type" "3cycle")])
-
;; ??? Write truncdisi pattern using sra?
(define_expand "zero_extendsidi2"
@@ -4301,7 +3761,8 @@
"andcc\t%1, 0xff, %0"
[(set_attr "type" "compare")])
-;;- sign extension instructions
+
+;; Sign-extension instructions
;; These patterns originally accepted general_operands, however, slightly
;; better code is generated by only accepting register_operands, and then
@@ -4486,7 +3947,8 @@
ldsw\t%1, %0"
[(set_attr "type" "shift,sload")
(set_attr "us3load_type" "*,3cycle")])
-
+
+
;; Special pattern for optimizing bit-field compares. This is needed
;; because combine uses this as a canonical form.
@@ -4494,23 +3956,14 @@
[(set (reg:CC 100)
(compare:CC
(zero_extract:SI (match_operand:SI 0 "register_operand" "r")
- (match_operand:SI 1 "small_int_or_double" "n")
- (match_operand:SI 2 "small_int_or_double" "n"))
+ (match_operand:SI 1 "small_int_operand" "I")
+ (match_operand:SI 2 "small_int_operand" "I"))
(const_int 0)))]
- "(GET_CODE (operands[2]) == CONST_INT
- && INTVAL (operands[2]) > 19)
- || (GET_CODE (operands[2]) == CONST_DOUBLE
- && CONST_DOUBLE_LOW (operands[2]) > 19)"
-{
- int len = (GET_CODE (operands[1]) == CONST_INT
- ? INTVAL (operands[1])
- : CONST_DOUBLE_LOW (operands[1]));
- int pos = 32 -
- (GET_CODE (operands[2]) == CONST_INT
- ? INTVAL (operands[2])
- : CONST_DOUBLE_LOW (operands[2])) - len;
+ "INTVAL (operands[2]) > 19"
+{
+ int len = INTVAL (operands[1]);
+ int pos = 32 - INTVAL (operands[2]) - len;
HOST_WIDE_INT mask = ((1 << len) - 1) << pos;
-
operands[1] = GEN_INT (mask);
return "andcc\t%0, %1, %%g0";
}
@@ -4520,29 +3973,20 @@
[(set (reg:CCX 100)
(compare:CCX
(zero_extract:DI (match_operand:DI 0 "register_operand" "r")
- (match_operand:SI 1 "small_int_or_double" "n")
- (match_operand:SI 2 "small_int_or_double" "n"))
+ (match_operand:SI 1 "small_int_operand" "I")
+ (match_operand:SI 2 "small_int_operand" "I"))
(const_int 0)))]
- "TARGET_ARCH64
- && ((GET_CODE (operands[2]) == CONST_INT
- && INTVAL (operands[2]) > 51)
- || (GET_CODE (operands[2]) == CONST_DOUBLE
- && CONST_DOUBLE_LOW (operands[2]) > 51))"
-{
- int len = (GET_CODE (operands[1]) == CONST_INT
- ? INTVAL (operands[1])
- : CONST_DOUBLE_LOW (operands[1]));
- int pos = 64 -
- (GET_CODE (operands[2]) == CONST_INT
- ? INTVAL (operands[2])
- : CONST_DOUBLE_LOW (operands[2])) - len;
+ "TARGET_ARCH64 && INTVAL (operands[2]) > 51"
+{
+ int len = INTVAL (operands[1]);
+ int pos = 64 - INTVAL (operands[2]) - len;
HOST_WIDE_INT mask = (((unsigned HOST_WIDE_INT) 1 << len) - 1) << pos;
-
operands[1] = GEN_INT (mask);
return "andcc\t%0, %1, %%g0";
}
[(set_attr "type" "compare")])
-
+
+
;; Conversions between float, double and long double.
(define_insn "extendsfdf2"
@@ -4622,7 +4066,8 @@
"TARGET_FPU && TARGET_HARD_QUAD"
"fqtod\t%1, %0"
[(set_attr "type" "fp")])
-
+
+
;; Conversion between fixed point and floating point.
(define_insn "floatsisf2"
@@ -4672,9 +4117,9 @@
(define_expand "floatunsdisf2"
[(use (match_operand:SF 0 "register_operand" ""))
- (use (match_operand:DI 1 "register_operand" ""))]
+ (use (match_operand:DI 1 "general_operand" ""))]
"TARGET_ARCH64 && TARGET_FPU"
- "sparc_emit_floatunsdi (operands); DONE;")
+ "sparc_emit_floatunsdi (operands, SFmode); DONE;")
(define_insn "floatdidf2"
[(set (match_operand:DF 0 "register_operand" "=e")
@@ -4686,9 +4131,9 @@
(define_expand "floatunsdidf2"
[(use (match_operand:DF 0 "register_operand" ""))
- (use (match_operand:DI 1 "register_operand" ""))]
+ (use (match_operand:DI 1 "general_operand" ""))]
"TARGET_ARCH64 && TARGET_FPU"
- "sparc_emit_floatunsdi (operands); DONE;")
+ "sparc_emit_floatunsdi (operands, DFmode); DONE;")
(define_expand "floatditf2"
[(set (match_operand:TF 0 "nonimmediate_operand" "")
@@ -4757,6 +4202,12 @@
[(set_attr "type" "fp")
(set_attr "fptype" "double")])
+(define_expand "fixuns_truncsfdi2"
+ [(use (match_operand:DI 0 "register_operand" ""))
+ (use (match_operand:SF 1 "general_operand" ""))]
+ "TARGET_ARCH64 && TARGET_FPU"
+ "sparc_emit_fixunsdi (operands, SFmode); DONE;")
+
(define_insn "fix_truncdfdi2"
[(set (match_operand:DI 0 "register_operand" "=e")
(fix:DI (fix:DF (match_operand:DF 1 "register_operand" "e"))))]
@@ -4765,6 +4216,12 @@
[(set_attr "type" "fp")
(set_attr "fptype" "double")])
+(define_expand "fixuns_truncdfdi2"
+ [(use (match_operand:DI 0 "register_operand" ""))
+ (use (match_operand:DF 1 "general_operand" ""))]
+ "TARGET_ARCH64 && TARGET_FPU"
+ "sparc_emit_fixunsdi (operands, DFmode); DONE;")
+
(define_expand "fix_trunctfdi2"
[(set (match_operand:DI 0 "register_operand" "")
(fix:DI (match_operand:TF 1 "general_operand" "")))]
@@ -4783,8 +4240,9 @@
(unsigned_fix:DI (match_operand:TF 1 "general_operand" "")))]
"TARGET_FPU && TARGET_ARCH64 && ! TARGET_HARD_QUAD"
"emit_tfmode_cvt (UNSIGNED_FIX, operands); DONE;")
-
-;;- arithmetic instructions
+
+
+;; Integer addition/subtraction instructions.
(define_expand "adddi3"
[(set (match_operand:DI 0 "register_operand" "")
@@ -4842,41 +4300,6 @@
}
[(set_attr "length" "2")])
-(define_split
- [(set (match_operand:DI 0 "register_operand" "")
- (minus:DI (match_operand:DI 1 "arith_double_operand" "")
- (match_operand:DI 2 "arith_double_operand" "")))
- (clobber (reg:CC 100))]
- "! TARGET_ARCH64 && reload_completed"
- [(parallel [(set (reg:CC_NOOV 100)
- (compare:CC_NOOV (minus:SI (match_dup 4)
- (match_dup 5))
- (const_int 0)))
- (set (match_dup 3)
- (minus:SI (match_dup 4) (match_dup 5)))])
- (set (match_dup 6)
- (minus:SI (minus:SI (match_dup 7)
- (match_dup 8))
- (ltu:SI (reg:CC_NOOV 100) (const_int 0))))]
-{
- operands[3] = gen_lowpart (SImode, operands[0]);
- operands[4] = gen_lowpart (SImode, operands[1]);
- operands[5] = gen_lowpart (SImode, operands[2]);
- operands[6] = gen_highpart (SImode, operands[0]);
- operands[7] = gen_highpart (SImode, operands[1]);
-#if HOST_BITS_PER_WIDE_INT == 32
- if (GET_CODE (operands[2]) == CONST_INT)
- {
- if (INTVAL (operands[2]) < 0)
- operands[8] = constm1_rtx;
- else
- operands[8] = const0_rtx;
- }
- else
-#endif
- operands[8] = gen_highpart_mode (SImode, DImode, operands[2]);
-})
-
;; LTU here means "carry set"
(define_insn "addx"
[(set (match_operand:SI 0 "register_operand" "=r")
@@ -4890,7 +4313,7 @@
(define_insn_and_split "*addx_extend_sp32"
[(set (match_operand:DI 0 "register_operand" "=r")
(zero_extend:DI (plus:SI (plus:SI
- (match_operand:SI 1 "reg_or_0_operand" "%rJ")
+ (match_operand:SI 1 "register_or_zero_operand" "%rJ")
(match_operand:SI 2 "arith_operand" "rI"))
(ltu:SI (reg:CC_NOOV 100) (const_int 0)))))]
"! TARGET_ARCH64"
@@ -4905,46 +4328,13 @@
(define_insn "*addx_extend_sp64"
[(set (match_operand:DI 0 "register_operand" "=r")
- (zero_extend:DI (plus:SI (plus:SI (match_operand:SI 1 "reg_or_0_operand" "%rJ")
+ (zero_extend:DI (plus:SI (plus:SI (match_operand:SI 1 "register_or_zero_operand" "%rJ")
(match_operand:SI 2 "arith_operand" "rI"))
(ltu:SI (reg:CC_NOOV 100) (const_int 0)))))]
"TARGET_ARCH64"
"addx\t%r1, %2, %0"
[(set_attr "type" "ialuX")])
-(define_insn "subx"
- [(set (match_operand:SI 0 "register_operand" "=r")
- (minus:SI (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rJ")
- (match_operand:SI 2 "arith_operand" "rI"))
- (ltu:SI (reg:CC_NOOV 100) (const_int 0))))]
- ""
- "subx\t%r1, %2, %0"
- [(set_attr "type" "ialuX")])
-
-(define_insn "*subx_extend_sp64"
- [(set (match_operand:DI 0 "register_operand" "=r")
- (zero_extend:DI (minus:SI (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rJ")
- (match_operand:SI 2 "arith_operand" "rI"))
- (ltu:SI (reg:CC_NOOV 100) (const_int 0)))))]
- "TARGET_ARCH64"
- "subx\t%r1, %2, %0"
- [(set_attr "type" "ialuX")])
-
-(define_insn_and_split "*subx_extend"
- [(set (match_operand:DI 0 "register_operand" "=r")
- (zero_extend:DI (minus:SI (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rJ")
- (match_operand:SI 2 "arith_operand" "rI"))
- (ltu:SI (reg:CC_NOOV 100) (const_int 0)))))]
- "! TARGET_ARCH64"
- "#"
- "&& reload_completed"
- [(set (match_dup 3) (minus:SI (minus:SI (match_dup 1) (match_dup 2))
- (ltu:SI (reg:CC_NOOV 100) (const_int 0))))
- (set (match_dup 4) (const_int 0))]
- "operands[3] = gen_lowpart (SImode, operands[0]);
- operands[4] = gen_highpart (SImode, operands[0]);"
- [(set_attr "length" "2")])
-
(define_insn_and_split ""
[(set (match_operand:DI 0 "register_operand" "=r")
(plus:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
@@ -4969,7 +4359,7 @@
(define_insn "*adddi3_sp64"
[(set (match_operand:DI 0 "register_operand" "=r,r")
(plus:DI (match_operand:DI 1 "register_operand" "%r,r")
- (match_operand:DI 2 "arith_double_add_operand" "rHI,O")))]
+ (match_operand:DI 2 "arith_add_operand" "rI,O")))]
"TARGET_ARCH64"
"@
add\t%1, %2, %0
@@ -4984,7 +4374,8 @@
add\t%1, %2, %0
sub\t%1, -%2, %0
fpadd32s\t%1, %2, %0"
- [(set_attr "type" "*,*,fga")])
+ [(set_attr "type" "*,*,fga")
+ (set_attr "fptype" "*,*,single")])
(define_insn "*cmp_cc_plus"
[(set (reg:CC_NOOV 100)
@@ -4997,8 +4388,8 @@
(define_insn "*cmp_ccx_plus"
[(set (reg:CCX_NOOV 100)
- (compare:CCX_NOOV (plus:DI (match_operand:DI 0 "arith_double_operand" "%r")
- (match_operand:DI 1 "arith_double_operand" "rHI"))
+ (compare:CCX_NOOV (plus:DI (match_operand:DI 0 "arith_operand" "%r")
+ (match_operand:DI 1 "arith_operand" "rI"))
(const_int 0)))]
"TARGET_ARCH64"
"addcc\t%0, %1, %%g0"
@@ -5017,8 +4408,8 @@
(define_insn "*cmp_ccx_plus_set"
[(set (reg:CCX_NOOV 100)
- (compare:CCX_NOOV (plus:DI (match_operand:DI 1 "arith_double_operand" "%r")
- (match_operand:DI 2 "arith_double_operand" "rHI"))
+ (compare:CCX_NOOV (plus:DI (match_operand:DI 1 "arith_operand" "%r")
+ (match_operand:DI 2 "arith_operand" "rI"))
(const_int 0)))
(set (match_operand:DI 0 "register_operand" "=r")
(plus:DI (match_dup 1) (match_dup 2)))]
@@ -5044,62 +4435,77 @@
}
})
-(define_insn_and_split "*subdi3_sp32"
+(define_insn_and_split "subdi3_insn_sp32"
[(set (match_operand:DI 0 "register_operand" "=r")
- (minus:DI (match_operand:DI 1 "register_operand" "r")
- (match_operand:DI 2 "arith_double_operand" "rHI")))
+ (minus:DI (match_operand:DI 1 "register_operand" "r")
+ (match_operand:DI 2 "arith_double_operand" "rHI")))
(clobber (reg:CC 100))]
"! TARGET_ARCH64"
"#"
- "&& reload_completed
- && (GET_CODE (operands[2]) == CONST_INT
- || GET_CODE (operands[2]) == CONST_DOUBLE)"
- [(clobber (const_int 0))]
+ "&& reload_completed"
+ [(parallel [(set (reg:CC_NOOV 100)
+ (compare:CC_NOOV (minus:SI (match_dup 4)
+ (match_dup 5))
+ (const_int 0)))
+ (set (match_dup 3)
+ (minus:SI (match_dup 4) (match_dup 5)))])
+ (set (match_dup 6)
+ (minus:SI (minus:SI (match_dup 7)
+ (match_dup 8))
+ (ltu:SI (reg:CC_NOOV 100) (const_int 0))))]
{
- rtx highp, lowp;
-
- highp = gen_highpart_mode (SImode, DImode, operands[2]);
- lowp = gen_lowpart (SImode, operands[2]);
- if ((lowp == const0_rtx)
- && (operands[0] == operands[1]))
+ operands[3] = gen_lowpart (SImode, operands[0]);
+ operands[4] = gen_lowpart (SImode, operands[1]);
+ operands[5] = gen_lowpart (SImode, operands[2]);
+ operands[6] = gen_highpart (SImode, operands[0]);
+ operands[7] = gen_highpart (SImode, operands[1]);
+#if HOST_BITS_PER_WIDE_INT == 32
+ if (GET_CODE (operands[2]) == CONST_INT)
{
- emit_insn (gen_rtx_SET (VOIDmode,
- gen_highpart (SImode, operands[0]),
- gen_rtx_MINUS (SImode,
- gen_highpart_mode (SImode, DImode,
- operands[1]),
- highp)));
+ if (INTVAL (operands[2]) < 0)
+ operands[8] = constm1_rtx;
+ else
+ operands[8] = const0_rtx;
}
else
- {
- emit_insn (gen_cmp_minus_cc_set (gen_lowpart (SImode, operands[0]),
- gen_lowpart (SImode, operands[1]),
- lowp));
- emit_insn (gen_subx (gen_highpart (SImode, operands[0]),
- gen_highpart_mode (SImode, DImode, operands[1]),
- highp));
- }
- DONE;
+#endif
+ operands[8] = gen_highpart_mode (SImode, DImode, operands[2]);
}
[(set_attr "length" "2")])
-(define_split
- [(set (match_operand:DI 0 "register_operand" "")
- (minus:DI (match_operand:DI 1 "register_operand" "")
- (match_operand:DI 2 "register_operand" "")))
- (clobber (reg:CC 100))]
- "! TARGET_ARCH64
- && reload_completed"
- [(clobber (const_int 0))]
-{
- emit_insn (gen_cmp_minus_cc_set (gen_lowpart (SImode, operands[0]),
- gen_lowpart (SImode, operands[1]),
- gen_lowpart (SImode, operands[2])));
- emit_insn (gen_subx (gen_highpart (SImode, operands[0]),
- gen_highpart (SImode, operands[1]),
- gen_highpart (SImode, operands[2])));
- DONE;
-})
+;; LTU here means "carry set"
+(define_insn "subx"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (minus:SI (match_operand:SI 1 "register_or_zero_operand" "rJ")
+ (match_operand:SI 2 "arith_operand" "rI"))
+ (ltu:SI (reg:CC_NOOV 100) (const_int 0))))]
+ ""
+ "subx\t%r1, %2, %0"
+ [(set_attr "type" "ialuX")])
+
+(define_insn "*subx_extend_sp64"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (zero_extend:DI (minus:SI (minus:SI (match_operand:SI 1 "register_or_zero_operand" "rJ")
+ (match_operand:SI 2 "arith_operand" "rI"))
+ (ltu:SI (reg:CC_NOOV 100) (const_int 0)))))]
+ "TARGET_ARCH64"
+ "subx\t%r1, %2, %0"
+ [(set_attr "type" "ialuX")])
+
+(define_insn_and_split "*subx_extend"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (zero_extend:DI (minus:SI (minus:SI (match_operand:SI 1 "register_or_zero_operand" "rJ")
+ (match_operand:SI 2 "arith_operand" "rI"))
+ (ltu:SI (reg:CC_NOOV 100) (const_int 0)))))]
+ "! TARGET_ARCH64"
+ "#"
+ "&& reload_completed"
+ [(set (match_dup 3) (minus:SI (minus:SI (match_dup 1) (match_dup 2))
+ (ltu:SI (reg:CC_NOOV 100) (const_int 0))))
+ (set (match_dup 4) (const_int 0))]
+ "operands[3] = gen_lowpart (SImode, operands[0]);
+ operands[4] = gen_highpart (SImode, operands[0]);"
+ [(set_attr "length" "2")])
(define_insn_and_split ""
[(set (match_operand:DI 0 "register_operand" "=r")
@@ -5125,7 +4531,7 @@
(define_insn "*subdi3_sp64"
[(set (match_operand:DI 0 "register_operand" "=r,r")
(minus:DI (match_operand:DI 1 "register_operand" "r,r")
- (match_operand:DI 2 "arith_double_add_operand" "rHI,O")))]
+ (match_operand:DI 2 "arith_add_operand" "rI,O")))]
"TARGET_ARCH64"
"@
sub\t%1, %2, %0
@@ -5140,11 +4546,12 @@
sub\t%1, %2, %0
add\t%1, -%2, %0
fpsub32s\t%1, %2, %0"
- [(set_attr "type" "*,*,fga")])
+ [(set_attr "type" "*,*,fga")
+ (set_attr "fptype" "*,*,single")])
(define_insn "*cmp_minus_cc"
[(set (reg:CC_NOOV 100)
- (compare:CC_NOOV (minus:SI (match_operand:SI 0 "reg_or_0_operand" "rJ")
+ (compare:CC_NOOV (minus:SI (match_operand:SI 0 "register_or_zero_operand" "rJ")
(match_operand:SI 1 "arith_operand" "rI"))
(const_int 0)))]
""
@@ -5154,7 +4561,7 @@
(define_insn "*cmp_minus_ccx"
[(set (reg:CCX_NOOV 100)
(compare:CCX_NOOV (minus:DI (match_operand:DI 0 "register_operand" "r")
- (match_operand:DI 1 "arith_double_operand" "rHI"))
+ (match_operand:DI 1 "arith_operand" "rI"))
(const_int 0)))]
"TARGET_ARCH64"
"subcc\t%0, %1, %%g0"
@@ -5162,7 +4569,7 @@
(define_insn "cmp_minus_cc_set"
[(set (reg:CC_NOOV 100)
- (compare:CC_NOOV (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rJ")
+ (compare:CC_NOOV (minus:SI (match_operand:SI 1 "register_or_zero_operand" "rJ")
(match_operand:SI 2 "arith_operand" "rI"))
(const_int 0)))
(set (match_operand:SI 0 "register_operand" "=r")
@@ -5174,15 +4581,16 @@
(define_insn "*cmp_minus_ccx_set"
[(set (reg:CCX_NOOV 100)
(compare:CCX_NOOV (minus:DI (match_operand:DI 1 "register_operand" "r")
- (match_operand:DI 2 "arith_double_operand" "rHI"))
+ (match_operand:DI 2 "arith_operand" "rI"))
(const_int 0)))
(set (match_operand:DI 0 "register_operand" "=r")
(minus:DI (match_dup 1) (match_dup 2)))]
"TARGET_ARCH64"
"subcc\t%1, %2, %0"
[(set_attr "type" "compare")])
-
-;; Integer Multiply/Divide.
+
+
+;; Integer multiply/divide instructions.
;; The 32 bit multiply/divide instructions are deprecated on v9, but at
;; least in UltraSPARC I, II and IIi it is a win tick-wise.
@@ -5196,9 +4604,9 @@
[(set_attr "type" "imul")])
(define_expand "muldi3"
- [(set (match_operand:DI 0 "register_operand" "=r")
- (mult:DI (match_operand:DI 1 "arith_double_operand" "%r")
- (match_operand:DI 2 "arith_double_operand" "rHI")))]
+ [(set (match_operand:DI 0 "register_operand" "")
+ (mult:DI (match_operand:DI 1 "arith_operand" "")
+ (match_operand:DI 2 "arith_operand" "")))]
"TARGET_ARCH64 || TARGET_V8PLUS"
{
if (TARGET_V8PLUS)
@@ -5210,8 +4618,8 @@
(define_insn "*muldi3_sp64"
[(set (match_operand:DI 0 "register_operand" "=r")
- (mult:DI (match_operand:DI 1 "arith_double_operand" "%r")
- (match_operand:DI 2 "arith_double_operand" "rHI")))]
+ (mult:DI (match_operand:DI 1 "arith_operand" "%r")
+ (match_operand:DI 2 "arith_operand" "rI")))]
"TARGET_ARCH64"
"mulx\t%1, %2, %0"
[(set_attr "type" "imul")])
@@ -5220,8 +4628,8 @@
;; XXX
(define_insn "muldi3_v8plus"
[(set (match_operand:DI 0 "register_operand" "=r,h")
- (mult:DI (match_operand:DI 1 "arith_double_operand" "%r,0")
- (match_operand:DI 2 "arith_double_operand" "rI,rI")))
+ (mult:DI (match_operand:DI 1 "arith_operand" "%r,0")
+ (match_operand:DI 2 "arith_operand" "rI,rI")))
(clobber (match_scratch:SI 3 "=&h,X"))
(clobber (match_scratch:SI 4 "=&h,X"))]
"TARGET_V8PLUS"
@@ -5310,7 +4718,7 @@
(define_insn "const_mulsidi3_v8plus"
[(set (match_operand:DI 0 "register_operand" "=h,r")
(mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r,r"))
- (match_operand:DI 2 "small_int" "I,I")))
+ (match_operand:DI 2 "small_int_operand" "I,I")))
(clobber (match_scratch:SI 3 "=X,&h"))]
"TARGET_V8PLUS"
"@
@@ -5351,7 +4759,7 @@
(define_insn "const_mulsidi3_sp32"
[(set (match_operand:DI 0 "register_operand" "=r")
(mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r"))
- (match_operand:DI 2 "small_int" "I")))]
+ (match_operand:DI 2 "small_int_operand" "I")))]
"TARGET_HARD_MUL32"
{
return TARGET_SPARCLET
@@ -5368,7 +4776,7 @@
(define_insn "const_mulsidi3_sp64"
[(set (match_operand:DI 0 "register_operand" "=r")
(mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r"))
- (match_operand:DI 2 "small_int" "I")))]
+ (match_operand:DI 2 "small_int_operand" "I")))]
"TARGET_DEPRECATED_V8_INSNS && TARGET_ARCH64"
"smul\t%1, %2, %0"
[(set_attr "type" "imul")])
@@ -5408,7 +4816,7 @@
(truncate:SI
(lshiftrt:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r,r"))
(sign_extend:DI (match_operand:SI 2 "register_operand" "r,r")))
- (match_operand:SI 3 "const_int_operand" "i,i"))))
+ (match_operand:SI 3 "small_int_operand" "I,I"))))
(clobber (match_scratch:SI 4 "=X,&h"))]
"TARGET_V8PLUS"
"@
@@ -5425,7 +4833,7 @@
(lshiftrt:DI
(mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r,r"))
(sign_extend:DI (match_operand:SI 2 "register_operand" "r,r")))
- (match_operand:SI 3 "const_int_operand" "i,i"))
+ (match_operand:SI 3 "small_int_operand" "I,I"))
4))
(clobber (match_scratch:SI 4 "=X,&h"))]
"TARGET_V8PLUS"
@@ -5440,8 +4848,8 @@
[(set (match_operand:SI 0 "register_operand" "=h,r")
(truncate:SI
(lshiftrt:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r,r"))
- (match_operand:DI 2 "small_int" "i,i"))
- (match_operand:SI 3 "const_int_operand" "i,i"))))
+ (match_operand:DI 2 "small_int_operand" "I,I"))
+ (match_operand:SI 3 "small_int_operand" "I,I"))))
(clobber (match_scratch:SI 4 "=X,&h"))]
"TARGET_V8PLUS"
"@
@@ -5467,7 +4875,7 @@
[(set (match_operand:SI 0 "register_operand" "=r")
(truncate:SI
(lshiftrt:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r"))
- (match_operand:DI 2 "small_int" "i"))
+ (match_operand:DI 2 "small_int_operand" "i"))
(const_int 32))))]
"TARGET_HARD_MUL32"
"smul\t%1, %2, %%g0\n\trd\t%%y, %0"
@@ -5545,7 +4953,7 @@
(define_insn "const_umulsidi3_sp32"
[(set (match_operand:DI 0 "register_operand" "=r")
(mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
- (match_operand:DI 2 "uns_small_int" "")))]
+ (match_operand:DI 2 "uns_small_int_operand" "")))]
"TARGET_HARD_MUL32"
{
return TARGET_SPARCLET
@@ -5562,7 +4970,7 @@
(define_insn "const_umulsidi3_sp64"
[(set (match_operand:DI 0 "register_operand" "=r")
(mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
- (match_operand:DI 2 "uns_small_int" "")))]
+ (match_operand:DI 2 "uns_small_int_operand" "")))]
"TARGET_DEPRECATED_V8_INSNS && TARGET_ARCH64"
"umul\t%1, %s2, %0"
[(set_attr "type" "imul")])
@@ -5571,7 +4979,7 @@
(define_insn "const_umulsidi3_v8plus"
[(set (match_operand:DI 0 "register_operand" "=h,r")
(mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r,r"))
- (match_operand:DI 2 "uns_small_int" "")))
+ (match_operand:DI 2 "uns_small_int_operand" "")))
(clobber (match_scratch:SI 3 "=X,h"))]
"TARGET_V8PLUS"
"@
@@ -5615,7 +5023,7 @@
(truncate:SI
(lshiftrt:DI (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r,r"))
(zero_extend:DI (match_operand:SI 2 "register_operand" "r,r")))
- (match_operand:SI 3 "const_int_operand" "i,i"))))
+ (match_operand:SI 3 "small_int_operand" "I,I"))))
(clobber (match_scratch:SI 4 "=X,h"))]
"TARGET_V8PLUS"
"@
@@ -5629,8 +5037,8 @@
[(set (match_operand:SI 0 "register_operand" "=h,r")
(truncate:SI
(lshiftrt:DI (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r,r"))
- (match_operand:DI 2 "uns_small_int" ""))
- (match_operand:SI 3 "const_int_operand" "i,i"))))
+ (match_operand:DI 2 "uns_small_int_operand" ""))
+ (match_operand:SI 3 "small_int_operand" "I,I"))))
(clobber (match_scratch:SI 4 "=X,h"))]
"TARGET_V8PLUS"
"@
@@ -5656,15 +5064,15 @@
[(set (match_operand:SI 0 "register_operand" "=r")
(truncate:SI
(lshiftrt:DI (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
- (match_operand:DI 2 "uns_small_int" ""))
+ (match_operand:DI 2 "uns_small_int_operand" ""))
(const_int 32))))]
"TARGET_HARD_MUL32"
"umul\t%1, %s2, %%g0\n\trd\t%%y, %0"
[(set_attr "type" "multi")
(set_attr "length" "2")])
-;; The v8 architecture specifies that there must be 3 instructions between
-;; a y register write and a use of it for correct results.
+;; The V8 architecture specifies that there must be 3 instructions between
+;; a Y register write and a use of it for correct results.
(define_expand "divsi3"
[(parallel [(set (match_operand:SI 0 "register_operand" "=r,r")
@@ -5720,7 +5128,7 @@
(define_insn "divdi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(div:DI (match_operand:DI 1 "register_operand" "r")
- (match_operand:DI 2 "arith_double_operand" "rHI")))]
+ (match_operand:DI 2 "arith_operand" "rI")))]
"TARGET_ARCH64"
"sdivx\t%1, %2, %0"
[(set_attr "type" "idiv")])
@@ -5748,17 +5156,19 @@
;; XXX
(define_expand "udivsi3"
[(set (match_operand:SI 0 "register_operand" "")
- (udiv:SI (match_operand:SI 1 "reg_or_nonsymb_mem_operand" "")
+ (udiv:SI (match_operand:SI 1 "nonimmediate_operand" "")
(match_operand:SI 2 "input_operand" "")))]
"TARGET_V8 || TARGET_DEPRECATED_V8_INSNS"
"")
+;; The V8 architecture specifies that there must be 3 instructions between
+;; a Y register write and a use of it for correct results.
+
(define_insn "udivsi3_sp32"
[(set (match_operand:SI 0 "register_operand" "=r,&r,&r")
- (udiv:SI (match_operand:SI 1 "reg_or_nonsymb_mem_operand" "r,r,m")
+ (udiv:SI (match_operand:SI 1 "nonimmediate_operand" "r,r,m")
(match_operand:SI 2 "input_operand" "rI,m,r")))]
- "(TARGET_V8
- || TARGET_DEPRECATED_V8_INSNS)
+ "(TARGET_V8 || TARGET_DEPRECATED_V8_INSNS)
&& TARGET_ARCH32"
{
output_asm_insn ("wr\t%%g0, %%g0, %%y", operands);
@@ -5777,7 +5187,7 @@
(define_insn "udivsi3_sp64"
[(set (match_operand:SI 0 "register_operand" "=r")
- (udiv:SI (match_operand:SI 1 "reg_or_nonsymb_mem_operand" "r")
+ (udiv:SI (match_operand:SI 1 "nonimmediate_operand" "r")
(match_operand:SI 2 "input_operand" "rI")))]
"TARGET_DEPRECATED_V8_INSNS && TARGET_ARCH64"
"wr\t%%g0, 0, %%y\n\tudiv\t%1, %2, %0"
@@ -5787,7 +5197,7 @@
(define_insn "udivdi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(udiv:DI (match_operand:DI 1 "register_operand" "r")
- (match_operand:DI 2 "arith_double_operand" "rHI")))]
+ (match_operand:DI 2 "arith_operand" "rI")))]
"TARGET_ARCH64"
"udivx\t%1, %2, %0"
[(set_attr "type" "idiv")])
@@ -5844,103 +5254,73 @@
"TARGET_SPARCLET"
"umacd\t%1, %2, %L0"
[(set_attr "type" "imul")])
-
-;;- Boolean instructions
+
+
+;; Boolean instructions.
+
;; We define DImode `and' so with DImode `not' we can get
;; DImode `andn'. Other combinations are possible.
-(define_expand "anddi3"
- [(set (match_operand:DI 0 "register_operand" "")
- (and:DI (match_operand:DI 1 "arith_double_operand" "")
- (match_operand:DI 2 "arith_double_operand" "")))]
+(define_mode_macro V64I [DI V2SI V4HI V8QI])
+(define_mode_macro V32I [SI V2HI V4QI])
+
+(define_expand "and<V64I:mode>3"
+ [(set (match_operand:V64I 0 "register_operand" "")
+ (and:V64I (match_operand:V64I 1 "arith_double_operand" "")
+ (match_operand:V64I 2 "arith_double_operand" "")))]
""
"")
-(define_insn "*anddi3_sp32"
- [(set (match_operand:DI 0 "register_operand" "=r,b")
- (and:DI (match_operand:DI 1 "arith_double_operand" "%r,b")
- (match_operand:DI 2 "arith_double_operand" "rHI,b")))]
+(define_insn "*and<V64I:mode>3_sp32"
+ [(set (match_operand:V64I 0 "register_operand" "=r,b")
+ (and:V64I (match_operand:V64I 1 "arith_double_operand" "%r,b")
+ (match_operand:V64I 2 "arith_double_operand" "rHI,b")))]
"! TARGET_ARCH64"
"@
#
fand\t%1, %2, %0"
[(set_attr "type" "*,fga")
(set_attr "length" "2,*")
- (set_attr "fptype" "double")])
+ (set_attr "fptype" "*,double")])
-(define_insn "*anddi3_sp64"
- [(set (match_operand:DI 0 "register_operand" "=r,b")
- (and:DI (match_operand:DI 1 "arith_double_operand" "%r,b")
- (match_operand:DI 2 "arith_double_operand" "rHI,b")))]
+(define_insn "*and<V64I:mode>3_sp64"
+ [(set (match_operand:V64I 0 "register_operand" "=r,b")
+ (and:V64I (match_operand:V64I 1 "arith_operand" "%r,b")
+ (match_operand:V64I 2 "arith_operand" "rI,b")))]
"TARGET_ARCH64"
"@
and\t%1, %2, %0
fand\t%1, %2, %0"
[(set_attr "type" "*,fga")
- (set_attr "fptype" "double")])
+ (set_attr "fptype" "*,double")])
-(define_insn "andsi3"
- [(set (match_operand:SI 0 "register_operand" "=r,d")
- (and:SI (match_operand:SI 1 "arith_operand" "%r,d")
- (match_operand:SI 2 "arith_operand" "rI,d")))]
+(define_insn "and<V32I:mode>3"
+ [(set (match_operand:V32I 0 "register_operand" "=r,d")
+ (and:V32I (match_operand:V32I 1 "arith_operand" "%r,d")
+ (match_operand:V32I 2 "arith_operand" "rI,d")))]
""
"@
and\t%1, %2, %0
fands\t%1, %2, %0"
- [(set_attr "type" "*,fga")])
+ [(set_attr "type" "*,fga")
+ (set_attr "fptype" "*,single")])
(define_split
[(set (match_operand:SI 0 "register_operand" "")
(and:SI (match_operand:SI 1 "register_operand" "")
- (match_operand:SI 2 "" "")))
+ (match_operand:SI 2 "const_compl_high_operand" "")))
(clobber (match_operand:SI 3 "register_operand" ""))]
- "GET_CODE (operands[2]) == CONST_INT
- && !SMALL_INT32 (operands[2])
- && (INTVAL (operands[2]) & 0x3ff) == 0x3ff"
+ ""
[(set (match_dup 3) (match_dup 4))
(set (match_dup 0) (and:SI (not:SI (match_dup 3)) (match_dup 1)))]
{
operands[4] = GEN_INT (~INTVAL (operands[2]));
})
-;; Split DImode logical operations requiring two instructions.
-(define_split
- [(set (match_operand:DI 0 "register_operand" "")
- (match_operator:DI 1 "cc_arithop" ; AND, IOR, XOR
- [(match_operand:DI 2 "register_operand" "")
- (match_operand:DI 3 "arith_double_operand" "")]))]
- "! TARGET_ARCH64
- && reload_completed
- && ((GET_CODE (operands[0]) == REG
- && REGNO (operands[0]) < 32)
- || (GET_CODE (operands[0]) == SUBREG
- && GET_CODE (SUBREG_REG (operands[0])) == REG
- && REGNO (SUBREG_REG (operands[0])) < 32))"
- [(set (match_dup 4) (match_op_dup:SI 1 [(match_dup 6) (match_dup 8)]))
- (set (match_dup 5) (match_op_dup:SI 1 [(match_dup 7) (match_dup 9)]))]
-{
- operands[4] = gen_highpart (SImode, operands[0]);
- operands[5] = gen_lowpart (SImode, operands[0]);
- operands[6] = gen_highpart (SImode, operands[2]);
- operands[7] = gen_lowpart (SImode, operands[2]);
-#if HOST_BITS_PER_WIDE_INT == 32
- if (GET_CODE (operands[3]) == CONST_INT)
- {
- if (INTVAL (operands[3]) < 0)
- operands[8] = constm1_rtx;
- else
- operands[8] = const0_rtx;
- }
- else
-#endif
- operands[8] = gen_highpart_mode (SImode, DImode, operands[3]);
- operands[9] = gen_lowpart (SImode, operands[3]);
-})
-
-(define_insn_and_split "*and_not_di_sp32"
- [(set (match_operand:DI 0 "register_operand" "=r,b")
- (and:DI (not:DI (match_operand:DI 1 "register_operand" "r,b"))
- (match_operand:DI 2 "register_operand" "r,b")))]
+(define_insn_and_split "*and_not_<V64I:mode>_sp32"
+ [(set (match_operand:V64I 0 "register_operand" "=r,b")
+ (and:V64I (not:V64I (match_operand:V64I 1 "register_operand" "%r,b"))
+ (match_operand:V64I 2 "register_operand" "r,b")))]
"! TARGET_ARCH64"
"@
#
@@ -5961,87 +5341,87 @@
operands[8] = gen_lowpart (SImode, operands[2]);"
[(set_attr "type" "*,fga")
(set_attr "length" "2,*")
- (set_attr "fptype" "double")])
+ (set_attr "fptype" "*,double")])
-(define_insn "*and_not_di_sp64"
- [(set (match_operand:DI 0 "register_operand" "=r,b")
- (and:DI (not:DI (match_operand:DI 1 "register_operand" "r,b"))
- (match_operand:DI 2 "register_operand" "r,b")))]
+(define_insn "*and_not_<V64I:mode>_sp64"
+ [(set (match_operand:V64I 0 "register_operand" "=r,b")
+ (and:V64I (not:V64I (match_operand:V64I 1 "register_operand" "%r,b"))
+ (match_operand:V64I 2 "register_operand" "r,b")))]
"TARGET_ARCH64"
"@
andn\t%2, %1, %0
fandnot1\t%1, %2, %0"
[(set_attr "type" "*,fga")
- (set_attr "fptype" "double")])
+ (set_attr "fptype" "*,double")])
-(define_insn "*and_not_si"
- [(set (match_operand:SI 0 "register_operand" "=r,d")
- (and:SI (not:SI (match_operand:SI 1 "register_operand" "r,d"))
- (match_operand:SI 2 "register_operand" "r,d")))]
+(define_insn "*and_not_<V32I:mode>"
+ [(set (match_operand:V32I 0 "register_operand" "=r,d")
+ (and:V32I (not:V32I (match_operand:V32I 1 "register_operand" "%r,d"))
+ (match_operand:V32I 2 "register_operand" "r,d")))]
""
"@
andn\t%2, %1, %0
fandnot1s\t%1, %2, %0"
- [(set_attr "type" "*,fga")])
+ [(set_attr "type" "*,fga")
+ (set_attr "fptype" "*,single")])
-(define_expand "iordi3"
- [(set (match_operand:DI 0 "register_operand" "")
- (ior:DI (match_operand:DI 1 "arith_double_operand" "")
- (match_operand:DI 2 "arith_double_operand" "")))]
+(define_expand "ior<V64I:mode>3"
+ [(set (match_operand:V64I 0 "register_operand" "")
+ (ior:V64I (match_operand:V64I 1 "arith_double_operand" "")
+ (match_operand:V64I 2 "arith_double_operand" "")))]
""
"")
-(define_insn "*iordi3_sp32"
- [(set (match_operand:DI 0 "register_operand" "=r,b")
- (ior:DI (match_operand:DI 1 "arith_double_operand" "%r,b")
- (match_operand:DI 2 "arith_double_operand" "rHI,b")))]
+(define_insn "*ior<V64I:mode>3_sp32"
+ [(set (match_operand:V64I 0 "register_operand" "=r,b")
+ (ior:V64I (match_operand:V64I 1 "arith_double_operand" "%r,b")
+ (match_operand:V64I 2 "arith_double_operand" "rHI,b")))]
"! TARGET_ARCH64"
"@
#
for\t%1, %2, %0"
[(set_attr "type" "*,fga")
(set_attr "length" "2,*")
- (set_attr "fptype" "double")])
+ (set_attr "fptype" "*,double")])
-(define_insn "*iordi3_sp64"
- [(set (match_operand:DI 0 "register_operand" "=r,b")
- (ior:DI (match_operand:DI 1 "arith_double_operand" "%r,b")
- (match_operand:DI 2 "arith_double_operand" "rHI,b")))]
+(define_insn "*ior<V64I:mode>3_sp64"
+ [(set (match_operand:V64I 0 "register_operand" "=r,b")
+ (ior:V64I (match_operand:V64I 1 "arith_operand" "%r,b")
+ (match_operand:V64I 2 "arith_operand" "rI,b")))]
"TARGET_ARCH64"
"@
or\t%1, %2, %0
for\t%1, %2, %0"
[(set_attr "type" "*,fga")
- (set_attr "fptype" "double")])
+ (set_attr "fptype" "*,double")])
-(define_insn "iorsi3"
- [(set (match_operand:SI 0 "register_operand" "=r,d")
- (ior:SI (match_operand:SI 1 "arith_operand" "%r,d")
- (match_operand:SI 2 "arith_operand" "rI,d")))]
+(define_insn "ior<V32I:mode>3"
+ [(set (match_operand:V32I 0 "register_operand" "=r,d")
+ (ior:V32I (match_operand:V32I 1 "arith_operand" "%r,d")
+ (match_operand:V32I 2 "arith_operand" "rI,d")))]
""
"@
or\t%1, %2, %0
fors\t%1, %2, %0"
- [(set_attr "type" "*,fga")])
+ [(set_attr "type" "*,fga")
+ (set_attr "fptype" "*,single")])
(define_split
[(set (match_operand:SI 0 "register_operand" "")
(ior:SI (match_operand:SI 1 "register_operand" "")
- (match_operand:SI 2 "" "")))
+ (match_operand:SI 2 "const_compl_high_operand" "")))
(clobber (match_operand:SI 3 "register_operand" ""))]
- "GET_CODE (operands[2]) == CONST_INT
- && !SMALL_INT32 (operands[2])
- && (INTVAL (operands[2]) & 0x3ff) == 0x3ff"
+ ""
[(set (match_dup 3) (match_dup 4))
(set (match_dup 0) (ior:SI (not:SI (match_dup 3)) (match_dup 1)))]
{
operands[4] = GEN_INT (~INTVAL (operands[2]));
})
-(define_insn_and_split "*or_not_di_sp32"
- [(set (match_operand:DI 0 "register_operand" "=r,b")
- (ior:DI (not:DI (match_operand:DI 1 "register_operand" "r,b"))
- (match_operand:DI 2 "register_operand" "r,b")))]
+(define_insn_and_split "*or_not_<V64I:mode>_sp32"
+ [(set (match_operand:V64I 0 "register_operand" "=r,b")
+ (ior:V64I (not:V64I (match_operand:V64I 1 "register_operand" "r,b"))
+ (match_operand:V64I 2 "register_operand" "r,b")))]
"! TARGET_ARCH64"
"@
#
@@ -6062,85 +5442,77 @@
operands[8] = gen_lowpart (SImode, operands[2]);"
[(set_attr "type" "*,fga")
(set_attr "length" "2,*")
- (set_attr "fptype" "double")])
+ (set_attr "fptype" "*,double")])
-(define_insn "*or_not_di_sp64"
- [(set (match_operand:DI 0 "register_operand" "=r,b")
- (ior:DI (not:DI (match_operand:DI 1 "register_operand" "r,b"))
- (match_operand:DI 2 "register_operand" "r,b")))]
+(define_insn "*or_not_<V64I:mode>_sp64"
+ [(set (match_operand:V64I 0 "register_operand" "=r,b")
+ (ior:V64I (not:V64I (match_operand:V64I 1 "register_operand" "r,b"))
+ (match_operand:V64I 2 "register_operand" "r,b")))]
"TARGET_ARCH64"
"@
orn\t%2, %1, %0
fornot1\t%1, %2, %0"
[(set_attr "type" "*,fga")
- (set_attr "fptype" "double")])
+ (set_attr "fptype" "*,double")])
-(define_insn "*or_not_si"
- [(set (match_operand:SI 0 "register_operand" "=r,d")
- (ior:SI (not:SI (match_operand:SI 1 "register_operand" "r,d"))
- (match_operand:SI 2 "register_operand" "r,d")))]
+(define_insn "*or_not_<V32I:mode>"
+ [(set (match_operand:V32I 0 "register_operand" "=r,d")
+ (ior:V32I (not:V32I (match_operand:V32I 1 "register_operand" "r,d"))
+ (match_operand:V32I 2 "register_operand" "r,d")))]
""
"@
orn\t%2, %1, %0
fornot1s\t%1, %2, %0"
- [(set_attr "type" "*,fga")])
+ [(set_attr "type" "*,fga")
+ (set_attr "fptype" "*,single")])
-(define_expand "xordi3"
- [(set (match_operand:DI 0 "register_operand" "")
- (xor:DI (match_operand:DI 1 "arith_double_operand" "")
- (match_operand:DI 2 "arith_double_operand" "")))]
+(define_expand "xor<V64I:mode>3"
+ [(set (match_operand:V64I 0 "register_operand" "")
+ (xor:V64I (match_operand:V64I 1 "arith_double_operand" "")
+ (match_operand:V64I 2 "arith_double_operand" "")))]
""
"")
-(define_insn "*xordi3_sp32"
- [(set (match_operand:DI 0 "register_operand" "=r,b")
- (xor:DI (match_operand:DI 1 "arith_double_operand" "%r,b")
- (match_operand:DI 2 "arith_double_operand" "rHI,b")))]
+(define_insn "*xor<V64I:mode>3_sp32"
+ [(set (match_operand:V64I 0 "register_operand" "=r,b")
+ (xor:V64I (match_operand:V64I 1 "arith_double_operand" "%r,b")
+ (match_operand:V64I 2 "arith_double_operand" "rHI,b")))]
"! TARGET_ARCH64"
"@
#
fxor\t%1, %2, %0"
[(set_attr "type" "*,fga")
(set_attr "length" "2,*")
- (set_attr "fptype" "double")])
+ (set_attr "fptype" "*,double")])
-(define_insn "*xordi3_sp64"
- [(set (match_operand:DI 0 "register_operand" "=r,b")
- (xor:DI (match_operand:DI 1 "arith_double_operand" "%rJ,b")
- (match_operand:DI 2 "arith_double_operand" "rHI,b")))]
+(define_insn "*xor<V64I:mode>3_sp64"
+ [(set (match_operand:V64I 0 "register_operand" "=r,b")
+ (xor:V64I (match_operand:V64I 1 "arith_operand" "%rJ,b")
+ (match_operand:V64I 2 "arith_operand" "rI,b")))]
"TARGET_ARCH64"
"@
xor\t%r1, %2, %0
fxor\t%1, %2, %0"
[(set_attr "type" "*,fga")
- (set_attr "fptype" "double")])
+ (set_attr "fptype" "*,double")])
-(define_insn "*xordi3_sp64_dbl"
- [(set (match_operand:DI 0 "register_operand" "=r")
- (xor:DI (match_operand:DI 1 "register_operand" "r")
- (match_operand:DI 2 "const64_operand" "")))]
- "(TARGET_ARCH64
- && HOST_BITS_PER_WIDE_INT != 64)"
- "xor\t%1, %2, %0")
-
-(define_insn "xorsi3"
- [(set (match_operand:SI 0 "register_operand" "=r,d")
- (xor:SI (match_operand:SI 1 "arith_operand" "%rJ,d")
- (match_operand:SI 2 "arith_operand" "rI,d")))]
+(define_insn "xor<V32I:mode>3"
+ [(set (match_operand:V32I 0 "register_operand" "=r,d")
+ (xor:V32I (match_operand:V32I 1 "arith_operand" "%rJ,d")
+ (match_operand:V32I 2 "arith_operand" "rI,d")))]
""
"@
xor\t%r1, %2, %0
fxors\t%1, %2, %0"
- [(set_attr "type" "*,fga")])
+ [(set_attr "type" "*,fga")
+ (set_attr "fptype" "*,single")])
(define_split
[(set (match_operand:SI 0 "register_operand" "")
(xor:SI (match_operand:SI 1 "register_operand" "")
- (match_operand:SI 2 "" "")))
+ (match_operand:SI 2 "const_compl_high_operand" "")))
(clobber (match_operand:SI 3 "register_operand" ""))]
- "GET_CODE (operands[2]) == CONST_INT
- && !SMALL_INT32 (operands[2])
- && (INTVAL (operands[2]) & 0x3ff) == 0x3ff"
+ ""
[(set (match_dup 3) (match_dup 4))
(set (match_dup 0) (not:SI (xor:SI (match_dup 3) (match_dup 1))))]
{
@@ -6150,23 +5522,55 @@
(define_split
[(set (match_operand:SI 0 "register_operand" "")
(not:SI (xor:SI (match_operand:SI 1 "register_operand" "")
- (match_operand:SI 2 "" ""))))
+ (match_operand:SI 2 "const_compl_high_operand" ""))))
(clobber (match_operand:SI 3 "register_operand" ""))]
- "GET_CODE (operands[2]) == CONST_INT
- && !SMALL_INT32 (operands[2])
- && (INTVAL (operands[2]) & 0x3ff) == 0x3ff"
+ ""
[(set (match_dup 3) (match_dup 4))
(set (match_dup 0) (xor:SI (match_dup 3) (match_dup 1)))]
{
operands[4] = GEN_INT (~INTVAL (operands[2]));
})
+;; Split DImode logical operations requiring two instructions.
+(define_split
+ [(set (match_operand:V64I 0 "register_operand" "")
+ (match_operator:V64I 1 "cc_arith_operator" ; AND, IOR, XOR
+ [(match_operand:V64I 2 "register_operand" "")
+ (match_operand:V64I 3 "arith_double_operand" "")]))]
+ "! TARGET_ARCH64
+ && reload_completed
+ && ((GET_CODE (operands[0]) == REG
+ && REGNO (operands[0]) < 32)
+ || (GET_CODE (operands[0]) == SUBREG
+ && GET_CODE (SUBREG_REG (operands[0])) == REG
+ && REGNO (SUBREG_REG (operands[0])) < 32))"
+ [(set (match_dup 4) (match_op_dup:SI 1 [(match_dup 6) (match_dup 8)]))
+ (set (match_dup 5) (match_op_dup:SI 1 [(match_dup 7) (match_dup 9)]))]
+{
+ operands[4] = gen_highpart (SImode, operands[0]);
+ operands[5] = gen_lowpart (SImode, operands[0]);
+ operands[6] = gen_highpart (SImode, operands[2]);
+ operands[7] = gen_lowpart (SImode, operands[2]);
+#if HOST_BITS_PER_WIDE_INT == 32
+ if (GET_CODE (operands[3]) == CONST_INT && <V64I:MODE>mode == DImode)
+ {
+ if (INTVAL (operands[3]) < 0)
+ operands[8] = constm1_rtx;
+ else
+ operands[8] = const0_rtx;
+ }
+ else
+#endif
+ operands[8] = gen_highpart_mode (SImode, <V64I:MODE>mode, operands[3]);
+ operands[9] = gen_lowpart (SImode, operands[3]);
+})
+
;; xnor patterns. Note that (a ^ ~b) == (~a ^ b) == ~(a ^ b).
;; Combine now canonicalizes to the rightmost expression.
-(define_insn_and_split "*xor_not_di_sp32"
- [(set (match_operand:DI 0 "register_operand" "=r,b")
- (not:DI (xor:DI (match_operand:DI 1 "register_operand" "r,b")
- (match_operand:DI 2 "register_operand" "r,b"))))]
+(define_insn_and_split "*xor_not_<V64I:mode>_sp32"
+ [(set (match_operand:V64I 0 "register_operand" "=r,b")
+ (not:V64I (xor:V64I (match_operand:V64I 1 "register_operand" "r,b")
+ (match_operand:V64I 2 "register_operand" "r,b"))))]
"! TARGET_ARCH64"
"@
#
@@ -6187,28 +5591,29 @@
operands[8] = gen_lowpart (SImode, operands[2]);"
[(set_attr "type" "*,fga")
(set_attr "length" "2,*")
- (set_attr "fptype" "double")])
+ (set_attr "fptype" "*,double")])
-(define_insn "*xor_not_di_sp64"
- [(set (match_operand:DI 0 "register_operand" "=r,b")
- (not:DI (xor:DI (match_operand:DI 1 "reg_or_0_operand" "rJ,b")
- (match_operand:DI 2 "arith_double_operand" "rHI,b"))))]
+(define_insn "*xor_not_<V64I:mode>_sp64"
+ [(set (match_operand:V64I 0 "register_operand" "=r,b")
+ (not:V64I (xor:V64I (match_operand:V64I 1 "register_or_zero_operand" "rJ,b")
+ (match_operand:V64I 2 "arith_operand" "rI,b"))))]
"TARGET_ARCH64"
"@
xnor\t%r1, %2, %0
fxnor\t%1, %2, %0"
[(set_attr "type" "*,fga")
- (set_attr "fptype" "double")])
+ (set_attr "fptype" "*,double")])
-(define_insn "*xor_not_si"
- [(set (match_operand:SI 0 "register_operand" "=r,d")
- (not:SI (xor:SI (match_operand:SI 1 "reg_or_0_operand" "rJ,d")
- (match_operand:SI 2 "arith_operand" "rI,d"))))]
+(define_insn "*xor_not_<V32I:mode>"
+ [(set (match_operand:V32I 0 "register_operand" "=r,d")
+ (not:V32I (xor:V32I (match_operand:V32I 1 "register_or_zero_operand" "rJ,d")
+ (match_operand:V32I 2 "arith_operand" "rI,d"))))]
""
"@
xnor\t%r1, %2, %0
fxnors\t%1, %2, %0"
- [(set_attr "type" "*,fga")])
+ [(set_attr "type" "*,fga")
+ (set_attr "fptype" "*,single")])
;; These correspond to the above in the case where we also (or only)
;; want to set the condition code.
@@ -6216,7 +5621,7 @@
(define_insn "*cmp_cc_arith_op"
[(set (reg:CC 100)
(compare:CC
- (match_operator:SI 2 "cc_arithop"
+ (match_operator:SI 2 "cc_arith_operator"
[(match_operand:SI 0 "arith_operand" "%r")
(match_operand:SI 1 "arith_operand" "rI")])
(const_int 0)))]
@@ -6227,9 +5632,9 @@
(define_insn "*cmp_ccx_arith_op"
[(set (reg:CCX 100)
(compare:CCX
- (match_operator:DI 2 "cc_arithop"
- [(match_operand:DI 0 "arith_double_operand" "%r")
- (match_operand:DI 1 "arith_double_operand" "rHI")])
+ (match_operator:DI 2 "cc_arith_operator"
+ [(match_operand:DI 0 "arith_operand" "%r")
+ (match_operand:DI 1 "arith_operand" "rI")])
(const_int 0)))]
"TARGET_ARCH64"
"%A2cc\t%0, %1, %%g0"
@@ -6238,12 +5643,12 @@
(define_insn "*cmp_cc_arith_op_set"
[(set (reg:CC 100)
(compare:CC
- (match_operator:SI 3 "cc_arithop"
+ (match_operator:SI 3 "cc_arith_operator"
[(match_operand:SI 1 "arith_operand" "%r")
(match_operand:SI 2 "arith_operand" "rI")])
(const_int 0)))
(set (match_operand:SI 0 "register_operand" "=r")
- (match_operator:SI 4 "cc_arithop" [(match_dup 1) (match_dup 2)]))]
+ (match_operator:SI 4 "cc_arith_operator" [(match_dup 1) (match_dup 2)]))]
"GET_CODE (operands[3]) == GET_CODE (operands[4])"
"%A3cc\t%1, %2, %0"
[(set_attr "type" "compare")])
@@ -6251,12 +5656,12 @@
(define_insn "*cmp_ccx_arith_op_set"
[(set (reg:CCX 100)
(compare:CCX
- (match_operator:DI 3 "cc_arithop"
- [(match_operand:DI 1 "arith_double_operand" "%r")
- (match_operand:DI 2 "arith_double_operand" "rHI")])
+ (match_operator:DI 3 "cc_arith_operator"
+ [(match_operand:DI 1 "arith_operand" "%r")
+ (match_operand:DI 2 "arith_operand" "rI")])
(const_int 0)))
(set (match_operand:DI 0 "register_operand" "=r")
- (match_operator:DI 4 "cc_arithop" [(match_dup 1) (match_dup 2)]))]
+ (match_operator:DI 4 "cc_arith_operator" [(match_dup 1) (match_dup 2)]))]
"TARGET_ARCH64 && GET_CODE (operands[3]) == GET_CODE (operands[4])"
"%A3cc\t%1, %2, %0"
[(set_attr "type" "compare")])
@@ -6264,7 +5669,7 @@
(define_insn "*cmp_cc_xor_not"
[(set (reg:CC 100)
(compare:CC
- (not:SI (xor:SI (match_operand:SI 0 "reg_or_0_operand" "%rJ")
+ (not:SI (xor:SI (match_operand:SI 0 "register_or_zero_operand" "%rJ")
(match_operand:SI 1 "arith_operand" "rI")))
(const_int 0)))]
""
@@ -6274,8 +5679,8 @@
(define_insn "*cmp_ccx_xor_not"
[(set (reg:CCX 100)
(compare:CCX
- (not:DI (xor:DI (match_operand:DI 0 "reg_or_0_operand" "%rJ")
- (match_operand:DI 1 "arith_double_operand" "rHI")))
+ (not:DI (xor:DI (match_operand:DI 0 "register_or_zero_operand" "%rJ")
+ (match_operand:DI 1 "arith_operand" "rI")))
(const_int 0)))]
"TARGET_ARCH64"
"xnorcc\t%r0, %1, %%g0"
@@ -6284,7 +5689,7 @@
(define_insn "*cmp_cc_xor_not_set"
[(set (reg:CC 100)
(compare:CC
- (not:SI (xor:SI (match_operand:SI 1 "reg_or_0_operand" "%rJ")
+ (not:SI (xor:SI (match_operand:SI 1 "register_or_zero_operand" "%rJ")
(match_operand:SI 2 "arith_operand" "rI")))
(const_int 0)))
(set (match_operand:SI 0 "register_operand" "=r")
@@ -6296,8 +5701,8 @@
(define_insn "*cmp_ccx_xor_not_set"
[(set (reg:CCX 100)
(compare:CCX
- (not:DI (xor:DI (match_operand:DI 1 "reg_or_0_operand" "%rJ")
- (match_operand:DI 2 "arith_double_operand" "rHI")))
+ (not:DI (xor:DI (match_operand:DI 1 "register_or_zero_operand" "%rJ")
+ (match_operand:DI 2 "arith_operand" "rI")))
(const_int 0)))
(set (match_operand:DI 0 "register_operand" "=r")
(not:DI (xor:DI (match_dup 1) (match_dup 2))))]
@@ -6308,9 +5713,9 @@
(define_insn "*cmp_cc_arith_op_not"
[(set (reg:CC 100)
(compare:CC
- (match_operator:SI 2 "cc_arithopn"
+ (match_operator:SI 2 "cc_arith_not_operator"
[(not:SI (match_operand:SI 0 "arith_operand" "rI"))
- (match_operand:SI 1 "reg_or_0_operand" "rJ")])
+ (match_operand:SI 1 "register_or_zero_operand" "rJ")])
(const_int 0)))]
""
"%B2cc\t%r1, %0, %%g0"
@@ -6319,9 +5724,9 @@
(define_insn "*cmp_ccx_arith_op_not"
[(set (reg:CCX 100)
(compare:CCX
- (match_operator:DI 2 "cc_arithopn"
- [(not:DI (match_operand:DI 0 "arith_double_operand" "rHI"))
- (match_operand:DI 1 "reg_or_0_operand" "rJ")])
+ (match_operator:DI 2 "cc_arith_not_operator"
+ [(not:DI (match_operand:DI 0 "arith_operand" "rI"))
+ (match_operand:DI 1 "register_or_zero_operand" "rJ")])
(const_int 0)))]
"TARGET_ARCH64"
"%B2cc\t%r1, %0, %%g0"
@@ -6330,12 +5735,12 @@
(define_insn "*cmp_cc_arith_op_not_set"
[(set (reg:CC 100)
(compare:CC
- (match_operator:SI 3 "cc_arithopn"
+ (match_operator:SI 3 "cc_arith_not_operator"
[(not:SI (match_operand:SI 1 "arith_operand" "rI"))
- (match_operand:SI 2 "reg_or_0_operand" "rJ")])
+ (match_operand:SI 2 "register_or_zero_operand" "rJ")])
(const_int 0)))
(set (match_operand:SI 0 "register_operand" "=r")
- (match_operator:SI 4 "cc_arithopn"
+ (match_operator:SI 4 "cc_arith_not_operator"
[(not:SI (match_dup 1)) (match_dup 2)]))]
"GET_CODE (operands[3]) == GET_CODE (operands[4])"
"%B3cc\t%r2, %1, %0"
@@ -6344,12 +5749,12 @@
(define_insn "*cmp_ccx_arith_op_not_set"
[(set (reg:CCX 100)
(compare:CCX
- (match_operator:DI 3 "cc_arithopn"
- [(not:DI (match_operand:DI 1 "arith_double_operand" "rHI"))
- (match_operand:DI 2 "reg_or_0_operand" "rJ")])
+ (match_operator:DI 3 "cc_arith_not_operator"
+ [(not:DI (match_operand:DI 1 "arith_operand" "rI"))
+ (match_operand:DI 2 "register_or_zero_operand" "rJ")])
(const_int 0)))
(set (match_operand:DI 0 "register_operand" "=r")
- (match_operator:DI 4 "cc_arithopn"
+ (match_operator:DI 4 "cc_arith_not_operator"
[(not:DI (match_dup 1)) (match_dup 2)]))]
"TARGET_ARCH64 && GET_CODE (operands[3]) == GET_CODE (operands[4])"
"%B3cc\t%r2, %1, %0"
@@ -6418,7 +5823,7 @@
(define_insn "*cmp_ccx_neg"
[(set (reg:CCX_NOOV 100)
- (compare:CCX_NOOV (neg:DI (match_operand:DI 0 "arith_double_operand" "rHI"))
+ (compare:CCX_NOOV (neg:DI (match_operand:DI 0 "arith_operand" "rI"))
(const_int 0)))]
"TARGET_ARCH64"
"subcc\t%%g0, %0, %%g0"
@@ -6436,7 +5841,7 @@
(define_insn "*cmp_ccx_set_neg"
[(set (reg:CCX_NOOV 100)
- (compare:CCX_NOOV (neg:DI (match_operand:DI 1 "arith_double_operand" "rHI"))
+ (compare:CCX_NOOV (neg:DI (match_operand:DI 1 "arith_operand" "rI"))
(const_int 0)))
(set (match_operand:DI 0 "register_operand" "=r")
(neg:DI (match_dup 1)))]
@@ -6446,15 +5851,15 @@
;; We cannot use the "not" pseudo insn because the Sun assembler
;; does not know how to make it work for constants.
-(define_expand "one_cmpldi2"
- [(set (match_operand:DI 0 "register_operand" "")
- (not:DI (match_operand:DI 1 "register_operand" "")))]
+(define_expand "one_cmpl<V64I:mode>2"
+ [(set (match_operand:V64I 0 "register_operand" "")
+ (not:V64I (match_operand:V64I 1 "register_operand" "")))]
""
"")
-(define_insn_and_split "*one_cmpldi2_sp32"
- [(set (match_operand:DI 0 "register_operand" "=r,b")
- (not:DI (match_operand:DI 1 "register_operand" "r,b")))]
+(define_insn_and_split "*one_cmpl<V64I:mode>2_sp32"
+ [(set (match_operand:V64I 0 "register_operand" "=r,b")
+ (not:V64I (match_operand:V64I 1 "register_operand" "r,b")))]
"! TARGET_ARCH64"
"@
#
@@ -6473,26 +5878,27 @@
operands[5] = gen_lowpart (SImode, operands[1]);"
[(set_attr "type" "*,fga")
(set_attr "length" "2,*")
- (set_attr "fptype" "double")])
+ (set_attr "fptype" "*,double")])
-(define_insn "*one_cmpldi2_sp64"
- [(set (match_operand:DI 0 "register_operand" "=r,b")
- (not:DI (match_operand:DI 1 "arith_double_operand" "rHI,b")))]
+(define_insn "*one_cmpl<V64I:mode>2_sp64"
+ [(set (match_operand:V64I 0 "register_operand" "=r,b")
+ (not:V64I (match_operand:V64I 1 "arith_operand" "rI,b")))]
"TARGET_ARCH64"
"@
xnor\t%%g0, %1, %0
fnot1\t%1, %0"
[(set_attr "type" "*,fga")
- (set_attr "fptype" "double")])
+ (set_attr "fptype" "*,double")])
-(define_insn "one_cmplsi2"
- [(set (match_operand:SI 0 "register_operand" "=r,d")
- (not:SI (match_operand:SI 1 "arith_operand" "rI,d")))]
+(define_insn "one_cmpl<V32I:mode>2"
+ [(set (match_operand:V32I 0 "register_operand" "=r,d")
+ (not:V32I (match_operand:V32I 1 "arith_operand" "rI,d")))]
""
"@
xnor\t%%g0, %1, %0
fnot1s\t%1, %0"
- [(set_attr "type" "*,fga")])
+ [(set_attr "type" "*,fga")
+ (set_attr "fptype" "*,single")])
(define_insn "*cmp_cc_not"
[(set (reg:CC 100)
@@ -6504,7 +5910,7 @@
(define_insn "*cmp_ccx_not"
[(set (reg:CCX 100)
- (compare:CCX (not:DI (match_operand:DI 0 "arith_double_operand" "rHI"))
+ (compare:CCX (not:DI (match_operand:DI 0 "arith_operand" "rI"))
(const_int 0)))]
"TARGET_ARCH64"
"xnorcc\t%%g0, %0, %%g0"
@@ -6522,7 +5928,7 @@
(define_insn "*cmp_ccx_set_not"
[(set (reg:CCX 100)
- (compare:CCX (not:DI (match_operand:DI 1 "arith_double_operand" "rHI"))
+ (compare:CCX (not:DI (match_operand:DI 1 "arith_operand" "rI"))
(const_int 0)))
(set (match_operand:DI 0 "register_operand" "=r")
(not:DI (match_dup 1)))]
@@ -6549,7 +5955,8 @@
"TARGET_ARCH64"
"orcc\t%1, 0, %0"
[(set_attr "type" "compare")])
-
+
+
;; Floating point arithmetic instructions.
(define_expand "addtf3"
@@ -6909,8 +6316,9 @@
"TARGET_FPU"
"fsqrts\t%1, %0"
[(set_attr "type" "fpsqrts")])
-
-;;- arithmetic shift instructions
+
+
+;; Arithmetic shift instructions.
(define_insn "ashlsi3"
[(set (match_operand:SI 0 "register_operand" "=r")
@@ -6918,14 +6326,12 @@
(match_operand:SI 2 "arith_operand" "rI")))]
""
{
- if (operands[2] == const1_rtx)
- return "add\t%1, %1, %0";
if (GET_CODE (operands[2]) == CONST_INT)
operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f);
return "sll\t%1, %2, %0";
}
[(set (attr "type")
- (if_then_else (match_operand 2 "const1_operand" "")
+ (if_then_else (match_operand 2 "const_one_operand" "")
(const_string "ialu") (const_string "shift")))])
(define_expand "ashldi3"
@@ -6949,14 +6355,12 @@
(match_operand:SI 2 "arith_operand" "rI")))]
"TARGET_ARCH64"
{
- if (operands[2] == const1_rtx)
- return "add\t%1, %1, %0";
if (GET_CODE (operands[2]) == CONST_INT)
operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f);
return "sllx\t%1, %2, %0";
}
[(set (attr "type")
- (if_then_else (match_operand 2 "const1_operand" "")
+ (if_then_else (match_operand 2 "const_one_operand" "")
(const_string "ialu") (const_string "shift")))])
;; XXX UGH!
@@ -6966,7 +6370,7 @@
(match_operand:SI 2 "arith_operand" "rI,rI,rI")))
(clobber (match_scratch:SI 3 "=X,X,&h"))]
"TARGET_V8PLUS"
- { return sparc_v8plus_shift (operands, insn, "sllx"); }
+ "* return output_v8plus_shift (operands, insn, \"sllx\");"
[(set_attr "type" "multi")
(set_attr "length" "5,5,6")])
@@ -7033,17 +6437,10 @@
[(set (match_operand:DI 0 "register_operand" "=r")
(ashiftrt:DI (ashift:DI (subreg:DI (match_operand:SI 1 "register_operand" "r") 0)
(const_int 32))
- (match_operand:SI 2 "small_int_or_double" "n")))]
- "TARGET_ARCH64
- && ((GET_CODE (operands[2]) == CONST_INT
- && INTVAL (operands[2]) >= 32 && INTVAL (operands[2]) < 64)
- || (GET_CODE (operands[2]) == CONST_DOUBLE
- && !CONST_DOUBLE_HIGH (operands[2])
- && CONST_DOUBLE_LOW (operands[2]) >= 32
- && CONST_DOUBLE_LOW (operands[2]) < 64))"
+ (match_operand:SI 2 "small_int_operand" "I")))]
+ "TARGET_ARCH64 && INTVAL (operands[2]) >= 32 && INTVAL (operands[2]) < 64"
{
operands[2] = GEN_INT (INTVAL (operands[2]) - 32);
-
return "sra\t%1, %2, %0";
}
[(set_attr "type" "shift")])
@@ -7083,7 +6480,7 @@
(match_operand:SI 2 "arith_operand" "rI,rI,rI")))
(clobber (match_scratch:SI 3 "=X,X,&h"))]
"TARGET_V8PLUS"
- { return sparc_v8plus_shift (operands, insn, "srax"); }
+ "* return output_v8plus_shift (operands, insn, \"srax\");"
[(set_attr "type" "multi")
(set_attr "length" "5,5,6")])
@@ -7106,14 +6503,8 @@
[(set (match_operand:DI 0 "register_operand" "=r")
(and:DI (subreg:DI (lshiftrt:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:SI 2 "arith_operand" "r")) 0)
- (match_operand 3 "" "")))]
- "TARGET_ARCH64
- && ((GET_CODE (operands[3]) == CONST_DOUBLE
- && CONST_DOUBLE_HIGH (operands[3]) == 0
- && CONST_DOUBLE_LOW (operands[3]) == 0xffffffff)
- || (HOST_BITS_PER_WIDE_INT >= 64
- && GET_CODE (operands[3]) == CONST_INT
- && (unsigned HOST_WIDE_INT) INTVAL (operands[3]) == 0xffffffff))"
+ (match_operand 3 "const_int_operand" "")))]
+ "TARGET_ARCH64 && (unsigned HOST_WIDE_INT) INTVAL (operands[3]) == 0xffffffff"
"srl\t%1, %2, %0"
[(set_attr "type" "shift")])
@@ -7123,17 +6514,11 @@
(define_insn "*lshrsi3_extend2"
[(set (match_operand:DI 0 "register_operand" "=r")
(zero_extract:DI (subreg:DI (match_operand:SI 1 "register_operand" "r") 0)
- (match_operand 2 "small_int_or_double" "n")
+ (match_operand 2 "small_int_operand" "I")
(const_int 32)))]
- "TARGET_ARCH64
- && ((GET_CODE (operands[2]) == CONST_INT
- && (unsigned HOST_WIDE_INT) INTVAL (operands[2]) < 32)
- || (GET_CODE (operands[2]) == CONST_DOUBLE
- && CONST_DOUBLE_HIGH (operands[2]) == 0
- && (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (operands[2]) < 32))"
+ "TARGET_ARCH64 && (unsigned HOST_WIDE_INT) INTVAL (operands[2]) < 32"
{
operands[2] = GEN_INT (32 - INTVAL (operands[2]));
-
return "srl\t%1, %2, %0";
}
[(set_attr "type" "shift")])
@@ -7172,7 +6557,7 @@
(match_operand:SI 2 "arith_operand" "rI,rI,rI")))
(clobber (match_scratch:SI 3 "=X,X,&h"))]
"TARGET_V8PLUS"
- { return sparc_v8plus_shift (operands, insn, "srlx"); }
+ "* return output_v8plus_shift (operands, insn, \"srlx\");"
[(set_attr "type" "multi")
(set_attr "length" "5,5,6")])
@@ -7180,16 +6565,10 @@
[(set (match_operand:SI 0 "register_operand" "=r")
(ashiftrt:SI (subreg:SI (lshiftrt:DI (match_operand:DI 1 "register_operand" "r")
(const_int 32)) 4)
- (match_operand:SI 2 "small_int_or_double" "n")))]
- "TARGET_ARCH64
- && ((GET_CODE (operands[2]) == CONST_INT
- && (unsigned HOST_WIDE_INT) INTVAL (operands[2]) < 32)
- || (GET_CODE (operands[2]) == CONST_DOUBLE
- && !CONST_DOUBLE_HIGH (operands[2])
- && (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (operands[2]) < 32))"
+ (match_operand:SI 2 "small_int_operand" "I")))]
+ "TARGET_ARCH64 && (unsigned HOST_WIDE_INT) INTVAL (operands[2]) < 32"
{
operands[2] = GEN_INT (INTVAL (operands[2]) + 32);
-
return "srax\t%1, %2, %0";
}
[(set_attr "type" "shift")])
@@ -7198,16 +6577,10 @@
[(set (match_operand:SI 0 "register_operand" "=r")
(lshiftrt:SI (subreg:SI (ashiftrt:DI (match_operand:DI 1 "register_operand" "r")
(const_int 32)) 4)
- (match_operand:SI 2 "small_int_or_double" "n")))]
- "TARGET_ARCH64
- && ((GET_CODE (operands[2]) == CONST_INT
- && (unsigned HOST_WIDE_INT) INTVAL (operands[2]) < 32)
- || (GET_CODE (operands[2]) == CONST_DOUBLE
- && !CONST_DOUBLE_HIGH (operands[2])
- && (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (operands[2]) < 32))"
+ (match_operand:SI 2 "small_int_operand" "I")))]
+ "TARGET_ARCH64 && (unsigned HOST_WIDE_INT) INTVAL (operands[2]) < 32"
{
operands[2] = GEN_INT (INTVAL (operands[2]) + 32);
-
return "srlx\t%1, %2, %0";
}
[(set_attr "type" "shift")])
@@ -7215,10 +6588,9 @@
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(ashiftrt:SI (subreg:SI (ashiftrt:DI (match_operand:DI 1 "register_operand" "r")
- (match_operand:SI 2 "small_int_or_double" "n")) 4)
- (match_operand:SI 3 "small_int_or_double" "n")))]
+ (match_operand:SI 2 "small_int_operand" "I")) 4)
+ (match_operand:SI 3 "small_int_operand" "I")))]
"TARGET_ARCH64
- && GET_CODE (operands[2]) == CONST_INT && GET_CODE (operands[3]) == CONST_INT
&& (unsigned HOST_WIDE_INT) INTVAL (operands[2]) >= 32
&& (unsigned HOST_WIDE_INT) INTVAL (operands[3]) < 32
&& (unsigned HOST_WIDE_INT) (INTVAL (operands[2]) + INTVAL (operands[3])) < 64"
@@ -7232,10 +6604,9 @@
(define_insn ""
[(set (match_operand:SI 0 "register_operand" "=r")
(lshiftrt:SI (subreg:SI (lshiftrt:DI (match_operand:DI 1 "register_operand" "r")
- (match_operand:SI 2 "small_int_or_double" "n")) 4)
- (match_operand:SI 3 "small_int_or_double" "n")))]
+ (match_operand:SI 2 "small_int_operand" "I")) 4)
+ (match_operand:SI 3 "small_int_operand" "I")))]
"TARGET_ARCH64
- && GET_CODE (operands[2]) == CONST_INT && GET_CODE (operands[3]) == CONST_INT
&& (unsigned HOST_WIDE_INT) INTVAL (operands[2]) >= 32
&& (unsigned HOST_WIDE_INT) INTVAL (operands[3]) < 32
&& (unsigned HOST_WIDE_INT) (INTVAL (operands[2]) + INTVAL (operands[3])) < 64"
@@ -7245,8 +6616,10 @@
return "srlx\t%1, %2, %0";
}
[(set_attr "type" "shift")])
-
-;; Unconditional and other jump instructions
+
+
+;; Unconditional and other jump instructions.
+
(define_insn "jump"
[(set (pc) (label_ref (match_operand 0 "" "")))]
""
@@ -7258,8 +6631,7 @@
(use (label_ref (match_operand 1 "" "")))])]
""
{
- if (GET_MODE (operands[0]) != CASE_VECTOR_MODE)
- abort ();
+ gcc_assert (GET_MODE (operands[0]) == CASE_VECTOR_MODE);
/* In pic mode, our address differences are against the base of the
table. Add that base value back in; CSE ought to be able to combine
@@ -7290,16 +6662,9 @@
"jmp\t%a0%#"
[(set_attr "type" "uncond_branch")])
-;; This pattern recognizes the "instruction" that appears in
-;; a function call that wants a structure value,
-;; to inform the called function if compiled with Sun CC.
-;(define_insn "*unimp_insn"
-; [(match_operand:SI 0 "immediate_operand" "")]
-; "GET_CODE (operands[0]) == CONST_INT && INTVAL (operands[0]) > 0"
-; "unimp\t%0"
-; [(set_attr "type" "marker")])
-;;- jump to subroutine
+;; Jump to subroutine instructions.
+
(define_expand "call"
;; Note that this expression is not used for generating RTL.
;; All the RTL is generated explicitly below.
@@ -7309,10 +6674,11 @@
;; operands[3] is struct_value_size_rtx.
""
{
- rtx fn_rtx, nregs_rtx;
+ rtx fn_rtx;
- if (GET_MODE (operands[0]) != FUNCTION_MODE)
- abort ();
+ gcc_assert (GET_MODE (operands[0]) == FUNCTION_MODE);
+
+ gcc_assert (GET_CODE (operands[3]) == CONST_INT);
if (GET_CODE (XEXP (operands[0], 0)) == LABEL_REF)
{
@@ -7323,6 +6689,7 @@
call-clobbered registers? We lose this if it is a JUMP_INSN.
Why cannot we have delay slots filled if it were a CALL? */
+ /* We accept negative sizes for untyped calls. */
if (! TARGET_ARCH64 && INTVAL (operands[3]) != 0)
emit_jump_insn
(gen_rtx_PARALLEL
@@ -7343,42 +6710,22 @@
fn_rtx = operands[0];
- /* Count the number of parameter registers being used by this call.
- if that argument is NULL, it means we are using them all, which
- means 6 on the sparc. */
-#if 0
- if (operands[2])
- nregs_rtx = GEN_INT (REGNO (operands[2]) - 8);
- else
- nregs_rtx = GEN_INT (6);
-#else
- nregs_rtx = const0_rtx;
-#endif
-
+ /* We accept negative sizes for untyped calls. */
if (! TARGET_ARCH64 && INTVAL (operands[3]) != 0)
emit_call_insn
(gen_rtx_PARALLEL
(VOIDmode,
- gen_rtvec (3, gen_rtx_CALL (VOIDmode, fn_rtx, nregs_rtx),
+ gen_rtvec (3, gen_rtx_CALL (VOIDmode, fn_rtx, const0_rtx),
operands[3],
gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 15)))));
else
emit_call_insn
(gen_rtx_PARALLEL
(VOIDmode,
- gen_rtvec (2, gen_rtx_CALL (VOIDmode, fn_rtx, nregs_rtx),
+ gen_rtvec (2, gen_rtx_CALL (VOIDmode, fn_rtx, const0_rtx),
gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 15)))));
finish_call:
-#if 0
- /* If this call wants a structure value,
- emit an unimp insn to let the called function know about this. */
- if (! TARGET_ARCH64 && INTVAL (operands[3]) > 0)
- {
- rtx insn = emit_insn (operands[3]);
- SCHED_GROUP_P (insn) = 1;
- }
-#endif
DONE;
})
@@ -7430,8 +6777,11 @@
(match_operand 2 "immediate_operand" "")
(clobber (reg:SI 15))]
;;- Do not use operand 1 for most machines.
- "! TARGET_ARCH64 && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 0"
- "call\t%a0, %1\n\tnop\n\tunimp\t%2"
+ "! TARGET_ARCH64 && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) > 0"
+{
+ operands[2] = GEN_INT (INTVAL (operands[2]) & 0xfff);
+ return "call\t%a0, %1\n\t nop\n\tunimp\t%2";
+}
[(set_attr "type" "call_no_delay_slot")
(set_attr "length" "3")])
@@ -7443,8 +6793,11 @@
(match_operand 2 "immediate_operand" "")
(clobber (reg:SI 15))]
;;- Do not use operand 1 for most machines.
- "! TARGET_ARCH64 && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) >= 0"
- "call\t%a0, %1\n\tnop\n\tunimp\t%2"
+ "! TARGET_ARCH64 && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) > 0"
+{
+ operands[2] = GEN_INT (INTVAL (operands[2]) & 0xfff);
+ return "call\t%a0, %1\n\t nop\n\tunimp\t%2";
+}
[(set_attr "type" "call_no_delay_slot")
(set_attr "length" "3")])
@@ -7457,11 +6810,12 @@
(clobber (reg:SI 15))]
;;- Do not use operand 1 for most machines.
"! TARGET_ARCH64 && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0"
- "call\t%a0, %1\n\tnop\n\tnop"
+ "call\t%a0, %1\n\t nop\n\tnop"
[(set_attr "type" "call_no_delay_slot")
(set_attr "length" "3")])
-;; This is a call that wants a structure value.
+;; This is a call that may want a structure value. This is used for
+;; untyped_calls.
(define_insn "*call_symbolic_untyped_struct_value_sp32"
[(call (mem:SI (match_operand:SI 0 "symbolic_operand" "s"))
(match_operand 1 "" ""))
@@ -7469,7 +6823,7 @@
(clobber (reg:SI 15))]
;;- Do not use operand 1 for most machines.
"! TARGET_ARCH64 && GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0"
- "call\t%a0, %1\n\tnop\n\tnop"
+ "call\t%a0, %1\n\t nop\n\tnop"
[(set_attr "type" "call_no_delay_slot")
(set_attr "length" "3")])
@@ -7483,26 +6837,16 @@
;; operand 3 is next_arg_register
""
{
- rtx fn_rtx, nregs_rtx;
+ rtx fn_rtx;
rtvec vec;
- if (GET_MODE (operands[1]) != FUNCTION_MODE)
- abort ();
+ gcc_assert (GET_MODE (operands[1]) == FUNCTION_MODE);
fn_rtx = operands[1];
-#if 0
- if (operands[3])
- nregs_rtx = GEN_INT (REGNO (operands[3]) - 8);
- else
- nregs_rtx = GEN_INT (6);
-#else
- nregs_rtx = const0_rtx;
-#endif
-
vec = gen_rtvec (2,
gen_rtx_SET (VOIDmode, operands[0],
- gen_rtx_CALL (VOIDmode, fn_rtx, nregs_rtx)),
+ gen_rtx_CALL (VOIDmode, fn_rtx, const0_rtx)),
gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 15)));
emit_call_insn (gen_rtx_PARALLEL (VOIDmode, vec));
@@ -7553,21 +6897,22 @@
(define_expand "untyped_call"
[(parallel [(call (match_operand 0 "" "")
(const_int 0))
- (match_operand 1 "" "")
+ (match_operand:BLK 1 "memory_operand" "")
(match_operand 2 "" "")])]
""
{
- int i;
+ rtx valreg1 = gen_rtx_REG (DImode, 8);
+ rtx valreg2 = gen_rtx_REG (TARGET_ARCH64 ? TFmode : DFmode, 32);
+ rtx result = operands[1];
/* Pass constm1 to indicate that it may expect a structure value, but
we don't know what size it is. */
emit_call_insn (GEN_CALL (operands[0], const0_rtx, NULL, constm1_rtx));
- for (i = 0; i < XVECLEN (operands[2], 0); i++)
- {
- rtx set = XVECEXP (operands[2], 0, i);
- emit_move_insn (SET_DEST (set), SET_SRC (set));
- }
+ /* Save the function value registers. */
+ emit_move_insn (adjust_address (result, DImode, 0), valreg1);
+ emit_move_insn (adjust_address (result, TARGET_ARCH64 ? TFmode : DFmode, 8),
+ valreg2);
/* The optimizer does not know that the call sets the function value
registers we stored in the result block. We avoid problems by
@@ -7578,7 +6923,8 @@
DONE;
})
-;;- tail calls
+;; Tail call instructions.
+
(define_expand "sibcall"
[(parallel [(call (match_operand 0 "call_operand" "") (const_int 0))
(return)])]
@@ -7626,10 +6972,77 @@
"* return output_sibcall(insn, operands[1]);"
[(set_attr "type" "sibcall")])
-(define_expand "sibcall_epilogue"
+
+;; Special instructions.
+
+(define_expand "prologue"
[(const_int 0)]
""
- "DONE;")
+{
+ sparc_expand_prologue ();
+ DONE;
+})
+
+;; The "save register window" insn is modelled as follows so that the DWARF-2
+;; backend automatically emits the required call frame debugging information
+;; while it is parsing it. Therefore, the pattern should not be modified
+;; without first studying the impact of the changes on the debug info.
+;; [(set (%fp) (%sp))
+;; (set (%sp) (unspec_volatile [(%sp) (-frame_size)] UNSPECV_SAVEW))
+;; (set (%i7) (%o7))]
+
+(define_insn "save_register_window<P:mode>"
+ [(set (reg:P 30) (reg:P 14))
+ (set (reg:P 14) (unspec_volatile:P [(reg:P 14)
+ (match_operand:P 0 "arith_operand" "rI")] UNSPECV_SAVEW))
+ (set (reg:P 31) (reg:P 15))]
+ ""
+ "save\t%%sp, %0, %%sp"
+ [(set_attr "type" "savew")])
+
+(define_expand "epilogue"
+ [(return)]
+ ""
+{
+ sparc_expand_epilogue ();
+})
+
+(define_expand "sibcall_epilogue"
+ [(return)]
+ ""
+{
+ sparc_expand_epilogue ();
+ DONE;
+})
+
+(define_expand "return"
+ [(return)]
+ "sparc_can_use_return_insn_p ()"
+ "")
+
+(define_insn "*return_internal"
+ [(return)]
+ ""
+ "* return output_return (insn);"
+ [(set_attr "type" "return")
+ (set (attr "length")
+ (cond [(eq_attr "leaf_function" "true")
+ (if_then_else (eq_attr "empty_delay_slot" "true")
+ (const_int 2)
+ (const_int 1))
+ (eq_attr "calls_eh_return" "true")
+ (if_then_else (eq_attr "delayed_branch" "true")
+ (if_then_else (eq_attr "isa" "v9")
+ (const_int 2)
+ (const_int 3))
+ (if_then_else (eq_attr "isa" "v9")
+ (const_int 3)
+ (const_int 4)))
+ (eq_attr "empty_delay_slot" "true")
+ (if_then_else (eq_attr "delayed_branch" "true")
+ (const_int 2)
+ (const_int 3))
+ ] (const_int 1)))])
;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
;; all of memory. This blocks insns from being moved across this point.
@@ -7681,16 +7094,29 @@
DONE;
})
-;; This is a bit of a hack. We're incrementing a fixed register (%i7),
-;; and parts of the compiler don't want to believe that the add is needed.
+;; Adjust the return address conditionally. If the value of op1 is equal
+;; to all zero then adjust the return address i.e. op0 = op0 + 4.
+;; This is technically *half* the check required by the 32-bit SPARC
+;; psABI. This check only ensures that an "unimp" insn was written by
+;; the caller, but doesn't check to see if the expected size matches
+;; (this is encoded in the 12 lower bits). This check is obsolete and
+;; only used by the above code "untyped_return".
(define_insn "update_return"
[(unspec:SI [(match_operand:SI 0 "register_operand" "r")
(match_operand:SI 1 "register_operand" "r")] UNSPEC_UPDATE_RETURN)]
"! TARGET_ARCH64"
- "cmp\t%1, 0\;be,a\t.+8\;add\t%0, 4, %0"
- [(set_attr "type" "multi")
- (set_attr "length" "3")])
+{
+ if (flag_delayed_branch)
+ return "cmp\t%1, 0\n\tbe,a\t.+8\n\t add\t%0, 4, %0";
+ else
+ return "cmp\t%1, 0\n\tbne\t.+12\n\t nop\n\tadd\t%0, 4, %0";
+}
+ [(set (attr "type") (const_string "multi"))
+ (set (attr "length")
+ (if_then_else (eq_attr "delayed_branch" "true")
+ (const_int 3)
+ (const_int 4)))])
(define_insn "nop"
[(const_int 0)]
@@ -7714,7 +7140,6 @@
"jmp\t%a0%#"
[(set_attr "type" "uncond_branch")])
-;; ??? Doesn't work with -mflat.
(define_expand "nonlocal_goto"
[(match_operand:SI 0 "general_operand" "")
(match_operand:SI 1 "general_operand" "")
@@ -7722,9 +7147,6 @@
(match_operand:SI 3 "" "")]
""
{
-#if 0
- rtx chain = operands[0];
-#endif
rtx lab = operands[1];
rtx stack = operands[2];
rtx fp = operands[3];
@@ -7750,27 +7172,10 @@
and reload the appropriate value into %fp. */
emit_move_insn (hard_frame_pointer_rtx, stack);
- /* USE of frame_pointer_rtx added for consistency; not clear if
- really needed. */
- /*emit_insn (gen_rtx_USE (VOIDmode, frame_pointer_rtx));*/
emit_insn (gen_rtx_USE (VOIDmode, stack_pointer_rtx));
-
-#if 0
- /* Return, restoring reg window and jumping to goto handler. */
- if (TARGET_V9 && GET_CODE (chain) == CONST_INT
- && ! (INTVAL (chain) & ~(HOST_WIDE_INT)0xffffffff))
- {
- emit_jump_insn (gen_goto_handler_and_restore_v9 (labreg,
- static_chain_rtx,
- chain));
- emit_barrier ();
- DONE;
- }
- /* Put in the static chain register the nonlocal label address. */
- emit_move_insn (static_chain_rtx, chain);
-#endif
-
emit_insn (gen_rtx_USE (VOIDmode, static_chain_rtx));
+
+ /* ??? The V9-specific version was disabled in rev 1.65. */
emit_jump_insn (gen_goto_handler_and_restore (labreg));
emit_barrier ();
DONE;
@@ -7786,31 +7191,17 @@
(define_insn "goto_handler_and_restore"
[(unspec_volatile [(match_operand 0 "register_operand" "=r")] UNSPECV_GOTO)]
"GET_MODE (operands[0]) == Pmode"
- "jmp\t%0+0\n\trestore"
- [(set_attr "type" "multi")
- (set_attr "length" "2")])
-
-;;(define_insn "goto_handler_and_restore_v9"
-;; [(unspec_volatile [(match_operand:SI 0 "register_operand" "=r,r")
-;; (match_operand:SI 1 "register_operand" "=r,r")
-;; (match_operand:SI 2 "const_int_operand" "I,n")] UNSPECV_GOTO_V9)]
-;; "TARGET_V9 && ! TARGET_ARCH64"
-;; "@
-;; return\t%0+0\n\tmov\t%2, %Y1
-;; sethi\t%%hi(%2), %1\n\treturn\t%0+0\n\tor\t%Y1, %%lo(%2), %Y1"
-;; [(set_attr "type" "multi")
-;; (set_attr "length" "2,3")])
-;;
-;;(define_insn "*goto_handler_and_restore_v9_sp64"
-;; [(unspec_volatile [(match_operand:DI 0 "register_operand" "=r,r")
-;; (match_operand:DI 1 "register_operand" "=r,r")
-;; (match_operand:SI 2 "const_int_operand" "I,n")] UNSPECV_GOTO_V9)]
-;; "TARGET_V9 && TARGET_ARCH64"
-;; "@
-;; return\t%0+0\n\tmov\t%2, %Y1
-;; sethi\t%%hi(%2), %1\n\treturn\t%0+0\n\tor\t%Y1, %%lo(%2), %Y1"
-;; [(set_attr "type" "multi")
-;; (set_attr "length" "2,3")])
+{
+ if (flag_delayed_branch)
+ return "jmp\t%0\n\t restore";
+ else
+ return "mov\t%0,%%g1\n\trestore\n\tjmp\t%%g1\n\t nop";
+}
+ [(set (attr "type") (const_string "multi"))
+ (set (attr "length")
+ (if_then_else (eq_attr "delayed_branch" "true")
+ (const_int 2)
+ (const_int 4)))])
;; For __builtin_setjmp we need to flush register windows iff the function
;; calls alloca as well, because otherwise the register window might be
@@ -7829,7 +7220,7 @@
{
if (! current_function_calls_alloca)
return "";
- if (! TARGET_V9 || TARGET_FLAT)
+ if (! TARGET_V9)
return "\tta\t3\n";
fputs ("\tflushw\n", asm_out_file);
if (flag_pic)
@@ -7846,10 +7237,8 @@
}
[(set_attr "type" "multi")
(set (attr "length")
- (cond [(eq_attr "current_function_calls_alloca" "false")
+ (cond [(eq_attr "calls_alloca" "false")
(const_int 0)
- (eq_attr "flat" "true")
- (const_int 1)
(eq_attr "isa" "!v9")
(const_int 1)
(eq_attr "pic" "true")
@@ -7862,25 +7251,20 @@
[(const_int 0)]
""
{
- if (TARGET_ARCH64)
- emit_insn (gen_setjmp_64 ());
- else
- emit_insn (gen_setjmp_32 ());
+ rtx mem;
+
+ mem = gen_rtx_MEM (Pmode,
+ plus_constant (stack_pointer_rtx,
+ SPARC_STACK_BIAS + 14 * UNITS_PER_WORD));
+ emit_insn (gen_rtx_SET (VOIDmode, mem, frame_pointer_rtx));
+
+ mem = gen_rtx_MEM (Pmode,
+ plus_constant (stack_pointer_rtx,
+ SPARC_STACK_BIAS + 15 * UNITS_PER_WORD));
+ emit_insn (gen_rtx_SET (VOIDmode, mem, gen_rtx_REG (Pmode, 31)));
DONE;
})
-(define_expand "setjmp_32"
- [(set (mem:SI (plus:SI (reg:SI 14) (const_int 56))) (match_dup 0))
- (set (mem:SI (plus:SI (reg:SI 14) (const_int 60))) (reg:SI 31))]
- ""
- { operands[0] = frame_pointer_rtx; })
-
-(define_expand "setjmp_64"
- [(set (mem:DI (plus:DI (reg:DI 14) (const_int 112))) (match_dup 0))
- (set (mem:DI (plus:DI (reg:DI 14) (const_int 120))) (reg:DI 31))]
- ""
- { operands[0] = frame_pointer_rtx; })
-
;; Special pattern for the FLUSH instruction.
; We do SImode and DImode versions of this to quiet down genrecog's complaints
@@ -7900,8 +7284,8 @@
{ return TARGET_V9 ? "flush\t%f0" : "iflush\t%f0"; }
[(set_attr "type" "iflush")])
-
-;; find first set.
+
+;; Find first set instructions.
;; The scan instruction searches from the most significant bit while ffs
;; searches from the least significant bit. The bit index and treatment of
@@ -8097,165 +7481,8 @@
(compare:CCX (match_dup 1) (const_int 0)))])]
"")
-;; Return peepholes. These are generated by sparc_nonflat_function_epilogue
-;; who then immediately calls final_scan_insn.
-
-(define_insn "*return_qi"
- [(set (match_operand:QI 0 "restore_operand" "")
- (match_operand:QI 1 "arith_operand" "rI"))
- (return)]
- "sparc_emitting_epilogue"
-{
- if (! TARGET_ARCH64 && current_function_returns_struct)
- return "jmp\t%%i7+12\n\trestore %%g0, %1, %Y0";
- else if (TARGET_V9 && (GET_CODE (operands[1]) == CONST_INT
- || IN_OR_GLOBAL_P (operands[1])))
- return "return\t%%i7+8\n\tmov\t%Y1, %Y0";
- else
- return "ret\n\trestore %%g0, %1, %Y0";
-}
- [(set_attr "type" "multi")
- (set_attr "length" "2")])
-
-(define_insn "*return_hi"
- [(set (match_operand:HI 0 "restore_operand" "")
- (match_operand:HI 1 "arith_operand" "rI"))
- (return)]
- "sparc_emitting_epilogue"
-{
- if (! TARGET_ARCH64 && current_function_returns_struct)
- return "jmp\t%%i7+12\n\trestore %%g0, %1, %Y0";
- else if (TARGET_V9 && (GET_CODE (operands[1]) == CONST_INT
- || IN_OR_GLOBAL_P (operands[1])))
- return "return\t%%i7+8\n\tmov\t%Y1, %Y0";
- else
- return "ret\;restore %%g0, %1, %Y0";
-}
- [(set_attr "type" "multi")
- (set_attr "length" "2")])
-
-(define_insn "*return_si"
- [(set (match_operand:SI 0 "restore_operand" "")
- (match_operand:SI 1 "arith_operand" "rI"))
- (return)]
- "sparc_emitting_epilogue"
-{
- if (! TARGET_ARCH64 && current_function_returns_struct)
- return "jmp\t%%i7+12\n\trestore %%g0, %1, %Y0";
- else if (TARGET_V9 && (GET_CODE (operands[1]) == CONST_INT
- || IN_OR_GLOBAL_P (operands[1])))
- return "return\t%%i7+8\n\tmov\t%Y1, %Y0";
- else
- return "ret\;restore %%g0, %1, %Y0";
-}
- [(set_attr "type" "multi")
- (set_attr "length" "2")])
-
-(define_insn "*return_sf_no_fpu"
- [(set (match_operand:SF 0 "restore_operand" "=r")
- (match_operand:SF 1 "register_operand" "r"))
- (return)]
- "sparc_emitting_epilogue"
-{
- if (! TARGET_ARCH64 && current_function_returns_struct)
- return "jmp\t%%i7+12\n\trestore %%g0, %1, %Y0";
- else if (TARGET_V9 && IN_OR_GLOBAL_P (operands[1]))
- return "return\t%%i7+8\n\tmov\t%Y1, %Y0";
- else
- return "ret\;restore %%g0, %1, %Y0";
-}
- [(set_attr "type" "multi")
- (set_attr "length" "2")])
-
-(define_insn "*return_df_no_fpu"
- [(set (match_operand:DF 0 "restore_operand" "=r")
- (match_operand:DF 1 "register_operand" "r"))
- (return)]
- "sparc_emitting_epilogue && TARGET_ARCH64"
-{
- if (IN_OR_GLOBAL_P (operands[1]))
- return "return\t%%i7+8\n\tmov\t%Y1, %Y0";
- else
- return "ret\;restore %%g0, %1, %Y0";
-}
- [(set_attr "type" "multi")
- (set_attr "length" "2")])
-
-(define_insn "*return_addsi"
- [(set (match_operand:SI 0 "restore_operand" "")
- (plus:SI (match_operand:SI 1 "register_operand" "r")
- (match_operand:SI 2 "arith_operand" "rI")))
- (return)]
- "sparc_emitting_epilogue"
-{
- if (! TARGET_ARCH64 && current_function_returns_struct)
- return "jmp\t%%i7+12\n\trestore %r1, %2, %Y0";
- /* If operands are global or in registers, can use return */
- else if (TARGET_V9 && IN_OR_GLOBAL_P (operands[1])
- && (GET_CODE (operands[2]) == CONST_INT
- || IN_OR_GLOBAL_P (operands[2])))
- return "return\t%%i7+8\n\tadd\t%Y1, %Y2, %Y0";
- else
- return "ret\;restore %r1, %2, %Y0";
-}
- [(set_attr "type" "multi")
- (set_attr "length" "2")])
-
-(define_insn "*return_losum_si"
- [(set (match_operand:SI 0 "restore_operand" "")
- (lo_sum:SI (match_operand:SI 1 "register_operand" "r")
- (match_operand:SI 2 "immediate_operand" "in")))
- (return)]
- "sparc_emitting_epilogue && ! TARGET_CM_MEDMID"
-{
- if (! TARGET_ARCH64 && current_function_returns_struct)
- return "jmp\t%%i7+12\n\trestore %r1, %%lo(%a2), %Y0";
- /* If operands are global or in registers, can use return */
- else if (TARGET_V9 && IN_OR_GLOBAL_P (operands[1]))
- return "return\t%%i7+8\n\tor\t%Y1, %%lo(%a2), %Y0";
- else
- return "ret\;restore %r1, %%lo(%a2), %Y0";
-}
- [(set_attr "type" "multi")
- (set_attr "length" "2")])
-
-(define_insn "*return_di"
- [(set (match_operand:DI 0 "restore_operand" "")
- (match_operand:DI 1 "arith_double_operand" "rHI"))
- (return)]
- "sparc_emitting_epilogue && TARGET_ARCH64"
- "ret\;restore %%g0, %1, %Y0"
- [(set_attr "type" "multi")
- (set_attr "length" "2")])
-
-(define_insn "*return_adddi"
- [(set (match_operand:DI 0 "restore_operand" "")
- (plus:DI (match_operand:DI 1 "arith_operand" "%r")
- (match_operand:DI 2 "arith_double_operand" "rHI")))
- (return)]
- "sparc_emitting_epilogue && TARGET_ARCH64"
- "ret\;restore %r1, %2, %Y0"
- [(set_attr "type" "multi")
- (set_attr "length" "2")])
-(define_insn "*return_losum_di"
- [(set (match_operand:DI 0 "restore_operand" "")
- (lo_sum:DI (match_operand:DI 1 "arith_operand" "%r")
- (match_operand:DI 2 "immediate_operand" "in")))
- (return)]
- "sparc_emitting_epilogue && TARGET_ARCH64 && ! TARGET_CM_MEDMID"
- "ret\;restore %r1, %%lo(%a2), %Y0"
- [(set_attr "type" "multi")
- (set_attr "length" "2")])
-
-(define_insn "*return_sf"
- [(set (reg:SF 32)
- (match_operand:SF 0 "register_operand" "f"))
- (return)]
- "sparc_emitting_epilogue"
- "ret\;fmovs\t%0, %%f0"
- [(set_attr "type" "multi")
- (set_attr "length" "2")])
+;; Prefetch instructions.
;; ??? UltraSPARC-III note: A memory operation loading into the floating point register
;; ??? file, if it hits the prefetch cache, has a chance to dual-issue with other memory
@@ -8293,10 +7520,8 @@
int read_or_write = INTVAL (operands[1]);
int locality = INTVAL (operands[2]);
- if (read_or_write != 0 && read_or_write != 1)
- abort ();
- if (locality < 0 || locality > 3)
- abort ();
+ gcc_assert (read_or_write == 0 || read_or_write == 1);
+ gcc_assert (locality >= 0 && locality < 4);
return prefetch_instr [read_or_write][locality == 0 ? 0 : 1];
}
[(set_attr "type" "load")])
@@ -8320,42 +7545,15 @@
int read_or_write = INTVAL (operands[1]);
int locality = INTVAL (operands[2]);
- if (read_or_write != 0 && read_or_write != 1)
- abort ();
- if (locality < 0 || locality > 3)
- abort ();
+ gcc_assert (read_or_write == 0 || read_or_write == 1);
+ gcc_assert (locality >= 0 && locality < 4);
return prefetch_instr [read_or_write][locality == 0 ? 0 : 1];
}
[(set_attr "type" "load")])
-
-(define_expand "prologue"
- [(const_int 1)]
- "flag_pic && current_function_uses_pic_offset_table"
-{
- load_pic_register ();
- DONE;
-})
-;; We need to reload %l7 for -mflat -fpic,
-;; otherwise %l7 should be preserved simply
-;; by loading the function's register window
-(define_expand "exception_receiver"
- [(const_int 0)]
- "TARGET_FLAT && flag_pic"
-{
- load_pic_register ();
- DONE;
-})
-;; Likewise
-(define_expand "builtin_setjmp_receiver"
- [(label_ref (match_operand 0 "" ""))]
- "TARGET_FLAT && flag_pic"
-{
- load_pic_register ();
- DONE;
-})
-
+;; Trap instructions.
+
(define_insn "trap"
[(trap_if (const_int 1) (const_int 5))]
""
@@ -8363,29 +7561,36 @@
[(set_attr "type" "trap")])
(define_expand "conditional_trap"
- [(trap_if (match_operator 0 "noov_compare_op"
- [(match_dup 2) (match_dup 3)])
+ [(trap_if (match_operator 0 "noov_compare_operator" [(match_dup 2) (match_dup 3)])
(match_operand:SI 1 "arith_operand" ""))]
""
- "operands[2] = gen_compare_reg (GET_CODE (operands[0]),
- sparc_compare_op0, sparc_compare_op1);
+ "operands[2] = gen_compare_reg (GET_CODE (operands[0]));
+ if (GET_MODE (operands[2]) != CCmode && GET_MODE (operands[2]) != CCXmode)
+ FAIL;
operands[3] = const0_rtx;")
(define_insn ""
- [(trap_if (match_operator 0 "noov_compare_op" [(reg:CC 100) (const_int 0)])
+ [(trap_if (match_operator 0 "noov_compare_operator" [(reg:CC 100) (const_int 0)])
(match_operand:SI 1 "arith_operand" "rM"))]
""
- "t%C0\t%1"
+{
+ if (TARGET_V9)
+ return "t%C0\t%%icc, %1";
+ else
+ return "t%C0\t%1";
+}
[(set_attr "type" "trap")])
(define_insn ""
- [(trap_if (match_operator 0 "noov_compare_op" [(reg:CCX 100) (const_int 0)])
+ [(trap_if (match_operator 0 "noov_compare_operator" [(reg:CCX 100) (const_int 0)])
(match_operand:SI 1 "arith_operand" "rM"))]
"TARGET_V9"
"t%C0\t%%xcc, %1"
[(set_attr "type" "trap")])
-;; TLS support
+
+;; TLS support instructions.
+
(define_insn "tgd_hi22"
[(set (match_operand:SI 0 "register_operand" "=r")
(high:SI (unspec:SI [(match_operand 1 "tgd_symbolic_operand" "")]
@@ -8947,3 +8152,335 @@
"TARGET_TLS && TARGET_ARCH64"
"stx\t%0, [%1 + %2], %%tldo_add(%3)"
[(set_attr "type" "store")])
+
+
+;; Stack protector instructions.
+
+(define_expand "stack_protect_set"
+ [(match_operand 0 "memory_operand" "")
+ (match_operand 1 "memory_operand" "")]
+ ""
+{
+#ifdef TARGET_THREAD_SSP_OFFSET
+ rtx tlsreg = gen_rtx_REG (Pmode, 7);
+ rtx addr = gen_rtx_PLUS (Pmode, tlsreg, GEN_INT (TARGET_THREAD_SSP_OFFSET));
+ operands[1] = gen_rtx_MEM (Pmode, addr);
+#endif
+ if (TARGET_ARCH64)
+ emit_insn (gen_stack_protect_setdi (operands[0], operands[1]));
+ else
+ emit_insn (gen_stack_protect_setsi (operands[0], operands[1]));
+ DONE;
+})
+
+(define_insn "stack_protect_setsi"
+ [(set (match_operand:SI 0 "memory_operand" "=m")
+ (unspec:SI [(match_operand:SI 1 "memory_operand" "m")] UNSPEC_SP_SET))
+ (set (match_scratch:SI 2 "=&r") (const_int 0))]
+ "TARGET_ARCH32"
+ "ld\t%1, %2\;st\t%2, %0\;mov\t0, %2"
+ [(set_attr "type" "multi")
+ (set_attr "length" "3")])
+
+(define_insn "stack_protect_setdi"
+ [(set (match_operand:DI 0 "memory_operand" "=m")
+ (unspec:DI [(match_operand:DI 1 "memory_operand" "m")] UNSPEC_SP_SET))
+ (set (match_scratch:DI 2 "=&r") (const_int 0))]
+ "TARGET_ARCH64"
+ "ldx\t%1, %2\;stx\t%2, %0\;mov\t0, %2"
+ [(set_attr "type" "multi")
+ (set_attr "length" "3")])
+
+(define_expand "stack_protect_test"
+ [(match_operand 0 "memory_operand" "")
+ (match_operand 1 "memory_operand" "")
+ (match_operand 2 "" "")]
+ ""
+{
+#ifdef TARGET_THREAD_SSP_OFFSET
+ rtx tlsreg = gen_rtx_REG (Pmode, 7);
+ rtx addr = gen_rtx_PLUS (Pmode, tlsreg, GEN_INT (TARGET_THREAD_SSP_OFFSET));
+ operands[1] = gen_rtx_MEM (Pmode, addr);
+#endif
+ if (TARGET_ARCH64)
+ {
+ rtx temp = gen_reg_rtx (Pmode);
+ emit_insn (gen_stack_protect_testdi (temp, operands[0], operands[1]));
+ sparc_compare_op0 = temp;
+ sparc_compare_op1 = const0_rtx;
+ }
+ else
+ {
+ emit_insn (gen_stack_protect_testsi (operands[0], operands[1]));
+ sparc_compare_op0 = operands[0];
+ sparc_compare_op1 = operands[1];
+ sparc_compare_emitted = gen_rtx_REG (CCmode, SPARC_ICC_REG);
+ }
+ emit_jump_insn (gen_beq (operands[2]));
+ DONE;
+})
+
+(define_insn "stack_protect_testsi"
+ [(set (reg:CC 100)
+ (unspec:CC [(match_operand:SI 0 "memory_operand" "m")
+ (match_operand:SI 1 "memory_operand" "m")]
+ UNSPEC_SP_TEST))
+ (set (match_scratch:SI 3 "=r") (const_int 0))
+ (clobber (match_scratch:SI 2 "=&r"))]
+ "TARGET_ARCH32"
+ "ld\t%0, %2\;ld\t%1, %3\;xorcc\t%2, %3, %2\;mov\t0, %3"
+ [(set_attr "type" "multi")
+ (set_attr "length" "4")])
+
+(define_insn "stack_protect_testdi"
+ [(set (match_operand:DI 0 "register_operand" "=&r")
+ (unspec:DI [(match_operand:DI 1 "memory_operand" "m")
+ (match_operand:DI 2 "memory_operand" "m")]
+ UNSPEC_SP_TEST))
+ (set (match_scratch:DI 3 "=r") (const_int 0))]
+ "TARGET_ARCH64"
+ "ldx\t%1, %0\;ldx\t%2, %3\;xor\t%0, %3, %0\;mov\t0, %3"
+ [(set_attr "type" "multi")
+ (set_attr "length" "4")])
+
+
+;; Vector instructions.
+
+(define_insn "addv2si3"
+ [(set (match_operand:V2SI 0 "register_operand" "=e")
+ (plus:V2SI (match_operand:V2SI 1 "register_operand" "e")
+ (match_operand:V2SI 2 "register_operand" "e")))]
+ "TARGET_VIS"
+ "fpadd32\t%1, %2, %0"
+ [(set_attr "type" "fga")
+ (set_attr "fptype" "double")])
+
+(define_insn "addv4hi3"
+ [(set (match_operand:V4HI 0 "register_operand" "=e")
+ (plus:V4HI (match_operand:V4HI 1 "register_operand" "e")
+ (match_operand:V4HI 2 "register_operand" "e")))]
+ "TARGET_VIS"
+ "fpadd16\t%1, %2, %0"
+ [(set_attr "type" "fga")
+ (set_attr "fptype" "double")])
+
+;; fpadd32s is emitted by the addsi3 pattern.
+
+(define_insn "addv2hi3"
+ [(set (match_operand:V2HI 0 "register_operand" "=f")
+ (plus:V2HI (match_operand:V2HI 1 "register_operand" "f")
+ (match_operand:V2HI 2 "register_operand" "f")))]
+ "TARGET_VIS"
+ "fpadd16s\t%1, %2, %0"
+ [(set_attr "type" "fga")
+ (set_attr "fptype" "single")])
+
+(define_insn "subv2si3"
+ [(set (match_operand:V2SI 0 "register_operand" "=e")
+ (minus:V2SI (match_operand:V2SI 1 "register_operand" "e")
+ (match_operand:V2SI 2 "register_operand" "e")))]
+ "TARGET_VIS"
+ "fpsub32\t%1, %2, %0"
+ [(set_attr "type" "fga")
+ (set_attr "fptype" "double")])
+
+(define_insn "subv4hi3"
+ [(set (match_operand:V4HI 0 "register_operand" "=e")
+ (minus:V4HI (match_operand:V4HI 1 "register_operand" "e")
+ (match_operand:V4HI 2 "register_operand" "e")))]
+ "TARGET_VIS"
+ "fpsub16\t%1, %2, %0"
+ [(set_attr "type" "fga")
+ (set_attr "fptype" "double")])
+
+;; fpsub32s is emitted by the subsi3 pattern.
+
+(define_insn "subv2hi3"
+ [(set (match_operand:V2HI 0 "register_operand" "=f")
+ (minus:V2HI (match_operand:V2HI 1 "register_operand" "f")
+ (match_operand:V2HI 2 "register_operand" "f")))]
+ "TARGET_VIS"
+ "fpsub16s\t%1, %2, %0"
+ [(set_attr "type" "fga")
+ (set_attr "fptype" "single")])
+
+;; All other logical instructions have integer equivalents so they
+;; are defined together.
+
+;; (ior (not (op1)) (not (op2))) is the canonical form of NAND.
+
+(define_insn "*nand<V64mode>_vis"
+ [(set (match_operand:V64 0 "register_operand" "=e")
+ (ior:V64 (not:V64 (match_operand:V64 1 "register_operand" "e"))
+ (not:V64 (match_operand:V64 2 "register_operand" "e"))))]
+ "TARGET_VIS"
+ "fnand\t%1, %2, %0"
+ [(set_attr "type" "fga")
+ (set_attr "fptype" "double")])
+
+(define_insn "*nand<V32mode>_vis"
+ [(set (match_operand:V32 0 "register_operand" "=f")
+ (ior:V32 (not:V32 (match_operand:V32 1 "register_operand" "f"))
+ (not:V32 (match_operand:V32 2 "register_operand" "f"))))]
+ "TARGET_VIS"
+ "fnands\t%1, %2, %0"
+ [(set_attr "type" "fga")
+ (set_attr "fptype" "single")])
+
+;; Hard to generate VIS instructions. We have builtins for these.
+
+(define_insn "fpack16_vis"
+ [(set (match_operand:V4QI 0 "register_operand" "=f")
+ (unspec:V4QI [(match_operand:V4HI 1 "register_operand" "e")]
+ UNSPEC_FPACK16))]
+ "TARGET_VIS"
+ "fpack16\t%1, %0"
+ [(set_attr "type" "fga")
+ (set_attr "fptype" "double")])
+
+(define_insn "fpackfix_vis"
+ [(set (match_operand:V2HI 0 "register_operand" "=f")
+ (unspec:V2HI [(match_operand:V2SI 1 "register_operand" "e")]
+ UNSPEC_FPACKFIX))]
+ "TARGET_VIS"
+ "fpackfix\t%1, %0"
+ [(set_attr "type" "fga")
+ (set_attr "fptype" "double")])
+
+(define_insn "fpack32_vis"
+ [(set (match_operand:V8QI 0 "register_operand" "=e")
+ (unspec:V8QI [(match_operand:V2SI 1 "register_operand" "e")
+ (match_operand:V8QI 2 "register_operand" "e")]
+ UNSPEC_FPACK32))]
+ "TARGET_VIS"
+ "fpack32\t%1, %2, %0"
+ [(set_attr "type" "fga")
+ (set_attr "fptype" "double")])
+
+(define_insn "fexpand_vis"
+ [(set (match_operand:V4HI 0 "register_operand" "=e")
+ (unspec:V4HI [(match_operand:V4QI 1 "register_operand" "f")]
+ UNSPEC_FEXPAND))]
+ "TARGET_VIS"
+ "fexpand\t%1, %0"
+ [(set_attr "type" "fga")
+ (set_attr "fptype" "double")])
+
+;; It may be possible to describe this operation as (1 indexed):
+;; (vec_select (vec_duplicate (vec_duplicate (vec_concat 1 2)))
+;; 1,5,10,14,19,23,28,32)
+;; Note that (vec_merge:V8QI [(V4QI) (V4QI)] (10101010 = 170) doesn't work
+;; because vec_merge expects all the operands to be of the same type.
+(define_insn "fpmerge_vis"
+ [(set (match_operand:V8QI 0 "register_operand" "=e")
+ (unspec:V8QI [(match_operand:V4QI 1 "register_operand" "f")
+ (match_operand:V4QI 2 "register_operand" "f")]
+ UNSPEC_FPMERGE))]
+ "TARGET_VIS"
+ "fpmerge\t%1, %2, %0"
+ [(set_attr "type" "fga")
+ (set_attr "fptype" "double")])
+
+;; Partitioned multiply instructions
+(define_insn "fmul8x16_vis"
+ [(set (match_operand:V4HI 0 "register_operand" "=e")
+ (mult:V4HI (match_operand:V4QI 1 "register_operand" "f")
+ (match_operand:V4HI 2 "register_operand" "e")))]
+ "TARGET_VIS"
+ "fmul8x16\t%1, %2, %0"
+ [(set_attr "type" "fpmul")
+ (set_attr "fptype" "double")])
+
+;; Only one of the following two insns can be a multiply.
+(define_insn "fmul8x16au_vis"
+ [(set (match_operand:V4HI 0 "register_operand" "=e")
+ (mult:V4HI (match_operand:V4QI 1 "register_operand" "f")
+ (match_operand:V2HI 2 "register_operand" "f")))]
+ "TARGET_VIS"
+ "fmul8x16au\t%1, %2, %0"
+ [(set_attr "type" "fpmul")
+ (set_attr "fptype" "double")])
+
+(define_insn "fmul8x16al_vis"
+ [(set (match_operand:V4HI 0 "register_operand" "=e")
+ (unspec:V4HI [(match_operand:V4QI 1 "register_operand" "f")
+ (match_operand:V2HI 2 "register_operand" "f")]
+ UNSPEC_MUL16AL))]
+ "TARGET_VIS"
+ "fmul8x16al\t%1, %2, %0"
+ [(set_attr "type" "fpmul")
+ (set_attr "fptype" "double")])
+
+;; Only one of the following two insns can be a multiply.
+(define_insn "fmul8sux16_vis"
+ [(set (match_operand:V4HI 0 "register_operand" "=e")
+ (mult:V4HI (match_operand:V8QI 1 "register_operand" "e")
+ (match_operand:V4HI 2 "register_operand" "e")))]
+ "TARGET_VIS"
+ "fmul8sux16\t%1, %2, %0"
+ [(set_attr "type" "fpmul")
+ (set_attr "fptype" "double")])
+
+(define_insn "fmul8ulx16_vis"
+ [(set (match_operand:V4HI 0 "register_operand" "=e")
+ (unspec:V4HI [(match_operand:V8QI 1 "register_operand" "e")
+ (match_operand:V4HI 2 "register_operand" "e")]
+ UNSPEC_MUL8UL))]
+ "TARGET_VIS"
+ "fmul8ulx16\t%1, %2, %0"
+ [(set_attr "type" "fpmul")
+ (set_attr "fptype" "double")])
+
+;; Only one of the following two insns can be a multiply.
+(define_insn "fmuld8sux16_vis"
+ [(set (match_operand:V2SI 0 "register_operand" "=e")
+ (mult:V2SI (match_operand:V4QI 1 "register_operand" "f")
+ (match_operand:V2HI 2 "register_operand" "f")))]
+ "TARGET_VIS"
+ "fmuld8sux16\t%1, %2, %0"
+ [(set_attr "type" "fpmul")
+ (set_attr "fptype" "double")])
+
+(define_insn "fmuld8ulx16_vis"
+ [(set (match_operand:V2SI 0 "register_operand" "=e")
+ (unspec:V2SI [(match_operand:V4QI 1 "register_operand" "f")
+ (match_operand:V2HI 2 "register_operand" "f")]
+ UNSPEC_MULDUL))]
+ "TARGET_VIS"
+ "fmuld8ulx16\t%1, %2, %0"
+ [(set_attr "type" "fpmul")
+ (set_attr "fptype" "double")])
+
+;; Using faligndata only makes sense after an alignaddr since the choice of
+;; bytes to take out of each operand is dependent on the results of the last
+;; alignaddr.
+(define_insn "faligndata<V64I:mode>_vis"
+ [(set (match_operand:V64I 0 "register_operand" "=e")
+ (unspec:V64I [(match_operand:V64I 1 "register_operand" "e")
+ (match_operand:V64I 2 "register_operand" "e")]
+ UNSPEC_ALIGNDATA))]
+ "TARGET_VIS"
+ "faligndata\t%1, %2, %0"
+ [(set_attr "type" "fga")
+ (set_attr "fptype" "double")])
+
+(define_insn "alignaddr<P:mode>_vis"
+ [(set (match_operand:P 0 "register_operand" "=r")
+ (unspec:P [(match_operand:P 1 "register_or_zero_operand" "rJ")
+ (match_operand:P 2 "register_or_zero_operand" "rJ")]
+ UNSPEC_ALIGNADDR))]
+ "TARGET_VIS"
+ "alignaddr\t%r1, %r2, %0")
+
+(define_insn "pdist_vis"
+ [(set (match_operand:DI 0 "register_operand" "=e")
+ (unspec:DI [(match_operand:V8QI 1 "register_operand" "e")
+ (match_operand:V8QI 2 "register_operand" "e")
+ (match_operand:DI 3 "register_operand" "0")]
+ UNSPEC_PDIST))]
+ "TARGET_VIS"
+ "pdist\t%1, %2, %0"
+ [(set_attr "type" "fga")
+ (set_attr "fptype" "double")])
+
+(include "sync.md")
diff --git a/contrib/gcc/config/sparc/sparc.opt b/contrib/gcc/config/sparc/sparc.opt
new file mode 100644
index 0000000..8cdf11c
--- /dev/null
+++ b/contrib/gcc/config/sparc/sparc.opt
@@ -0,0 +1,126 @@
+; Options for the SPARC port of the compiler
+;
+; Copyright (C) 2005 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.
+
+mfpu
+Target Report Mask(FPU)
+Use hardware FP
+
+mhard-float
+Target RejectNegative Mask(FPU) MaskExists
+Use hardware FP
+
+msoft-float
+Target RejectNegative InverseMask(FPU)
+Do not use hardware FP
+
+munaligned-doubles
+Target Report Mask(UNALIGNED_DOUBLES)
+Assume possible double misalignment
+
+mimpure-text
+Target Report
+Pass -assert pure-text to linker
+
+mapp-regs
+Target Report Mask(APP_REGS)
+Use ABI reserved registers
+
+mhard-quad-float
+Target Report RejectNegative Mask(HARD_QUAD)
+Use hardware quad FP instructions
+
+msoft-quad-float
+Target Report RejectNegative InverseMask(HARD_QUAD)
+Do not use hardware quad fp instructions
+
+mv8plus
+Target Report Mask(V8PLUS)
+Compile for V8+ ABI
+
+mvis
+Target Report Mask(VIS)
+Use UltraSPARC Visual Instruction Set extensions
+
+mptr64
+Target Report RejectNegative Mask(PTR64)
+Pointers are 64-bit
+
+mptr32
+Target Report RejectNegative InverseMask(PTR64)
+Pointers are 32-bit
+
+m64
+Target Report RejectNegative Mask(64BIT)
+Use 64-bit ABI
+
+m32
+Target Report RejectNegative InverseMask(64BIT)
+Use 32-bit ABI
+
+mstack-bias
+Target Report Mask(STACK_BIAS)
+Use stack bias
+
+mfaster-structs
+Target Report Mask(FASTER_STRUCTS)
+Use structs on stronger alignment for double-word copies
+
+mrelax
+Target
+Optimize tail call instructions in assembler and linker
+
+mcpu=
+Target RejectNegative Joined
+Use features of and schedule code for given CPU
+
+mtune=
+Target RejectNegative Joined
+Schedule code for given CPU
+
+mcmodel=
+Target RejectNegative Joined Var(sparc_cmodel_string)
+Use given SPARC-V9 code model
+
+mstd-struct-return
+Target Report RejectNegative Var(sparc_std_struct_return)
+Enable strict 32-bit psABI struct return checking.
+
+Mask(LITTLE_ENDIAN)
+;; Generate code for little-endian
+
+Mask(LONG_DOUBLE_128)
+;; Use 128-bit long double
+
+Mask(SPARCLITE)
+;; Generate code for SPARClite
+
+Mask(SPARCLET)
+;; Generate code for SPARClet
+
+Mask(V8)
+;; Generate code for SPARC-V8
+
+Mask(V9)
+;; Generate code for SPARC-V9
+
+Mask(DEPRECATED_V8_INSNS)
+;; Generate code that uses the V8 instructions deprecated
+;; in the V9 architecture.
diff --git a/contrib/gcc/config/sparc/sparclet.md b/contrib/gcc/config/sparc/sparclet.md
index 15020ba..fdc03ab 100644
--- a/contrib/gcc/config/sparc/sparclet.md
+++ b/contrib/gcc/config/sparc/sparclet.md
@@ -15,8 +15,8 @@
;;
;; 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, 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
;; The SPARClet is a single-issue processor.
diff --git a/contrib/gcc/config/sparc/supersparc.md b/contrib/gcc/config/sparc/supersparc.md
index 93e4cf7..8aaa75f 100644
--- a/contrib/gcc/config/sparc/supersparc.md
+++ b/contrib/gcc/config/sparc/supersparc.md
@@ -15,8 +15,8 @@
;;
;; 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, 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
;; The SuperSPARC is a tri-issue, which was considered quite parallel
;; at the time it was released. Much like UltraSPARC-I and UltraSPARC-II
diff --git a/contrib/gcc/config/sparc/sync.md b/contrib/gcc/config/sparc/sync.md
new file mode 100644
index 0000000..1337921
--- /dev/null
+++ b/contrib/gcc/config/sparc/sync.md
@@ -0,0 +1,208 @@
+;; GCC machine description for SPARC synchronization instructions.
+;; Copyright (C) 2005
+;; 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.
+
+(define_mode_macro I12MODE [QI HI])
+(define_mode_macro I24MODE [HI SI])
+(define_mode_macro I48MODE [SI (DI "TARGET_ARCH64 || TARGET_V8PLUS")])
+(define_mode_attr modesuffix [(SI "") (DI "x")])
+
+(define_expand "memory_barrier"
+ [(set (mem:BLK (match_dup 0))
+ (unspec_volatile:BLK [(mem:BLK (match_dup 0)) (match_dup 1)]
+ UNSPECV_MEMBAR))]
+ "TARGET_V8 || TARGET_V9"
+{
+ operands[0] = gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (DImode));
+ MEM_VOLATILE_P (operands[0]) = 1;
+ if (TARGET_V9)
+ /* member #StoreStore | #LoadStore | #StoreLoad | #LoadLoad */
+ operands[1] = GEN_INT (15);
+ else
+ /* stbar */
+ operands[1] = GEN_INT (8);
+})
+
+(define_insn "*stbar"
+ [(set (match_operand:BLK 0 "" "")
+ (unspec_volatile:BLK [(match_operand:BLK 1 "" "")
+ (const_int 8)] UNSPECV_MEMBAR))]
+ "TARGET_V8"
+ "stbar"
+ [(set_attr "type" "multi")])
+
+(define_insn "*membar"
+ [(set (match_operand:BLK 0 "" "")
+ (unspec_volatile:BLK [(match_operand:BLK 1 "" "")
+ (match_operand:SI 2 "immediate_operand" "I")]
+ UNSPECV_MEMBAR))]
+ "TARGET_V9"
+ "membar\t%2"
+ [(set_attr "type" "multi")])
+
+(define_expand "sync_compare_and_swap<mode>"
+ [(match_operand:I12MODE 0 "register_operand" "")
+ (match_operand:I12MODE 1 "memory_operand" "")
+ (match_operand:I12MODE 2 "register_operand" "")
+ (match_operand:I12MODE 3 "register_operand" "")]
+ "TARGET_V9"
+{
+ sparc_expand_compare_and_swap_12 (operands[0], operands[1],
+ operands[2], operands[3]);
+ DONE;
+})
+
+(define_expand "sync_compare_and_swap<mode>"
+ [(parallel
+ [(set (match_operand:I48MODE 0 "register_operand" "=r")
+ (match_operand:I48MODE 1 "memory_operand" ""))
+ (set (match_dup 1)
+ (unspec_volatile:I48MODE
+ [(match_operand:I48MODE 2 "register_operand" "")
+ (match_operand:I48MODE 3 "register_operand" "")]
+ UNSPECV_CAS))])]
+ "TARGET_V9"
+{
+ if (! REG_P (XEXP (operands[1], 0)))
+ {
+ rtx addr = force_reg (Pmode, XEXP (operands[1], 0));
+ operands[1] = replace_equiv_address (operands[1], addr);
+ }
+ emit_insn (gen_memory_barrier ());
+})
+
+(define_insn "*sync_compare_and_swap<mode>"
+ [(set (match_operand:I48MODE 0 "register_operand" "=r")
+ (match_operand:I48MODE 1 "memory_reg_operand" "+m"))
+ (set (match_dup 1)
+ (unspec_volatile:I48MODE
+ [(match_operand:I48MODE 2 "register_operand" "r")
+ (match_operand:I48MODE 3 "register_operand" "0")]
+ UNSPECV_CAS))]
+ "TARGET_V9 && (<MODE>mode == SImode || TARGET_ARCH64)"
+ "cas<modesuffix>\t%1, %2, %0"
+ [(set_attr "type" "multi")])
+
+(define_insn "*sync_compare_and_swapdi_v8plus"
+ [(set (match_operand:DI 0 "register_operand" "=h")
+ (match_operand:DI 1 "memory_reg_operand" "+m"))
+ (set (match_dup 1)
+ (unspec_volatile:DI
+ [(match_operand:DI 2 "register_operand" "h")
+ (match_operand:DI 3 "register_operand" "0")]
+ UNSPECV_CAS))]
+ "TARGET_V8PLUS"
+{
+ if (sparc_check_64 (operands[3], insn) <= 0)
+ output_asm_insn ("srl\t%L3, 0, %L3", operands);
+ output_asm_insn ("sllx\t%H3, 32, %H3", operands);
+ output_asm_insn ("or\t%L3, %H3, %L3", operands);
+ if (sparc_check_64 (operands[2], insn) <= 0)
+ output_asm_insn ("srl\t%L2, 0, %L2", operands);
+ output_asm_insn ("sllx\t%H2, 32, %H3", operands);
+ output_asm_insn ("or\t%L2, %H3, %H3", operands);
+ output_asm_insn ("casx\t%1, %H3, %L3", operands);
+ return "srlx\t%L3, 32, %H3";
+}
+ [(set_attr "type" "multi")
+ (set_attr "length" "8")])
+
+(define_expand "sync_lock_test_and_set<mode>"
+ [(match_operand:I12MODE 0 "register_operand" "")
+ (match_operand:I12MODE 1 "memory_operand" "")
+ (match_operand:I12MODE 2 "arith_operand" "")]
+ "!TARGET_V9"
+{
+ if (operands[2] != const1_rtx)
+ FAIL;
+ if (TARGET_V8)
+ emit_insn (gen_memory_barrier ());
+ if (<MODE>mode != QImode)
+ operands[1] = adjust_address (operands[1], QImode, 0);
+ emit_insn (gen_ldstub<mode> (operands[0], operands[1]));
+ DONE;
+})
+
+(define_expand "sync_lock_test_and_setsi"
+ [(parallel
+ [(set (match_operand:SI 0 "register_operand" "")
+ (unspec_volatile:SI [(match_operand:SI 1 "memory_operand" "")]
+ UNSPECV_SWAP))
+ (set (match_dup 1)
+ (match_operand:SI 2 "arith_operand" ""))])]
+ ""
+{
+ if (! TARGET_V8 && ! TARGET_V9)
+ {
+ if (operands[2] != const1_rtx)
+ FAIL;
+ operands[1] = adjust_address (operands[1], QImode, 0);
+ emit_insn (gen_ldstubsi (operands[0], operands[1]));
+ DONE;
+ }
+ emit_insn (gen_memory_barrier ());
+ operands[2] = force_reg (SImode, operands[2]);
+})
+
+(define_insn "*swapsi"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec_volatile:SI [(match_operand:SI 1 "memory_operand" "+m")]
+ UNSPECV_SWAP))
+ (set (match_dup 1)
+ (match_operand:SI 2 "register_operand" "0"))]
+ "TARGET_V8 || TARGET_V9"
+ "swap\t%1, %0"
+ [(set_attr "type" "multi")])
+
+(define_expand "ldstubqi"
+ [(parallel [(set (match_operand:QI 0 "register_operand" "")
+ (unspec_volatile:QI [(match_operand:QI 1 "memory_operand" "")]
+ UNSPECV_LDSTUB))
+ (set (match_dup 1) (const_int -1))])]
+ ""
+ "")
+
+(define_expand "ldstub<mode>"
+ [(parallel [(set (match_operand:I24MODE 0 "register_operand" "")
+ (zero_extend:I24MODE
+ (unspec_volatile:QI [(match_operand:QI 1 "memory_operand" "")]
+ UNSPECV_LDSTUB)))
+ (set (match_dup 1) (const_int -1))])]
+ ""
+ "")
+
+(define_insn "*ldstubqi"
+ [(set (match_operand:QI 0 "register_operand" "=r")
+ (unspec_volatile:QI [(match_operand:QI 1 "memory_operand" "+m")]
+ UNSPECV_LDSTUB))
+ (set (match_dup 1) (const_int -1))]
+ ""
+ "ldstub\t%1, %0"
+ [(set_attr "type" "multi")])
+
+(define_insn "*ldstub<mode>"
+ [(set (match_operand:I24MODE 0 "register_operand" "=r")
+ (zero_extend:I24MODE
+ (unspec_volatile:QI [(match_operand:QI 1 "memory_operand" "+m")]
+ UNSPECV_LDSTUB)))
+ (set (match_dup 1) (const_int -1))]
+ ""
+ "ldstub\t%1, %0"
+ [(set_attr "type" "multi")])
diff --git a/contrib/gcc/config/sparc/sysv4-only.h b/contrib/gcc/config/sparc/sysv4-only.h
index da265a0..dca78ba 100644
--- a/contrib/gcc/config/sparc/sysv4-only.h
+++ b/contrib/gcc/config/sparc/sysv4-only.h
@@ -1,5 +1,5 @@
/* Target macros for GCC for SPARC running System V.4
- Copyright (C) 2003
+ Copyright (C) 2003, 2005
Free Software Foundation, Inc.
This file is part of GCC.
@@ -16,8 +16,8 @@ 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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
/* Provide a set of pre-definitions and pre-assertions appropriate for
the SPARC running svr4. __svr4__ is our extension. */
@@ -26,7 +26,6 @@ Boston, MA 02111-1307, USA. */
#define TARGET_OS_CPP_BUILTINS() \
do \
{ \
- builtin_define_std ("sparc"); \
builtin_define_std ("unix"); \
builtin_define ("__svr4__"); \
builtin_assert ("system=unix"); \
diff --git a/contrib/gcc/config/sparc/sysv4.h b/contrib/gcc/config/sparc/sysv4.h
index 776debc..0c0c8e0 100644
--- a/contrib/gcc/config/sparc/sysv4.h
+++ b/contrib/gcc/config/sparc/sysv4.h
@@ -17,8 +17,8 @@ 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, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
#ifndef TARGET_VERSION
#define TARGET_VERSION fprintf (stderr, " (sparc ELF)");
diff --git a/contrib/gcc/config/sparc/t-linux b/contrib/gcc/config/sparc/t-linux
new file mode 100644
index 0000000..a3e5130
--- /dev/null
+++ b/contrib/gcc/config/sparc/t-linux
@@ -0,0 +1,5 @@
+# Override t-slibgcc-elf-ver to export some libgcc symbols with
+# the symbol versions that glibc used.
+# Avoid the t-linux version file.
+SHLIB_MAPFILES = $(srcdir)/libgcc-std.ver \
+ $(srcdir)/config/sparc/libgcc-sparc-glibc.ver
diff --git a/contrib/gcc/config/sparc/t-linux64 b/contrib/gcc/config/sparc/t-linux64
index 3e3fa4c..7a1d5b1 100644
--- a/contrib/gcc/config/sparc/t-linux64
+++ b/contrib/gcc/config/sparc/t-linux64
@@ -8,12 +8,6 @@ INSTALL_LIBGCC = install-multilib
EXTRA_MULTILIB_PARTS=crtbegin.o crtend.o crtbeginS.o crtendS.o crtbeginT.o \
crtfastmath.o
-# Override t-slibgcc-elf-ver to export some libgcc symbols with
-# the symbol versions that glibc used.
-# Avoid the t-linux version file.
-SHLIB_MAPFILES = $(srcdir)/libgcc-std.ver \
- $(srcdir)/config/sparc/libgcc-sparc-glibc.ver
-
CRTSTUFF_T_CFLAGS = `if test x$$($(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) \
-print-multi-os-directory) \
= x../lib64; then echo -mcmodel=medany; fi`
diff --git a/contrib/gcc/config/sparc/ultra1_2.md b/contrib/gcc/config/sparc/ultra1_2.md
index e58c624..b7329fd 100644
--- a/contrib/gcc/config/sparc/ultra1_2.md
+++ b/contrib/gcc/config/sparc/ultra1_2.md
@@ -1,5 +1,5 @@
;; Scheduling description for UltraSPARC-I/II.
-;; Copyright (C) 2002 Free Software Foundation, Inc.
+;; Copyright (C) 2002, 2004 Free Software Foundation, Inc.
;;
;; This file is part of GCC.
;;
@@ -15,8 +15,8 @@
;;
;; 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, 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
;; UltraSPARC-I and II are quad-issue processors. Interesting features
;; to note:
@@ -80,7 +80,7 @@
(define_insn_reservation "us1_single" 1
(and (eq_attr "cpu" "ultrasparc")
- (eq_attr "type" "multi,flushw,iflush,trap"))
+ (eq_attr "type" "multi,savew,flushw,iflush,trap"))
"us1_single_issue")
(define_insn_reservation "us1_simple_ieuN" 1
diff --git a/contrib/gcc/config/sparc/ultra3.md b/contrib/gcc/config/sparc/ultra3.md
index 238beab..7f9905f 100644
--- a/contrib/gcc/config/sparc/ultra3.md
+++ b/contrib/gcc/config/sparc/ultra3.md
@@ -1,5 +1,5 @@
;; Scheduling description for UltraSPARC-III.
-;; Copyright (C) 2002 Free Software Foundation, Inc.
+;; Copyright (C) 2002, 2004 Free Software Foundation, Inc.
;;
;; This file is part of GCC.
;;
@@ -15,8 +15,8 @@
;;
;; 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, 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
;; UltraSPARC-III is a quad-issue processor.
;;
@@ -37,7 +37,7 @@
(define_insn_reservation "us3_single" 1
(and (eq_attr "cpu" "ultrasparc3")
- (eq_attr "type" "multi,flushw,iflush,trap"))
+ (eq_attr "type" "multi,savew,flushw,iflush,trap"))
"us3_single_issue")
(define_insn_reservation "us3_integer" 1
OpenPOWER on IntegriCloud